From f07762a46830005b6ff4218c1f070ce27a9ecebe Mon Sep 17 00:00:00 2001 From: Frederick Martian Date: Wed, 12 Nov 2025 19:19:59 +0100 Subject: Refactoring of LLFile class to support additional methods - LLFile with its own class method interface to access files for read and write - Remove rudimentary LLUniqueFile class as LLFile supports now all of that and more - Implement most of the filename based functions using std::filesystem functions - Replace LLFile::rmdir() with LLFile::remove() since this function now supports deleting files and directories on all platforms. --- indra/llrender/llshadermgr.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) mode change 100644 => 100755 indra/llrender/llshadermgr.cpp (limited to 'indra/llrender') diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp old mode 100644 new mode 100755 index 2c35a6acae..49df9cd88c --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1059,7 +1059,7 @@ void LLShaderMgr::clearShaderCache() LL_INFOS("ShaderMgr") << "Removing shader cache at " << shader_cache << LL_ENDL; const std::string mask = "*"; gDirUtilp->deleteFilesInDir(shader_cache, mask); - LLFile::rmdir(shader_cache); + LLFile::remove(shader_cache); mShaderBinaryCache.clear(); } @@ -1131,11 +1131,11 @@ bool LLShaderMgr::loadCachedProgramBinary(LLGLSLShader* shader) { std::vector in_data; in_data.resize(shader_info.mBinaryLength); - - LLUniqueFile filep = LLFile::fopen(in_path, "rb"); + std::error_code ec; + LLFile filep = LLFile(in_path, LLFile::in | LLFile::binary, ec); if (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()) @@ -1180,11 +1180,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(); -- cgit v1.3 From 2c8f8fd6b4cae17bf8f74e422327b052d212a7ab Mon Sep 17 00:00:00 2001 From: Frederick Martian Date: Sun, 7 Dec 2025 13:08:16 +0100 Subject: Fix typo and check for valid opened file --- indra/llrender/llshadermgr.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'indra/llrender') diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 49df9cd88c..0522307661 100755 --- 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)) @@ -1078,7 +1077,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"]; @@ -1133,7 +1132,7 @@ bool LLShaderMgr::loadCachedProgramBinary(LLGLSLShader* shader) in_data.resize(shader_info.mBinaryLength); std::error_code ec; LLFile filep = LLFile(in_path, LLFile::in | LLFile::binary, ec); - if (filep) + if (!ec && (bool)filep) { size_t result = filep.read(in_data.data(), in_data.size(), ec); filep.close(); -- cgit v1.3 From c92b0b74cbd963cd79d1cb7754256b801f1479b1 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Thu, 11 Dec 2025 01:42:52 +0200 Subject: Revert #4899 "Add more functionality to LLFile and cleanup LLAPRFile" Interferes with linux work, will be moved to a different branch and applied separately. --- indra/llaudio/llaudiodecodemgr.cpp | 2 +- indra/llcommon/llapp.cpp | 4 +- indra/llcommon/llapr.cpp | 220 ++++++ indra/llcommon/llapr.h | 19 + indra/llcommon/llerror.cpp | 10 +- indra/llcommon/llfile.cpp | 1136 ++++++++----------------------- indra/llcommon/llfile.h | 488 ++++--------- indra/llcrashlogger/llcrashlock.cpp | 7 +- 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/llrender/llshadermgr.cpp | 22 +- 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 | 89 ++- 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 +- indra/test/CMakeLists.txt | 13 +- indra/test/llfile_tut.cpp | 253 ------- indra/test/llmessageconfig_tut.cpp | 2 +- indra/test/message_tut.cpp | 2 +- 32 files changed, 910 insertions(+), 1610 deletions(-) mode change 100755 => 100644 indra/llcommon/llerror.cpp mode change 100755 => 100644 indra/llcommon/llfile.cpp mode change 100755 => 100644 indra/llcommon/llfile.h mode change 100755 => 100644 indra/llcrashlogger/llcrashlock.cpp mode change 100755 => 100644 indra/llfilesystem/lldir.cpp mode change 100755 => 100644 indra/llfilesystem/lldir_win32.cpp mode change 100755 => 100644 indra/llfilesystem/llfilesystem.cpp mode change 100755 => 100644 indra/llfilesystem/tests/lldir_test.cpp mode change 100755 => 100644 indra/llrender/llshadermgr.cpp mode change 100755 => 100644 indra/llxml/tests/llcontrol_test.cpp mode change 100755 => 100644 indra/newview/llappviewer.cpp mode change 100755 => 100644 indra/newview/llfloaterpreference.cpp mode change 100755 => 100644 indra/newview/llfloateruipreview.cpp mode change 100755 => 100644 indra/newview/llpreviewnotecard.cpp mode change 100755 => 100644 indra/newview/llpreviewscript.cpp mode change 100755 => 100644 indra/newview/lltexturecache.cpp mode change 100755 => 100644 indra/newview/llviewerdisplay.cpp mode change 100755 => 100644 indra/newview/llviewermedia.cpp mode change 100755 => 100644 indra/newview/llvocache.cpp mode change 100755 => 100644 indra/newview/llvoicevivox.cpp mode change 100755 => 100644 indra/test/CMakeLists.txt delete mode 100755 indra/test/llfile_tut.cpp mode change 100755 => 100644 indra/test/llmessageconfig_tut.cpp mode change 100755 => 100644 indra/test/message_tut.cpp (limited to 'indra/llrender') diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp index 232b429130..d8a6fffea6 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() <= 0) + if (!mInFilep || !mInFilep->getSize()) { LL_WARNS("AudioEngine") << "unable to open vorbis source vfile for reading" << LL_ENDL; delete mInFilep; diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 5829d2be49..c532620daa 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,8 +53,6 @@ // // 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 22bed48542..eeff2694a7 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -526,6 +526,226 @@ 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 72458c6302..11e474b5dd 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -35,6 +35,12 @@ #include "llwin32headers.h" #include "apr_thread_proc.h" +#include "apr_getopt.h" +#include "apr_signal.h" + +#include "llstring.h" + +#include "mutex.h" struct apr_dso_handle_t; /** @@ -178,7 +184,20 @@ 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 100755 new mode 100644 index bfa8bca224..b14464382b --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -435,9 +435,13 @@ namespace std::string file = user_dir + "/logcontrol-dev.xml"; - if (!LLFile::isfile(file)) - { - file = app_dir + "/logcontrol.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"; } return * new LogControlFile(file); // NB: This instance is never freed diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp old mode 100755 new mode 100644 index a1d41cdf73..a539e4fe28 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -29,17 +29,22 @@ #include "linden_common.h" #include "llfile.h" +#include "llstring.h" #include "llerror.h" #include "stringize.h" #if LL_WINDOWS -#include +#include "llwin32headers.h" +#include #else #include -#include #endif -// Some of the methods below use OS-level functions that mess with errno. Wrap +using namespace std; + +static std::string empty; + +// Many of the methods below use OS-level functions that mess with errno. Wrap // variants of strerror() to report errors. #if LL_WINDOWS @@ -74,7 +79,6 @@ 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 @@ -105,25 +109,22 @@ static errentry const errtable[] { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } // 1816 }; -static int get_errno_from_oserror(int oserr) +static int set_errno_from_oserror(unsigned long 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) { - return entry.errcode; + _set_errno(entry.errcode); + return -1; } } - return EINVAL; -} -static int set_errno_from_oserror(unsigned long oserr) -{ - _set_errno(get_errno_from_oserror(oserr)); + _set_errno(EINVAL); return -1; } @@ -135,8 +136,69 @@ std::string strerr(int errn) return buffer; } -#else +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 @@ -183,50 +245,9 @@ std::string strerr(int errn) return message_from(errn, buffer, sizeof(buffer), strerror_r(errn, buffer, sizeof(buffer))); } - #endif // ! LL_WINDOWS -#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) +static int warnif(const std::string& desc, const std::string& filename, int rc, int accept = 0) { if (rc < 0) { @@ -235,930 +256,319 @@ 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 log a warning if caller explicitly says this errno is okay. - if (errn != suppress_warning) + // EEXIST. Don't warn if caller explicitly says this errno is okay. + if (errn != accept) { - 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 PROCESS_LOCKING_CHECK +#if 0 && LL_WINDOWS // turn on to debug file-locking problems // 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 { - find_locking_process(filename); + // 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; } -#endif +#endif // LL_WINDOWS hack to identify processes holding file open } return rc; } -static int warnif(const std::string& desc, const std::string& filename, const std::error_code& ec, int suppress_warning = 0) +// static +int LLFile::mkdir(const std::string& dirname, int perms) { - 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 + // 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 LL_WINDOWS - 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) + // 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) { - find_locking_process(filename); + rc = set_errno_from_oserror(oserr); } -#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 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)) - { - 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 - -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) -{ - switch (omode & (LLFile::in | LLFile::out)) + int rc = ::mkdir(dirname.c_str(), (mode_t)perms); + if (rc < 0 && errno == EEXIST) { - case LLFile::out: - return O_WRONLY; - case 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; + // this is not the error you want, move along + return 0; } - return SEEK_SET; -} - #endif - -inline int clear_error(std::error_code& ec) -{ - ec.clear(); - return 0; -} - -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; + // anything else might be a problem + return warnif("mkdir", dirname, rc); } -//---------------------------------------------------------------------------------------- -// class member functions -//---------------------------------------------------------------------------------------- -int LLFile::open(const std::string& filename, std::ios_base::openmode omode, std::error_code& ec, int perm) +// static +int LLFile::rmdir(const std::string& dirname, int suppress_error) { - close(ec); - if (are_open_mode_flags_invalid(omode)) - { - return set_ec_to_parameter_error(ec); - } #if LL_WINDOWS - 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 + std::wstring utf16dirname = utf8path_to_wstring(dirname); + int rc = _wrmdir(utf16dirname.c_str()); #else - 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; - } + int rc = ::rmdir(dirname.c_str()); #endif - 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); + return warnif("rmdir", dirname, rc, suppress_error); } -S64 LLFile::size(std::error_code& ec) +// static +LLFILE* LLFile::fopen(const std::string& filename, const char* mode) { #if LL_WINDOWS - LARGE_INTEGER value = { 0 }; - if (GetFileSizeEx(mHandle, &value)) - { - clear_error(ec); - return value.QuadPart; - } + std::wstring utf16filename = utf8path_to_wstring(filename); + std::wstring utf16mode = ll_convert(std::string(mode)); + return _wfopen(utf16filename.c_str(), utf16mode.c_str()); #else - struct stat statval; - if (fstat(mHandle, &statval) == 0) - { - clear_error(ec); - return statval.st_size; - } + return ::fopen(filename.c_str(),mode); #endif - return set_ec_from_system_error(ec); } -S64 LLFile::tell(std::error_code& ec) +// static +int LLFile::close(LLFILE * file) { -#if LL_WINDOWS - LARGE_INTEGER value = { 0 }; - if (SetFilePointerEx(mHandle, value, &value, FILE_CURRENT)) - { - clear_error(ec); - return value.QuadPart; - } -#else - off_t offset = lseek(mHandle, 0, SEEK_CUR); - if (offset != -1) + int ret_value = 0; + if (file) { - clear_error(ec); - return offset; + ret_value = fclose(file); } -#endif - return set_ec_from_system_error(ec); -} - -int LLFile::seek(S64 pos, std::error_code& ec) -{ - return seek(pos, LLFile::beg, ec); + return ret_value; } -int LLFile::seek(S64 offset, std::ios_base::seekdir dir, std::error_code& ec) +// static +std::string LLFile::getContents(const std::string& filename) { - 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 + LLFILE* fp = LLFile::fopen(filename, "rb"); + if (fp) { - return clear_error(ec); - } - return set_ec_from_system_error(ec); -} + fseek(fp, 0, SEEK_END); + U32 length = ftell(fp); + fseek(fp, 0, SEEK_SET); -#if LL_WINDOWS -inline DWORD next_buffer_size(S64 nbytes) -{ - return nbytes > 0x80000000 ? 0x80000000 : (DWORD)nbytes; -} -#endif + std::vector buffer(length); + size_t nread = fread(buffer.data(), 1, length, fp); + fclose(fp); -S64 LLFile::read(void* buffer, S64 nbytes, std::error_code& ec) -{ - if (nbytes == 0) - { - // Nothing to do - return clear_error(ec); + return std::string(buffer.data(), nread); } - 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); - // 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); + return LLStringUtil::null; } -S64 LLFile::write(const void* buffer, S64 nbytes, std::error_code& ec) +// static +int LLFile::remove(const std::string& filename, int suppress_error) { - 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 - // If this was opened in append mode, we emulate it on Windows - if (mOpen & LLFile::app && seek(0, LLFile::end, ec) != 0) + // 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)) { - return -1; + rc = _wrmdir(utf16filename.c_str()); } - - 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)) + else if (S_ISREG(st_mode)) { - totalBytes += bytesWritten; - if (nbytes <= totalBytes) - { - clear_error(ec); - return totalBytes; - } - ptr += bytesWritten; - bytesToWrite = next_buffer_size(nbytes - totalBytes); + rc = _wunlink(utf16filename.c_str()); } -#else - ssize_t bytesWritten = ::write(mHandle, buffer, nbytes); - if (bytesWritten != -1) + else if (st_mode) { - 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) - { - va_end(args2); - return -1; - } - void* buffer = malloc(length + 1); - if (!buffer) - { - va_end(args2); - return -1; - } - 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)) - { - if (UnlockFile(mHandle, 0, 0, MAXDWORD, MAXDWORD)) - { - return clear_error(ec); - } + // 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); } else { - 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 - if (flock(mHandle, decode_lock_mode(mode)) == 0) - { - return clear_error(ec); + // get_fileattr() failed and already set errno, preserve it for correct error reporting } -#endif - 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)) + int rc = ::remove(filename.c_str()); #endif - { - return set_ec_from_system_error(ec); - } - } - return clear_error(ec); -} - -int LLFile::close() -{ - std::error_code ec; - return close(ec); + return warnif("remove", filename, rc, suppress_error); } -//---------------------------------------------------------------------------------------- -// static member functions -//---------------------------------------------------------------------------------------- - // static -LLFILE* LLFile::fopen(const std::string& filename, const char* mode, int lmode) +int LLFile::rename(const std::string& filename, const std::string& newname, int suppress_error) { - LLFILE* file; #if LL_WINDOWS - int shflag = _SH_DENYNO; - switch (lmode) + // 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)) { - case LLFile::exclusive: - shflag = _SH_DENYRW; - break; - case LLFile::shared: - shflag = _SH_DENYWR; - break; + rc = set_errno_from_oserror(GetLastError()); } - 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 - 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(lmode | LLFile::noblock))) - { - ::fclose(file); - file = nullptr; - } - } + int rc = ::rename(filename.c_str(),newname.c_str()); #endif - return file; + return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc, suppress_error); } -// 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); -} +// Make this a define rather than using magic numbers multiple times in the code +#define LLFILE_COPY_BUFFER_SIZE 16384 // static -std::string LLFile::getContents(const std::string& filename, std::error_code& ec) +bool LLFile::copy(const std::string& from, const std::string& to) { - std::string buffer; - LLFile file(filename, LLFile::in | LLFile::binary, ec); - if (file) + bool copied = false; + LLFILE* in = LLFile::fopen(from, "rb"); + if (in) { - S64 length = file.size(ec); - if (!ec && length > 0) + LLFILE* out = LLFile::fopen(to, "wb"); + if (out) { - buffer = std::string(length, 0); - file.read(&buffer[0], length, ec); - if (ec) + 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))) { - buffer.clear(); - } - } - } - return buffer; -} - -// 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 -int LLFile::remove(const std::string& filename, int suppress_warning) -{ - 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) - { - 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) - { - if (offset > 0) - { - file.seek(offset, ec); - } - // else (offset == 0) file was just opened and should already be at 0. - if (!ec) - { - S64 bytes_read = file.read(buf, nbytes, ec); - if (!ec) + if (fwrite(buf, 1, readbytes, out) != readbytes) { - return bytes_read; + LL_WARNS("LLFile") << "Short write" << LL_ENDL; + write_ok = false; } } - } - } - 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) + if ( write_ok ) { - file.seek(offset, ec); - } - // else (offset == 0) we are not appending, file was just opened and should already be at 0. - if (!ec) - { - S64 bytes_written = file.write(buf, nbytes, ec); - if (!ec) - { - return bytes_written; - } + copied = true; } + fclose(out); } - } - 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); + fclose(in); } return copied; } // static -int LLFile::stat(const std::string& filename, llstat* filestatus, const char *fname, int suppress_warning) +int LLFile::stat(const std::string& filename, llstat* filestatus, int suppress_error) { #if LL_WINDOWS - std::wstring file_path = utf8StringToWstring(filename); - int rc = _wstat64(file_path.c_str(), filestatus); + std::wstring utf16filename = utf8path_to_wstring(filename); + int rc = _wstat64(utf16filename.c_str(), filestatus); #else int rc = ::stat(filename.c_str(), filestatus); #endif - return warnif(fname ? fname : "stat", filename, rc, suppress_warning); + return warnif("stat", filename, rc, suppress_error); } // static -std::time_t LLFile::getCreationTime(const std::string& filename, int suppress_warning) +unsigned short LLFile::getattr(const std::string& filename, bool dontFollowSymLink, int suppress_error) { - // 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_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) { -#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 st_mode; } - 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); +#else + llstat filestatus; + int rc = dontFollowSymLink ? ::lstat(filename.c_str(), &filestatus) : ::stat(filename.c_str(), &filestatus); if (rc == 0) { - return filestat.st_mtime; + return filestatus.st_mode; } +#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) { - std::filesystem::file_status status = getStatus(filename); - return std::filesystem::is_directory(status); + return S_ISDIR(getattr(filename)); } // static bool LLFile::isfile(const std::string& filename) { - std::filesystem::file_status status = getStatus(filename); - return std::filesystem::is_regular_file(status); + return S_ISREG(getattr(filename)); } // 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() -{ - static std::string temppath; - if (temppath.empty()) - { - temppath = std::filesystem::temp_directory_path().string(); - } - return temppath; + return S_ISLNK(getattr(filename, true)); } // static -std::filesystem::path LLFile::utf8StringToPath(const std::string& pathname) +const char *LLFile::tmpdir() { -#if LL_WINDOWS - return ll_convert(pathname); -#else - return pathname; -#endif -} + static std::string utf8path; -#if LL_WINDOWS - -// static -std::wstring LLFile::utf8StringToWstring(const std::string& pathname) -{ - std::wstring utf16string(ll_convert(pathname)); - if (utf16string.size() >= MAX_PATH) + if (utf8path.empty()) { - // 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); + char sep; +#if LL_WINDOWS + sep = '\\'; - // By prepending "\\?\" to a path, Windows widechar file APIs will not fail on long path names - utf16string.assign(L"\\\\?\\").append(utf16path); + std::vector utf16path(MAX_PATH + 1); + GetTempPathW(static_cast(utf16path.size()), &utf16path[0]); + utf8path = ll_convert_wide_to_string(&utf16path[0]); +#else + sep = '/'; - /* 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 = LLStringUtil::getenv("TMPDIR", "/tmp/"); +#endif + if (utf8path[utf8path.size() - 1] != sep) { - return std::wstring(); + utf8path += sep; } - return utf16string.substr(0, last_valid + 1); } - return utf16string; + return utf8path.c_str(); } +#if LL_WINDOWS + /************** input file stream ********************************/ llifstream::llifstream() {} @@ -1176,8 +586,10 @@ void llifstream::open(const std::string& _Filename, ios_base::openmode _Mode) _Mode | ios_base::in); } + /************** output file stream ********************************/ + llofstream::llofstream() {} // explicit @@ -1193,4 +605,30 @@ 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 100755 new mode 100644 index 2c74c97d0b..04a2946ac4 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -35,359 +35,118 @@ * 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 -typedef FILE LLFILE; +#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 #include "llstring.h" // safe char* -> std::string conversion -/// 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 +/// LLFile is a class of static functions operating on paths /// 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 = 1 << 1; // append to end - static const std::ios_base::openmode ate = 1 << 2; // initialize to end - static const std::ios_base::openmode binary = 1 << 3; // binary mode - static const std::ios_base::openmode in = 1 << 4; // for reading - static const std::ios_base::openmode out = 1 << 5; // for writing - static const std::ios_base::openmode trunc = 1 << 6; // truncate on open - static const std::ios_base::openmode noreplace = 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 = 1 << 16; - static const std::ios_base::openmode shared = 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 = 1 << 18; - - /// The mask value for the lock mask bits - static const std::ios_base::openmode lock_mask = 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, int lmode = 0); + static LLFILE* fopen(const std::string& filename, const char* accessmode); /* Flawfinder: ignore */ ///< '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 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 + /// "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 /// - /// 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 + /// 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 - /// Close a file handle opened with fopen() above static int close(LLFILE * file); - ///< @returns 0 on success and -1 on failure. + + /// 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 /// create a directory - static int mkdir(const std::string& filename); - ///< mkdir() considers "directory already exists" to be not an error. + 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 /// @returns 0 on success and -1 on failure. /// remove a file or directory - 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) + 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 /// @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); + static int rename(const std::string& filename, const std::string& newname, int suppress_error = 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 - /// APIs do not make such guarantees. + /// under Windows at this time. It may do it in the same way but the used Windows API + /// does 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 - /// 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 + /// 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. /// 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); + static int stat(const std::string& filename, llstat* file_status, int suppress_error = 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 + /// optional 'suppress_error' 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); - ///< 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 + /// 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. /// check if filename is an existing directory static bool isdir(const std::string& filename); @@ -402,44 +161,70 @@ public: ///< @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(); + static const char * 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 - ///@} +/// 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(); + } -private: -#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 + // 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; + } - /// ================================================================================ - /// @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 + // 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; }; #if LL_WINDOWS @@ -530,6 +315,17 @@ 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/llcrashlogger/llcrashlock.cpp b/indra/llcrashlogger/llcrashlock.cpp old mode 100755 new mode 100644 index 731b53b7e9..bc34f6798f --- a/indra/llcrashlogger/llcrashlock.cpp +++ b/indra/llcrashlogger/llcrashlock.cpp @@ -188,7 +188,12 @@ LLSD LLCrashLock::getProcessList() //static bool LLCrashLock::fileExists(std::string filename) { - return LLFile::exists(filename); +#ifdef LL_WINDOWS // or BOOST_WINDOWS_API + boost::filesystem::path file_path(ll_convert(filename)); +#else + boost::filesystem::path file_path(filename); +#endif + return boost::filesystem::exists(file_path); } void LLCrashLock::cleanupProcess(std::string proc_dir) diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp old mode 100755 new mode 100644 index eb3c2d9909..190539cea5 --- a/indra/llfilesystem/lldir.cpp +++ b/indra/llfilesystem/lldir.cpp @@ -30,6 +30,8 @@ #include #include #include +#else +#include #endif #include "lldir.h" @@ -41,6 +43,7 @@ #include "lldiriterator.h" #include "stringize.h" #include "llstring.h" +#include #include #include @@ -90,20 +93,30 @@ 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); + //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 + std::vector v; - std::error_code ec; - if (std::filesystem::is_directory(p, ec)) + + boost::system::error_code ec; + if (exists(p, ec) && !ec.failed()) { - std::filesystem::directory_iterator end_iter; - for (std::filesystem::directory_iterator dir_itr(p); - dir_itr != end_iter; - ++dir_itr) + if (is_directory(p, ec) && !ec.failed()) { - if (std::filesystem::is_regular_file(dir_itr->status())) + boost::filesystem::directory_iterator end_iter; + for (boost::filesystem::directory_iterator dir_itr(p); + dir_itr != end_iter; + ++dir_itr) { - v.push_back(dir_itr->path().filename().string()); + if (boost::filesystem::is_regular_file(dir_itr->status())) + { + v.push_back(dir_itr->path().filename().string()); + } } } } @@ -173,23 +186,28 @@ 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 { - if (std::filesystem::is_directory(dir_path)) +#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_empty(dir_path)) + if (!boost::filesystem::is_empty(dir_path)) { // Directory has content - num_deleted = (U32)std::filesystem::remove_all(dir_path); + num_deleted = (U32)boost::filesystem::remove_all(dir_path); } else { // Directory is empty - std::filesystem::remove(dir_path); + boost::filesystem::remove(dir_path); } } } - catch (std::filesystem::filesystem_error &er) + catch (boost::filesystem::filesystem_error &er) { LL_WARNS() << "Failed to delete " << dir_name << " with error " << er.code().message() << LL_ENDL; } @@ -1087,15 +1105,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); + LLFile::mkdir(dir_name, 0700); #else - llstat dir_stat; + struct stat dir_stat; if(0 != LLFile::stat(dir_name, &dir_stat)) { S32 stat_rv = errno; if(ENOENT == stat_rv) { - if(0 != LLFile::mkdir(dir_name)) + if(0 != LLFile::mkdir(dir_name, 0700)) // octal { 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 100755 new mode 100644 index 2b478e5dce..58c080c982 --- a/indra/llfilesystem/lldir_win32.cpp +++ b/indra/llfilesystem/lldir_win32.cpp @@ -376,7 +376,18 @@ std::string LLDir_Win32::getCurPath() bool LLDir_Win32::fileExists(const std::string &filename) const { - return LLFile::exists(filename); + 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; + } } diff --git a/indra/llfilesystem/llfilesystem.cpp b/indra/llfilesystem/llfilesystem.cpp old mode 100755 new mode 100644 index 0c220fe7cf..541266af4f --- a/indra/llfilesystem/llfilesystem.cpp +++ b/indra/llfilesystem/llfilesystem.cpp @@ -77,17 +77,21 @@ 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); - // not only test for existence but for the file to be not empty - S64 size = LLFile::size(filename); - return size > 0; + llifstream file(filename, std::ios::binary); + if (file.is_open()) + { + file.seekg(0, std::ios::end); + return file.tellg() > 0; + } + return false; } // static -bool LLFileSystem::removeFile(const LLUUID& file_id, const LLAssetType::EType file_type, int suppress_warning /*= 0*/) +bool LLFileSystem::removeFile(const LLUUID& file_id, const LLAssetType::EType file_type, int suppress_error /*= 0*/) { const std::string filename = LLDiskCache::metaDataToFilepath(file_id, file_type); - LLFile::remove(filename.c_str(), suppress_warning); + LLFile::remove(filename.c_str(), suppress_error); return true; } @@ -112,10 +116,19 @@ bool LLFileSystem::renameFile(const LLUUID& old_file_id, const LLAssetType::ETyp } // static -S64 LLFileSystem::getFileSize(const LLUUID& file_id, const LLAssetType::EType file_type) +S32 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); + + 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; } bool LLFileSystem::read(U8* buffer, S32 bytes) @@ -256,7 +269,7 @@ S32 LLFileSystem::tell() const S32 LLFileSystem::getSize() const { - return (S32)LLFileSystem::getFileSize(mFileID, mFileType); + return LLFileSystem::getFileSize(mFileID, mFileType); } S32 LLFileSystem::getMaxSize() const diff --git a/indra/llfilesystem/llfilesystem.h b/indra/llfilesystem/llfilesystem.h index 7188683e7f..10649b6920 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_warning = 0); + static bool removeFile(const LLUUID& file_id, const LLAssetType::EType file_type, int suppress_error = 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); + static S32 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 100755 new mode 100644 index 17e4ffecf1..13db6fad80 --- a/indra/llfilesystem/tests/lldir_test.cpp +++ b/indra/llfilesystem/tests/lldir_test.cpp @@ -558,8 +558,8 @@ namespace tut LLFile::remove(dir1files[i]); LLFile::remove(dir2files[i]); } - LLFile::remove(dir1); - LLFile::remove(dir2); + LLFile::rmdir(dir1); + LLFile::rmdir(dir2); } template<> template<> diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index 34eeacb273..10fd56a68e 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 " << size << ", ignoring" << LL_ENDL; + << " found in static cache with bad size " << file.getSize() << ", ignoring" << LL_ENDL; } } return false; diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp old mode 100755 new mode 100644 index 0522307661..2c35a6acae --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1014,6 +1014,7 @@ 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)) @@ -1058,7 +1059,7 @@ void LLShaderMgr::clearShaderCache() LL_INFOS("ShaderMgr") << "Removing shader cache at " << shader_cache << LL_ENDL; const std::string mask = "*"; gDirUtilp->deleteFilesInDir(shader_cache, mask); - LLFile::remove(shader_cache); + LLFile::rmdir(shader_cache); mShaderBinaryCache.clear(); } @@ -1077,7 +1078,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. - // Duplicate version to the cache itself. + // Dupplicate version to the cache itself. out["version"] = mShaderCacheVersion; out["shaders"] = LLSD::emptyMap(); LLSD &shaders = out["shaders"]; @@ -1130,11 +1131,11 @@ bool LLShaderMgr::loadCachedProgramBinary(LLGLSLShader* shader) { std::vector in_data; in_data.resize(shader_info.mBinaryLength); - std::error_code ec; - LLFile filep = LLFile(in_path, LLFile::in | LLFile::binary, ec); - if (!ec && (bool)filep) + + LLUniqueFile filep = LLFile::fopen(in_path, "rb"); + if (filep) { - size_t result = filep.read(in_data.data(), in_data.size(), ec); + size_t result = fread(in_data.data(), sizeof(U8), in_data.size(), filep); filep.close(); if (result == in_data.size()) @@ -1179,12 +1180,11 @@ bool LLShaderMgr::saveCachedProgramBinary(LLGLSLShader* shader) if (error == GL_NO_ERROR) { std::string out_path = gDirUtilp->add(mShaderCacheDir, shader->mShaderHash.asString() + ".shaderbin"); - std::error_code ec; - LLFile filep = LLFile(out_path, LLFile::out | LLFile::binary, ec); - if (filep) + LLUniqueFile outfile = LLFile::fopen(out_path, "wb"); + if (outfile) { - filep.write(program_binary.data(), program_binary.size(), ec); - filep.close(); + fwrite(program_binary.data(), sizeof(U8), program_binary.size(), outfile); + outfile.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 100755 new mode 100644 index e15117fc29..4192e029c5 --- 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::remove(mTestConfigDir); + LLFile::rmdir(mTestConfigDir); } void writeSettingsFile(const LLSD& config) { diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp old mode 100755 new mode 100644 index 962a91bb73..569fd30b21 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2268,7 +2268,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 (!LLFile::isfile(error_marker_file)) + if (!LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) { // If marker doesn't exist, create a marker with llerror code for next launch // otherwise don't override existing file @@ -3031,11 +3031,13 @@ void LLAppViewer::initStrings() } else { - if (!LLFile::exists(strings_path_full)) + llstat st; + int rc = LLFile::stat(strings_path_full, &st); + if (rc != 0) { - crash_reason = "The file '" + strings_path_full + "' doesn't seem to exist"; + crash_reason = "The file '" + strings_path_full + "' failed to get status. Error code: " + std::to_string(rc); } - else if (LLFile::isdir(strings_path_full)) + else if (S_ISDIR(st.st_mode)) { crash_reason = "The filename '" + strings_path_full + "' is a directory name"; } @@ -3898,7 +3900,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 (LLFile::isfile(mMarkerFileName)) + if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB)) { // File exists... // first, read it to see if it was created by the same version (we need this later) @@ -3990,7 +3992,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(LLFile::isfile(logout_marker_file)) + if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB)) { if (markerIsSameVersion(logout_marker_file)) { @@ -4002,11 +4004,11 @@ void LLAppViewer::processMarkerFiles() { LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "' found, but versions did not match" << LL_ENDL; } - LLFile::remove(logout_marker_file); + LLAPRFile::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(LLFile::isfile(error_marker_file)) + if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) { S32 marker_code = getMarkerErrorCode(error_marker_file); if (marker_code >= 0) @@ -4031,7 +4033,7 @@ void LLAppViewer::processMarkerFiles() { LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' marker found, but versions did not match" << LL_ENDL; } - LLFile::remove(error_marker_file); + LLAPRFile::remove(error_marker_file); } #if LL_DARWIN @@ -4058,7 +4060,7 @@ void LLAppViewer::removeMarkerFiles() if (mMarkerFile.getFileHandle()) { mMarkerFile.close() ; - LLFile::remove( mMarkerFileName ); + LLAPRFile::remove( mMarkerFileName ); LL_DEBUGS("MarkerFile") << "removed exec marker '"<getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); - return LLFile::isfile(error_marker_file); + return LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB); } void LLAppViewer::outOfMemorySoftQuit() diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp old mode 100755 new mode 100644 index 66066a45b2..c5c1e01538 --- 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::remove(chatLogPath); + LLFile::rmdir(chatLogPath); } return false; } @@ -1526,7 +1526,7 @@ bool LLFloaterPreference::moveTranscriptsAndLog() if(madeDirectory) { - LLFile::remove(chatLogPath); + LLFile::rmdir(chatLogPath); } return false; @@ -2031,15 +2031,17 @@ 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::isfile(LLConversationLog::instance().getFileName()) - && LLFile::size(LLConversationLog::instance().getFileName()) > 0; + && LLFile::stat(LLConversationLog::instance().getFileName(), &st) == 0 + && S_ISREG(st.st_mode) + && st.st_size > 0; getChild("clear_log")->setEnabled(has_logs); } diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp old mode 100755 new mode 100644 index 0bf0946c42..c3bc24c6b9 --- 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::isdir(full_path.c_str())) // if it's not a directory, skip it + if(LLFile::isfile(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,7 +892,8 @@ 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"; - if (LLFile::isfile(full_path.c_str())) // use localized language if the file exists + llstat dummy; + if(!LLFile::stat(full_path.c_str(), &dummy)) // if the file does not exist { floater_lang = getLocStr(ID); } @@ -965,8 +966,9 @@ void LLFloaterUIPreview::onClickEditFloater() } file_path = getLocalizedDirectory() + file_name; - // 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 + // 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 { 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 @@ -1115,14 +1117,15 @@ 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; } - 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) + 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) { 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 100755 new mode 100644 index 4fe661b055..9a991727b2 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -575,7 +575,8 @@ void LLPreviewNotecard::syncExternal() { // Sync with external editor. std::string tmp_file = getTmpFileName(); - if (LLFile::isfile(tmp_file)) // file exists + llstat s; + if (LLFile::stat(tmp_file, &s) == 0) // file exists { if (mLiveFile) mLiveFile->ignoreNextUpdate(); writeToFile(tmp_file); diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp old mode 100755 new mode 100644 index 2c436198e3..c2aa4925bd --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -694,7 +694,8 @@ void LLScriptEdCore::sync() if (mLiveFile) { std::string tmp_file = mLiveFile->filename(); - if (LLFile::isfile(tmp_file)) // file exists + llstat s; + if (LLFile::stat(tmp_file, &s) == 0) // file exists { mLiveFile->ignoreNextUpdate(); writeToFile(tmp_file); diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp old mode 100755 new mode 100644 index a6d81816ce..1a7ce74ccc --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -180,7 +180,8 @@ private: bool LLTextureCacheLocalFileWorker::doRead() { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - S32 local_size = (S32)LLFile::size(mFileName); + S32 local_size = LLAPRFile::size(mFileName, mCache->getLocalAPRFilePool()); + if (local_size > 0 && mFileName.size() > 4) { mDataSize = local_size; // Only a complete file is valid @@ -209,7 +210,8 @@ bool LLTextureCacheLocalFileWorker::doRead() } mReadData = (U8*)ll_aligned_malloc_16(mDataSize); - S32 bytes_read = (S32)LLFile::read(mFileName, mReadData, mOffset, mDataSize); + S32 bytes_read = LLAPRFile::readEx(mFileName, mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool()); + if (bytes_read != mDataSize) { // LL_WARNS() << "Error reading file from local cache: " << mFileName @@ -294,7 +296,7 @@ bool LLTextureCacheRemoteWorker::doRead() // Is it a JPEG2000 file? { local_filename = filename + ".j2c"; - local_size = (S32)LLFile::size(local_filename); + local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool()); if (local_size > 0) { mImageFormat = IMG_CODEC_J2C; @@ -304,7 +306,7 @@ bool LLTextureCacheRemoteWorker::doRead() if (local_size == 0) { local_filename = filename + ".jpg"; - local_size = (S32)LLFile::size(local_filename); + local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool()); if (local_size > 0) { mImageFormat = IMG_CODEC_JPEG; @@ -315,7 +317,7 @@ bool LLTextureCacheRemoteWorker::doRead() if (local_size == 0) { local_filename = filename + ".tga"; - local_size = (S32)LLFile::size(local_filename); + local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool()); if (local_size > 0) { mImageFormat = IMG_CODEC_TGA; @@ -344,10 +346,12 @@ bool LLTextureCacheRemoteWorker::doRead() if (mReadData) { - S32 bytes_read = (S32)LLFile::read(local_filename, - mReadData, - mOffset, - mDataSize); + S32 bytes_read = LLAPRFile::readEx( local_filename, + mReadData, + mOffset, + mDataSize, + mCache->getLocalAPRFilePool()); + if (bytes_read != mDataSize) { LL_WARNS() << "Error reading file from local cache: " << local_filename @@ -406,7 +410,8 @@ bool LLTextureCacheRemoteWorker::doRead() mReadData = (U8*)ll_aligned_malloc_16(size); if (mReadData) { - S32 bytes_read = (S32)LLFile::read(mCache->mHeaderDataFileName, mReadData, offset, size); + S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, + mReadData, offset, size, mCache->getLocalAPRFilePool()); if (bytes_read != size) { LL_WARNS() << "LLTextureCacheWorker: " << mID @@ -441,9 +446,9 @@ bool LLTextureCacheRemoteWorker::doRead() if (!done && (mState == BODY)) { std::string filename = mCache->getTextureFileName(mID); - S32 filesize = (S32)LLFile::size(filename); + S32 filesize = LLAPRFile::size(filename, mCache->getLocalAPRFilePool()); - if (filesize > 0 && (filesize + TEXTURE_CACHE_ENTRY_SIZE) > mOffset) + if (filesize && (filesize + TEXTURE_CACHE_ENTRY_SIZE) > mOffset) { S32 max_datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize - mOffset; mDataSize = llmin(max_datasize, mDataSize); @@ -482,9 +487,10 @@ bool LLTextureCacheRemoteWorker::doRead() mReadData = data; // Read the data at last - S32 bytes_read = (S32)LLFile::read(filename, - mReadData + data_offset, - file_offset, file_size); + S32 bytes_read = LLAPRFile::readEx(filename, + mReadData + data_offset, + file_offset, file_size, + mCache->getLocalAPRFilePool()); if (bytes_read != file_size) { LL_WARNS() << "LLTextureCacheWorker: " << mID @@ -630,13 +636,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 = (S32)LLFile::write(mCache->mHeaderDataFileName, padBuffer, offset, size); + bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size, mCache->getLocalAPRFilePool()); 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 = (S32)LLFile::write(mCache->mHeaderDataFileName, mWriteData, offset, size); + bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size, mCache->getLocalAPRFilePool()); } if (bytes_written <= 0) @@ -672,11 +678,15 @@ 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 = (S32)LLFile::write(filename, mWriteData + TEXTURE_CACHE_ENTRY_SIZE, 0, file_size); + S32 bytes_written = LLAPRFile::writeEx(filename, + mWriteData + TEXTURE_CACHE_ENTRY_SIZE, + 0, file_size, + mCache->getLocalAPRFilePool()); if (bytes_written <= 0) { LL_WARNS() << "LLTextureCacheWorker: " << mID @@ -881,7 +891,7 @@ bool LLTextureCache::isInLocal(const LLUUID& id) // Is it a JPEG2000 file? { local_filename = filename + ".j2c"; - local_size = (S32)LLFile::size(local_filename); + local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool()); if (local_size > 0) { return true ; @@ -891,7 +901,7 @@ bool LLTextureCache::isInLocal(const LLUUID& id) // If not, is it a jpeg file? { local_filename = filename + ".jpg"; - local_size = (S32)LLFile::size(local_filename); + local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool()); if (local_size > 0) { return true ; @@ -901,7 +911,7 @@ bool LLTextureCache::isInLocal(const LLUUID& id) // Hmm... What about a targa file? (used for UI texture mostly) { local_filename = filename + ".tga"; - local_size = (S32)LLFile::size(local_filename); + local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool()); if (local_size > 0) { return true ; @@ -933,6 +943,8 @@ const char* fast_cache_filename = "FastCache.cache"; void LLTextureCache::setDirNames(ELLPath location) { + std::string delem = gDirUtilp->getDirDelimiter(); + mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, textures_dirname, entries_filename); mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, textures_dirname, cache_filename); mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname); @@ -954,10 +966,11 @@ void LLTextureCache::purgeCache(ELLPath location, bool remove_dir) if(LLFile::isdir(mTexturesDirName)) { std::string file_name = gDirUtilp->getExpandedFilename(location, entries_filename); - LLFile::remove(file_name); + // mHeaderAPRFilePoolp because we are under header mutex, and can be in main thread + LLAPRFile::remove(file_name, mHeaderAPRFilePoolp); file_name = gDirUtilp->getExpandedFilename(location, cache_filename); - LLFile::remove(file_name); + LLAPRFile::remove(file_name, mHeaderAPRFilePoolp); purgeAllTextures(true); } @@ -1058,9 +1071,10 @@ void LLTextureCache::readEntriesHeader() { // mHeaderEntriesInfo initializes to default values so safe not to read it llassert_always(mHeaderAPRFile == NULL); - if (LLFile::isfile(mHeaderEntriesFileName)) + if (LLAPRFile::isExist(mHeaderEntriesFileName, mHeaderAPRFilePoolp)) { - LLFile::read(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); + LLAPRFile::readEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo), + mHeaderAPRFilePoolp); } else //create an empty entries header. { @@ -1076,7 +1090,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 account that c_str() returns additional null character + // Also take into accout that c_str() returns additional null character LL_ERRS() << "Version string doesn't fit in header" << LL_ENDL; } @@ -1091,7 +1105,8 @@ void LLTextureCache::writeEntriesHeader() llassert_always(mHeaderAPRFile == NULL); if (!mReadOnly) { - LLFile::write(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); + LLAPRFile::writeEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo), + mHeaderAPRFilePoolp); } } @@ -1195,7 +1210,8 @@ void LLTextureCache::writeEntryToHeaderImmediately(S32& idx, Entry& entry, bool idx = -1 ;//mark the idx invalid. return ; } - aprfile->seek(APR_SET, offset); + + mHeaderAPRFile->seek(APR_SET, offset); } else { @@ -1599,7 +1615,7 @@ void LLTextureCache::purgeAllTextures(bool purge_directories) gDirUtilp->deleteFilesInDir(mTexturesDirName, mask); // headers, fast cache if (purge_directories) { - LLFile::remove(mTexturesDirName); + LLFile::rmdir(mTexturesDirName); } } mHeaderIDMap.clear(); @@ -1779,7 +1795,8 @@ void LLTextureCache::purgeTextures(bool validate) { std::string filename = getTextureFileName(entries[idx].mID); LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mBodySize << LL_ENDL; - S32 bodysize = (S32)LLFile::size(filename); + // mHeaderAPRFilePoolp because this is under header mutex in main thread + S32 bodysize = LLAPRFile::size(filename, mHeaderAPRFilePoolp); if (bodysize != entries[idx].mBodySize) { LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mBodySize << filename << LL_ENDL; @@ -2130,7 +2147,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 (LLFile::isfile(mFastCacheFileName)) + if (LLAPRFile::isExist(mFastCacheFileName, mFastCachePoolp)) { mFastCachep = new LLAPRFile(mFastCacheFileName, APR_READ|APR_WRITE|APR_BINARY, mFastCachePoolp) ; } @@ -2213,7 +2230,9 @@ void LLTextureCache::removeCachedTexture(const LLUUID& id) mTexturesSizeMap.erase(id); } mHeaderIDMap.erase(id); - LLFile::remove(getTextureFileName(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); } //called after mHeaderMutex is locked. @@ -2226,7 +2245,9 @@ 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. - if (LLFile::isfile(filename)) + // 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)) { LL_WARNS("TextureCache") << "Entry has body size of zero but file " << filename << " exists. Deleting this file, too." << LL_ENDL; } @@ -2246,7 +2267,7 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename) if (file_maybe_exists) { - LLFile::remove(filename); + LLAPRFile::remove(filename, mHeaderAPRFilePoolp); } } diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index e76d340eda..141f370ecb 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 = 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 5ac7d6b1fe..65a69acc88 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -45,7 +45,11 @@ #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" @@ -401,7 +405,6 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() std::string errorMessage; std::string errorLabel; - std::error_code ec; bool error = false; @@ -472,38 +475,30 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() error = true; // read from getFileName() - LLFile infile(getFileName(), LLFile::in | LLFile::binary, ec); - if (ec || !infile) + LLAPRFile infile; + infile.open(getFileName(),LL_APR_RB); + if (!infile.getFileHandle()) { LL_WARNS() << "Couldn't open file for reading: " << getFileName() << LL_ENDL; errorMessage = llformat("Failed to open animation file %s\n", getFileName().c_str()); } else { - 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; - } + S32 size = LLAPRFile::size(getFileName()); U8* buffer = new(std::nothrow) U8[size]; if (!buffer) { LLError::LLUserWarningMsg::showOutOfMemory(); LL_ERRS() << "Bad memory allocation for buffer, size: " << size << LL_ENDL; } - S64 size_read = infile.read(buffer, size, ec); - if (ec || size_read != size) + S32 size_read = infile.read(buffer,size); + if (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, (S32)size); + LLDataPackerBinaryBuffer dp(buffer, size); LLKeyframeMotion *motionp = new LLKeyframeMotion(getAssetId()); motionp->setCharacter(gAgentAvatarp); if (motionp->deserialize(dp, getAssetId(), false)) @@ -549,17 +544,18 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() setAssetType(assetType); // copy this file into the cache for upload - LLFile infile(filename, LLFile::in | LLFile::binary, ec); - if (!ec && infile.size(ec) > 0) + S32 file_size; + LLAPRFile infile; + infile.open(filename, LL_APR_RB, NULL, &file_size); + if (infile.getFileHandle()) { LLFileSystem file(getAssetId(), assetType, LLFileSystem::APPEND); - S64 read_bytes; const S32 buf_size = 65536; U8 copy_buf[buf_size]; - while (((read_bytes = infile.read(copy_buf, buf_size, ec))) > 0) + while ((file_size = infile.read(copy_buf, buf_size))) { - file.write(copy_buf, (S32)read_bytes); + file.write(copy_buf, file_size); } } else @@ -573,6 +569,7 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() } return LLSD(); + } //========================================================================= diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp old mode 100755 new mode 100644 index 7534d778a5..35ac7919ac --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1140,12 +1140,15 @@ 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 (LLFile::exists(fsyspath(name))); + } 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? return name; } diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp old mode 100755 new mode 100644 index 5cb05460bc..a77b9f6103 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1827,11 +1827,12 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ user_data_path_cache += gDirUtilp->getDirDelimiter(); // See if the plugin executable exists - if (!LLFile::isfile(launcher_name)) + llstat s; + if(LLFile::stat(launcher_name, &s)) { LL_WARNS_ONCE("Media") << "Couldn't find launcher at " << launcher_name << LL_ENDL; } - else if (!LLFile::isfile(plugin_name)) + else if(LLFile::stat(plugin_name, &s)) { #if !LL_LINUX 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 100755 new mode 100644 index cdc41baa88..5d456b1a19 --- 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::remove(cache_dir); + LLFile::rmdir(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; - LLFile::remove(filename); + LLAPRFile::remove(filename, mLocalAPRFilePoolp); // 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 (LLFile::isfile(mHeaderFileName)) + if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp)) { LLAPRFile apr_file(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp); diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp old mode 100755 new mode 100644 index e58a6577f1..d132cbfa36 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -943,7 +943,8 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() gDirUtilp->append(exe_path, "SLVoice"); #endif // See if the vivox executable exists - if (LLFile::isfile(exe_path)) + llstat s; + if (!LLFile::stat(exe_path, &s)) { // vivox executable exists. Build the command line and launch the daemon. LLProcess::Params params; diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt old mode 100755 new mode 100644 index 69c9660575..246fc5e6f8 --- a/indra/test/CMakeLists.txt +++ b/indra/test/CMakeLists.txt @@ -16,7 +16,6 @@ set(test_SOURCE_FILES llbuffer_tut.cpp lldoubledispatch_tut.cpp llevents_tut.cpp - llfile_tut.cpp llhttpdate_tut.cpp llhttpnode_tut.cpp lliohttpserver_tut.cpp @@ -68,7 +67,7 @@ target_link_libraries(lltest if (WINDOWS) set_target_properties(lltest - PROPERTIES + PROPERTIES LINK_FLAGS "/NODEFAULTLIB:LIBCMT" LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\"" RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}" @@ -86,10 +85,10 @@ set(TEST_EXE $) SET_TEST_PATH(LD_LIBRARY_PATH) -LL_TEST_COMMAND(command +LL_TEST_COMMAND(command "${LD_LIBRARY_PATH}" "${TEST_EXE}" - "--output=${CMAKE_CURRENT_BINARY_DIR}/cpp_test_results.txt" + "--output=${CMAKE_CURRENT_BINARY_DIR}/cpp_test_results.txt" "--touch=${CMAKE_CURRENT_BINARY_DIR}/cpp_tests_ok.txt") ADD_CUSTOM_COMMAND( @@ -102,11 +101,11 @@ ADD_CUSTOM_COMMAND( set(test_results ${CMAKE_CURRENT_BINARY_DIR}/cpp_tests_ok.txt) -# This should cause the test executable to be built, but not +# This should cause the test executable to be built, but not # run if LL_TESTS is disabled. This will hopefully keep the -# tests up to date with any code changes changes even if +# tests up to date with any code changes changes even if # developers choose to disable LL_TESTS. -if (LL_TESTS) +if (LL_TESTS) add_custom_target(tests_ok ALL DEPENDS ${test_results}) if(DARWIN) # Support our "@executable_path/../Resources" load path for our test diff --git a/indra/test/llfile_tut.cpp b/indra/test/llfile_tut.cpp deleted file mode 100755 index 9f2a9b2988..0000000000 --- a/indra/test/llfile_tut.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/** - * @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/test/llmessageconfig_tut.cpp b/indra/test/llmessageconfig_tut.cpp old mode 100755 new mode 100644 index b8942e99b3..93443467a2 --- a/indra/test/llmessageconfig_tut.cpp +++ b/indra/test/llmessageconfig_tut.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::remove(mTestConfigDir); + int rmdir = LLFile::rmdir(mTestConfigDir); ensure_equals("rmdir value", rmdir, 0); } diff --git a/indra/test/message_tut.cpp b/indra/test/message_tut.cpp old mode 100755 new mode 100644 index 6fb2b92803..11cd710ef6 --- a/indra/test/message_tut.cpp +++ b/indra/test/message_tut.cpp @@ -113,7 +113,7 @@ namespace tut ensure_equals("rmfile value", rmfile, 0); // rm temp dir - int rmdir = LLFile::remove(mTestConfigDir); + int rmdir = LLFile::rmdir(mTestConfigDir); ensure_equals("rmdir value", rmdir, 0); } -- cgit v1.3 From 9d684bc9241cca4aae79d93886d0f95dcee26d65 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 27 Sep 2024 05:38:39 -0400 Subject: Migrate ~LLPointer()'s peculiar warning case to llpointer.cpp. This allows removing #include "llerror.h" from llpointer.h. Also remove #include "llmutex.h" as a heavy way to get . That requires adding #include "llmutex.h" to llimage.h, llnotifications.h, llwatchdog.cpp and llvolumemgr.cpp, which were inheriting it from llpointer.h. --- indra/llcommon/CMakeLists.txt | 1 + indra/llcommon/llpointer.cpp | 43 +++++++++++++++++++++++++++++++ indra/llcommon/llpointer.h | 19 ++++++++++---- indra/llimage/llimage.h | 5 ++-- indra/llmath/llvolumemgr.cpp | 1 + indra/llrender/lltexturemanagerbridge.cpp | 2 ++ indra/llui/llnotifications.h | 1 + indra/newview/llwatchdog.cpp | 1 + 8 files changed, 66 insertions(+), 7 deletions(-) create mode 100755 indra/llcommon/llpointer.cpp (limited to 'indra/llrender') diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 2de9deea70..5adb0bf083 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -68,6 +68,7 @@ set(llcommon_SOURCE_FILES llmetricperformancetester.cpp llmortician.cpp llmutex.cpp + llpointer.cpp llptrto.cpp llpredicate.cpp llprocess.cpp diff --git a/indra/llcommon/llpointer.cpp b/indra/llcommon/llpointer.cpp new file mode 100755 index 0000000000..1bb7055b3a --- /dev/null +++ b/indra/llcommon/llpointer.cpp @@ -0,0 +1,43 @@ +/** + * @file llpointer.cpp + * @author Nat Goodspeed + * @date 2024-09-26 + * @brief Implementation for llpointer. + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, 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$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "llpointer.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "llerror.h" + +void LLPointerBase::wild_dtor(std::string_view msg) +{ +// LL_WARNS() << msg << LL_ENDL; + llassert_msg(false, msg); +} diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index 71c955c4c5..77c02fab11 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -26,8 +26,8 @@ #ifndef LLPOINTER_H #define LLPOINTER_H -#include "llerror.h" // *TODO: consider eliminating this -#include "llmutex.h" +#include +#include #include // std::swap() //---------------------------------------------------------------------------- @@ -43,8 +43,18 @@ //---------------------------------------------------------------------------- +class LLPointerBase +{ +protected: + // alert the coder that a referenced type's destructor did something very + // strange -- this is in a non-template base class so we can hide the + // implementation in llpointer.cpp + static void wild_dtor(std::string_view msg); +}; + // Note: relies on Type having ref() and unref() methods -template class LLPointer +template +class LLPointer: public LLPointerBase { public: template @@ -106,7 +116,6 @@ public: const Type& operator*() const { return *mPointer; } Type& operator*() { return *mPointer; } - operator BOOL() const { return (mPointer != nullptr); } operator bool() const { return (mPointer != nullptr); } bool operator!() const { return (mPointer == nullptr); } bool isNull() const { return (mPointer == nullptr); } @@ -210,7 +219,7 @@ protected: temp->unref(); if (mPointer != nullptr) { - LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; + wild_dtor("Unreference did assignment to non-NULL because of destructor"); unref(); } } diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 6b14b68c78..1fb61673bd 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -27,10 +27,11 @@ #ifndef LL_LLIMAGE_H #define LL_LLIMAGE_H -#include "lluuid.h" -#include "llstring.h" +#include "llmutex.h" #include "llpointer.h" +#include "llstring.h" #include "lltrace.h" +#include "lluuid.h" constexpr S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2 constexpr S32 MAX_IMAGE_MIP = 12; // 4096x4096 diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index bb0c94d513..d8f649140f 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -25,6 +25,7 @@ #include "linden_common.h" +#include "llmutex.h" #include "llvolumemgr.h" #include "llvolume.h" diff --git a/indra/llrender/lltexturemanagerbridge.cpp b/indra/llrender/lltexturemanagerbridge.cpp index c243f0697a..67838418bf 100644 --- a/indra/llrender/lltexturemanagerbridge.cpp +++ b/indra/llrender/lltexturemanagerbridge.cpp @@ -24,6 +24,8 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "lltexturemanagerbridge.h" // Define a null texture manager bridge. Applications must provide their own bridge implementaton. diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index d56c459560..c7c7435be2 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -93,6 +93,7 @@ #include "llinitparam.h" #include "llinstancetracker.h" #include "llmortician.h" +#include "llmutex.h" #include "llnotificationptr.h" #include "llpointer.h" #include "llrefcount.h" diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp index 614d1afc2a..072743505f 100644 --- a/indra/newview/llwatchdog.cpp +++ b/indra/newview/llwatchdog.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "llwatchdog.h" +#include "llmutex.h" #include "llthread.h" #include "llappviewer.h" -- cgit v1.3 From 852e31b6ff639489a199a54029fd10198d134cbd Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Sun, 4 Jan 2026 16:11:29 -0500 Subject: secondlife/viewer#2674 Optimize LLWorld::renderPropertyLines() - use vertexBatchPreTransformed() --- indra/llmath/v3math.h | 9 +++ indra/llrender/llrender.cpp | 63 +++++++++++++++---- indra/llrender/llrender.h | 13 +++- indra/newview/llviewerparceloverlay.cpp | 104 ++++++++++++++++++-------------- indra/newview/llviewerparceloverlay.h | 5 +- 5 files changed, 133 insertions(+), 61 deletions(-) (limited to 'indra/llrender') diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index 196ecdcf7d..0e11dca876 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -155,6 +155,7 @@ class LLVector3 friend const LLVector3& operator*=(LLVector3 &a, const LLVector3 &b); // Returns a * b; friend const LLVector3& operator*=(LLVector3 &a, F32 k); // Return a times scaler k friend const LLVector3& operator/=(LLVector3 &a, F32 k); // Return a divided by scaler k + friend const LLVector3& operator/=(LLVector3& a, const LLVector3& b); friend const LLVector3& operator*=(LLVector3 &a, const LLQuaternion &b); // Returns a * b; friend LLVector3 operator-(const LLVector3 &a); // Return vector -a @@ -460,6 +461,14 @@ inline const LLVector3& operator/=(LLVector3& a, F32 k) return a; } +inline const LLVector3& operator/=(LLVector3& a, const LLVector3& b) +{ + a.mV[VX] /= b.mV[VX]; + a.mV[VY] /= b.mV[VY]; + a.mV[VZ] /= b.mV[VZ]; + return a; +} + inline LLVector3 operator-(const LLVector3& a) { return LLVector3(-a.mV[VX], -a.mV[VY], -a.mV[VZ]); diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 57be8570af..1a3a499b20 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -1774,25 +1774,64 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z) return; } - if (mUIOffset.empty()) + LLVector4a vert(x, y, z); + transform(vert); + mVerticesp[mCount] = vert; + + mCount++; + mVerticesp[mCount] = mVerticesp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; +} + +void LLRender::transform(LLVector3& vert) +{ + if (!mUIOffset.empty()) { - mVerticesp[mCount].set(x,y,z); + vert += LLVector3(mUIOffset.back().getF32ptr()); + vert *= LLVector3(mUIScale.back().getF32ptr()); } - else +} + +void LLRender::transform(LLVector4a& vert) +{ + if (!mUIOffset.empty()) { - LLVector4a vert(x, y, z); vert.add(mUIOffset.back()); vert.mul(mUIScale.back()); - mVerticesp[mCount] = vert; } +} - mCount++; - mVerticesp[mCount] = mVerticesp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; +void LLRender::untransform(LLVector3& vert) +{ + if (!mUIOffset.empty()) + { + vert /= LLVector3(mUIScale.back().getF32ptr()); + vert -= LLVector3(mUIOffset.back().getF32ptr()); + } +} + +void LLRender::batchTransform(LLVector4a* verts, U32 vert_count) +{ + if (!mUIOffset.empty()) + { + const LLVector4a& offset = mUIOffset.back(); + const LLVector4a& scale = mUIScale.back(); + + for (U32 i = 0; i < vert_count; ++i) + { + verts[i].add(offset); + verts[i].mul(scale); + } + } +} + +void LLRender::vertexBatchPreTransformed(const std::vector& verts) +{ + vertexBatchPreTransformed(verts.data(), narrow(verts.size())); } -void LLRender::vertexBatchPreTransformed(LLVector4a* verts, S32 vert_count) +void LLRender::vertexBatchPreTransformed(const LLVector4a* verts, S32 vert_count) { if (mCount + vert_count > 4094) { @@ -1813,7 +1852,7 @@ void LLRender::vertexBatchPreTransformed(LLVector4a* verts, S32 vert_count) mVerticesp[mCount] = mVerticesp[mCount-1]; } -void LLRender::vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, S32 vert_count) +void LLRender::vertexBatchPreTransformed(const LLVector4a* verts, const LLVector2* uvs, S32 vert_count) { if (mCount + vert_count > 4094) { @@ -1837,7 +1876,7 @@ void LLRender::vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, S32 } } -void LLRender::vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, LLColor4U* colors, S32 vert_count) +void LLRender::vertexBatchPreTransformed(const LLVector4a* verts, const LLVector2* uvs, const LLColor4U* colors, S32 vert_count) { if (mCount + vert_count > 4094) { diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 0801c12fb4..be8539433c 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -450,9 +450,16 @@ public: void diffuseColor4ubv(const U8* c); void diffuseColor4ub(U8 r, U8 g, U8 b, U8 a); - void vertexBatchPreTransformed(LLVector4a* verts, S32 vert_count); - void vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, S32 vert_count); - void vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, LLColor4U*, S32 vert_count); + void transform(LLVector3& vert); + void transform(LLVector4a& vert); + void untransform(LLVector3& vert); + + void batchTransform(LLVector4a* verts, U32 vert_count); + + void vertexBatchPreTransformed(const std::vector& verts); + void vertexBatchPreTransformed(const LLVector4a* verts, S32 vert_count); + void vertexBatchPreTransformed(const LLVector4a* verts, const LLVector2* uvs, S32 vert_count); + void vertexBatchPreTransformed(const LLVector4a* verts, const LLVector2* uvs, const LLColor4U*, S32 vert_count); void setColorMask(bool writeColor, bool writeAlpha); void setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha); diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index 6b4bcbe86e..63bcd82798 100755 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -555,52 +555,52 @@ void LLViewerParcelOverlay::addPropertyLine(F32 start_x, F32 start_y, F32 dx, F3 inside_z = land.resolveHeightRegion(inside_x, inside_y); }; - auto split = [&](U32 lod, const LLVector3& start, F32 x, F32 y, F32 z, F32 part) + auto split = [&](U32 lod, const LLVector4a& start, F32 x, F32 y, F32 z, F32 part) { - F32 new_x = start.mV[VX] + (x - start.mV[VX]) * part; - F32 new_y = start.mV[VY] + (y - start.mV[VY]) * part; - F32 new_z = start.mV[VZ] + (z - start.mV[VZ]) * part; - edge.vertices[lod].emplace_back(new_x, new_y, new_z); + F32 new_x = start[VX] + (x - start[VX]) * part; + F32 new_y = start[VY] + (y - start[VY]) * part; + F32 new_z = start[VZ] + (z - start[VZ]) * part; + edge.pushVertex(lod, new_x, new_y, new_z, water_z); }; auto checkForSplit = [&](U32 lod) { - const std::vector& vertices = edge.vertices[lod]; - const LLVector3& last_outside = vertices.back(); - F32 z0 = last_outside.mV[VZ]; + const std::vector& vertices = edge.verticesUnderWater[lod]; + const LLVector4a& last_outside = vertices.back(); + F32 z0 = last_outside[VZ]; F32 z1 = outside_z; if ((z0 >= water_z && z1 >= water_z) || (z0 < water_z && z1 < water_z)) return; F32 part = (water_z - z0) / (z1 - z0); - const LLVector3& last_inside = vertices[vertices.size() - 2]; + const LLVector4a& last_inside = vertices[vertices.size() - 2]; split(lod, last_inside, inside_x, inside_y, inside_z, part); split(lod, last_outside, outside_x, outside_y, outside_z, part); }; auto pushTwoVertices = [&](U32 lod) { + LLVector3 out(outside_x, outside_y, outside_z); + LLVector3 in(inside_x, inside_y, inside_z); if (fabs(inside_z - outside_z) < LINE_WIDTH / 5) { - edge.vertices[lod].emplace_back(inside_x, inside_y, inside_z); + edge.pushVertex(lod, inside_x, inside_y, inside_z, water_z); } else { // Make the line thinner if heights differ too much - LLVector3 out(outside_x, outside_y, outside_z); - LLVector3 in(inside_x, inside_y, inside_z); LLVector3 dist(in - out); F32 coef = dist.length() / LINE_WIDTH; LLVector3 new_in(out + dist / coef); - edge.vertices[lod].push_back(new_in); + edge.pushVertex(lod, new_in[VX], new_in[VY], new_in[VZ], water_z); } - edge.vertices[lod].emplace_back(outside_x, outside_y, outside_z); + edge.pushVertex(lod, outside_x, outside_y, outside_z, water_z); }; // Point A simplified (first two vertices) pushTwoVertices(1); // Point A detailized (only one vertex) - edge.vertices[0].emplace_back(outside_x, outside_y, outside_z); + edge.pushVertex(0, outside_x, outside_y, outside_z, water_z); // Point B (two vertices) move(LINE_WIDTH); @@ -628,7 +628,23 @@ void LLViewerParcelOverlay::addPropertyLine(F32 start_x, F32 start_y, F32 dx, F3 pushTwoVertices(1); // Point G detailized (only one vertex) - edge.vertices[0].emplace_back(outside_x, outside_y, outside_z); + edge.pushVertex(0, outside_x, outside_y, outside_z, water_z); +} + +void LLViewerParcelOverlay::Edge::pushVertex(U32 lod, F32 x, F32 y, F32 z, F32 water_z) +{ + verticesUnderWater[lod].emplace_back(x, y, z); + gGL.transform(verticesUnderWater[lod].back()); + + if (z >= water_z) + { + verticesAboveWater[lod].push_back(verticesUnderWater[lod].back()); + } + else + { + verticesAboveWater[lod].emplace_back(x, y, water_z); + gGL.transform(verticesAboveWater[lod].back()); + } } void LLViewerParcelOverlay::setDirty() @@ -673,6 +689,9 @@ void LLViewerParcelOverlay::renderPropertyLines() if (!show) return; + LL_PROFILE_ZONE_SCOPED; + LL_PROFILE_GPU_ZONE("Property Lines"); + LLSurface& land = mRegion->getLand(); bool render_water = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER); @@ -710,6 +729,8 @@ void LLViewerParcelOverlay::renderPropertyLines() // Stomp the camera into two dimensions LLVector3 camera_region = mRegion->getPosRegionFromGlobal( gAgentCamera.getCameraPositionGlobal() ); + bool draw_underwater = camera_region.mV[VZ] < water_z || + !gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER); // Set up a cull plane 2 * PARCEL_GRID_STEP_METERS behind // the camera. The cull plane normal is the camera's at axis. @@ -717,17 +738,22 @@ void LLViewerParcelOverlay::renderPropertyLines() cull_plane_point *= -2.f * PARCEL_GRID_STEP_METERS; cull_plane_point += camera_region; - bool render_hidden = LLSelectMgr::sRenderHiddenSelections && LLFloaterReg::instanceVisible("build"); + bool render_hidden = !draw_underwater && + LLSelectMgr::sRenderHiddenSelections && + LLFloaterReg::instanceVisible("build"); constexpr F32 PROPERTY_LINE_CLIP_DIST_SQUARED = 256.f * 256.f; const F32 PROPERTY_LINE_LOD0_DIST_SQUARED = PROPERTY_LINE_CLIP_DIST_SQUARED / 25; for (const Edge& edge : mEdges) { - const std::vector& vertices0 = edge.vertices[0]; - LLVector3 center = (vertices0.front() + vertices0.back()) / 2; - F32 dist_squared = dist_vec_squared(center, camera_region); + const std::vector& vertices0 = edge.verticesAboveWater[0]; + const F32* first = vertices0.front().getF32ptr(); + const F32* last = vertices0.back().getF32ptr(); + LLVector3 center((first[VX] + last[VX]) / 2, (first[VY] + last[VY]) / 2, (first[VZ] + last[VZ]) / 2); + gGL.untransform(center); + F32 dist_squared = dist_vec_squared(center, camera_region); if (dist_squared > PROPERTY_LINE_CLIP_DIST_SQUARED) { continue; @@ -748,39 +774,27 @@ void LLViewerParcelOverlay::renderPropertyLines() gGL.color4ubv(edge.color.mV); - for (const LLVector3& vertex : edge.vertices[lod]) + if (draw_underwater) { - if (render_hidden || camera_z < water_z || vertex.mV[2] >= water_z) - { - gGL.vertex3fv(vertex.mV); - } - else - { - LLVector3 visible = vertex; - visible.mV[VZ] = water_z; - gGL.vertex3fv(visible.mV); - } + gGL.vertexBatchPreTransformed(edge.verticesUnderWater[lod]); } - - gGL.end(); - - if (render_hidden) + else { - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER); + gGL.vertexBatchPreTransformed(edge.verticesAboveWater[lod]); - gGL.begin(LLRender::TRIANGLE_STRIP); + if (render_hidden) + { + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER); - LLColor4U color = edge.color; - color.mV[VALPHA] /= 4; - gGL.color4ubv(color.mV); + LLColor4U color = edge.color; + color.mV[VALPHA] /= 4; + gGL.color4ubv(color.mV); - for (const LLVector3& vertex : edge.vertices[lod]) - { - gGL.vertex3fv(vertex.mV); + gGL.vertexBatchPreTransformed(edge.verticesUnderWater[lod]); } - - gGL.end(); } + + gGL.end(); } gGL.popMatrix(); diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h index 68900d16a6..7271c85701 100644 --- a/indra/newview/llviewerparceloverlay.h +++ b/indra/newview/llviewerparceloverlay.h @@ -116,7 +116,10 @@ private: struct Edge { - std::vector vertices[2]; // 0 - detailized, 1 - simplified + void pushVertex(U32 lod, F32 x, F32 y, F32 z, F32 water_z); + // LOD: 0 - detailized, 1 - simplified + std::vector verticesAboveWater[2]; + std::vector verticesUnderWater[2]; LLColor4U color; }; -- 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/llrender') 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 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/llrender') 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/llrender') 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