summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/fsyspath.h4
-rw-r--r--indra/llcommon/llcrc.cpp2
-rw-r--r--indra/llcommon/llcrc.h2
-rwxr-xr-xindra/llcommon/llfile.cpp290
-rwxr-xr-xindra/llcommon/llfile.h465
-rw-r--r--indra/llcommon/llprocessor.cpp4
-rw-r--r--indra/llcommon/llprofilercategories.h9
-rw-r--r--indra/llcommon/llsys.cpp6
-rw-r--r--indra/llcommon/tests/llfile_test.cpp115
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