diff --git a/configure.ac b/configure.ac index b579b92f..369f66ae 100644 --- a/configure.ac +++ b/configure.ac @@ -184,6 +184,28 @@ AC_ARG_ENABLE([buggy_ifs], ) AC_MSG_RESULT([$buggy_ifs]) +dnl +dnl Handle --enable-xml-indent (default:no) +dnl +AC_MSG_CHECKING([whether to enable xml indentation for index]) +AC_ARG_ENABLE([xml_indent], + [AS_HELP_STRING([--enable-xml-indent],[Enable XML indentation for index])], + [xml_indent=$enableval], + [xml_indent=no] +) +AC_MSG_RESULT([$xml_indent]) + +dnl +dnl Handle --enable-format-spec25 (default:no) +dnl +AC_MSG_CHECKING([whether to enable format spec 2.5 support or not]) +AC_ARG_ENABLE([format_spec25], + [AS_HELP_STRING([--enable-format-spec25],[Support format spec 2.5])], + [format_spec25=$enableval], + [format_spec25=no] +) +AC_MSG_RESULT([$format_spec25]) + dnl dnl Handle extra compile flags for tape driver dnl @@ -499,6 +521,16 @@ then AM_CPPFLAGS="${AM_CPPFLAGS} -DPOSIXLINK_ONLY" fi +if test "x$xml_indent" = "xyes" +then + AM_CPPFLAGS="${AM_CPPFLAGS} -DINDENT_INDEXES" +fi + +if test "x$format_spec25" = "xyes" +then + AM_CPPFLAGS="${AM_CPPFLAGS} -DFORMAT_SPEC25" +fi + dnl dnl Specify CPU specific optimizer options for CRC calculation dnl diff --git a/contrib/ut-incindex/README.md b/contrib/ut-incindex/README.md new file mode 100644 index 00000000..ec3d9658 --- /dev/null +++ b/contrib/ut-incindex/README.md @@ -0,0 +1,13 @@ +# Unit Tests for incremental index + +This is a directory for having unit tests for incremental index feature. + +## How to run + +### Basic operation test + + 1. `cd` to this directory + 2. Run the basic test with `./ut-basic.sh [mount_point]` + - The test script formats a (filebackend) tape under `/tmp/ltfstape`, start ltfs and stop ltfs automatically. + - If `[mount_point]` is not specified, the script uses `/tmp/mnt` + - You can pass the specific `ltfs` binary directory with teh environmental value `LTFS_BIN_PATH` diff --git a/contrib/ut-incindex/ut-basic.sh b/contrib/ut-incindex/ut-basic.sh new file mode 100755 index 00000000..de61a29b --- /dev/null +++ b/contrib/ut-incindex/ut-basic.sh @@ -0,0 +1,96 @@ +#!/bin/sh + +source ./utils.sh + +MOUNTPOINT='/tmp/mnt' +TAPE_PATH='/tmp/ltfstape' + +if [ $# == 1 ]; then + MOUNTPOINT=$1 +elif [ $# -gt 2 ]; then + MOUNTPOINT=$1 + TAPE_PATH=$2 +fi + +# Format LTFS +FormatLTFS ${TAPE_PATH} +if [ $? != 0 ]; then + exit 1 +fi + +# Launch LTFS +LaunchLTFS ${MOUNTPOINT} ${TAPE_PATH} +if [ $? != 0 ]; then + exit 1 +fi + +# 1. CREATE DIRS +# Create a few dirs and files but all objects are handles by new dirs +echo "1. CREATE DIRS" +mkdir -p ${MOUNTPOINT}/dir1/dir11 +mkdir -p ${MOUNTPOINT}/dir1/dir12 +mkdir -p ${MOUNTPOINT}/dir2/dir21 +mkdir -p ${MOUNTPOINT}/dir2/dir22 +echo "AAA" > ${MOUNTPOINT}/dir1/file11 +echo "AAA" > ${MOUNTPOINT}/dir1/dir11/file111 +echo "AAA" > ${MOUNTPOINT}/dir1/dir11/file112 +IncrementalSync ${MOUNTPOINT} '1.CREATE_DIRS' +if [ $? != 0 ]; then + exit 1 +fi + +# 2. CREATE FILES +# Create files for checking file creation and directory traverse +echo "2. CREATE FILES" +echo "AAA" > ${MOUNTPOINT}/dir1/dir11/file113 +echo "AAA" > ${MOUNTPOINT}/dir1/dir12/file121 +echo "AAA" > ${MOUNTPOINT}/dir2/dir22/file221 +echo "AAA" > ${MOUNTPOINT}/dir2/file21 +IncrementalSync ${MOUNTPOINT} '2.CREATE_FILES' +if [ $? != 0 ]; then + exit 1 +fi + +# 3. MODIFY FILES +# Modify contents of files. Need to check /dir2 doesn't have meta-data on the incremental index +echo "3. MODIFY FILES" +echo "BBB" > ${MOUNTPOINT}/dir1/dir11/file111 +echo "BBB" > ${MOUNTPOINT}/dir2/dir22/file221 +echo "BBB" > ${MOUNTPOINT}/dir1/file11 +IncrementalSync ${MOUNTPOINT} '3.MODIFY_FILES' +if [ $? != 0 ]; then + exit 1 +fi + +# 4. MODIFY DIRS +# Modify directory's meta-data. Need to check both /dir1 and /dir1/dir11 has meta-data +# on the incremental index +echo "4. MODIFY DIRS" +AddXattr ${MOUNTPOINT}/dir1 'ut-attr1' 'val1' +echo "CCC" > ${MOUNTPOINT}/dir1/dir11/file111 +IncrementalSync ${MOUNTPOINT} '4.MODIFY_DIRS' +if [ $? != 0 ]; then + exit 1 +fi + +# 5. DELETE FILES +echo "5. DELETE FILES" +rm ${MOUNTPOINT}/dir1/dir11/* +IncrementalSync ${MOUNTPOINT} '5.DELETE_FILES' +if [ $? != 0 ]; then + exit 1 +fi + +# 6. DELETE DIR +echo "5. DELETE DIR" +rm -rf ${MOUNTPOINT}/dir1/dir11 +IncrementalSync ${MOUNTPOINT} '6.DELETE_DIR' +if [ $? != 0 ]; then + exit 1 +fi + +# Stop LTFS +StopLTFS ${MOUNTPOINT} ${TAPE_PATH} +if [ $? != 0 ]; then + exit 1 +fi diff --git a/contrib/ut-incindex/utils.sh b/contrib/ut-incindex/utils.sh new file mode 100755 index 00000000..ca79d3c6 --- /dev/null +++ b/contrib/ut-incindex/utils.sh @@ -0,0 +1,197 @@ +#!/bin/sh + +PLATFORM=`uname` +ECHO='/bin/echo' + +if [ "x${LTFS_BIN_PATH}" == 'x' ]; then + LTFS_BIN_PATH='/usr/local/bin' +fi + +AddXattr() +{ + if [ "x$1" == "x" ]; then + "Need to a target to set xattr" + return 1 + else + TARGET=$1 + fi + + if [ "x$2" == "x" ]; then + "Need to a name to set xattr" + return 1 + else + NAME=$2 + fi + + if [ "x$3" == "x" ]; then + "Need to a value to set xattr" + return 1 + else + VAL=$2 + fi + + ${ECHO} -n "Setting a xattr ${NAME} to ${TARGET} ... " + if [ "$PLATFORM" == "Darwin" ]; then + /usr/bin/xattr -w ${NAME} ${VAL} ${TARGET} + else + /usr/bin/attr -s ${NAME} -V ${VAL} ${TARGET} + fi + + if [ $? == 0 ]; then + ${ECHO} "Done" + return 0 + else + ${ECHO} "Failed" + return 1 + fi + +} + +IncrementalSync() +{ + if [ "x$1" == "x" ]; then + MOUNTPOINT='/tmp/mnt' + else + MOUNTPOINT=$1 + fi + + if [ "x$2" == "x" ]; then + MSG='Incremental Sync' + else + MSG=$2 + fi + + ${ECHO} -n "Syncing LTFS (Incremental) ... " + if [ "$PLATFORM" == "Darwin" ]; then + /usr/bin/xattr -w ltfs.vendor.IBM.IncrementalSync ${MSG} ${MOUNTPOINT} + else + /usr/bin/attr -s ltfs.vendor.IBM.IncrementalSync -V ${MSG} ${MOUNTPOINT} + fi + + if [ $? == 0 ]; then + ${ECHO} "Done" + return 0 + else + ${ECHO} "Failed" + return 1 + fi +} + +FullSync() +{ + if [ "x$1" == "x" ]; then + MOUNTPOINT='/tmp/mnt' + else + MOUNTPOINT=$1 + fi + + if [ "x$2" == "x" ]; then + MSG='Full Sync' + else + MSG=$2 + fi + + ${ECHO} "Syncing LTFS (Full) ... " + if [ "$PLATFORM" == "Darwin" ]; then + /usr/bin/xattr -w ltfs.vendor.IBM.FullSync ${MSG} ${MOUNTPOINT} + else + /usr/bin/attr -s ltfs.vendor.IBM.FullSync -V ${MSG} ${MOUNTPOINT} + fi + + if [ $? == 0 ]; then + ${ECHO} "Done" + return 0 + else + ${ECHO} "Failed" + return 1 + fi +} + +FormatLTFS() +{ + if [ "x$1" == "x" ]; then + TAPE_PATH='/tmp/ltfstape' + else + TAPE_PATH=$1 + fi + + if [ ! -d ${TAPE_PATH} ]; then + ${ECHO} "Creating tape directory for file backend: ${TAPE_PATH}" + mkdir -p ${TAPE_PATH} + if [ $? != 0 ]; then + ${ECHO} "Failed to create a tape path: ${TAPE_PATH}" + return 1 + fi + fi + + ${ECHO} "Formatting tape directory with the file backend on ${TAPE_PATH} ... " + ${LTFS_BIN_PATH}/mkltfs -f -e file -d ${TAPE_PATH} + if [ $? != 0 ]; then + ${ECHO} "Failed to format a tape path: ${TAPE_PATH}" + return 1 + fi + + ${ECHO} "Formatted the file backend on ${TAPE_PATH}" + return 0 +} + +LaunchLTFS() +{ + if [ "x$1" == "x" ]; then + MOUNTPOINT='/tmp/mnt' + else + MOUNTPOINT=$1 + fi + + if [ "x$2" == "x" ]; then + TAPE_PATH='/tmp/ltfstape' + else + TAPE_PATH=$2 + fi + + if [ ! -d ${MOUNTPOINT} ]; then + ${ECHO} "Creating mount point for LTFS: ${MOUNTPOINT}" + mkdir -p ${MOUNTPOINT} + if [ $? != 0 ]; then + ${ECHO} "Failed to create a mount point" + return 1 + fi + fi + + if [ ! -d ${TAPE_PATH} ]; then + ${ECHO} "Creating tape directory for file backend: ${TAPE_PATH}" + mkdir -p ${TAPE_PATH} + if [ $? != 0 ]; then + ${ECHO} "Failed to create a tape path: ${TAPE_PATH}" + return 1 + fi + + ${ECHO} "Formatting tape directory with the file backend" + ${LTFS_BIN_PATH}/mkltfs -f -e file -d ${TAPE_PATH} + if [ $? != 0 ]; then + ${ECHO} "Failed to format a tape path: ${TAPE_PATH}" + return 1 + fi + fi + + ${ECHO} "Launching LTFS with the file backend" + ${LTFS_BIN_PATH}/ltfs -o tape_backend=file -o sync_type=unmount -o devname=${TAPE_PATH} ${MOUNTPOINT} + if [ $? != 0 ]; then + ${ECHO} "Failed to launch LTFS on ${MOUNTPOINT}" + return 1 + fi + + ${ECHO} "LTFS is launched on ${MOUNTPOINT}" + return 0 +} + +StopLTFS() +{ + if [ "x$1" == "x" ]; then + MOUNTPOINT='/tmp/mnt' + else + MOUNTPOINT=$1 + fi + + sudo umount ${MOUNTPOINT} +} diff --git a/messages/internal_error/root.txt b/messages/internal_error/root.txt index 0df5c020..7692c8b9 100644 --- a/messages/internal_error/root.txt +++ b/messages/internal_error/root.txt @@ -309,6 +309,7 @@ root:table { I5048E:string{ "Unexpected partition map in a label." } I5049E:string{ "Unexpected blocksize in a label." } I5050E:string{ "Unexpected compression in a label." } + I5051E:string{ "Unsupported index type is specified." } // Special error codes I9997E:string{ "Child process error (ltfsck/mkltfs): %s (%d)." } diff --git a/messages/libltfs/root.txt b/messages/libltfs/root.txt index 938f8811..a4f0515b 100644 --- a/messages/libltfs/root.txt +++ b/messages/libltfs/root.txt @@ -836,6 +836,14 @@ v 17292I:string { "Current position is (%llu, %llu), Error position is (%llu, %llu)." } 17293E:string { "UUID in the index does not match the label." } + 17300I:string { "Wrote inc-index of %s (Gen = %lld, Part = %c, Pos = %lld, %s)." } + 17301I:string { "Info inc-index, Gen = %lld, Full Part = %c, Full Pos = %lld, Back Part = %c, Back Pos = %lld)." } + 17302E:string { "Path helper: Provided path must be an absolute path (%s)." } + 17303E:string { "Unexpected value was found in the reason of inc-journal entry (%d)." } + 17304E:string { "Unexpected value was provided to _xml_write_incremental_delete (%d)." } + 17305E:string { "Failed to construct a path helper (push: %d)." } + 17306E:string { "Failed to find a corresponded directory in path helper (push: %d)." } + // For Debug 19999I:string { "%s %s %d." } // DO NOT place messages with IDs 20000 or higher here! diff --git a/src/iosched/unified.c b/src/iosched/unified.c index af5265e7..a7ac70ca 100644 --- a/src/iosched/unified.c +++ b/src/iosched/unified.c @@ -2292,7 +2292,7 @@ int _unified_write_index_after_perm(int write_ret, struct unified_data *priv) } ltfs_set_commit_message_reason(SYNC_WRITE_PERM, priv->vol); - ret = ltfs_write_index(ltfs_ip_id(priv->vol), SYNC_WRITE_PERM, priv->vol); + ret = ltfs_write_index(ltfs_ip_id(priv->vol), SYNC_WRITE_PERM, LTFS_FULL_INDEX, priv->vol); return ret; } diff --git a/src/libltfs/arch/errormap.c b/src/libltfs/arch/errormap.c index 9c5f34b6..8459c23a 100644 --- a/src/libltfs/arch/errormap.c +++ b/src/libltfs/arch/errormap.c @@ -342,6 +342,7 @@ static struct error_map fuse_error_list[] = { { LTFS_XML_WRONG_PART_MAP, "I5048E", EINVAL}, { LTFS_XML_WRONG_BLOCKSIZE, "I5049E", EINVAL}, { LTFS_XML_WRONG_COMP, "I5050E", EINVAL}, + { LTFS_BAD_INDEX_TYPE, "I5051E", EINVAL}, { EDEV_NO_SENSE, "D0000E", EIO}, { EDEV_OVERRUN, "D0002E", EIO}, { EDEV_UNDERRUN, "D0003E", ENODATA}, diff --git a/src/libltfs/inc_journal.c b/src/libltfs/inc_journal.c index 67712f92..9c4386e0 100644 --- a/src/libltfs/inc_journal.c +++ b/src/libltfs/inc_journal.c @@ -57,22 +57,24 @@ static int _allocate_jentry(struct jentry **e, char *path, struct dentry* d) { struct jentry *ent = NULL; + *e = NULL; ent = calloc(1, sizeof(struct jentry)); if (!ent) { - ltfsmsg(LTFS_ERR, 11168E); + ltfsmsg(LTFS_ERR, 10001E, "allocating a jentry"); return -LTFS_NO_MEMORY; } ent->id.full_path = path; ent->id.uid = d->uid; + *e = ent; return 0; } -static int _dispose_jentry(struct jentry *ent) +static inline int _dispose_jentry(struct jentry *ent) { if (ent) { if (ent->id.full_path) @@ -115,7 +117,7 @@ int incj_create(char *ppath, struct dentry *d, struct ltfs_volume *vol) /* Create full path of created object and jentry */ len = asprintf(&full_path, "%s/%s", ppath, d->name.name); if (len < 0) { - ltfsmsg(LTFS_ERR, 11168E); + ltfsmsg(LTFS_ERR, 10001E, "full path of a jentry"); vol->journal_err = true; return -LTFS_NO_MEMORY; } @@ -135,7 +137,7 @@ int incj_create(char *ppath, struct dentry *d, struct ltfs_volume *vol) if (d->isdir) { jdir = calloc(1, sizeof(struct jcreated_entry)); if (!jdir) { - ltfsmsg(LTFS_ERR, 11168E); + ltfsmsg(LTFS_ERR, 10001E, "allocating a jcreated_entry"); return -LTFS_NO_MEMORY; } @@ -169,7 +171,7 @@ int incj_modify(char *path, struct dentry *d, struct ltfs_volume *vol) } /* Skip journal modification because it is already existed */ - HASH_FIND(hh, vol->journal, &ent->id, sizeof(struct jentry), ent); + HASH_FIND(hh, vol->journal, &d->uid, sizeof(struct jentry), ent); if (ent) { return 0; } @@ -247,10 +249,10 @@ int incj_rmfile(char *path, struct dentry *d, struct ltfs_volume *vol) } } - /* Create full path of created object and jentry */ + /* Create full path of deleted object and jentry */ full_path = strdup(path); if (!full_path) { - ltfsmsg(LTFS_ERR, 11168E); + ltfsmsg(LTFS_ERR, 10001E, "duplicating a path for deleted file"); vol->journal_err = true; return -LTFS_NO_MEMORY; } @@ -262,6 +264,13 @@ int incj_rmfile(char *path, struct dentry *d, struct ltfs_volume *vol) } ent->reason = DELETE_FILE; + ent->name.percent_encode = d->name.percent_encode; + ent->name.name = strdup(d->name.name); + if (!ent->name.name) { + ltfsmsg(LTFS_ERR, 10001E, "duplicating a name of deleted file"); + vol->journal_err = true; + return -LTFS_NO_MEMORY; + } HASH_ADD(hh, vol->journal, id, sizeof(struct jentry), ent); @@ -320,7 +329,7 @@ int incj_rmdir(char *path, struct dentry *d, struct ltfs_volume *vol) /* Create full path of created object and jentry */ full_path = strdup(path); if (!full_path) { - ltfsmsg(LTFS_ERR, 11168E); + ltfsmsg(LTFS_ERR, 10001E, "duplicating a path of deleted directory"); vol->journal_err = true; return -LTFS_NO_MEMORY; } @@ -332,12 +341,24 @@ int incj_rmdir(char *path, struct dentry *d, struct ltfs_volume *vol) } ent->reason = DELETE_DIRECTORY; + ent->name.percent_encode = d->name.percent_encode; + ent->name.name = strdup(d->name.name); + if (!ent->name.name) { + ltfsmsg(LTFS_ERR, 10001E, "duplicating a name of deleted directory"); + vol->journal_err = true; + return -LTFS_NO_MEMORY; + } HASH_ADD(hh, vol->journal, id, sizeof(struct jentry), ent); return 0; } +int incj_dispose_jentry(struct jentry *ent) +{ + return (_dispose_jentry(ent)); +} + /** * Clear all entries into the incremental journal */ @@ -394,6 +415,11 @@ static inline int dig_path(char *p, struct ltfs_index *idx) return ret; } +void incj_sort(struct ltfs_volume *vol) +{ + HASH_SORT(vol->journal, _by_path); +} + /** * This is a function for debug. Print contents of the journal and the created * directory list to stdout. @@ -412,7 +438,7 @@ void incj_dump(struct ltfs_volume *vol) } printf("--------------------------------------------------------------------------------\n"); - HASH_SORT(vol->journal, _by_path); + incj_sort(vol); HASH_ITER(hh, vol->journal, ent, tmp) { printf("JOURNAL: %s, %llu, %s, ", ent->id.full_path, (unsigned long long)ent->id.uid, reason[ent->reason]); if (!ent->dentry) @@ -425,7 +451,7 @@ void incj_dump(struct ltfs_volume *vol) } else printf("file\n"); - parent= strdup(ent->id.full_path); + parent = strdup(ent->id.full_path); fs_split_path(parent, &filename, strlen(parent) + 1); if (prev_parent) { @@ -448,3 +474,234 @@ void incj_dump(struct ltfs_volume *vol) return; } + +int incj_create_path_helper(const char *dpath, struct incj_path_helper **pm, struct ltfs_volume *vol) +{ + struct incj_path_helper *ipm; + char *wp = NULL, *tmp = NULL, *dname = NULL; + int ret = 0; + + *pm = NULL; + + ipm = calloc(1, sizeof(struct incj_path_helper)); + if (!ipm) { + ltfsmsg(LTFS_ERR, 10001E, "allocating a path helper"); + return -LTFS_NO_MEMORY; + } + + if (dpath[0] != '/') { + /* Provided path must be a absolute path */ + ltfsmsg(LTFS_ERR, 17302E, dpath); + free(ipm); + return -LTFS_INVALID_PATH; + } + + ipm->vol = vol; + + if (strcmp(dpath, "/") == 0) { + /* Provided path is the root, return good */ + *pm = ipm; + return 0; + } + + wp = strdup(dpath); + if (!wp) { + ltfsmsg(LTFS_ERR, 10001E, "duplicating a directory path for path helper"); + free(ipm); + return -LTFS_NO_MEMORY; + } + + for (dname = strtok_r(wp, "/", &tmp); dname != NULL; dname = strtok_r(NULL, "/", &tmp)) { + ret = incj_push_directory(dname, ipm); + if (ret < 0) { + ltfsmsg(LTFS_ERR, 17305E, ret); + free(wp); + incj_destroy_path_helper(ipm); + return ret; + } + } + + free(wp); + *pm = ipm; + + return 0; +} + +int incj_destroy_path_helper(struct incj_path_helper *pm) +{ + struct incj_path_element *cur, *next; + + cur = pm->head; + + while (cur) { + next = cur->next; + if (cur->d) + fs_release_dentry(cur->d); + if (cur->name) + free(cur->name); + free(cur); + cur = next; + } + + free(pm); + return 0; +} + +int incj_push_directory(char *name, struct incj_path_helper *pm) +{ + int ret = 0; + struct incj_path_element *ipelm = NULL, *cur_tail = NULL; + struct dentry *parent = NULL; + + ipelm = calloc(1, sizeof(struct incj_path_element)); + if (!ipelm) { + ltfsmsg(LTFS_ERR, 10001E, "allocating a path element on push"); + return -LTFS_NO_MEMORY; + } + + /* Set name field of new path element */ + ipelm->name = strdup(name); + if (!ipelm->name) { + ltfsmsg(LTFS_ERR, 10001E, "duplicating a path of pushing directory"); + incj_destroy_path_helper(pm); + return -LTFS_NO_MEMORY; + } + + /* Set dentry field of new path element */ + if (pm->elems) + parent = pm->tail->d; + else + parent = pm->vol->index->root; + + ret = fs_directory_lookup(parent, name, &ipelm->d); + if (ret) { + ltfsmsg(LTFS_ERR, 17306E, ret); + free(ipelm->name); + free(ipelm); + incj_destroy_path_helper(pm); + return -LTFS_INVALID_PATH; + } + + /* Modify path chain and # of elements */ + if (!pm->elems) { + pm->head = ipelm; + pm->tail = ipelm; + } else { + cur_tail = pm->tail; + cur_tail->next = ipelm; + ipelm->prev = cur_tail; + pm->tail = ipelm; + } + + pm->elems++; + + return 0; +} + +int incj_pop_directory(struct incj_path_helper *pm) +{ + struct incj_path_element *cur_tail = NULL, *new_tail = NULL; + + if (!pm->elems) { + /* Must have one or more elements */ + return -LTFS_UNEXPECTED_VALUE; + } + + cur_tail = pm->tail; + new_tail = cur_tail->prev; + + new_tail->next = NULL; + pm->tail = new_tail; + + pm->elems--; + if (!pm->elems) { + pm->head = NULL; + } + + if (cur_tail->d) + fs_release_dentry(cur_tail->d); + if (cur_tail->name) + free(cur_tail->name); + free(cur_tail); + + return 0; +} + +int incj_compare_path(struct incj_path_helper *now, struct incj_path_helper *next, + int *matches, int *pops, bool *perfect_match) +{ + int ret = 0, matched = 0; + struct incj_path_element *cur1 = NULL, *cur2 = NULL; + + *matches = 0; + *pops = 0; + *perfect_match = false; + + cur1 = now->head; + cur2 = next->head; + + if (!cur1 && !cur2) { + /* Both are root */ + *perfect_match = true; + return 0; + } + + while (cur1 && cur2) { + if (cur1->d != cur2->d) + break; + matched++; + cur1 = cur1->next; + cur2 = cur2->next; + } + + *matches = matched; + *pops = now->elems - *matches; + + if (!cur1 && !cur2) + *perfect_match = true; + + return ret; +} + +char* incj_get_path(struct incj_path_helper *pm) +{ + char *path = NULL, *path_old = NULL; + struct incj_path_element *cur = NULL; + int ret = 0; + + cur = pm->head; + + if (!cur) { + /* Root directory */ + ret = asprintf(&path, "/"); + if (ret < 0) { + /* memory allocation error */ + return NULL; + } + return path; + } + + while (cur) { + if (path) path_old = path; + ret = asprintf(&path, "%s/%s", path_old, cur->name); + if (ret < 0) { + /* memory allocation error */ + free(path_old); + return NULL; + } + free(path_old); + + cur++; + } + + if (path) path_old = path; + ret = asprintf(&path, "/%s", path_old); + if (ret < 0) { + /* memory allocation error */ + free(path_old); + return NULL; + } + free(path_old); + + return path; +} diff --git a/src/libltfs/inc_journal.h b/src/libltfs/inc_journal.h index 1b4b1b2f..14784857 100644 --- a/src/libltfs/inc_journal.h +++ b/src/libltfs/inc_journal.h @@ -81,9 +81,10 @@ struct journal_id { * Journal entry */ struct jentry { - struct journal_id id; /**< ID of the journal entry (key of the hash table) */ - enum journal_reason reason; /**< Reason of the entry */ - struct dentry *dentry; /**< Target dentry if required */ + struct journal_id id; /**< ID of the journal entry (key of the hash table) */ + enum journal_reason reason; /**< Reason of the entry */ + struct dentry *dentry; /**< Target dentry if required */ + struct ltfs_name name; /**< Name of entry for delete */ UT_hash_handle hh; }; @@ -95,13 +96,40 @@ struct jcreated_entry { char *path; }; +/** + * + */ +struct incj_path_element { + struct incj_path_element *prev; + struct incj_path_element *next; + char* name; + struct dentry *d; +}; + +struct incj_path_helper { + struct incj_path_element *head; + struct incj_path_element *tail; + struct ltfs_volume *vol; + unsigned int elems; +}; + int incj_create(char *ppath, struct dentry *d, struct ltfs_volume *vol); int incj_modify(char *path, struct dentry *d, struct ltfs_volume *vol); int incj_rmfile(char *path, struct dentry *d, struct ltfs_volume *vol); int incj_rmdir(char *path, struct dentry *d, struct ltfs_volume *vol); +int incj_dispose_jentry(struct jentry *ent); int incj_clear(struct ltfs_volume *vol); +void incj_sort(struct ltfs_volume *vol); void incj_dump(struct ltfs_volume *vol); +int incj_create_path_helper(const char *path, struct incj_path_helper **pm, struct ltfs_volume *vol); +int incj_destroy_path_helper(struct incj_path_helper *pm); +int incj_push_directory(char *name, struct incj_path_helper *pm); +int incj_pop_directory(struct incj_path_helper *pm); +int incj_compare_path(struct incj_path_helper *p1, struct incj_path_helper *p2, + int *matches, int *pops, bool *perfect_match); +char* incj_get_path(struct incj_path_helper *pm); + #ifdef __cplusplus } #endif diff --git a/src/libltfs/ltfs.c b/src/libltfs/ltfs.c index 40624c6e..baa7aae3 100644 --- a/src/libltfs/ltfs.c +++ b/src/libltfs/ltfs.c @@ -1780,7 +1780,7 @@ int ltfs_mount(bool force_full, bool deep_recovery, bool recover_extra, bool rec INTERRUPTED_GOTO(ret, out_unlock); ltfsmsg(LTFS_INFO, 11022I); ltfs_set_commit_message_reason(SYNC_RECOVERY, vol); - ret = ltfs_write_index(vol->label->partid_ip, SYNC_RECOVERY, vol); + ret = ltfs_write_index(vol->label->partid_ip, SYNC_RECOVERY, LTFS_FULL_INDEX, vol); if (ret < 0) goto out_unlock; } @@ -2073,7 +2073,7 @@ int ltfs_unmount(char *reason, struct ltfs_volume *vol) if (vol->mount_type == MOUNT_NORMAL && (ltfs_is_dirty(vol) || vol->index->selfptr.partition != ltfs_ip_id(vol)) && (vollock != PWE_MAM_IP && vollock != PWE_MAM_BOTH)) { - ret = ltfs_write_index(ltfs_ip_id(vol), reason, vol); + ret = ltfs_write_index(ltfs_ip_id(vol), reason, LTFS_FULL_INDEX, vol); if (NEED_REVAL(ret)) { ret = ltfs_revalidate(true, vol); if (ret == 0) { @@ -2435,13 +2435,15 @@ size_t ltfs_max_cache_size(struct ltfs_volume *vol) * when the cartridge is known to be in a sane state. * The caller must hold vol->lock for write if thread safety is required. * @param partition partition in which the schema should be written to + * @param reason the reason to write down an index + * @param type type of index to write (shall be LTFS_FULL_INDEX or LTFS_INCREMENTAL_INDEX) * @param vol LTFS volume * @return 0 on success or a negative value on error */ -int ltfs_write_index(char partition, char *reason, struct ltfs_volume *vol) +int ltfs_write_index(char partition, char *reason, enum ltfs_index_type type, struct ltfs_volume *vol) { int ret, ret_mam; - struct tape_offset old_selfptr, old_backptr; + struct tape_offset old_selfptr, old_backptr, old_selfptr_inc, old_backptr_inc; struct ltfs_timespec modtime_old = { .tv_sec = 0, .tv_nsec = 0 }; bool generation_inc = false; struct tc_position physical_selfptr; @@ -2459,7 +2461,30 @@ int ltfs_write_index(char partition, char *reason, struct ltfs_volume *vol) return ret; } - incj_clear(vol); /* Clear incremental journal data */ + if (type == LTFS_INDEX_AUTO) { + if (vol->index->full_index_interval) { + if (vol->index->full_index_to_go) + type = LTFS_INCREMENTAL_INDEX; + else + type = LTFS_FULL_INDEX; + } else { + type = LTFS_FULL_INDEX; + } + } + + switch (type) { + case LTFS_FULL_INDEX: + if (vol->index->full_index_interval) + vol->index->full_index_to_go = vol->index->full_index_interval; + break; + case LTFS_INCREMENTAL_INDEX: + if (vol->index->full_index_interval && vol->index->full_index_to_go) + vol->index->full_index_to_go--; + break; + default: + /* TODO: Unexpected index type error */ + break; + } bc_print = _get_barcode(vol); @@ -2497,7 +2522,10 @@ int ltfs_write_index(char partition, char *reason, struct ltfs_volume *vol) /* Surpress on-disk index cache write on the recursive call */ cache_path_save = vol->index_cache_path_w; vol->index_cache_path_w = NULL; - ret = ltfs_write_index(ltfs_dp_id(vol), reason, vol); + + type = LTFS_FULL_INDEX; + incj_clear(vol); /* Clear incremental journal data */ + ret = ltfs_write_index(ltfs_dp_id(vol), reason, type, vol); /* Restore cache path to handle on-disk index cache */ vol->index_cache_path_w = cache_path_save; @@ -2536,10 +2564,10 @@ int ltfs_write_index(char partition, char *reason, struct ltfs_volume *vol) /* update index generation */ if (ltfs_is_dirty(vol)) { - modtime_old = vol->index->mod_time; generation_inc = true; - get_current_timespec(&vol->index->mod_time); ++vol->index->generation; + modtime_old = vol->index->mod_time; + get_current_timespec(&vol->index->mod_time); } /* locate to append position */ @@ -2554,38 +2582,61 @@ int ltfs_write_index(char partition, char *reason, struct ltfs_volume *vol) } /* update back pointer */ - old_backptr = vol->index->backptr; - if (vol->index->selfptr.partition == ltfs_dp_id(vol)) - memcpy(&vol->index->backptr, &vol->index->selfptr, sizeof(struct tape_offset)); + if (type == LTFS_FULL_INDEX) { + old_backptr = vol->index->backptr; + if (vol->index->selfptr.partition == ltfs_dp_id(vol)) + memcpy(&vol->index->backptr, &vol->index->selfptr, sizeof(struct tape_offset)); + } else { + old_backptr_inc = vol->index->backptr_inc; + memcpy(&vol->index->backptr_inc, &vol->index->selfptr_inc, sizeof(struct tape_offset)); + } /* update self pointer */ ret = tape_get_position(vol->device, &physical_selfptr); if (ret < 0) { ltfsmsg(LTFS_ERR, 11081E, ret); - if (generation_inc) { - vol->index->mod_time = modtime_old; - --vol->index->generation; + if (type == LTFS_FULL_INDEX) { + if (generation_inc) { + vol->index->mod_time = modtime_old; + --vol->index->generation; + } + vol->index->backptr = old_backptr; + } else { + vol->index->backptr_inc = old_backptr_inc; } - vol->index->backptr = old_backptr; goto out_write_perm; } - old_selfptr = vol->index->selfptr; - vol->index->selfptr.partition = partition; - vol->index->selfptr.partition = vol->label->part_num2id[physical_selfptr.partition]; - vol->index->selfptr.block = physical_selfptr.block; - ++vol->index->selfptr.block; /* point to first data block, not preceding filemark */ + + if (type == LTFS_FULL_INDEX) { + old_selfptr = vol->index->selfptr; + vol->index->selfptr.partition = partition; + vol->index->selfptr.partition = vol->label->part_num2id[physical_selfptr.partition]; + vol->index->selfptr.block = physical_selfptr.block; + ++vol->index->selfptr.block; /* point to first data block, not preceding filemark */ + } else { + old_selfptr_inc = vol->index->selfptr_inc; + vol->index->selfptr_inc.partition = partition; + vol->index->selfptr_inc.partition = vol->label->part_num2id[physical_selfptr.partition]; + vol->index->selfptr_inc.block = physical_selfptr.block; + ++vol->index->selfptr_inc.block; /* point to first data block, not preceding filemark */ + } /* Write the Index. */ if ((partition == ltfs_ip_id(vol)) && !vol->ip_index_file_end) { ret = tape_write_filemark(vol->device, 0, true, true, false); // Flush data before writing FM if (ret < 0) { ltfsmsg(LTFS_ERR, 11326E, ret); - if (generation_inc) { - vol->index->mod_time = modtime_old; - --vol->index->generation; + if (type == LTFS_FULL_INDEX) { + if (generation_inc) { + vol->index->mod_time = modtime_old; + --vol->index->generation; + } + vol->index->backptr = old_backptr; + vol->index->selfptr = old_selfptr; + } else { + vol->index->backptr_inc = old_backptr_inc; + vol->index->selfptr_inc = old_selfptr_inc; } - vol->index->backptr = old_backptr; - vol->index->selfptr = old_selfptr; if (IS_WRITE_PERM(-ret)) update_vollock = true; @@ -2600,12 +2651,18 @@ int ltfs_write_index(char partition, char *reason, struct ltfs_volume *vol) ret = tape_write_filemark(vol->device, 1, true, true, true); // immediate WFM if (ret < 0) { ltfsmsg(LTFS_ERR, 11082E, ret); - if (generation_inc) { - vol->index->mod_time = modtime_old; - --vol->index->generation; + + if (type == LTFS_FULL_INDEX) { + if (generation_inc) { + vol->index->mod_time = modtime_old; + --vol->index->generation; + } + vol->index->backptr = old_backptr; + vol->index->selfptr = old_selfptr; + } else { + vol->index->backptr_inc = old_backptr_inc; + vol->index->selfptr_inc = old_selfptr_inc; } - vol->index->backptr = old_backptr; - vol->index->selfptr = old_selfptr; if (IS_WRITE_PERM(-ret)) update_vollock = true; @@ -2614,15 +2671,21 @@ int ltfs_write_index(char partition, char *reason, struct ltfs_volume *vol) } /* Actually write index to tape and disk if vol->index_cache_path is existed */ - ret = xml_schema_to_tape(reason, vol); + ret = xml_schema_to_tape(reason, type, vol); if (ret < 0) { ltfsmsg(LTFS_ERR, 11083E, ret); - if (generation_inc) { - vol->index->mod_time = modtime_old; - --vol->index->generation; + + if (type == LTFS_FULL_INDEX) { + if (generation_inc) { + vol->index->mod_time = modtime_old; + --vol->index->generation; + } + vol->index->backptr = old_backptr; + vol->index->selfptr = old_selfptr; + } else { + vol->index->backptr_inc = old_backptr_inc; + vol->index->selfptr_inc = old_selfptr_inc; } - vol->index->backptr = old_backptr; - vol->index->selfptr = old_selfptr; if (IS_WRITE_PERM(-ret)) update_vollock = true; @@ -2630,38 +2693,60 @@ int ltfs_write_index(char partition, char *reason, struct ltfs_volume *vol) goto out_write_perm; } - /* Update MAM parameters. */ - if (partition == ltfs_ip_id(vol)) - vol->ip_index_file_end = true; - else /* partition == ltfs_dp_id(vol) */ - vol->dp_index_file_end = true; + if (type == LTFS_FULL_INDEX) { + /* Update MAM parameters. */ + if (partition == ltfs_ip_id(vol)) + vol->ip_index_file_end = true; + else /* partition == ltfs_dp_id(vol) */ + vol->dp_index_file_end = true; + + /* The MAM may be inaccessible, or it may not be available on this medium. Either way, + * ignore failures when updating MAM parameters. */ + ltfs_update_cart_coherency(vol); + + ltfsmsg(LTFS_INFO, 17236I, + bc_print, + (unsigned long long)vol->index->generation, + vol->index->selfptr.partition, + (unsigned long long)vol->index->selfptr.block, + tape_get_serialnumber(vol->device)); + + /* update append position */ + if (partition == ltfs_ip_id(vol)) { + tape_set_ip_append_position(vol->device, ltfs_part_id2num(partition, vol), + vol->index->selfptr.block - 1); + } - /* The MAM may be inaccessible, or it may not be available on this medium. Either way, - * ignore failures when updating MAM parameters. */ - ltfs_update_cart_coherency(vol); + if (dcache_initialized(vol)) { + dcache_set_dirty(false, vol); + if (generation_inc) { + dcache_set_generation(vol->index->generation, vol); + } + } - ltfsmsg(LTFS_INFO, 17236I, - bc_print, - (unsigned long long)vol->index->generation, - vol->index->selfptr.partition, - (unsigned long long)vol->index->selfptr.block, - tape_get_serialnumber(vol->device)); + /* Clear incremental index metrix */ + vol->index->backptr_inc.partition = 0; + vol->index->backptr_inc.block = 0; + vol->index->selfptr_inc.partition = 0; + vol->index->selfptr_inc.block = 0; - /* update append position */ - if (partition == ltfs_ip_id(vol)) { - tape_set_ip_append_position(vol->device, ltfs_part_id2num(partition, vol), - vol->index->selfptr.block - 1); - } - - if (dcache_initialized(vol)) { - dcache_set_dirty(false, vol); - if (generation_inc) { - dcache_set_generation(vol->index->generation, vol); - } + incj_clear(vol); /* Clear incremental journal data */ + ltfs_unset_index_dirty(true, vol->index); + } else { + ltfsmsg(LTFS_INFO, 17300I, + bc_print, + (unsigned long long)vol->index->generation, + vol->index->selfptr_inc.partition, + (unsigned long long)vol->index->selfptr_inc.block, + tape_get_serialnumber(vol->device)); + ltfsmsg(LTFS_INFO, 17301I, + (unsigned long long)vol->index->generation, + vol->index->backptr.partition, + (unsigned long long)vol->index->backptr.block, + vol->index->backptr_inc.partition, + (unsigned long long)vol->index->backptr_inc.block); } - ltfs_unset_index_dirty(true, vol->index); - out_write_perm: if (write_perm) { /* Restore device->write_error flag that is disabled to handle a write perm on DP */ @@ -3133,7 +3218,7 @@ int ltfs_format_tape(struct ltfs_volume *vol, int density_code, bool destructive return ret; ltfsmsg(LTFS_INFO, 11278I, vol->label->partid_dp); /* "Writing Index to ..." */ ltfs_set_commit_message_reason(SYNC_FORMAT, vol); - ret = ltfs_write_index(vol->label->partid_dp, SYNC_FORMAT, vol); + ret = ltfs_write_index(vol->label->partid_dp, SYNC_FORMAT, LTFS_FULL_INDEX, vol); if (ret < 0) { ltfsmsg(LTFS_ERR, 11279E, vol->label->partid_dp, ret); return ret; @@ -3146,7 +3231,7 @@ int ltfs_format_tape(struct ltfs_volume *vol, int density_code, bool destructive if (ret < 0) return ret; ltfsmsg(LTFS_INFO, 11278I, vol->label->partid_ip); /* "Writing Index to ..." */ - ret = ltfs_write_index(vol->label->partid_ip, SYNC_FORMAT, vol); + ret = ltfs_write_index(vol->label->partid_ip, SYNC_FORMAT, LTFS_FULL_INDEX, vol); if (ret < 0) { ltfsmsg(LTFS_ERR, 11279E, vol->label->partid_ip, ret); return ret; @@ -3547,11 +3632,13 @@ int ltfs_revalidate(bool have_write_lock, struct ltfs_volume *vol) /** * Write index to tape if the index is dirty, and if there is space available * on the data partition. - * @param vol LTFS volume + * @param reason the reason to write an index * @param index_locking Take index lock while writing an index + * @param type index type to write + * @param vol LTFS volume * @return 0 on success or a negative value on error */ -int ltfs_sync_index(char *reason, bool index_locking, struct ltfs_volume *vol) +int ltfs_sync_index(char *reason, bool index_locking, enum ltfs_index_type type, struct ltfs_volume *vol) { int ret = 0, ret_r = 0; bool dirty; @@ -3559,6 +3646,10 @@ int ltfs_sync_index(char *reason, bool index_locking, struct ltfs_volume *vol) bool dp_index_file_end, ip_index_file_end; char *bc_print = NULL; +#ifndef FORMAT_SPEC25 + type = LTFS_FULL_INDEX; +#endif + start: ret = ltfs_get_partition_readonly(ltfs_dp_id(vol), vol); if (ret < 0 && ret != -LTFS_LESS_SPACE) @@ -3613,7 +3704,7 @@ int ltfs_sync_index(char *reason, bool index_locking, struct ltfs_volume *vol) releasewrite_mrsw(&vol->lock); return ret; } - ret = ltfs_write_index(partition, reason, vol); + ret = ltfs_write_index(partition, reason, type, vol); if (IS_WRITE_PERM(-ret) && partition == ltfs_dp_id(vol)) { /* * TODO: Need to determine the last record on DP of the tape and cleanup @@ -3630,7 +3721,7 @@ int ltfs_sync_index(char *reason, bool index_locking, struct ltfs_volume *vol) * request. */ ltfs_set_commit_message_reason(SYNC_WRITE_PERM, vol); - ret_r = ltfs_write_index(ltfs_ip_id(vol), SYNC_WRITE_PERM, vol); + ret_r = ltfs_write_index(ltfs_ip_id(vol), SYNC_WRITE_PERM, LTFS_FULL_INDEX, vol); if (!ret_r) { ltfsmsg(LTFS_INFO, 11344I, bc_print); ret = -LTFS_SYNC_FAIL_ON_DP; diff --git a/src/libltfs/ltfs.h b/src/libltfs/ltfs.h index 18f4b2dd..ec518f1a 100644 --- a/src/libltfs/ltfs.h +++ b/src/libltfs/ltfs.h @@ -154,16 +154,34 @@ struct device_data; #define LTFS_LABEL_VERSION_MIN MAKE_LTFS_VERSION(1,0,0) /* Min supported label version */ #define LTFS_LABEL_VERSION_MAX MAKE_LTFS_VERSION(2,99,99) /* Max supported label version */ + +#ifdef FORMAT_SPEC25 +#define LTFS_LABEL_VERSION MAKE_LTFS_VERSION(2,5,0) /* Written label version */ +#define LTFS_LABEL_VERSION_STR "2.5.0" /* Label version string */ +#else #define LTFS_LABEL_VERSION MAKE_LTFS_VERSION(2,4,0) /* Written label version */ #define LTFS_LABEL_VERSION_STR "2.4.0" /* Label version string */ +#endif #define LTFS_INDEX_VERSION_MIN MAKE_LTFS_VERSION(1,0,0) /* Min supported index version */ #define LTFS_INDEX_VERSION_MAX MAKE_LTFS_VERSION(2,99,99) /* Max supported index version */ + +#ifdef FORMAT_SPEC25 +#define LTFS_INDEX_VERSION MAKE_LTFS_VERSION(2,5,0) /* Written index version */ +#define LTFS_INDEX_VERSION_STR "2.5.0" /* Index version string */ +#else #define LTFS_INDEX_VERSION MAKE_LTFS_VERSION(2,4,0) /* Written index version */ #define LTFS_INDEX_VERSION_STR "2.4.0" /* Index version string */ +#endif #define INDEX_MAX_COMMENT_LEN 65536 /* Maximum comment field length (per LTFS Format) */ +enum ltfs_index_type { + LTFS_INDEX_AUTO = 0, /**< Select index type to write based on specified options */ + LTFS_FULL_INDEX, /**< Forcibly write full index */ + LTFS_INCREMENTAL_INDEX /**< Forcibly write incremental index */ +}; + #define LTFS_NO_BARCODE "NO_BARCODE" #ifndef __APPLE_MAKEFILE__ @@ -363,7 +381,7 @@ typedef enum mam_advisory_lock_status { PWE_MAM_IP = 5, /* Single write perm on IP (Set VOL_IP_PERM__ERR) */ PWE_MAM_BOTH = 6, /* Double write perm (Set both VOL_DP_PERM_ERR and VOL_IP_PERM_ERR) */ NOLOCK_MAM = 128, /* From HPE */ -} mam_lockval; +} mam_lockval_t; #define IS_SINGLE_WRITE_PERM(stat) (stat == PWE_MAM || (stat == PWE_MAM_DP || stat == PWE_MAM_IP) ) #define IS_DOUBLE_WRITE_PERM(stat) (stat == PWE_MAM_BOTH) @@ -456,7 +474,7 @@ struct ltfs_volume { char *mountpoint; /**< Store mount point for Live Link (SDE) */ size_t mountpoint_len; /**< Store mount point path length (SDE) */ struct tape_attr *t_attr; /**< Tape Attribute data */ - mam_lockval lock_status; /**< Total volume lock status from t_attr->vollock and index->vollock */ + mam_lockval_t lock_status; /**< Total volume lock status from t_attr->vollock and index->vollock */ struct ltfs_timespec first_locate; /**< Time to first locate */ int file_open_count; /**< Number of opened files */ @@ -520,10 +538,10 @@ struct ltfs_index { struct index_criteria index_criteria; /**< Active index criteria */ struct dentry *root; /**< The directory tree */ - ltfs_mutex_t rename_lock; /**< Controls name tree access during renames */ + ltfs_mutex_t rename_lock; /**< Controls name tree access during renames */ /* Update tracking */ - ltfs_mutex_t dirty_lock; /**< Controls access to the update tracking bits */ + ltfs_mutex_t dirty_lock; /**< Controls access to the update tracking bits */ bool dirty; /**< Set on metadata update, cleared on write to tape */ bool atime_dirty; /**< Set on atime update, cleared on write to tape */ bool use_atime; /**< Set if atime updates should make the index dirty */ @@ -542,7 +560,13 @@ struct ltfs_index { size_t symerr_count; /**< Number of conflicted symlink dentries */ struct dentry **symlink_conflict; /**< symlink/extent conflicted dentries */ - mam_lockval vollock; /**< volume lock status on index */ + mam_lockval_t vollock; /**< volume lock status on index */ + + /* Incremental index */ + uint64_t full_index_interval; /**< Number of indexes between full indexes */ + uint64_t full_index_to_go; /**< How many incremental index shall be written to the next full index */ + struct tape_offset selfptr_inc; /**< self-pointer of previous incremental index (to prior generation on data partition) */ + struct tape_offset backptr_inc; /**< back pointer of previous incremental index (to prior generation on data partition) */ }; struct ltfs_direntry { @@ -697,14 +721,14 @@ int ltfs_parse_library_backend_opts(void *opt_args, void *opts); void ltfs_set_index_dirty(bool locking, bool atime, struct ltfs_index *idx); void ltfs_unset_index_dirty(bool update_version, struct ltfs_index *idx); -int ltfs_write_index(char partition, char *reason, struct ltfs_volume *vol); +int ltfs_write_index(char partition, char *reason, enum ltfs_index_type type, struct ltfs_volume *vol); int ltfs_save_index_to_disk(const char *work_dir, char *reason, char id, struct ltfs_volume *vol); char ltfs_dp_id(struct ltfs_volume *vol); char ltfs_ip_id(struct ltfs_volume *vol); const char *ltfs_get_volume_uuid(struct ltfs_volume *vol); -int ltfs_sync_index(char *reason, bool index_locking, struct ltfs_volume *vol); +int ltfs_sync_index(char *reason, bool index_locking, enum ltfs_index_type type, struct ltfs_volume *vol); int ltfs_traverse_index_forward(struct ltfs_volume *vol, char partition, unsigned int gen, bool skip_dir, f_index_found func, void **list, void *priv); diff --git a/src/libltfs/ltfs_error.h b/src/libltfs/ltfs_error.h index ab661262..703b6324 100644 --- a/src/libltfs/ltfs_error.h +++ b/src/libltfs/ltfs_error.h @@ -317,6 +317,7 @@ #define LTFS_XML_WRONG_PART_MAP 5048 /* Unexpected partition map in a label */ #define LTFS_XML_WRONG_BLOCKSIZE 5049 /* Unexpected blocksize in a label */ #define LTFS_XML_WRONG_COMP 5050 /* Unexpected compression in a label */ +#define LTFS_BAD_INDEX_TYPE 5051 /* Unsupported index type is specified */ #define LTFS_ERR_MAX 19999 diff --git a/src/libltfs/ltfs_fsops.c b/src/libltfs/ltfs_fsops.c index be046720..98868d41 100644 --- a/src/libltfs/ltfs_fsops.c +++ b/src/libltfs/ltfs_fsops.c @@ -2110,7 +2110,7 @@ int ltfs_fsops_volume_sync(char *reason, struct ltfs_volume *vol) ltfs_set_commit_message_reason_unlocked(reason, vol); ltfs_mutex_unlock(&vol->index->dirty_lock); - ret = ltfs_sync_index(reason, true, vol); + ret = ltfs_sync_index(reason, true, LTFS_INDEX_AUTO, vol); return ret; } diff --git a/src/libltfs/ltfs_internal.c b/src/libltfs/ltfs_internal.c index cbd78c74..028e32bf 100644 --- a/src/libltfs/ltfs_internal.c +++ b/src/libltfs/ltfs_internal.c @@ -1326,11 +1326,11 @@ int ltfs_check_medium(bool fix, bool deep, bool recover_extra, bool recover_syml ltfs_set_commit_message_reason(SYNC_RECOVERY, vol); if (! dp_have_index || dp_blocks_after) { ltfsmsg(LTFS_INFO, 17259I, "DP", vol->index->selfptr.partition, (unsigned long long)vol->index->selfptr.block); - ret = ltfs_write_index(vol->label->partid_dp, SYNC_RECOVERY, vol); + ret = ltfs_write_index(vol->label->partid_dp, SYNC_RECOVERY, LTFS_FULL_INDEX, vol); } if (!ret) { ltfsmsg(LTFS_INFO, 17259I, "IP", vol->index->selfptr.partition, (unsigned long long)vol->index->selfptr.block); - ltfs_write_index(vol->label->partid_ip, SYNC_RECOVERY, vol); + ltfs_write_index(vol->label->partid_ip, SYNC_RECOVERY, LTFS_FULL_INDEX, vol); } } else { ltfsmsg(LTFS_ERR, 11231E); @@ -1410,12 +1410,12 @@ int ltfs_write_index_conditional(char partition, struct ltfs_volume *vol) if (partition == ltfs_ip_id(vol) && ! vol->ip_index_file_end) { ltfs_set_commit_message_reason(SYNC_CASCHE_PRESSURE, vol); - ret = ltfs_write_index(partition, SYNC_CASCHE_PRESSURE, vol); + ret = ltfs_write_index(partition, SYNC_CASCHE_PRESSURE, LTFS_FULL_INDEX, vol); } else if (partition == ltfs_dp_id(vol) && (! vol->dp_index_file_end || (vol->ip_index_file_end && vol->index->selfptr.partition == ltfs_ip_id(vol)))) { ltfs_set_commit_message_reason(SYNC_CASCHE_PRESSURE, vol); - ret = ltfs_write_index(partition, SYNC_CASCHE_PRESSURE, vol); + ret = ltfs_write_index(partition, SYNC_CASCHE_PRESSURE, LTFS_FULL_INDEX, vol); } return ret; diff --git a/src/libltfs/periodic_sync.c b/src/libltfs/periodic_sync.c index f11740c7..4edca3ef 100644 --- a/src/libltfs/periodic_sync.c +++ b/src/libltfs/periodic_sync.c @@ -102,7 +102,8 @@ ltfs_thread_return periodic_sync_thread(void* data) } ltfs_set_commit_message_reason(SYNC_PERIODIC, priv->vol); - ret = ltfs_sync_index(SYNC_PERIODIC, true, priv->vol); + + ret = ltfs_sync_index(SYNC_PERIODIC, true, LTFS_INDEX_AUTO, priv->vol); if (ret < 0) { ltfsmsg(LTFS_INFO, 11030I, ret); priv->keepalive = false; diff --git a/src/libltfs/xattr.c b/src/libltfs/xattr.c index b223edd7..e19d9ff3 100644 --- a/src/libltfs/xattr.c +++ b/src/libltfs/xattr.c @@ -882,7 +882,7 @@ static int _xattr_get_virtual(struct dentry *d, char *buf, size_t buf_size, cons } } else if (! strcmp(name, "ltfs.sync")) { ltfs_set_commit_message_reason(SYNC_EA, vol); - ret = ltfs_sync_index(SYNC_EA, false, vol); + ret = ltfs_sync_index(SYNC_EA, false, LTFS_FULL_INDEX, vol); } } @@ -915,8 +915,12 @@ static int _xattr_set_virtual(struct dentry *d, const char *name, const char *va size_t size, struct ltfs_volume *vol) { int ret = 0; + enum ltfs_index_type idx_type = LTFS_INDEX_AUTO; - if ((! strcmp(name, "ltfs.commitMessage") || ! strcmp(name, "ltfs.sync")) + if ((! strcmp(name, "ltfs.commitMessage") || + ! strcmp(name, "ltfs.sync") || + ! strcmp(name, "ltfs.vendor.IBM.FullSync") || + ! strcmp(name, "ltfs.vendor.IBM.IncrementalSync")) && d == vol->index->root) { char *value_null_terminated, *new_value; @@ -925,6 +929,17 @@ static int _xattr_set_virtual(struct dentry *d, const char *name, const char *va ret = -LTFS_LARGE_XATTR; } +#ifdef FORMAT_SPEC25 + if (! strcmp(name, "ltfs.vendor.IBM.FullSync")) + idx_type = LTFS_FULL_INDEX; + else if (! strcmp(name, "ltfs.vendor.IBM.IncrementalSync")) + idx_type = LTFS_INCREMENTAL_INDEX; +#else + if (! strcmp(name, "ltfs.vendor.IBM.FullSync") || + ! strcmp(name, "ltfs.vendor.IBM.IncrementalSync")) { + } +#endif + ltfs_mutex_lock(&vol->index->dirty_lock); if (! vol->index->dirty) { /* Do nothing because index is clean */ @@ -953,12 +968,12 @@ static int _xattr_set_virtual(struct dentry *d, const char *name, const char *va ltfs_set_commit_message_reason_unlocked(SYNC_EA, vol); ltfs_mutex_unlock(&vol->index->dirty_lock); - ret = ltfs_sync_index(SYNC_EA, false, vol); + ret = ltfs_sync_index(SYNC_EA, false, LTFS_FULL_INDEX, vol); return ret; } ret = 0; - /* Update THE commit message in the index */ + /* Update the commit message in the index */ if (vol->index->commit_message) free(vol->index->commit_message); vol->index->commit_message = new_value; @@ -968,7 +983,7 @@ static int _xattr_set_virtual(struct dentry *d, const char *name, const char *va } ltfs_mutex_unlock(&vol->index->dirty_lock); - ret = ltfs_sync_index(SYNC_EA, false, vol); + ret = ltfs_sync_index(SYNC_EA, false, idx_type, vol); } else if (! strcmp(name, "ltfs.volumeName") && d == vol->index->root) { char *value_null_terminated, *new_value; @@ -1187,7 +1202,7 @@ static int _xattr_set_virtual(struct dentry *d, const char *name, const char *va lock = strtoull(v, &invalid_start, 0); if( (*invalid_start == '\0') && v ) { - mam_lockval new = UNLOCKED_MAM; + mam_lockval_t new = UNLOCKED_MAM; char status_mam[TC_MAM_LOCKED_MAM_SIZE]; switch (vol->t_attr->vollock) { @@ -1241,13 +1256,13 @@ static int _xattr_set_virtual(struct dentry *d, const char *name, const char *va ltfs_set_index_dirty(false, false, vol->index); ltfs_set_commit_message_reason_unlocked(SYNC_ADV_LOCK, vol); - ret = ltfs_sync_index(SYNC_ADV_LOCK, false, vol); + ret = ltfs_sync_index(SYNC_ADV_LOCK, false, LTFS_FULL_INDEX, vol); ret = tape_device_lock(vol->device); if (ret < 0) { ltfsmsg(LTFS_ERR, 12010E, __FUNCTION__); return ret; } - ret = ltfs_write_index(ltfs_ip_id(vol), SYNC_EA, vol); + ret = ltfs_write_index(ltfs_ip_id(vol), SYNC_EA, LTFS_FULL_INDEX, vol); tape_device_unlock(vol->device); } else ret = -LTFS_STRING_CONVERSION; @@ -1501,7 +1516,7 @@ int xattr_set(struct dentry *d, const char *name, const char *value, size_t size if (write_idx) { ltfs_set_commit_message_reason(SYNC_EA, vol); - ret = ltfs_sync_index(SYNC_EA, false, vol); + ret = ltfs_sync_index(SYNC_EA, false, LTFS_INDEX_AUTO, vol); } else ret = 0; diff --git a/src/libltfs/xml_libltfs.h b/src/libltfs/xml_libltfs.h index 2f64e98f..b2e85f70 100644 --- a/src/libltfs/xml_libltfs.h +++ b/src/libltfs/xml_libltfs.h @@ -83,7 +83,7 @@ xmlBufferPtr xml_make_label(const char *creator, tape_partition_t partition, xmlBufferPtr xml_make_schema(const char *creator, const struct ltfs_index *idx); int xml_schema_to_file(const char *filename, const char *creator, const char *reason, const struct ltfs_index *idx); -int xml_schema_to_tape(char *reason, struct ltfs_volume *vol); +int xml_schema_to_tape(char *reason, int type, struct ltfs_volume *vol); /* Functions for reading XML files. See xml_reader_libltfs.c */ int xml_label_from_file(const char *filename, struct ltfs_label *label); diff --git a/src/libltfs/xml_writer_libltfs.c b/src/libltfs/xml_writer_libltfs.c index 5f8f76b1..098b1892 100644 --- a/src/libltfs/xml_writer_libltfs.c +++ b/src/libltfs/xml_writer_libltfs.c @@ -60,6 +60,7 @@ #include "fs.h" #include "tape.h" #include "pathname.h" +#include "inc_journal.h" #include "arch/time_internal.h" /* Structure to control EE's file offset cache and sync file list */ @@ -338,10 +339,11 @@ static int _xml_write_file(xmlTextWriterPtr writer, struct dentry *file, struct /* Write dirty file list */ if (sync_list->fp && file->dirty) { fprintf(sync_list->fp, "%s,%"PRIu64"\n", file->name.name, file->size); - file->dirty = false; sync_list->count++; } + file->dirty = false; + return 0; } @@ -586,6 +588,433 @@ static int _xml_write_schema(xmlTextWriterPtr writer, const char *creator, return 0; } +#ifdef FORMAT_SPEC25 +static int _xml_write_incremental_dir(xmlTextWriterPtr writer, struct dentry *dir) +{ + /* Handle R/O and timestamp if it is dirty */ + if (dir->dirty) { + xml_mktag(xmlTextWriterWriteElement( + writer, BAD_CAST "readonly", BAD_CAST (dir->readonly ? "true" : "false")), -1); + xml_mktag(_xml_write_dentry_times(writer, dir), -1); + } + + /* Handle UID in any case */ + xml_mktag(xmlTextWriterWriteFormatElement( + writer, BAD_CAST UID_TAGNAME, "%"PRIu64, dir->uid), -1); + + /* Handle extended attribute if it is dirty */ + if (dir->dirty) { + xml_mktag(_xml_write_xattr(writer, dir), -1); + dir->dirty = false; + } + + return 0; +} + +static int _xml_open_incremental_dir_ent(xmlTextWriterPtr writer, struct dentry *dir) +{ + /* Handle R/O and timestamp if it is dirty */ + if (dir->dirty) { + xml_mktag(xmlTextWriterWriteElement( + writer, BAD_CAST "readonly", BAD_CAST (dir->readonly ? "true" : "false")), -1); + xml_mktag(_xml_write_dentry_times(writer, dir), -1); + } + + /* Handle UID in any case */ + xml_mktag(xmlTextWriterWriteFormatElement( + writer, BAD_CAST UID_TAGNAME, "%"PRIu64, dir->uid), -1); + + /* Handle extended attribute if it is dirty */ + if (dir->dirty) { + xml_mktag(_xml_write_xattr(writer, dir), -1); + dir->dirty = false; + } + + xml_mktag(xmlTextWriterStartElement(writer, BAD_CAST "contents"), -1); + + return 0; +} + +static int _xml_open_incrental_root(xmlTextWriterPtr writer, struct ltfs_volume *vol) +{ + int ret = 0; + struct ltfs_index *idx = vol->index; + struct dentry *dir = idx->root; + + /* Handle name tag */ + xml_mktag(xmlTextWriterStartElement(writer, BAD_CAST "directory"), -1); + if (idx->volume_name.name) { + xml_mktag(_xml_write_nametype(writer, "name", (struct ltfs_name*)(&idx->volume_name)), -1); + } else { + xml_mktag(xmlTextWriterStartElement(writer, BAD_CAST "name"), -1); + xml_mktag(xmlTextWriterEndElement(writer), -1); + } + + ret = _xml_open_incremental_dir_ent(writer, dir); + + return ret; +} + +static inline int _xml_close_incrental_root(xmlTextWriterPtr writer) +{ + xml_mktag(xmlTextWriterEndElement(writer), -1); /* close contents tag */ + xml_mktag(xmlTextWriterEndElement(writer), -1); /* close directory tag */ + return 0; +} + +static int _xml_open_incremental_dir(xmlTextWriterPtr writer, struct dentry *dir) +{ + int ret = 0; + + /* Handle name tag */ + xml_mktag(xmlTextWriterStartElement(writer, BAD_CAST "directory"), -1); + xml_mktag(_xml_write_nametype(writer, "name", &dir->name), -1); + xml_mktag(xmlTextWriterEndElement(writer), -1); + + ret = _xml_open_incremental_dir_ent(writer, dir); + + return ret; +} + +static inline int _xml_close_incremental_dir(xmlTextWriterPtr writer) +{ + xml_mktag(xmlTextWriterEndElement(writer), -1); + return 0; +} + +static int _xml_open_incremental_dirs(xmlTextWriterPtr writer, struct incj_path_helper *pm, int offset) +{ + int ret = 0, i = 0; + struct incj_path_element *cur = NULL; + + cur = pm->head; + for (i = 0; i < offset; i++) { + cur = cur->next; + } + + while (cur) { + ret = _xml_open_incremental_dir(writer, cur->d); + if (ret < 0) + break; + cur = cur->next; + } + + return ret; +} + +static int _xml_close_incremental_dirs(xmlTextWriterPtr writer, int pops) +{ + int ret = 0, i = 0; + + for (i = 0; i < pops; i++) { + ret = _xml_close_incremental_dir(writer); + if (ret < 0) + break; + } + + return ret; +} + +static int _xml_write_incremental_delete(xmlTextWriterPtr writer, enum journal_reason reason, struct ltfs_name *name) +{ + /* Open directory tag or file tag based on the provided reason */ + switch (reason) { + case DELETE_DIRECTORY: + xml_mktag(xmlTextWriterStartElement(writer, BAD_CAST "directory"), -1); + break; + case DELETE_FILE: + xml_mktag(xmlTextWriterStartElement(writer, BAD_CAST "file"), -1); + break; + default: + ltfsmsg(LTFS_ERR, 17304E, reason); + return -1; + break; + } + + /* Create a name tag */ + xml_mktag(_xml_write_nametype(writer, "name", name), -1); + + /* Create a empty deleted tag */ + xml_mktag(xmlTextWriterStartElement(writer, BAD_CAST "deleted"), -1); + xml_mktag(xmlTextWriterEndElement(writer), -1); + + /* Close directory or file tag */ + xml_mktag(xmlTextWriterEndElement(writer), -1); + + return 0; +} + +static int _xml_goto_increment_parent(xmlTextWriterPtr writer, + struct jentry *ent, struct incj_path_helper **cur, + struct ltfs_volume *vol) +{ + int ret = 0, matches = 0, pops = 0; + bool perfect_match = false; + char *parent_path = NULL, *filename = NULL; + struct incj_path_helper *new = NULL; + + parent_path = strdup(ent->id.full_path); + if (!parent_path) { + ltfsmsg(LTFS_ERR, 10001E, "parent path for traveling incremental index dirs"); + return -LTFS_NO_MEMORY; + } + + fs_split_path(parent_path, &filename, strlen(parent_path) + 1); + if (strlen(parent_path) == 0) { + parent_path = "/"; + } + + ret = incj_create_path_helper(parent_path, &new, vol); + if (ret < 0) { + free(parent_path); + return ret; + } + + ret = incj_compare_path(*cur, new, &matches, &pops, &perfect_match); + if (ret < 0) { + incj_destroy_path_helper(new); + free(parent_path); + return ret; + } + + if (pops) { + ret = _xml_close_incremental_dirs(writer, pops); + if (ret < 0) { + incj_destroy_path_helper(new); + free(parent_path); + return ret; + } + } + + if (!perfect_match) + ret = _xml_open_incremental_dirs(writer, new, matches); + + if (!ret) { + incj_destroy_path_helper(*cur); + *cur = new; + } else { + incj_destroy_path_helper(new); + } + + if (strcmp(parent_path, "/")) + free(parent_path); + + return ret; +} + +/** + * Write directory tags for incremental index based on current incremental journal information + * @param writer output pointer + * @param vol ltfs volume + * @param offset_c file pointer to write offest cache + * @param sync_list file pointer to write sync file list + * @return 0 on success or negative on failure + */ +static int _xml_write_inc_journal(xmlTextWriterPtr writer, struct ltfs_volume *vol, + struct ltfsee_cache* offset_c, struct ltfsee_cache* sync_list) +{ + int ret = 0; + bool failed = false; + struct ltfsee_cache offset = {NULL, 0}; /* Cache structure for file offset cache */ + struct ltfsee_cache list = {NULL, 0}; /* Cache structure for sync list */ + struct jentry *ent = NULL, *tmp = NULL; + struct incj_path_helper *cur_parent = NULL; + + /* Create a directory tag for root */ + ret = _xml_open_incrental_root(writer, vol); + if (ret < 0) { + return ret; + } + + ret = incj_create_path_helper("/", &cur_parent, vol); + if (ret < 0) { + return ret; + } + + /* Crawl incremental journal and generate XML tags */ + incj_sort(vol); + HASH_ITER(hh, vol->journal, ent, tmp) { + if (!failed) { + ret = _xml_goto_increment_parent(writer, ent, &cur_parent, vol); + if (!ret) { + switch (ent->reason) { + case CREATE: + /* TODO: Need to support sync cache and offset cache */ + if (ent->dentry->isdir) { + /* Create XML recursively */ + ret = _xml_write_dirtree(writer, ent->dentry, vol->index, &offset, &list); + } else { + /* Create XML for a file */ + ret = _xml_write_file(writer, ent->dentry, &offset, &list); + } + break; + case MODIFY: + if (ent->dentry->isdir) { + /* Create XML for dir (no recursive) */ + ret = _xml_write_incremental_dir(writer, ent->dentry); + } else { + /* Create XML for a file */ + ret = _xml_write_file(writer, ent->dentry, &offset, &list); + } + break; + case DELETE_FILE: + case DELETE_DIRECTORY: + /* Create a delete tag */ + ret = _xml_write_incremental_delete(writer, ent->reason, &ent->name); + break; + default: + ltfsmsg(LTFS_ERR, 17303E, ent->reason); + ret = -LTFS_UNEXPECTED_VALUE; + break; + } + + if (ret < 0) + failed = true; + } else + failed = true; + } + HASH_DEL(vol->journal, ent); + incj_dispose_jentry(ent); + } + + if (cur_parent) { + incj_destroy_path_helper(cur_parent); + } + + /* Clear created directory just in case */ + incj_clear(vol); + + /* Close the directory tag for root */ + ret = _xml_close_incrental_root(writer); + + return ret; +} + +/** + * Generate an XML schema, sending it to a user-provided output (memory or file). + * Note: this function does very little input validation; any user-provided information + * must be verified by the caller. + * @param writer the XML writer to send output to + * @param priv LTFS data + * @param pos position on tape where the schema will be written + * @return 0 on success, negative on failure + */ +static int _xml_write_incremental_schema(xmlTextWriterPtr writer, const char *creator, struct ltfs_volume *vol) +{ + int ret; + size_t i; + char *update_time; + struct ltfsee_cache offset = {NULL, 0}; /* Cache structure for file offset cache */ + struct ltfsee_cache list = {NULL, 0}; /* Cache structure for sync list */ + struct ltfs_index *idx = vol->index; + + ret = xml_format_time(idx->mod_time, &update_time); + if (!update_time) + return -1; + else if (ret == LTFS_TIME_OUT_OF_RANGE) + ltfsmsg(LTFS_WARN, 17224W, "modifytime", (unsigned long long)idx->mod_time.tv_sec); + + ret = xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL); + if (ret < 0) { + ltfsmsg(LTFS_ERR, 17057E, ret); + return -1; + } + + xmlTextWriterSetIndent(writer, 1); + /* Define INDENT_INDEXES to write Indexes to tape with full indentation. + * This is normally a waste of space, but it may be useful for debugging. */ +#ifdef INDENT_INDEXES + xmlTextWriterSetIndentString(writer, BAD_CAST " "); +#else + xmlTextWriterSetIndentString(writer, BAD_CAST ""); +#endif + + /* write index properties */ + xml_mktag(xmlTextWriterStartElement(writer, BAD_CAST "ltfsincrementalindex"), -1); + xml_mktag(xmlTextWriterWriteAttribute(writer, BAD_CAST "version", + BAD_CAST LTFS_INDEX_VERSION_STR), -1); + xml_mktag(xmlTextWriterWriteElement(writer, BAD_CAST "creator", BAD_CAST creator), -1); + if (idx->commit_message && strlen(idx->commit_message)) { + xml_mktag(xmlTextWriterWriteFormatElement(writer, BAD_CAST "comment", + "%s", BAD_CAST (idx->commit_message)), -1); + } + xml_mktag(xmlTextWriterWriteElement(writer, BAD_CAST "volumeuuid", BAD_CAST idx->vol_uuid), -1); + xml_mktag(xmlTextWriterWriteFormatElement( + writer, BAD_CAST "generationnumber", "%u", idx->generation), -1); + xml_mktag(xmlTextWriterWriteElement(writer, BAD_CAST "updatetime", BAD_CAST update_time), -1); + xml_mktag(xmlTextWriterStartElement(writer, BAD_CAST "location"), -1); + xml_mktag(xmlTextWriterWriteFormatElement( + writer, BAD_CAST "partition", "%c", idx->selfptr_inc.partition), -1); + xml_mktag(xmlTextWriterWriteFormatElement( + writer, BAD_CAST "startblock", "%"PRIu64, idx->selfptr_inc.block), -1); + xml_mktag(xmlTextWriterEndElement(writer), -1); + if (idx->backptr.block) { + xml_mktag(xmlTextWriterStartElement(writer, BAD_CAST "previousgenerationlocation"), -1); + xml_mktag(xmlTextWriterWriteFormatElement( + writer, BAD_CAST "partition", "%c", idx->backptr.partition), -1); + xml_mktag(xmlTextWriterWriteFormatElement( + writer, BAD_CAST "startblock", "%"PRIu64, idx->backptr.block), -1); + xml_mktag(xmlTextWriterEndElement(writer), -1); + } + + if (idx->backptr_inc.block) { + xml_mktag(xmlTextWriterStartElement(writer, BAD_CAST "previousincrementallocation"), -1); + xml_mktag(xmlTextWriterWriteFormatElement( + writer, BAD_CAST "partition", "%c", idx->backptr_inc.partition), -1); + xml_mktag(xmlTextWriterWriteFormatElement( + writer, BAD_CAST "startblock", "%"PRIu64, idx->backptr_inc.block), -1); + xml_mktag(xmlTextWriterEndElement(writer), -1); + } + + xml_mktag(xmlTextWriterWriteFormatElement( + writer, BAD_CAST NEXTUID_TAGNAME, "%"PRIu64, idx->uid_number), -1); + + { + char *value = NULL; + + switch (idx->vollock) { + case LOCKED_MAM: + asprintf(&value, "locked"); + break; + case PERMLOCKED_MAM: + asprintf(&value, "permlocked"); + break; + default: + asprintf(&value, "unlocked"); + break; + } + + if (value) + xml_mktag(xmlTextWriterWriteElement(writer, BAD_CAST "volumelockstate", BAD_CAST value), -1); + + free(value); + } + + /* Create XML of update */ + xml_mktag(_xml_write_inc_journal(writer, vol, &offset, &list), -1); + + /* Save unrecognized tags */ + if (idx->tag_count > 0) { + for (i=0; itag_count; ++i) { + if (xmlTextWriterWriteRaw(writer, idx->preserved_tags[i]) < 0) { + ltfsmsg(LTFS_ERR, 17092E, __FUNCTION__); + return -1; + } + } + } + + xml_mktag(xmlTextWriterEndElement(writer), -1); + ret = xmlTextWriterEndDocument(writer); + if (ret < 0) { + ltfsmsg(LTFS_ERR, 17058E, ret); + return -1; + } + + free(update_time); + return 0; +} +#endif + /************************************************************************************** * Global Functions **************************************************************************************/ @@ -809,10 +1238,12 @@ int xml_schema_to_file(const char *filename, const char *creator, /** * Generate an XML Index based on the vol->index->root directory tree. * The generated data are written directly to the tape with the appropriate blocksize. + * @param reason the reason of writing an index on tape + * @param type index type to write (shall be LTFS_FULL_INDEX or LTFS_INCREMENTAL_INDEX) * @param vol LTFS volume. * @return 0 on success or a negative value on error. */ -int xml_schema_to_tape(char *reason, struct ltfs_volume *vol) +int xml_schema_to_tape(char *reason, int type, struct ltfs_volume *vol) { int ret, bk = -1; xmlOutputBufferPtr write_buf; @@ -875,7 +1306,19 @@ int xml_schema_to_tape(char *reason, struct ltfs_volume *vol) /* Generate the Index. */ asprintf(&creator, "%s - %s", vol->creator, reason); if (creator) { - ret = _xml_write_schema(writer, creator, vol->index); + switch (type) { + case LTFS_FULL_INDEX: + ret = _xml_write_schema(writer, creator, vol->index); + break; +#ifdef FORMAT_SPEC25 + case LTFS_INCREMENTAL_INDEX: + ret = _xml_write_incremental_schema(writer, creator, vol); + break; +#endif + default: + ret = -LTFS_BAD_INDEX_TYPE; + break; + } if (ret < 0) { ltfsmsg(LTFS_ERR, 17055E, ret); } diff --git a/src/ltfs_fuse.c b/src/ltfs_fuse.c index 00aaf3bc..4e12188f 100644 --- a/src/ltfs_fuse.c +++ b/src/ltfs_fuse.c @@ -452,7 +452,7 @@ int ltfs_fuse_release(const char *path, struct fuse_file_info *fi) ret = ltfs_fsops_close(file->file_info->dentry_handle, dirty, open_write, true, priv->data); if (write_index) { ltfs_set_commit_message_reason(SYNC_CLOSE, priv->data); - ltfs_sync_index(SYNC_CLOSE, true, priv->data); + ltfs_sync_index(SYNC_CLOSE, true, LTFS_INDEX_AUTO, priv->data); } _file_close(file->file_info, priv); diff --git a/src/utils/ltfsck.c b/src/utils/ltfsck.c index 007ae6ce..dc7cef85 100644 --- a/src/utils/ltfsck.c +++ b/src/utils/ltfsck.c @@ -1154,7 +1154,7 @@ int _rollback_ip(struct ltfs_volume *vol, struct other_check_opts *opt, struct t if (ret != LTFSCK_NO_ERRORS) ltfsmsg(LTFS_ERR, 16059E, ret); } else { - ret = ltfs_write_index(ltfs_ip_id(vol), SYNC_ROLLBACK, vol); + ret = ltfs_write_index(ltfs_ip_id(vol), SYNC_ROLLBACK, LTFS_FULL_INDEX, vol); if (ret < 0) { ltfsmsg(LTFS_ERR, 16060E, ret); ret = LTFSCK_OPERATIONAL_ERROR; @@ -1176,7 +1176,7 @@ int _rollback_dp(struct ltfs_volume *vol, struct other_check_opts *opt, struct t ltfsmsg(LTFS_ERR, 16055E, ret); } else { ltfs_set_commit_message_reason(SYNC_ROLLBACK, vol); - ret = ltfs_write_index(ltfs_dp_id(vol), SYNC_ROLLBACK, vol); + ret = ltfs_write_index(ltfs_dp_id(vol), SYNC_ROLLBACK, LTFS_FULL_INDEX, vol); if (ret < 0) { ltfsmsg(LTFS_ERR, 16056E, ret); ret = LTFSCK_OPERATIONAL_ERROR;