From 37f89080ba5ce1ddd7848d2029794a5f5aabb7be Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 23 Oct 2025 09:15:38 -0400 Subject: Introduce global precompiled header to accelerate build Signed-off-by: Rye --- indra/llxml/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra/llxml') diff --git a/indra/llxml/CMakeLists.txt b/indra/llxml/CMakeLists.txt index 508c2b919b..bc79e2ef19 100644 --- a/indra/llxml/CMakeLists.txt +++ b/indra/llxml/CMakeLists.txt @@ -34,6 +34,9 @@ target_link_libraries( llxml ) target_include_directories( llxml INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) +if (USE_PRECOMPILED_HEADERS) + target_precompile_headers(llxml REUSE_FROM llprecompiled) +endif () # tests -- cgit v1.3 From 9440f969033b73e2e2a037c291bcb45619b1dfd1 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Thu, 11 Dec 2025 01:43:58 +0200 Subject: Reapply "Add more functionality to LLFile and cleanup LLAPRFile"" # Conflicts: # indra/llcrashlogger/llcrashlock.cpp # indra/llrender/llshadermgr.cpp # indra/test/CMakeLists.txt --- .../llappearanceutility/llappappearanceutility.cpp | 2 + indra/llaudio/llaudiodecodemgr.cpp | 2 +- indra/llcommon/CMakeLists.txt | 1 + indra/llcommon/llapp.cpp | 4 +- indra/llcommon/llapr.cpp | 220 ---- indra/llcommon/llapr.h | 17 - indra/llcommon/llerror.cpp | 10 +- indra/llcommon/llfile.cpp | 1155 +++++++++++++++----- indra/llcommon/llfile.h | 488 ++++++--- indra/llcommon/tests/llfile_test.cpp | 253 +++++ indra/llfilesystem/lldir.cpp | 56 +- indra/llfilesystem/lldir_win32.cpp | 13 +- indra/llfilesystem/llfilesystem.cpp | 29 +- indra/llfilesystem/llfilesystem.h | 4 +- indra/llfilesystem/tests/lldir_test.cpp | 4 +- indra/llmessage/llassetstorage.cpp | 2 +- indra/llmessage/tests/llmessageconfig_test.cpp | 2 +- indra/llmessage/tests/message_test.cpp | 2 +- indra/llrender/llshadermgr.cpp | 20 +- indra/llxml/tests/llcontrol_test.cpp | 2 +- indra/newview/llappviewer.cpp | 28 +- indra/newview/llfloaterpreference.cpp | 12 +- indra/newview/llfloateruipreview.cpp | 37 +- indra/newview/llpreviewnotecard.cpp | 3 +- indra/newview/llpreviewscript.cpp | 3 +- indra/newview/lltexturecache.cpp | 87 +- indra/newview/llviewerassetstorage.cpp | 2 +- indra/newview/llviewerassetupload.cpp | 39 +- indra/newview/llviewerdisplay.cpp | 5 +- indra/newview/llviewermedia.cpp | 5 +- indra/newview/llvocache.cpp | 6 +- indra/newview/llvoicevivox.cpp | 3 +- 32 files changed, 1624 insertions(+), 892 deletions(-) mode change 100644 => 100755 indra/llcommon/llerror.cpp mode change 100644 => 100755 indra/llcommon/llfile.cpp mode change 100644 => 100755 indra/llcommon/llfile.h create mode 100644 indra/llcommon/tests/llfile_test.cpp mode change 100644 => 100755 indra/llfilesystem/lldir.cpp mode change 100644 => 100755 indra/llfilesystem/lldir_win32.cpp mode change 100644 => 100755 indra/llfilesystem/llfilesystem.cpp mode change 100644 => 100755 indra/llfilesystem/tests/lldir_test.cpp mode change 100644 => 100755 indra/llmessage/tests/llmessageconfig_test.cpp mode change 100644 => 100755 indra/llmessage/tests/message_test.cpp mode change 100644 => 100755 indra/llxml/tests/llcontrol_test.cpp mode change 100644 => 100755 indra/newview/llappviewer.cpp mode change 100644 => 100755 indra/newview/llfloaterpreference.cpp mode change 100644 => 100755 indra/newview/llfloateruipreview.cpp mode change 100644 => 100755 indra/newview/llpreviewnotecard.cpp mode change 100644 => 100755 indra/newview/llpreviewscript.cpp mode change 100644 => 100755 indra/newview/lltexturecache.cpp mode change 100644 => 100755 indra/newview/llviewerdisplay.cpp mode change 100644 => 100755 indra/newview/llviewermedia.cpp mode change 100644 => 100755 indra/newview/llvocache.cpp mode change 100644 => 100755 indra/newview/llvoicevivox.cpp (limited to 'indra/llxml') diff --git a/indra/llappearanceutility/llappappearanceutility.cpp b/indra/llappearanceutility/llappappearanceutility.cpp index d223c859ab..cdc9cfdf40 100644 --- a/indra/llappearanceutility/llappappearanceutility.cpp +++ b/indra/llappearanceutility/llappappearanceutility.cpp @@ -57,6 +57,8 @@ #include "llprocesstexture.h" #include "llprocessskin.h" +#include "apr_getopt.h" + const std::string NOTHING_EXTRA(""); //////////////////////////////////////////// diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp index d8a6fffea6..232b429130 100755 --- a/indra/llaudio/llaudiodecodemgr.cpp +++ b/indra/llaudio/llaudiodecodemgr.cpp @@ -199,7 +199,7 @@ bool LLVorbisDecodeState::initDecode() LL_DEBUGS("AudioEngine") << "Initing decode from vfile: " << mUUID << LL_ENDL; mInFilep = new LLFileSystem(mUUID, LLAssetType::AT_SOUND); - if (!mInFilep || !mInFilep->getSize()) + if (!mInFilep || mInFilep->getSize() <= 0) { LL_WARNS("AudioEngine") << "unable to open vorbis source vfile for reading" << LL_ENDL; delete mInFilep; diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 597a222b32..cb3f0d7842 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -322,6 +322,7 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(lleventdispatcher "" "${test_libs}") LL_ADD_INTEGRATION_TEST(lleventfilter "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llevents "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llfile "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llframetimer "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llhttpdate "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llheteromap "" "${test_libs}") diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 73b50d0a50..aa84895fb8 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -37,7 +37,7 @@ #endif #include "llcommon.h" -#include "llapr.h" + #include "llerrorcontrol.h" #include "llframetimer.h" #include "lllivefile.h" @@ -53,6 +53,8 @@ // // Signal handling #ifndef LL_WINDOWS +#include "apr_signal.h" + # include # include // for fork() void setup_signals(); diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 65ee383c6b..9ea7a34bac 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -526,226 +526,6 @@ S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset) } } -//static -S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) -{ - LL_PROFILE_ZONE_SCOPED; - //***************************************** - LLAPRFilePoolScope scope(pool); - apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), APR_READ|APR_BINARY); - //***************************************** - if (!file_handle) - { - return 0; - } - - llassert(offset >= 0); - - if (offset > 0) - offset = LLAPRFile::seek(file_handle, APR_SET, offset); - - apr_size_t bytes_read; - if (offset < 0) - { - bytes_read = 0; - } - else - { - bytes_read = nbytes ; - apr_status_t s = apr_file_read(file_handle, buf, &bytes_read); - if (s != APR_SUCCESS) - { - LL_WARNS("APR") << " Attempting to read filename: " << filename << LL_ENDL; - ll_apr_warn_status(s); - bytes_read = 0; - } - else - { - llassert_always(bytes_read <= 0x7fffffff); - } - } - - //***************************************** - close(file_handle) ; - //***************************************** - return (S32)bytes_read; -} - -//static -S32 LLAPRFile::writeEx(const std::string& filename, const void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) -{ - LL_PROFILE_ZONE_SCOPED; - apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; - if (offset < 0) - { - flags |= APR_APPEND; - offset = 0; - } - - //***************************************** - LLAPRFilePoolScope scope(pool); - apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), flags); - //***************************************** - if (!file_handle) - { - return 0; - } - - if (offset > 0) - { - offset = LLAPRFile::seek(file_handle, APR_SET, offset); - } - - apr_size_t bytes_written; - if (offset < 0) - { - bytes_written = 0; - } - else - { - bytes_written = nbytes ; - apr_status_t s = apr_file_write(file_handle, buf, &bytes_written); - if (s != APR_SUCCESS) - { - LL_WARNS("APR") << "Attempting to write filename: " << filename << LL_ENDL; - if (APR_STATUS_IS_ENOSPC(s)) - { - LLApp::notifyOutOfDiskSpace(); - } - ll_apr_warn_status(s); - bytes_written = 0; - } - else - { - llassert_always(bytes_written <= 0x7fffffff); - } - } - - //***************************************** - LLAPRFile::close(file_handle); - //***************************************** - - return (S32)bytes_written; -} - -//static -bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool) -{ - apr_status_t s; - - LLAPRFilePoolScope scope(pool); - s = apr_file_remove(filename.c_str(), scope.getVolatileAPRPool()); - - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - LL_WARNS("APR") << " Attempting to remove filename: " << filename << LL_ENDL; - return false; - } - return true; -} - -//static -bool LLAPRFile::rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool) -{ - apr_status_t s; - - LLAPRFilePoolScope scope(pool); - s = apr_file_rename(filename.c_str(), newname.c_str(), scope.getVolatileAPRPool()); - - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - LL_WARNS("APR") << " Attempting to rename filename: " << filename << LL_ENDL; - return false; - } - return true; -} - -//static -bool LLAPRFile::isExist(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags) -{ - apr_file_t* apr_file; - apr_status_t s; - - LLAPRFilePoolScope scope(pool); - s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, scope.getVolatileAPRPool()); - - if (s != APR_SUCCESS || !apr_file) - { - return false; - } - else - { - apr_file_close(apr_file) ; - return true; - } -} - -//static -S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool) -{ - apr_file_t* apr_file; - apr_finfo_t info; - apr_status_t s; - - LLAPRFilePoolScope scope(pool); - s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, scope.getVolatileAPRPool()); - - if (s != APR_SUCCESS || !apr_file) - { - return 0; - } - else - { - apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file); - - apr_file_close(apr_file) ; - - if (s == APR_SUCCESS) - { - return (S32)info.size; - } - else - { - return 0; - } - } -} - -//static -bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool) -{ - apr_status_t s; - - LLAPRFilePoolScope scope(pool); - s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, scope.getVolatileAPRPool()); - - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - LL_WARNS("APR") << " Attempting to make directory: " << dirname << LL_ENDL; - return false; - } - return true; -} - -//static -bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool) -{ - apr_status_t s; - - LLAPRFilePoolScope scope(pool); - s = apr_file_remove(dirname.c_str(), scope.getVolatileAPRPool()); - - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - LL_WARNS("APR") << " Attempting to remove directory: " << dirname << LL_ENDL; - return false; - } - return true; -} // //end of static components of LLAPRFile //******************************************************************************************************************************* diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 0e1e4277e7..8795a0f2c4 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -35,10 +35,6 @@ #include "llwin32headers.h" #include "apr_thread_proc.h" -#include "apr_getopt.h" -#include "apr_signal.h" - -#include "llstring.h" #include @@ -184,20 +180,7 @@ private: static apr_file_t* open(const std::string& filename, apr_pool_t* apr_pool, apr_int32_t flags); static apr_status_t close(apr_file_t* file) ; static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset); -public: - // returns false if failure: - static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL); - static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL); - static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ); - static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL); - static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); - static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); - - // Returns bytes read/written, 0 if read/write fails: - static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); - static S32 writeEx(const std::string& filename, const void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); // offset<0 means append //******************************************************************************************************************************* }; - #endif // LL_LLAPR_H diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp old mode 100644 new mode 100755 index 8ae0fabcc6..5b42c83a14 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -481,13 +481,9 @@ namespace std::string file = user_dir + "/logcontrol-dev.xml"; - llstat stat_info; - if (LLFile::stat(file, &stat_info)) { - // NB: stat returns non-zero if it can't read the file, for example - // if it doesn't exist. LLFile has no better abstraction for - // testing for file existence. - - file = app_dir + "/logcontrol.xml"; + if (!LLFile::isfile(file)) + { + file = app_dir + "/logcontrol.xml"; } return * new LogControlFile(file); // NB: This instance is never freed diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp old mode 100644 new mode 100755 index a539e4fe28..ff87d8ce10 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -29,22 +29,17 @@ #include "linden_common.h" #include "llfile.h" -#include "llstring.h" #include "llerror.h" #include "stringize.h" #if LL_WINDOWS -#include "llwin32headers.h" -#include +#include #else #include +#include #endif -using namespace std; - -static std::string empty; - -// Many of the methods below use OS-level functions that mess with errno. Wrap +// Some of the methods below use OS-level functions that mess with errno. Wrap // variants of strerror() to report errors. #if LL_WINDOWS @@ -79,6 +74,7 @@ static errentry const errtable[] { ERROR_CURRENT_DIRECTORY, EACCES }, // 16 { ERROR_NOT_SAME_DEVICE, EXDEV }, // 17 { ERROR_NO_MORE_FILES, ENOENT }, // 18 + { ERROR_SHARING_VIOLATION, EACCES }, // 32 { ERROR_LOCK_VIOLATION, EACCES }, // 33 { ERROR_BAD_NETPATH, ENOENT }, // 53 { ERROR_NETWORK_ACCESS_DENIED, EACCES }, // 65 @@ -109,22 +105,25 @@ static errentry const errtable[] { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } // 1816 }; -static int set_errno_from_oserror(unsigned long oserr) +static int get_errno_from_oserror(int oserr) { if (!oserr) return 0; // Check the table for the Windows OS error code - for (const struct errentry &entry : errtable) + for (const struct errentry& entry : errtable) { if (oserr == entry.oserr) { - _set_errno(entry.errcode); - return -1; + return entry.errcode; } } + return EINVAL; +} - _set_errno(EINVAL); +static int set_errno_from_oserror(unsigned long oserr) +{ + _set_errno(get_errno_from_oserror(oserr)); return -1; } @@ -136,69 +135,8 @@ std::string strerr(int errn) return buffer; } -inline bool is_slash(wchar_t const c) -{ - return c == L'\\' || c == L'/'; -} - -static std::wstring utf8path_to_wstring(const std::string& utf8path) -{ - if (utf8path.size() >= MAX_PATH) - { - // By prepending "\\?\" to a path, Windows widechar file APIs will not fail on long path names - std::wstring utf16path = L"\\\\?\\" + ll_convert(utf8path); - // We need to make sure that the path does not contain forward slashes as above - // prefix does bypass the path normalization that replaces slashes with backslashes - // before passing the path to kernel mode APIs - std::replace(utf16path.begin(), utf16path.end(), L'/', L'\\'); - return utf16path; - } - return ll_convert(utf8path); -} - -static unsigned short get_fileattr(const std::wstring& utf16path, bool dontFollowSymLink = false) -{ - unsigned long flags = FILE_FLAG_BACKUP_SEMANTICS; - if (dontFollowSymLink) - { - flags |= FILE_FLAG_OPEN_REPARSE_POINT; - } - HANDLE file_handle = CreateFileW(utf16path.c_str(), FILE_READ_ATTRIBUTES, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - nullptr, OPEN_EXISTING, flags, nullptr); - if (file_handle != INVALID_HANDLE_VALUE) - { - FILE_ATTRIBUTE_TAG_INFO attribute_info; - if (GetFileInformationByHandleEx(file_handle, FileAttributeTagInfo, &attribute_info, sizeof(attribute_info))) - { - // A volume path alone (only drive letter) is not recognized as directory while it technically is - bool is_directory = (attribute_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) || - (iswalpha(utf16path[0]) && utf16path[1] == ':' && - (!utf16path[2] || (is_slash(utf16path[2]) && !utf16path[3]))); - unsigned short st_mode = is_directory ? S_IFDIR : - (attribute_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ? S_IFLNK : S_IFREG); - st_mode |= (attribute_info.FileAttributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : S_IREAD | S_IWRITE; - // we do not try to guess executable flag - - // propagate user bits to group/other fields: - st_mode |= (st_mode & 0700) >> 3; - st_mode |= (st_mode & 0700) >> 6; - - CloseHandle(file_handle); - return st_mode; - } - } - // Retrieve last error and set errno before calling CloseHandle() - set_errno_from_oserror(GetLastError()); - - if (file_handle != INVALID_HANDLE_VALUE) - { - CloseHandle(file_handle); - } - return 0; -} - #else + // On Posix we want to call strerror_r(), but alarmingly, there are two // different variants. The one that returns int always populates the passed // buffer (except in case of error), whereas the other one always returns a @@ -245,9 +183,50 @@ std::string strerr(int errn) return message_from(errn, buffer, sizeof(buffer), strerror_r(errn, buffer, sizeof(buffer))); } + #endif // ! LL_WINDOWS -static int warnif(const std::string& desc, const std::string& filename, int rc, int accept = 0) +#if LL_WINDOWS && 0 // turn on to debug file-locking problems +#define PROCESS_LOCKING_CHECK 1 +static void find_locking_process(const std::string& filename) +{ + // Only do any of this stuff (before LL_ENDL) if it will be logged. + LL_DEBUGS("LLFile") << ""; + // wrong way + std::string TEMP = LLFile::tmpdir(); + if (TEMP.empty()) + { + LL_CONT << "No $TEMP, not running 'handle'"; + } + else + { + std::string tf(TEMP); + tf += "\\handle.tmp"; + // http://technet.microsoft.com/en-us/sysinternals/bb896655 + std::string cmd(STRINGIZE("handle \"" << filename + // "openfiles /query /v | fgrep -i \"" << filename + << "\" > \"" << tf << '"')); + LL_CONT << cmd; + if (system(cmd.c_str()) != 0) + { + LL_CONT << "\nDownload 'handle.exe' from http://technet.microsoft.com/en-us/sysinternals/bb896655"; + } + else + { + std::ifstream inf(tf); + std::string line; + while (std::getline(inf, line)) + { + LL_CONT << '\n' << line; + } + } + LLFile::remove(tf); + } + LL_CONT << LL_ENDL; +} +#endif // LL_WINDOWS hack to identify processes holding file open + +static int warnif(const std::string& desc, const std::string& filename, int rc, int suppress_warning = 0) { if (rc < 0) { @@ -256,319 +235,951 @@ static int warnif(const std::string& desc, const std::string& filename, int rc, // For certain operations, a particular errno value might be // acceptable -- e.g. stat() could permit ENOENT, mkdir() could permit - // EEXIST. Don't warn if caller explicitly says this errno is okay. - if (errn != accept) + // EEXIST. Don't log a warning if caller explicitly says this errno is okay. + if (errn != suppress_warning) { - LL_WARNS("LLFile") << "Couldn't " << desc << " '" << filename - << "' (errno " << errn << "): " << strerr(errn) << LL_ENDL; + LL_WARNS("LLFile") << "Couldn't " << desc << " '" << filename << "' (errno " << errn << "): " << strerr(errn) << LL_ENDL; } -#if 0 && LL_WINDOWS // turn on to debug file-locking problems +#if PROCESS_LOCKING_CHECK // If the problem is "Permission denied," maybe it's because another // process has the file open. Try to find out. - if (errn == EACCES) // *not* EPERM + if (errn == EACCES) // *not* EPERM { - // Only do any of this stuff (before LL_ENDL) if it will be logged. - LL_DEBUGS("LLFile") << empty; - // would be nice to use LLDir for this, but dependency goes the - // wrong way - const char* TEMP = LLFile::tmpdir(); - if (! (TEMP && *TEMP)) - { - LL_CONT << "No $TEMP, not running 'handle'"; - } - else - { - std::string tf(TEMP); - tf += "\\handle.tmp"; - // http://technet.microsoft.com/en-us/sysinternals/bb896655 - std::string cmd(STRINGIZE("handle \"" << filename - // "openfiles /query /v | fgrep -i \"" << filename - << "\" > \"" << tf << '"')); - LL_CONT << cmd; - if (system(cmd.c_str()) != 0) - { - LL_CONT << "\nDownload 'handle.exe' from http://technet.microsoft.com/en-us/sysinternals/bb896655"; - } - else - { - std::ifstream inf(tf); - std::string line; - while (std::getline(inf, line)) - { - LL_CONT << '\n' << line; - } - } - LLFile::remove(tf); - } - LL_CONT << LL_ENDL; + find_locking_process(filename); } -#endif // LL_WINDOWS hack to identify processes holding file open +#endif } return rc; } -// static -int LLFile::mkdir(const std::string& dirname, int perms) +static int warnif(const std::string& desc, const std::string& filename, const std::error_code& ec, int suppress_warning = 0) { - // We often use mkdir() to ensure the existence of a directory that might - // already exist. There is no known case in which we want to call out as - // an error the requested directory already existing. + if (ec) + { + // get Posix errno from the std::error_code so we can compare it to the suppress_warning parameter + // to see when a caller wants us to not generate a warning for a particular error code #if LL_WINDOWS - // permissions are ignored on Windows - int rc = 0; - std::wstring utf16dirname = utf8path_to_wstring(dirname); - if (!CreateDirectoryW(utf16dirname.c_str(), nullptr)) - { - // Only treat other errors than an already existing file as a real error - unsigned long oserr = GetLastError(); - if (oserr != ERROR_ALREADY_EXISTS) + int errn = get_errno_from_oserror(ec.value()); +#else + int errn = ec.value(); +#endif + // For certain operations, a particular errno value might be acceptable + // Don't warn if caller explicitly says this errno is okay. + if (errn != suppress_warning) + { + LL_WARNS("LLFile") << "Couldn't " << desc << " '" << filename << "' (errno " << errn << "): " << ec.message() << LL_ENDL; + } +#if PROCESS_LOCKING_CHECK + // Try to detect locked files by other processes + if (ec.value() == ERROR_SHARING_VIOLATION || ec.value() == ERROR_LOCK_VIOLATION) + { + find_locking_process(filename); + } +#endif + return -1; + } + return 0; +} + +#if LL_WINDOWS + +inline int set_ec_from_system_error(std::error_code& ec, DWORD error) +{ + ec.assign(error, std::system_category()); + return -1; +} + +static int set_ec_from_system_error(std::error_code& ec) +{ + return set_ec_from_system_error(ec, GetLastError()); +} + +inline int set_ec_to_parameter_error(std::error_code& ec) +{ + return set_ec_from_system_error(ec, ERROR_INVALID_PARAMETER); +} + +inline int set_ec_to_outofmemory_error(std::error_code& ec) +{ + return set_ec_from_system_error(ec, ERROR_NOT_ENOUGH_MEMORY); +} + +inline DWORD decode_access_mode(std::ios_base::openmode omode) +{ + switch (omode & (LLFile::in | LLFile::out)) + { + case LLFile::in: + return GENERIC_READ; + case LLFile::out: + return GENERIC_WRITE; + case static_cast(LLFile::in | LLFile::out): + return GENERIC_READ | GENERIC_WRITE; + } + if (omode & LLFile::app) + { + return GENERIC_WRITE; + } + return 0; +} + +inline DWORD decode_open_create_flags(std::ios_base::openmode omode) +{ + if (omode & LLFile::noreplace) + { + return CREATE_NEW; // create if it does not exist, otherwise fail + } + if (omode & LLFile::trunc) + { + if (!(omode & LLFile::out)) { - rc = set_errno_from_oserror(oserr); + return TRUNCATE_EXISTING; // open and truncate if it exists, otherwise fail } + return CREATE_ALWAYS; // open and truncate if it exists, otherwise create it + } + if (!(omode & LLFile::out)) + { + return OPEN_EXISTING; // open if it exists, otherwise fail + } + // LLFile::app or (LLFile::out and (!LLFile::trunc or !LLFile::noreplace)) + return OPEN_ALWAYS; // open if it exists, otherwise create it +} + +inline DWORD decode_share_mode(int omode) +{ + if (omode & LLFile::exclusive) + { + return 0; // allow no other access + } + if (omode & LLFile::shared) + { + return FILE_SHARE_READ; // allow read access + } + return FILE_SHARE_READ | FILE_SHARE_WRITE; // allow read and write access to others +} + +inline DWORD decode_attributes(std::ios_base::openmode omode, int perm) +{ + return (perm & S_IWRITE) ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_READONLY; +} + +// Under Windows the values for the std::ios_base::seekdir constants match the according FILE_BEGIN +// and other constants but we do a programmatic translation for now to be sure +static DWORD seek_mode_from_dir(std::ios_base::seekdir seekdir) +{ + switch (seekdir) + { + case LLFile::beg: + return FILE_BEGIN; + case LLFile::cur: + return FILE_CURRENT; + case LLFile::end: + return FILE_END; } + return FILE_BEGIN; +} + #else - int rc = ::mkdir(dirname.c_str(), (mode_t)perms); - if (rc < 0 && errno == EEXIST) + +inline int set_ec_from_system_error(std::error_code& ec, int error) +{ + ec.assign(error, std::system_category()); + return -1; +} + +static int set_ec_from_system_error(std::error_code& ec) +{ + return set_ec_from_system_error(ec, errno); +} + +inline int set_ec_to_parameter_error(std::error_code& ec) +{ + return set_ec_from_system_error(ec, EINVAL); +} + +inline int set_ec_to_outofmemory_error(std::error_code& ec) +{ + return set_ec_from_system_error(ec, ENOMEM); +} + +inline int decode_access_mode(std::ios_base::openmode omode) +{ + if (omode & LLFile::out) { - // this is not the error you want, move along - return 0; + if (omode & LLFile::in) + { + return O_RDWR; + } + return O_WRONLY; + } + return O_RDONLY; + + /*switch (omode & (LLFile::in | LLFile::out)) + { + case LLFile::out: + return O_WRONLY; + case static_cast(LLFile::in | LLFile::out): + return O_RDWR; + } + return O_RDONLY;*/ +} + +inline int decode_open_mode(std::ios_base::openmode omode) +{ + int flags = O_CREAT | decode_access_mode(omode); + if (omode & LLFile::app) + { + flags |= O_APPEND; } + if (omode & LLFile::trunc) + { + flags |= O_TRUNC; + } + if (omode & LLFile::binary) + { + // Not a thing under *nix + } + if (omode & LLFile::noreplace) + { + flags |= O_EXCL; + } + return flags; +} + +inline int decode_lock_mode(std::ios_base::openmode omode) +{ + int lmode = omode & LLFile::noblock ? LOCK_NB : 0; + if (omode & LLFile::lock_mask) + { + if (omode & LLFile::exclusive) + { + return lmode | LOCK_EX; + } + return lmode | LOCK_SH; + } + return lmode | LOCK_UN; +} + +// Under Linux and Mac the values for the std::ios_base::seekdir constants match the according SEEK_SET +// and other constants but we do a programmatic translation for now to be sure +inline int seek_mode_from_dir(std::ios_base::seekdir seekdir) +{ + switch (seekdir) + { + case LLFile::beg: + return SEEK_SET; + case LLFile::cur: + return SEEK_CUR; + case LLFile::end: + return SEEK_END; + } + return SEEK_SET; +} + #endif - // anything else might be a problem - return warnif("mkdir", dirname, rc); + +inline int clear_error(std::error_code& ec) +{ + ec.clear(); + return 0; } -// static -int LLFile::rmdir(const std::string& dirname, int suppress_error) +inline bool are_open_mode_flags_invalid(std::ios_base::openmode omode) +{ + // at least one of input or output needs to be specified + if (!(omode & (LLFile::in | LLFile::out))) + { + return true; + } + // output must be possible for any of the extra options + if (!(omode & LLFile::out) && (omode & (LLFile::trunc | LLFile::app | LLFile::noreplace))) + { + return true; + } + // invalid combination, mutually exclusive + if ((omode & LLFile::app) && (omode & (LLFile::trunc | LLFile::noreplace))) + { + return true; + } + return false; +} + +//---------------------------------------------------------------------------------------- +// class member functions +//---------------------------------------------------------------------------------------- +int LLFile::open(const std::string& filename, std::ios_base::openmode omode, std::error_code& ec, int perm) { + close(ec); + if (are_open_mode_flags_invalid(omode)) + { + return set_ec_to_parameter_error(ec); + } #if LL_WINDOWS - std::wstring utf16dirname = utf8path_to_wstring(dirname); - int rc = _wrmdir(utf16dirname.c_str()); + DWORD access = decode_access_mode(omode), + share = decode_share_mode(omode), + create = decode_open_create_flags(omode), + attributes = decode_attributes(omode, perm); + + std::wstring file_path = utf8StringToWstring(filename); + mHandle = CreateFileW(file_path.c_str(), access, share, nullptr, create, attributes, nullptr); + // The dwShareMode = share parameter takes care of locking the file for other processes if indicated, + // no need to do anything else for file locking here #else - int rc = ::rmdir(dirname.c_str()); + int oflags = decode_open_mode(omode); + int lmode = omode & LLFile::lock_mask; + mHandle = ::open(filename.c_str(), oflags, perm); + if (mHandle != InvalidHandle && lmode && lock(lmode | LLFile::noblock, ec) != 0) + { + close(); + return -1; + } #endif - return warnif("rmdir", dirname, rc, suppress_error); + if (mHandle == InvalidHandle) + { + return set_ec_from_system_error(ec); + } + + if (omode & LLFile::ate && seek(0, LLFile::end, ec) != 0) + { + close(); + return -1; + } + mOpen = omode; + return clear_error(ec); } -// static -LLFILE* LLFile::fopen(const std::string& filename, const char* mode) +S64 LLFile::size(std::error_code& ec) { #if LL_WINDOWS - std::wstring utf16filename = utf8path_to_wstring(filename); - std::wstring utf16mode = ll_convert(std::string(mode)); - return _wfopen(utf16filename.c_str(), utf16mode.c_str()); + LARGE_INTEGER value = { 0 }; + if (GetFileSizeEx(mHandle, &value)) + { + clear_error(ec); + return value.QuadPart; + } #else - return ::fopen(filename.c_str(),mode); + struct stat statval; + if (fstat(mHandle, &statval) == 0) + { + clear_error(ec); + return statval.st_size; + } #endif + return set_ec_from_system_error(ec); } -// static -int LLFile::close(LLFILE * file) +S64 LLFile::tell(std::error_code& ec) { - int ret_value = 0; - if (file) +#if LL_WINDOWS + LARGE_INTEGER value = { 0 }; + if (SetFilePointerEx(mHandle, value, &value, FILE_CURRENT)) { - ret_value = fclose(file); + clear_error(ec); + return value.QuadPart; } - return ret_value; +#else + off_t offset = lseek(mHandle, 0, SEEK_CUR); + if (offset != -1) + { + clear_error(ec); + return offset; + } +#endif + return set_ec_from_system_error(ec); } -// static -std::string LLFile::getContents(const std::string& filename) +int LLFile::seek(S64 pos, std::error_code& ec) { - LLFILE* fp = LLFile::fopen(filename, "rb"); - if (fp) + return seek(pos, LLFile::beg, ec); +} + +int LLFile::seek(S64 offset, std::ios_base::seekdir dir, std::error_code& ec) +{ + S64 newOffset = 0; +#if LL_WINDOWS + DWORD seekdir = seek_mode_from_dir(dir); + LARGE_INTEGER value; + value.QuadPart = offset; + if (SetFilePointerEx(mHandle, value, (PLARGE_INTEGER)&newOffset, seekdir)) +#else + newOffset = lseek(mHandle, offset, seek_mode_from_dir(dir)); + if (newOffset != -1) +#endif { - fseek(fp, 0, SEEK_END); - U32 length = ftell(fp); - fseek(fp, 0, SEEK_SET); + return clear_error(ec); + } + return set_ec_from_system_error(ec); +} - std::vector buffer(length); - size_t nread = fread(buffer.data(), 1, length, fp); - fclose(fp); +#if LL_WINDOWS +inline DWORD next_buffer_size(S64 nbytes) +{ + return nbytes > 0x80000000 ? 0x80000000 : (DWORD)nbytes; +} +#endif - return std::string(buffer.data(), nread); +S64 LLFile::read(void* buffer, S64 nbytes, std::error_code& ec) +{ + if (nbytes == 0) + { + // Nothing to do + return clear_error(ec); } + else if (!buffer || nbytes < 0) + { + return set_ec_to_parameter_error(ec); + } +#if LL_WINDOWS + S64 totalBytes = 0; + char *ptr = (char*)buffer; + DWORD bytesRead, bytesToRead = next_buffer_size(nbytes); - return LLStringUtil::null; + // Read in chunks to support >4GB which the S64 nbytes value makes possible + while (ReadFile(mHandle, ptr, bytesToRead, &bytesRead, nullptr)) + { + totalBytes += bytesRead; + if (nbytes <= totalBytes || // requested amount read + bytesRead < bytesToRead) // ReadFile encountered eof + { + clear_error(ec); + return totalBytes; + } + ptr += bytesRead; + bytesToRead = next_buffer_size(nbytes - totalBytes); + } +#else + ssize_t bytesRead = ::read(mHandle, buffer, nbytes); + if (bytesRead != -1) + { + clear_error(ec); + return bytesRead; + } +#endif + return set_ec_from_system_error(ec); } -// static -int LLFile::remove(const std::string& filename, int suppress_error) +S64 LLFile::write(const void* buffer, S64 nbytes, std::error_code& ec) { + if (nbytes == 0) + { + // Nothing to do here + return clear_error(ec); + } + else if (!buffer || nbytes < 0) + { + return set_ec_to_parameter_error(ec); + } #if LL_WINDOWS - // Posix remove() works on both files and directories although on Windows - // remove() and its wide char variant _wremove() only removes files just - // as its siblings unlink() and _wunlink(). - // If we really only want to support files we should instead use - // unlink() in the non-Windows part below too - int rc = -1; - std::wstring utf16filename = utf8path_to_wstring(filename); - unsigned short st_mode = get_fileattr(utf16filename); - if (S_ISDIR(st_mode)) + // If this was opened in append mode, we emulate it on Windows + if (mOpen & LLFile::app && seek(0, LLFile::end, ec) != 0) + { + return -1; + } + + S64 totalBytes = 0; + char* ptr = (char*)buffer; + DWORD bytesWritten, bytesToWrite = next_buffer_size(nbytes); + + // Write in chunks to support >4GB which the S64 nbytes value makes possible + while (WriteFile(mHandle, ptr, bytesToWrite, &bytesWritten, nullptr)) + { + totalBytes += bytesWritten; + if (nbytes <= totalBytes) + { + clear_error(ec); + return totalBytes; + } + ptr += bytesWritten; + bytesToWrite = next_buffer_size(nbytes - totalBytes); + } +#else + ssize_t bytesWritten = ::write(mHandle, buffer, nbytes); + if (bytesWritten != -1) + { + clear_error(ec); + return bytesWritten; + } +#endif + return set_ec_from_system_error(ec); +} + +S64 LLFile::printf(const char* fmt, ...) +{ + va_list args1; + va_start(args1, fmt); + va_list args2; + va_copy(args2, args1); + int length = vsnprintf(nullptr, 0, fmt, args1); + va_end(args1); + if (length < 0) { - rc = _wrmdir(utf16filename.c_str()); + va_end(args2); + return -1; } - else if (S_ISREG(st_mode)) + void* buffer = malloc(length + 1); + if (!buffer) { - rc = _wunlink(utf16filename.c_str()); + va_end(args2); + return -1; } - else if (st_mode) + length = vsnprintf((char*)buffer, length + 1, fmt, args2); + va_end(args2); + std::error_code ec; + S64 written = write(buffer, length, ec); + free(buffer); + return written; +} + +int LLFile::lock(int mode, std::error_code& ec) +{ +#if LL_WINDOWS + if (!(mode & LLFile::lock_mask)) { - // it is something else than a file or directory - // this should not really happen as long as we do not allow for symlink - // detection in the optional parameter to get_fileattr() - rc = set_errno_from_oserror(ERROR_INVALID_PARAMETER); + if (UnlockFile(mHandle, 0, 0, MAXDWORD, MAXDWORD)) + { + return clear_error(ec); + } } else { - // get_fileattr() failed and already set errno, preserve it for correct error reporting + OVERLAPPED overlapped = { 0 }; + DWORD flags = (mode & LLFile::noblock) ? LOCKFILE_FAIL_IMMEDIATELY : 0; + if (mode & LLFile::exclusive) + { + flags |= LOCKFILE_EXCLUSIVE_LOCK; + } + // We lock the maximum range, since flock only supports locking the entire file too + if (LockFileEx(mHandle, flags, 0, MAXDWORD, MAXDWORD, &overlapped)) + { + return clear_error(ec); + } } #else - int rc = ::remove(filename.c_str()); + if (flock(mHandle, decode_lock_mode(static_cast(mode))) == 0) + { + return clear_error(ec); + } #endif - return warnif("remove", filename, rc, suppress_error); + return set_ec_from_system_error(ec); +} + +int LLFile::close(std::error_code& ec) +{ + if (mHandle != InvalidHandle) + { + llfile_handle_t handle = InvalidHandle; + std::swap(handle, mHandle); +#if LL_WINDOWS + if (!CloseHandle(handle)) +#else + if (::close(handle)) +#endif + { + return set_ec_from_system_error(ec); + } + } + return clear_error(ec); +} + +int LLFile::close() +{ + std::error_code ec; + return close(ec); } +//---------------------------------------------------------------------------------------- +// static member functions +//---------------------------------------------------------------------------------------- + // static -int LLFile::rename(const std::string& filename, const std::string& newname, int suppress_error) +LLFILE* LLFile::fopen(const std::string& filename, const char* mode, int lmode) { + LLFILE* file; #if LL_WINDOWS - // Posix rename() will gladly overwrite a file at newname if it exists, the Windows - // rename(), respectively _wrename(), will bark on that. Instead call directly the Windows - // API MoveFileEx() and use its flags to specify that overwrite is allowed. - std::wstring utf16filename = utf8path_to_wstring(filename); - std::wstring utf16newname = utf8path_to_wstring(newname); - int rc = 0; - if (!MoveFileExW(utf16filename.c_str(), utf16newname.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED)) + int shflag = _SH_DENYNO; + switch (lmode) { - rc = set_errno_from_oserror(GetLastError()); + case LLFile::exclusive: + shflag = _SH_DENYRW; + break; + case LLFile::shared: + shflag = _SH_DENYWR; + break; } + std::wstring file_path = utf8StringToWstring(filename); + std::wstring utf16mode = ll_convert(std::string(mode)); + file = _wfsopen(file_path.c_str(), utf16mode.c_str(), shflag); #else - int rc = ::rename(filename.c_str(),newname.c_str()); + file = ::fopen(filename.c_str(), mode); + if (file && (lmode & (LLFile::lock_mask))) + { + // Rather fail on a sharing conflict than block + if (flock(fileno(file), decode_lock_mode(static_cast(lmode | LLFile::noblock)))) + { + ::fclose(file); + file = nullptr; + } + } #endif - return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc, suppress_error); + return file; +} + +// static +int LLFile::close(LLFILE* file) +{ + int ret_value = 0; + if (file) + { + ret_value = ::fclose(file); + } + return ret_value; +} + +// static +std::string LLFile::getContents(const std::string& filename) +{ + std::error_code ec; + return getContents(filename, ec); +} + +// static +std::string LLFile::getContents(const std::string& filename, std::error_code& ec) +{ + std::string buffer; + LLFile file(filename, LLFile::in | LLFile::binary, ec); + if (file) + { + S64 length = file.size(ec); + if (!ec && length > 0) + { + buffer = std::string(length, 0); + file.read(&buffer[0], length, ec); + if (ec) + { + buffer.clear(); + } + } + } + return buffer; } -// Make this a define rather than using magic numbers multiple times in the code -#define LLFILE_COPY_BUFFER_SIZE 16384 +// static +int LLFile::mkdir(const std::string& dirname) +{ + std::error_code ec; + std::filesystem::path file_path = utf8StringToPath(dirname); + // We often use mkdir() to ensure the existence of a directory that might + // already exist. There is no known case in which we want to call out as + // an error the requested directory already existing. + std::filesystem::create_directory(file_path, ec); + // The return value is only true if the directory was actually created. + // But if it already existed, ec still indicates success. + return warnif("mkdir", dirname, ec); +} // static -bool LLFile::copy(const std::string& from, const std::string& to) +int LLFile::remove(const std::string& filename, int suppress_warning) { - bool copied = false; - LLFILE* in = LLFile::fopen(from, "rb"); - if (in) + std::error_code ec; + std::filesystem::path file_path = utf8StringToPath(filename); + std::filesystem::remove(file_path, ec); + return warnif("remove", filename, ec, suppress_warning); +} + +// static +int LLFile::rename(const std::string& filename, const std::string& newname, int suppress_warning) +{ + std::error_code ec; + std::filesystem::path file_path = utf8StringToPath(filename); + std::filesystem::path new_path = utf8StringToPath(newname); + std::filesystem::rename(file_path, new_path, ec); + return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, ec, suppress_warning); +} + +// static +S64 LLFile::read(const std::string& filename, void* buf, S64 offset, S64 nbytes) +{ + std::error_code ec; + return read(filename, buf, offset, nbytes, ec); +} + +// static +S64 LLFile::read(const std::string& filename, void* buf, S64 offset, S64 nbytes, std::error_code& ec) +{ + // if number of bytes is 0 or less there is nothing to do here + if (nbytes <= 0) + { + clear_error(ec); + return 0; + } + + if (!buf || offset < 0) { - LLFILE* out = LLFile::fopen(to, "wb"); - if (out) + set_ec_to_parameter_error(ec); + } + else + { + std::ios_base::openmode omode = LLFile::in | LLFile::binary; + + LLFile file(filename, omode, ec); + if (!ec && (bool)file) { - char buf[LLFILE_COPY_BUFFER_SIZE]; - size_t readbytes; - bool write_ok = true; - while (write_ok && (readbytes = fread(buf, 1, LLFILE_COPY_BUFFER_SIZE, in))) + if (offset > 0) + { + file.seek(offset, ec); + } + // else (offset == 0) file was just opened and should already be at 0. + if (!ec) { - if (fwrite(buf, 1, readbytes, out) != readbytes) + S64 bytes_read = file.read(buf, nbytes, ec); + if (!ec) { - LL_WARNS("LLFile") << "Short write" << LL_ENDL; - write_ok = false; + return bytes_read; } } - if ( write_ok ) + } + } + return warnif("read from file failed", filename, ec); +} + +// static +S64 LLFile::write(const std::string& filename, const void* buf, S64 offset, S64 nbytes) +{ + std::error_code ec; + return write(filename, buf, offset, nbytes, ec); +} + +// static +S64 LLFile::write(const std::string& filename, const void* buf, S64 offset, S64 nbytes, std::error_code& ec) +{ + // if number of bytes is 0 or less there is nothing to do here + if (nbytes <= 0) + { + clear_error(ec); + return 0; + } + + if (!buf) + { + set_ec_to_parameter_error(ec); + } + else + { + std::ios_base::openmode omode = LLFile::out | LLFile::binary; + if (offset < 0) + { + omode |= LLFile::app; + } + + LLFile file(filename, omode, ec); + if (!ec && (bool)file) + { + if (offset > 0) + { + file.seek(offset, ec); + } + // else (offset == 0) we are not appending, file was just opened and should already be at 0. + if (!ec) { - copied = true; + S64 bytes_written = file.write(buf, nbytes, ec); + if (!ec) + { + return bytes_written; + } } - fclose(out); } - fclose(in); + } + return warnif("write to file failed", filename, ec); +} + +// static +bool LLFile::copy(const std::string& source, const std::string& target) +{ + std::error_code ec; + return copy(source, target, std::filesystem::copy_options::overwrite_existing, ec); +} + +// static +bool LLFile::copy(const std::string& source, const std::string& target, std::filesystem::copy_options options, std::error_code& ec) +{ + std::filesystem::path source_path = utf8StringToPath(source); + std::filesystem::path target_path = utf8StringToPath(target); + bool copied = std::filesystem::copy_file(source_path, target_path, options, ec); + if (!copied) + { + warnif(STRINGIZE("copy failed, to '" << target << "' from"), source, ec); } return copied; } // static -int LLFile::stat(const std::string& filename, llstat* filestatus, int suppress_error) +int LLFile::stat(const std::string& filename, llstat* filestatus, const char *fname, int suppress_warning) { #if LL_WINDOWS - std::wstring utf16filename = utf8path_to_wstring(filename); - int rc = _wstat64(utf16filename.c_str(), filestatus); + std::wstring file_path = utf8StringToWstring(filename); + int rc = _wstat64(file_path.c_str(), filestatus); #else int rc = ::stat(filename.c_str(), filestatus); #endif - return warnif("stat", filename, rc, suppress_error); + return warnif(fname ? fname : "stat", filename, rc, suppress_warning); } // static -unsigned short LLFile::getattr(const std::string& filename, bool dontFollowSymLink, int suppress_error) +std::time_t LLFile::getCreationTime(const std::string& filename, int suppress_warning) { -#if LL_WINDOWS - // _wstat64() is a bit heavyweight on Windows, use a more lightweight API - // to just get the attributes - int rc = -1; - std::wstring utf16filename = utf8path_to_wstring(filename); - unsigned short st_mode = get_fileattr(utf16filename, dontFollowSymLink); - if (st_mode) + // As of C++20 there is no functionality in std::filesystem to retrieve this information + llstat filestat; + int rc = stat(filename, &filestat, "getCreationTime", suppress_warning); + if (rc == 0) { - return st_mode; - } +#if LL_DARWIN + return filestat.st_birthtime; #else - llstat filestatus; - int rc = dontFollowSymLink ? ::lstat(filename.c_str(), &filestatus) : ::stat(filename.c_str(), &filestatus); + // Linux stat() doesn't have a creation/birth time (st_ctime really is the last status + // change or inode attributes change) unless we would use statx() instead. But that is + // a major effort, which would require Linux specific changes to LLFile::stat() above + // and possibly adaptions for other platforms that we leave for a later exercise if it + // is ever desired. + return filestat.st_ctime; +#endif + } + return 0; +} + +// static +std::time_t LLFile::getModificationTime(const std::string& filename, int suppress_warning) +{ + // tried to use std::filesystem::last_write_time() but the whole std::chrono infrastructure is as of + // C++20 still not fully implemented on all platforms. Specifically MacOS C++20 seems lacking here, + // and Windows requires a roundabout through std::chrono::utc_clock to then get a + // std::chrono::system_clock that can return a more useful time_t. + // So we take the easy way out in a similar way as with getCreationTime(). + llstat filestat; + int rc = stat(filename, &filestat, "getModificationTime", suppress_warning); if (rc == 0) { - return filestatus.st_mode; + return filestat.st_mtime; } -#endif - warnif("getattr", filename, rc, suppress_error); return 0; } +// static +S64 LLFile::size(const std::string& filename, int suppress_warning) +{ + std::error_code ec; + std::filesystem::path file_path = utf8StringToPath(filename); + std::intmax_t size = static_cast(std::filesystem::file_size(file_path, ec)); + if (ec) + { + return warnif("size", filename, ec, suppress_warning); + } + return size; +} + +// static +std::filesystem::file_status LLFile::getStatus(const std::string& filename, bool dontFollowSymLink, int suppress_warning) +{ + std::error_code ec; + std::filesystem::path file_path = utf8StringToPath(filename); + std::filesystem::file_status status; + if (dontFollowSymLink) + { + status = std::filesystem::symlink_status(file_path, ec); + } + else + { + status = std::filesystem::status(file_path, ec); + } + warnif("getStatus()", filename, ec, suppress_warning); + return status; +} + +// static +bool LLFile::exists(const std::string& filename) +{ + std::filesystem::file_status status = getStatus(filename); + return std::filesystem::exists(status); +} + // static bool LLFile::isdir(const std::string& filename) { - return S_ISDIR(getattr(filename)); + std::filesystem::file_status status = getStatus(filename); + return std::filesystem::is_directory(status); } // static bool LLFile::isfile(const std::string& filename) { - return S_ISREG(getattr(filename)); + std::filesystem::file_status status = getStatus(filename); + return std::filesystem::is_regular_file(status); } // static bool LLFile::islink(const std::string& filename) { - return S_ISLNK(getattr(filename, true)); + std::filesystem::file_status status = getStatus(filename, true); + return std::filesystem::is_symlink(status); } // static -const char *LLFile::tmpdir() +const std::string& LLFile::tmpdir() { - static std::string utf8path; - - if (utf8path.empty()) + static std::string temppath; + if (temppath.empty()) { - char sep; -#if LL_WINDOWS - sep = '\\'; + temppath = std::filesystem::temp_directory_path().string(); + } - std::vector utf16path(MAX_PATH + 1); - GetTempPathW(static_cast(utf16path.size()), &utf16path[0]); - utf8path = ll_convert_wide_to_string(&utf16path[0]); + char sep; +#if LL_WINDOWS + sep = '\\'; #else - sep = '/'; + sep = '/'; +#endif + if (temppath[temppath.size() - 1] != sep) + { + temppath += sep; + } + return temppath; +} - utf8path = LLStringUtil::getenv("TMPDIR", "/tmp/"); +// static +std::filesystem::path LLFile::utf8StringToPath(const std::string& pathname) +{ +#if LL_WINDOWS + return ll_convert(pathname); +#else + return pathname; #endif - if (utf8path[utf8path.size() - 1] != sep) +} + +#if LL_WINDOWS + +// static +std::wstring LLFile::utf8StringToWstring(const std::string& pathname) +{ + std::wstring utf16string(ll_convert(pathname)); + if (utf16string.size() >= MAX_PATH) + { + // By going through std::filesystem::path we get a lot of path sanitation done for us that + // is needed when passing a path with a kernel object space prefix to Windows API functions + // since this prefix disables the kernel32 path normalization + std::filesystem::path utf16path(utf16string); + + // By prepending "\\?\" to a path, Windows widechar file APIs will not fail on long path names + utf16string.assign(L"\\\\?\\").append(utf16path); + + /* remove trailing spaces and dots (yes, Windows really does that) */ + size_t last_valid = utf16string.find_last_not_of(L" \t."); + if (last_valid == std::wstring::npos) { - utf8path += sep; + return std::wstring(); } + return utf16string.substr(0, last_valid + 1); } - return utf8path.c_str(); + return utf16string; } -#if LL_WINDOWS - /************** input file stream ********************************/ llifstream::llifstream() {} @@ -586,10 +1197,8 @@ void llifstream::open(const std::string& _Filename, ios_base::openmode _Mode) _Mode | ios_base::in); } - /************** output file stream ********************************/ - llofstream::llofstream() {} // explicit @@ -605,30 +1214,4 @@ void llofstream::open(const std::string& _Filename, ios_base::openmode _Mode) _Mode | ios_base::out); } -/************** helper functions ********************************/ - -std::streamsize llifstream_size(llifstream& ifstr) -{ - if(!ifstr.is_open()) return 0; - std::streampos pos_old = ifstr.tellg(); - ifstr.seekg(0, ios_base::beg); - std::streampos pos_beg = ifstr.tellg(); - ifstr.seekg(0, ios_base::end); - std::streampos pos_end = ifstr.tellg(); - ifstr.seekg(pos_old, ios_base::beg); - return pos_end - pos_beg; -} - -std::streamsize llofstream_size(llofstream& ofstr) -{ - if(!ofstr.is_open()) return 0; - std::streampos pos_old = ofstr.tellp(); - ofstr.seekp(0, ios_base::beg); - std::streampos pos_beg = ofstr.tellp(); - ofstr.seekp(0, ios_base::end); - std::streampos pos_end = ofstr.tellp(); - ofstr.seekp(pos_old, ios_base::beg); - return pos_end - pos_beg; -} - #endif // LL_WINDOWS diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h old mode 100644 new mode 100755 index 04a2946ac4..0036e896c3 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -35,118 +35,359 @@ * Attempts to mostly mirror the POSIX style IO functions. */ -typedef FILE LLFILE; - #include +#include #include #if LL_WINDOWS +#include // The Windows version of stat function and stat data structure are called _stat64 // We use _stat64 here to support 64-bit st_size and time_t values -typedef struct _stat64 llstat; +typedef struct _stat64 llstat; #else -typedef struct stat llstat; #include +typedef struct stat llstat; #endif -#ifndef S_ISREG -# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) -#endif - -#ifndef S_ISDIR -# define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR) -#endif - -// Windows C runtime library does not define this and does not support symlink detection in the -// stat functions but we do in our getattr() function -#ifndef S_IFLNK -#define S_IFLNK 0xA000 /* symlink */ -#endif - -#ifndef S_ISLNK -#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) -#endif +typedef FILE LLFILE; #include "llstring.h" // safe char* -> std::string conversion -/// LLFile is a class of static functions operating on paths +/// This class provides a selection of functions to operate on files through names and +/// a class implementation to represent a file for reading and writing to it /// All the functions with a path string input take UTF8 path/filenames +/// +/// @nosubgrouping +/// class LL_COMMON_API LLFile { public: + // ================================================================================ + /// @name Constants + /// + ///@{ + /** These can be passed to the omode parameter of LLFile::open() and its constructor + + This is similar to the openmode flags for std:fstream but not exactly the same + std::fstream open() does not allow to open a file for writing without either + forcing the file to be truncated on open or all write operations being always + appended to the end of the file or failing to open when the file does not exist. + But to allow implementing the LLAPRFile::writeEx() functionality we need to be + able to write at a random position to the file without truncating it on open. + + any other combinations than listed here are not allowed and will cause an error + + bin in out trunc app noreplace File exists File doesn't exist + ---------------------------------------------------------------------------------- + - + - - - - Open at begin Failure to open + + + - - - - " " + - - + - - - " Create new + + - + - - - " " + - + + - - - " " + + + + - - - " " + ---------------------------------------------------------------------------------- + - - + + - - Destroy contents Create new + + - + + - - " " + - + + + - - " " + + + + + - - " " + ---------------------------------------------------------------------------------- + - - + x - + Failure to open Create new + + - + x - + " " + - + + x - + " " + + + + x - + " " + ---------------------------------------------------------------------------------- + - - + - + - Write to end Create new + + - + - + - " " + - + + - + - " " + + + + - + - " " + ---------------------------------------------------------------------------------- + */ + static const std::ios_base::openmode app = static_cast(1 << 1); // append to end + static const std::ios_base::openmode ate = static_cast(1 << 2); // initialize to end + static const std::ios_base::openmode binary = static_cast(1 << 3); // binary mode + static const std::ios_base::openmode in = static_cast(1 << 4); // for reading + static const std::ios_base::openmode out = static_cast(1 << 5); // for writing // for writing and reading + static const std::ios_base::openmode trunc = static_cast(1 << 6); // truncate on open + static const std::ios_base::openmode noreplace = static_cast(1 << 7); // no replace if it exists + + /// Additional optional flags to omode in open() and lmode in fopen() or lock() + /// to indicate which sort of lock if any to attempt to get + /// + /// NOTE: there is a fundamental difference between platforms. + /// On Windows this lock is mandatory as it is part of the API to open a file handle and other + /// processes can not avoid it. If a file was opened denying other processes read and/or write + /// access, trying to open the same file in another process with that access will fail. + /// On Mac and Linux it is only an advisory lock implemented through the flock() system call. + /// This means that any other application needs to also attempt to at least acquire a shared + /// lock on the file in order to notice that the file is actually already locked. It can + /// therefore not be used to prevent random other applications from accessing the file, but it + /// works for other viewer processes when they use either the LLFile::open() or LLFile::fopen() + /// functions with the appropriate lock flags to open a file. + static const std::ios_base::openmode exclusive = static_cast(1 << 16); + static const std::ios_base::openmode shared = static_cast(1 << 17); + + /// Additional lmode flag to indicate to rather fail instead of blocking when trying + /// to acquire a lock with LLFile::lock() + static const std::ios_base::openmode noblock = static_cast(1 << 18); + + /// The mask value for the lock mask bits + static const std::ios_base::openmode lock_mask = static_cast(exclusive | shared); + + /// One of these can be passed to the dir parameter of LLFile::seek() + static const std::ios_base::seekdir beg = std::ios_base::beg; + static const std::ios_base::seekdir cur = std::ios_base::cur; + static const std::ios_base::seekdir end = std::ios_base::end; + ///@} + + // ================================================================================ + /// @name constructor/deconstructor + /// + ///@{ + /// default constructor + LLFile() : mHandle(InvalidHandle) {} + + /// no copy constructor + LLFile(const LLFile&) = delete; + + /// move constructor + LLFile(LLFile&& other) noexcept + { + mHandle = other.mHandle; + other.mHandle = InvalidHandle; + } + + /// constructor opening the file + LLFile(const std::string& filename, std::ios_base::openmode omode, std::error_code& ec, int perm = 0666) : + mHandle(InvalidHandle) + { + open(filename, omode, ec, perm); + } + + /// destructor always attempts to close the file + ~LLFile() { close(); } + ///@} + + // ================================================================================ + /// @name operators + /// + ///@{ + /// copy assignment deleted + LLFile& operator=(const LLFile&) = delete; + + /// move assignment + LLFile& operator=(LLFile&& other) noexcept + { + close(); + std::swap(mHandle, other.mHandle); + return *this; + } + + // detect whether the wrapped file descriptor/handle is open or not + explicit operator bool() const { return (mHandle != InvalidHandle); } + bool operator!() { return (mHandle == InvalidHandle); } + ///@} + + /// ================================================================================ + /// @name class member methods + /// + /// These methods provide read and write support as well as additional functionality to query the size of + /// the file, change the position of the current file pointer or query it. + /// + /// Most of these functions take as one of their parameters a std::error_code object which can be used to + /// determine in more detail what error occurred if required + ///@{ + + /// Open a file with the specific open mode flags + int open(const std::string& filename, std::ios_base::openmode omode, std::error_code& ec, int perm = 0666); + ///< @returns 0 on success, -1 on failure + + /// Determine the size of the opened file + S64 size(std::error_code& ec); + ///< @returns the number of bytes in the file or -1 on failure + + /// Query the position of the current file pointer in the file + S64 tell(std::error_code& ec); + ///< @returns the absolute offset of the file pointer in bytes relative to the start of the file or -1 on failure + + /// Move the file pointer to the specified absolute position relative to the start of the file + int seek(S64 pos, std::error_code& ec); + ///< @returns 0 on success, -1 on failure + + /// Move the file pointer to the specified position relative to dir + int seek(S64 offset, std::ios_base::seekdir dir, std::error_code& ec); + ///< @returns 0 on success, -1 on failure + + /// Read the specified number of bytes into the buffer starting at the current file pointer + S64 read(void* buffer, S64 nbytes, std::error_code& ec); + ///< If the file ends before the requested amount of bytes could be read, the function succeeds and + /// returns the bytes up to the end of the file. The return value indicates the number of actually + /// read bytes and can be therefore smaller than the requested amount. + /// @returns the number of bytes read from the file or -1 on failure + + /// Write the specified number of bytes to the file starting at the current file pointer + S64 write(const void* buffer, S64 nbytes, std::error_code& ec); + ///< @returns the number of bytes written to the file or -1 on failure + + /// Write into the file starting at the current file pointer using printf style format and + /// additional optional parameters as specified in the fmt string + S64 printf(const char* fmt, ...); + ///< @returns the number of bytes written to the file or -1 on failure + + /// Attempt to acquire or release a lock on the file + int lock(int lmode, std::error_code& ec); + ///< lmode can be one of LLFile::exclusive or LLFile::shared to acquire the according lock + /// or 0 to give up an earlier acquired lock. Adding LLFile::noblock together with one of + /// the lock requests will cause the function to fail if the lock can not be acquired, + /// otherwise the function will block until the lock can be acquired. + /// @returns 0 on success, -1 on failure + + /// close the file explicitly + int close(std::error_code& ec); + ///< @returns 0 on success, -1 on failure + + /// Convenience function to close the file without additional parameters + int close(); + ///< @returns 0 on success, -1 on failure + ///@} + + /// ================================================================================ + /// @name static member functions + /// + /// These functions are static and operate with UTF8 filenames as one of their parameters. + /// + ///@{ /// open a file with the specified access mode - static LLFILE* fopen(const std::string& filename, const char* accessmode); /* Flawfinder: ignore */ + static LLFILE* fopen(const std::string& filename, const char* accessmode, int lmode = 0); ///< 'accessmode' follows the rules of the Posix fopen() mode parameter - /// "r" open the file for reading only and positions the stream at the beginning - /// "r+" open the file for reading and writing and positions the stream at the beginning - /// "w" open the file for reading and writing and truncate it to zero length - /// "w+" open or create the file for reading and writing and truncate to zero length if it existed - /// "a" open the file for reading and writing and position the stream at the end of the file - /// "a+" open or create the file for reading and writing and position the stream at the end of the file + /// "r" open the file for reading only and positions the stream at the beginning + /// "r+" open the file for reading and writing and positions the stream at the beginning + /// "w" open the file for reading and writing and truncate it to zero length + /// "w+" open or create the file for reading and writing and truncate to zero length if it existed + /// "a" open the file for reading and writing and before every write position the stream at the end of the file + /// "a+" open or create the file for reading and writing and before every write position the stream at the end of the file + /// + /// in addition to these values, "b" can be appended to indicate binary stream access, but on Linux and Mac + /// this is strictly for compatibility and has no effect. On Windows this makes the file functions not + /// try to translate line endings. Windows also allows to append "t" to indicate text mode. If neither + /// "b" or "t" is defined, Windows uses the value set by _fmode which by default is _O_TEXT. + /// This means that it is always a good idea to append "b" specifically for binary file access to + /// avoid corruption of the binary consistency of the data stream when reading or writing + /// Other characters in 'accessmode', while possible on some platforms (Windows), will usually + /// cause an error on other platforms as fopen will verify this parameter /// - /// in addition to these values, "b" can be appended to indicate binary stream access, but on Linux and Mac - /// this is strictly for compatibility and has no effect. On Windows this makes the file functions not - /// try to translate line endings. Windows also allows to append "t" to indicate text mode. If neither - /// "b" or "t" is defined, Windows uses the value set by _fmode which by default is _O_TEXT. - /// This means that it is always a good idea to append "b" specifically for binary file access to - /// avoid corruption of the binary consistency of the data stream when reading or writing - /// Other characters in 'accessmode' will usually cause an error as fopen will verify this parameter - /// @returns a valid LLFILE* pointer on success or NULL on failure + /// lmode is optional and allows to lock the file for other processes either as a shared lock or an + /// exclusive lock. If the requested lock conflicts with an already existing lock, the open fails. + /// Pass either LLFIle::exclusive or LLFile::shared to this parameter if you want to prevent other + /// processes from reading (exclusive lock) or writing (shared lock) to the file. It will always use + /// LLFile::noblock, meaning the open will immediately fail if it conflicts with an existing lock on the + /// file. + /// + /// @returns a valid LLFILE* pointer on success that can be passed to the fread() and fwrite() functions + /// and some other f functions in the Standard C library that accept a FILE* as parameter + /// or NULL on failure + /// Close a file handle opened with fopen() above static int close(LLFILE * file); - - /// retrieve the content of a file into a string - static std::string getContents(const std::string& filename); - ///< @returns the content of the file or an empty string on failure + ///< @returns 0 on success and -1 on failure. /// create a directory - static int mkdir(const std::string& filename, int perms = 0700); - ///< perms is a permissions mask like 0777 or 0700. In most cases it will be - /// overridden by the user's umask. It is ignored on Windows. - /// mkdir() considers "directory already exists" to be not an error. - /// @returns 0 on success and -1 on failure. - - //// remove a directory - static int rmdir(const std::string& filename, int suppress_error = 0); - ///< pass ENOENT in the optional 'suppress_error' parameter - /// if you don't want a warning in the log when the directory does not exist + static int mkdir(const std::string& filename); + ///< mkdir() considers "directory already exists" to be not an error. /// @returns 0 on success and -1 on failure. /// remove a file or directory - static int remove(const std::string& filename, int suppress_error = 0); - ///< pass ENOENT in the optional 'suppress_error' parameter - /// if you don't want a warning in the log when the directory does not exist + static int remove(const std::string& filename, int suppress_warning = 0); + ///< pass an errno value (e.g., ENOENT) in the optional 'suppress_warning' parameter if you want to + /// suppress a warning in the log when the failure matches that errno (e.g., suppress warning if + /// the file or directory does not exist) /// @returns 0 on success and -1 on failure. /// rename a file - static int rename(const std::string& filename, const std::string& newname, int suppress_error = 0); + static int rename(const std::string& filename, const std::string& newname, int suppress_warning = 0); ///< it will silently overwrite newname if it exists without returning an error /// Posix guarantees that if newname already exists, then there will be no moment /// in which for other processes newname does not exist. There is no such guarantee - /// under Windows at this time. It may do it in the same way but the used Windows API - /// does not make such guarantees. + /// under Windows at this time. It may do it in the same way but the used Windows + /// APIs do not make such guarantees. /// @returns 0 on success and -1 on failure. + /// copy the contents of the file from 'source' to 'target' + static bool copy(const std::string& source, const std::string& target); + ///< Copies the contents of the file 'source' to the file 'target', overwriting 'target' if it already + /// existed. + /// This is a convenience function that implements the previous behavior of silently overwriting an + /// already existing target file. Consider using the function below if you desire a different + /// behavior when the target file already exists + /// @returns true on success and false on failure. + + /// copy the contents of the file from 'from' to 'to' + static bool copy(const std::string& source, const std::string& target, std::filesystem::copy_options options, std::error_code& ec); + ///< Copies the contents of the file 'source' to the file 'target'. The options parameter allows to + /// specify what should happen if the "target" file already exists: + /// std::filesystem::copy_options::none - return an error in ec and fail + /// std::filesystem::copy_options::skip_existing - skip the operation and do not overwrite file + /// std::filesystem::copy_options::overwrite_existing - overwrite the file + /// std::filesystem::copy_options::update_existing - overwrite the file only if it is older than the file being copied + /// @returns true on success and false on failure. + + /// retrieve the content of a file into a string + static std::string getContents(const std::string& filename); + static std::string getContents(const std::string& filename, std::error_code& ec); + ///< @returns the entire content of the file as std::string or an empty string on failure + + /// read nBytes from the file into the buffer, starting at offset in the file + static S64 read(const std::string& filename, void* buf, S64 offset, S64 nbytes); + static S64 read(const std::string& filename, void* buf, S64 offset, S64 nbytes, std::error_code& ec); + ///< @returns bytes read on success, or -1 on failure - /// copy the contents of file from 'from' to 'to' filename - static bool copy(const std::string& from, const std::string& to); - ///< @returns true on success and false on failure. + /// write nBytes from the buffer into the file, starting at offset in the file + static S64 write(const std::string& filename, const void* buf, S64 offset, S64 nbytes); + static S64 write(const std::string& filename, const void* buf, S64 offset, S64 nbytes, std::error_code& ec); + ///< If a negative offset is provided, the file is opened in append mode and the + /// write will be appended to the end of the file. + /// @returns bytes written on success, or -1 on failure /// return the file stat structure for filename - static int stat(const std::string& filename, llstat* file_status, int suppress_error = ENOENT); + static int stat(const std::string& filename, llstat* file_status, const char *operation = nullptr, int suppress_warning = ENOENT); ///< for compatibility with existing uses of LL_File::stat() we use ENOENT as default in the - /// optional 'suppress_error' parameter to avoid spamming the log with warnings when the API + /// optional 'suppress_warning' parameter to avoid spamming the log with warnings when the API /// is used to detect if a file exists /// @returns 0 on success and -1 on failure. - /// get the file or directory attributes for filename - static unsigned short getattr(const std::string& filename, bool dontFollowSymLink = false, int suppress_error = ENOENT); - ///< a more lightweight function on Windows to stat, that just returns the file attribute flags - /// dontFollowSymLinks set to true returns the attributes of the symlink if it is one, rather than resolving it - /// we pass by default ENOENT in the optional 'suppress_error' parameter to not spam the log with - /// warnings when the file or directory does not exist - /// @returns 0 on failure and a st_mode value with either S_IFDIR or S_IFREG set otherwise - /// together with the three access bits which under Windows only the write bit is relevant. + /// get the creation data and time of a file + static std::time_t getCreationTime(const std::string& filename, int suppress_warning = 0); + ///< Different systems have different support for this. Under Windows this is supposedly + /// the actual time the file was created, on the Mac this is the actual birth date of + /// the file which is in fact the creation time. The according ctime entry in the stat + /// structure under Linux (and any other *nix really) is however contrary to what one + /// might expect based on the c in ctime not the creation time but the time the last + /// change to the inode entry was made. Changing access rights to a file will update + /// this value too. In order to have a true creation time under Linux, we would have + /// to use the statx() call which is available since kernel 4.19, but that will require + /// considerable changes to the implementation of above stat() function. + /// @returns the creation time (last status change under Linux) of the file or 0 on error + + /// get the last modification data and time of a file + static std::time_t getModificationTime(const std::string& filename, int suppress_warning = 0); + ///< @returns the modification time of the file or 0 on error + + /// get the std::filesystem::file_status for filename + static std::filesystem::file_status getStatus(const std::string& filename, bool dontFollowSymLink = false, int suppress_warning = ENOENT); + ///< dontFollowSymLinks set to true returns the std::filesystem::file_status of the symlink if it + /// is one, rather than resolving it. We pass by default ENOENT in the optional 'suppress_warning' + /// parameter to not spam the log with warnings when the file or directory does not exist + /// @returns a std::filesystem::file_status value that can be passed to the appropriate std::filesystem::exists() + /// and other APIs accepting a file_status. + + /// get the size of a file in bytes + static S64 size(const std::string& filename, int suppress_warning = ENOENT); + ///< we pass by default ENOENT in the optional 'suppress_warning' parameter to not spam + /// the log with warnings when the file does not exist + /// @returns the file size on success or -1 on failure. + + /// check if filename is an existing file or directory + static bool exists(const std::string& filename); + ///< @returns true if the path is for an existing file or directory /// check if filename is an existing directory static bool isdir(const std::string& filename); @@ -161,70 +402,44 @@ public: ///< @returns true if the path is pointing at a symlink /// return a path to the temporary directory on the system - static const char * tmpdir(); -}; - -/// RAII class -class LLUniqueFile -{ -public: - // empty - LLUniqueFile(): mFileHandle(nullptr) {} - // wrap (e.g.) result of LLFile::fopen() - LLUniqueFile(LLFILE* f): mFileHandle(f) {} - // no copy - LLUniqueFile(const LLUniqueFile&) = delete; - // move construction - LLUniqueFile(LLUniqueFile&& other) noexcept - { - mFileHandle = other.mFileHandle; - other.mFileHandle = nullptr; - } - // The point of LLUniqueFile is to close on destruction. - ~LLUniqueFile() - { - close(); - } - - // simple assignment - LLUniqueFile& operator=(LLFILE* f) - { - close(); - mFileHandle = f; - return *this; - } - // copy assignment deleted - LLUniqueFile& operator=(const LLUniqueFile&) = delete; - // move assignment - LLUniqueFile& operator=(LLUniqueFile&& other) noexcept - { - close(); - std::swap(mFileHandle, other.mFileHandle); - return *this; - } - - // explicit close operation - void close() - { - if (mFileHandle) - { - // in case close() throws, set mFileHandle null FIRST - LLFILE* h{nullptr}; - std::swap(h, mFileHandle); - LLFile::close(h); - } - } - - // detect whether the wrapped LLFILE is open or not - explicit operator bool() const { return bool(mFileHandle); } - bool operator!() { return ! mFileHandle; } + static const std::string& tmpdir(); - // LLUniqueFile should be usable for any operation that accepts LLFILE* - // (or FILE* for that matter) - operator LLFILE*() const { return mFileHandle; } + /// converts a string containing a path in utf8 encoding into an explicit filesystem path + static std::filesystem::path utf8StringToPath(const std::string& pathname); + ///< @returns the path as a std::filesystem::path + ///@} private: - LLFILE* mFileHandle; +#if LL_WINDOWS + typedef HANDLE llfile_handle_t; + const llfile_handle_t InvalidHandle = INVALID_HANDLE_VALUE; +#else + typedef int llfile_handle_t; + const llfile_handle_t InvalidHandle = -1; +#endif + + /// ================================================================================ + /// @name private static member functions + /// +#if LL_WINDOWS + /// convert a string containing a path in utf8 encoding into a Windows format std::wstring + static std::wstring utf8StringToWstring(const std::string& pathname); + ///< this will prepend the path with the Windows kernel object space prefix when the path is + /// equal or longer than MAX_PATH characters and do some sanitation on the path. + /// This allows the underlaying Windows APIs to process long path names. Do not pass such a path + /// to std::filesystem functions. These functions are not guaranteed to handle such paths properly. + /// It's only useful to pass the resulting string buffer to Microsoft Windows widechar APIs or + /// the Microsoft C runtime widechar file functions. + /// + /// Example: + /// + /// std::wstring file_path = utf8StringToWstring(filename); + /// HANDLE CreateFileW(file_path.c_str(), ......); + /// + /// @returns the path as a std::wstring path +#endif + llfile_handle_t mHandle; // The file handle/descriptor + std::ios_base::openmode mOpen; // Used to emulate std::ios_base::app under Windows }; #if LL_WINDOWS @@ -315,17 +530,6 @@ class LL_COMMON_API llofstream : public std::ofstream ios_base::openmode _Mode = ios_base::out|ios_base::trunc); }; - -/** - * @brief filesize helpers. - * - * The file size helpers are not considered particularly efficient, - * and should only be used for config files and the like -- not in a - * loop. - */ -std::streamsize LL_COMMON_API llifstream_size(llifstream& fstr); -std::streamsize LL_COMMON_API llofstream_size(llofstream& fstr); - #else // ! LL_WINDOWS // on non-windows, llifstream and llofstream are just mapped directly to the std:: equivalents diff --git a/indra/llcommon/tests/llfile_test.cpp b/indra/llcommon/tests/llfile_test.cpp new file mode 100644 index 0000000000..9f2a9b2988 --- /dev/null +++ b/indra/llcommon/tests/llfile_test.cpp @@ -0,0 +1,253 @@ +/** + * @file llfile_tut.cpp + * @author Frederick Martian + * @date 2025-11 + * @brief LLFile test cases. + * + * $LicenseInfo:firstyear=2025&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2025, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include +#include "lltut.h" +#include "linden_common.h" +#include "llfile.h" + +namespace tut +{ + static void clear_entire_dir(std::filesystem::path &dir) + { + std::error_code ec; + std::filesystem::remove_all(dir, ec); + } + + static std::filesystem::path append_filename(const std::filesystem::path& dir, const std::string& element) + { + std::filesystem::path path = dir; + return path.append(element); + } + + static std::filesystem::path get_testdir(const std::filesystem::path& tempdir) + { + return append_filename(tempdir, std::string("test_dir")); + } + + struct llfile_test + { + std::filesystem::path tempdir = LLFile::tmpdir(); + std::filesystem::path testdir = get_testdir(tempdir); + }; + typedef test_group llfile_test_t; + typedef llfile_test_t::object llfile_test_object_t; + tut::llfile_test_t tut_llfile_test("llfile_test"); + + template<> template<> + void llfile_test_object_t::test<1>() + { + // Test creating directories and files and deleting them and checking if the + // relevant status functions work as expected + ensure("LLFile::tmpdir() empty", !tempdir.empty()); + ensure("LLFile::tmpdir() doesn't exist", LLFile::exists(tempdir.string())); + ensure("LLFile::tmpdir() is not a directory", LLFile::isdir(tempdir.string())); + ensure("LLFile::tmpdir() should not be a file", !LLFile::isfile(tempdir.string())); + + // Make sure there is nothing left from a previous test run + clear_entire_dir(testdir); + ensure("llfile_test should not exist anymore", !LLFile::exists(testdir.string())); + + int rc = LLFile::mkdir(testdir.string()); + ensure("LLFile::mkdir() failed", rc == 0); + ensure("llfile_test should be a directory", LLFile::isdir(testdir.string())); + rc = LLFile::mkdir(testdir.string()); + ensure("LLFile::mkdir() should not fail when the directory already exists", rc == 0); + + std::filesystem::path testfile1 = testdir; + testfile1.append("llfile_test.dat"); + ensure("llfile_test1.dat should not yet exist", !LLFile::exists(testfile1.string())); + + const char* testdata = "testdata"; + S64 bytes = LLFile::write(testfile1.string(), testdata, 0, sizeof(testdata)); + ensure("LLFile::write() did not write correctly", bytes == sizeof(testdata)); + + rc = LLFile::remove(testfile1.string()); + ensure("LLFile::remove() for file test_file.dat", rc == 0); + ensure("llfile_test.dat should not exist anymore", !LLFile::exists(testfile1.string())); + ensure("llfile_test.dat should not be a file", !LLFile::isfile(testfile1.string())); + ensure("llfile_test.dat should not be a directory", !LLFile::isdir(testfile1.string())); + ensure("llfile_test.dat should not be a symlink", !LLFile::islink(testfile1.string())); + + rc = LLFile::remove(testdir.string()); + ensure("LLFile::remove() for directory llfile_test failed", rc == 0); + ensure("llfile_test should not exist anymore", !LLFile::exists(testdir.string())); + } + + template<> template<> + void llfile_test_object_t::test<2>() + { + // High level static file IO functions to read and write data files + LLFile::mkdir(testdir.string()); + ensure("llfile_test should exist", LLFile::isdir(testdir.string())); + + std::filesystem::path testfile1 = testdir; + testfile1.append("llfile_test.dat"); + + std::string testdata1("testdata"); + std::string testdata2("datateststuff"); + std::time_t current = time(nullptr); + S64 bytes = LLFile::write(testfile1.string(), testdata1.c_str(), 0, testdata1.length()); + ensure("LLFile::write() did not write correctly", bytes == testdata1.length()); + ensure("llfile_test.dat should exist", LLFile::exists(testfile1.string())); + ensure("llfile_test.dat should be a file", LLFile::isfile(testfile1.string())); + ensure("llfile_test.dat should not be a directory", !LLFile::isdir(testfile1.string())); + + bytes = LLFile::size(testfile1.string()); + ensure("LLFile::size() did not return the correct size", bytes == testdata1.length()); + + std::string data = LLFile::getContents(testfile1.string()); + ensure("LLFile::getContents() did not return the correct size data", data.length() == testdata1.length()); + ensure_memory_matches("LLFile::getContents() did not read correct data", testdata1.c_str(), (U32)testdata1.length(), data.c_str(), (U32)data.length()); + + std::time_t ctime = LLFile::getCreationTime(testfile1.string()); + ensure_approximately_equals_range("LLFile::getCreationTime() did not return correct time", (F32)(ctime - current), 0.f, 1); + + std::time_t mtime = LLFile::getModificationTime(testfile1.string()); + ensure_approximately_equals_range("LLFile::getModificationTime() did not return correct time", (F32)(mtime - current), 0.f, 1); + + char buffer[1024]; + bytes = LLFile::read(testfile1.string(), buffer, 0, testdata1.length()); + ensure("LLFile:read() did not return the correct size", bytes == testdata1.length()); + ensure_memory_matches("LLFile::read() did not read correct data", testdata1.c_str(), (U32)bytes, buffer, (U32)bytes); + + // What if we try to read more data than there is in the file? + bytes = LLFile::read(testfile1.string(), buffer, 0, bytes + 10); + ensure("LLFile:read() did not correctly stop on eof", bytes == testdata1.length()); + ensure_memory_matches("LLFile::read() did not read correct data", testdata1.c_str(), (U32)bytes, buffer, (U32)bytes); + + // Let's append more data + bytes = LLFile::write(testfile1.string(), testdata2.c_str(), -1, testdata2.length()); + ensure("LLFile::write() did not write correctly", bytes == testdata2.length()); + + bytes = LLFile::size(testfile1.string()); + ensure("LLFile::size() did not return the correct size", bytes == testdata1.length() + testdata2.length()); + bytes = LLFile::read(testfile1.string(), buffer, 0, bytes); + ensure("LLFile:read() did not read correct number of bytes", bytes == testdata1.length() + testdata2.length()); + ensure_memory_matches("LLFile:read() did not read correct testdata1", testdata1.c_str(), (U32)testdata1.length(), buffer, (U32)testdata1.length()); + ensure_memory_matches("LLFile:read() did not read correct testdata2", testdata2.c_str(), (U32)testdata2.length(), buffer + testdata1.length(), (U32)testdata2.length()); + } + + template<> template<> + void llfile_test_object_t::test<3>() + { + const size_t numints = 1024; + + // Testing the LLFile class implementation + std::filesystem::path testfile = testdir; + testfile.append("llfile_test.bin"); + + int data[numints]; + for (int &t : data) + { + t = rand(); + } + + std::error_code ec; + LLFile fileout(testfile.string(), LLFile::out, ec); + ensure("LLFile constructor did not open correctly", (bool)fileout); + ensure("error_code from LLFile constructor should not indicate an error", !ec); + if (fileout) + { + S64 length = fileout.size(ec); + ensure("freshly created file should be empty", length == 0); + ensure("error_code from LLFile::size() should not indicate an error", !ec); + S64 bytes = fileout.write(data, sizeof(data), ec); + ensure("LLFile::write() did not write correctly", bytes == sizeof(data)); + ensure("error_code from LLFile::write() should not indicate an error", !ec); + bytes = fileout.write(data, sizeof(data), ec); + ensure("LLFile::write() did not write correctly", bytes == sizeof(data)); + ensure("error_code from LLFile::write() should not indicate an error", !ec); + bytes = fileout.size(ec); + ensure("LLFile::size() returned wrong size", bytes == 2 * sizeof(data)); + ensure("error_code from LLFile::size() should not indicate an error", !ec); + fileout.close(); + } + + LLFile filein(testfile.string(), LLFile::in, ec); + ensure("LLFile constructor did not open correctly", (bool)filein); + ensure("error_code from LLFile constructor should not indicate an error", !ec); + if (filein) + { + S64 length = filein.size(ec); + ensure("LLFile::size() returned wrong size", length == 2 * sizeof(data)); + ensure("error_code from LLFile::size() should not indicate an error", !ec); + char* buffer = (char*)malloc(length); + S64 bytes = filein.read(buffer, length, ec); + ensure("LLFile::read() did not read correctly", bytes == length); + ensure("error_code from LLFile::read() should not indicate an error", !ec); + ensure_memory_matches("LLFile:read() did not read correct data1", data, (U32)sizeof(data), buffer, (U32)sizeof(data)); + ensure_memory_matches("LLFile:read() did not read correct data2", data, (U32)sizeof(data), buffer + sizeof(data), (U32)sizeof(data)); + S64 offset = filein.tell(ec); + ensure("LLFile::tell() returned a bad offset", offset == length); + ensure("error_code from LLFile::read() should not indicate an error", !ec); + offset = sizeof(data) / 2; + int rc = filein.seek(offset, ec); + ensure("LLFile::seek() indicated an error", rc == 0); + ensure("error_code from LLFile::seek() should not indicate an error", !ec); + bytes = filein.read(buffer, 2 * sizeof(data), ec); + ensure("LLFile::read() did not read correctly", bytes == sizeof(data) + offset); + ensure("error_code from LLFile::read() should not indicate an error", !ec); + ensure_memory_matches("LLFile:read() did not read correct data3", (char*)data + offset, (U32)offset, buffer, (U32)offset); + ensure_memory_matches("LLFile:read() did not read correct data4", (char*)data, (U32)sizeof(data), buffer + offset, (U32)sizeof(data)); + filein.close(); + + free(buffer); + } + } + + template<> template<> + void llfile_test_object_t::test<4>() + { + // Testing the LLFile class implementation with wrong paths and parameters + std::filesystem::path testfile = testdir; + testfile.append("llfile_test.bin"); + + std::error_code ec; + LLFile file(testfile.string(), LLFile::out | LLFile::noreplace, ec); + ensure("LLFile constructor should not have opened the already existing file", !file); + ensure("error_code from LLFile constructor should indicate an error", (bool)ec); + + LLFile::remove(testfile.string()); + file = LLFile(testfile.string(), LLFile::out | LLFile::app | LLFile::trunc, ec); + ensure("LLFile constructor should not have opened the file with conflicting flags", !file); + ensure("error_code from LLFile constructor should indicate an error", (bool)ec); + + file = LLFile(testfile.string(), LLFile::out | LLFile::app | LLFile::noreplace, ec); + ensure("LLFile constructor should not have opened the file with conflicting flags", !file); + ensure("error_code from LLFile constructor should indicate an error", (bool)ec); + + testfile = testdir; + testfile.append("llfile_test"); + testfile.append("llfile_test.bin"); + + file = LLFile(testfile.string(), LLFile::in, ec); + ensure("LLFile constructor should not have been able to open the file in the non-existing directory", !file); + ensure("error_code from LLFile constructor should indicate an error", (bool)ec); + } +} // namespace tut diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp old mode 100644 new mode 100755 index 190539cea5..eb3c2d9909 --- a/indra/llfilesystem/lldir.cpp +++ b/indra/llfilesystem/lldir.cpp @@ -30,8 +30,6 @@ #include #include #include -#else -#include #endif #include "lldir.h" @@ -43,7 +41,6 @@ #include "lldiriterator.h" #include "stringize.h" #include "llstring.h" -#include #include #include @@ -93,30 +90,20 @@ LLDir::~LLDir() std::vector LLDir::getFilesInDir(const std::string &dirname) { - //Returns a vector of fullpath filenames. - -#ifdef LL_WINDOWS // or BOOST_WINDOWS_API - boost::filesystem::path p(ll_convert(dirname)); -#else - boost::filesystem::path p(dirname); -#endif - + // Returns a vector of filenames in the directory. + std::filesystem::path p = LLFile::utf8StringToPath(dirname); std::vector v; - - boost::system::error_code ec; - if (exists(p, ec) && !ec.failed()) + std::error_code ec; + if (std::filesystem::is_directory(p, ec)) { - if (is_directory(p, ec) && !ec.failed()) + std::filesystem::directory_iterator end_iter; + for (std::filesystem::directory_iterator dir_itr(p); + dir_itr != end_iter; + ++dir_itr) { - boost::filesystem::directory_iterator end_iter; - for (boost::filesystem::directory_iterator dir_itr(p); - dir_itr != end_iter; - ++dir_itr) + if (std::filesystem::is_regular_file(dir_itr->status())) { - if (boost::filesystem::is_regular_file(dir_itr->status())) - { - v.push_back(dir_itr->path().filename().string()); - } + v.push_back(dir_itr->path().filename().string()); } } } @@ -186,28 +173,23 @@ U32 LLDir::deleteDirAndContents(const std::string& dir_name) //Removes the directory and its contents. Returns number of files deleted. U32 num_deleted = 0; + std::filesystem::path dir_path = LLFile::utf8StringToPath(dir_name); try { -#ifdef LL_WINDOWS // or BOOST_WINDOWS_API - boost::filesystem::path dir_path(ll_convert(dir_name)); -#else - boost::filesystem::path dir_path(dir_name); -#endif - - if (boost::filesystem::exists(dir_path)) + if (std::filesystem::is_directory(dir_path)) { - if (!boost::filesystem::is_empty(dir_path)) + if (!std::filesystem::is_empty(dir_path)) { // Directory has content - num_deleted = (U32)boost::filesystem::remove_all(dir_path); + num_deleted = (U32)std::filesystem::remove_all(dir_path); } else { // Directory is empty - boost::filesystem::remove(dir_path); + std::filesystem::remove(dir_path); } } } - catch (boost::filesystem::filesystem_error &er) + catch (std::filesystem::filesystem_error &er) { LL_WARNS() << "Failed to delete " << dir_name << " with error " << er.code().message() << LL_ENDL; } @@ -1105,15 +1087,15 @@ void dir_exists_or_crash(const std::string &dir_name) #if LL_WINDOWS // *FIX: lame - it doesn't do the same thing on windows. not so // important since we don't deploy simulator to windows boxes. - LLFile::mkdir(dir_name, 0700); + LLFile::mkdir(dir_name); #else - struct stat dir_stat; + llstat dir_stat; if(0 != LLFile::stat(dir_name, &dir_stat)) { S32 stat_rv = errno; if(ENOENT == stat_rv) { - if(0 != LLFile::mkdir(dir_name, 0700)) // octal + if(0 != LLFile::mkdir(dir_name)) { LL_ERRS() << "Unable to create directory: " << dir_name << LL_ENDL; } diff --git a/indra/llfilesystem/lldir_win32.cpp b/indra/llfilesystem/lldir_win32.cpp old mode 100644 new mode 100755 index 9624b1197f..1cfa157634 --- a/indra/llfilesystem/lldir_win32.cpp +++ b/indra/llfilesystem/lldir_win32.cpp @@ -376,18 +376,7 @@ std::string LLDir_Win32::getCurPath() bool LLDir_Win32::fileExists(const std::string &filename) const { - llstat stat_data; - // Check the age of the file - // Now, we see if the files we've gathered are recent... - int res = LLFile::stat(filename, &stat_data); - if (!res) - { - return true; - } - else - { - return false; - } + return LLFile::exists(filename); } diff --git a/indra/llfilesystem/llfilesystem.cpp b/indra/llfilesystem/llfilesystem.cpp old mode 100644 new mode 100755 index 541266af4f..0c220fe7cf --- a/indra/llfilesystem/llfilesystem.cpp +++ b/indra/llfilesystem/llfilesystem.cpp @@ -77,21 +77,17 @@ bool LLFileSystem::getExists(const LLUUID& file_id, const LLAssetType::EType fil LL_PROFILE_ZONE_SCOPED; const std::string filename = LLDiskCache::metaDataToFilepath(file_id, file_type); - llifstream file(filename, std::ios::binary); - if (file.is_open()) - { - file.seekg(0, std::ios::end); - return file.tellg() > 0; - } - return false; + // not only test for existence but for the file to be not empty + S64 size = LLFile::size(filename); + return size > 0; } // static -bool LLFileSystem::removeFile(const LLUUID& file_id, const LLAssetType::EType file_type, int suppress_error /*= 0*/) +bool LLFileSystem::removeFile(const LLUUID& file_id, const LLAssetType::EType file_type, int suppress_warning /*= 0*/) { const std::string filename = LLDiskCache::metaDataToFilepath(file_id, file_type); - LLFile::remove(filename.c_str(), suppress_error); + LLFile::remove(filename.c_str(), suppress_warning); return true; } @@ -116,19 +112,10 @@ bool LLFileSystem::renameFile(const LLUUID& old_file_id, const LLAssetType::ETyp } // static -S32 LLFileSystem::getFileSize(const LLUUID& file_id, const LLAssetType::EType file_type) +S64 LLFileSystem::getFileSize(const LLUUID& file_id, const LLAssetType::EType file_type) { const std::string filename = LLDiskCache::metaDataToFilepath(file_id, file_type); - - S32 file_size = 0; - llifstream file(filename, std::ios::binary); - if (file.is_open()) - { - file.seekg(0, std::ios::end); - file_size = (S32)file.tellg(); - } - - return file_size; + return LLFile::size(filename); } bool LLFileSystem::read(U8* buffer, S32 bytes) @@ -269,7 +256,7 @@ S32 LLFileSystem::tell() const S32 LLFileSystem::getSize() const { - return LLFileSystem::getFileSize(mFileID, mFileType); + return (S32)LLFileSystem::getFileSize(mFileID, mFileType); } S32 LLFileSystem::getMaxSize() const diff --git a/indra/llfilesystem/llfilesystem.h b/indra/llfilesystem/llfilesystem.h index 10649b6920..7188683e7f 100644 --- a/indra/llfilesystem/llfilesystem.h +++ b/indra/llfilesystem/llfilesystem.h @@ -61,10 +61,10 @@ class LLFileSystem void updateFileAccessTime(const std::string& file_path); static bool getExists(const LLUUID& file_id, const LLAssetType::EType file_type); - static bool removeFile(const LLUUID& file_id, const LLAssetType::EType file_type, int suppress_error = 0); + static bool removeFile(const LLUUID& file_id, const LLAssetType::EType file_type, int suppress_warning = 0); static bool renameFile(const LLUUID& old_file_id, const LLAssetType::EType old_file_type, const LLUUID& new_file_id, const LLAssetType::EType new_file_type); - static S32 getFileSize(const LLUUID& file_id, const LLAssetType::EType file_type); + static S64 getFileSize(const LLUUID& file_id, const LLAssetType::EType file_type); public: static const S32 READ; diff --git a/indra/llfilesystem/tests/lldir_test.cpp b/indra/llfilesystem/tests/lldir_test.cpp old mode 100644 new mode 100755 index a2104d1ef9..8b86da40b3 --- a/indra/llfilesystem/tests/lldir_test.cpp +++ b/indra/llfilesystem/tests/lldir_test.cpp @@ -557,8 +557,8 @@ namespace tut LLFile::remove(dir1files[i]); LLFile::remove(dir2files[i]); } - LLFile::rmdir(dir1); - LLFile::rmdir(dir2); + LLFile::remove(dir1); + LLFile::remove(dir2); } template<> template<> diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index 10fd56a68e..34eeacb273 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -467,7 +467,7 @@ bool LLAssetStorage::findInCacheAndInvokeCallback(const LLUUID& uuid, LLAssetTyp else { LL_WARNS("AssetStorage") << "Asset vfile " << uuid << ":" << type - << " found in static cache with bad size " << file.getSize() << ", ignoring" << LL_ENDL; + << " found in static cache with bad size " << size << ", ignoring" << LL_ENDL; } } return false; diff --git a/indra/llmessage/tests/llmessageconfig_test.cpp b/indra/llmessage/tests/llmessageconfig_test.cpp old mode 100644 new mode 100755 index 93443467a2..b8942e99b3 --- a/indra/llmessage/tests/llmessageconfig_test.cpp +++ b/indra/llmessage/tests/llmessageconfig_test.cpp @@ -62,7 +62,7 @@ namespace tut int rmfile = LLFile::remove((mTestConfigDir + "/message.xml")); ensure_equals("rmfile value", rmfile, 0); // rm temp dir - int rmdir = LLFile::rmdir(mTestConfigDir); + int rmdir = LLFile::remove(mTestConfigDir); ensure_equals("rmdir value", rmdir, 0); } diff --git a/indra/llmessage/tests/message_test.cpp b/indra/llmessage/tests/message_test.cpp old mode 100644 new mode 100755 index 11cd710ef6..6fb2b92803 --- a/indra/llmessage/tests/message_test.cpp +++ b/indra/llmessage/tests/message_test.cpp @@ -113,7 +113,7 @@ namespace tut ensure_equals("rmfile value", rmfile, 0); // rm temp dir - int rmdir = LLFile::rmdir(mTestConfigDir); + int rmdir = LLFile::remove(mTestConfigDir); ensure_equals("rmdir value", rmdir, 0); } diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 1da71e6bf4..7e8d31232b 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1014,7 +1014,6 @@ void LLShaderMgr::initShaderCache(bool enabled, const LLUUID& old_cache_version, mShaderCacheDir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "shader_cache"); LLFile::mkdir(mShaderCacheDir); - { std::string meta_out_path = gDirUtilp->add(mShaderCacheDir, "shaderdata.llsd"); if (gDirUtilp->fileExists(meta_out_path)) @@ -1077,7 +1076,7 @@ void LLShaderMgr::persistShaderCacheMetadata() // Settings and shader cache get saved at different time, thus making // RenderShaderCacheVersion unreliable when running multiple viewer // instances, or for cases where viewer crashes before saving settings. - // Dupplicate version to the cache itself. + // Duplicate version to the cache itself. out["version"] = mShaderCacheVersion; out["shaders"] = LLSD::emptyMap(); LLSD &shaders = out["shaders"]; @@ -1130,11 +1129,11 @@ bool LLShaderMgr::loadCachedProgramBinary(LLGLSLShader* shader) { std::vector in_data; in_data.resize(shader_info.mBinaryLength); - - LLUniqueFile filep = LLFile::fopen(in_path, "rb"); - if (filep) + std::error_code ec; + LLFile filep = LLFile(in_path, LLFile::in | LLFile::binary, ec); + if (!ec && (bool)filep) { - size_t result = fread(in_data.data(), sizeof(U8), in_data.size(), filep); + size_t result = filep.read(in_data.data(), in_data.size(), ec); filep.close(); if (result == in_data.size()) @@ -1179,11 +1178,12 @@ bool LLShaderMgr::saveCachedProgramBinary(LLGLSLShader* shader) if (error == GL_NO_ERROR) { std::string out_path = gDirUtilp->add(mShaderCacheDir, shader->mShaderHash.asString() + ".shaderbin"); - LLUniqueFile outfile = LLFile::fopen(out_path, "wb"); - if (outfile) + std::error_code ec; + LLFile filep = LLFile(out_path, LLFile::out | LLFile::binary, ec); + if (filep) { - fwrite(program_binary.data(), sizeof(U8), program_binary.size(), outfile); - outfile.close(); + filep.write(program_binary.data(), program_binary.size(), ec); + filep.close(); binary_info.mLastUsedTime = (F32)LLTimer::getTotalSeconds(); diff --git a/indra/llxml/tests/llcontrol_test.cpp b/indra/llxml/tests/llcontrol_test.cpp old mode 100644 new mode 100755 index 4192e029c5..e15117fc29 --- a/indra/llxml/tests/llcontrol_test.cpp +++ b/indra/llxml/tests/llcontrol_test.cpp @@ -69,7 +69,7 @@ namespace tut LLFile::remove(filename); } LLFile::remove(mTestConfigFile); - LLFile::rmdir(mTestConfigDir); + LLFile::remove(mTestConfigDir); } void writeSettingsFile(const LLSD& config) { diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp old mode 100644 new mode 100755 index ea380896ca..6058973176 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2267,7 +2267,7 @@ void errorCallback(LLError::ELevel level, const std::string &error_string) LLAppViewer::instance()->writeDebugInfo(); std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); - if (!LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) + if (!LLFile::isfile(error_marker_file)) { // If marker doesn't exist, create a marker with llerror code for next launch // otherwise don't override existing file @@ -3030,13 +3030,11 @@ void LLAppViewer::initStrings() } else { - llstat st; - int rc = LLFile::stat(strings_path_full, &st); - if (rc != 0) + if (!LLFile::exists(strings_path_full)) { - crash_reason = "The file '" + strings_path_full + "' failed to get status. Error code: " + std::to_string(rc); + crash_reason = "The file '" + strings_path_full + "' doesn't seem to exist"; } - else if (S_ISDIR(st.st_mode)) + else if (LLFile::isdir(strings_path_full)) { crash_reason = "The filename '" + strings_path_full + "' is a directory name"; } @@ -3891,7 +3889,7 @@ void LLAppViewer::processMarkerFiles() bool marker_is_same_version = true; // first, look for the marker created at startup and deleted on a clean exit mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME); - if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB)) + if (LLFile::isfile(mMarkerFileName)) { // File exists... // first, read it to see if it was created by the same version (we need this later) @@ -3983,7 +3981,7 @@ void LLAppViewer::processMarkerFiles() // check for any last exec event report based on whether or not it happened during logout // (the logout marker is created when logout begins) std::string logout_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME); - if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB)) + if(LLFile::isfile(logout_marker_file)) { if (markerIsSameVersion(logout_marker_file)) { @@ -3995,11 +3993,11 @@ void LLAppViewer::processMarkerFiles() { LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "' found, but versions did not match" << LL_ENDL; } - LLAPRFile::remove(logout_marker_file); + LLFile::remove(logout_marker_file); } // and last refine based on whether or not a marker created during a non-llerr crash is found std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); - if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) + if(LLFile::isfile(error_marker_file)) { S32 marker_code = getMarkerErrorCode(error_marker_file); if (marker_code >= 0) @@ -4024,7 +4022,7 @@ void LLAppViewer::processMarkerFiles() { LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' marker found, but versions did not match" << LL_ENDL; } - LLAPRFile::remove(error_marker_file); + LLFile::remove(error_marker_file); } #if LL_DARWIN @@ -4051,7 +4049,7 @@ void LLAppViewer::removeMarkerFiles() if (mMarkerFile.getFileHandle()) { mMarkerFile.close() ; - LLAPRFile::remove( mMarkerFileName ); + LLFile::remove( mMarkerFileName ); LL_DEBUGS("MarkerFile") << "removed exec marker '"<getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); - return LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB); + return LLFile::isfile(error_marker_file); } void LLAppViewer::outOfMemorySoftQuit() diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp old mode 100644 new mode 100755 index 425e9e2269..4fa14a199d --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1500,7 +1500,7 @@ bool LLFloaterPreference::moveTranscriptsAndLog() //Couldn't move the log and created a new directory so remove the new directory if(madeDirectory) { - LLFile::rmdir(chatLogPath); + LLFile::remove(chatLogPath); } return false; } @@ -1526,7 +1526,7 @@ bool LLFloaterPreference::moveTranscriptsAndLog() if(madeDirectory) { - LLFile::rmdir(chatLogPath); + LLFile::remove(chatLogPath); } return false; @@ -2031,17 +2031,15 @@ void LLFloaterPreference::changed() { if (LLConversationLog::instance().getIsLoggingEnabled()) { - getChild("clear_log")->setEnabled(LLConversationLog::instance().getConversations().size() > 0); + getChild("clear_log")->setEnabled(LLConversationLog::instance().getConversations().size() > 0); } else { // onClearLog clears list, then notifies changed() and only then clears file, // so check presence of conversations before checking file, file will cleared later. - llstat st; bool has_logs = LLConversationLog::instance().getConversations().size() > 0 - && LLFile::stat(LLConversationLog::instance().getFileName(), &st) == 0 - && S_ISREG(st.st_mode) - && st.st_size > 0; + && LLFile::isfile(LLConversationLog::instance().getFileName()) + && LLFile::size(LLConversationLog::instance().getFileName()) > 0; getChild("clear_log")->setEnabled(has_logs); } diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp old mode 100644 new mode 100755 index c3bc24c6b9..0bf0946c42 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -484,47 +484,47 @@ bool LLFloaterUIPreview::postBuild() bool found_en_us = false; std::string language_directory; std::string xui_dir = get_xui_dir(); // directory containing localizations -- don't forget trailing delim - mLanguageSelection->removeall(); // clear out anything temporarily in list from XML + mLanguageSelection->removeall(); // clear out anything temporarily in list from XML LLDirIterator iter(xui_dir, "*"); - while(found) // for every directory + while (found) // for every directory { - if((found = iter.next(language_directory))) // get next directory + if ((found = iter.next(language_directory))) // get next directory { std::string full_path = gDirUtilp->add(xui_dir, language_directory); - if(LLFile::isfile(full_path.c_str())) // if it's not a directory, skip it + if (!LLFile::isdir(full_path.c_str())) // if it's not a directory, skip it { continue; } - if(strncmp("template",language_directory.c_str(),8) && -1 == language_directory.find(".")) // if it's not the template directory or a hidden directory + if (strncmp("template",language_directory.c_str(), 8) && -1 == language_directory.find(".")) // if it's not the template directory or a hidden directory { - if(!strncmp("en",language_directory.c_str(),5)) // remember if we've seen en, so we can make it default + if (!strncmp("en",language_directory.c_str(), 5)) // remember if we've seen en, so we can make it default { found_en_us = true; } else { - mLanguageSelection->add(std::string(language_directory)); // add it to the language selection dropdown menu + mLanguageSelection->add(std::string(language_directory)); // add it to the language selection dropdown menu mLanguageSelection_2->add(std::string(language_directory)); } } } } - if(found_en_us) + if (found_en_us) { - mLanguageSelection->add(std::string("en"),ADD_TOP); // make en first item if we found it - mLanguageSelection_2->add(std::string("en"),ADD_TOP); + mLanguageSelection->add(std::string("en"), ADD_TOP); // make en first item if we found it + mLanguageSelection_2->add(std::string("en"), ADD_TOP); } else { std::string warning = std::string("No EN localization found; check your XUI directories!"); popupAndPrintWarning(warning); } - mLanguageSelection->selectFirstItem(); // select the first item + mLanguageSelection->selectFirstItem(); // select the first item mLanguageSelection_2->selectFirstItem(); - refreshList(); // refresh the list of available floaters + refreshList(); // refresh the list of available floaters return true; } @@ -892,8 +892,7 @@ void LLFloaterUIPreview::displayFloater(bool click, S32 ID) // Add localization to title so user knows whether it's localized or defaulted to en std::string full_path = getLocalizedDirectory() + path; std::string floater_lang = "EN"; - llstat dummy; - if(!LLFile::stat(full_path.c_str(), &dummy)) // if the file does not exist + if (LLFile::isfile(full_path.c_str())) // use localized language if the file exists { floater_lang = getLocStr(ID); } @@ -966,9 +965,8 @@ void LLFloaterUIPreview::onClickEditFloater() } file_path = getLocalizedDirectory() + file_name; - // stat file to see if it exists (some localized versions may not have it there are no diffs, and then we try to open an nonexistent file) - llstat dummy; - if(LLFile::stat(file_path.c_str(), &dummy)) // if the file does not exist + // Does it exist? (Some localized versions may not have it when there are no diffs, and then we try to open a nonexistent file) + if (!LLFile::isfile(file_path.c_str())) // if the file does not exist { popupAndPrintWarning("No file for this floater exists in the selected localization. Opening the EN version instead."); file_path = get_xui_dir() + mDelim + "en" + mDelim + file_name; // open the en version instead, by default @@ -1117,15 +1115,14 @@ void LLFloaterUIPreview::onClickToggleDiffHighlighting() std::string path_in_textfield = mDiffPathTextBox->getText(); // get file path bool error = false; - if(std::string("") == path_in_textfield) // check for blank file + if(std::string("") == path_in_textfield) // check for blank file { std::string warning = "Unable to highlight differences because no file was provided; fill in the relevant text field"; popupAndPrintWarning(warning); error = true; } - llstat dummy; - if(LLFile::stat(path_in_textfield.c_str(), &dummy) && !error) // check if the file exists (empty check is reduntant but useful for the informative error message) + if (!LLFile::isfile(path_in_textfield.c_str()) && !error) // check if the file exists (empty check is redundant but useful for the informative error message) { std::string warning = std::string("Unable to highlight differences because an invalid path to a difference file was provided:\"") + path_in_textfield + "\""; popupAndPrintWarning(warning); diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp old mode 100644 new mode 100755 index 9a991727b2..4fe661b055 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -575,8 +575,7 @@ void LLPreviewNotecard::syncExternal() { // Sync with external editor. std::string tmp_file = getTmpFileName(); - llstat s; - if (LLFile::stat(tmp_file, &s) == 0) // file exists + if (LLFile::isfile(tmp_file)) // file exists { if (mLiveFile) mLiveFile->ignoreNextUpdate(); writeToFile(tmp_file); diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp old mode 100644 new mode 100755 index c2aa4925bd..2c436198e3 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -694,8 +694,7 @@ void LLScriptEdCore::sync() if (mLiveFile) { std::string tmp_file = mLiveFile->filename(); - llstat s; - if (LLFile::stat(tmp_file, &s) == 0) // file exists + if (LLFile::isfile(tmp_file)) // file exists { mLiveFile->ignoreNextUpdate(); writeToFile(tmp_file); diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp old mode 100644 new mode 100755 index 612af0d147..be6c71ab86 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -180,8 +180,7 @@ private: bool LLTextureCacheLocalFileWorker::doRead() { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - S32 local_size = LLAPRFile::size(mFileName, mCache->getLocalAPRFilePool()); - + S32 local_size = (S32)LLFile::size(mFileName); if (local_size > 0 && mFileName.size() > 4) { mDataSize = local_size; // Only a complete file is valid @@ -210,8 +209,7 @@ bool LLTextureCacheLocalFileWorker::doRead() } mReadData = (U8*)ll_aligned_malloc_16(mDataSize); - S32 bytes_read = LLAPRFile::readEx(mFileName, mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool()); - + S32 bytes_read = (S32)LLFile::read(mFileName, mReadData, mOffset, mDataSize); if (bytes_read != mDataSize) { // LL_WARNS() << "Error reading file from local cache: " << mFileName @@ -296,7 +294,7 @@ bool LLTextureCacheRemoteWorker::doRead() // Is it a JPEG2000 file? { local_filename = filename + ".j2c"; - local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool()); + local_size = (S32)LLFile::size(local_filename); if (local_size > 0) { mImageFormat = IMG_CODEC_J2C; @@ -306,7 +304,7 @@ bool LLTextureCacheRemoteWorker::doRead() if (local_size == 0) { local_filename = filename + ".jpg"; - local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool()); + local_size = (S32)LLFile::size(local_filename); if (local_size > 0) { mImageFormat = IMG_CODEC_JPEG; @@ -317,7 +315,7 @@ bool LLTextureCacheRemoteWorker::doRead() if (local_size == 0) { local_filename = filename + ".tga"; - local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool()); + local_size = (S32)LLFile::size(local_filename); if (local_size > 0) { mImageFormat = IMG_CODEC_TGA; @@ -346,12 +344,10 @@ bool LLTextureCacheRemoteWorker::doRead() if (mReadData) { - S32 bytes_read = LLAPRFile::readEx( local_filename, - mReadData, - mOffset, - mDataSize, - mCache->getLocalAPRFilePool()); - + S32 bytes_read = (S32)LLFile::read(local_filename, + mReadData, + mOffset, + mDataSize); if (bytes_read != mDataSize) { LL_WARNS() << "Error reading file from local cache: " << local_filename @@ -410,8 +406,7 @@ bool LLTextureCacheRemoteWorker::doRead() mReadData = (U8*)ll_aligned_malloc_16(size); if (mReadData) { - S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, - mReadData, offset, size, mCache->getLocalAPRFilePool()); + S32 bytes_read = (S32)LLFile::read(mCache->mHeaderDataFileName, mReadData, offset, size); if (bytes_read != size) { LL_WARNS() << "LLTextureCacheWorker: " << mID @@ -446,9 +441,9 @@ bool LLTextureCacheRemoteWorker::doRead() if (!done && (mState == BODY)) { std::string filename = mCache->getTextureFileName(mID); - S32 filesize = LLAPRFile::size(filename, mCache->getLocalAPRFilePool()); + S32 filesize = (S32)LLFile::size(filename); - if (filesize && (filesize + TEXTURE_CACHE_ENTRY_SIZE) > mOffset) + if (filesize > 0 && (filesize + TEXTURE_CACHE_ENTRY_SIZE) > mOffset) { S32 max_datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize - mOffset; mDataSize = llmin(max_datasize, mDataSize); @@ -487,10 +482,9 @@ bool LLTextureCacheRemoteWorker::doRead() mReadData = data; // Read the data at last - S32 bytes_read = LLAPRFile::readEx(filename, - mReadData + data_offset, - file_offset, file_size, - mCache->getLocalAPRFilePool()); + S32 bytes_read = (S32)LLFile::read(filename, + mReadData + data_offset, + file_offset, file_size); if (bytes_read != file_size) { LL_WARNS() << "LLTextureCacheWorker: " << mID @@ -636,13 +630,13 @@ bool LLTextureCacheRemoteWorker::doWrite() U8* padBuffer = (U8*)ll_aligned_malloc_16(TEXTURE_CACHE_ENTRY_SIZE); memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE); // Init with zeros memcpy(padBuffer, mWriteData, mDataSize); // Copy the write buffer - bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size, mCache->getLocalAPRFilePool()); + bytes_written = (S32)LLFile::write(mCache->mHeaderDataFileName, padBuffer, offset, size); ll_aligned_free_16(padBuffer); } else { // Write the header record (== first TEXTURE_CACHE_ENTRY_SIZE bytes of the raw file) in the header file - bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size, mCache->getLocalAPRFilePool()); + bytes_written = (S32)LLFile::write(mCache->mHeaderDataFileName, mWriteData, offset, size); } if (bytes_written <= 0) @@ -678,15 +672,11 @@ bool LLTextureCacheRemoteWorker::doWrite() else { S32 file_size = mDataSize - TEXTURE_CACHE_ENTRY_SIZE; - { // build the cache file name from the UUID std::string filename = mCache->getTextureFileName(mID); // LL_INFOS() << "Writing Body: " << filename << " Bytes: " << file_offset+file_size << LL_ENDL; - S32 bytes_written = LLAPRFile::writeEx(filename, - mWriteData + TEXTURE_CACHE_ENTRY_SIZE, - 0, file_size, - mCache->getLocalAPRFilePool()); + S32 bytes_written = (S32)LLFile::write(filename, mWriteData + TEXTURE_CACHE_ENTRY_SIZE, 0, file_size); if (bytes_written <= 0) { LL_WARNS() << "LLTextureCacheWorker: " << mID @@ -891,7 +881,7 @@ bool LLTextureCache::isInLocal(const LLUUID& id) // Is it a JPEG2000 file? { local_filename = filename + ".j2c"; - local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool()); + local_size = (S32)LLFile::size(local_filename); if (local_size > 0) { return true ; @@ -901,7 +891,7 @@ bool LLTextureCache::isInLocal(const LLUUID& id) // If not, is it a jpeg file? { local_filename = filename + ".jpg"; - local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool()); + local_size = (S32)LLFile::size(local_filename); if (local_size > 0) { return true ; @@ -911,7 +901,7 @@ bool LLTextureCache::isInLocal(const LLUUID& id) // Hmm... What about a targa file? (used for UI texture mostly) { local_filename = filename + ".tga"; - local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool()); + local_size = (S32)LLFile::size(local_filename); if (local_size > 0) { return true ; @@ -964,11 +954,10 @@ void LLTextureCache::purgeCache(ELLPath location, bool remove_dir) if(LLFile::isdir(mTexturesDirName)) { std::string file_name = gDirUtilp->getExpandedFilename(location, entries_filename); - // mHeaderAPRFilePoolp because we are under header mutex, and can be in main thread - LLAPRFile::remove(file_name, mHeaderAPRFilePoolp); + LLFile::remove(file_name); file_name = gDirUtilp->getExpandedFilename(location, cache_filename); - LLAPRFile::remove(file_name, mHeaderAPRFilePoolp); + LLFile::remove(file_name); purgeAllTextures(true); } @@ -1069,10 +1058,9 @@ void LLTextureCache::readEntriesHeader() { // mHeaderEntriesInfo initializes to default values so safe not to read it llassert_always(mHeaderAPRFile == NULL); - if (LLAPRFile::isExist(mHeaderEntriesFileName, mHeaderAPRFilePoolp)) + if (LLFile::isfile(mHeaderEntriesFileName)) { - LLAPRFile::readEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo), - mHeaderAPRFilePoolp); + LLFile::read(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); } else //create an empty entries header. { @@ -1088,7 +1076,7 @@ void LLTextureCache::setEntriesHeader() // For simplicity we use predefined size of header, so if version string // doesn't fit, either getEngineInfo() returned malformed string or // sHeaderEncoderStringSize need to be increased. - // Also take into accout that c_str() returns additional null character + // Also take into account that c_str() returns additional null character LL_ERRS() << "Version string doesn't fit in header" << LL_ENDL; } @@ -1103,8 +1091,7 @@ void LLTextureCache::writeEntriesHeader() llassert_always(mHeaderAPRFile == NULL); if (!mReadOnly) { - LLAPRFile::writeEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo), - mHeaderAPRFilePoolp); + LLFile::write(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); } } @@ -1208,8 +1195,7 @@ void LLTextureCache::writeEntryToHeaderImmediately(S32& idx, Entry& entry, bool idx = -1 ;//mark the idx invalid. return ; } - - mHeaderAPRFile->seek(APR_SET, offset); + aprfile->seek(APR_SET, offset); } else { @@ -1618,7 +1604,7 @@ void LLTextureCache::purgeAllTextures(bool purge_directories) gDirUtilp->deleteFilesInDir(mTexturesDirName, mask); // headers, fast cache if (purge_directories) { - LLFile::rmdir(mTexturesDirName); + LLFile::remove(mTexturesDirName); } } mHeaderIDMap.clear(); @@ -1798,8 +1784,7 @@ void LLTextureCache::purgeTextures(bool validate) { std::string filename = getTextureFileName(entries[idx].mID); LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mBodySize << LL_ENDL; - // mHeaderAPRFilePoolp because this is under header mutex in main thread - S32 bodysize = LLAPRFile::size(filename, mHeaderAPRFilePoolp); + S32 bodysize = (S32)LLFile::size(filename); if (bodysize != entries[idx].mBodySize) { LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mBodySize << filename << LL_ENDL; @@ -2150,7 +2135,7 @@ void LLTextureCache::openFastCache(bool first_time) mFastCachePadBuffer = (U8*)ll_aligned_malloc_16(TEXTURE_FAST_CACHE_ENTRY_SIZE); } mFastCachePoolp = new LLVolatileAPRPool(); // is_local= true by default, so not thread safe by default - if (LLAPRFile::isExist(mFastCacheFileName, mFastCachePoolp)) + if (LLFile::isfile(mFastCacheFileName)) { mFastCachep = new LLAPRFile(mFastCacheFileName, APR_READ|APR_WRITE|APR_BINARY, mFastCachePoolp) ; } @@ -2233,9 +2218,7 @@ void LLTextureCache::removeCachedTexture(const LLUUID& id) mTexturesSizeMap.erase(id); } mHeaderIDMap.erase(id); - // We are inside header's mutex so mHeaderAPRFilePoolp is safe to use, - // but getLocalAPRFilePool() is not safe, it might be in use by worker - LLAPRFile::remove(getTextureFileName(id), mHeaderAPRFilePoolp); + LLFile::remove(getTextureFileName(id)); } //called after mHeaderMutex is locked. @@ -2248,9 +2231,7 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename) if (entry.mBodySize == 0) // Always attempt to remove when mBodySize > 0. { // Sanity check. Shouldn't exist when body size is 0. - // We are inside header's mutex so mHeaderAPRFilePoolp is safe to use, - // but getLocalAPRFilePool() is not safe, it might be in use by worker - if (LLAPRFile::isExist(filename, mHeaderAPRFilePoolp)) + if (LLFile::isfile(filename)) { LL_WARNS("TextureCache") << "Entry has body size of zero but file " << filename << " exists. Deleting this file, too." << LL_ENDL; } @@ -2270,7 +2251,7 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename) if (file_maybe_exists) { - LLAPRFile::remove(filename, mHeaderAPRFilePoolp); + LLFile::remove(filename); } } diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index 141f370ecb..e76d340eda 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -182,7 +182,7 @@ void LLViewerAssetStorage::storeAssetData( else { // LLAssetStorage metric: Successful Request - S32 size = LLFileSystem::getFileSize(asset_id, asset_type); + S32 size = (S32)LLFileSystem::getFileSize(asset_id, asset_type); const char *message = "Added to upload queue"; reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, size, MR_OKAY, __FILE__, __LINE__, message ); diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index 65a69acc88..5ac7d6b1fe 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -45,11 +45,7 @@ #include "llappviewer.h" #include "llviewerstats.h" #include "llfilesystem.h" -#include "llgesturemgr.h" -#include "llpreviewnotecard.h" -#include "llpreviewgesture.h" #include "llcoproceduremanager.h" -#include "llthread.h" #include "llkeyframemotion.h" #include "lldatapacker.h" #include "llvoavatarself.h" @@ -405,6 +401,7 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() std::string errorMessage; std::string errorLabel; + std::error_code ec; bool error = false; @@ -475,30 +472,38 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() error = true; // read from getFileName() - LLAPRFile infile; - infile.open(getFileName(),LL_APR_RB); - if (!infile.getFileHandle()) + LLFile infile(getFileName(), LLFile::in | LLFile::binary, ec); + if (ec || !infile) { LL_WARNS() << "Couldn't open file for reading: " << getFileName() << LL_ENDL; errorMessage = llformat("Failed to open animation file %s\n", getFileName().c_str()); } else { - S32 size = LLAPRFile::size(getFileName()); + S64 size = infile.size(ec); + if (ec || size <= 0) + { + LLError::LLUserWarningMsg::showMissingFiles(); + LL_ERRS() << "Invalid file" << LL_ENDL; + } + else if (size > INT_MAX) + { + LL_ERRS() << "File is too big, size: " << size << LL_ENDL; + } U8* buffer = new(std::nothrow) U8[size]; if (!buffer) { LLError::LLUserWarningMsg::showOutOfMemory(); LL_ERRS() << "Bad memory allocation for buffer, size: " << size << LL_ENDL; } - S32 size_read = infile.read(buffer,size); - if (size_read != size) + S64 size_read = infile.read(buffer, size, ec); + if (ec || size_read != size) { errorMessage = llformat("Failed to read animation file %s: wanted %d bytes, got %d\n", getFileName().c_str(), size, size_read); } else { - LLDataPackerBinaryBuffer dp(buffer, size); + LLDataPackerBinaryBuffer dp(buffer, (S32)size); LLKeyframeMotion *motionp = new LLKeyframeMotion(getAssetId()); motionp->setCharacter(gAgentAvatarp); if (motionp->deserialize(dp, getAssetId(), false)) @@ -544,18 +549,17 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() setAssetType(assetType); // copy this file into the cache for upload - S32 file_size; - LLAPRFile infile; - infile.open(filename, LL_APR_RB, NULL, &file_size); - if (infile.getFileHandle()) + LLFile infile(filename, LLFile::in | LLFile::binary, ec); + if (!ec && infile.size(ec) > 0) { LLFileSystem file(getAssetId(), assetType, LLFileSystem::APPEND); + S64 read_bytes; const S32 buf_size = 65536; U8 copy_buf[buf_size]; - while ((file_size = infile.read(copy_buf, buf_size))) + while (((read_bytes = infile.read(copy_buf, buf_size, ec))) > 0) { - file.write(copy_buf, file_size); + file.write(copy_buf, (S32)read_bytes); } } else @@ -569,7 +573,6 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() } return LLSD(); - } //========================================================================= diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp old mode 100644 new mode 100755 index ce59e844ec..5ad3344a6e --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1139,15 +1139,12 @@ std::string getProfileStatsFilename() // same second), may produce (e.g.) sec==61, but avoids collisions and // preserves chronological filename sort order. std::string name; - std::error_code ec; do { // base + missing 2-digit seconds, append ".json" // post-increment sec in case we have to try again name = stringize(base, std::setw(2), std::setfill('0'), sec++, ".json"); - } while (std::filesystem::exists(fsyspath(name), ec)); - // Ignoring ec means we might potentially return a name that does already - // exist -- but if we can't check its existence, what more can we do? + } while (LLFile::exists(fsyspath(name))); return name; } diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp old mode 100644 new mode 100755 index 071a66209b..a8eaadc426 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1833,12 +1833,11 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ user_data_path_cache += gDirUtilp->getDirDelimiter(); // See if the plugin executable exists - llstat s; - if(LLFile::stat(launcher_name, &s)) + if (!LLFile::isfile(launcher_name)) { LL_WARNS_ONCE("Media") << "Couldn't find launcher at " << launcher_name << LL_ENDL; } - else if(LLFile::stat(plugin_name, &s)) + else if (!LLFile::isfile(plugin_name)) { LL_WARNS_ONCE("Media") << "Couldn't find plugin at " << plugin_name << LL_ENDL; } diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp old mode 100644 new mode 100755 index 5d456b1a19..cdc41baa88 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -1250,7 +1250,7 @@ void LLVOCache::removeCache(ELLPath location, bool started) std::string cache_dir = gDirUtilp->getExpandedFilename(location, object_cache_dirname); LL_INFOS() << "Removing cache at " << cache_dir << LL_ENDL; gDirUtilp->deleteFilesInDir(cache_dir, mask); //delete all files - LLFile::rmdir(cache_dir); + LLFile::remove(cache_dir); clearCacheInMemory(); mInitialized = false; @@ -1370,7 +1370,7 @@ void LLVOCache::removeFromCache(HeaderEntryInfo* entry) std::string filename; getObjectCacheFilename(entry->mHandle, filename); LL_WARNS("GLTF", "VOCache") << "Removing object cache for handle " << entry->mHandle << "Filename: " << filename << LL_ENDL; - LLAPRFile::remove(filename, mLocalAPRFilePoolp); + LLFile::remove(filename); // Note: `removeFromCache` should take responsibility for cleaning up all cache artefacts specfic to the handle/entry. // as such this now includes the generic extras @@ -1394,7 +1394,7 @@ void LLVOCache::readCacheHeader() clearCacheInMemory(); bool success = true ; - if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp)) + if (LLFile::isfile(mHeaderFileName)) { LLAPRFile apr_file(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp); diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp old mode 100644 new mode 100755 index d132cbfa36..e58a6577f1 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -943,8 +943,7 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() gDirUtilp->append(exe_path, "SLVoice"); #endif // See if the vivox executable exists - llstat s; - if (!LLFile::stat(exe_path, &s)) + if (LLFile::isfile(exe_path)) { // vivox executable exists. Build the command line and launch the daemon. LLProcess::Params params; -- cgit v1.3 From b74a3c25d16685b8dfad8880e20ac99c5769d2e4 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Mon, 5 Jan 2026 22:33:33 +0200 Subject: #4899 Fix permissions flags on files that shouldn't be executable --- indra/llcommon/llerror.cpp | 0 indra/llfilesystem/lldir_win32.cpp | 0 indra/llfilesystem/tests/lldir_test.cpp | 0 indra/llmessage/tests/llmessageconfig_test.cpp | 0 indra/llmessage/tests/message_test.cpp | 0 indra/llxml/tests/llcontrol_test.cpp | 0 indra/newview/llpreviewnotecard.cpp | 0 indra/newview/llpreviewscript.cpp | 0 indra/newview/llviewerdisplay.cpp | 0 indra/newview/llviewermedia.cpp | 0 indra/newview/llvoicevivox.cpp | 0 11 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 indra/llcommon/llerror.cpp mode change 100755 => 100644 indra/llfilesystem/lldir_win32.cpp mode change 100755 => 100644 indra/llfilesystem/tests/lldir_test.cpp mode change 100755 => 100644 indra/llmessage/tests/llmessageconfig_test.cpp mode change 100755 => 100644 indra/llmessage/tests/message_test.cpp mode change 100755 => 100644 indra/llxml/tests/llcontrol_test.cpp mode change 100755 => 100644 indra/newview/llpreviewnotecard.cpp mode change 100755 => 100644 indra/newview/llpreviewscript.cpp mode change 100755 => 100644 indra/newview/llviewerdisplay.cpp mode change 100755 => 100644 indra/newview/llviewermedia.cpp mode change 100755 => 100644 indra/newview/llvoicevivox.cpp (limited to 'indra/llxml') diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp old mode 100755 new mode 100644 diff --git a/indra/llfilesystem/lldir_win32.cpp b/indra/llfilesystem/lldir_win32.cpp old mode 100755 new mode 100644 diff --git a/indra/llfilesystem/tests/lldir_test.cpp b/indra/llfilesystem/tests/lldir_test.cpp old mode 100755 new mode 100644 diff --git a/indra/llmessage/tests/llmessageconfig_test.cpp b/indra/llmessage/tests/llmessageconfig_test.cpp old mode 100755 new mode 100644 diff --git a/indra/llmessage/tests/message_test.cpp b/indra/llmessage/tests/message_test.cpp old mode 100755 new mode 100644 diff --git a/indra/llxml/tests/llcontrol_test.cpp b/indra/llxml/tests/llcontrol_test.cpp old mode 100755 new mode 100644 diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp old mode 100755 new mode 100644 diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp old mode 100755 new mode 100644 diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp old mode 100755 new mode 100644 diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp old mode 100755 new mode 100644 diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp old mode 100755 new mode 100644 -- cgit v1.3 From 25dc8660efedecfd9f021142ac1e4ff3639e80d4 Mon Sep 17 00:00:00 2001 From: Rye Date: Tue, 30 Dec 2025 11:39:16 -0500 Subject: Clean up LLFile and LLFilesystem operations to reduce temporaries allocations and utf8->utf16 conversions Fix LLFile::tmpdir failing when temp directory is located in a unicode path on windows Add Tracy profiler tagging to LLFile that's disabled by default Replace LLFile::utf8StringToWstring with our fsyspath std::filesystem::path adapter Introduce std::filesystem::path to llifstream/llofstream wrappers Add move operators to fsyspath to match copy operator Restore LLUniqueFile RAII class for direct c file io wrapping and reducing merge conflicts with downstream code that may depend upon it Signed-off-by: Rye --- indra/llappearance/llpolymesh.cpp | 2 +- indra/llcommon/fsyspath.h | 4 +- indra/llcommon/llcrc.cpp | 2 +- indra/llcommon/llcrc.h | 2 +- indra/llcommon/llfile.cpp | 290 +++++++---------- indra/llcommon/llfile.h | 465 +++++++++++++++++++++++----- indra/llcommon/llprocessor.cpp | 4 +- indra/llcommon/llprofilercategories.h | 9 + indra/llcommon/llsys.cpp | 6 +- indra/llcommon/tests/llfile_test.cpp | 115 ++++--- indra/llfilesystem/lldir.cpp | 15 +- indra/llfilesystem/lldir.h | 2 +- indra/llfilesystem/lldir_linux.cpp | 18 -- indra/llfilesystem/lldir_linux.h | 1 - indra/llfilesystem/lldir_mac.cpp | 8 - indra/llfilesystem/lldir_mac.h | 1 - indra/llfilesystem/lldir_win32.cpp | 7 - indra/llfilesystem/lldir_win32.h | 1 - indra/llfilesystem/llfilesystem.cpp | 81 ++--- indra/llfilesystem/llfilesystem.h | 5 +- indra/llfilesystem/tests/lldir_test.cpp | 2 +- indra/llimage/llimagedimensionsinfo.cpp | 2 +- indra/llimage/llimagetga.cpp | 2 +- indra/llmessage/llassetstorage.cpp | 2 +- indra/llmessage/lltransfersourcefile.cpp | 2 +- indra/llmessage/lltransfertargetfile.cpp | 2 +- indra/llmessage/llxfer_file.cpp | 16 +- indra/llmessage/message.cpp | 4 +- indra/llmessage/tests/lldatapacker_test.cpp | 4 +- indra/llrender/llshadermgr.cpp | 4 +- indra/llui/lluicolortable.cpp | 2 +- indra/llui/llxuiparser.cpp | 6 +- indra/llxml/llcontrol.cpp | 2 +- indra/llxml/llxmlparser.cpp | 4 +- indra/newview/llconversationlog.cpp | 4 +- indra/newview/lldrawpoolbump.cpp | 2 +- indra/newview/llfloaterpreference.cpp | 10 +- indra/newview/llfloateruipreview.cpp | 2 +- indra/newview/llinventorymodel.cpp | 4 +- indra/newview/llkeyconflict.cpp | 2 +- indra/newview/lllogchat.cpp | 12 +- indra/newview/llmutelist.cpp | 8 +- indra/newview/llpreviewnotecard.cpp | 4 +- indra/newview/llpreviewscript.cpp | 4 +- indra/newview/llstartup.cpp | 6 +- indra/newview/lltoolbarview.cpp | 2 +- indra/newview/llviewerassetstorage.cpp | 4 +- indra/newview/llviewerinput.cpp | 2 +- indra/newview/llviewermenufile.cpp | 2 +- indra/newview/llviewerstatsrecorder.cpp | 2 +- 50 files changed, 678 insertions(+), 484 deletions(-) (limited to 'indra/llxml') diff --git a/indra/llappearance/llpolymesh.cpp b/indra/llappearance/llpolymesh.cpp index d5323e0b84..b579dc007b 100644 --- a/indra/llappearance/llpolymesh.cpp +++ b/indra/llappearance/llpolymesh.cpp @@ -280,7 +280,7 @@ bool LLPolyMeshSharedData::loadMesh( const std::string& fileName ) LL_ERRS() << "Filename is Empty!" << LL_ENDL; return false; } - LLFILE* fp = LLFile::fopen(fileName, "rb"); /*Flawfinder: ignore*/ + LLFILE* fp = LLFile::fopen(fileName, TEXT("rb")); /*Flawfinder: ignore*/ if (!fp) { LLError::LLUserWarningMsg::showMissingFiles(); diff --git a/indra/llcommon/fsyspath.h b/indra/llcommon/fsyspath.h index 2c900c02a7..237d99ae86 100644 --- a/indra/llcommon/fsyspath.h +++ b/indra/llcommon/fsyspath.h @@ -57,7 +57,7 @@ class fsyspath: public std::filesystem::path public: // default - fsyspath() {} + fsyspath() = default; // construct from UTF-8 encoded string fsyspath(const std::string& path): fsyspath(std::string_view(path)) {} fsyspath(const char* path): fsyspath(std::string_view(path)) {} @@ -66,8 +66,10 @@ public: {} // construct from existing path fsyspath(const super& path): super(path) {} + fsyspath(super&& path) : super(std::move(path)) {} fsyspath& operator=(const super& p) { super::operator=(p); return *this; } + fsyspath& operator=(super&& p) { super::operator=(std::move(p)); return *this; } fsyspath& operator=(const std::string& p) { return (*this) = std::string_view(p); } fsyspath& operator=(const char* p) { return (*this) = std::string_view(p); } fsyspath& operator=(std::string_view p) diff --git a/indra/llcommon/llcrc.cpp b/indra/llcommon/llcrc.cpp index d79d06e2a2..f836a12c35 100644 --- a/indra/llcommon/llcrc.cpp +++ b/indra/llcommon/llcrc.cpp @@ -166,7 +166,7 @@ void LLCRC::update(const std::string& filename) return; } - FILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ + FILE* fp = LLFile::fopen(filename, TEXT("rb")); /* Flawfinder: ignore */ if (fp) { diff --git a/indra/llcommon/llcrc.h b/indra/llcommon/llcrc.h index a3bde47780..cbf4cf4e75 100644 --- a/indra/llcommon/llcrc.h +++ b/indra/llcommon/llcrc.h @@ -36,7 +36,7 @@ // example (don't try this at work kids): // // LLCRC crc; -// FILE* fp = LLFile::fopen(filename,"rb"); +// FILE* fp = LLFile::fopen(filename,TEXT("rb")); // while(!feof(fp)) { // crc.update(fgetc(fp)); // } diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index 0ceb2eb03b..114df29f6e 100755 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -226,7 +226,7 @@ static void find_locking_process(const std::string& filename) } #endif // LL_WINDOWS hack to identify processes holding file open -static int warnif(std::string_view desc, const std::string& filename, int rc, int suppress_warning = 0) +static int warnif(std::string_view desc, const std::filesystem::path& filename, int rc, int suppress_warning = 0) { if (rc < 0) { @@ -252,7 +252,7 @@ static int warnif(std::string_view desc, const std::string& filename, int rc, in return rc; } -static int warnif(std::string_view desc, const std::string& filename, const std::error_code& ec, int suppress_warning = 0) +static int warnif(std::string_view desc, const std::filesystem::path& filename, const std::error_code& ec, int suppress_warning = 0) { if (ec) { @@ -506,8 +506,9 @@ inline bool are_open_mode_flags_invalid(std::ios_base::openmode omode) //---------------------------------------------------------------------------------------- // class member functions //---------------------------------------------------------------------------------------- -int LLFile::open(const std::string& filename, std::ios_base::openmode omode, std::error_code& ec, int perm) +int LLFile::open(const std::filesystem::path& file_path, std::ios_base::openmode omode, std::error_code& ec, int perm) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; close(ec); if (are_open_mode_flags_invalid(omode)) { @@ -519,14 +520,13 @@ int LLFile::open(const std::string& filename, std::ios_base::openmode omode, std create = decode_open_create_flags(omode), attributes = decode_attributes(omode, perm); - std::wstring file_path = utf8StringToWstring(filename); - mHandle = CreateFileW(file_path.c_str(), access, share, nullptr, create, attributes, nullptr); + mHandle = CreateFileW(file_path.native().c_str(), access, share, nullptr, create, attributes, nullptr); // The dwShareMode = share parameter takes care of locking the file for other processes if indicated, // no need to do anything else for file locking here #else int oflags = decode_open_mode(omode); int lmode = omode & LLFile::lock_mask; - mHandle = ::open(filename.c_str(), oflags, perm); + mHandle = ::open(file_path.native().c_str(), oflags, perm); if (mHandle != InvalidHandle && lmode && lock(lmode | LLFile::noblock, ec) != 0) { close(); @@ -549,6 +549,7 @@ int LLFile::open(const std::string& filename, std::ios_base::openmode omode, std S64 LLFile::size(std::error_code& ec) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; #if LL_WINDOWS LARGE_INTEGER value = { 0 }; if (GetFileSizeEx(mHandle, &value)) @@ -570,6 +571,7 @@ S64 LLFile::size(std::error_code& ec) S64 LLFile::tell(std::error_code& ec) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; #if LL_WINDOWS LARGE_INTEGER value = { 0 }; if (SetFilePointerEx(mHandle, value, &value, FILE_CURRENT)) @@ -595,6 +597,7 @@ int LLFile::seek(S64 pos, std::error_code& ec) int LLFile::seek(S64 offset, std::ios_base::seekdir dir, std::error_code& ec) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; S64 newOffset = 0; #if LL_WINDOWS DWORD seekdir = seek_mode_from_dir(dir); @@ -620,6 +623,7 @@ inline DWORD next_buffer_size(S64 nbytes) S64 LLFile::read(void* buffer, S64 nbytes, std::error_code& ec) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; if (nbytes == 0) { // Nothing to do @@ -660,6 +664,7 @@ S64 LLFile::read(void* buffer, S64 nbytes, std::error_code& ec) S64 LLFile::write(const void* buffer, S64 nbytes, std::error_code& ec) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; if (nbytes == 0) { // Nothing to do here @@ -705,6 +710,7 @@ S64 LLFile::write(const void* buffer, S64 nbytes, std::error_code& ec) S64 LLFile::printf(const char* fmt, ...) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; va_list args1; va_start(args1, fmt); va_list args2; @@ -732,6 +738,7 @@ S64 LLFile::printf(const char* fmt, ...) int LLFile::lock(int mode, std::error_code& ec) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; #if LL_WINDOWS if (!(mode & LLFile::lock_mask)) { @@ -765,6 +772,7 @@ int LLFile::lock(int mode, std::error_code& ec) int LLFile::close(std::error_code& ec) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; if (mHandle != InvalidHandle) { llfile_handle_t handle = InvalidHandle; @@ -792,8 +800,9 @@ int LLFile::close() //---------------------------------------------------------------------------------------- // static -LLFILE* LLFile::fopen(const std::string& filename, const char* mode, int lmode) +LLFILE* LLFile::fopen(const std::filesystem::path& file_path, const fopen_flags_t* mode, int lmode) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; LLFILE* file; #if LL_WINDOWS int shflag = _SH_DENYNO; @@ -806,11 +815,9 @@ LLFILE* LLFile::fopen(const std::string& filename, const char* mode, int lmode) shflag = _SH_DENYWR; break; } - std::wstring file_path = utf8StringToWstring(filename); - std::wstring utf16mode = ll_convert(std::string(mode)); - file = _wfsopen(file_path.c_str(), utf16mode.c_str(), shflag); + file = _wfsopen(file_path.native().c_str(), mode, shflag); #else - file = ::fopen(filename.c_str(), mode); + file = ::fopen(file_path.native().c_str(), mode); if (file && (lmode & (LLFile::lock_mask))) { // Rather fail on a sharing conflict than block @@ -827,6 +834,7 @@ LLFILE* LLFile::fopen(const std::string& filename, const char* mode, int lmode) // static int LLFile::close(LLFILE* file) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; int ret_value = 0; if (file) { @@ -836,17 +844,11 @@ int LLFile::close(LLFILE* file) } // static -std::string LLFile::getContents(const std::string& filename) -{ - std::error_code ec; - return getContents(filename, ec); -} - -// static -std::string LLFile::getContents(const std::string& filename, std::error_code& ec) +std::string LLFile::getContents(const std::filesystem::path& file_path, std::error_code& ec) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; std::string buffer; - LLFile file(filename, LLFile::in | LLFile::binary, ec); + LLFile file(file_path, LLFile::in | LLFile::binary, ec); if (file) { S64 length = file.size(ec); @@ -864,48 +866,41 @@ std::string LLFile::getContents(const std::string& filename, std::error_code& ec } // static -int LLFile::mkdir(const std::string& dirname) +int LLFile::mkdir(const std::filesystem::path& file_path) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; std::error_code ec; - std::filesystem::path file_path = utf8StringToPath(dirname); // We often use mkdir() to ensure the existence of a directory that might // already exist. There is no known case in which we want to call out as // an error the requested directory already existing. std::filesystem::create_directory(file_path, ec); // The return value is only true if the directory was actually created. // But if it already existed, ec still indicates success. - return warnif("mkdir", dirname, ec); + return warnif("mkdir", file_path, ec); } // static -int LLFile::remove(const std::string& filename, int suppress_warning) +int LLFile::remove(const std::filesystem::path& file_path, int suppress_warning) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; std::error_code ec; - std::filesystem::path file_path = utf8StringToPath(filename); std::filesystem::remove(file_path, ec); - return warnif("remove", filename, ec, suppress_warning); + return warnif("remove", file_path, ec, suppress_warning); } // static -int LLFile::rename(const std::string& filename, const std::string& newname, int suppress_warning) +int LLFile::rename(const std::filesystem::path& file_path, const std::filesystem::path& new_path, int suppress_warning) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; std::error_code ec; - std::filesystem::path file_path = utf8StringToPath(filename); - std::filesystem::path new_path = utf8StringToPath(newname); std::filesystem::rename(file_path, new_path, ec); - return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, ec, suppress_warning); -} - -// static -S64 LLFile::read(const std::string& filename, void* buf, S64 offset, S64 nbytes) -{ - std::error_code ec; - return read(filename, buf, offset, nbytes, ec); + return warnif("rename", file_path, ec, suppress_warning); } // static -S64 LLFile::read(const std::string& filename, void* buf, S64 offset, S64 nbytes, std::error_code& ec) +S64 LLFile::read(const std::filesystem::path& file_path, void* buf, S64 offset, S64 nbytes, std::error_code& ec) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; // if number of bytes is 0 or less there is nothing to do here if (nbytes <= 0) { @@ -921,7 +916,7 @@ S64 LLFile::read(const std::string& filename, void* buf, S64 offset, S64 nbytes, { std::ios_base::openmode omode = LLFile::in | LLFile::binary; - LLFile file(filename, omode, ec); + LLFile file(file_path, omode, ec); if (!ec && (bool)file) { if (offset > 0) @@ -939,19 +934,13 @@ S64 LLFile::read(const std::string& filename, void* buf, S64 offset, S64 nbytes, } } } - return warnif("read from file failed", filename, ec); + return warnif("read from file failed", file_path, ec); } // static -S64 LLFile::write(const std::string& filename, const void* buf, S64 offset, S64 nbytes) -{ - std::error_code ec; - return write(filename, buf, offset, nbytes, ec); -} - -// static -S64 LLFile::write(const std::string& filename, const void* buf, S64 offset, S64 nbytes, std::error_code& ec) +S64 LLFile::write(const std::filesystem::path& file_path, const void* buf, S64 offset, S64 nbytes, std::error_code& ec) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; // if number of bytes is 0 or less there is nothing to do here if (nbytes <= 0) { @@ -971,7 +960,7 @@ S64 LLFile::write(const std::string& filename, const void* buf, S64 offset, S64 omode |= LLFile::app; } - LLFile file(filename, omode, ec); + LLFile file(file_path, omode, ec); if (!ec && (bool)file) { if (offset > 0) @@ -989,99 +978,52 @@ S64 LLFile::write(const std::string& filename, const void* buf, S64 offset, S64 } } } - return warnif("write to file failed", filename, ec); + return warnif("write to file failed", file_path, ec); } // static -bool LLFile::copy(const std::string& source, const std::string& target) +bool LLFile::copy(const std::filesystem::path& source_path, const std::filesystem::path& target_path, std::filesystem::copy_options options, std::error_code& ec) { - std::error_code ec; - return copy(source, target, std::filesystem::copy_options::overwrite_existing, ec); -} - -// static -bool LLFile::copy(const std::string& source, const std::string& target, std::filesystem::copy_options options, std::error_code& ec) -{ - std::filesystem::path source_path = utf8StringToPath(source); - std::filesystem::path target_path = utf8StringToPath(target); + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; bool copied = std::filesystem::copy_file(source_path, target_path, options, ec); if (!copied) { - warnif(STRINGIZE("copy failed, to '" << target << "' from"), source, ec); + warnif(STRINGIZE("copy failed, to '" << target_path << "' from"), source_path, ec); } return copied; } // static -int LLFile::stat(const std::string& filename, llstat* filestatus, const char *fname, int suppress_warning) +int LLFile::stat(const std::filesystem::path& file_path, llstat* filestatus, const char *fname, int suppress_warning) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; #if LL_WINDOWS - std::wstring file_path = utf8StringToWstring(filename); - int rc = _wstat64(file_path.c_str(), filestatus); + int rc = _wstat64(file_path.native().c_str(), filestatus); #else - int rc = ::stat(filename.c_str(), filestatus); + int rc = ::stat(file_path.native().c_str(), filestatus); #endif - return warnif(fname ? fname : "stat", filename, rc, suppress_warning); + return warnif(fname ? fname : "stat", file_path, rc, suppress_warning); } // static -std::time_t LLFile::getCreationTime(const std::string& filename, int suppress_warning) -{ - // As of C++20 there is no functionality in std::filesystem to retrieve this information - llstat filestat; - int rc = stat(filename, &filestat, "getCreationTime", suppress_warning); - if (rc == 0) - { -#if LL_DARWIN - return filestat.st_birthtime; -#else - // Linux stat() doesn't have a creation/birth time (st_ctime really is the last status - // change or inode attributes change) unless we would use statx() instead. But that is - // a major effort, which would require Linux specific changes to LLFile::stat() above - // and possibly adaptions for other platforms that we leave for a later exercise if it - // is ever desired. - return filestat.st_ctime; -#endif - } - return 0; -} - -// static -std::time_t LLFile::getModificationTime(const std::string& filename, int suppress_warning) -{ - // tried to use std::filesystem::last_write_time() but the whole std::chrono infrastructure is as of - // C++20 still not fully implemented on all platforms. Specifically MacOS C++20 seems lacking here, - // and Windows requires a roundabout through std::chrono::utc_clock to then get a - // std::chrono::system_clock that can return a more useful time_t. - // So we take the easy way out in a similar way as with getCreationTime(). - llstat filestat; - int rc = stat(filename, &filestat, "getModificationTime", suppress_warning); - if (rc == 0) - { - return filestat.st_mtime; - } - return 0; -} - -// static -S64 LLFile::size(const std::string& filename, int suppress_warning) +S64 LLFile::size(const std::filesystem::path& file_path, int suppress_warning) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; std::error_code ec; - std::filesystem::path file_path = utf8StringToPath(filename); std::intmax_t size = static_cast(std::filesystem::file_size(file_path, ec)); if (ec) { - warnif("size", filename, ec, suppress_warning); + warnif("size", file_path, ec, suppress_warning); return 0; } return size; } // static -std::filesystem::file_status LLFile::getStatus(const std::string& filename, bool dontFollowSymLink, int suppress_warning) +std::filesystem::file_status LLFile::getStatus(const std::filesystem::path& file_path, bool dontFollowSymLink, int suppress_warning) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; std::error_code ec; - std::filesystem::path file_path = utf8StringToPath(filename); std::filesystem::file_status status; if (dontFollowSymLink) { @@ -1091,100 +1033,43 @@ std::filesystem::file_status LLFile::getStatus(const std::string& filename, bool { status = std::filesystem::status(file_path, ec); } - warnif("getStatus()", filename, ec, suppress_warning); + warnif("getStatus()", file_path, ec, suppress_warning); return status; } -// static -bool LLFile::exists(const std::string& filename) -{ - std::filesystem::file_status status = getStatus(filename); - return std::filesystem::exists(status); -} - -// static -bool LLFile::isdir(const std::string& filename) -{ - std::filesystem::file_status status = getStatus(filename); - return std::filesystem::is_directory(status); -} - -// static -bool LLFile::isfile(const std::string& filename) -{ - std::filesystem::file_status status = getStatus(filename); - return std::filesystem::is_regular_file(status); -} - -// static -bool LLFile::islink(const std::string& filename) -{ - std::filesystem::file_status status = getStatus(filename, true); - return std::filesystem::is_symlink(status); -} - // static const std::string& LLFile::tmpdir() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE; static std::string temppath; if (temppath.empty()) { - temppath = std::filesystem::temp_directory_path().string(); - } - #if LL_WINDOWS - char sep = '\\'; + temppath = ll_convert(std::filesystem::temp_directory_path().native()); + char sep = '\\'; #else - char sep = '/'; + temppath = std::filesystem::temp_directory_path().string(); + char sep = '/'; #endif - if (temppath[temppath.size() - 1] != sep) - { - temppath += sep; + if (temppath[temppath.size() - 1] != sep) + { + temppath += sep; + } } + return temppath; } -// static -std::filesystem::path LLFile::utf8StringToPath(const std::string& pathname) -{ #if LL_WINDOWS - return ll_convert(pathname); -#else - return pathname; -#endif -} -#if LL_WINDOWS +/************** input file stream ********************************/ -// static -std::wstring LLFile::utf8StringToWstring(const std::string& pathname) +// explicit +llifstream::llifstream(const char* _Filename, ios_base::openmode _Mode) : + std::ifstream(ll_convert(_Filename).c_str(), _Mode | ios_base::in) { - std::wstring utf16string(ll_convert(pathname)); - if (utf16string.size() >= MAX_PATH) - { - // By going through std::filesystem::path we get a lot of path sanitation done for us that - // is needed when passing a path with a kernel object space prefix to Windows API functions - // since this prefix disables the kernel32 path normalization - std::filesystem::path utf16path(utf16string); - - // By prepending "\\?\" to a path, Windows widechar file APIs will not fail on long path names - utf16string.assign(L"\\\\?\\").append(utf16path); - - /* remove trailing spaces and dots (yes, Windows really does that) */ - size_t last_valid = utf16string.find_last_not_of(L" \t."); - if (last_valid == std::wstring::npos) - { - return std::wstring(); - } - return utf16string.substr(0, last_valid + 1); - } - return utf16string; } -/************** input file stream ********************************/ - -llifstream::llifstream() {} - // explicit llifstream::llifstream(const std::string& _Filename, ios_base::openmode _Mode): std::ifstream(ll_convert( _Filename ).c_str(), @@ -1192,15 +1077,37 @@ llifstream::llifstream(const std::string& _Filename, ios_base::openmode _Mode): { } +// explicit +llifstream::llifstream(const std::filesystem::path& _Filepath, ios_base::openmode _Mode) : + std::ifstream(_Filepath, _Mode | ios_base::in) +{ +} + +void llifstream::open(const char* _Filename, ios_base::openmode _Mode) +{ + std::ifstream::open(ll_convert(_Filename).c_str(), + _Mode | ios_base::in); +} + void llifstream::open(const std::string& _Filename, ios_base::openmode _Mode) { std::ifstream::open(ll_convert(_Filename).c_str(), _Mode | ios_base::in); } +void llifstream::open(const std::filesystem::path& _Filepath, ios_base::openmode _Mode) +{ + std::ifstream::open(_Filepath, + _Mode | ios_base::in); +} + /************** output file stream ********************************/ -llofstream::llofstream() {} +// explicit +llofstream::llofstream(const char* _Filename, ios_base::openmode _Mode) : + std::ofstream(ll_convert(_Filename).c_str(), _Mode | ios_base::out) +{ +} // explicit llofstream::llofstream(const std::string& _Filename, ios_base::openmode _Mode): @@ -1209,10 +1116,27 @@ llofstream::llofstream(const std::string& _Filename, ios_base::openmode _Mode): { } +// explicit +llofstream::llofstream(const std::filesystem::path& _Filepath, ios_base::openmode _Mode) : + std::ofstream(_Filepath, _Mode | ios_base::out) +{ +} + +void llofstream::open(const char* _Filename, ios_base::openmode _Mode) +{ + std::ofstream::open(ll_convert(_Filename).c_str(), _Mode | ios_base::out); +} + void llofstream::open(const std::string& _Filename, ios_base::openmode _Mode) { std::ofstream::open(ll_convert( _Filename ).c_str(), _Mode | ios_base::out); } +void llofstream::open(const std::filesystem::path& _Filepath, ios_base::openmode _Mode) +{ + std::ofstream::open(_Filepath, + _Mode | ios_base::out); +} + #endif // LL_WINDOWS diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index dcd561ce7f..7e8e114098 100755 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -35,6 +35,8 @@ * Attempts to mostly mirror the POSIX style IO functions. */ +#include "stdtypes.h" + #include #include #include @@ -51,15 +53,24 @@ typedef struct stat llstat; typedef FILE LLFILE; +#include "fsyspath.h" #include "llstring.h" // safe char* -> std::string conversion +#ifndef TEXT +#if LL_WINDOWS +#define TEXT(flags) L##flags +#else +#define TEXT(flags) flags +#endif +#endif + /// This class provides a selection of functions to operate on files through names and /// a class implementation to represent a file for reading and writing to it /// All the functions with a path string input take UTF8 path/filenames /// /// @nosubgrouping /// -class LL_COMMON_API LLFile +class LLFile { public: // ================================================================================ @@ -157,12 +168,24 @@ public: } /// constructor opening the file - LLFile(const std::string& filename, std::ios_base::openmode omode, std::error_code& ec, int perm = 0666) : + explicit LLFile(const char* filename, std::ios_base::openmode omode, std::error_code& ec, int perm = 0666) : + mHandle(InvalidHandle) + { + open(filename, omode, ec, perm); + } + + explicit LLFile(const std::string& filename, std::ios_base::openmode omode, std::error_code& ec, int perm = 0666) : mHandle(InvalidHandle) { open(filename, omode, ec, perm); } + explicit LLFile(const std::filesystem::path& file_path, std::ios_base::openmode omode, std::error_code& ec, int perm = 0666) : + mHandle(InvalidHandle) + { + open(file_path, omode, ec, perm); + } + /// destructor always attempts to close the file ~LLFile() { close(); } ///@} @@ -198,7 +221,17 @@ public: ///@{ /// Open a file with the specific open mode flags - int open(const std::string& filename, std::ios_base::openmode omode, std::error_code& ec, int perm = 0666); + inline int open(const char* filename, std::ios_base::openmode omode, std::error_code& ec, int perm = 0666) + { + std::filesystem::path file_path = fsyspath(filename); + return open(file_path, omode, ec, perm); + } + inline int open(const std::string& filename, std::ios_base::openmode omode, std::error_code& ec, int perm = 0666) + { + std::filesystem::path file_path = fsyspath(filename); + return open(file_path, omode, ec, perm); + } + int open(const std::filesystem::path& filename, std::ios_base::openmode omode, std::error_code& ec, int perm = 0666); ///< @returns 0 on success, -1 on failure /// Determine the size of the opened file @@ -257,7 +290,23 @@ public: /// ///@{ /// open a file with the specified access mode - static LLFILE* fopen(const std::string& filename, const char* accessmode, int lmode = 0); + /// +#if LL_WINDOWS + using fopen_flags_t = wchar_t; +#else + using fopen_flags_t = char; +#endif + inline static LLFILE* fopen(const char* filename, const fopen_flags_t* accessmode, int lmode = 0) + { + std::filesystem::path file_path = fsyspath(filename); + return LLFile::fopen(file_path, accessmode, lmode); + } + inline static LLFILE* fopen(const std::string& filename, const fopen_flags_t* accessmode, int lmode = 0) + { + std::filesystem::path file_path = fsyspath(filename); + return LLFile::fopen(file_path, accessmode, lmode); + } + static LLFILE* fopen(const std::filesystem::path& file_path, const fopen_flags_t* accessmode, int lmode = 0); ///< 'accessmode' follows the rules of the Posix fopen() mode parameter /// "r" open the file for reading only and positions the stream at the beginning /// "r+" open the file for reading and writing and positions the stream at the beginning @@ -291,19 +340,63 @@ public: ///< @returns 0 on success and -1 on failure. /// create a directory - static int mkdir(const std::string& filename); + inline static int mkdir(const char* dirname) + { + std::filesystem::path dir_path = fsyspath(dirname); + return mkdir(dir_path); + } + inline static int mkdir(const std::string& dirname) + { + std::filesystem::path dir_path = fsyspath(dirname); + return mkdir(dir_path); + } + static int mkdir(const std::filesystem::path& dirname); ///< mkdir() considers "directory already exists" to be not an error. /// @returns 0 on success and -1 on failure. /// remove a file or directory - static int remove(const std::string& filename, int suppress_warning = 0); + inline static int remove(const char* filename, int suppress_warning = 0) + { + std::filesystem::path file_path = fsyspath(filename); + return remove(file_path, suppress_warning); + } + inline static int remove(const std::string& filename, int suppress_warning = 0) + { + std::filesystem::path file_path = fsyspath(filename); + return remove(file_path, suppress_warning); + } + static int remove(const std::filesystem::path& file_path, int suppress_warning = 0); ///< pass an errno value (e.g., ENOENT) in the optional 'suppress_warning' parameter if you want to /// suppress a warning in the log when the failure matches that errno (e.g., suppress warning if /// the file or directory does not exist) /// @returns 0 on success and -1 on failure. /// rename a file - static int rename(const std::string& filename, const std::string& newname, int suppress_warning = 0); + inline static int rename(const char* filename, const char* newname, int suppress_warning = 0) + { + std::filesystem::path file_path = fsyspath(filename); + std::filesystem::path new_path = fsyspath(newname); + return rename(file_path, new_path, suppress_warning); + } + inline static int rename(const std::string& filename, const char* newname, int suppress_warning = 0) + { + std::filesystem::path file_path = fsyspath(filename); + std::filesystem::path new_path = fsyspath(newname); + return rename(file_path, new_path, suppress_warning); + } + inline static int rename(const char* filename, const std::string& newname, int suppress_warning = 0) + { + std::filesystem::path file_path = fsyspath(filename); + std::filesystem::path new_path = fsyspath(newname); + return rename(file_path, new_path, suppress_warning); + } + inline static int rename(const std::string& filename, const std::string& newname, int suppress_warning = 0) + { + std::filesystem::path file_path = fsyspath(filename); + std::filesystem::path new_path = fsyspath(newname); + return rename(file_path, new_path, suppress_warning); + } + static int rename(const std::filesystem::path& file_path, const std::filesystem::path& new_path, int suppress_warning = 0); ///< it will silently overwrite newname if it exists without returning an error /// Posix guarantees that if newname already exists, then there will be no moment /// in which for other processes newname does not exist. There is no such guarantee @@ -312,7 +405,31 @@ public: /// @returns 0 on success and -1 on failure. /// copy the contents of the file from 'source' to 'target' - static bool copy(const std::string& source, const std::string& target); + inline static bool copy(const char* source, const char* target) + { + std::error_code ec; + return copy(source, target, std::filesystem::copy_options::overwrite_existing, ec); + } + inline static bool copy(const char* source, const std::string& target) + { + std::error_code ec; + return copy(source, target, std::filesystem::copy_options::overwrite_existing, ec); + } + inline static bool copy(const std::string& source, char* target) + { + std::error_code ec; + return copy(source, target, std::filesystem::copy_options::overwrite_existing, ec); + } + inline static bool copy(const std::string& source, const std::string& target) + { + std::error_code ec; + return copy(source, target, std::filesystem::copy_options::overwrite_existing, ec); + } + inline static bool copy(const std::filesystem::path& source_path, const std::filesystem::path& target_path) + { + std::error_code ec; + return copy(source_path, target_path, std::filesystem::copy_options::overwrite_existing, ec); + } ///< Copies the contents of the file 'source' to the file 'target', overwriting 'target' if it already /// existed. /// This is a convenience function that implements the previous behavior of silently overwriting an @@ -321,7 +438,31 @@ public: /// @returns true on success and false on failure. /// copy the contents of the file from 'from' to 'to' - static bool copy(const std::string& source, const std::string& target, std::filesystem::copy_options options, std::error_code& ec); + inline static bool copy(const char* source, const char* target, std::filesystem::copy_options options, std::error_code& ec) + { + std::filesystem::path source_path = fsyspath(source); + std::filesystem::path target_path = fsyspath(target); + return copy(source_path, target_path, options, ec); + } + inline static bool copy(const char* source, const std::string& target, std::filesystem::copy_options options, std::error_code& ec) + { + std::filesystem::path source_path = fsyspath(source); + std::filesystem::path target_path = fsyspath(target); + return copy(source_path, target_path, options, ec); + } + inline static bool copy(const std::string& source, const char* target, std::filesystem::copy_options options, std::error_code& ec) + { + std::filesystem::path source_path = fsyspath(source); + std::filesystem::path target_path = fsyspath(target); + return copy(source_path, target_path, options, ec); + } + inline static bool copy(const std::string& source, const std::string& target, std::filesystem::copy_options options, std::error_code& ec) + { + std::filesystem::path source_path = fsyspath(source); + std::filesystem::path target_path = fsyspath(target); + return copy(source_path, target_path, options, ec); + } + static bool copy(const std::filesystem::path& source_path, const std::filesystem::path& target_path, std::filesystem::copy_options options, std::error_code& ec); ///< Copies the contents of the file 'source' to the file 'target'. The options parameter allows to /// specify what should happen if the "target" file already exists: /// std::filesystem::copy_options::none - return an error in ec and fail @@ -331,48 +472,115 @@ public: /// @returns true on success and false on failure. /// retrieve the content of a file into a string - static std::string getContents(const std::string& filename); - static std::string getContents(const std::string& filename, std::error_code& ec); + inline static std::string getContents(const char* filename) + { + std::error_code ec; + return getContents(filename, ec); + } + inline static std::string getContents(const std::string& filename) + { + std::error_code ec; + return getContents(filename, ec); + } + inline static std::string getContents(const std::filesystem::path& file_path) + { + std::error_code ec; + return getContents(file_path, ec); + } + inline static std::string getContents(const char* filename, std::error_code& ec) + { + std::filesystem::path file_path = fsyspath(filename); + return getContents(file_path, ec); + } + inline static std::string getContents(const std::string& filename, std::error_code& ec) + { + std::filesystem::path file_path = fsyspath(filename); + return getContents(file_path, ec); + } + static std::string getContents(const std::filesystem::path& file_path, std::error_code& ec); ///< @returns the entire content of the file as std::string or an empty string on failure /// read nBytes from the file into the buffer, starting at offset in the file - static S64 read(const std::string& filename, void* buf, S64 offset, S64 nbytes); - static S64 read(const std::string& filename, void* buf, S64 offset, S64 nbytes, std::error_code& ec); + inline static S64 read(const char* filename, void* buf, S64 offset, S64 nbytes) + { + std::error_code ec; + return read(filename, buf, offset, nbytes, ec); + } + inline static S64 read(const std::string& filename, void* buf, S64 offset, S64 nbytes) + { + std::error_code ec; + return read(filename, buf, offset, nbytes, ec); + } + inline static S64 read(const std::filesystem::path& file_path, void* buf, S64 offset, S64 nbytes) + { + std::error_code ec; + return read(file_path, buf, offset, nbytes, ec); + } + inline static S64 read(const char* filename, void* buf, S64 offset, S64 nbytes, std::error_code& ec) + { + std::filesystem::path file_path = fsyspath(filename); + return read(file_path, buf, offset, nbytes, ec); + } + inline static S64 read(const std::string& filename, void* buf, S64 offset, S64 nbytes, std::error_code& ec) + { + std::filesystem::path file_path = fsyspath(filename); + return read(file_path, buf, offset, nbytes, ec); + } + static S64 read(const std::filesystem::path& filename, void* buf, S64 offset, S64 nbytes, std::error_code& ec); ///< @returns bytes read on success, or -1 on failure /// write nBytes from the buffer into the file, starting at offset in the file - static S64 write(const std::string& filename, const void* buf, S64 offset, S64 nbytes); - static S64 write(const std::string& filename, const void* buf, S64 offset, S64 nbytes, std::error_code& ec); + inline static S64 write(const std::string& filename, const void* buf, S64 offset, S64 nbytes) + { + std::error_code ec; + std::filesystem::path file_path = fsyspath(filename); + return write(file_path, buf, offset, nbytes, ec); + } + inline static S64 write(const std::filesystem::path& filename, const void* buf, S64 offset, S64 nbytes) + { + std::error_code ec; + std::filesystem::path file_path = fsyspath(filename); + return write(file_path, buf, offset, nbytes, ec); + } + inline static S64 write(const std::string& filename, const void* buf, S64 offset, S64 nbytes, std::error_code& ec) + { + std::filesystem::path file_path = fsyspath(filename); + return write(file_path, buf, offset, nbytes, ec); + } + static S64 write(const std::filesystem::path& filename, const void* buf, S64 offset, S64 nbytes, std::error_code& ec); ///< If a negative offset is provided, the file is opened in append mode and the /// write will be appended to the end of the file. /// @returns bytes written on success, or -1 on failure /// return the file stat structure for filename - static int stat(const std::string& filename, llstat* file_status, const char *operation = nullptr, int suppress_warning = ENOENT); + inline static int stat(const char* filename, llstat* file_status, const char* operation = nullptr, int suppress_warning = ENOENT) + { + std::filesystem::path file_path = fsyspath(filename); + return stat(file_path, file_status, operation, suppress_warning); + } + inline static int stat(const std::string& filename, llstat* file_status, const char* operation = nullptr, int suppress_warning = ENOENT) + { + std::filesystem::path file_path = fsyspath(filename); + return stat(file_path, file_status, operation, suppress_warning); + } + static int stat(const std::filesystem::path& file_path, llstat* file_status, const char *operation = nullptr, int suppress_warning = ENOENT); ///< for compatibility with existing uses of LL_File::stat() we use ENOENT as default in the /// optional 'suppress_warning' parameter to avoid spamming the log with warnings when the API /// is used to detect if a file exists /// @returns 0 on success and -1 on failure. - /// get the creation data and time of a file - static std::time_t getCreationTime(const std::string& filename, int suppress_warning = 0); - ///< Different systems have different support for this. Under Windows this is supposedly - /// the actual time the file was created, on the Mac this is the actual birth date of - /// the file which is in fact the creation time. The according ctime entry in the stat - /// structure under Linux (and any other *nix really) is however contrary to what one - /// might expect based on the c in ctime not the creation time but the time the last - /// change to the inode entry was made. Changing access rights to a file will update - /// this value too. In order to have a true creation time under Linux, we would have - /// to use the statx() call which is available since kernel 4.19, but that will require - /// considerable changes to the implementation of above stat() function. - /// @returns the creation time (last status change under Linux) of the file or 0 on error - - /// get the last modification data and time of a file - static std::time_t getModificationTime(const std::string& filename, int suppress_warning = 0); - ///< @returns the modification time of the file or 0 on error - /// get the std::filesystem::file_status for filename - static std::filesystem::file_status getStatus(const std::string& filename, bool dontFollowSymLink = false, int suppress_warning = ENOENT); + inline static std::filesystem::file_status getStatus(const char* filename, bool dontFollowSymLink = false, int suppress_warning = ENOENT) + { + std::filesystem::path file_path = fsyspath(filename); + return getStatus(file_path, dontFollowSymLink, suppress_warning); + } + inline static std::filesystem::file_status getStatus(const std::string& filename, bool dontFollowSymLink = false, int suppress_warning = ENOENT) + { + std::filesystem::path file_path = fsyspath(filename); + return getStatus(file_path, dontFollowSymLink, suppress_warning); + } + static std::filesystem::file_status getStatus(const std::filesystem::path& file_path, bool dontFollowSymLink = false, int suppress_warning = ENOENT); ///< dontFollowSymLinks set to true returns the std::filesystem::file_status of the symlink if it /// is one, rather than resolving it. We pass by default ENOENT in the optional 'suppress_warning' /// parameter to not spam the log with warnings when the file or directory does not exist @@ -380,66 +588,108 @@ public: /// and other APIs accepting a file_status. /// get the size of a file in bytes - static S64 size(const std::string& filename, int suppress_warning = ENOENT); + inline static S64 size(const char* filename, int suppress_warning = ENOENT) + { + std::filesystem::path file_path = fsyspath(filename); + return size(file_path, suppress_warning); + } + inline static S64 size(const std::string& filename, int suppress_warning = ENOENT) + { + std::filesystem::path file_path = fsyspath(filename); + return size(file_path, suppress_warning); + } + static S64 size(const std::filesystem::path& file_path, int suppress_warning = ENOENT); ///< we pass by default ENOENT in the optional 'suppress_warning' parameter to not spam /// the log with warnings when the file does not exist /// @returns the file size on success or 0 on failure. /// check if filename is an existing file or directory - static bool exists(const std::string& filename); + inline static bool exists(const char* filename) + { + std::filesystem::file_status status = getStatus(filename); + return std::filesystem::exists(status); + } + inline static bool exists(const std::string& filename) + { + std::filesystem::file_status status = getStatus(filename); + return std::filesystem::exists(status); + } + inline static bool exists(const std::filesystem::path& file_path) + { + std::filesystem::file_status status = getStatus(file_path); + return std::filesystem::exists(status); + } ///< @returns true if the path is for an existing file or directory /// check if filename is an existing directory - static bool isdir(const std::string& filename); + inline static bool isdir(const char* filename) + { + std::filesystem::file_status status = getStatus(filename); + return std::filesystem::is_directory(status); + } + inline static bool isdir(const std::string& filename) + { + std::filesystem::file_status status = getStatus(filename); + return std::filesystem::is_directory(status); + } + inline static bool isdir(const std::filesystem::path& file_path) + { + std::filesystem::file_status status = getStatus(file_path); + return std::filesystem::is_directory(status); + } ///< @returns true if the path is for an existing directory /// check if filename is an existing file - static bool isfile(const std::string& filename); + inline static bool isfile(const char* filename) + { + std::filesystem::file_status status = getStatus(filename); + return std::filesystem::is_regular_file(status); + } + inline static bool isfile(const std::string& filename) + { + std::filesystem::file_status status = getStatus(filename); + return std::filesystem::is_regular_file(status); + } + inline static bool isfile(const std::filesystem::path& file_path) + { + std::filesystem::file_status status = getStatus(file_path); + return std::filesystem::is_regular_file(status); + } ///< @returns true if the path is for an existing file /// check if filename is a symlink - static bool islink(const std::string& filename); + inline static bool islink(const char* filename) + { + std::filesystem::file_status status = getStatus(filename, true); + return std::filesystem::is_symlink(status); + } + inline static bool islink(const std::string& filename) + { + std::filesystem::file_status status = getStatus(filename, true); + return std::filesystem::is_symlink(status); + } + inline static bool islink(const std::filesystem::path& file_path) + { + std::filesystem::file_status status = getStatus(file_path, true); + return std::filesystem::is_symlink(status); + } ///< @returns true if the path is pointing at a symlink /// return a path to the temporary directory on the system static const std::string& tmpdir(); - /// converts a string containing a path in utf8 encoding into an explicit filesystem path - static std::filesystem::path utf8StringToPath(const std::string& pathname); - ///< @returns the path as a std::filesystem::path - ///@} - private: #if LL_WINDOWS typedef HANDLE llfile_handle_t; const llfile_handle_t InvalidHandle = INVALID_HANDLE_VALUE; + llfile_handle_t mHandle = INVALID_HANDLE_VALUE; // The file handle/descriptor #else typedef int llfile_handle_t; const llfile_handle_t InvalidHandle = -1; + llfile_handle_t mHandle = -1;; // The file handle/descriptor #endif - /// ================================================================================ - /// @name private static member functions - /// -#if LL_WINDOWS - /// convert a string containing a path in utf8 encoding into a Windows format std::wstring - static std::wstring utf8StringToWstring(const std::string& pathname); - ///< this will prepend the path with the Windows kernel object space prefix when the path is - /// equal or longer than MAX_PATH characters and do some sanitation on the path. - /// This allows the underlaying Windows APIs to process long path names. Do not pass such a path - /// to std::filesystem functions. These functions are not guaranteed to handle such paths properly. - /// It's only useful to pass the resulting string buffer to Microsoft Windows widechar APIs or - /// the Microsoft C runtime widechar file functions. - /// - /// Example: - /// - /// std::wstring file_path = utf8StringToWstring(filename); - /// HANDLE CreateFileW(file_path.c_str(), ......); - /// - /// @returns the path as a std::wstring path -#endif - llfile_handle_t mHandle; // The file handle/descriptor - std::ios_base::openmode mOpen; // Used to emulate std::ios_base::app under Windows + std::ios_base::openmode mOpen{}; // Used to emulate std::ios_base::app under Windows }; #if LL_WINDOWS @@ -451,7 +701,7 @@ private: * Does The Right Thing when passed a non-ASCII pathname. Sadly, that isn't * true of Microsoft's std::ifstream. */ -class LL_COMMON_API llifstream : public std::ifstream +class llifstream : public std::ifstream { // input stream associated with a C stream public: @@ -463,7 +713,7 @@ class LL_COMMON_API llifstream : public std::ifstream * @c &sb to the base class initializer. Does not open any files * (you haven't given it a filename to open). */ - llifstream(); + llifstream() = default; /** * @brief Create an input file stream. @@ -472,8 +722,12 @@ class LL_COMMON_API llifstream : public std::ifstream * * @c ios_base::in is automatically included in @a mode. */ + explicit llifstream(const char* _Filename, + ios_base::openmode _Mode = ios_base::in); explicit llifstream(const std::string& _Filename, ios_base::openmode _Mode = ios_base::in); + explicit llifstream(const std::filesystem::path& _Filepath, + ios_base::openmode _Mode = ios_base::in); /** * @brief Opens an external file. @@ -483,10 +737,73 @@ class LL_COMMON_API llifstream : public std::ifstream * Calls @c llstdio_filebuf::open(s,mode|in). If that function * fails, @c failbit is set in the stream's error state. */ + void open(const char* _Filename, + ios_base::openmode _Mode = ios_base::in); void open(const std::string& _Filename, ios_base::openmode _Mode = ios_base::in); + void open(const std::filesystem::path& _Filepath, + ios_base::openmode _Mode = ios_base::in); }; +/// RAII class +class LLUniqueFile +{ +public: + // empty + LLUniqueFile() = default; + // wrap (e.g.) result of LLFile::fopen() + LLUniqueFile(LLFILE* f) : mFileHandle(f) {} + // no copy + LLUniqueFile(const LLUniqueFile&) = delete; + // move construction + LLUniqueFile(LLUniqueFile&& other) noexcept + { + mFileHandle = other.mFileHandle; + other.mFileHandle = nullptr; + } + // The point of LLUniqueFile is to close on destruction. + ~LLUniqueFile() { close(); } + + // simple assignment + LLUniqueFile& operator=(LLFILE* f) + { + close(); + mFileHandle = f; + return *this; + } + // copy assignment deleted + LLUniqueFile& operator=(const LLUniqueFile&) = delete; + // move assignment + LLUniqueFile& operator=(LLUniqueFile&& other) noexcept + { + close(); + std::swap(mFileHandle, other.mFileHandle); + return *this; + } + + // explicit close operation + void close() + { + if (mFileHandle) + { + // in case close() throws, set mFileHandle null FIRST + LLFILE* h{ nullptr }; + std::swap(h, mFileHandle); + LLFile::close(h); + } + } + + // detect whether the wrapped LLFILE is open or not + explicit operator bool() const { return bool(mFileHandle); } + bool operator!() { return !mFileHandle; } + + // LLUniqueFile should be usable for any operation that accepts LLFILE* + // (or FILE* for that matter) + operator LLFILE*() const { return mFileHandle; } + +private: + LLFILE* mFileHandle = nullptr; +}; /** * @brief Controlling output for files. @@ -496,7 +813,7 @@ class LL_COMMON_API llifstream : public std::ifstream * Right Thing when passed a non-ASCII pathname. Sadly, that isn't true of * Microsoft's std::ofstream. */ -class LL_COMMON_API llofstream : public std::ofstream +class llofstream : public std::ofstream { public: // Constructors: @@ -507,7 +824,7 @@ class LL_COMMON_API llofstream : public std::ofstream * @c &sb to the base class initializer. Does not open any files * (you haven't given it a filename to open). */ - llofstream(); + llofstream() = default; /** * @brief Create an output file stream. @@ -516,8 +833,12 @@ class LL_COMMON_API llofstream : public std::ofstream * * @c ios_base::out is automatically included in @a mode. */ + explicit llofstream(const char* _Filename, + ios_base::openmode _Mode = ios_base::out|ios_base::trunc); explicit llofstream(const std::string& _Filename, ios_base::openmode _Mode = ios_base::out|ios_base::trunc); + explicit llofstream(const std::filesystem::path& _Filepath, + ios_base::openmode _Mode = ios_base::out|ios_base::trunc); /** * @brief Opens an external file. @@ -526,8 +847,12 @@ class LL_COMMON_API llofstream : public std::ofstream * * @c ios_base::out is automatically included in @a mode. */ + void open(const char* _Filename, + ios_base::openmode _Mode = ios_base::out|ios_base::trunc); void open(const std::string& _Filename, ios_base::openmode _Mode = ios_base::out|ios_base::trunc); + void open(const std::filesystem::path& _Filepath, + ios_base::openmode _Mode = ios_base::out|ios_base::trunc); }; #else // ! LL_WINDOWS diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index 37d1c60f91..7656986fe2 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -837,7 +837,7 @@ private: void get_proc_cpuinfo() { std::map< std::string, std::string > cpuinfo; - LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb"); + LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, TEXT("rb")); if(cpuinfo_fp) { char line[MAX_STRING]; @@ -954,7 +954,7 @@ private: std::ostringstream s; // *NOTE:Mani - This is for linux only. - LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb"); + LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, TEXT("rb")); if(cpuinfo) { char line[MAX_STRING]; diff --git a/indra/llcommon/llprofilercategories.h b/indra/llcommon/llprofilercategories.h index 1c4f0f5624..261fdf14b7 100644 --- a/indra/llcommon/llprofilercategories.h +++ b/indra/llcommon/llprofilercategories.h @@ -48,6 +48,7 @@ #define LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL 1 #define LL_PROFILER_CATEGORY_ENABLE_ENVIRONMENT 1 #define LL_PROFILER_CATEGORY_ENABLE_FACE 1 +//#define LL_PROFILER_CATEGORY_ENABLE_FILE 1 #define LL_PROFILER_CATEGORY_ENABLE_LLSD 1 #define LL_PROFILER_CATEGORY_ENABLE_LOGGING 1 #define LL_PROFILER_CATEGORY_ENABLE_MATERIAL 1 @@ -126,6 +127,14 @@ #define LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE #endif +#if LL_PROFILER_CATEGORY_ENABLE_FILE +#define LL_PROFILE_ZONE_NAMED_CATEGORY_FILE LL_PROFILE_ZONE_NAMED +#define LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE LL_PROFILE_ZONE_SCOPED +#else +#define LL_PROFILE_ZONE_NAMED_CATEGORY_FILE(name) +#define LL_PROFILE_ZONE_SCOPED_CATEGORY_FILE +#endif + #if LL_PROFILER_CATEGORY_ENABLE_LLSD #define LL_PROFILE_ZONE_NAMED_CATEGORY_LLSD LL_PROFILE_ZONE_NAMED #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD LL_PROFILE_ZONE_SCOPED diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 9b5dd2df39..499de996e2 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -514,7 +514,7 @@ namespace { #if LL_LINUX constexpr U32 STATUS_SIZE = 2048; - LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); + LLFILE* status_filep = LLFile::fopen("/proc/self/status", TEXT("rb")); if (status_filep) { char buff[STATUS_SIZE]; /* Flawfinder: ignore */ @@ -1273,7 +1273,7 @@ bool gunzip_file(const std::string& srcfile, const std::string& dstfile) src = gzopen(srcfile.c_str(), "rb"); #endif if (! src) goto err; - dst = LLFile::fopen(tmpfile, "wb"); /* Flawfinder: ignore */ + dst = LLFile::fopen(tmpfile, TEXT("wb")); /* Flawfinder: ignore */ if (! dst) goto err; do { @@ -1314,7 +1314,7 @@ bool gzip_file(const std::string& srcfile, const std::string& dstfile) #endif if (! dst) goto err; - src = LLFile::fopen(srcfile, "rb"); /* Flawfinder: ignore */ + src = LLFile::fopen(srcfile, TEXT("rb")); /* Flawfinder: ignore */ if (! src) goto err; while ((bytes = (S32)fread(buffer, sizeof(U8), COMPRESS_BUFFER_SIZE, src)) > 0) diff --git a/indra/llcommon/tests/llfile_test.cpp b/indra/llcommon/tests/llfile_test.cpp index f1cee06856..ab4616cfb2 100644 --- a/indra/llcommon/tests/llfile_test.cpp +++ b/indra/llcommon/tests/llfile_test.cpp @@ -33,14 +33,13 @@ namespace tut { - static void clear_entire_dir(const std::string &dir) + static void clear_entire_dir(const std::filesystem::path& dir_path) { std::error_code ec; - std::filesystem::path dir_path = LLFile::utf8StringToPath(dir); std::filesystem::remove_all(dir_path, ec); } - static std::filesystem::path append_filename(const std::filesystem::path& dir, const std::string& element) + static std::filesystem::path append_filename(const std::filesystem::path& dir, const std::u8string& element) { std::filesystem::path path = dir; return path.append(element); @@ -48,13 +47,13 @@ namespace tut static std::filesystem::path get_testdir(const std::filesystem::path& tempdir) { - return append_filename(tempdir, std::string("test_dir")); + return append_filename(tempdir, std::u8string(u8"test_dir")); } static std::filesystem::path get_testdir_unicode(const std::filesystem::path& tempdir) { // Example Unicode directory name: "test_ユニコード_dir" - return append_filename(tempdir, std::string("test_\xE3\x83\xA6\xE3\x83\x8B\xE3\x82\xB3\xE3\x83\xBC\xE3\x83\x89_dir")); + return append_filename(tempdir, std::u8string(u8"test_\xE3\x83\xA6\xE3\x83\x8B\xE3\x82\xB3\xE3\x83\xBC\xE3\x83\x89_dir")); } struct llfile_test @@ -72,46 +71,46 @@ namespace tut // Test creating directories and files and deleting them and checking if the // relevant status functions work as expected ensure("LLFile::tmpdir() empty", !tempdir.empty()); - ensure("LLFile::tmpdir() doesn't exist", LLFile::exists(tempdir.string())); - ensure("LLFile::tmpdir() is not a directory", LLFile::isdir(tempdir.string())); - ensure("LLFile::tmpdir() should not be a file", !LLFile::isfile(tempdir.string())); + ensure("LLFile::tmpdir() doesn't exist", LLFile::exists(tempdir)); + ensure("LLFile::tmpdir() is not a directory", LLFile::isdir(tempdir)); + ensure("LLFile::tmpdir() should not be a file", !LLFile::isfile(tempdir)); // Make sure there is nothing left from a previous test run - clear_entire_dir(testdir.string()); - ensure("llfile_test should not exist anymore", !LLFile::exists(testdir.string())); + clear_entire_dir(testdir); + ensure("llfile_test should not exist anymore", !LLFile::exists(testdir)); - int rc = LLFile::mkdir(testdir.string()); + int rc = LLFile::mkdir(testdir); ensure("LLFile::mkdir() failed", rc == 0); - ensure("llfile_test should be a directory", LLFile::isdir(testdir.string())); - rc = LLFile::mkdir(testdir.string()); + ensure("llfile_test should be a directory", LLFile::isdir(testdir)); + rc = LLFile::mkdir(testdir); ensure("LLFile::mkdir() should not fail when the directory already exists", rc == 0); std::filesystem::path testfile1 = testdir; testfile1.append("llfile_test.dat"); - ensure("llfile_test1.dat should not yet exist", !LLFile::exists(testfile1.string())); + ensure("llfile_test1.dat should not yet exist", !LLFile::exists(testfile1)); const char* testdata = "testdata"; - S64 bytes = LLFile::write(testfile1.string(), testdata, 0, sizeof(testdata)); + S64 bytes = LLFile::write(testfile1, testdata, 0, sizeof(testdata)); ensure("LLFile::write() did not write correctly", bytes == sizeof(testdata)); - rc = LLFile::remove(testfile1.string()); + rc = LLFile::remove(testfile1); ensure("LLFile::remove() for file test_file.dat", rc == 0); - ensure("llfile_test.dat should not exist anymore", !LLFile::exists(testfile1.string())); - ensure("llfile_test.dat should not be a file", !LLFile::isfile(testfile1.string())); - ensure("llfile_test.dat should not be a directory", !LLFile::isdir(testfile1.string())); - ensure("llfile_test.dat should not be a symlink", !LLFile::islink(testfile1.string())); + ensure("llfile_test.dat should not exist anymore", !LLFile::exists(testfile1)); + ensure("llfile_test.dat should not be a file", !LLFile::isfile(testfile1)); + ensure("llfile_test.dat should not be a directory", !LLFile::isdir(testfile1)); + ensure("llfile_test.dat should not be a symlink", !LLFile::islink(testfile1)); - rc = LLFile::remove(testdir.string()); + rc = LLFile::remove(testdir); ensure("LLFile::remove() for directory llfile_test failed", rc == 0); - ensure("llfile_test should not exist anymore", !LLFile::exists(testdir.string())); + ensure("llfile_test should not exist anymore", !LLFile::exists(testdir)); } template<> template<> void llfile_test_object_t::test<2>() { // High level static file IO functions to read and write data files - LLFile::mkdir(testdir.string()); - ensure("llfile_test should exist", LLFile::isdir(testdir.string())); + LLFile::mkdir(testdir); + ensure("llfile_test should exist", LLFile::isdir(testdir)); std::filesystem::path testfile1 = testdir; testfile1.append("llfile_test.dat"); @@ -119,42 +118,36 @@ namespace tut std::string testdata1("testdata"); std::string testdata2("datateststuff"); std::time_t current = time(nullptr); - S64 bytes = LLFile::write(testfile1.string(), testdata1.c_str(), 0, testdata1.length()); + S64 bytes = LLFile::write(testfile1, testdata1.c_str(), 0, testdata1.length()); ensure("LLFile::write() did not write correctly", bytes == testdata1.length()); - ensure("llfile_test.dat should exist", LLFile::exists(testfile1.string())); - ensure("llfile_test.dat should be a file", LLFile::isfile(testfile1.string())); - ensure("llfile_test.dat should not be a directory", !LLFile::isdir(testfile1.string())); + ensure("llfile_test.dat should exist", LLFile::exists(testfile1)); + ensure("llfile_test.dat should be a file", LLFile::isfile(testfile1)); + ensure("llfile_test.dat should not be a directory", !LLFile::isdir(testfile1)); - bytes = LLFile::size(testfile1.string()); + bytes = LLFile::size(testfile1); ensure("LLFile::size() did not return the correct size", bytes == testdata1.length()); - std::string data = LLFile::getContents(testfile1.string()); + std::string data = LLFile::getContents(testfile1); ensure("LLFile::getContents() did not return the correct size data", data.length() == testdata1.length()); ensure_memory_matches("LLFile::getContents() did not read correct data", testdata1.c_str(), (U32)testdata1.length(), data.c_str(), (U32)data.length()); - std::time_t ctime = LLFile::getCreationTime(testfile1.string()); - ensure_approximately_equals_range("LLFile::getCreationTime() did not return correct time", (F32)(ctime - current), 0.f, 1); - - std::time_t mtime = LLFile::getModificationTime(testfile1.string()); - ensure_approximately_equals_range("LLFile::getModificationTime() did not return correct time", (F32)(mtime - current), 0.f, 1); - char buffer[1024]; - bytes = LLFile::read(testfile1.string(), buffer, 0, testdata1.length()); + bytes = LLFile::read(testfile1, buffer, 0, testdata1.length()); ensure("LLFile:read() did not return the correct size", bytes == testdata1.length()); ensure_memory_matches("LLFile::read() did not read correct data", testdata1.c_str(), (U32)bytes, buffer, (U32)bytes); // What if we try to read more data than there is in the file? - bytes = LLFile::read(testfile1.string(), buffer, 0, bytes + 10); + bytes = LLFile::read(testfile1, buffer, 0, bytes + 10); ensure("LLFile:read() did not correctly stop on eof", bytes == testdata1.length()); ensure_memory_matches("LLFile::read() did not read correct data", testdata1.c_str(), (U32)bytes, buffer, (U32)bytes); // Let's append more data - bytes = LLFile::write(testfile1.string(), testdata2.c_str(), -1, testdata2.length()); + bytes = LLFile::write(testfile1, testdata2.c_str(), -1, testdata2.length()); ensure("LLFile::write() did not write correctly", bytes == testdata2.length()); - bytes = LLFile::size(testfile1.string()); + bytes = LLFile::size(testfile1); ensure("LLFile::size() did not return the correct size", bytes == testdata1.length() + testdata2.length()); - bytes = LLFile::read(testfile1.string(), buffer, 0, bytes); + bytes = LLFile::read(testfile1, buffer, 0, bytes); ensure("LLFile:read() did not read correct number of bytes", bytes == testdata1.length() + testdata2.length()); ensure_memory_matches("LLFile:read() did not read correct testdata1", testdata1.c_str(), (U32)testdata1.length(), buffer, (U32)testdata1.length()); ensure_memory_matches("LLFile:read() did not read correct testdata2", testdata2.c_str(), (U32)testdata2.length(), buffer + testdata1.length(), (U32)testdata2.length()); @@ -176,7 +169,7 @@ namespace tut } std::error_code ec; - LLFile fileout(testfile.string(), LLFile::out, ec); + LLFile fileout(testfile, LLFile::out, ec); ensure("LLFile constructor did not open correctly", (bool)fileout); ensure("error_code from LLFile constructor should not indicate an error", !ec); if (fileout) @@ -196,7 +189,7 @@ namespace tut fileout.close(); } - LLFile filein(testfile.string(), LLFile::in, ec); + LLFile filein(testfile, LLFile::in, ec); ensure("LLFile constructor did not open correctly", (bool)filein); ensure("error_code from LLFile constructor should not indicate an error", !ec); if (filein) @@ -236,16 +229,16 @@ namespace tut testfile.append("llfile_test.bin"); std::error_code ec; - LLFile file(testfile.string(), LLFile::out | LLFile::noreplace, ec); + LLFile file(testfile, LLFile::out | LLFile::noreplace, ec); ensure("LLFile constructor should not have opened the already existing file", !file); ensure("error_code from LLFile constructor should indicate an error", (bool)ec); - LLFile::remove(testfile.string()); - file = LLFile(testfile.string(), LLFile::out | LLFile::app | LLFile::trunc, ec); + LLFile::remove(testfile); + file = LLFile(testfile, LLFile::out | LLFile::app | LLFile::trunc, ec); ensure("LLFile constructor should not have opened the file with conflicting flags", !file); ensure("error_code from LLFile constructor should indicate an error", (bool)ec); - file = LLFile(testfile.string(), LLFile::out | LLFile::app | LLFile::noreplace, ec); + file = LLFile(testfile, LLFile::out | LLFile::app | LLFile::noreplace, ec); ensure("LLFile constructor should not have opened the file with conflicting flags", !file); ensure("error_code from LLFile constructor should indicate an error", (bool)ec); @@ -253,7 +246,7 @@ namespace tut testfile.append("llfile_test"); testfile.append("llfile_test.bin"); - file = LLFile(testfile.string(), LLFile::in, ec); + file = LLFile(testfile, LLFile::in, ec); ensure("LLFile constructor should not have been able to open the file in the non-existing directory", !file); ensure("error_code from LLFile constructor should indicate an error", (bool)ec); } @@ -270,37 +263,37 @@ namespace tut testfile_unicode.append(unicode_filename); // Clean up any previous test artifacts - clear_entire_dir(testdir_unicode.string()); - ensure("Unicode test directory should not exist", !LLFile::exists(testdir_unicode.string())); + clear_entire_dir(testdir_unicode); + ensure("Unicode test directory should not exist", !LLFile::exists(testdir_unicode)); // Create the Unicode directory - int rc = LLFile::mkdir(testdir_unicode.string()); + int rc = LLFile::mkdir(testdir_unicode); ensure("LLFile::mkdir() failed for Unicode directory", rc == 0); - ensure("Unicode test directory should exist", LLFile::isdir(testdir_unicode.string())); + ensure("Unicode test directory should exist", LLFile::isdir(testdir_unicode)); - ensure("Unicode test file should not exist", !LLFile::exists(testfile_unicode.string())); + ensure("Unicode test file should not exist", !LLFile::exists(testfile_unicode)); // Write to the Unicode file const char* testdata = "unicode_testdata"; - S64 bytes = LLFile::write(testfile_unicode.string(), testdata, 0, strlen(testdata)); - ensure("Unicode test file should exist", LLFile::exists(testfile_unicode.string())); - ensure("Unicode test file should be a file", LLFile::isfile(testfile_unicode.string())); + S64 bytes = LLFile::write(testfile_unicode, testdata, 0, strlen(testdata)); + ensure("Unicode test file should exist", LLFile::exists(testfile_unicode)); + ensure("Unicode test file should be a file", LLFile::isfile(testfile_unicode)); ensure("LLFile::write() did not write correctly to Unicode file", bytes == (S64)strlen(testdata)); // Read back the data char buffer[64] = {}; - bytes = LLFile::read(testfile_unicode.string(), buffer, 0, sizeof(buffer)); + bytes = LLFile::read(testfile_unicode, buffer, 0, sizeof(buffer)); ensure("LLFile::read() did not read correctly from Unicode file", bytes == (S64)strlen(testdata)); ensure_memory_matches("LLFile::read() did not read correct Unicode data", testdata, (U32)bytes, buffer, (U32)bytes); // Remove the file and directory - rc = LLFile::remove(testfile_unicode.string()); + rc = LLFile::remove(testfile_unicode); ensure("LLFile::remove() failed for Unicode file", rc == 0); - ensure("Unicode test file should not exist after removal", !LLFile::exists(testfile_unicode.string())); + ensure("Unicode test file should not exist after removal", !LLFile::exists(testfile_unicode)); - rc = LLFile::remove(testdir_unicode.string()); + rc = LLFile::remove(testdir_unicode); ensure("LLFile::remove() failed for Unicode directory", rc == 0); - ensure("Unicode test directory should not exist after removal", !LLFile::exists(testdir_unicode.string())); + ensure("Unicode test directory should not exist after removal", !LLFile::exists(testdir_unicode)); } } // namespace tut diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp index eb3c2d9909..3ec8983e8a 100755 --- a/indra/llfilesystem/lldir.cpp +++ b/indra/llfilesystem/lldir.cpp @@ -91,13 +91,13 @@ LLDir::~LLDir() std::vector LLDir::getFilesInDir(const std::string &dirname) { // Returns a vector of filenames in the directory. - std::filesystem::path p = LLFile::utf8StringToPath(dirname); + fsyspath dir_path(dirname); std::vector v; std::error_code ec; - if (std::filesystem::is_directory(p, ec)) + if (std::filesystem::is_directory(dir_path, ec)) { std::filesystem::directory_iterator end_iter; - for (std::filesystem::directory_iterator dir_itr(p); + for (std::filesystem::directory_iterator dir_itr(dir_path); dir_itr != end_iter; ++dir_itr) { @@ -173,10 +173,10 @@ U32 LLDir::deleteDirAndContents(const std::string& dir_name) //Removes the directory and its contents. Returns number of files deleted. U32 num_deleted = 0; - std::filesystem::path dir_path = LLFile::utf8StringToPath(dir_name); try { + fsyspath dir_path(dir_name); if (std::filesystem::is_directory(dir_path)) { if (!std::filesystem::is_empty(dir_path)) @@ -196,6 +196,11 @@ U32 LLDir::deleteDirAndContents(const std::string& dir_name) return num_deleted; } +bool LLDir::fileExists(const std::string& filename) const +{ + return LLFile::exists(filename); +} + const std::string LLDir::findFile(const std::string &filename, const std::string& searchPath1, const std::string& searchPath2, @@ -1005,7 +1010,7 @@ bool LLDir::setCacheDir(const std::string &path) { LLFile::mkdir(path); std::string tempname = add(path, "temp"); - LLFILE* file = LLFile::fopen(tempname,"wt"); + LLFILE* file = LLFile::fopen(tempname, TEXT("wt")); if (file) { fclose(file); diff --git a/indra/llfilesystem/lldir.h b/indra/llfilesystem/lldir.h index b0d2b6aada..8388816059 100644 --- a/indra/llfilesystem/lldir.h +++ b/indra/llfilesystem/lldir.h @@ -71,7 +71,7 @@ class LLDir std::vector getFilesInDir(const std::string &dirname); // pure virtual functions virtual std::string getCurPath() = 0; - virtual bool fileExists(const std::string &filename) const = 0; + virtual bool fileExists(const std::string &filename) const; const std::string findFile(const std::string& filename, const std::vector filenames) const; const std::string findFile(const std::string& filename, const std::string& searchPath1 = "", const std::string& searchPath2 = "", const std::string& searchPath3 = "") const; diff --git a/indra/llfilesystem/lldir_linux.cpp b/indra/llfilesystem/lldir_linux.cpp index b13b42c954..0ebaab1114 100644 --- a/indra/llfilesystem/lldir_linux.cpp +++ b/indra/llfilesystem/lldir_linux.cpp @@ -238,24 +238,6 @@ std::string LLDir_Linux::getCurPath() return tmp_str; } - -bool LLDir_Linux::fileExists(const std::string &filename) const -{ - struct stat stat_data; - // Check the age of the file - // Now, we see if the files we've gathered are recent... - int res = stat(filename.c_str(), &stat_data); - if (!res) - { - return true; - } - else - { - return false; - } -} - - /*virtual*/ std::string LLDir_Linux::getLLPluginLauncher() { return gDirUtilp->getExecutableDir() + gDirUtilp->getDirDelimiter() + diff --git a/indra/llfilesystem/lldir_linux.h b/indra/llfilesystem/lldir_linux.h index bd031bd7bb..ad9cd76554 100644 --- a/indra/llfilesystem/lldir_linux.h +++ b/indra/llfilesystem/lldir_linux.h @@ -47,7 +47,6 @@ public: virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - /*virtual*/ bool fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); /*virtual*/ std::string getLLPluginFilename(std::string base_name); diff --git a/indra/llfilesystem/lldir_mac.cpp b/indra/llfilesystem/lldir_mac.cpp index 2db1b6ec5d..7bddee0f75 100644 --- a/indra/llfilesystem/lldir_mac.cpp +++ b/indra/llfilesystem/lldir_mac.cpp @@ -177,14 +177,6 @@ std::string LLDir_Mac::getCurPath() return boost::filesystem::path( boost::filesystem::current_path() ).string(); } - - -bool LLDir_Mac::fileExists(const std::string &filename) const -{ - return boost::filesystem::exists(filename); -} - - /*virtual*/ std::string LLDir_Mac::getLLPluginLauncher() { return gDirUtilp->getAppRODataDir() + gDirUtilp->getDirDelimiter() + diff --git a/indra/llfilesystem/lldir_mac.h b/indra/llfilesystem/lldir_mac.h index f812ee810b..54dc2eb237 100644 --- a/indra/llfilesystem/lldir_mac.h +++ b/indra/llfilesystem/lldir_mac.h @@ -45,7 +45,6 @@ public: const std::string& app_read_only_data_dir); virtual std::string getCurPath(); - virtual bool fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); /*virtual*/ std::string getLLPluginFilename(std::string base_name); diff --git a/indra/llfilesystem/lldir_win32.cpp b/indra/llfilesystem/lldir_win32.cpp index 1cfa157634..912a2963c6 100644 --- a/indra/llfilesystem/lldir_win32.cpp +++ b/indra/llfilesystem/lldir_win32.cpp @@ -373,13 +373,6 @@ std::string LLDir_Win32::getCurPath() return ll_convert(std::wstring(w_str)); } - -bool LLDir_Win32::fileExists(const std::string &filename) const -{ - return LLFile::exists(filename); -} - - /*virtual*/ std::string LLDir_Win32::getLLPluginLauncher() { return gDirUtilp->getExecutableDir() + gDirUtilp->getDirDelimiter() + diff --git a/indra/llfilesystem/lldir_win32.h b/indra/llfilesystem/lldir_win32.h index 21a3f1213b..c3a41d3e33 100644 --- a/indra/llfilesystem/lldir_win32.h +++ b/indra/llfilesystem/lldir_win32.h @@ -44,7 +44,6 @@ public: /*virtual*/ std::string getCurPath(); /*virtual*/ U32 countFilesInDir(const std::string &dirname, const std::string &mask); - /*virtual*/ bool fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); /*virtual*/ std::string getLLPluginFilename(std::string base_name); diff --git a/indra/llfilesystem/llfilesystem.cpp b/indra/llfilesystem/llfilesystem.cpp index 0c220fe7cf..388cbc280f 100755 --- a/indra/llfilesystem/llfilesystem.cpp +++ b/indra/llfilesystem/llfilesystem.cpp @@ -34,8 +34,6 @@ #include "llfasttimer.h" #include "lldiskcache.h" -#include "boost/filesystem.hpp" - constexpr S32 LLFileSystem::READ = 0x00000001; constexpr S32 LLFileSystem::WRITE = 0x00000002; constexpr S32 LLFileSystem::READ_WRITE = 0x00000003; // LLFileSystem::READ & LLFileSystem::WRITE @@ -51,22 +49,21 @@ LLFileSystem::LLFileSystem(const LLUUID& file_id, const LLAssetType::EType file_ mBytesRead = 0; mMode = mode; + // build the filepath + mPath = fsyspath(LLDiskCache::metaDataToFilepath(mFileID, mFileType)); + // This block of code was originally called in the read() method but after comments here: // https://bitbucket.org/lindenlab/viewer/commits/e28c1b46e9944f0215a13cab8ee7dded88d7fc90#comment-10537114 // we decided to follow Henri's suggestion and move the code to update the last access time here. if (mode == LLFileSystem::READ) { - // build the filename (TODO: we do this in a few places - perhaps we should factor into a single function) - const std::string filename = LLDiskCache::metaDataToFilepath(mFileID, mFileType); - // update the last access time for the file if it exists - this is required // even though we are reading and not writing because this is the // way the cache works - it relies on a valid "last accessed time" for // each file so it knows how to remove the oldest, unused files - bool exists = gDirUtilp->fileExists(filename); - if (exists) + if (LLFile::exists(mPath)) { - updateFileAccessTime(filename); + updateFileAccessTime(); } } } @@ -111,20 +108,11 @@ bool LLFileSystem::renameFile(const LLUUID& old_file_id, const LLAssetType::ETyp return true; } -// static -S64 LLFileSystem::getFileSize(const LLUUID& file_id, const LLAssetType::EType file_type) -{ - const std::string filename = LLDiskCache::metaDataToFilepath(file_id, file_type); - return LLFile::size(filename); -} - bool LLFileSystem::read(U8* buffer, S32 bytes) { bool success = false; - const std::string filename = LLDiskCache::metaDataToFilepath(mFileID, mFileType); - - llifstream file(filename, std::ios::binary); + llifstream file(mPath, std::ios::binary); if (file.is_open()) { file.seekg(mPosition, std::ios::beg); @@ -164,13 +152,11 @@ bool LLFileSystem::eof() const bool LLFileSystem::write(const U8* buffer, S32 bytes) { - const std::string filename = LLDiskCache::metaDataToFilepath(mFileID, mFileType); - bool success = false; if (mMode == APPEND) { - llofstream ofs(filename, std::ios::app | std::ios::binary); + llofstream ofs(mPath, std::ios::app | std::ios::binary); if (ofs) { ofs.write((const char*)buffer, bytes); @@ -183,7 +169,7 @@ bool LLFileSystem::write(const U8* buffer, S32 bytes) else if (mMode == READ_WRITE) { // Don't truncate if file already exists - llofstream ofs(filename, std::ios::in | std::ios::binary); + llofstream ofs(mPath, std::ios::in | std::ios::binary); if (ofs) { ofs.seekp(mPosition, std::ios::beg); @@ -194,7 +180,7 @@ bool LLFileSystem::write(const U8* buffer, S32 bytes) else { // File doesn't exist - open in write mode - ofs.open(filename, std::ios::binary); + ofs.open(mPath, std::ios::binary); if (ofs.is_open()) { ofs.write((const char*)buffer, bytes); @@ -205,7 +191,7 @@ bool LLFileSystem::write(const U8* buffer, S32 bytes) } else { - llofstream ofs(filename, std::ios::binary); + llofstream ofs(mPath, std::ios::binary); if (ofs) { ofs.write((const char*)buffer, bytes); @@ -256,7 +242,7 @@ S32 LLFileSystem::tell() const S32 LLFileSystem::getSize() const { - return (S32)LLFileSystem::getFileSize(mFileID, mFileType); + return narrow(LLFile::size(mPath)); } S32 LLFileSystem::getMaxSize() const @@ -271,17 +257,18 @@ bool LLFileSystem::rename(const LLUUID& new_id, const LLAssetType::EType new_typ mFileID = new_id; mFileType = new_type; + mPath = fsyspath(LLDiskCache::metaDataToFilepath(mFileID, mFileType)); return true; } bool LLFileSystem::remove() const { - LLFileSystem::removeFile(mFileID, mFileType); + LLFile::remove(mPath); return true; } -void LLFileSystem::updateFileAccessTime(const std::string& file_path) +void LLFileSystem::updateFileAccessTime() { /** * Threshold in time_t units that is used to decide if the last access time @@ -292,52 +279,32 @@ void LLFileSystem::updateFileAccessTime(const std::string& file_path) * * Let's start with 1 hour in time_t units and see how that unfolds */ - constexpr std::time_t time_threshold = 1 * 60 * 60; + constexpr std::chrono::hours time_threshold(1); // current time - const std::time_t cur_time = std::time(nullptr); - - boost::system::error_code ec; -#if LL_WINDOWS - // file last write time - const std::time_t last_write_time = boost::filesystem::last_write_time(ll_convert(file_path), ec); - if (ec.failed()) - { - LL_WARNS() << "Failed to read last write time for cache file " << file_path << ": " << ec.message() << LL_ENDL; - return; - } - - // delta between cur time and last time the file was written - const std::time_t delta_time = cur_time - last_write_time; + const std::filesystem::file_time_type cur_time = std::chrono::file_clock::now(); - // we only write the new value if the time in time_threshold has elapsed - // before the last one - if (delta_time > time_threshold) - { - boost::filesystem::last_write_time(ll_convert(file_path), cur_time, ec); - } -#else + std::error_code ec; // file last write time - const std::time_t last_write_time = boost::filesystem::last_write_time(file_path, ec); - if (ec.failed()) + const std::filesystem::file_time_type last_write_time = std::filesystem::last_write_time(mPath, ec); + if (ec) { - LL_WARNS() << "Failed to read last write time for cache file " << file_path << ": " << ec.message() << LL_ENDL; + LL_WARNS() << "Failed to read last write time for cache file " << mPath << ": " << ec.message() << LL_ENDL; return; } // delta between cur time and last time the file was written - const std::time_t delta_time = cur_time - last_write_time; + const auto delta_time = cur_time - last_write_time; // we only write the new value if the time in time_threshold has elapsed // before the last one if (delta_time > time_threshold) { - boost::filesystem::last_write_time(file_path, cur_time, ec); + std::filesystem::last_write_time(mPath, cur_time, ec); } -#endif - if (ec.failed()) + if (ec) { - LL_WARNS() << "Failed to update last write time for cache file " << file_path << ": " << ec.message() << LL_ENDL; + LL_WARNS() << "Failed to update last write time for cache file " << mPath << ": " << ec.message() << LL_ENDL; } } diff --git a/indra/llfilesystem/llfilesystem.h b/indra/llfilesystem/llfilesystem.h index 7188683e7f..bc8b9216bd 100644 --- a/indra/llfilesystem/llfilesystem.h +++ b/indra/llfilesystem/llfilesystem.h @@ -33,6 +33,7 @@ #include "lluuid.h" #include "llassettype.h" #include "lldiskcache.h" +#include class LLFileSystem { @@ -58,13 +59,12 @@ class LLFileSystem * file in the cache is read (not written) so that the last time the file was * accessed is up to date (This is used in the mechanism for purging the cache) */ - void updateFileAccessTime(const std::string& file_path); + void updateFileAccessTime(); static bool getExists(const LLUUID& file_id, const LLAssetType::EType file_type); static bool removeFile(const LLUUID& file_id, const LLAssetType::EType file_type, int suppress_warning = 0); static bool renameFile(const LLUUID& old_file_id, const LLAssetType::EType old_file_type, const LLUUID& new_file_id, const LLAssetType::EType new_file_type); - static S64 getFileSize(const LLUUID& file_id, const LLAssetType::EType file_type); public: static const S32 READ; @@ -73,6 +73,7 @@ class LLFileSystem static const S32 APPEND; protected: + std::filesystem::path mPath; LLAssetType::EType mFileType; LLUUID mFileID; S32 mPosition; diff --git a/indra/llfilesystem/tests/lldir_test.cpp b/indra/llfilesystem/tests/lldir_test.cpp index 8b86da40b3..b879fef48a 100644 --- a/indra/llfilesystem/tests/lldir_test.cpp +++ b/indra/llfilesystem/tests/lldir_test.cpp @@ -405,7 +405,7 @@ namespace tut std::string makeTestFile( const std::string& dir, const std::string& file ) { std::string path = dir + file; - LLFILE* handle = LLFile::fopen( path, "w" ); + LLFILE* handle = LLFile::fopen(path, TEXT("w")); ensure("failed to open test file '"+path+"'", handle != NULL ); // Harbison & Steele, 4th ed., p. 366: "If an error occurs, fputs // returns EOF; otherwise, it returns some other, nonnegative value." diff --git a/indra/llimage/llimagedimensionsinfo.cpp b/indra/llimage/llimagedimensionsinfo.cpp index c896d60c85..1d93014e1b 100644 --- a/indra/llimage/llimagedimensionsinfo.cpp +++ b/indra/llimage/llimagedimensionsinfo.cpp @@ -166,7 +166,7 @@ bool LLImageDimensionsInfo::getImageDimensionsJpeg() { sJpegErrorEncountered = false; clean(); - FILE* fp = LLFile::fopen(mSrcFilename, "rb"); + FILE* fp = LLFile::fopen(mSrcFilename, TEXT("rb")); if (!fp) { setLastError("Unable to open file for reading", mSrcFilename); diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp index 25232b77aa..7c6686db95 100644 --- a/indra/llimage/llimagetga.cpp +++ b/indra/llimage/llimagetga.cpp @@ -1191,7 +1191,7 @@ bool LLImageTGA::loadFile( const std::string& path ) return false; } - LLFILE* file = LLFile::fopen(path, "rb"); /* Flawfinder: ignore */ + LLFILE* file = LLFile::fopen(path, TEXT("rb")); /* Flawfinder: ignore */ if( !file ) { LL_WARNS() << "Couldn't open file " << path << LL_ENDL; diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index 34eeacb273..13be0161b4 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -1402,7 +1402,7 @@ void LLAssetStorage::legacyGetDataCallback(const LLUUID &uuid, uuid.toString(uuid_str); filename = llformat("%s.%s",gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str(),LLAssetType::lookup(type)); - LLFILE* fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ + LLFILE* fp = LLFile::fopen(filename, TEXT("wb")); /* Flawfinder: ignore */ if (fp) { const S32 buf_size = 65536; diff --git a/indra/llmessage/lltransfersourcefile.cpp b/indra/llmessage/lltransfersourcefile.cpp index 77a6c466c7..c2bf5c2afa 100644 --- a/indra/llmessage/lltransfersourcefile.cpp +++ b/indra/llmessage/lltransfersourcefile.cpp @@ -62,7 +62,7 @@ void LLTransferSourceFile::initTransfer() return; } // Look for the file. - mFP = LLFile::fopen(mParams.getFilename(), "rb"); /* Flawfinder: ignore */ + mFP = LLFile::fopen(mParams.getFilename(), TEXT("rb")); /* Flawfinder: ignore */ if (!mFP) { sendTransferStatus(LLTS_ERROR); diff --git a/indra/llmessage/lltransfertargetfile.cpp b/indra/llmessage/lltransfertargetfile.cpp index 6d8b69fa6f..cc66befcae 100644 --- a/indra/llmessage/lltransfertargetfile.cpp +++ b/indra/llmessage/lltransfertargetfile.cpp @@ -75,7 +75,7 @@ LLTSCode LLTransferTargetFile::dataCallback(const S32 packet_id, U8 *in_datap, c if (!mFP) { - mFP = LLFile::fopen(mParams.mFilename, "wb"); /* Flawfinder: ignore */ + mFP = LLFile::fopen(mParams.mFilename, TEXT("wb")); /* Flawfinder: ignore */ if (!mFP) { diff --git a/indra/llmessage/llxfer_file.cpp b/indra/llmessage/llxfer_file.cpp index 71b910297b..f0310c6297 100644 --- a/indra/llmessage/llxfer_file.cpp +++ b/indra/llmessage/llxfer_file.cpp @@ -161,7 +161,7 @@ S32 LLXfer_File::initializeRequest(U64 xfer_id, S32 LLXfer_File::startDownload() { S32 retval = 0; // presume success - mFp = LLFile::fopen(mTempFilename,"w+b"); /* Flawfinder : ignore */ + mFp = LLFile::fopen(mTempFilename,TEXT("w+b")); /* Flawfinder : ignore */ if (mFp) { fclose(mFp); @@ -209,7 +209,7 @@ S32 LLXfer_File::startSend (U64 xfer_id, const LLHost &remote_host) mBufferStartOffset = 0; // We leave the file open, assuming we'll start reading and sending soon - mFp = LLFile::fopen(mLocalFilename,"rb"); /* Flawfinder : ignore */ + mFp = LLFile::fopen(mLocalFilename,TEXT("rb")); /* Flawfinder : ignore */ if (mFp) { fseek(mFp,0,SEEK_END); @@ -252,7 +252,7 @@ S32 LLXfer_File::reopenFileHandle() if (mFp == NULL) { - mFp = LLFile::fopen(mLocalFilename,"rb"); /* Flawfinder : ignore */ + mFp = LLFile::fopen(mLocalFilename,TEXT("rb")); /* Flawfinder : ignore */ if (mFp == NULL) { LL_INFOS("Xfer") << "Warning: " << mLocalFilename << " not found when re-opening file" << LL_ENDL; @@ -313,7 +313,7 @@ S32 LLXfer_File::flush() { LL_ERRS("Xfer") << "Overwriting open file pointer!" << LL_ENDL; } - mFp = LLFile::fopen(mTempFilename,"a+b"); /* Flawfinder : ignore */ + mFp = LLFile::fopen(mTempFilename,TEXT("a+b")); /* Flawfinder : ignore */ if (mFp) { @@ -381,11 +381,11 @@ S32 LLXfer_File::processEOF() } else { - //LLFILE* fp = LLFile::fopen(mTempFilename, "r"); + //LLFILE* fp = LLFile::fopen(mTempFilename, TEXT("r")); //LL_WARNS() << "File " << mTempFilename << " does " // << (!fp ? "not" : "" ) << " exit." << LL_ENDL; //if(fp) fclose(fp); - //fp = LLFile::fopen(mLocalFilename, "r"); + //fp = LLFile::fopen(mLocalFilename, TEXT("r")); //LL_WARNS() << "File " << mLocalFilename << " does " // << (!fp ? "not" : "" ) << " exit." << LL_ENDL; //if(fp) fclose(fp); @@ -452,8 +452,8 @@ U32 LLXfer_File::getXferTypeTag() S32 copy_file(const std::string& from, const std::string& to) { S32 rv = 0; - LLFILE* in = LLFile::fopen(from, "rb"); /*Flawfinder: ignore*/ - LLFILE* out = LLFile::fopen(to, "wb"); /*Flawfinder: ignore*/ + LLFILE* in = LLFile::fopen(from, TEXT("rb")); /*Flawfinder: ignore*/ + LLFILE* out = LLFile::fopen(to, TEXT("wb")); /*Flawfinder: ignore*/ if(in && out) { S32 read = 0; diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index e2937490ba..5b3b57f11e 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -2376,7 +2376,7 @@ void dump_prehash_files() { U32 i; std::string filename("../../indra/llmessage/message_prehash.h"); - LLFILE* fp = LLFile::fopen(filename, "w"); /* Flawfinder: ignore */ + LLFILE* fp = LLFile::fopen(filename, TEXT("w")); /* Flawfinder: ignore */ if (fp) { fprintf( @@ -2407,7 +2407,7 @@ void dump_prehash_files() fclose(fp); } filename = std::string("../../indra/llmessage/message_prehash.cpp"); - fp = LLFile::fopen(filename, "w"); /* Flawfinder: ignore */ + fp = LLFile::fopen(filename, TEXT("w")); /* Flawfinder: ignore */ if (fp) { fprintf( diff --git a/indra/llmessage/tests/lldatapacker_test.cpp b/indra/llmessage/tests/lldatapacker_test.cpp index 746817936d..92a2c31ca8 100644 --- a/indra/llmessage/tests/lldatapacker_test.cpp +++ b/indra/llmessage/tests/lldatapacker_test.cpp @@ -348,7 +348,7 @@ namespace tut { F32 f_val = 44.44f, f_unpkval; - LLFILE* fp = LLFile::fopen(TEST_FILE_NAME, "w+"); + LLFILE* fp = LLFile::fopen(TEST_FILE_NAME, TEXT("w+")); if(!fp) { LL_ERRS() << "File couldnt be open" << LL_ENDL; @@ -403,7 +403,7 @@ namespace tut LLVector4 unpkllvec4; LLUUID unpkuuid; - LLFILE* fp = LLFile::fopen(TEST_FILE_NAME,"w+"); + LLFILE* fp = LLFile::fopen(TEST_FILE_NAME,TEXT("w+")); if(!fp) { LL_ERRS() << "File couldnt be open" << LL_ENDL; diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 7e8d31232b..0ed98f2e7e 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -501,7 +501,7 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev open_file_name = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "shaders/errorF.glsl"); } - file = LLFile::fopen(open_file_name, "r"); + file = LLFile::fopen(open_file_name, TEXT("r")); } else #endif @@ -529,7 +529,7 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev */ LL_DEBUGS("ShaderLoading") << "Looking in " << open_file_name << LL_ENDL; - file = LLFile::fopen(open_file_name, "r"); /* Flawfinder: ignore */ + file = LLFile::fopen(open_file_name, TEXT("r")); /* Flawfinder: ignore */ if (file) { LL_DEBUGS("ShaderLoading") << "Loading file: " << open_file_name << " (Want class " << gpu_class << ")" << LL_ENDL; diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp index a792cb8103..206d02b366 100644 --- a/indra/llui/lluicolortable.cpp +++ b/indra/llui/lluicolortable.cpp @@ -298,7 +298,7 @@ void LLUIColorTable::saveUserSettings() const if(!output_node->isNull()) { const std::string& filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "colors.xml"); - LLFILE *fp = LLFile::fopen(filename, "w"); + LLFILE *fp = LLFile::fopen(filename, TEXT("w")); if(fp != NULL) { diff --git a/indra/llui/llxuiparser.cpp b/indra/llui/llxuiparser.cpp index 8fd85a89a1..e3d806bdd0 100644 --- a/indra/llui/llxuiparser.cpp +++ b/indra/llui/llxuiparser.cpp @@ -637,7 +637,7 @@ void LLXUIXSDWriter::writeXSD(const std::string& type_name, const std::string& p } } - LLFILE* xsd_file = LLFile::fopen(file_name.c_str(), "w"); + LLFILE* xsd_file = LLFile::fopen(file_name.c_str(), TEXT("w")); LLXMLNode::writeHeaderToFile(xsd_file); root_nodep->writeToFile(xsd_file); fclose(xsd_file); @@ -1326,7 +1326,7 @@ void LLXUIParser::parserError(const std::string& message) struct ScopedFile { - ScopedFile( const std::string& filename, const char* accessmode ) + ScopedFile( const std::string& filename, const LLFile::fopen_flags_t* accessmode ) { mFile = LLFile::fopen(filename, accessmode); } @@ -1397,7 +1397,7 @@ bool LLSimpleXUIParser::readXUI(const std::string& filename, LLInitParam::BaseBl mCurReadDepth = 0; setParseSilently(silent); - ScopedFile file(filename, "rb"); + ScopedFile file(filename, TEXT("rb")); if( !file.isOpen() ) { LL_WARNS("ReadXUI") << "Unable to open file " << filename << LL_ENDL; diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index 562a30e8d1..a8e44f7bdd 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -399,7 +399,7 @@ void LLControlGroup::cleanup() if(mSettingsProfile && getCount.size() != 0) { std::string file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, SETTINGS_PROFILE); - LLFILE* out = LLFile::fopen(file, "w"); /* Flawfinder: ignore */ + LLFILE* out = LLFile::fopen(file, TEXT("w")); /* Flawfinder: ignore */ if(!out) { LL_WARNS("SettingsProfile") << "Error opening " << SETTINGS_PROFILE << LL_ENDL; diff --git a/indra/llxml/llxmlparser.cpp b/indra/llxml/llxmlparser.cpp index e2c7d17e2a..5aac9100dd 100644 --- a/indra/llxml/llxmlparser.cpp +++ b/indra/llxml/llxmlparser.cpp @@ -72,7 +72,7 @@ bool LLXmlParser::parseFile(const std::string &path) bool success = true; - LLFILE* file = LLFile::fopen(path, "rb"); /* Flawfinder: ignore */ + LLFILE* file = LLFile::fopen(path, TEXT("rb")); /* Flawfinder: ignore */ if( !file ) { mAuxErrorString = llformat( "Couldn't open file %s", path.c_str()); @@ -388,7 +388,7 @@ int main() { char buf[1024]; - LLFILE* file = LLFile::fopen("test.xml", "rb"); + LLFILE* file = LLFile::fopen("test.xml", TEXT("rb")); if( !file ) { return 1; diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp index 4a4985d8ac..63a3743ef7 100644 --- a/indra/newview/llconversationlog.cpp +++ b/indra/newview/llconversationlog.cpp @@ -512,7 +512,7 @@ bool LLConversationLog::saveToFile(const std::string& filename) return false; } - LLFILE* fp = LLFile::fopen(filename, "wb"); + LLFILE* fp = LLFile::fopen(filename, TEXT("wb")); if (!fp) { LL_WARNS() << "Couldn't open call log list" << filename << LL_ENDL; @@ -556,7 +556,7 @@ bool LLConversationLog::loadFromFile(const std::string& filename) return false; } - LLFILE* fp = LLFile::fopen(filename, "rb"); + LLFILE* fp = LLFile::fopen(filename, TEXT("rb")); if (!fp) { LL_WARNS() << "Couldn't open call log list" << filename << LL_ENDL; diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 6c151351ff..200fce7b5b 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -114,7 +114,7 @@ void LLStandardBumpmap::addstandard() gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("Darkness"); // BE_DARKNESS std::string file_name = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "std_bump.ini" ); - LLFILE* file = LLFile::fopen( file_name, "rt" ); /*Flawfinder: ignore*/ + LLFILE* file = LLFile::fopen( file_name, TEXT("rt") ); /*Flawfinder: ignore*/ if( !file ) { LL_WARNS() << "Could not open std_bump <" << file_name << ">" << LL_ENDL; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 4fa14a199d..989dbc0c29 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -2037,9 +2037,13 @@ void LLFloaterPreference::changed() { // onClearLog clears list, then notifies changed() and only then clears file, // so check presence of conversations before checking file, file will cleared later. - bool has_logs = LLConversationLog::instance().getConversations().size() > 0 - && LLFile::isfile(LLConversationLog::instance().getFileName()) - && LLFile::size(LLConversationLog::instance().getFileName()) > 0; + bool has_logs = false; + if (LLConversationLog::instance().getConversations().size() > 0) + { + std::filesystem::path file_path = fsyspath(LLConversationLog::instance().getFileName()); + has_logs = LLFile::isfile(file_path) + && LLFile::size(file_path) > 0; + } getChild("clear_log")->setEnabled(has_logs); } diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 0bf0946c42..cf710d45dd 100755 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -574,7 +574,7 @@ void LLFloaterUIPreview::onClickExportSchema() // std::string file_name(template_path + gDirUtilp->getDirDelimiter() + widget_name + ".rng"); - // LLFILE* rng_file = LLFile::fopen(file_name.c_str(), "w"); + // LLFILE* rng_file = LLFile::fopen(file_name.c_str(), TEXT("w")); // { // LLXMLNode::writeHeaderToFile(rng_file); // const bool use_type_decorations = false; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 043fd7003d..9491c9d610 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2745,7 +2745,7 @@ bool LLInventoryModel::loadSkeleton( const S32 NO_VERSION = LLViewerInventoryCategory::VERSION_UNKNOWN; std::string gzip_filename(inventory_filename); gzip_filename.append(".gz"); - LLFILE* fp = LLFile::fopen(gzip_filename, "rb"); + LLFILE* fp = LLFile::fopen(gzip_filename, TEXT("rb")); bool remove_inventory_file = false; if (LLAppViewer::instance()->isSecondInstance()) { @@ -4908,7 +4908,7 @@ bool decompress_file(const char* src_filename, const char* dst_filename) // open the files src = gzopen(src_filename, "rb"); if(!src) goto err_decompress; - dst = LLFile::fopen(dst_filename, "wb"); + dst = LLFile::fopen(dst_filename, TEXT("wb")); if(!dst) goto err_decompress; // decompress. diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp index 666ab4f5d0..458d5225e1 100644 --- a/indra/newview/llkeyconflict.cpp +++ b/indra/newview/llkeyconflict.cpp @@ -575,7 +575,7 @@ void LLKeyConflictHandler::saveToSettings(bool temporary) // Write the resulting XML to file if (!output_node->isNull()) { - LLFILE *fp = LLFile::fopen(filename, "w"); + LLFILE *fp = LLFile::fopen(filename, TEXT("w")); if (fp != NULL) { LLXMLNode::writeHeaderToFile(fp); diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 30ea255e24..405530f5bd 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -453,7 +453,7 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list& m // If we got here, we managed to stat the file. // Open the file to read in binary mode to prevent interpreting other characters as EOF - LLFILE* fptr = LLFile::fopen(log_file_name, "rb"); /*Flawfinder: ignore*/ + LLFILE* fptr = LLFile::fopen(log_file_name, TEXT("rb")); /*Flawfinder: ignore*/ if (!fptr) { // Ok, this is strange but not really tragic in the big picture of things LL_WARNS("ChatHistory") << "Unable to read file " << log_file_name << " after stat was successful" << LL_ENDL; @@ -890,7 +890,7 @@ bool LLLogChat::isAdHocTranscriptExist(std::string file_name) bool LLLogChat::isTranscriptFileFound(std::string fullname) { bool result = false; - LLFILE * filep = LLFile::fopen(fullname, "rb"); + LLFILE * filep = LLFile::fopen(fullname, TEXT("rb")); if (NULL != filep) { if (makeLogFileName("chat") == fullname) @@ -1183,7 +1183,7 @@ void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::listgetExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "render_mute_settings.txt"); - LLFILE* fp = LLFile::fopen(filename, "wb"); + LLFILE* fp = LLFile::fopen(filename, TEXT("wb")); if (!fp) { LL_WARNS() << "Couldn't open render mute list file: " << filename << LL_ENDL; @@ -963,7 +963,7 @@ bool LLRenderMuteList::saveToFile() bool LLRenderMuteList::loadFromFile() { std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "render_mute_settings.txt"); - LLFILE* fp = LLFile::fopen(filename, "rb"); + LLFILE* fp = LLFile::fopen(filename, TEXT("rb")); if (!fp) { LL_WARNS() << "Couldn't open render mute list file: " << filename << LL_ENDL; diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 4fe661b055..6928d7e6c3 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -801,7 +801,7 @@ bool LLPreviewNotecard::loadNotecardText(const std::string& filename) return false; } - LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ + LLFILE* file = LLFile::fopen(filename, TEXT("rb")); /*Flawfinder: ignore*/ if (!file) { LL_WARNS() << "Error opening " << filename << LL_ENDL; @@ -832,7 +832,7 @@ bool LLPreviewNotecard::loadNotecardText(const std::string& filename) bool LLPreviewNotecard::writeToFile(const std::string& filename) { - LLFILE* fp = LLFile::fopen(filename, "wb"); + LLFILE* fp = LLFile::fopen(filename, TEXT("wb")); if (!fp) { LL_WARNS() << "Unable to write to " << filename << LL_ENDL; diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 2c436198e3..c73976e540 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -632,7 +632,7 @@ bool LLScriptEdCore::loadScriptText(const std::string& filename) return false; } - LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ + LLFILE* file = LLFile::fopen(filename, TEXT("rb")); /*Flawfinder: ignore*/ if (!file) { LL_WARNS() << "Error opening " << filename << LL_ENDL; @@ -663,7 +663,7 @@ bool LLScriptEdCore::loadScriptText(const std::string& filename) bool LLScriptEdCore::writeToFile(const std::string& filename) { - LLFILE* fp = LLFile::fopen(filename, "wb"); + LLFILE* fp = LLFile::fopen(filename, TEXT("wb")); if (!fp) { LL_WARNS() << "Unable to write to " << filename << LL_ENDL; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 3ce9526488..37609f74ed 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -587,7 +587,7 @@ bool idle_startup() std::string message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message_template.msg"); LLFILE* found_template = NULL; - found_template = LLFile::fopen(message_template_path, "r"); /* Flawfinder: ignore */ + found_template = LLFile::fopen(message_template_path, TEXT("r")); /* Flawfinder: ignore */ #if LL_WINDOWS // On the windows dev builds, unpackaged, the message_template.msg @@ -596,7 +596,7 @@ bool idle_startup() if (!found_template) { message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "message_template.msg"); - found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ + found_template = LLFile::fopen(message_template_path.c_str(), TEXT("r")); /* Flawfinder: ignore */ } #elif LL_DARWIN // On Mac dev builds, message_template.msg lives in: @@ -606,7 +606,7 @@ bool idle_startup() message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "message_template.msg"); - found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ + found_template = LLFile::fopen(message_template_path.c_str(), TEXT("r")); /* Flawfinder: ignore */ } #endif diff --git a/indra/newview/lltoolbarview.cpp b/indra/newview/lltoolbarview.cpp index c1ec5fa183..d1e36676af 100644 --- a/indra/newview/lltoolbarview.cpp +++ b/indra/newview/lltoolbarview.cpp @@ -420,7 +420,7 @@ void LLToolBarView::saveToolbars() const if(!output_node->isNull()) { const std::string& filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "toolbars.xml"); - LLFILE *fp = LLFile::fopen(filename, "w"); + LLFILE *fp = LLFile::fopen(filename, TEXT("w")); if (fp != NULL) { LLXMLNode::writeHeaderToFile(fp); diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index e76d340eda..c28f3dc73a 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -182,7 +182,7 @@ void LLViewerAssetStorage::storeAssetData( else { // LLAssetStorage metric: Successful Request - S32 size = (S32)LLFileSystem::getFileSize(asset_id, asset_type); + S32 size = vfile.getSize(); const char *message = "Added to upload queue"; reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, size, MR_OKAY, __FILE__, __LINE__, message ); @@ -279,7 +279,7 @@ void LLViewerAssetStorage::storeAssetData( LL_DEBUGS("AssetStorage") << "ASSET_ID: " << asset_id << LL_ENDL; S32 size = 0; - LLFILE* fp = LLFile::fopen(filename, "rb"); + LLFILE* fp = LLFile::fopen(filename, TEXT("rb")); if (fp) { fseek(fp, 0, SEEK_END); diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp index 3c79f0b21c..9b39f7b0e9 100644 --- a/indra/newview/llviewerinput.cpp +++ b/indra/newview/llviewerinput.cpp @@ -1430,7 +1430,7 @@ S32 LLViewerInput::loadBindingsXML(const std::string& filename) // file in app_settings is supposed to be up to date // this is only for the file from user_settings LL_INFOS("ViewerInput") << "Updating file " << filename << " to a newer version" << LL_ENDL; - LLFILE *fp = LLFile::fopen(filename, "w"); + LLFILE *fp = LLFile::fopen(filename, TEXT("w")); if (fp != NULL) { LLXMLNode::writeHeaderToFile(fp); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 0e9bfb102f..a8ed2da9e0 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -1161,7 +1161,7 @@ void handle_compress_image() // so doing dirty, but OS independent fopen and fseek size_t get_file_size(std::string &filename) { - LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ + LLFILE* file = LLFile::fopen(filename, TEXT("rb")); /*Flawfinder: ignore*/ if (!file) { LL_WARNS() << "Error opening " << filename << LL_ENDL; diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index 58065ecce5..a2141f4eed 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -194,7 +194,7 @@ void LLViewerStatsRecorder::writeToLog( F32 interval ) // Open the data file makeStatsFileName(); - mStatsFile = LLFile::fopen(mStatsFileName, "wb"); + mStatsFile = LLFile::fopen(mStatsFileName, TEXT("wb")); if (mStatsFile) { -- cgit v1.3 From 9873abfb94f0d9cbc6df60fef9df622ef51355ec Mon Sep 17 00:00:00 2001 From: Rye Date: Mon, 5 Jan 2026 15:01:23 -0500 Subject: Address feedback from copilot Signed-off-by: Rye --- indra/llappearance/llpolymesh.cpp | 2 +- indra/llcommon/llcrc.cpp | 2 +- indra/llcommon/llcrc.h | 2 +- indra/llcommon/llfile.h | 10 ++++------ indra/llcommon/llprocessor.cpp | 4 ++-- indra/llcommon/llsys.cpp | 6 +++--- indra/llfilesystem/lldir.cpp | 2 +- indra/llfilesystem/tests/lldir_test.cpp | 2 +- indra/llimage/llimagedimensionsinfo.cpp | 2 +- indra/llimage/llimagetga.cpp | 2 +- indra/llmessage/llassetstorage.cpp | 2 +- indra/llmessage/lltransfersourcefile.cpp | 2 +- indra/llmessage/lltransfertargetfile.cpp | 2 +- indra/llmessage/llxfer_file.cpp | 16 ++++++++-------- indra/llmessage/message.cpp | 4 ++-- indra/llmessage/tests/lldatapacker_test.cpp | 4 ++-- indra/llrender/llshadermgr.cpp | 4 ++-- indra/llui/lluicolortable.cpp | 2 +- indra/llui/llxuiparser.cpp | 4 ++-- indra/llxml/llcontrol.cpp | 2 +- indra/llxml/llxmlparser.cpp | 4 ++-- indra/newview/llconversationlog.cpp | 4 ++-- indra/newview/lldrawpoolbump.cpp | 2 +- indra/newview/llfloateruipreview.cpp | 2 +- indra/newview/llinventorymodel.cpp | 4 ++-- indra/newview/llkeyconflict.cpp | 2 +- indra/newview/lllogchat.cpp | 12 ++++++------ indra/newview/llmutelist.cpp | 8 ++++---- indra/newview/llpreviewnotecard.cpp | 4 ++-- indra/newview/llpreviewscript.cpp | 4 ++-- indra/newview/llstartup.cpp | 6 +++--- indra/newview/lltoolbarview.cpp | 2 +- indra/newview/llviewerassetstorage.cpp | 2 +- indra/newview/llviewerinput.cpp | 2 +- indra/newview/llviewermenufile.cpp | 2 +- indra/newview/llviewerstatsrecorder.cpp | 2 +- 36 files changed, 68 insertions(+), 70 deletions(-) (limited to 'indra/llxml') diff --git a/indra/llappearance/llpolymesh.cpp b/indra/llappearance/llpolymesh.cpp index b579dc007b..45f51950ec 100644 --- a/indra/llappearance/llpolymesh.cpp +++ b/indra/llappearance/llpolymesh.cpp @@ -280,7 +280,7 @@ bool LLPolyMeshSharedData::loadMesh( const std::string& fileName ) LL_ERRS() << "Filename is Empty!" << LL_ENDL; return false; } - LLFILE* fp = LLFile::fopen(fileName, TEXT("rb")); /*Flawfinder: ignore*/ + LLFILE* fp = LLFile::fopen(fileName, LLFILE_MODE("rb")); /*Flawfinder: ignore*/ if (!fp) { LLError::LLUserWarningMsg::showMissingFiles(); diff --git a/indra/llcommon/llcrc.cpp b/indra/llcommon/llcrc.cpp index f836a12c35..33bf01a29b 100644 --- a/indra/llcommon/llcrc.cpp +++ b/indra/llcommon/llcrc.cpp @@ -166,7 +166,7 @@ void LLCRC::update(const std::string& filename) return; } - FILE* fp = LLFile::fopen(filename, TEXT("rb")); /* Flawfinder: ignore */ + FILE* fp = LLFile::fopen(filename, LLFILE_MODE("rb")); /* Flawfinder: ignore */ if (fp) { diff --git a/indra/llcommon/llcrc.h b/indra/llcommon/llcrc.h index cbf4cf4e75..2ea5fbc3b0 100644 --- a/indra/llcommon/llcrc.h +++ b/indra/llcommon/llcrc.h @@ -36,7 +36,7 @@ // example (don't try this at work kids): // // LLCRC crc; -// FILE* fp = LLFile::fopen(filename,TEXT("rb")); +// FILE* fp = LLFile::fopen(filename,LLFILE_MODE("rb")); // while(!feof(fp)) { // crc.update(fgetc(fp)); // } diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index 7e8e114098..8de3f5c9b4 100755 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -56,12 +56,10 @@ typedef FILE LLFILE; #include "fsyspath.h" #include "llstring.h" // safe char* -> std::string conversion -#ifndef TEXT #if LL_WINDOWS -#define TEXT(flags) L##flags +#define LLFILE_MODE(flags) L##flags #else -#define TEXT(flags) flags -#endif +#define LLFILE_MODE(flags) flags #endif /// This class provides a selection of functions to operate on files through names and @@ -415,7 +413,7 @@ public: std::error_code ec; return copy(source, target, std::filesystem::copy_options::overwrite_existing, ec); } - inline static bool copy(const std::string& source, char* target) + inline static bool copy(const std::string& source, const char* target) { std::error_code ec; return copy(source, target, std::filesystem::copy_options::overwrite_existing, ec); @@ -686,7 +684,7 @@ private: #else typedef int llfile_handle_t; const llfile_handle_t InvalidHandle = -1; - llfile_handle_t mHandle = -1;; // The file handle/descriptor + llfile_handle_t mHandle = -1; // The file handle/descriptor #endif std::ios_base::openmode mOpen{}; // Used to emulate std::ios_base::app under Windows diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index 7656986fe2..9d0ef45bee 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -837,7 +837,7 @@ private: void get_proc_cpuinfo() { std::map< std::string, std::string > cpuinfo; - LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, TEXT("rb")); + LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, LLFILE_MODE("rb")); if(cpuinfo_fp) { char line[MAX_STRING]; @@ -954,7 +954,7 @@ private: std::ostringstream s; // *NOTE:Mani - This is for linux only. - LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, TEXT("rb")); + LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, LLFILE_MODE("rb")); if(cpuinfo) { char line[MAX_STRING]; diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 499de996e2..5ef042b5a7 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -514,7 +514,7 @@ namespace { #if LL_LINUX constexpr U32 STATUS_SIZE = 2048; - LLFILE* status_filep = LLFile::fopen("/proc/self/status", TEXT("rb")); + LLFILE* status_filep = LLFile::fopen("/proc/self/status", LLFILE_MODE("rb")); if (status_filep) { char buff[STATUS_SIZE]; /* Flawfinder: ignore */ @@ -1273,7 +1273,7 @@ bool gunzip_file(const std::string& srcfile, const std::string& dstfile) src = gzopen(srcfile.c_str(), "rb"); #endif if (! src) goto err; - dst = LLFile::fopen(tmpfile, TEXT("wb")); /* Flawfinder: ignore */ + dst = LLFile::fopen(tmpfile, LLFILE_MODE("wb")); /* Flawfinder: ignore */ if (! dst) goto err; do { @@ -1314,7 +1314,7 @@ bool gzip_file(const std::string& srcfile, const std::string& dstfile) #endif if (! dst) goto err; - src = LLFile::fopen(srcfile, TEXT("rb")); /* Flawfinder: ignore */ + src = LLFile::fopen(srcfile, LLFILE_MODE("rb")); /* Flawfinder: ignore */ if (! src) goto err; while ((bytes = (S32)fread(buffer, sizeof(U8), COMPRESS_BUFFER_SIZE, src)) > 0) diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp index 3ec8983e8a..1a647362c5 100755 --- a/indra/llfilesystem/lldir.cpp +++ b/indra/llfilesystem/lldir.cpp @@ -1010,7 +1010,7 @@ bool LLDir::setCacheDir(const std::string &path) { LLFile::mkdir(path); std::string tempname = add(path, "temp"); - LLFILE* file = LLFile::fopen(tempname, TEXT("wt")); + LLFILE* file = LLFile::fopen(tempname, LLFILE_MODE("wt")); if (file) { fclose(file); diff --git a/indra/llfilesystem/tests/lldir_test.cpp b/indra/llfilesystem/tests/lldir_test.cpp index b879fef48a..412feb147b 100644 --- a/indra/llfilesystem/tests/lldir_test.cpp +++ b/indra/llfilesystem/tests/lldir_test.cpp @@ -405,7 +405,7 @@ namespace tut std::string makeTestFile( const std::string& dir, const std::string& file ) { std::string path = dir + file; - LLFILE* handle = LLFile::fopen(path, TEXT("w")); + LLFILE* handle = LLFile::fopen(path, LLFILE_MODE("w")); ensure("failed to open test file '"+path+"'", handle != NULL ); // Harbison & Steele, 4th ed., p. 366: "If an error occurs, fputs // returns EOF; otherwise, it returns some other, nonnegative value." diff --git a/indra/llimage/llimagedimensionsinfo.cpp b/indra/llimage/llimagedimensionsinfo.cpp index 1d93014e1b..2ae7760d4c 100644 --- a/indra/llimage/llimagedimensionsinfo.cpp +++ b/indra/llimage/llimagedimensionsinfo.cpp @@ -166,7 +166,7 @@ bool LLImageDimensionsInfo::getImageDimensionsJpeg() { sJpegErrorEncountered = false; clean(); - FILE* fp = LLFile::fopen(mSrcFilename, TEXT("rb")); + FILE* fp = LLFile::fopen(mSrcFilename, LLFILE_MODE("rb")); if (!fp) { setLastError("Unable to open file for reading", mSrcFilename); diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp index 7c6686db95..7b09553974 100644 --- a/indra/llimage/llimagetga.cpp +++ b/indra/llimage/llimagetga.cpp @@ -1191,7 +1191,7 @@ bool LLImageTGA::loadFile( const std::string& path ) return false; } - LLFILE* file = LLFile::fopen(path, TEXT("rb")); /* Flawfinder: ignore */ + LLFILE* file = LLFile::fopen(path, LLFILE_MODE("rb")); /* Flawfinder: ignore */ if( !file ) { LL_WARNS() << "Couldn't open file " << path << LL_ENDL; diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index 13be0161b4..a8f0554a71 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -1402,7 +1402,7 @@ void LLAssetStorage::legacyGetDataCallback(const LLUUID &uuid, uuid.toString(uuid_str); filename = llformat("%s.%s",gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str(),LLAssetType::lookup(type)); - LLFILE* fp = LLFile::fopen(filename, TEXT("wb")); /* Flawfinder: ignore */ + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("wb")); /* Flawfinder: ignore */ if (fp) { const S32 buf_size = 65536; diff --git a/indra/llmessage/lltransfersourcefile.cpp b/indra/llmessage/lltransfersourcefile.cpp index c2bf5c2afa..d2d264c520 100644 --- a/indra/llmessage/lltransfersourcefile.cpp +++ b/indra/llmessage/lltransfersourcefile.cpp @@ -62,7 +62,7 @@ void LLTransferSourceFile::initTransfer() return; } // Look for the file. - mFP = LLFile::fopen(mParams.getFilename(), TEXT("rb")); /* Flawfinder: ignore */ + mFP = LLFile::fopen(mParams.getFilename(), LLFILE_MODE("rb")); /* Flawfinder: ignore */ if (!mFP) { sendTransferStatus(LLTS_ERROR); diff --git a/indra/llmessage/lltransfertargetfile.cpp b/indra/llmessage/lltransfertargetfile.cpp index cc66befcae..05dba219ed 100644 --- a/indra/llmessage/lltransfertargetfile.cpp +++ b/indra/llmessage/lltransfertargetfile.cpp @@ -75,7 +75,7 @@ LLTSCode LLTransferTargetFile::dataCallback(const S32 packet_id, U8 *in_datap, c if (!mFP) { - mFP = LLFile::fopen(mParams.mFilename, TEXT("wb")); /* Flawfinder: ignore */ + mFP = LLFile::fopen(mParams.mFilename, LLFILE_MODE("wb")); /* Flawfinder: ignore */ if (!mFP) { diff --git a/indra/llmessage/llxfer_file.cpp b/indra/llmessage/llxfer_file.cpp index f0310c6297..5f27cc4827 100644 --- a/indra/llmessage/llxfer_file.cpp +++ b/indra/llmessage/llxfer_file.cpp @@ -161,7 +161,7 @@ S32 LLXfer_File::initializeRequest(U64 xfer_id, S32 LLXfer_File::startDownload() { S32 retval = 0; // presume success - mFp = LLFile::fopen(mTempFilename,TEXT("w+b")); /* Flawfinder : ignore */ + mFp = LLFile::fopen(mTempFilename,LLFILE_MODE("w+b")); /* Flawfinder : ignore */ if (mFp) { fclose(mFp); @@ -209,7 +209,7 @@ S32 LLXfer_File::startSend (U64 xfer_id, const LLHost &remote_host) mBufferStartOffset = 0; // We leave the file open, assuming we'll start reading and sending soon - mFp = LLFile::fopen(mLocalFilename,TEXT("rb")); /* Flawfinder : ignore */ + mFp = LLFile::fopen(mLocalFilename, LLFILE_MODE("rb")); /* Flawfinder : ignore */ if (mFp) { fseek(mFp,0,SEEK_END); @@ -252,7 +252,7 @@ S32 LLXfer_File::reopenFileHandle() if (mFp == NULL) { - mFp = LLFile::fopen(mLocalFilename,TEXT("rb")); /* Flawfinder : ignore */ + mFp = LLFile::fopen(mLocalFilename, LLFILE_MODE("rb")); /* Flawfinder : ignore */ if (mFp == NULL) { LL_INFOS("Xfer") << "Warning: " << mLocalFilename << " not found when re-opening file" << LL_ENDL; @@ -313,7 +313,7 @@ S32 LLXfer_File::flush() { LL_ERRS("Xfer") << "Overwriting open file pointer!" << LL_ENDL; } - mFp = LLFile::fopen(mTempFilename,TEXT("a+b")); /* Flawfinder : ignore */ + mFp = LLFile::fopen(mTempFilename, LLFILE_MODE("a+b")); /* Flawfinder : ignore */ if (mFp) { @@ -381,11 +381,11 @@ S32 LLXfer_File::processEOF() } else { - //LLFILE* fp = LLFile::fopen(mTempFilename, TEXT("r")); + //LLFILE* fp = LLFile::fopen(mTempFilename, LLFILE_MODE("r")); //LL_WARNS() << "File " << mTempFilename << " does " // << (!fp ? "not" : "" ) << " exit." << LL_ENDL; //if(fp) fclose(fp); - //fp = LLFile::fopen(mLocalFilename, TEXT("r")); + //fp = LLFile::fopen(mLocalFilename, LLFILE_MODE("r")); //LL_WARNS() << "File " << mLocalFilename << " does " // << (!fp ? "not" : "" ) << " exit." << LL_ENDL; //if(fp) fclose(fp); @@ -452,8 +452,8 @@ U32 LLXfer_File::getXferTypeTag() S32 copy_file(const std::string& from, const std::string& to) { S32 rv = 0; - LLFILE* in = LLFile::fopen(from, TEXT("rb")); /*Flawfinder: ignore*/ - LLFILE* out = LLFile::fopen(to, TEXT("wb")); /*Flawfinder: ignore*/ + LLFILE* in = LLFile::fopen(from, LLFILE_MODE("rb")); /*Flawfinder: ignore*/ + LLFILE* out = LLFile::fopen(to, LLFILE_MODE("wb")); /*Flawfinder: ignore*/ if(in && out) { S32 read = 0; diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 5b3b57f11e..df58c8a7f3 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -2376,7 +2376,7 @@ void dump_prehash_files() { U32 i; std::string filename("../../indra/llmessage/message_prehash.h"); - LLFILE* fp = LLFile::fopen(filename, TEXT("w")); /* Flawfinder: ignore */ + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("w")); /* Flawfinder: ignore */ if (fp) { fprintf( @@ -2407,7 +2407,7 @@ void dump_prehash_files() fclose(fp); } filename = std::string("../../indra/llmessage/message_prehash.cpp"); - fp = LLFile::fopen(filename, TEXT("w")); /* Flawfinder: ignore */ + fp = LLFile::fopen(filename, LLFILE_MODE("w")); /* Flawfinder: ignore */ if (fp) { fprintf( diff --git a/indra/llmessage/tests/lldatapacker_test.cpp b/indra/llmessage/tests/lldatapacker_test.cpp index 92a2c31ca8..5823980d43 100644 --- a/indra/llmessage/tests/lldatapacker_test.cpp +++ b/indra/llmessage/tests/lldatapacker_test.cpp @@ -348,7 +348,7 @@ namespace tut { F32 f_val = 44.44f, f_unpkval; - LLFILE* fp = LLFile::fopen(TEST_FILE_NAME, TEXT("w+")); + LLFILE* fp = LLFile::fopen(TEST_FILE_NAME, LLFILE_MODE("w+")); if(!fp) { LL_ERRS() << "File couldnt be open" << LL_ENDL; @@ -403,7 +403,7 @@ namespace tut LLVector4 unpkllvec4; LLUUID unpkuuid; - LLFILE* fp = LLFile::fopen(TEST_FILE_NAME,TEXT("w+")); + LLFILE* fp = LLFile::fopen(TEST_FILE_NAME, LLFILE_MODE("w+")); if(!fp) { LL_ERRS() << "File couldnt be open" << LL_ENDL; diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 0ed98f2e7e..f6738364a6 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -501,7 +501,7 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev open_file_name = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "shaders/errorF.glsl"); } - file = LLFile::fopen(open_file_name, TEXT("r")); + file = LLFile::fopen(open_file_name, LLFILE_MODE("r")); } else #endif @@ -529,7 +529,7 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev */ LL_DEBUGS("ShaderLoading") << "Looking in " << open_file_name << LL_ENDL; - file = LLFile::fopen(open_file_name, TEXT("r")); /* Flawfinder: ignore */ + file = LLFile::fopen(open_file_name, LLFILE_MODE("r")); /* Flawfinder: ignore */ if (file) { LL_DEBUGS("ShaderLoading") << "Loading file: " << open_file_name << " (Want class " << gpu_class << ")" << LL_ENDL; diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp index 206d02b366..cd062b23b8 100644 --- a/indra/llui/lluicolortable.cpp +++ b/indra/llui/lluicolortable.cpp @@ -298,7 +298,7 @@ void LLUIColorTable::saveUserSettings() const if(!output_node->isNull()) { const std::string& filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "colors.xml"); - LLFILE *fp = LLFile::fopen(filename, TEXT("w")); + LLFILE *fp = LLFile::fopen(filename, LLFILE_MODE("w")); if(fp != NULL) { diff --git a/indra/llui/llxuiparser.cpp b/indra/llui/llxuiparser.cpp index e3d806bdd0..9bf2f4220c 100644 --- a/indra/llui/llxuiparser.cpp +++ b/indra/llui/llxuiparser.cpp @@ -637,7 +637,7 @@ void LLXUIXSDWriter::writeXSD(const std::string& type_name, const std::string& p } } - LLFILE* xsd_file = LLFile::fopen(file_name.c_str(), TEXT("w")); + LLFILE* xsd_file = LLFile::fopen(file_name.c_str(), LLFILE_MODE("w")); LLXMLNode::writeHeaderToFile(xsd_file); root_nodep->writeToFile(xsd_file); fclose(xsd_file); @@ -1397,7 +1397,7 @@ bool LLSimpleXUIParser::readXUI(const std::string& filename, LLInitParam::BaseBl mCurReadDepth = 0; setParseSilently(silent); - ScopedFile file(filename, TEXT("rb")); + ScopedFile file(filename, LLFILE_MODE("rb")); if( !file.isOpen() ) { LL_WARNS("ReadXUI") << "Unable to open file " << filename << LL_ENDL; diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index a8e44f7bdd..24d2facc4c 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -399,7 +399,7 @@ void LLControlGroup::cleanup() if(mSettingsProfile && getCount.size() != 0) { std::string file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, SETTINGS_PROFILE); - LLFILE* out = LLFile::fopen(file, TEXT("w")); /* Flawfinder: ignore */ + LLFILE* out = LLFile::fopen(file, LLFILE_MODE("w")); /* Flawfinder: ignore */ if(!out) { LL_WARNS("SettingsProfile") << "Error opening " << SETTINGS_PROFILE << LL_ENDL; diff --git a/indra/llxml/llxmlparser.cpp b/indra/llxml/llxmlparser.cpp index 5aac9100dd..8afd412cda 100644 --- a/indra/llxml/llxmlparser.cpp +++ b/indra/llxml/llxmlparser.cpp @@ -72,7 +72,7 @@ bool LLXmlParser::parseFile(const std::string &path) bool success = true; - LLFILE* file = LLFile::fopen(path, TEXT("rb")); /* Flawfinder: ignore */ + LLFILE* file = LLFile::fopen(path, LLFILE_MODE("rb")); /* Flawfinder: ignore */ if( !file ) { mAuxErrorString = llformat( "Couldn't open file %s", path.c_str()); @@ -388,7 +388,7 @@ int main() { char buf[1024]; - LLFILE* file = LLFile::fopen("test.xml", TEXT("rb")); + LLFILE* file = LLFile::fopen("test.xml", LLFILE_MODE("rb")); if( !file ) { return 1; diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp index 63a3743ef7..bfcc2e4182 100644 --- a/indra/newview/llconversationlog.cpp +++ b/indra/newview/llconversationlog.cpp @@ -512,7 +512,7 @@ bool LLConversationLog::saveToFile(const std::string& filename) return false; } - LLFILE* fp = LLFile::fopen(filename, TEXT("wb")); + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("wb")); if (!fp) { LL_WARNS() << "Couldn't open call log list" << filename << LL_ENDL; @@ -556,7 +556,7 @@ bool LLConversationLog::loadFromFile(const std::string& filename) return false; } - LLFILE* fp = LLFile::fopen(filename, TEXT("rb")); + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("rb")); if (!fp) { LL_WARNS() << "Couldn't open call log list" << filename << LL_ENDL; diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 200fce7b5b..a42972205a 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -114,7 +114,7 @@ void LLStandardBumpmap::addstandard() gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("Darkness"); // BE_DARKNESS std::string file_name = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "std_bump.ini" ); - LLFILE* file = LLFile::fopen( file_name, TEXT("rt") ); /*Flawfinder: ignore*/ + LLFILE* file = LLFile::fopen( file_name, LLFILE_MODE("rt") ); /*Flawfinder: ignore*/ if( !file ) { LL_WARNS() << "Could not open std_bump <" << file_name << ">" << LL_ENDL; diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index cf710d45dd..637871da0d 100755 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -574,7 +574,7 @@ void LLFloaterUIPreview::onClickExportSchema() // std::string file_name(template_path + gDirUtilp->getDirDelimiter() + widget_name + ".rng"); - // LLFILE* rng_file = LLFile::fopen(file_name.c_str(), TEXT("w")); + // LLFILE* rng_file = LLFile::fopen(file_name.c_str(), LLFILE_MODE("w")); // { // LLXMLNode::writeHeaderToFile(rng_file); // const bool use_type_decorations = false; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 9491c9d610..c34df48f7d 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2745,7 +2745,7 @@ bool LLInventoryModel::loadSkeleton( const S32 NO_VERSION = LLViewerInventoryCategory::VERSION_UNKNOWN; std::string gzip_filename(inventory_filename); gzip_filename.append(".gz"); - LLFILE* fp = LLFile::fopen(gzip_filename, TEXT("rb")); + LLFILE* fp = LLFile::fopen(gzip_filename, LLFILE_MODE("rb")); bool remove_inventory_file = false; if (LLAppViewer::instance()->isSecondInstance()) { @@ -4908,7 +4908,7 @@ bool decompress_file(const char* src_filename, const char* dst_filename) // open the files src = gzopen(src_filename, "rb"); if(!src) goto err_decompress; - dst = LLFile::fopen(dst_filename, TEXT("wb")); + dst = LLFile::fopen(dst_filename, LLFILE_MODE("wb")); if(!dst) goto err_decompress; // decompress. diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp index 458d5225e1..c082c632f1 100644 --- a/indra/newview/llkeyconflict.cpp +++ b/indra/newview/llkeyconflict.cpp @@ -575,7 +575,7 @@ void LLKeyConflictHandler::saveToSettings(bool temporary) // Write the resulting XML to file if (!output_node->isNull()) { - LLFILE *fp = LLFile::fopen(filename, TEXT("w")); + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("w")); if (fp != NULL) { LLXMLNode::writeHeaderToFile(fp); diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 405530f5bd..59f6993a0b 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -453,7 +453,7 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list& m // If we got here, we managed to stat the file. // Open the file to read in binary mode to prevent interpreting other characters as EOF - LLFILE* fptr = LLFile::fopen(log_file_name, TEXT("rb")); /*Flawfinder: ignore*/ + LLFILE* fptr = LLFile::fopen(log_file_name, LLFILE_MODE("rb")); /*Flawfinder: ignore*/ if (!fptr) { // Ok, this is strange but not really tragic in the big picture of things LL_WARNS("ChatHistory") << "Unable to read file " << log_file_name << " after stat was successful" << LL_ENDL; @@ -890,7 +890,7 @@ bool LLLogChat::isAdHocTranscriptExist(std::string file_name) bool LLLogChat::isTranscriptFileFound(std::string fullname) { bool result = false; - LLFILE * filep = LLFile::fopen(fullname, TEXT("rb")); + LLFILE * filep = LLFile::fopen(fullname, LLFILE_MODE("rb")); if (NULL != filep) { if (makeLogFileName("chat") == fullname) @@ -1183,7 +1183,7 @@ void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::listgetExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "render_mute_settings.txt"); - LLFILE* fp = LLFile::fopen(filename, TEXT("wb")); + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("wb")); if (!fp) { LL_WARNS() << "Couldn't open render mute list file: " << filename << LL_ENDL; @@ -963,7 +963,7 @@ bool LLRenderMuteList::saveToFile() bool LLRenderMuteList::loadFromFile() { std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "render_mute_settings.txt"); - LLFILE* fp = LLFile::fopen(filename, TEXT("rb")); + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("rb")); if (!fp) { LL_WARNS() << "Couldn't open render mute list file: " << filename << LL_ENDL; diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 6928d7e6c3..cecda23e7b 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -801,7 +801,7 @@ bool LLPreviewNotecard::loadNotecardText(const std::string& filename) return false; } - LLFILE* file = LLFile::fopen(filename, TEXT("rb")); /*Flawfinder: ignore*/ + LLFILE* file = LLFile::fopen(filename, LLFILE_MODE("rb")); /*Flawfinder: ignore*/ if (!file) { LL_WARNS() << "Error opening " << filename << LL_ENDL; @@ -832,7 +832,7 @@ bool LLPreviewNotecard::loadNotecardText(const std::string& filename) bool LLPreviewNotecard::writeToFile(const std::string& filename) { - LLFILE* fp = LLFile::fopen(filename, TEXT("wb")); + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("wb")); if (!fp) { LL_WARNS() << "Unable to write to " << filename << LL_ENDL; diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index c73976e540..53d0a712a8 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -632,7 +632,7 @@ bool LLScriptEdCore::loadScriptText(const std::string& filename) return false; } - LLFILE* file = LLFile::fopen(filename, TEXT("rb")); /*Flawfinder: ignore*/ + LLFILE* file = LLFile::fopen(filename, LLFILE_MODE("rb")); /*Flawfinder: ignore*/ if (!file) { LL_WARNS() << "Error opening " << filename << LL_ENDL; @@ -663,7 +663,7 @@ bool LLScriptEdCore::loadScriptText(const std::string& filename) bool LLScriptEdCore::writeToFile(const std::string& filename) { - LLFILE* fp = LLFile::fopen(filename, TEXT("wb")); + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("wb")); if (!fp) { LL_WARNS() << "Unable to write to " << filename << LL_ENDL; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 37609f74ed..2cb2a7f8d5 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -587,7 +587,7 @@ bool idle_startup() std::string message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message_template.msg"); LLFILE* found_template = NULL; - found_template = LLFile::fopen(message_template_path, TEXT("r")); /* Flawfinder: ignore */ + found_template = LLFile::fopen(message_template_path, LLFILE_MODE("r")); /* Flawfinder: ignore */ #if LL_WINDOWS // On the windows dev builds, unpackaged, the message_template.msg @@ -596,7 +596,7 @@ bool idle_startup() if (!found_template) { message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "message_template.msg"); - found_template = LLFile::fopen(message_template_path.c_str(), TEXT("r")); /* Flawfinder: ignore */ + found_template = LLFile::fopen(message_template_path.c_str(), LLFILE_MODE("r")); /* Flawfinder: ignore */ } #elif LL_DARWIN // On Mac dev builds, message_template.msg lives in: @@ -606,7 +606,7 @@ bool idle_startup() message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "message_template.msg"); - found_template = LLFile::fopen(message_template_path.c_str(), TEXT("r")); /* Flawfinder: ignore */ + found_template = LLFile::fopen(message_template_path.c_str(), LLFILE_MODE("r")); /* Flawfinder: ignore */ } #endif diff --git a/indra/newview/lltoolbarview.cpp b/indra/newview/lltoolbarview.cpp index d1e36676af..c401a00fd7 100644 --- a/indra/newview/lltoolbarview.cpp +++ b/indra/newview/lltoolbarview.cpp @@ -420,7 +420,7 @@ void LLToolBarView::saveToolbars() const if(!output_node->isNull()) { const std::string& filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "toolbars.xml"); - LLFILE *fp = LLFile::fopen(filename, TEXT("w")); + LLFILE *fp = LLFile::fopen(filename, LLFILE_MODE("w")); if (fp != NULL) { LLXMLNode::writeHeaderToFile(fp); diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index c28f3dc73a..867d47c893 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -279,7 +279,7 @@ void LLViewerAssetStorage::storeAssetData( LL_DEBUGS("AssetStorage") << "ASSET_ID: " << asset_id << LL_ENDL; S32 size = 0; - LLFILE* fp = LLFile::fopen(filename, TEXT("rb")); + LLFILE* fp = LLFile::fopen(filename, LLFILE_MODE("rb")); if (fp) { fseek(fp, 0, SEEK_END); diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp index 9b39f7b0e9..5741d7f5fb 100644 --- a/indra/newview/llviewerinput.cpp +++ b/indra/newview/llviewerinput.cpp @@ -1430,7 +1430,7 @@ S32 LLViewerInput::loadBindingsXML(const std::string& filename) // file in app_settings is supposed to be up to date // this is only for the file from user_settings LL_INFOS("ViewerInput") << "Updating file " << filename << " to a newer version" << LL_ENDL; - LLFILE *fp = LLFile::fopen(filename, TEXT("w")); + LLFILE *fp = LLFile::fopen(filename, LLFILE_MODE("w")); if (fp != NULL) { LLXMLNode::writeHeaderToFile(fp); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index a8ed2da9e0..423bb5f31d 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -1161,7 +1161,7 @@ void handle_compress_image() // so doing dirty, but OS independent fopen and fseek size_t get_file_size(std::string &filename) { - LLFILE* file = LLFile::fopen(filename, TEXT("rb")); /*Flawfinder: ignore*/ + LLFILE* file = LLFile::fopen(filename, LLFILE_MODE("rb")); /*Flawfinder: ignore*/ if (!file) { LL_WARNS() << "Error opening " << filename << LL_ENDL; diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index a2141f4eed..a183d7c8de 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -194,7 +194,7 @@ void LLViewerStatsRecorder::writeToLog( F32 interval ) // Open the data file makeStatsFileName(); - mStatsFile = LLFile::fopen(mStatsFileName, TEXT("wb")); + mStatsFile = LLFile::fopen(mStatsFileName, LLFILE_MODE("wb")); if (mStatsFile) { -- cgit v1.3 From d2a3a157a023f8608c44dfd3b07e8986df88c416 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Fri, 8 May 2026 00:26:24 +0300 Subject: #5772 'Control not found' crash --- indra/llxml/llcontrol.h | 2 +- indra/newview/llagent.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/llxml') diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index 5aa2b9715e..ad283c89b1 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -321,7 +321,7 @@ public: { if(!group.controlExists(name)) { - LL_ERRS() << "Control named " << name << "not found." << LL_ENDL; + LL_ERRS() << "Control named " << name << " not found." << LL_ENDL; } bindToControl(group, name); diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 3ab87cac13..3f5c0ad843 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -2676,7 +2676,7 @@ void LLAgent::onAnimStop(const LLUUID& id) const bool up_pos = (mControlFlags & AGENT_CONTROL_UP_POS) != 0; const F64 now = LLTimer::getTotalSeconds(); const F64 elapsed = now - mLastJumpInputTime; - static LLCachedControl recent_jump_threshold_secs(gSavedSettings, "RecentJumpThresholdSecs"); + static LLCachedControl recent_jump_threshold_secs(gSavedSettings, "RecentJumpThresholdSecs", 1.0); const bool recent_jump = (mLastJumpInputTime > 0.0) && (elapsed < recent_jump_threshold_secs); if (!up_pos && !recent_jump) -- cgit v1.3 From 5986568a23836f9ce448a1912406eaedd3794175 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Mon, 20 Jul 2026 19:21:50 +0300 Subject: #6014 More tracy coverage --- indra/llappearance/llpolymesh.cpp | 1 + indra/llcommon/llcoros.cpp | 1 + indra/llcommon/llwatchdog.cpp | 1 + indra/llfilesystem/lllfsthread.cpp | 1 + indra/llmessage/message.cpp | 1 + indra/llphysicsextensionsos/llphysicsextensions.cpp | 1 + indra/llplugin/llpluginclassmedia.cpp | 1 + indra/llxml/llcontrol.cpp | 2 ++ 8 files changed, 9 insertions(+) (limited to 'indra/llxml') diff --git a/indra/llappearance/llpolymesh.cpp b/indra/llappearance/llpolymesh.cpp index d5323e0b84..1162efb868 100644 --- a/indra/llappearance/llpolymesh.cpp +++ b/indra/llappearance/llpolymesh.cpp @@ -862,6 +862,7 @@ LLPolyMesh *LLPolyMesh::getMesh(const std::string &name, LLPolyMesh* reference_m //----------------------------------------------------------------------------- void LLPolyMesh::freeAllMeshes() { + LL_PROFILE_ZONE_SCOPED; // delete each item in the global lists for_each(sGlobalSharedMeshList.begin(), sGlobalSharedMeshList.end(), DeletePairedPointer()); sGlobalSharedMeshList.clear(); diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 9e95d9c85f..ae7c50e9a3 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -252,6 +252,7 @@ void LLCoros::setStackSize(S32 stacksize) void LLCoros::printActiveCoroutines(const std::string& when) { + LL_PROFILE_ZONE_SCOPED; LL_INFOS("LLCoros") << "Number of active coroutines " << when << ": " << CoroData::instanceCount() << LL_ENDL; if (CoroData::instanceCount() > 0) diff --git a/indra/llcommon/llwatchdog.cpp b/indra/llcommon/llwatchdog.cpp index 056a0cc940..b17b68dbe7 100644 --- a/indra/llcommon/llwatchdog.cpp +++ b/indra/llcommon/llwatchdog.cpp @@ -236,6 +236,7 @@ void LLWatchdog::shutdown() void LLWatchdog::cleanup() { + LL_PROFILE_ZONE_SCOPED; if (mTimer) { mTimer->stop(); diff --git a/indra/llfilesystem/lllfsthread.cpp b/indra/llfilesystem/lllfsthread.cpp index 6a882f64a8..69f7085290 100644 --- a/indra/llfilesystem/lllfsthread.cpp +++ b/indra/llfilesystem/lllfsthread.cpp @@ -51,6 +51,7 @@ S32 LLLFSThread::updateClass(U32 ms_elapsed) //static void LLLFSThread::cleanupClass() { + LL_PROFILE_ZONE_SCOPED; llassert(sLocal != NULL); sLocal->setQuitting(); while (sLocal->getPending()) diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index b11e4598e7..52180b20f1 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -2906,6 +2906,7 @@ void LLMessageSystem::summarizeLogs(std::ostream& str) void end_messaging_system(bool print_summary) { + LL_PROFILE_ZONE_SCOPED; gTransferManager.cleanup(); LLTransferTargetVFile::updateQueue(true); // shutdown LLTransferTargetVFile if (gMessageSystem) diff --git a/indra/llphysicsextensionsos/llphysicsextensions.cpp b/indra/llphysicsextensionsos/llphysicsextensions.cpp index 3bb8ffbf1a..295ab41a17 100644 --- a/indra/llphysicsextensionsos/llphysicsextensions.cpp +++ b/indra/llphysicsextensionsos/llphysicsextensions.cpp @@ -72,6 +72,7 @@ //============================================================================= /*static */bool LLPhysicsExtensions::quitSystem() { + LL_PROFILE_ZONE_SCOPED; return LLPhysicsExtensionsImpl::quitSystem(); } //============================================================================= diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 94c29d9457..9a1f408b34 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -92,6 +92,7 @@ bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::s void LLPluginClassMedia::reset() { + LL_PROFILE_ZONE_SCOPED; if(mPlugin) { mPlugin->requestShutdown(); diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index 5a37167f18..be53a93a2d 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -407,6 +407,7 @@ static bool compareRoutine(settings_pair_t lhs, settings_pair_t rhs) void LLControlGroup::cleanup() { + LL_PROFILE_ZONE_SCOPED; if(mSettingsProfile && getCount.size() != 0) { std::string file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, SETTINGS_PROFILE); @@ -982,6 +983,7 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, bool require U32 LLControlGroup::saveToFile(const std::string& filename, bool nondefault_only) { + LL_PROFILE_ZONE_SCOPED; LLSD settings; int num_saved = 0; for (ctrl_name_table_t::iterator iter = mNameTable.begin(); -- cgit v1.3 From b33d4053eca36480098f764c7b7ad8f3516641ea Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Tue, 18 Aug 2026 00:30:13 +0300 Subject: #1841 Fix viewer attempting to parse joystick key string into an llsd Key already is an LLSD::String and needs no further parsing. This parsing was added for command line handling and should be done explicitly in command line's parser. Also extended event listeners, there should be no ambiguity in what kind of data we are passing. --- indra/llxml/llcontrol.cpp | 38 +++++++++++++++++++------------ indra/llxml/llcontrol.h | 1 + indra/newview/llcommandlineparser.cpp | 5 ++++ indra/newview/llviewercontrollistener.cpp | 35 ++++++++++++++++++++++++++++ indra/newview/llviewercontrollistener.h | 1 + 5 files changed, 66 insertions(+), 14 deletions(-) (limited to 'indra/llxml') diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index 84d03a6d0c..eccf672e46 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -192,20 +192,6 @@ LLSD LLControlVariable::getComparableValue(const LLSD& value) storable_value = false; } } - else if (TYPE_LLSD == type() && value.isString()) - { - LLPointer parser = new LLSDNotationParser; - LLSD result; - std::stringstream value_stream(value.asString()); - if (parser->parse(value_stream, result, LLSDSerialize::SIZE_UNLIMITED) != LLSDParser::PARSE_FAILURE) - { - storable_value = result; - } - else - { - storable_value = value; - } - } else { storable_value = value; @@ -735,6 +721,30 @@ void LLControlGroup::setLLSD(std::string_view name, const LLSD& val) set(name, val); } +bool LLControlVariable::setValueFromNotation(const std::string& notation, bool saved_value) +{ + if (mType == TYPE_LLSD) + { + LLPointer parser = new LLSDNotationParser; + LLSD result; + std::stringstream value_stream(notation); + S32 parse_count = parser->parse(value_stream, result, LLSDSerialize::SIZE_UNLIMITED); + if (parse_count != LLSDParser::PARSE_FAILURE) + { + setValue(result, saved_value); + return true; + } + LL_WARNS("Controls") << "Failed to parse LLSD notation for control '" + << mName << "': " << notation << LL_ENDL; + } + else + { + LL_WARNS("Controls") << "setValueFromNotation() called on non-LLSD control '" + << mName << "' (type " << LLControlGroup::typeEnumToString(mType) << "); ignoring." << LL_ENDL; + } + return false; +} + void LLControlGroup::setUntypedValue(std::string_view name, const LLSD& val) { if (name.empty()) diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index ad283c89b1..7f28c71232 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -127,6 +127,7 @@ public: void setPersist(ePersist); void setHiddenFromSettingsEditor(bool hide); void setComment(const std::string& comment); + bool setValueFromNotation(const std::string& notation, bool saved_value = true); private: void firePropertyChanged(const LLSD &pPreviousValue) diff --git a/indra/newview/llcommandlineparser.cpp b/indra/newview/llcommandlineparser.cpp index 0734b12531..84d3ff90d5 100644 --- a/indra/newview/llcommandlineparser.cpp +++ b/indra/newview/llcommandlineparser.cpp @@ -611,6 +611,11 @@ void setControlValueCB(const LLCommandLineParser::token_vector_t& value, ctrl->setValue(llsdArray, false); } + else if (ctrl->isType(TYPE_LLSD)) + { + // Command-line LLSD should support a notation format string + ctrl->setValueFromNotation(onevalue(option, value), false); + } else { ctrl->setValue(onevalue(option, value), false); diff --git a/indra/newview/llviewercontrollistener.cpp b/indra/newview/llviewercontrollistener.cpp index 6f77e21fcc..f8e829deb9 100644 --- a/indra/newview/llviewercontrollistener.cpp +++ b/indra/newview/llviewercontrollistener.cpp @@ -65,6 +65,11 @@ LLViewerControlListener::LLViewerControlListener() grouphelp + replyhelp, &LLViewerControlListener::set, LLSDMap("group", LLSD())("key", LLSD())); + add("set_notation", + std::string("Set [\"group\"] TYPE_LLSD control [\"key\"] by parsing [\"value\"] as LLSD notation.\n") + + grouphelp + replyhelp, + &LLViewerControlListener::set_notation, + LLSDMap("group", LLSD())("key", LLSD())("value", LLSD())); add("toggle", std::string("Toggle [\"group\"] control [\"key\"], if boolean\n") + grouphelp + replyhelp, &LLViewerControlListener::toggle, @@ -149,6 +154,36 @@ void LLViewerControlListener::set(LLSD const & request) } } +//static +void LLViewerControlListener::set_notation(LLSD const& request) +{ + Info info(request); + if (!info.control) + return; + + if (!info.control->isType(TYPE_LLSD)) + { + info.response.error(STRINGIZE("set_notation requires a TYPE_LLSD control, but '" + << info.key << "' in group '" << info.groupname + << "' has type " + << LLControlGroup::typeEnumToString(info.control->type()))); + return; + } + + if (!request["value"].isString()) + { + info.response.error(STRINGIZE("set_notation requires [\"value\"] to be a string " + "containing LLSD notation, but received type: " + << LLSD::typeString(request["value"].type()))); + return; + } + + if (!info.control->setValueFromNotation(request["value"].asString())) + { + info.response.error(STRINGIZE("set_notation failed to parse notation")); + } +} + //static void LLViewerControlListener::toggle(LLSD const & request) { diff --git a/indra/newview/llviewercontrollistener.h b/indra/newview/llviewercontrollistener.h index 346acac439..c5a3a31baf 100644 --- a/indra/newview/llviewercontrollistener.h +++ b/indra/newview/llviewercontrollistener.h @@ -41,6 +41,7 @@ public: private: static void set(LLSD const & event_data); + static void set_notation(LLSD const & event_data); static void toggle(LLSD const & event_data); static void get(LLSD const & event_data); static void groups(LLSD const & event_data); -- cgit v1.3