Set time of pool links

This avoid index refresh from various applications.
This commit is contained in:
Andrea Mazzoleni 2017-05-01 15:01:38 +02:00
parent 71c11d7ecd
commit 17bec43be2
8 changed files with 141 additions and 7 deletions

View file

@ -13,6 +13,7 @@ SnapRAID HISTORY
compatibility.
* Fixed building in platforms that don't provide major/minor definitions
in sys/types.h.
* When creating 'pool' symbolic links, set their time as the linked files.
* Added support for the Windows 10 symbolic link unprivileged creation,
using SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE.
* Windows binaries built with gcc 4.9.4 using the MXE cross compiler at

3
TODO
View file

@ -5,9 +5,6 @@ This is the list of TODO items for SnapRAID.
- Next
* When creating links, set the mtime like the linked file.
See: https://sourceforge.net/p/snapraid/discussion/1677233/thread/936f0087/?limit=25#b3d6
- Minor
* Allow to filter in diff/list by disk name.

View file

@ -1040,6 +1040,70 @@ int windows_futimens(int fd, struct windows_timespec tv[2])
return 0;
}
int windows_utimensat(int fd, const char* file, struct windows_timespec tv[2], int flags)
{
wchar_t conv_buf[CONV_MAX];
HANDLE h;
FILETIME ft;
uint64_t mtime;
DWORD wflags;
/*
* Support only the absolute paths
*/
if (fd != AT_FDCWD) {
errno = EBADF;
return -1;
}
/*
* Open the handle of the file.
*
* Use FILE_FLAG_BACKUP_SEMANTICS to open directories (it's just ignored for files).
* Use FILE_FLAG_OPEN_REPARSE_POINT to open symbolic links and not the their target.
*
* Note that even with FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
* and FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT some paths
* cannot be opened like "C:\System Volume Information" resulting
* in error ERROR_ACCESS_DENIED.
*/
wflags = FILE_FLAG_BACKUP_SEMANTICS;
if ((flags & AT_SYMLINK_NOFOLLOW) != 0)
wflags |= FILE_FLAG_OPEN_REPARSE_POINT;
h = CreateFileW(convert(conv_buf, file), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, wflags, 0);
if (h == INVALID_HANDLE_VALUE) {
windows_errno(GetLastError());
return -1;
}
/*
* Convert to windows time
*
* How To Convert a UNIX time_t to a Win32 FILETIME or SYSTEMTIME
* http://support.microsoft.com/kb/167296
*/
mtime = tv[0].tv_sec;
mtime *= 10000000;
mtime += tv[0].tv_nsec / 100;
mtime += 116444736000000000;
ft.dwHighDateTime = mtime >> 32;
ft.dwLowDateTime = mtime;
if (!SetFileTime(h, 0, 0, &ft)) {
windows_errno(GetLastError());
CloseHandle(h);
return -1;
}
if (!CloseHandle(h)) {
windows_errno(GetLastError());
return -1;
}
return 0;
}
int windows_rename(const char* from, const char* to)
{
wchar_t conv_buf_from[CONV_MAX];

View file

@ -85,6 +85,11 @@
#define HAVE_FUTIMENS 1
#undef futimens
#define futimens windows_futimens
#define HAVE_UTIMENSAT 1
#define AT_FDCWD -1
#define AT_SYMLINK_NOFOLLOW 1
#undef utimensat
#define utimensat windows_utimensat
#define O_NOFOLLOW 0
#define dirent_hidden windows_dirent_hidden
#define HAVE_STRUCT_DIRENT_D_STAT 1
@ -241,6 +246,11 @@ struct windows_timespec {
*/
int windows_futimens(int fd, struct windows_timespec tv[2]);
/**
* Like the C utimensat().
*/
int windows_utimensat(int fd, const char* file, struct windows_timespec tv[2], int flags);
/**
* Like the C rename().
*/

View file

@ -147,7 +147,7 @@ static int clean_dir(struct snapraid_state* state, const char* dir)
/**
* Create a link to the specified disk entry.
*/
static void make_link(const char* pool_dir, const char* share_dir, struct snapraid_disk* disk, const char* sub)
static void make_link(const char* pool_dir, const char* share_dir, struct snapraid_disk* disk, const char* sub, int64_t mtime_sec, int mtime_nsec)
{
char path[PATH_MAX];
char linkto[PATH_MAX];
@ -196,6 +196,16 @@ static void make_link(const char* pool_dir, const char* share_dir, struct snapra
/* LCOV_EXCL_STOP */
}
}
if (mtime_sec) {
ret = lmtime(path, mtime_sec, mtime_nsec);
if (ret != 0) {
/* LCOV_EXCL_START */
log_fatal("Error setting time to symlink '%s'. %s.\n", path, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
}
void state_pool(struct snapraid_state* state)
@ -236,14 +246,14 @@ void state_pool(struct snapraid_state* state)
/* for each file */
for (j = disk->filelist; j != 0; j = j->next) {
struct snapraid_file* file = j->data;
make_link(pool_dir, share_dir, disk, file->sub);
make_link(pool_dir, share_dir, disk, file->sub, file->mtime_sec, file->mtime_nsec);
++count;
}
/* for each link */
for (j = disk->linklist; j != 0; j = j->next) {
struct snapraid_link* slink = j->data;
make_link(pool_dir, share_dir, disk, slink->sub);
make_link(pool_dir, share_dir, disk, slink->sub, 0, 0);
++count;
}

View file

@ -897,6 +897,52 @@ int fmtime(int f, int64_t mtime_sec, int mtime_nsec)
return ret;
}
int lmtime(const char* path, int64_t mtime_sec, int mtime_nsec)
{
#if HAVE_UTIMENSAT
struct timespec tv[2];
#else
struct timeval tv[2];
#endif
int ret;
#if HAVE_UTIMENSAT /* utimensat() is preferred because it gives nanosecond precision */
tv[0].tv_sec = mtime_sec;
if (mtime_nsec != STAT_NSEC_INVALID)
tv[0].tv_nsec = mtime_nsec;
else
tv[0].tv_nsec = 0;
tv[1].tv_sec = tv[0].tv_sec;
tv[1].tv_nsec = tv[0].tv_nsec;
ret = utimensat(AT_FDCWD, path, tv, AT_SYMLINK_NOFOLLOW);
#elif HAVE_LUTIMES /* fallback to lutimes() if nanosecond precision is not available */
tv[0].tv_sec = mtime_sec;
if (mtime_nsec != STAT_NSEC_INVALID)
tv[0].tv_usec = mtime_nsec / 1000;
else
tv[0].tv_usec = 0;
tv[1].tv_sec = tv[0].tv_sec;
tv[1].tv_usec = tv[0].tv_usec;
ret = lutimes(path, tv);
#elif HAVE_FUTIMESAT /* fallback to futimesat() for Solaris, it only has futimesat() */
tv[0].tv_sec = mtime_sec;
if (mtime_nsec != STAT_NSEC_INVALID)
tv[0].tv_usec = mtime_nsec / 1000;
else
tv[0].tv_usec = 0;
tv[1].tv_sec = tv[0].tv_sec;
tv[1].tv_usec = tv[0].tv_usec;
ret = futimesat(AT_FDCWD, path, tv);
#else
#error No function available to set file timestamps with sub-second precision
#endif
return ret;
}
/****************************************************************************/
/* advise */

View file

@ -322,6 +322,12 @@ int mkancestor(const char* file);
*/
int fmtime(int f, int64_t mtime_sec, int mtime_nsec);
/**
* Change the modification time of a file or link.
* Note that links are NOT deferenced.
*/
int lmtime(const char* path, int64_t mtime_sec, int mtime_nsec);
/****************************************************************************/
/* advise */

View file

@ -99,7 +99,7 @@ AC_CHECK_FUNCS([getopt getopt_long snprintf vsnprintf sigaction])
AC_CHECK_FUNCS([ftruncate fallocate access])
AC_CHECK_FUNCS([fsync posix_fadvise sync_file_range])
AC_CHECK_FUNCS([getc_unlocked ferror_unlocked fnmatch])
AC_CHECK_FUNCS([futimes futimens futimesat localtime_r])
AC_CHECK_FUNCS([futimes futimens futimesat localtime_r lutimes utimensat])
AC_CHECK_FUNCS([fstatat flock statfs])
AC_CHECK_FUNCS([mach_absolute_time])
AC_CHECK_FUNCS([backtrace backtrace_symbols])