# HG changeset patch # User Markus Mützel # Date 1683308963 -7200 # Node ID ed3a18fe328a5685b4aad630714ed4db6e570397 # Parent 7ce8302036c116ad1d7b2a8decf5bcc221e08e2c Add more efficient functions to check for files or directories on Windows (bug #59711). * liboctave/system/lo-sysdep.h, liboctave/system/lo-sysdep.cc (octave::sys::file_exists, octave::sys::dir_exists): Calling `stat` on Windows is inefficient because it isn't a native function. Use native API functions to check if a file or directory with a given name exists. diff -r 7ce8302036c1 -r ed3a18fe328a liboctave/system/lo-sysdep.cc --- a/liboctave/system/lo-sysdep.cc Fri May 05 10:24:17 2023 +0100 +++ b/liboctave/system/lo-sysdep.cc Fri May 05 19:49:23 2023 +0200 @@ -33,6 +33,7 @@ #include "dir-ops.h" #include "file-ops.h" +#include "file-stat.h" #include "lo-error.h" #include "lo-sysdep.h" #include "localcharset-wrapper.h" @@ -308,8 +309,127 @@ return strcmp (buf1, buf2); } +static std::string +get_formatted_last_error () +{ + std::string msg = ""; + + DWORD last_error = GetLastError (); + + wchar_t *error_text = nullptr; + FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, last_error, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast (&error_text), 0, nullptr); + + if (error_text != nullptr) + { + msg = u8_from_wstring (error_text); + LocalFree (error_text); + } + else + msg = "Unknown error."; + + return msg; +} #endif +bool +file_exists (const std::string& filename, bool is_dir) +{ + // Check if a file with the given name exists on the file system. If is_dir + // is true (the default), also return true if filename refers to a directory. +#if defined (OCTAVE_USE_WINDOWS_API) + std::wstring w_fn = u8_to_wstring (filename); + + DWORD f_attr = GetFileAttributesW (w_fn.c_str ()); + + return ((f_attr != INVALID_FILE_ATTRIBUTES) + && (is_dir || ! (f_attr & FILE_ATTRIBUTE_DIRECTORY))); + +#else + file_stat fs (filename); + + return (fs && (fs.is_reg () || (is_dir && fs.is_dir ()))); + +#endif +} + +bool +file_exists (const std::string& filename, bool is_dir, std::string& msg) +{ + // Check if a file with the given name exists on the file system. If is_dir + // is true (the default), also return true if filename refers to a directory. +#if defined (OCTAVE_USE_WINDOWS_API) + std::wstring w_fn = u8_to_wstring (filename); + + DWORD f_attr = GetFileAttributesW (w_fn.c_str ()); + + if (f_attr == INVALID_FILE_ATTRIBUTES) + msg = get_formatted_last_error (); + + return ((f_attr != INVALID_FILE_ATTRIBUTES) + && (is_dir || ! (f_attr & FILE_ATTRIBUTE_DIRECTORY))); + +#else + file_stat fs (filename); + + if (! fs) + msg = fs.error (); + + return (fs && (fs.is_reg () || (is_dir && fs.is_dir ()))); + +#endif +} + +bool +dir_exists (const std::string& dirname) +{ + // Check if a directory with the given name exists on the file system. +#if defined (OCTAVE_USE_WINDOWS_API) + std::wstring w_dn = u8_to_wstring (dirname); + + DWORD f_attr = GetFileAttributesW (w_dn.c_str ()); + + return ((f_attr != INVALID_FILE_ATTRIBUTES) + && (f_attr & FILE_ATTRIBUTE_DIRECTORY)); + +#else + file_stat fs (dirname); + + return (fs && fs.is_dir ()); + +#endif +} + +bool +dir_exists (const std::string& dirname, std::string& msg) +{ + // Check if a directory with the given name exists on the file system. +#if defined (OCTAVE_USE_WINDOWS_API) + std::wstring w_dn = u8_to_wstring (dirname); + + DWORD f_attr = GetFileAttributesW (w_dn.c_str ()); + + if (f_attr == INVALID_FILE_ATTRIBUTES) + msg = get_formatted_last_error (); + + return ((f_attr != INVALID_FILE_ATTRIBUTES) + && (f_attr & FILE_ATTRIBUTE_DIRECTORY)); + +#else + file_stat fs (dirname); + + if (! fs) + msg = fs.error (); + + return (fs && fs.is_dir ()); + +#endif +} + std::FILE * fopen (const std::string& filename, const std::string& mode) { diff -r 7ce8302036c1 -r ed3a18fe328a liboctave/system/lo-sysdep.h --- a/liboctave/system/lo-sysdep.h Fri May 05 10:24:17 2023 +0100 +++ b/liboctave/system/lo-sysdep.h Fri May 05 19:49:23 2023 +0200 @@ -51,6 +51,17 @@ get_dirlist (const std::string& dirname, string_vector& dirlist, std::string& msg); +extern OCTAVE_API bool +file_exists (const std::string& filename, bool is_dir = true); + +extern OCTAVE_API bool +file_exists (const std::string& filename, bool is_dir, std::string& msg); + +extern OCTAVE_API bool dir_exists (const std::string& dirname); + +extern OCTAVE_API bool +dir_exists (const std::string& dirname, std::string& msg); + extern OCTAVE_API std::FILE * fopen (const std::string& name, const std::string& mode);