diff options
| author | Frederick Martian <fredmartian@gmail.com> | 2025-10-26 19:59:02 +0100 |
|---|---|---|
| committer | Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> | 2025-12-10 20:33:58 +0200 |
| commit | 9756b4b70b3cd24c03142d7e52eb2acae52002ef (patch) | |
| tree | 0f99eafe4bcd01661b508cf538206cfcb382346b /indra/llcommon/llfile.cpp | |
| parent | 3ca3ea75c333078013914e174564340f894573e2 (diff) | |
Clarify some documentation and add an LLFile:read() and LLFile::write() static function. These functions will be used to replace LLAPRFile::readEx() and LLAPRFile::writeEx() in an upcoming patch.
Diffstat (limited to 'indra/llcommon/llfile.cpp')
| -rw-r--r-- | indra/llcommon/llfile.cpp | 157 |
1 files changed, 121 insertions, 36 deletions
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index 4ef39674c2..9fff614efb 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -155,12 +155,15 @@ static std::wstring utf8path_to_wstring(const std::string& utf8path) } return ll_convert<std::wstring>(utf8path); } - -static unsigned short get_fileattr(const std::wstring& utf16path, bool dontFollowSymLink = false) +// This function retrieves the file attributes as they are used in Posix +// Like the Posix file functions it returns 0 on success, on failure it returns -1 and sets the errno variable +// if dontfollowSymlink is true it returns the attributes of the symlink itself if it is one +static int get_fileattr(const std::wstring& utf16path, unsigned short& st_mode, bool dontFollowSymLink = false) { - unsigned long flags = FILE_FLAG_BACKUP_SEMANTICS; + unsigned long flags = FILE_FLAG_BACKUP_SEMANTICS; // This allows CreateFile() to open a handle to a directory if (dontFollowSymLink) { + // This lets CreateFile() open a handle to a symlink rather than to the resolved target flags |= FILE_FLAG_OPEN_REPARSE_POINT; } HANDLE file_handle = CreateFileW(utf16path.c_str(), FILE_READ_ATTRIBUTES, @@ -175,27 +178,27 @@ static unsigned short get_fileattr(const std::wstring& utf16path, bool dontFollo bool is_directory = (attribute_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) || (iswalpha(utf16path[0]) && utf16path[1] == ':' && (!utf16path[2] || (is_slash(utf16path[2]) && !utf16path[3]))); - unsigned short st_mode = is_directory ? S_IFDIR : - (attribute_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ? S_IFLNK : S_IFREG); + st_mode = is_directory ? S_IFDIR : + (attribute_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ? S_IFLNK : S_IFREG); st_mode |= (attribute_info.FileAttributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : S_IREAD | S_IWRITE; - // we do not try to guess executable flag + // we do not try to guess the executable flag // propagate user bits to group/other fields: st_mode |= (st_mode & 0700) >> 3; st_mode |= (st_mode & 0700) >> 6; CloseHandle(file_handle); - return st_mode; + return 0; } } // Retrieve last error and set errno before calling CloseHandle() - set_errno_from_oserror(GetLastError()); + int rc = set_errno_from_oserror(GetLastError()); if (file_handle != INVALID_HANDLE_VALUE) { CloseHandle(file_handle); } - return 0; + return rc; } #else @@ -343,7 +346,11 @@ int LLFile::rmdir(const std::string& dirname, int suppress_error) { #if LL_WINDOWS std::wstring utf16dirname = utf8path_to_wstring(dirname); - int rc = _wrmdir(utf16dirname.c_str()); + if (RemoveDirectoryW(utf16dirname.c_str())) + { + return 0; + } + int rc = set_errno_from_oserror(GetLastError()); #else int rc = ::rmdir(dirname.c_str()); #endif @@ -402,27 +409,31 @@ int LLFile::remove(const std::string& filename, int suppress_error) // as its siblings unlink() and _wunlink(). // If we really only want to support files we should instead use // unlink() in the non-Windows part below too - int rc = -1; std::wstring utf16filename = utf8path_to_wstring(filename); - unsigned short st_mode = get_fileattr(utf16filename); - if (S_ISDIR(st_mode)) - { - rc = _wrmdir(utf16filename.c_str()); - } - else if (S_ISREG(st_mode)) - { - rc = _wunlink(utf16filename.c_str()); - } - else if (st_mode) - { - // it is something else than a file or directory - // this should not really happen as long as we do not allow for symlink - // detection in the optional parameter to get_fileattr() - rc = set_errno_from_oserror(ERROR_INVALID_PARAMETER); - } - else + unsigned short st_mode; + int rc = get_fileattr(utf16filename, st_mode); + if (rc == 0) { - // get_fileattr() failed and already set errno, preserve it for correct error reporting + if (S_ISDIR(st_mode)) + { + if (RemoveDirectoryW(utf16filename.c_str())) + { + return 0; + } + } + else if (S_ISREG(st_mode)) + { + if (DeleteFileW(utf16filename.c_str())) + { + return 0; + } + } + else + { + SetLastError(ERROR_INVALID_PARAMETER); + } + // Deleting the file or directory failed + rc = set_errno_from_oserror(GetLastError()); } #else int rc = ::remove(filename.c_str()); @@ -439,17 +450,91 @@ int LLFile::rename(const std::string& filename, const std::string& newname, int // API MoveFileEx() and use its flags to specify that overwrite is allowed. std::wstring utf16filename = utf8path_to_wstring(filename); std::wstring utf16newname = utf8path_to_wstring(newname); - int rc = 0; - if (!MoveFileExW(utf16filename.c_str(), utf16newname.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED)) + if (MoveFileExW(utf16filename.c_str(), utf16newname.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED)) { - rc = set_errno_from_oserror(GetLastError()); + return 0; } + int rc = set_errno_from_oserror(GetLastError()); #else int rc = ::rename(filename.c_str(),newname.c_str()); #endif return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc, suppress_error); } +// static +U64 LLFile::read(const std::string& filename, void* buf, U64 offset, U64 nbytes) +{ + LLFILE* file_handle = LLFile::fopen(filename, "rb"); + if (file_handle == nullptr) + { + warnif("read, opening file", filename, -1); + return 0; + } + + if (offset > 0) + { +#if LL_WINDOWS + // On Windows fseek() uses a long value as offset which is always 32-bit + int rc = _fseeki64(file_handle, (long long)offset, SEEK_SET); +#else + // offset is of type long which is 64-bit in 64-bit GCC + int rc = fseek(file_handle, (long)offset, SEEK_SET); +#endif + if (rc) + { + warnif("read, setting file offset", filename, rc); + fclose(file_handle); + return 0; + } + } + + // element_count is of size_t which is 64-bit on all 64-bit systems + U64 bytes_read = fread(buf, 1, nbytes, file_handle); + if (bytes_read == 0) + { + warnif("read from file", filename, -1); + } + fclose(file_handle); + return bytes_read; +} + +// static +U64 LLFile::write(const std::string& filename, const void* buf, U64 offset, U64 nbytes) +{ + LLFILE* file_handle = LLFile::fopen(filename, "wb"); + if (file_handle == nullptr) + { + warnif("write, opening file", filename, -1); + return 0; + } + + if (offset > 0) + { +#if LL_WINDOWS + // On Windows fseek() uses a long value as offset which is always 32-bit + int rc = _fseeki64(file_handle, (long long)offset, SEEK_SET); +#else + // offset is of type long which is 64-bit in 64-bit GCC + int rc = fseek(file_handle, (long)offset, SEEK_SET); +#endif + if (rc) + { + warnif("write, setting file offset", filename, rc); + fclose(file_handle); + return 0; + } + } + + // element_count is of size_t which is 64-bit on all 64-bit systems + U64 bytes_written = fwrite(buf, 1, nbytes, file_handle); + if (bytes_written == 0) + { + warnif("write to file", filename, -1); + } + fclose(file_handle); + return bytes_written; +} + // Make this a define rather than using magic numbers multiple times in the code #define LLFILE_COPY_BUFFER_SIZE 16384 @@ -523,7 +608,7 @@ S64 LLFile::size(const std::string& filename, int suppress_error) int rc = ::stat(filename.c_str(), &filestatus); if (rc == 0) { - if (S_ISREG(filestatus.st_mode) + if (S_ISREG(filestatus.st_mode)) { return filestatus.st_size; } @@ -542,10 +627,10 @@ unsigned short LLFile::getattr(const std::string& filename, bool dontFollowSymLi #if LL_WINDOWS // _wstat64() is a bit heavyweight on Windows, use a more lightweight API // to just get the attributes - int rc = -1; std::wstring utf16filename = utf8path_to_wstring(filename); - unsigned short st_mode = get_fileattr(utf16filename, dontFollowSymLink); - if (st_mode) + unsigned short st_mode; + int rc = get_fileattr(utf16filename, st_mode, dontFollowSymLink); + if (rc == 0) { return st_mode; } |
