# HG changeset patch # User Markus Mützel # Date 1683977637 -7200 # Node ID 7d663f770c5a0c786229541f8b914f956e7ca37f # Parent 212145b8e5f07dd53459c23849527a2cbd1fbf83 load-path: Avoid using file_stat on Windows (bug #59711). * liboctave/system/oct-time.h, oct-time.cc (octave::sys::file_time): New class to handle an efficient native file time type per platform. * libinterp/corefcn/load-path.h (load_path::dir_info::dir_mtime, load_path::dir_info::dir_time_last_checked): Change type to new class. * libinterp/corefcn/load-path.cc (subdirs_modified, load_path::dir_info::update, load_path::dir_info::initialize): Avoid using file_stat on Windows. diff -r 212145b8e5f0 -r 7d663f770c5a libinterp/corefcn/load-path.cc --- a/libinterp/corefcn/load-path.cc Fri May 12 08:03:14 2023 +0200 +++ b/libinterp/corefcn/load-path.cc Sat May 13 13:33:57 2023 +0200 @@ -32,10 +32,12 @@ #include "dir-ops.h" #include "file-ops.h" -#include "file-stat.h" #include "lo-sysdep.h" #include "oct-env.h" #include "pathsearch.h" +#if ! defined (OCTAVE_USE_WINDOWS_API) +# include "file-stat.h" +#endif #include "defaults.h" #include "defun.h" @@ -193,7 +195,7 @@ //! @return true if directory contains modified subdirectories static bool -subdirs_modified (const std::string& d, const sys::time& last_checked) +subdirs_modified (const std::string& d, const sys::file_time& last_checked) { sys::dir_entry dir (d); @@ -209,13 +211,22 @@ std::string full_name = sys::file_ops::concat (d, fname); - sys::file_stat fs (full_name); - // Check if directory AND if relevant (@,+,private) // AND (if modified OR recursion into (@,+) sub-directories) +#if defined (OCTAVE_USE_WINDOWS_API) + if (sys::dir_exists (full_name) +#else + sys::file_stat fs (full_name); + if (fs && fs.is_dir () +#endif && (fname[0] == '@' || fname[0] == '+' || fname == "private") - && ((fs.mtime () + fs.time_resolution () > last_checked) +#if defined (OCTAVE_USE_WINDOWS_API) + && ((sys::file_time (full_name) +#else + && ((sys::file_time (fs.mtime ().unix_time ()) +#endif + + sys::file_time::time_resolution () > last_checked) || ((fname[0] == '@' || fname[0] == '+') && subdirs_modified (full_name, last_checked)))) return true; @@ -1354,11 +1365,18 @@ bool load_path::dir_info::update () { +#if defined (OCTAVE_USE_WINDOWS_API) + std::string msg; + + if (! sys::dir_exists (dir_name, msg)) + { +#else sys::file_stat fs (dir_name); if (! fs) { std::string msg = fs.error (); +#endif warning_with_id ("Octave:load-path:dir-info:update-failed", "load_path: %s: %s", dir_name.c_str (), msg.c_str ()); @@ -1382,7 +1400,12 @@ // slow things down tremendously for large directories. const dir_info& di = p->second; - if ((fs.mtime () + fs.time_resolution () +#if defined (OCTAVE_USE_WINDOWS_API) + if ((sys::file_time (dir_name) +#else + if ((sys::file_time (fs.mtime ().unix_time ()) +#endif + + sys::file_time::time_resolution () > di.dir_time_last_checked) || subdirs_modified (dir_name, dir_time_last_checked)) initialize (); @@ -1417,7 +1440,12 @@ } } // Absolute path, check timestamp to see whether it requires re-caching - else if (fs.mtime () + fs.time_resolution () > dir_time_last_checked +#if defined (OCTAVE_USE_WINDOWS_API) + else if (sys::file_time (dir_name) +#else + else if (sys::file_time (fs.mtime ().unix_time ()) +#endif + + sys::file_time::time_resolution () > dir_time_last_checked || subdirs_modified (dir_name, dir_time_last_checked)) initialize (); @@ -1450,17 +1478,28 @@ { is_relative = ! sys::env::absolute_pathname (dir_name); - dir_time_last_checked = sys::time (static_cast (0)); - + dir_time_last_checked = sys::file_time (static_cast (0)); + +#if defined (OCTAVE_USE_WINDOWS_API) + std::string msg; + + if (sys::dir_exists (dir_name, msg)) +#else sys::file_stat fs (dir_name); if (fs) +#endif { method_file_map.clear (); package_dir_map.clear (); - dir_mtime = fs.mtime (); - dir_time_last_checked = sys::time (); +#if defined (OCTAVE_USE_WINDOWS_API) + dir_mtime = sys::file_time (dir_name); +#else + dir_mtime = fs.mtime ().unix_time (); +#endif + + dir_time_last_checked = sys::file_time (); get_file_list (dir_name); @@ -1486,7 +1525,9 @@ } else { +#if ! defined (OCTAVE_USE_WINDOWS_API) std::string msg = fs.error (); +#endif warning ("load_path: %s: %s", dir_name.c_str (), msg.c_str ()); } } diff -r 212145b8e5f0 -r 7d663f770c5a libinterp/corefcn/load-path.h --- a/libinterp/corefcn/load-path.h Fri May 12 08:03:14 2023 +0200 +++ b/libinterp/corefcn/load-path.h Sat May 13 13:33:57 2023 +0200 @@ -289,8 +289,8 @@ std::string dir_name; std::string abs_dir_name; bool is_relative; - sys::time dir_mtime; - sys::time dir_time_last_checked; + sys::file_time dir_mtime; + sys::file_time dir_time_last_checked; string_vector all_files; string_vector fcn_files; fcn_file_map_type private_file_map; diff -r 212145b8e5f0 -r 7d663f770c5a liboctave/system/oct-time.cc --- a/liboctave/system/oct-time.cc Fri May 12 08:03:14 2023 +0200 +++ b/liboctave/system/oct-time.cc Sat May 13 13:33:57 2023 +0200 @@ -36,6 +36,8 @@ #if defined (OCTAVE_USE_WINDOWS_API) # include +#else +# include "file-stat.h" #endif #include "lo-error.h" @@ -370,5 +372,42 @@ m_cpu = cpu_time (usr_sec, sys_sec, usr_usec, sys_usec); } +file_time::file_time () +{ +#if defined (OCTAVE_USE_WINDOWS_API) + FILETIME curr_file_time; + GetSystemTimeAsFileTime (&curr_file_time); + m_time + = (static_cast (curr_file_time.dwHighDateTime)) >> 32 + | curr_file_time.dwLowDateTime; +#else + time_t ot_unix_time; + time_t ot_usec; + octave_gettimeofday_wrapper (&ot_unix_time, &ot_usec); + // Discard usec. We are assuming a 1 second resolution anyway. + m_time = ot_unix_time; +#endif +} + +file_time::file_time (const std::string& filename) +{ +#if defined (OCTAVE_USE_WINDOWS_API) + std::wstring wfull_name = sys::u8_to_wstring (filename); + HANDLE h_file + = CreateFile (wfull_name.c_str (), GENERIC_READ, + FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, + nullptr); + FILETIME last_access_time; + GetFileTime (h_file, nullptr, &last_access_time, nullptr); + + m_time + = (static_cast (last_access_time.dwHighDateTime)) >> 32 + | last_access_time.dwLowDateTime; +#else + file_stat fs = file_stat (filename); + m_time = fs.mtime ().unix_time (); +#endif +} + OCTAVE_END_NAMESPACE(sys) OCTAVE_END_NAMESPACE(octave) diff -r 212145b8e5f0 -r 7d663f770c5a liboctave/system/oct-time.h --- a/liboctave/system/oct-time.h Fri May 12 08:03:14 2023 +0200 +++ b/liboctave/system/oct-time.h Sat May 13 13:33:57 2023 +0200 @@ -31,6 +31,18 @@ #include #include +#if defined (OCTAVE_USE_WINDOWS_API) +// Some Windows headers must be included in a certain order. +// Don't include "windows.h" here to avoid potential issues due to that. +// Instead just define the one type we need for the interface of one function. +struct OCTAVE_WIN_FILETIME +{ + uint32_t dwLowDateTime; + uint32_t dwHighDateTime; +}; +#endif + + static inline double as_double (OCTAVE_TIME_T sec, long usec) { @@ -465,6 +477,113 @@ long m_nivcsw; }; +// class to handle file time efficiently on different platforms + +class OCTAVE_API file_time +{ +public: + + file_time (); + + file_time (OCTAVE_TIME_T t) + : m_time (t) + { } + +#if defined (OCTAVE_USE_WINDOWS_API) + file_time (OCTAVE_WIN_FILETIME& t) + { + m_time = (static_cast (t.dwHighDateTime)) >> 32 + | t.dwLowDateTime; + } +#endif + + file_time (const std::string& filename); + + file_time (const file_time& ot) + { + m_time = ot.time (); + } + + file_time& operator = (const file_time& ot) + { + if (this != &ot) + m_time = ot.time (); + + return *this; + } + + ~file_time () = default; + + inline static file_time time_resolution () + { +#if defined (OCTAVE_USE_WINDOWS_API) + // FAT file systems have 2 seconds resolution for the modification time. + static OCTAVE_TIME_T time_resolution = 20000; +#else + // Assume 1 second (see file_stat) + static OCTAVE_TIME_T time_resolution = 1; +#endif + return time_resolution; + } + + inline bool + operator == (const file_time& t2) const + { + return time () == t2.time (); + } + + inline bool + operator != (const file_time& t2) const + { + return ! (*this == t2); + } + + inline bool + operator < (const file_time& t2) const + { + return time () < t2.time (); + } + + inline bool + operator <= (const file_time& t2) const + { + return (*this < t2 || *this == t2); + } + + inline bool + operator > (const file_time& t2) const + { + return time () > t2.time (); + } + + inline bool + operator >= (const file_time& t2) const + { + return (*this > t2 || *this == t2); + } + + inline file_time + operator + (const file_time& t2) const + { + return file_time (time () + t2.time ()); + } + + inline file_time + operator + (const OCTAVE_TIME_T t2) const + { + return file_time (time () + t2); + } + + OCTAVE_TIME_T time () const { return m_time; } + +private: + + // The native file time type differs per platform. + // On POSIX, this is the number of 1 second intervals since the epoch. + // On Windows, this is the number of 0.1 ms intervals since a different epoch. + OCTAVE_TIME_T m_time; +}; + OCTAVE_END_NAMESPACE(sys) OCTAVE_END_NAMESPACE(octave)