# Conflicts:
#	indra/llcommon/llfile.cpp
#	indra/llui/llviewereventrecorder.cpp
master
Ansariel 2025-10-21 00:24:37 +02:00
commit f3bce39d28
9 changed files with 375 additions and 172 deletions

View File

@ -35,7 +35,6 @@
#if LL_WINDOWS #if LL_WINDOWS
#include "llwin32headers.h" #include "llwin32headers.h"
#include <stdlib.h> // Windows errno
#include <vector> #include <vector>
#else #else
#include <errno.h> #include <errno.h>
@ -49,6 +48,86 @@ static std::string empty;
// variants of strerror() to report errors. // variants of strerror() to report errors.
#if LL_WINDOWS #if LL_WINDOWS
// For the situations where we directly call into Windows API functions we need to translate
// the Windows error codes into errno values
namespace
{
struct errentry
{
unsigned long oserr; // Windows OS error value
int errcode; // System V error code
};
}
// translation table between Windows OS error value and System V errno code
static errentry const errtable[]
{
{ ERROR_INVALID_FUNCTION, EINVAL }, // 1
{ ERROR_FILE_NOT_FOUND, ENOENT }, // 2
{ ERROR_PATH_NOT_FOUND, ENOENT }, // 3
{ ERROR_TOO_MANY_OPEN_FILES, EMFILE }, // 4
{ ERROR_ACCESS_DENIED, EACCES }, // 5
{ ERROR_INVALID_HANDLE, EBADF }, // 6
{ ERROR_ARENA_TRASHED, ENOMEM }, // 7
{ ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, // 8
{ ERROR_INVALID_BLOCK, ENOMEM }, // 9
{ ERROR_BAD_ENVIRONMENT, E2BIG }, // 10
{ ERROR_BAD_FORMAT, ENOEXEC }, // 11
{ ERROR_INVALID_ACCESS, EINVAL }, // 12
{ ERROR_INVALID_DATA, EINVAL }, // 13
{ ERROR_INVALID_DRIVE, ENOENT }, // 15
{ ERROR_CURRENT_DIRECTORY, EACCES }, // 16
{ ERROR_NOT_SAME_DEVICE, EXDEV }, // 17
{ ERROR_NO_MORE_FILES, ENOENT }, // 18
{ ERROR_LOCK_VIOLATION, EACCES }, // 33
{ ERROR_BAD_NETPATH, ENOENT }, // 53
{ ERROR_NETWORK_ACCESS_DENIED, EACCES }, // 65
{ ERROR_BAD_NET_NAME, ENOENT }, // 67
{ ERROR_FILE_EXISTS, EEXIST }, // 80
{ ERROR_CANNOT_MAKE, EACCES }, // 82
{ ERROR_FAIL_I24, EACCES }, // 83
{ ERROR_INVALID_PARAMETER, EINVAL }, // 87
{ ERROR_NO_PROC_SLOTS, EAGAIN }, // 89
{ ERROR_DRIVE_LOCKED, EACCES }, // 108
{ ERROR_BROKEN_PIPE, EPIPE }, // 109
{ ERROR_DISK_FULL, ENOSPC }, // 112
{ ERROR_INVALID_TARGET_HANDLE, EBADF }, // 114
{ ERROR_WAIT_NO_CHILDREN, ECHILD }, // 128
{ ERROR_CHILD_NOT_COMPLETE, ECHILD }, // 129
{ ERROR_DIRECT_ACCESS_HANDLE, EBADF }, // 130
{ ERROR_NEGATIVE_SEEK, EINVAL }, // 131
{ ERROR_SEEK_ON_DEVICE, EACCES }, // 132
{ ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, // 145
{ ERROR_NOT_LOCKED, EACCES }, // 158
{ ERROR_BAD_PATHNAME, ENOENT }, // 161
{ ERROR_MAX_THRDS_REACHED, EAGAIN }, // 164
{ ERROR_LOCK_FAILED, EACCES }, // 167
{ ERROR_ALREADY_EXISTS, EEXIST }, // 183
{ ERROR_FILENAME_EXCED_RANGE, ENOENT }, // 206
{ ERROR_NESTING_NOT_ALLOWED, EAGAIN }, // 215
{ ERROR_NO_UNICODE_TRANSLATION, EILSEQ }, // 1113
{ ERROR_NOT_ENOUGH_QUOTA, ENOMEM } // 1816
};
static int set_errno_from_oserror(unsigned long oserr)
{
if (!oserr)
return 0;
// Check the table for the Windows OS error code
for (const struct errentry &entry : errtable)
{
if (oserr == entry.oserr)
{
_set_errno(entry.errcode);
return -1;
}
}
_set_errno(EINVAL);
return -1;
}
// On Windows, use strerror_s(). // On Windows, use strerror_s().
std::string strerr(int errn) std::string strerr(int errn)
{ {
@ -57,7 +136,67 @@ std::string strerr(int errn)
return buffer; return buffer;
} }
typedef std::basic_ios<char,std::char_traits < char > > _Myios; inline bool is_slash(wchar_t const c)
{
return c == L'\\' || c == L'/';
}
static std::wstring utf8path_to_wstring(const std::string& utf8path)
{
if (utf8path.size() >= MAX_PATH)
{
// By prepending "\\?\" to a path, Windows widechar file APIs will not fail on long path names
std::wstring utf16path = L"\\\\?\\" + ll_convert<std::wstring>(utf8path);
// We need to make sure that the path does not contain forward slashes as above
// prefix does bypass the path normalization that replaces slashes with backslashes
// before passing the path to kernel mode APIs
std::replace(utf16path.begin(), utf16path.end(), L'/', L'\\');
return utf16path;
}
return ll_convert<std::wstring>(utf8path);
}
static unsigned short get_fileattr(const std::wstring& utf16path, bool dontFollowSymLink = false)
{
unsigned long flags = FILE_FLAG_BACKUP_SEMANTICS;
if (dontFollowSymLink)
{
flags |= FILE_FLAG_OPEN_REPARSE_POINT;
}
HANDLE file_handle = CreateFileW(utf16path.c_str(), FILE_READ_ATTRIBUTES,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr, OPEN_EXISTING, flags, nullptr);
if (file_handle != INVALID_HANDLE_VALUE)
{
FILE_ATTRIBUTE_TAG_INFO attribute_info;
if (GetFileInformationByHandleEx(file_handle, FileAttributeTagInfo, &attribute_info, sizeof(attribute_info)))
{
// A volume path alone (only drive letter) is not recognized as directory while it technically is
bool is_directory = (attribute_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
(iswalpha(utf16path[0]) && utf16path[1] == ':' &&
(!utf16path[2] || (is_slash(utf16path[2]) && !utf16path[3])));
unsigned short st_mode = is_directory ? S_IFDIR :
(attribute_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ? S_IFLNK : S_IFREG);
st_mode |= (attribute_info.FileAttributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : S_IREAD | S_IWRITE;
// we do not try to guess executable flag
// propagate user bits to group/other fields:
st_mode |= (st_mode & 0700) >> 3;
st_mode |= (st_mode & 0700) >> 6;
CloseHandle(file_handle);
return st_mode;
}
}
// Retrieve last error and set errno before calling CloseHandle()
set_errno_from_oserror(GetLastError());
if (file_handle != INVALID_HANDLE_VALUE)
{
CloseHandle(file_handle);
}
return 0;
}
#else #else
// On Posix we want to call strerror_r(), but alarmingly, there are two // On Posix we want to call strerror_r(), but alarmingly, there are two
@ -108,18 +247,13 @@ std::string strerr(int errn)
} }
#endif // ! LL_WINDOWS #endif // ! LL_WINDOWS
// On either system, shorthand call just infers global 'errno'. static int warnif(const std::string& desc, const std::string& filename, int rc, int accept = 0)
std::string strerr()
{
return strerr(errno);
}
int warnif(const std::string& desc, const std::string& filename, int rc, int accept=0)
{ {
if (rc < 0) if (rc < 0)
{ {
// Capture errno before we start emitting output // Capture errno before we start emitting output
int errn = errno; int errn = errno;
// For certain operations, a particular errno value might be // For certain operations, a particular errno value might be
// acceptable -- e.g. stat() could permit ENOENT, mkdir() could permit // acceptable -- e.g. stat() could permit ENOENT, mkdir() could permit
// EEXIST. Don't warn if caller explicitly says this errno is okay. // EEXIST. Don't warn if caller explicitly says this errno is okay.
@ -176,61 +310,68 @@ int warnif(const std::string& desc, const std::string& filename, int rc, int acc
// static // static
int LLFile::mkdir(const std::string& dirname, int perms) int LLFile::mkdir(const std::string& dirname, int perms)
{ {
#if LL_WINDOWS
// permissions are ignored on Windows
std::wstring utf16dirname = ll_convert<std::wstring>(dirname);
int rc = _wmkdir(utf16dirname.c_str());
#else
int rc = ::mkdir(dirname.c_str(), (mode_t)perms);
#endif
// We often use mkdir() to ensure the existence of a directory that might // 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 // already exist. There is no known case in which we want to call out as
// an error the requested directory already existing. // an error the requested directory already existing.
#if LL_WINDOWS
// permissions are ignored on Windows
int rc = 0;
std::wstring utf16dirname = utf8path_to_wstring(dirname);
if (!CreateDirectoryW(utf16dirname.c_str(), nullptr))
{
// Only treat other errors than an already existing file as a real error
unsigned long oserr = GetLastError();
if (oserr != ERROR_ALREADY_EXISTS)
{
rc = set_errno_from_oserror(oserr);
}
}
#else
int rc = ::mkdir(dirname.c_str(), (mode_t)perms);
if (rc < 0 && errno == EEXIST) if (rc < 0 && errno == EEXIST)
{ {
// this is not the error you want, move along // this is not the error you want, move along
return 0; return 0;
} }
#endif
// anything else might be a problem // anything else might be a problem
return warnif("mkdir", dirname, rc, EEXIST); return warnif("mkdir", dirname, rc);
} }
// static // static
int LLFile::rmdir(const std::string& dirname) int LLFile::rmdir(const std::string& dirname, int suppress_error)
{ {
#if LL_WINDOWS #if LL_WINDOWS
// permissions are ignored on Windows std::wstring utf16dirname = utf8path_to_wstring(dirname);
std::wstring utf16dirname = ll_convert<std::wstring>(dirname);
int rc = _wrmdir(utf16dirname.c_str()); int rc = _wrmdir(utf16dirname.c_str());
#else #else
int rc = ::rmdir(dirname.c_str()); int rc = ::rmdir(dirname.c_str());
#endif #endif
return warnif("rmdir", dirname, rc); return warnif("rmdir", dirname, rc, suppress_error);
} }
// static // static
LLFILE* LLFile::fopen(const std::string& filename, const char* mode) /* Flawfinder: ignore */ LLFILE* LLFile::fopen(const std::string& filename, const char* mode)
{ {
#if LL_WINDOWS #if LL_WINDOWS
std::wstring utf16filename = ll_convert<std::wstring>(filename); std::wstring utf16filename = utf8path_to_wstring(filename);
std::wstring utf16mode = ll_convert<std::wstring>(std::string(mode)); std::wstring utf16mode = ll_convert<std::wstring>(std::string(mode));
return _wfopen(utf16filename.c_str(),utf16mode.c_str()); return _wfopen(utf16filename.c_str(), utf16mode.c_str());
#else #else
return ::fopen(filename.c_str(),mode); /* Flawfinder: ignore */ return ::fopen(filename.c_str(),mode);
#endif #endif
} }
LLFILE* LLFile::_fsopen(const std::string& filename, const char* mode, int sharingFlag) // <FS:Ansariel> Keep this for Windows
{
#if LL_WINDOWS #if LL_WINDOWS
std::wstring utf16filename = ll_convert<std::wstring>(filename); LLFILE* LLFile::fsopen(const std::string& filename, const char* mode, int sharingFlag)
{
std::wstring utf16filename = utf8path_to_wstring(filename);
std::wstring utf16mode = ll_convert<std::wstring>(std::string(mode)); std::wstring utf16mode = ll_convert<std::wstring>(std::string(mode));
return _wfsopen(utf16filename.c_str(),utf16mode.c_str(),sharingFlag); return _wfsopen(utf16filename.c_str(), utf16mode.c_str(), sharingFlag);
#else
llassert(0);//No corresponding function on non-windows
return NULL;
#endif
} }
#endif
// </FS:Ansariel>
int LLFile::close(LLFILE * file) int LLFile::close(LLFILE * file)
{ {
@ -242,9 +383,10 @@ int LLFile::close(LLFILE * file)
return ret_value; return ret_value;
} }
// static
std::string LLFile::getContents(const std::string& filename) std::string LLFile::getContents(const std::string& filename)
{ {
LLFILE* fp = fopen(filename, "rb"); /* Flawfinder: ignore */ LLFILE* fp = LLFile::fopen(filename, "rb");
if (fp) if (fp)
{ {
fseek(fp, 0, SEEK_END); fseek(fp, 0, SEEK_END);
@ -261,23 +403,57 @@ std::string LLFile::getContents(const std::string& filename)
return LLStringUtil::null; return LLStringUtil::null;
} }
int LLFile::remove(const std::string& filename, int supress_error) // static
int LLFile::remove(const std::string& filename, int suppress_error)
{ {
#if LL_WINDOWS #if LL_WINDOWS
std::wstring utf16filename = ll_convert<std::wstring>(filename); // Posix remove() works on both files and directories although on Windows
int rc = _wremove(utf16filename.c_str()); // remove() and its wide char variant _wremove() only removes files just
// as its siblings unlink() and _wunlink().
// If we really only want to support files we should instead use
// unlink() in the non-Windows part below too
int rc = -1;
std::wstring utf16filename = utf8path_to_wstring(filename);
unsigned short st_mode = get_fileattr(utf16filename);
if (S_ISDIR(st_mode))
{
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
{
// get_fileattr() failed and already set errno, preserve it for correct error reporting
}
#else #else
int rc = ::remove(filename.c_str()); int rc = ::remove(filename.c_str());
#endif #endif
return warnif("remove", filename, rc, supress_error); return warnif("remove", filename, rc, suppress_error);
} }
int LLFile::rename(const std::string& filename, const std::string& newname, int supress_error) // static
int LLFile::rename(const std::string& filename, const std::string& newname, int suppress_error)
{ {
#if LL_WINDOWS #if LL_WINDOWS
std::wstring utf16filename = ll_convert<std::wstring>(filename); // Posix rename() will gladly overwrite a file at newname if it exists, the Windows
std::wstring utf16newname = ll_convert<std::wstring>(newname); // rename(), respectively _wrename(), will bark on that. Instead call directly the Windows
int rc = _wrename(utf16filename.c_str(),utf16newname.c_str()); // 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))
{
rc = set_errno_from_oserror(GetLastError());
}
#else #else
int rc = ::rename(filename.c_str(),newname.c_str()); int rc = ::rename(filename.c_str(),newname.c_str());
//<FS:Beq> FIRE-21669 & FIRE-11276 cross volume link rename workaround. //<FS:Beq> FIRE-21669 & FIRE-11276 cross volume link rename workaround.
@ -314,22 +490,26 @@ int LLFile::rename(const std::string& filename, const std::string& newname, int
} }
//</FS:Beq> //</FS:Beq>
#endif #endif
return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc, supress_error); return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc, suppress_error);
} }
// Make this a define rather than using magic numbers multiple times in the code
#define LLFILE_COPY_BUFFER_SIZE 16384
// static
bool LLFile::copy(const std::string& from, const std::string& to) bool LLFile::copy(const std::string& from, const std::string& to)
{ {
bool copied = false; bool copied = false;
LLFILE* in = LLFile::fopen(from, "rb"); /* Flawfinder: ignore */ LLFILE* in = LLFile::fopen(from, "rb");
if (in) if (in)
{ {
LLFILE* out = LLFile::fopen(to, "wb"); /* Flawfinder: ignore */ LLFILE* out = LLFile::fopen(to, "wb");
if (out) if (out)
{ {
char buf[16384]; /* Flawfinder: ignore */ char buf[LLFILE_COPY_BUFFER_SIZE];
size_t readbytes; size_t readbytes;
bool write_ok = true; bool write_ok = true;
while(write_ok && (readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */ while (write_ok && (readbytes = fread(buf, 1, LLFILE_COPY_BUFFER_SIZE, in)))
{ {
if (fwrite(buf, 1, readbytes, out) != readbytes) if (fwrite(buf, 1, readbytes, out) != readbytes)
{ {
@ -348,44 +528,73 @@ bool LLFile::copy(const std::string& from, const std::string& to)
return copied; return copied;
} }
int LLFile::stat(const std::string& filename, llstat* filestatus) // static
int LLFile::stat(const std::string& filename, llstat* filestatus, int suppress_error)
{ {
#if LL_WINDOWS #if LL_WINDOWS
std::wstring utf16filename = ll_convert<std::wstring>(filename); std::wstring utf16filename = utf8path_to_wstring(filename);
// <FS:ND> Make sure no path does end in / or \. Otherwise _wstat fails // <FS:ND> Make sure no path does end in / or \. Otherwise _wstat fails
// See http://msdn.microsoft.com/en-us/library/windows/desktop/aa364418(v=vs.85).aspx (FindFileFirst) // See http://msdn.microsoft.com/en-us/library/windows/desktop/aa364418(v=vs.85).aspx (FindFileFirst)
if( utf16filename.size() ) if (!utf16filename.empty())
{ {
wchar_t cLast( utf16filename[ utf16filename.size() -1 ] ); wchar_t cLast(utf16filename[utf16filename.size() - 1]);
if( cLast == '\\' || cLast == '/' ) if (cLast == '\\' || cLast == '/')
utf16filename[ utf16filename.size() -1 ] = 0; utf16filename[utf16filename.size() - 1] = 0;
} }
// </FS:ND> // </FS:ND>
int rc = _wstat(utf16filename.c_str(),filestatus); int rc = _wstat64(utf16filename.c_str(), filestatus);
#else #else
int rc = ::stat(filename.c_str(),filestatus); int rc = ::stat(filename.c_str(), filestatus);
#endif #endif
// We use stat() to determine existence (see isfile(), isdir()). return warnif("stat", filename, rc, suppress_error);
// Don't spam the log if the subject pathname doesn't exist.
return warnif("stat", filename, rc, ENOENT);
} }
// static
unsigned short LLFile::getattr(const std::string& filename, bool dontFollowSymLink, int suppress_error)
{
#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)
{
return st_mode;
}
#else
llstat filestatus;
int rc = dontFollowSymLink ? ::lstat(filename.c_str(), &filestatus) : ::stat(filename.c_str(), &filestatus);
if (rc == 0)
{
return filestatus.st_mode;
}
#endif
warnif("getattr", filename, rc, suppress_error);
return 0;
}
// static
bool LLFile::isdir(const std::string& filename) bool LLFile::isdir(const std::string& filename)
{ {
llstat st; return S_ISDIR(getattr(filename));
return stat(filename, &st) == 0 && S_ISDIR(st.st_mode);
} }
// static
bool LLFile::isfile(const std::string& filename) bool LLFile::isfile(const std::string& filename)
{ {
llstat st; return S_ISREG(getattr(filename));
return stat(filename, &st) == 0 && S_ISREG(st.st_mode);
} }
// static
bool LLFile::islink(const std::string& filename)
{
return S_ISLNK(getattr(filename, true));
}
// static
const char *LLFile::tmpdir() const char *LLFile::tmpdir()
{ {
static std::string utf8path; static std::string utf8path;
@ -412,75 +621,8 @@ const char *LLFile::tmpdir()
return utf8path.c_str(); return utf8path.c_str();
} }
/***************** Modified file stream created to overcome the incorrect behaviour of posix fopen in windows *******************/
#if LL_WINDOWS #if LL_WINDOWS
LLFILE * LLFile::_Fiopen(const std::string& filename,
std::ios::openmode mode)
{ // open a file
static const char *mods[] =
{ // fopen mode strings corresponding to valid[i]
"r", "w", "w", "a", "rb", "wb", "wb", "ab",
"r+", "w+", "a+", "r+b", "w+b", "a+b",
0};
static const int valid[] =
{ // valid combinations of open flags
ios_base::in,
ios_base::out,
ios_base::out | ios_base::trunc,
ios_base::out | ios_base::app,
ios_base::in | ios_base::binary,
ios_base::out | ios_base::binary,
ios_base::out | ios_base::trunc | ios_base::binary,
ios_base::out | ios_base::app | ios_base::binary,
ios_base::in | ios_base::out,
ios_base::in | ios_base::out | ios_base::trunc,
ios_base::in | ios_base::out | ios_base::app,
ios_base::in | ios_base::out | ios_base::binary,
ios_base::in | ios_base::out | ios_base::trunc
| ios_base::binary,
ios_base::in | ios_base::out | ios_base::app
| ios_base::binary,
0};
LLFILE *fp = 0;
int n;
ios_base::openmode atendflag = mode & ios_base::ate;
ios_base::openmode norepflag = mode & ios_base::_Noreplace;
if (mode & ios_base::_Nocreate)
mode |= ios_base::in; // file must exist
mode &= ~(ios_base::ate | ios_base::_Nocreate | ios_base::_Noreplace);
for (n = 0; valid[n] != 0 && valid[n] != mode; ++n)
; // look for a valid mode
if (valid[n] == 0)
return (0); // no valid mode
else if (norepflag && mode & (ios_base::out | ios_base::app)
&& (fp = LLFile::fopen(filename, "r")) != 0) /* Flawfinder: ignore */
{ // file must not exist, close and fail
fclose(fp);
return (0);
}
else if (fp != 0 && fclose(fp) != 0)
return (0); // can't close after test open
// should open with protection here, if other than default
else if ((fp = LLFile::fopen(filename, mods[n])) == 0) /* Flawfinder: ignore */
return (0); // open failed
if (!atendflag || fseek(fp, 0, SEEK_END) == 0)
return (fp); // no need to seek to end, or seek succeeded
fclose(fp); // can't position at end
return (0);
}
#endif /* LL_WINDOWS */
#if LL_WINDOWS
/************** input file stream ********************************/ /************** input file stream ********************************/
llifstream::llifstream() {} llifstream::llifstream() {}

View File

@ -41,8 +41,9 @@ typedef FILE LLFILE;
#include <sys/stat.h> #include <sys/stat.h>
#if LL_WINDOWS #if LL_WINDOWS
// windows version of stat function and stat data structure are called _stat // The Windows version of stat function and stat data structure are called _stat64
typedef struct _stat llstat; // We use _stat64 here to support 64-bit st_size and time_t values
typedef struct _stat64 llstat;
#else #else
typedef struct stat llstat; typedef struct stat llstat;
#include <sys/types.h> #include <sys/types.h>
@ -56,35 +57,115 @@ typedef struct stat llstat;
# define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR) # define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
#endif #endif
// Windows C runtime library does not define this and does not support symlink detection in the
// stat functions but we do in our getattr() function
#ifndef S_IFLNK
#define S_IFLNK 0xA000 /* symlink */
#endif
#ifndef S_ISLNK
#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
#endif
#include "llstring.h" // safe char* -> std::string conversion #include "llstring.h" // safe char* -> std::string conversion
/// LLFile is a class of static functions operating on paths
/// All the functions with a path string input take UTF8 path/filenames
class LL_COMMON_API LLFile class LL_COMMON_API LLFile
{ {
public: public:
// All these functions take UTF8 path/filenames. /// open a file with the specified access mode
static LLFILE* fopen(const std::string& filename,const char* accessmode); /* Flawfinder: ignore */ static LLFILE* fopen(const std::string& filename, const char* accessmode); /* Flawfinder: ignore */
static LLFILE* _fsopen(const std::string& filename,const char* accessmode,int sharingFlag); ///< 'accessmode' follows the rules of the Posix fopen() mode parameter
/// "r" open the file for reading only and positions the stream at the beginning
/// "r+" open the file for reading and writing and positions the stream at the beginning
/// "w" open the file for reading and writing and truncate it to zero length
/// "w+" open or create the file for reading and writing and truncate to zero length if it existed
/// "a" open the file for reading and writing and position the stream at the end of the file
/// "a+" open or create the file for reading and writing and position the stream at the end of the file
///
/// in addition to these values, "b" can be appended to indicate binary stream access, but on Linux and Mac
/// this is strictly for compatibility and has no effect. On Windows this makes the file functions not
/// try to translate line endings. Windows also allows to append "t" to indicate text mode. If neither
/// "b" or "t" is defined, Windows uses the value set by _fmode which by default is _O_TEXT.
/// This means that it is always a good idea to append "b" specifically for binary file access to
/// avoid corruption of the binary consistency of the data stream when reading or writing
/// Other characters in 'accessmode' will usually cause an error as fopen will verify this parameter
/// @returns a valid LLFILE* pointer on success or NULL on failure
// <FS:Ansariel> Keep this for Windows
#if LL_WINDOWS
static LLFILE* fsopen(const std::string& filename, const char* accessmode, int sharingFlag);
#endif
static int close(LLFILE * file); static int close(LLFILE * file);
/// 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);
///< @returns the content of the file or an empty string on failure
// perms is a permissions mask like 0777 or 0700. In most cases it will /// create a directory
// be overridden by the user's umask. It is ignored on Windows.
// mkdir() considers "directory already exists" to be SUCCESS.
static int mkdir(const std::string& filename, int perms = 0700); static int mkdir(const std::string& filename, int perms = 0700);
///< perms is a permissions mask like 0777 or 0700. In most cases it will be
/// overridden by the user's umask. It is ignored on Windows.
/// mkdir() considers "directory already exists" to be not an error.
/// @returns 0 on success and -1 on failure.
static int rmdir(const std::string& filename); //// remove a directory
static int remove(const std::string& filename, int supress_error = 0); static int rmdir(const std::string& filename, int suppress_error = 0);
static int rename(const std::string& filename,const std::string& newname, int supress_error = 0); ///< pass ENOENT in the optional 'suppress_error' parameter
/// if you don't want a warning in the log when the directory does not exist
/// @returns 0 on success and -1 on failure.
/// remove a file or directory
static int remove(const std::string& filename, int suppress_error = 0);
///< pass ENOENT in the optional 'suppress_error' parameter
/// if you don't want a warning in the log when the directory does not exist
/// @returns 0 on success and -1 on failure.
/// rename a file
static int rename(const std::string& filename, const std::string& newname, int suppress_error = 0);
///< it will silently overwrite newname if it exists without returning an error
/// Posix guarantees that if newname already exists, then there will be no moment
/// in which for other processes newname does not exist. There is no such guarantee
/// under Windows at this time. It may do it in the same way but the used Windows API
/// does not make such guarantees.
/// @returns 0 on success and -1 on failure.
/// copy the contents of file from 'from' to 'to' filename
static bool copy(const std::string& from, const std::string& to); static bool copy(const std::string& from, const std::string& to);
///< @returns true on success and false on failure.
static int stat(const std::string& filename,llstat* file_status); /// return the file stat structure for filename
static int stat(const std::string& filename, llstat* file_status, int suppress_error = ENOENT);
///< for compatibility with existing uses of LL_File::stat() we use ENOENT as default in the
/// optional 'suppress_error' parameter to avoid spamming the log with warnings when the API
/// is used to detect if a file exists
/// @returns 0 on success and -1 on failure.
/// get the file or directory attributes for filename
static unsigned short getattr(const std::string& filename, bool dontFollowSymLink = false, int suppress_error = ENOENT);
///< a more lightweight function on Windows to stat, that just returns the file attribute flags
/// dontFollowSymLinks set to true returns the attributes of the symlink if it is one, rather than resolving it
/// we pass by default ENOENT in the optional 'suppress_error' parameter to not spam the log with
/// warnings when the file or directory does not exist
/// @returns 0 on failure and a st_mode value with either S_IFDIR or S_IFREG set otherwise
/// together with the three access bits which under Windows only the write bit is relevant.
/// check if filename is an existing directory
static bool isdir(const std::string& filename); static bool isdir(const std::string& filename);
static bool isfile(const std::string& filename); ///< @returns true if the path is for an existing directory
static LLFILE * _Fiopen(const std::string& filename,
std::ios::openmode mode);
/// check if filename is an existing file
static bool isfile(const std::string& filename);
///< @returns true if the path is for an existing file
/// check if filename is a symlink
static bool islink(const std::string& filename);
///< @returns true if the path is pointing at a symlink
/// return a path to the temporary directory on the system
static const char * tmpdir(); static const char * tmpdir();
}; };

View File

@ -1380,10 +1380,6 @@ bool gunzip_file(const std::string& srcfile, const std::string& dstfile)
} while(gzeof(src) == 0); } while(gzeof(src) == 0);
fclose(dst); fclose(dst);
dst = NULL; dst = NULL;
#if LL_WINDOWS
// Rename in windows needs the dstfile to not exist.
LLFile::remove(dstfile, ENOENT);
#endif
if (LLFile::rename(tmpfile, dstfile) == -1) goto err; /* Flawfinder: ignore */ if (LLFile::rename(tmpfile, dstfile) == -1) goto err; /* Flawfinder: ignore */
retval = true; retval = true;
err: err:
@ -1431,10 +1427,6 @@ bool gzip_file(const std::string& srcfile, const std::string& dstfile)
gzclose(dst); gzclose(dst);
dst = NULL; dst = NULL;
#if LL_WINDOWS
// Rename in windows needs the dstfile to not exist.
LLFile::remove(dstfile);
#endif
if (LLFile::rename(tmpfile, dstfile) == -1) goto err; /* Flawfinder: ignore */ if (LLFile::rename(tmpfile, dstfile) == -1) goto err; /* Flawfinder: ignore */
retval = true; retval = true;
err: err:

View File

@ -704,10 +704,6 @@ bool LLCrashLogger::init()
std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "crashreport.log.old"); std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "crashreport.log.old");
std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "crashreport.log"); std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "crashreport.log");
#if LL_WINDOWS
LLAPRFile::remove(old_log_file);
#endif
LLFile::rename(log_file.c_str(), old_log_file.c_str()); LLFile::rename(log_file.c_str(), old_log_file.c_str());
// Set the log file to crashreport.log // Set the log file to crashreport.log

View File

@ -113,9 +113,6 @@ bool LLFileSystem::renameFile(const LLUUID& old_file_id, const LLAssetType::ETyp
const std::string old_filename = LLDiskCache::metaDataToFilepath(old_file_id, old_file_type); const std::string old_filename = LLDiskCache::metaDataToFilepath(old_file_id, old_file_type);
const std::string new_filename = LLDiskCache::metaDataToFilepath(new_file_id, new_file_type); const std::string new_filename = LLDiskCache::metaDataToFilepath(new_file_id, new_file_type);
// Rename needs the new file to not exist.
LLFileSystem::removeFile(new_file_id, new_file_type, ENOENT);
if (LLFile::rename(old_filename, new_filename) != 0) if (LLFile::rename(old_filename, new_filename) != 0)
{ {
// We would like to return false here indicating the operation // We would like to return false here indicating the operation
@ -142,10 +139,9 @@ S32 LLFileSystem::getFileSize(const LLUUID& file_id, const LLAssetType::EType fi
// file.seekg(0, std::ios::end); // file.seekg(0, std::ios::end);
// file_size = (S32)file.tellg(); // file_size = (S32)file.tellg();
//} //}
llstat file_stat; if (llstat file_stat; LLFile::stat(filename, &file_stat) == 0)
if (LLFile::stat(filename, &file_stat) == 0)
{ {
file_size = file_stat.st_size; file_size = static_cast<S32>(file_stat.st_size);
} }
// </FS:Ansariel> // </FS:Ansariel>

View File

@ -1206,16 +1206,15 @@ bool LLImageTGA::loadFile( const std::string& path )
{ {
return false; return false;
} }
//< FS:ND> FIRE-16342 make sure no one overwrites this file while we load it
// <FS:ND> FIRE-16342 make sure no one overwrites this file while we load it
// LLFILE* file = LLFile::fopen(path, "rb"); /* Flawfinder: ignore */ // LLFILE* file = LLFile::fopen(path, "rb"); /* Flawfinder: ignore */
#ifndef LL_WINDOWS #ifndef LL_WINDOWS
LLFILE* file = LLFile::fopen(path, "rb"); /* Flawfinder: ignore */ LLFILE* file = LLFile::fopen(path, "rb"); /* Flawfinder: ignore */
#else #else
LLFILE* file = LLFile::_fsopen(path, "rb", _SH_DENYWR);/* Flawfinder: ignore */ LLFILE* file = LLFile::fsopen(path, "rb", _SH_DENYWR);/* Flawfinder: ignore */
#endif #endif
// </FS:ND>
// </FS:ND:
if( !file ) if( !file )
{ {

View File

@ -35,7 +35,6 @@ LLViewerEventRecorder::LLViewerEventRecorder() {
// Remove any previous event log file // Remove any previous event log file
// <FS:Ansariel> Name this properly and silence the warnings // <FS:Ansariel> Name this properly and silence the warnings
//std::string old_log_ui_events_to_llsd_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.old"); //std::string old_log_ui_events_to_llsd_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.old");
//LLFile::remove(old_log_ui_events_to_llsd_file, ENOENT);
// //
//mLogFilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.llsd"); //mLogFilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.llsd");

View File

@ -2823,7 +2823,6 @@ void LLAppViewer::initLoggingAndGetLastDuration()
if (gDirUtilp->fileExists(user_data_path_cef_log)) if (gDirUtilp->fileExists(user_data_path_cef_log))
{ {
std::string user_data_path_cef_old = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.old"); std::string user_data_path_cef_old = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.old");
LLFile::remove(user_data_path_cef_old, ENOENT);
LLFile::rename(user_data_path_cef_log, user_data_path_cef_old); LLFile::rename(user_data_path_cef_log, user_data_path_cef_old);
} }
} }

View File

@ -1110,7 +1110,6 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon()
std::string old_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SLVoice.old"); std::string old_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SLVoice.old");
if (gDirUtilp->fileExists(new_log)) if (gDirUtilp->fileExists(new_log))
{ {
LLFile::remove(old_log, ENOENT);
LLFile::rename(new_log, old_log); LLFile::rename(new_log, old_log);
} }