From 5fef489a25356721b56addb7562cc26106329f83 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Fri, 31 May 2013 23:34:59 +0200 Subject: [PATCH] When renaming incomplete files, scans the full file list to take into account for fragmented files. --- TODO | 4 +--- check.c | 66 +++++++++++++++++++++++++++++++++++++++++---------------- elem.h | 31 +++++++++++++++++++-------- 3 files changed, 71 insertions(+), 30 deletions(-) diff --git a/TODO b/TODO index 289ab576..3be861ec 100644 --- a/TODO +++ b/TODO @@ -3,12 +3,10 @@ SnapRAID TODO This is the list of TODO items for SnapRAID. -- v3.1 +- v3.2 * Allow to specify the shared path to use to access remote symlink. -- v3.2 - * In the import list, uses also all the blocks in the array. But we must cover the case of bad blocks. Likely we can just check the hash after reading, and in case, skip it, and retry with another copy. diff --git a/check.c b/check.c index 5d7b0582..585e0f1a 100644 --- a/check.c +++ b/check.c @@ -963,6 +963,9 @@ static int state_check_process(struct snapraid_state* state, int check, int fix, /* finish the fix process if it's the last block of the files */ if (fix) { + /* mark that we finished with this file */ + file_flag_set(file, FILE_IS_FINISHED); + /* if the file is damaged, meaning that a fix failed */ if (file_flag_has(file, FILE_IS_DAMAGED)) { /* rename it to .unrecoverable */ @@ -1420,30 +1423,57 @@ close_and_continue: state_progress_end(state, countpos, countmax, countsize); bail: + /* close all the files left open */ for(j=0;jfile != 0) { - struct snapraid_file* file = handle[j].file; + ret = handle_close(&handle[j]); + if (ret == -1) { + fprintf(stderr, "DANGER! Unexpected close error in a data disk.\n"); + ++unrecoverable_error; + /* continue, as we are already exiting */ + } + } - /* now close it */ - ret = handle_close(&handle[j]); - if (ret == -1) { - fprintf(stderr, "DANGER! Unexpected close error in a data disk.\n"); - ++unrecoverable_error; - /* continue, as we are already exiting */ - } + /* rename all the files created from scratch that have not finished the processing */ + /* it happens only when aborting */ + if (fix) { + /* for each disk */ + for(i=0;ifilelist; + while (node) { char path[PATH_MAX]; char path_to[PATH_MAX]; + struct snapraid_file* file; - pathprint(path, sizeof(path), "%s%s", handle[j].disk->dir, file->sub); - pathprint(path_to, sizeof(path_to), "%s%s.unrecoverable", handle[j].disk->dir, file->sub); + file = node->data; + node = node->next; /* next node */ + + /* if the file was not created, meaning that it was already existing */ + if (!file_flag_has(file, FILE_IS_CREATED)) { + /* nothing to do */ + continue; + } + + /* if processing was finished */ + if (file_flag_has(file, FILE_IS_FINISHED)) { + /* nothing to do */ + continue; + } + + /* if the file was originally missing, and processing not yet finished */ + /* we have to throw it away to ensure that at the next run we will retry */ + /* to fix it, in case we select to undelete missing files */ + + /* rename it to .unrecoverable */ + pathprint(path, sizeof(path), "%s%s", disk->dir, file->sub); + pathprint(path_to, sizeof(path_to), "%s%s.unrecoverable", disk->dir, file->sub); ret = rename(path, path_to); if (ret != 0) { diff --git a/elem.h b/elem.h index b11e4602..e9c13eff 100644 --- a/elem.h +++ b/elem.h @@ -136,41 +136,54 @@ struct snapraid_block { #define BLOCK_EMPTY 0 /** - * If it's seen as present. - * It's used only in sync. + * If a file is present in the disk. + * It's used only in scan to detect present and missing files. */ #define FILE_IS_PRESENT 0x01 /** * If it's an excluded file from the processing. - * It's used in sync/check/fix. + * It's used in both check and fix to mark files to exclude from the processing. */ #define FILE_IS_EXCLUDED 0x02 /** - * If the file was originally larger, and then truncated to the expected suze. - * It's used in check/fix to avoid to report this condition more than one time. + * If the file was originally larger, and then truncated to the expected size. + * It's used only in check to avoid to report this condition more than one time, + * in case the file is opened multiple times. + * In fix it's not used, because the size is fixed just after the first opening. */ #define FILE_IS_LARGER 0x04 /** * If a fix was attempted but it failed. - * It's used only in fix. + * It's used only in fix to mark that some data is unrecoverable. */ #define FILE_IS_DAMAGED 0x08 /** * If a fix was done. - * It's used only in fix. + * It's used only in fix to mark that some data was recovered. */ #define FILE_IS_FIXED 0x10 /** - * If the file was originally missing, and it's created in the fix process. - * It's used only in fix. + * If the file was originally missing, and it was created in the fix process. + * It's used only in fix to mark files recovered from scratch, + * meaning that they don't have any previous content. + * This is important because it means that deleting them, you are not going + * to lose something that cannot be recovered. + * Note that excluded files won't ever get this flag. */ #define FILE_IS_CREATED 0x20 +/** + * If the file has completed its processing, meaning that it won't be opened anymore. + * It's used only in fix to mark when we finish processing one file. + * Note that excluded files won't ever get this flag. + */ +#define FILE_IS_FINISHED 0x40 + #define FILE_IS_HARDLINK 0x100 /**< If it's an hardlink. */ #define FILE_IS_SYMLINK 0x200 /**< If it's a file symlink. */ #define FILE_IS_SYMDIR 0x400 /**< If it's a dir symlink for Windows. Not yet supported. */