From c513af08ff048e7b80d6ab7c5ebf67ee367227cb Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Wed, 1 Oct 2014 21:44:35 +0200 Subject: [PATCH] Ensures to call lstat_ex() only on regular files. --- cmdline/import.c | 11 +++++++++++ cmdline/mingw.h | 25 ++++++++++++++++++------- cmdline/pool.c | 11 +++++++++++ cmdline/scan.c | 25 ++++++++++++++++--------- cmdline/state.c | 2 +- 5 files changed, 57 insertions(+), 17 deletions(-) diff --git a/cmdline/import.c b/cmdline/import.c index 328a1f22..adfda914 100644 --- a/cmdline/import.c +++ b/cmdline/import.c @@ -265,6 +265,17 @@ static void import_dir(struct snapraid_state* state, const char* dir) #if HAVE_STRUCT_DIRENT_D_STAT /* convert dirent to lstat result */ dirent_lstat(dd, &st); + + /* if the st_mode field is missing, takes care to fill it using normal lstat() */ + /* at now this can happen only in Windows */ + if (st.st_mode == 0) { + if (lstat(path, &st) != 0) { + /* LCOV_EXCL_START */ + fprintf(stderr, "Error in stat file/directory '%s'. %s.\n", path, strerror(errno)); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + } #else /* get lstat info about the file */ if (lstat(path, &st) != 0) { diff --git a/cmdline/mingw.h b/cmdline/mingw.h index 9d660c85..f6f232c5 100644 --- a/cmdline/mingw.h +++ b/cmdline/mingw.h @@ -142,13 +142,14 @@ struct windows_stat { int windows_fstat(int fd, struct windows_stat* st); /** - * Like the C lstat() but without some information. + * Like the C lstat(), but with some limitations. * * The st_ino field may be 0 if it's not possible to read it in a fast way. + * Specifically this always happens. * * In case of hardlinks, the size and the attributes of the file can - * be completely bogus, because changes made by other hardlinks are reported in the - * directory entry only when the file is opened. + * be completely bogus, because changes made by other hardlinks are reported + * in the directory entry only when the file is opened. * * MSDN CreateHardLinks * http://msdn.microsoft.com/en-us/library/windows/desktop/aa363860%28v=vs.85%29.aspx @@ -181,9 +182,14 @@ int windows_mkdir(const char* file); int windows_rmdir(const char* file); /** - * Like the C lstat(). - - * It doesn't work for all kind of files and directories. For example "\System Volume Information" cannot be opened. + * Like the C lstat(), but with some limitations. + * + * This call fills all the st_* fields of the stat struct. + * + * It doesn't work for all kinds of files and directories. + * You must call it only for regular files. + * For example, "\System Volume Information" cannot be accessed. + * * Note that instead lstat() works for all the files. */ #define HAVE_LSTAT_EX 1 @@ -266,10 +272,15 @@ struct windows_dirent* windows_readdir(windows_dir* dirstream); int windows_closedir(windows_dir* dirstream); /** - * Convert a dirent record to a lstat record. + * Convert a dirent record to a lstat record, but with some limitations. * * The st_mode field may be 0 if the file is a reparse point. + * Specifically this happens if we are using GetFileInformationByHandleEx() + * to read the directory stream. + * * The st_ino field may be 0 if it's not possible to read it in a fast way. + * Specifically this happens if we are using FindFirst/FindNext to enumerate + * the directory. * * In such cases, call lstat_ex() to fill the missing fields. */ diff --git a/cmdline/pool.c b/cmdline/pool.c index b327d5d8..481381ff 100644 --- a/cmdline/pool.c +++ b/cmdline/pool.c @@ -67,6 +67,17 @@ static int clean_dir(struct snapraid_state* state, const char* dir) #if HAVE_STRUCT_DIRENT_D_STAT /* convert dirent to lstat result */ dirent_lstat(dd, &st); + + /* if the st_mode field is missing, takes care to fill it using normal lstat() */ + /* at now this can happen only in Windows */ + if (st.st_mode == 0) { + if (lstat(path_next, &st) != 0) { + /* LCOV_EXCL_START */ + fprintf(stderr, "Error in stat file/directory '%s'. %s.\n", path_next, strerror(errno)); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + } #else /* get lstat info about the file */ if (lstat(path_next, &st) != 0) { diff --git a/cmdline/scan.c b/cmdline/scan.c index 0526e2a6..09b88a88 100644 --- a/cmdline/scan.c +++ b/cmdline/scan.c @@ -1019,6 +1019,8 @@ static int scan_dir(struct snapraid_scan* scan, int output, const char* dir, con #if HAVE_STRUCT_DIRENT_D_STAT /* convert dirent to lstat result */ dirent_lstat(dd, &entry->d_stat); + + /* note that at this point the st_mode may be 0 */ #endif memcpy(entry->d_name, dd->d_name, name_len + 1); @@ -1084,10 +1086,12 @@ static int scan_dir(struct snapraid_scan* scan, int output, const char* dir, con /* get the type from stat */ st = DSTAT(path_next, dd, &st_buf); -#if HAVE_LSTAT_EX - /* if the stat entry is incomplete, take care to fill it using the extended lstat() */ +#if HAVE_STRUCT_DIRENT_D_STAT + /* if the st_mode field is missing, takes care to fill it using normal lstat() */ + /* at now this can happen only in Windows, but we cannot call here lstat_ex(), */ + /* because we don't know what kind of file is it, and lstat_ex() doesn't always work */ if (st->st_mode == 0) { - if (lstat_ex(path_next, st) != 0) { + if (lstat(path_next, st) != 0) { /* LCOV_EXCL_START */ fprintf(stderr, "Error in stat file/directory '%s'. %s.\n", path_next, strerror(errno)); exit(EXIT_FAILURE); @@ -1115,8 +1119,9 @@ static int scan_dir(struct snapraid_scan* scan, int output, const char* dir, con st = DSTAT(path_next, dd, &st_buf); #if HAVE_LSTAT_EX - /* if the stat entry is incomplete, take care to fill it using the extended lstat() */ - if (st->st_ino == 0) { + /* if the st_ino field is missing, takes care to fill it using the extended lstat() */ + /* this can happen only in Windows */ + if (st->st_ino == 0) { if (lstat_ex(path_next, st) != 0) { /* LCOV_EXCL_START */ fprintf(stderr, "Error in stat file/directory '%s'. %s.\n", path_next, strerror(errno)); @@ -1177,8 +1182,9 @@ static int scan_dir(struct snapraid_scan* scan, int output, const char* dir, con } else if (type == 2) { /* DIR */ if (filter_dir(&state->filterlist, disk->name, sub_next) == 0) { #ifndef _WIN32 - /* late stat */ - if (!st) st = DSTAT(path_next, dd, &st_buf); + /* late stat, if not yet called */ + if (!st) + st = DSTAT(path_next, dd, &st_buf); /* in Unix don't follow mount points in different devices */ /* in Windows we are already skipping them reporting them as special files */ @@ -1207,8 +1213,9 @@ static int scan_dir(struct snapraid_scan* scan, int output, const char* dir, con } } else { if (filter_path(&state->filterlist, disk->name, sub_next) == 0) { - /* late stat */ - if (!st) st = DSTAT(path_next, dd, &st_buf); + /* late stat, if not yet called */ + if (!st) + st = DSTAT(path_next, dd, &st_buf); fprintf(stderr, "WARNING! Ignoring special '%s' file '%s'\n", stat_desc(st), path_next); } else { diff --git a/cmdline/state.c b/cmdline/state.c index 65505e7c..8f5f8590 100644 --- a/cmdline/state.c +++ b/cmdline/state.c @@ -367,7 +367,7 @@ void state_config(struct snapraid_state* state, const char* path, const char* co /* copy the options */ state->opt = *opt; - /* if unsed, sort by physical order */ + /* if unset, sort by physical order */ if (!state->opt.force_order) state->opt.force_order = SORT_PHYSICAL;