diff --git a/HISTORY b/HISTORY index 0100bbb4..2d98b520 100644 --- a/HISTORY +++ b/HISTORY @@ -10,6 +10,9 @@ SnapRAID HISTORY But any new data added will be protected if you are using enough parity to fix both the silent error and at least another potential error. + * In "fix", if a previous attempt was made, resulting in a + .unrecoverable file, uses this file as starting point for the + new attempt. * New source code organization. The RAID engine is now an external component usable also in other projects. diff --git a/TODO b/TODO index 2bc27d8e..f0977ba5 100644 --- a/TODO +++ b/TODO @@ -5,15 +5,6 @@ This is the list of TODO items for SnapRAID. - Next -* When renaming to .unrecoverable at now we always overwrite -a previous copy losing partial, but potentially better, file recovery. -Is it possible a better strategy ? -Maybe we can rename the unrecoverable as the real file, if the real file -is missing at the first open. This should ensure to always -get better results if the file is hashed. -Something like an incremental recovery, in case multiple fix commands -are attempted. - * Don't disable default 10d/12% if -p or -o is specified. But check that -p0 still work. @@ -25,6 +16,14 @@ parity, but we can reuse the hash to check that the file was moved correctly. We can assume a file moved to another disk if it has the same name, size, and timestamp. Directory and inode can be different. +This can be implemented with NEW blocks with HASH. +In synch, we can do the hash check of such blocks before any other operation, +before invalidating the parity of the moved files now converted in DELETED +blocks. +If an error is found, or we stop the sync, or we can use the parity of +DELETED blocks to recover the missing ones. +Missing blocks can be find by hash, using all the DELETED blocks with hash +as search base. * Avoid to do optimized move operation if more files with same timestamp/size are present. diff --git a/handle.c b/handle.c index 85f2f8b7..e3de6bc6 100644 --- a/handle.c +++ b/handle.c @@ -45,32 +45,41 @@ int handle_create(struct snapraid_handle* handle, struct snapraid_file* file, in handle->truncated = 0; handle->created = 0; - /* open for read write */ - /* O_SEQUENTIAL: opening in sequential mode in Windows */ + /* flags for opening */ + /* O_BINARY: open as binary file (Windows only) */ /* O_NOFOLLOW: do not follow links to ensure to open the real file */ - flags = O_RDWR | O_BINARY | O_NOFOLLOW; + /* O_SEQUENTIAL: improve performance for sequential access (Windows only) */ + flags = O_BINARY | O_NOFOLLOW; if (!skip_sequential) flags |= O_SEQUENTIAL; - handle->f = open(handle->path, flags); - /* if failed for missing permission */ - if (handle->f == -1 && errno == EACCES) { - /* retry without requesting write permission */ - flags = O_RDONLY | O_BINARY | O_NOFOLLOW; - if (!skip_sequential) - flags |= O_SEQUENTIAL; - handle->f = open(handle->path, flags); + /* open for read write */ + handle->f = open(handle->path, flags | O_RDWR); + + /* if failed for missing write permission */ + if (handle->f == -1 && (errno == EACCES || errno == EROFS)) { + /* open for real-only */ + handle->f = open(handle->path, flags | O_RDONLY); } /* if failed for missing file */ if (handle->f == -1 && errno == ENOENT) { - /* retry creating it */ - flags = O_RDWR | O_CREAT | O_BINARY | O_NOFOLLOW; - if (!skip_sequential) - flags |= O_SEQUENTIAL; - /* mark it as created */ - handle->created = 1; - handle->f = open(handle->path, flags, 0600); + char path_from[PATH_MAX]; + + /* check if exists a .unrecoverable copy, and rename to the real one */ + pathprint(path_from , sizeof(path_from), "%s.unrecoverable", handle->path); + + if (rename(path_from, handle->path) == 0) { + /* open for read write */ + handle->f = open(handle->path, flags | O_RDWR); + } else { + /* create it */ + handle->f = open(handle->path, flags | O_RDWR | O_CREAT, 0600); + if (handle->f != -1) { + /* mark it as created if really done */ + handle->created = 1; + } + } } if (handle->f == -1) { @@ -147,14 +156,16 @@ int handle_open(struct snapraid_handle* handle, struct snapraid_file* file, int handle->truncated = 0; handle->created = 0; - /* open for read */ - /* O_SEQUENTIAL: opening in sequential mode in Windows */ + /* flags for opening */ + /* O_BINARY: open as binary file (Windows only) */ /* O_NOFOLLOW: do not follow links to ensure to open the real file */ - /* O_NOATIME: do not change access time */ - flags = O_RDONLY | O_BINARY | O_NOFOLLOW; + /* O_SEQUENTIAL: improve performance for sequential access (Windows only) */ + flags = O_BINARY | O_NOFOLLOW; if (!skip_sequential) flags |= O_SEQUENTIAL; - handle->f = open_noatime(handle->path, flags); + + /* open for read */ + handle->f = open_noatime(handle->path, flags | O_RDONLY); if (handle->f == -1) { /* invalidate for error */ handle->file = 0;