diff --git a/cmdline/mingw.c b/cmdline/mingw.c index c741a5d9..c136a324 100644 --- a/cmdline/mingw.c +++ b/cmdline/mingw.c @@ -1339,7 +1339,7 @@ int devuuid(uint64_t device, char* uuid, size_t uuid_size) return 0; } -int filephy(const char* file, struct stat* st, uint64_t* physical) +int filephy(const char* file, uint64_t size, uint64_t* physical) { HANDLE h; STARTING_VCN_INPUT_BUFFER svib; @@ -1348,9 +1348,11 @@ int filephy(const char* file, struct stat* st, uint64_t* physical) BOOL ret; DWORD n; - /* in Wine just uses the inode number because FSCTL_GET_RETRIVIAL_POINTERS is not supported */ + (void)size; + + /* in Wine FSCTL_GET_RETRIVIAL_POINTERS is not supported */ if (is_wine) { - *physical = st->st_ino; + *physical = FILEPHY_UNREPORTED_OFFSET; return 0; } diff --git a/cmdline/portable.h b/cmdline/portable.h index 4af2e761..bb17ccee 100644 --- a/cmdline/portable.h +++ b/cmdline/portable.h @@ -212,27 +212,32 @@ static inline int hardlink(const char* a, const char* b) int devuuid(uint64_t device, char* uuid, size_t size); /** - * Special value returned when the file doesn't have a real offset. - * For example, because it's stored in the NTFS MFT. + * Physical offset not yet read. */ -#define FILEPHY_WITHOUT_OFFSET 0 +#define FILEPHY_UNREAD_OFFSET 0 /** * Special value returned when the filesystem doesn't report any offset for unknown reason. */ #define FILEPHY_UNREPORTED_OFFSET 1 +/** + * Special value returned when the file doesn't have a real offset. + * For example, because it's stored in the NTFS MFT. + */ +#define FILEPHY_WITHOUT_OFFSET 2 + /** * Value indicating real offsets. All offsets greater or equal at this one are real. */ -#define FILEPHY_REAL_OFFSET 2 +#define FILEPHY_REAL_OFFSET 3 /** * Get the physcal address of the specified file. * This is expected to be just a hint and not necessarely correct or unique. * Returns 0 on success. */ -int filephy(const char* path, struct stat* st, uint64_t* physical); +int filephy(const char* path, uint64_t size, uint64_t* physical); /** * Checks if the underline filesystem support persistent inodes. @@ -251,7 +256,7 @@ uint64_t tick(void); /** * Initializes the system. */ -void os_init(void); +void os_init(int opt); /** * Deintialize the system. diff --git a/cmdline/scan.c b/cmdline/scan.c index 09b88a88..4fb876d2 100644 --- a/cmdline/scan.c +++ b/cmdline/scan.c @@ -290,6 +290,28 @@ static int file_is_full_hashed_and_stable(struct snapraid_state* state, struct s return 1; } +static void scan_file_delayed_insert(struct snapraid_scan* scan, struct snapraid_file* file) +{ + struct snapraid_state* state = scan->state; + struct snapraid_disk* disk = scan->disk; + + /* if we sort for physical offsets we have to read them for the new files */ + if (state->opt.force_order == SORT_PHYSICAL) { + char path_next[PATH_MAX]; + + pathprint(path_next, sizeof(path_next), "%s%s", disk->dir, file->sub); + + if (filephy(path_next, file->size, &file->physical) != 0) { + /* LCOV_EXCL_START */ + fprintf(stderr, "Error in getting the physical offset of file '%s'. %s.\n", path_next, strerror(errno)); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + } + + tommy_list_insert_tail(&scan->file_insert_list, &file->nodelist, file); +} + /** * Keeps the file as it's (or with only a name/inode modification). * @@ -314,7 +336,7 @@ static void scan_file_keep(struct snapraid_scan* scan, struct snapraid_file* fil tommy_list_remove_existing(&disk->filelist, &file->nodelist); /* insert the file in the delayed block allocation */ - tommy_list_insert_tail(&scan->file_insert_list, &file->nodelist, file); + scan_file_delayed_insert(scan, file); } } @@ -789,7 +811,7 @@ static void scan_file(struct snapraid_scan* scan, int output, const char* sub, c tommy_hashdyn_insert(&disk->stampset, &file->stampset, file, file_stamp_hash(file->size, file->mtime_sec, file->mtime_nsec)); /* insert the file in the delayed block allocation */ - tommy_list_insert_tail(&scan->file_insert_list, &file->nodelist, file); + scan_file_delayed_insert(scan, file); } /** @@ -1112,7 +1134,6 @@ static int scan_dir(struct snapraid_scan* scan, int output, const char* dir, con if (type == 0) { /* REG */ if (filter_path(&state->filterlist, disk->name, sub_next) == 0) { - uint64_t physical; /* late stat, if not yet called */ if (!st) @@ -1131,18 +1152,7 @@ static int scan_dir(struct snapraid_scan* scan, int output, const char* dir, con } #endif - if (state->opt.force_order == SORT_PHYSICAL) { - if (filephy(path_next, st, &physical) != 0) { - /* LCOV_EXCL_START */ - fprintf(stderr, "Error in getting the physical offset of file '%s'. %s.\n", path_next, strerror(errno)); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ - } - } else { - physical = 0; - } - - scan_file(scan, output, sub_next, st, physical); + scan_file(scan, output, sub_next, st, FILEPHY_UNREAD_OFFSET); processed = 1; } else { if (state->opt.verbose) { @@ -1326,6 +1336,9 @@ void state_scan(struct snapraid_state* state, int output) uint64_t phy_last; struct snapraid_file* phy_file_last; + if (!output) + printf("Mapping disk %s...\n", disk->name); + /* check for removed files */ node = disk->filelist; while (node) { @@ -1402,20 +1415,24 @@ void state_scan(struct snapraid_state* state, int output) /* insert all the new files, we insert them only after the deletion */ /* to reuse the just freed space */ + /* also check if the physical offset reported are fakes or not */ node = scan->file_insert_list; phy_count = 0; phy_dup = 0; - phy_last = -1; + phy_last = FILEPHY_UNREAD_OFFSET; phy_file_last = 0; while (node) { struct snapraid_file* file = node->data; /* if the file is not empty, count duplicate physical offsets */ if (state->opt.force_order == SORT_PHYSICAL && file->size != 0) { - if (phy_file_last != 0 && file->physical == phy_last && phy_last != FILEPHY_WITHOUT_OFFSET) { - /* if verbose, prints the list of duplicates */ - /* if they are supposed real offsets */ - if (state->opt.verbose && phy_last != FILEPHY_UNREPORTED_OFFSET) { + if (phy_file_last != 0 && file->physical == phy_last + /* files without offset are expected to have duplicates */ + && phy_last != FILEPHY_WITHOUT_OFFSET + ) { + /* if verbose, prints the list of duplicates real offsets */ + /* other cases are for offsets not supported, so we don't need to report them file by file */ + if (state->opt.verbose && phy_last >= FILEPHY_REAL_OFFSET) { fprintf(stderr, "WARNING! Files '%s%s' and '%s%s' have the same physical offset %" PRId64 ".\n", disk->dir, phy_file_last->sub, disk->dir, file->sub, phy_last); } ++phy_dup; diff --git a/cmdline/unix.c b/cmdline/unix.c index 77fee7e3..7ac6b628 100644 --- a/cmdline/unix.c +++ b/cmdline/unix.c @@ -129,7 +129,7 @@ int devuuid(uint64_t device, char* uuid, size_t uuid_size) } #endif -int filephy(const char* path, struct stat* st, uint64_t* physical) +int filephy(const char* path, uint64_t size, uint64_t* physical) { #if HAVE_LINUX_FIEMAP_H /* In Linux gets the real physical address of the file */ @@ -162,7 +162,7 @@ int filephy(const char* path, struct stat* st, uint64_t* physical) } /* if the file is empty, FIBMAP doesn't work, and we don't even try to use it */ - if (st->st_size == 0) { + if (size == 0) { *physical = FILEPHY_WITHOUT_OFFSET; if (close(f) == -1) return -1; @@ -199,7 +199,7 @@ int filephy(const char* path, struct stat* st, uint64_t* physical) *physical = FILEPHY_UNREPORTED_OFFSET; (void)path; /* not used here */ - (void)st; + (void)size; #endif return 0; @@ -267,8 +267,9 @@ uint64_t tick(void) #endif } -void os_init(void) +void os_init(int opt) { + (void)opt; } void os_done(void)