diff options
Diffstat (limited to 'indra/llcommon')
| -rw-r--r-- | indra/llcommon/fsyspath.h | 4 | ||||
| -rw-r--r-- | indra/llcommon/llcrc.cpp | 2 | ||||
| -rw-r--r-- | indra/llcommon/llcrc.h | 2 | ||||
| -rwxr-xr-x | indra/llcommon/llfile.cpp | 290 | ||||
| -rwxr-xr-x | indra/llcommon/llfile.h | 465 | ||||
| -rw-r--r-- | indra/llcommon/llprocessor.cpp | 4 | ||||
| -rw-r--r-- | indra/llcommon/llprofilercategories.h | 9 | ||||
| -rw-r--r-- | indra/llcommon/llsys.cpp | 6 | ||||
| -rw-r--r-- | indra/llcommon/tests/llfile_test.cpp | 115 |
9 files changed, 575 insertions, 322 deletions
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::wstring>(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::intmax_t>(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::string>(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<std::wstring>(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<std::wstring>(_Filename).c_str(), _Mode | ios_base::in) { - std::wstring utf16string(ll_convert<std::wstring>(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<std::wstring>( _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<std::wstring>(_Filename).c_str(), + _Mode | ios_base::in); +} + void llifstream::open(const std::string& _Filename, ios_base::openmode _Mode) { std::ifstream::open(ll_convert<std::wstring>(_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<std::wstring>(_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<std::wstring>(_Filename).c_str(), _Mode | ios_base::out); +} + void llofstream::open(const std::string& _Filename, ios_base::openmode _Mode) { std::ofstream::open(ll_convert<std::wstring>( _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 <fstream> #include <filesystem> #include <sys/stat.h> @@ -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 |
