Ensures to call lstat_ex() only on regular files.

This commit is contained in:
Andrea Mazzoleni 2014-10-01 21:44:35 +02:00
parent 524360d8c2
commit c513af08ff
5 changed files with 57 additions and 17 deletions

View file

@ -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) {

View file

@ -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.
*/

View file

@ -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) {

View file

@ -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 {

View file

@ -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;