From: Dmitriy Anisimkov Date: Mon, 3 Aug 2020 06:18:20 +0000 (+0600) Subject: [Ada] Improve precision of Ada.Directories.Modification_Time X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=948c6d7e9e60ef8e1324bfed6d8d937112bef53d;p=gcc.git [Ada] Improve precision of Ada.Directories.Modification_Time gcc/ada/ * adaint.c (__gnat_file_time): New routine. (__gnat_copy_attribs): Copy timestamps in nanoseconds. * libgnat/a-direct.adb (C_Modification_Time): Bind to __gnat_file_time. (Modification_Time): Call to C_Modification_Time. --- diff --git a/gcc/ada/adaint.c b/gcc/ada/adaint.c index c44d1932332..9ef02438308 100644 --- a/gcc/ada/adaint.c +++ b/gcc/ada/adaint.c @@ -60,6 +60,7 @@ /* We want to use the POSIX variants of include files. */ #define POSIX #include "vxWorks.h" +#include #if defined (__mips_vxworks) #include "cacheLib.h" @@ -1474,6 +1475,74 @@ __gnat_file_time_fd (int fd) return __gnat_file_time_fd_attr (fd, &attr); } +extern long long __gnat_file_time(char* name) +{ + long long result; + + if (name == NULL) { + return LLONG_MIN; + } + /* Number of seconds between and . */ + static const long long ada_epoch_offset = (136 * 365 + 44 * 366) * 86400LL; +#if defined(_WIN32) + + /* Number of 100 nanoseconds between and . */ + static const long long w32_epoch_offset = + (11644473600LL + ada_epoch_offset) * 1E7; + + WIN32_FILE_ATTRIBUTE_DATA fad; + union + { + FILETIME ft_time; + long long ll_time; + } t_write; + + if (!GetFileAttributesExA(name, GetFileExInfoStandard, &fad)) { + return LLONG_MIN; + } + + t_write.ft_time = fad.ftLastWriteTime; + + /* Next code similar to (t_write.ll_time - w32_epoch_offset) * 100 + but on overflow returns LLONG_MIN value. */ + + if (__builtin_ssubll_overflow(t_write.ll_time, w32_epoch_offset, &result)) { + return LLONG_MIN; + } + + if (__builtin_smulll_overflow(result, 100, &result)) { + return LLONG_MIN; + } + +#else + + struct stat sb; + if (stat(name, &sb) != 0) { + return LLONG_MIN; + } + + /* Next code similar to + (sb.st_mtime - ada_epoch_offset) * 1E9 + sb.st_mtim.tv_nsec + but on overflow returns LLONG_MIN value. */ + + if (__builtin_ssubll_overflow(sb.st_mtime, ada_epoch_offset, &result)) { + return LLONG_MIN; + } + + if (__builtin_smulll_overflow(result, 1E9, &result)) { + return LLONG_MIN; + } + +#if defined(st_mtime) + if (__builtin_saddll_overflow(result, sb.st_mtim.tv_nsec, &result)) { + return LLONG_MIN; + } +#endif + +#endif + return result; +} + /* Set the file time stamp. */ void @@ -3173,22 +3242,45 @@ __gnat_copy_attribs (char *from ATTRIBUTE_UNUSED, char *to ATTRIBUTE_UNUSED, #else GNAT_STRUCT_STAT fbuf; - struct utimbuf tbuf; if (GNAT_STAT (from, &fbuf) == -1) { return -1; } - /* Do we need to copy timestamp ? */ +#if _POSIX_C_SOURCE >= 200809L + struct timespec tbuf[2]; + if (mode != 2) { - tbuf.actime = fbuf.st_atime; - tbuf.modtime = fbuf.st_mtime; + tbuf[0] = fbuf.st_atim; + tbuf[1] = fbuf.st_mtim; - if (utime (to, &tbuf) == -1) { + if (utimensat (AT_FDCWD, to, tbuf, 0) == -1) { return -1; } } +#else + struct timeval tbuf[2]; + /* Do we need to copy timestamp ? */ + + if (mode != 2) { + tbuf[0].tv_sec = fbuf.st_atime; + tbuf[1].tv_sec = fbuf.st_mtime; + + #if defined(st_mtime) + tbuf[0].tv_usec = fbuf.st_atim.tv_nsec / 1000; + tbuf[1].tv_usec = fbuf.st_mtim.tv_nsec / 1000; + #else + tbuf[0].tv_usec = 0; + tbuf[1].tv_usec = 0; + #endif + + if (utimes (to, tbuf) == -1) { + return -1; + } + } +#endif + /* Do we need to copy file permissions ? */ if (mode != 0 && (chmod (to, fbuf.st_mode) == -1)) { return -1; diff --git a/gcc/ada/libgnat/a-direct.adb b/gcc/ada/libgnat/a-direct.adb index b70bf0eee5d..162ace919f9 100644 --- a/gcc/ada/libgnat/a-direct.adb +++ b/gcc/ada/libgnat/a-direct.adb @@ -30,7 +30,6 @@ ------------------------------------------------------------------------------ with Ada.Calendar; use Ada.Calendar; -with Ada.Calendar.Formatting; use Ada.Calendar.Formatting; with Ada.Characters.Handling; use Ada.Characters.Handling; with Ada.Directories.Validity; use Ada.Directories.Validity; with Ada.Directories.Hierarchical_File_Names; @@ -70,6 +69,15 @@ package body Ada.Directories is pragma Import (C, Max_Path, "__gnat_max_path_len"); -- The maximum length of a path + function C_Modification_Time (N : System.Address) return Ada.Calendar.Time; + pragma Import (C, C_Modification_Time, "__gnat_file_time"); + -- Get modification time for file with name referenced by N + + Invalid_Time : constant Ada.Calendar.Time := + C_Modification_Time (System.Null_Address); + -- Result returned from C_Modification_Time call when routine unable to get + -- file modification time. + type Search_Data is record Is_Valid : Boolean := False; Name : Unbounded_String; @@ -991,14 +999,9 @@ package body Ada.Directories is ----------------------- function Modification_Time (Name : String) return Time is - Date : OS_Time; - Year : Year_Type; - Month : Month_Type; - Day : Day_Type; - Hour : Hour_Type; - Minute : Minute_Type; - Second : Second_Type; + Date : Time; + C_Name : aliased String (1 .. Name'Length + 1); begin -- First, the invalid cases @@ -1006,19 +1009,15 @@ package body Ada.Directories is raise Name_Error with '"' & Name & """ not a file or directory"; else - Date := File_Time_Stamp (Name); - - -- Break down the time stamp into its constituents relative to GMT. - -- This version of Split does not recognize leap seconds or buffer - -- space for time zone processing. + C_Name := Name & ASCII.NUL; + Date := C_Modification_Time (C_Name'Address); - GM_Split (Date, Year, Month, Day, Hour, Minute, Second); - - -- The result must be in GMT. Ada.Calendar. - -- Formatting.Time_Of with default time zone of zero (0) is the - -- routine of choice. + if Date = Invalid_Time then + raise Use_Error with + "Unable to get modification time of the file """ & Name & '"'; + end if; - return Time_Of (Year, Month, Day, Hour, Minute, Second, 0.0); + return Date; end if; end Modification_Time;