diff --git a/HISTORY b/HISTORY index 5e815034..b87096cf 100644 --- a/HISTORY +++ b/HISTORY @@ -7,11 +7,14 @@ SnapRAID HISTORY This allows to restore the exact modification time in 'fix'. The new 'content' files written with this version are not backward compatible, but it's still possible to read the old 'content' format. + * Fixed hard-links automatic exclusion. All the hardlinks after the first one + are now correctly ignored. + * If it isn't possible to grow a parity file, prints the list of files outside + the maximum size allocated. + * Autosave isn't triggered if we are near the end of the 'sync' process. * Before starting a 'sync', we wait for two seconds, to workaround the FAT limitation of having two seconds modification time precision. This a safe measure to be 100% sure to always detect file changes. - * Autosave isn't triggered if we are near the end of the 'sync' process. - * Fixed hard-links automatic exclusion after the first one. * Always fill the memory after allocating it to avoid the OOM (Out Of Memory) killer in Linux. diff --git a/TODO b/TODO index d6dbab8b..e26d8ef9 100644 --- a/TODO +++ b/TODO @@ -5,19 +5,7 @@ This is the list of TODO items for SnapRAID. - v1.13 -* In the repair() function the euristic to detect if we recovered after the sync, can be extended -to all the subsequent blocks, because we always proceeed in block order during a sync. -So, if for a block we can detect that we recovered after a sync, also for all the subsequent blocks -this is true. - -* To list all the hardlink in Windows Vista it's possible to use FindFirstFileNameW/FindNextFileNameW -See: http://blogs.msdn.com/b/oldnewthing/archive/2011/07/20/10188033.aspx - -* Support Symlinks also in Windows. -See: http://www.codeproject.com/Articles/21202/Reparse-Points-in-Vista - -* In Windows to use FILE_FLAG_BACKUP_SEMANTICS we should also get privileges. -See http://www.codeproject.com/Articles/21202/Reparse-Points-in-Vista. +* In error growing, print the last file in the bigger data disk. * Allow to filter the files to check/fix based on the drive where they reside. @@ -32,6 +20,20 @@ on the error message. See: https://sourceforge.net/projects/snapraid/forums/foru * Support interrupted operations with EINTR. For remote filesystems it could be relevant. +* In the repair() function the euristic to detect if we recovered after the sync, can be extended +to all the subsequent blocks, because we always proceeed in block order during a sync. +So, if for a block we can detect that we recovered after a sync, also for all the subsequent blocks +this is true. + +* In Windows to use FILE_FLAG_BACKUP_SEMANTICS we should also get privileges. +See http://www.codeproject.com/Articles/21202/Reparse-Points-in-Vista. + +* Support Symlinks also in Windows. +See: http://www.codeproject.com/Articles/21202/Reparse-Points-in-Vista + +* To list all the hardlink in Windows Vista it's possible to use FindFirstFileNameW/FindNextFileNameW +See: http://blogs.msdn.com/b/oldnewthing/archive/2011/07/20/10188033.aspx + * In Windows we must be case insensitive, at least for ASCII<128 comparison. For other UTF-8 chars is too complex. diff --git a/check.c b/check.c index b788eec7..0867b679 100644 --- a/check.c +++ b/check.c @@ -1190,7 +1190,7 @@ void state_check(struct snapraid_state* state, int fix, block_off_t blockstart, /* if fixing, create the file and open for writing */ /* if it fails, we cannot continue */ parity_ptr = &parity; - ret = parity_create(parity_ptr, state->parity, size); + ret = parity_create(parity_ptr, state->parity, size, 0); if (ret == -1) { fprintf(stderr, "WARNING! Without an accessible Parity file, it isn't possible to fix any error.\n"); exit(EXIT_FAILURE); @@ -1198,7 +1198,7 @@ void state_check(struct snapraid_state* state, int fix, block_off_t blockstart, if (state->level >= 2) { qarity_ptr = &qarity; - ret = parity_create(qarity_ptr, state->qarity, size); + ret = parity_create(qarity_ptr, state->qarity, size, 0); if (ret == -1) { fprintf(stderr, "WARNING! Without an accessible Q-Parity file, it isn't possible to fix any error.\n"); exit(EXIT_FAILURE); diff --git a/parity.c b/parity.c index 9dce0f67..0954852f 100644 --- a/parity.c +++ b/parity.c @@ -51,12 +51,54 @@ block_off_t parity_resize(struct snapraid_state* state) return parity_block; } -int parity_create(struct snapraid_parity* parity, const char* path, data_off_t size) +void parity_overflow(struct snapraid_state* state, data_off_t size) +{ + tommy_node* i; + block_off_t blockalloc; + int first = 1; + + /* don't report if everything is outside or if the file is not accessible */ + if (size == 0) { + return; + } + + blockalloc = size / state->block_size; + + /* for all disks */ + for(i=state->disklist;i!=0;i=i->next) { + struct snapraid_disk* disk = i->data; + tommy_node* j; + + /* for all files */ + for(j=disk->filelist;j!=0;j=j->next) { + struct snapraid_file* file = j->data; + + if (file->blockmax > 0) { + if (file->blockvec[0].parity_pos > blockalloc) { + if (state->gui) { + fprintf(stderr, "outofparity:%s:%s\n", disk->name, file->sub); + fflush(stderr); + } + if (first) { + first = 0; + printf("Files outside the parity:\n"); + } + printf("OutOfParity '%s%s'\n", disk->dir, file->sub); + } + } + } + } +} + +int parity_create(struct snapraid_parity* parity, const char* path, data_off_t size, data_off_t* out_size) { int ret; pathcpy(parity->path, sizeof(parity->path), path); + if (out_size) + *out_size = 0; + /* opening in sequential mode in Windows */ parity->f = open(parity->path, O_RDWR | O_CREAT | O_BINARY | O_SEQUENTIAL, 0600); if (parity->f == -1) { @@ -71,10 +113,14 @@ int parity_create(struct snapraid_parity* parity, const char* path, data_off_t s goto bail; } - /* get the size of the exising data */ + /* get the size of the existing data */ parity->valid_size = parity->st.st_size; + if (out_size) + *out_size = parity->st.st_size; if (parity->st.st_size < size) { + int f_ret; + int f_errno; #if HAVE_FALLOCATE /* allocate real space using the specific Linux fallocate() operation. */ /* If the underline filesystem doesn't support it, this operation fails, */ @@ -100,11 +146,27 @@ int parity_create(struct snapraid_parity* parity, const char* path, data_off_t s /* allocate using a sparse file */ ret = ftruncate(parity->f, size); #endif + /* save the state of the grow operation */ + f_ret = ret; + f_errno = errno; + + /* reget the stat info */ + ret = fstat(parity->f, &parity->st); if (ret != 0) { - if (errno == ENOSPC) { + fprintf(stderr, "Error accessing parity file '%s'. %s.\n", parity->path, strerror(errno)); + goto bail; + } + + /* return the new size */ + if (out_size) + *out_size = parity->st.st_size; + + /* now check the error */ + if (f_ret != 0) { + if (f_errno == ENOSPC) { fprintf(stderr, "Failed to grow parity file '%s' to size %"PRIu64" due lack of space.\n", parity->path, size); } else { - fprintf(stderr, "Error growing parity file '%s' to size %"PRIu64". Do you have enough space? %s.\n", parity->path, size, strerror(errno)); + fprintf(stderr, "Error growing parity file '%s' to size %"PRIu64". Do you have enough space? %s.\n", parity->path, size, strerror(f_errno)); } goto bail; } @@ -115,7 +177,18 @@ int parity_create(struct snapraid_parity* parity, const char* path, data_off_t s goto bail; } - /* adjust the size to the truncated size */ + /* reget the stat info */ + ret = fstat(parity->f, &parity->st); + if (ret != 0) { + fprintf(stderr, "Error accessing parity file '%s'. %s.\n", parity->path, strerror(errno)); + goto bail; + } + + /* return the new real size */ + if (out_size) + *out_size = parity->st.st_size; + + /* adjust the valid to the new size */ parity->valid_size = size; } @@ -310,3 +383,4 @@ int parity_read(struct snapraid_parity* parity, block_off_t pos, unsigned char* return block_size; } + diff --git a/parity.h b/parity.h index 5b0d65d3..29a0a198 100644 --- a/parity.h +++ b/parity.h @@ -34,9 +34,15 @@ struct snapraid_parity { block_off_t parity_resize(struct snapraid_state* state); /** - * Creates the parity file. + * Reports all the files outside the specified parity size. */ -int parity_create(struct snapraid_parity* parity, const char* path, data_off_t size); +void parity_overflow(struct snapraid_state* state, data_off_t size); + +/** + * Creates the parity file. + * \param out_size Return the final size of the parity file. Returned also in error cases. + */ +int parity_create(struct snapraid_parity* parity, const char* path, data_off_t size, data_off_t* out_size); /** * Opens an already existing parity file. diff --git a/sync.c b/sync.c index 460e8d71..584ceb77 100644 --- a/sync.c +++ b/sync.c @@ -353,6 +353,7 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t { block_off_t blockmax; data_off_t size; + data_off_t size_after; tommy_node* i; int ret; struct snapraid_parity parity; @@ -394,16 +395,18 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t /* create the file and open for writing */ parity_ptr = &parity; - ret = parity_create(parity_ptr, state->parity, size); + ret = parity_create(parity_ptr, state->parity, size, &size_after); if (ret == -1) { + parity_overflow(state, size_after); fprintf(stderr, "WARNING! Without an accessible Parity file, it isn't possible to sync.\n"); exit(EXIT_FAILURE); } if (state->level >= 2) { qarity_ptr = &qarity; - ret = parity_create(qarity_ptr, state->qarity, size); + ret = parity_create(qarity_ptr, state->qarity, size, &size_after); if (ret == -1) { + parity_overflow(state, size_after); fprintf(stderr, "WARNING! Without an accessible Q-Parity file, it isn't possible to sync.\n"); exit(EXIT_FAILURE); }