diff --git a/old-configure.in b/old-configure.in index 04e4ca9c76e0..c7aaabaa645b 100644 --- a/old-configure.in +++ b/old-configure.in @@ -1133,7 +1133,7 @@ fi dnl Checks for library functions. dnl ======================================================== -AC_CHECK_FUNCS(stat64 lstat64 truncate64 statvfs64 statvfs statfs64 statfs getpagesize gmtime_r localtime_r arc4random arc4random_buf mallinfo gettid lchown setpriority strerror syscall) +AC_CHECK_FUNCS(stat64 lstat64 truncate64 statvfs64 statvfs statfs64 statfs getpagesize gmtime_r localtime_r arc4random arc4random_buf mallinfo gettid lchown setpriority strerror syscall lutimes) dnl check for clock_gettime(), the CLOCK_MONOTONIC clock AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC), diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp index 5d167e3bf7ae..23594bba1e7f 100644 --- a/xpcom/io/nsLocalFileUnix.cpp +++ b/xpcom/io/nsLocalFileUnix.cpp @@ -13,9 +13,13 @@ #include "mozilla/DebugOnly.h" #include "mozilla/Sprintf.h" #include "mozilla/FilePreferences.h" +#include "prtime.h" -#include +#include +#include #include +#include +#include #include #include #include @@ -1073,68 +1077,92 @@ nsLocalFile::Remove(bool aRecursive) { return NSRESULT_FOR_RETURN(rmdir(mPath.get())); } -NS_IMETHODIMP -nsLocalFile::GetLastModifiedTime(PRTime* aLastModTime) { +nsresult nsLocalFile::GetLastModifiedTimeImpl(PRTime* aLastModTime, + bool aFollowLinks) { CHECK_mPath(); if (NS_WARN_IF(!aLastModTime)) { return NS_ERROR_INVALID_ARG; } - PRFileInfo64 info; - if (PR_GetFileInfo64(mPath.get(), &info) != PR_SUCCESS) { + using StatFn = int (*)(const char*, struct STAT*); + StatFn statFn = aFollowLinks ? &STAT : &LSTAT; + + struct STAT fileStats {}; + if (statFn(mPath.get(), &fileStats) < 0) { return NSRESULT_FOR_ERRNO(); } - PRTime modTime = info.modifyTime; - if (modTime == 0) { - *aLastModTime = 0; - } else { - *aLastModTime = modTime / PR_USEC_PER_MSEC; - } + + int64_t modSec = 0; + int64_t modNSec = 0; +#if (defined(__APPLE__) && defined(__MACH__)) + modSec = fileStats.st_mtimespec.tv_sec; + modNSec = fileStats.st_mtimespec.tv_nsec; +#else + modSec = fileStats.st_mtim.tv_sec; + modNSec = fileStats.st_mtim.tv_nsec; +#endif + *aLastModTime = + PRTime(modSec * PR_MSEC_PER_SEC) + PRTime(modNSec / PR_NSEC_PER_MSEC); return NS_OK; } -NS_IMETHODIMP -nsLocalFile::SetLastModifiedTime(PRTime aLastModTime) { +nsresult nsLocalFile::SetLastModifiedTimeImpl(PRTime aLastModTime, + bool aFollowLinks) { CHECK_mPath(); + using UtimesFn = int (*)(const char*, const timeval*); + UtimesFn utimesFn = &utimes; + +#if HAVE_LUTIMES + if (!aFollowLinks) { + utimesFn = &lutimes; + } +#endif + int result; if (aLastModTime != 0) { ENSURE_STAT_CACHE(); - struct utimbuf ut; - ut.actime = mCachedStat.st_atime; + timeval access{}; +#if (defined(__APPLE__) && defined(__MACH__)) + access.tv_sec = mCachedStat.st_atimespec.tv_sec; + access.tv_usec = mCachedStat.st_atimespec.tv_nsec / 1000; +#else + access.tv_sec = mCachedStat.st_atim.tv_sec; + access.tv_usec = mCachedStat.st_atim.tv_nsec / 1000; +#endif + timeval modification{}; + modification.tv_sec = aLastModTime / PR_MSEC_PER_SEC; + modification.tv_usec = (aLastModTime % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC; - // convert milliseconds to seconds since the unix epoch - ut.modtime = (time_t)(aLastModTime / PR_MSEC_PER_SEC); - result = utime(mPath.get(), &ut); + timeval times[2]; + times[0] = access; + times[1] = modification; + result = utimesFn(mPath.get(), times); } else { - result = utime(mPath.get(), nullptr); + result = utimesFn(mPath.get(), nullptr); } return NSRESULT_FOR_RETURN(result); } NS_IMETHODIMP -nsLocalFile::GetLastModifiedTimeOfLink(PRTime* aLastModTimeOfLink) { - CHECK_mPath(); - if (NS_WARN_IF(!aLastModTimeOfLink)) { - return NS_ERROR_INVALID_ARG; - } - - struct STAT sbuf; - if (LSTAT(mPath.get(), &sbuf) == -1) { - return NSRESULT_FOR_ERRNO(); - } - *aLastModTimeOfLink = PRTime(sbuf.st_mtime) * PR_MSEC_PER_SEC; - - return NS_OK; +nsLocalFile::GetLastModifiedTime(PRTime* aLastModTime) { + return GetLastModifiedTimeImpl(aLastModTime, /* follow links? */ true); +} + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTime(PRTime aLastModTime) { + return SetLastModifiedTimeImpl(aLastModTime, /* follow links ? */ true); +} + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTimeOfLink(PRTime* aLastModTimeOfLink) { + return GetLastModifiedTimeImpl(aLastModTimeOfLink, /* follow link? */ false); } -/* - * utime(2) may or may not dereference symlinks, joy. - */ NS_IMETHODIMP nsLocalFile::SetLastModifiedTimeOfLink(PRTime aLastModTimeOfLink) { - return SetLastModifiedTime(aLastModTimeOfLink); + return SetLastModifiedTimeImpl(aLastModTimeOfLink, /* follow links? */ false); } /* diff --git a/xpcom/io/nsLocalFileUnix.h b/xpcom/io/nsLocalFileUnix.h index 48fe531b2875..f3394218cabe 100644 --- a/xpcom/io/nsLocalFileUnix.h +++ b/xpcom/io/nsLocalFileUnix.h @@ -122,6 +122,9 @@ class nsLocalFile final nsresult CreateAndKeepOpen(uint32_t aType, int aFlags, uint32_t aPermissions, PRFileDesc** aResult); + + nsresult SetLastModifiedTimeImpl(PRTime aLastModTime, bool aFollowLinks); + nsresult GetLastModifiedTimeImpl(PRTime* aLastModTime, bool aFollowLinks); }; #endif /* _nsLocalFileUNIX_H_ */