Index: cmake/config-ix.cmake =================================================================== --- cmake/config-ix.cmake +++ cmake/config-ix.cmake @@ -7,6 +7,7 @@ include(CheckLibraryExists) include(CheckSymbolExists) include(CheckFunctionExists) +include(CheckStructHasMember) include(CheckCCompilerFlag) include(CheckCompilerVersion) @@ -248,6 +249,11 @@ endif() endif() +CHECK_STRUCT_HAS_MEMBER("struct stat" st_mtimespec.tv_nsec + "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC) +CHECK_STRUCT_HAS_MEMBER("struct stat" st_mtim.tv_nsec + "sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) + check_symbol_exists(__GLIBC__ stdio.h LLVM_USING_GLIBC) if( LLVM_USING_GLIBC ) add_definitions( -D_GNU_SOURCE ) Index: include/llvm/Config/config.h.cmake =================================================================== --- include/llvm/Config/config.h.cmake +++ include/llvm/Config/config.h.cmake @@ -208,6 +208,12 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_TIME_H ${HAVE_SYS_TIME_H} +/* Define to 1 if stat struct has st_mtimespec member .*/ +#cmakedefine HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC ${HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC} + +/* Define to 1 if stat struct has st_mtim member. */ +#cmakedefine HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC ${HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC} + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H} Index: include/llvm/Support/Chrono.h =================================================================== --- include/llvm/Support/Chrono.h +++ include/llvm/Support/Chrono.h @@ -47,6 +47,14 @@ return time_point_cast(system_clock::from_time_t(T)); } +/// Convert a std::time_t + nanoseconds to a TimePoint +LLVM_ATTRIBUTE_ALWAYS_INLINE inline TimePoint<> +toTimePoint(std::time_t T, uint32_t nsec) { + using namespace std::chrono; + return time_point_cast(system_clock::from_time_t(T)) + + nanoseconds(nsec); +} + } // namespace sys raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP); Index: include/llvm/Support/FileSystem.h =================================================================== --- include/llvm/Support/FileSystem.h +++ include/llvm/Support/FileSystem.h @@ -160,6 +160,8 @@ #if defined(LLVM_ON_UNIX) time_t fs_st_atime = 0; time_t fs_st_mtime = 0; + uint32_t fs_st_atime_nsec = 0; + uint32_t fs_st_mtime_nsec = 0; uid_t fs_st_uid = 0; gid_t fs_st_gid = 0; off_t fs_st_size = 0; @@ -180,9 +182,12 @@ explicit basic_file_status(file_type Type) : Type(Type) {} #if defined(LLVM_ON_UNIX) - basic_file_status(file_type Type, perms Perms, time_t ATime, time_t MTime, + basic_file_status(file_type Type, perms Perms, time_t ATime, + uint32_t ATimeNSec, time_t MTime, uint32_t MTimeNSec, uid_t UID, gid_t GID, off_t Size) - : fs_st_atime(ATime), fs_st_mtime(MTime), fs_st_uid(UID), fs_st_gid(GID), + : fs_st_atime(ATime), fs_st_mtime(MTime), + fs_st_atime_nsec(ATimeNSec), fs_st_mtime_nsec(MTimeNSec), + fs_st_uid(UID), fs_st_gid(GID), fs_st_size(Size), Type(Type), Perms(Perms) {} #elif defined(_WIN32) basic_file_status(file_type Type, perms Perms, uint32_t LastAccessTimeHigh, @@ -199,7 +204,20 @@ // getters file_type type() const { return Type; } perms permissions() const { return Perms; } + + /// The file access time as reported from the underlying file system. + /// + /// Also see comments on \c getLastModificationTime() related to the precision + /// of the returned value. TimePoint<> getLastAccessedTime() const; + + /// The file modification time as reported from the underlying file system. + /// + /// The returned value allows for nanosecond precision but the actual + /// resolution is an implementation detail of the underlying file system. + /// There is no guarantee for what kind of resolution you can expect, the + /// resolution can differ across platforms and even across mountpoints on the + /// same machine. TimePoint<> getLastModificationTime() const; #if defined(LLVM_ON_UNIX) @@ -247,8 +265,11 @@ #if defined(LLVM_ON_UNIX) file_status(file_type Type, perms Perms, dev_t Dev, nlink_t Links, ino_t Ino, - time_t ATime, time_t MTime, uid_t UID, gid_t GID, off_t Size) - : basic_file_status(Type, Perms, ATime, MTime, UID, GID, Size), + time_t ATime, uint32_t ATimeNSec, + time_t MTime, uint32_t MTimeNSec, + uid_t UID, gid_t GID, off_t Size) + : basic_file_status(Type, Perms, ATime, ATimeNSec, MTime, MTimeNSec, + UID, GID, Size), fs_st_dev(Dev), fs_st_nlinks(Links), fs_st_ino(Ino) {} #elif defined(_WIN32) file_status(file_type Type, perms Perms, uint32_t LinkCount, Index: lib/Support/Unix/Path.inc =================================================================== --- lib/Support/Unix/Path.inc +++ lib/Support/Unix/Path.inc @@ -229,11 +229,11 @@ } TimePoint<> basic_file_status::getLastAccessedTime() const { - return toTimePoint(fs_st_atime); + return toTimePoint(fs_st_atime, fs_st_atime_nsec); } TimePoint<> basic_file_status::getLastModificationTime() const { - return toTimePoint(fs_st_mtime); + return toTimePoint(fs_st_mtime, fs_st_mtime_nsec); } UniqueID file_status::getUniqueID() const { @@ -591,11 +591,22 @@ return EC; } + uint32_t atime_nsec, mtime_nsec; +#if defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC) + atime_nsec = Status.st_atimespec.tv_nsec; + mtime_nsec = Status.st_mtimespec.tv_nsec; +#elif defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) + atime_nsec = Status.st_atim.tv_nsec; + mtime_nsec = Status.st_mtim.tv_nsec; +#else + atime_nsec = mtime_nsec = 0; +#endif + perms Perms = static_cast(Status.st_mode) & all_perms; Result = file_status(typeForMode(Status.st_mode), Perms, Status.st_dev, - Status.st_nlink, Status.st_ino, Status.st_atime, - Status.st_mtime, Status.st_uid, Status.st_gid, - Status.st_size); + Status.st_nlink, Status.st_ino, + Status.st_atime, atime_nsec, Status.st_mtime, mtime_nsec, + Status.st_uid, Status.st_gid, Status.st_size); return std::error_code(); }