FileSystem: Don't follow symlinks when recursively deleting directories

This commit is contained in:
chaoticgd 2024-12-01 23:40:58 +00:00 committed by Ty
parent 46d17fcb20
commit 6e4dc1e8ab
2 changed files with 78 additions and 26 deletions

View File

@ -1225,7 +1225,12 @@ bool FileSystem::RecursiveDeleteDirectory(const char* path)
{ {
for (const FILESYSTEM_FIND_DATA& fd : results) for (const FILESYSTEM_FIND_DATA& fd : results)
{ {
if (fd.Attributes & FILESYSTEM_FILE_ATTRIBUTE_DIRECTORY) if (IsSymbolicLink(fd.FileName.c_str()))
{
if (!DeleteSymbolicLink(fd.FileName.c_str()))
return false;
}
else if ((fd.Attributes & FILESYSTEM_FILE_ATTRIBUTE_DIRECTORY))
{ {
if (!RecursiveDeleteDirectory(fd.FileName.c_str())) if (!RecursiveDeleteDirectory(fd.FileName.c_str()))
return false; return false;
@ -1650,21 +1655,6 @@ bool FileSystem::DirectoryExists(const char* path)
return false; return false;
} }
bool FileSystem::IsRealDirectory(const char* path)
{
// convert to wide string
const std::wstring wpath = GetWin32Path(path);
if (wpath.empty())
return false;
// determine attributes for the path. if it's a directory, things have to be handled differently..
const DWORD fileAttributes = GetFileAttributesW(wpath.c_str());
if (fileAttributes == INVALID_FILE_ATTRIBUTES)
return false;
return ((fileAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT)) != FILE_ATTRIBUTE_DIRECTORY);
}
bool FileSystem::DirectoryIsEmpty(const char* path) bool FileSystem::DirectoryIsEmpty(const char* path)
{ {
std::wstring wpath = GetWin32Path(path); std::wstring wpath = GetWin32Path(path);
@ -1935,6 +1925,52 @@ bool FileSystem::SetPathCompression(const char* path, bool enable)
return result; return result;
} }
bool FileSystem::IsSymbolicLink(const char* path)
{
// convert to wide string
const std::wstring wpath = GetWin32Path(path);
if (wpath.empty())
return false;
// determine attributes for the path
const DWORD fileAttributes = GetFileAttributesW(wpath.c_str());
if (fileAttributes == INVALID_FILE_ATTRIBUTES)
return false;
return fileAttributes & FILE_ATTRIBUTE_REPARSE_POINT;
}
bool FileSystem::DeleteSymbolicLink(const char* path, Error* error)
{
// convert to wide string
const std::wstring wpath = GetWin32Path(path);
if (wpath.empty())
{
Error::SetStringView(error, "Invalid path.");
return false;
}
// delete the symbolic link
if (DirectoryExists(path))
{
if (!RemoveDirectoryW(wpath.c_str()))
{
Error::SetWin32(error, "RemoveDirectoryW() failed: ", GetLastError());
return false;
}
}
else
{
if (!DeleteFileW(wpath.c_str()))
{
Error::SetWin32(error, "DeleteFileW() failed: ", GetLastError());
return false;
}
}
return true;
}
#else #else
// No 32-bit file offsets breaking stuff please. // No 32-bit file offsets breaking stuff please.
@ -2216,15 +2252,6 @@ bool FileSystem::DirectoryExists(const char* path)
return false; return false;
} }
bool FileSystem::IsRealDirectory(const char* path)
{
struct stat sysStatData;
if (lstat(path, &sysStatData) < 0)
return false;
return (S_ISDIR(sysStatData.st_mode) && !S_ISLNK(sysStatData.st_mode));
}
bool FileSystem::DirectoryIsEmpty(const char* path) bool FileSystem::DirectoryIsEmpty(const char* path)
{ {
DIR* pDir = opendir(path); DIR* pDir = opendir(path);
@ -2478,6 +2505,26 @@ bool FileSystem::SetPathCompression(const char* path, bool enable)
return false; return false;
} }
bool FileSystem::IsSymbolicLink(const char* path)
{
struct stat sysStatData;
if (lstat(path, &sysStatData) < 0)
return false;
return S_ISLNK(sysStatData.st_mode);
}
bool FileSystem::DeleteSymbolicLink(const char* path, Error* error)
{
if (unlink(path) != 0)
{
Error::SetErrno(error, "unlink() failed: ", errno);
return false;
}
return true;
}
FileSystem::POSIXLock::POSIXLock(int fd) FileSystem::POSIXLock::POSIXLock(int fd)
{ {
if (lockf(fd, F_LOCK, 0) == 0) if (lockf(fd, F_LOCK, 0) == 0)

View File

@ -84,7 +84,6 @@ namespace FileSystem
/// Directory exists? /// Directory exists?
bool DirectoryExists(const char* path); bool DirectoryExists(const char* path);
bool IsRealDirectory(const char* path);
/// Directory does not contain any files? /// Directory does not contain any files?
bool DirectoryIsEmpty(const char* path); bool DirectoryIsEmpty(const char* path);
@ -170,6 +169,12 @@ namespace FileSystem
/// Does nothing and returns false on non-Windows platforms. /// Does nothing and returns false on non-Windows platforms.
bool SetPathCompression(const char* path, bool enable); bool SetPathCompression(const char* path, bool enable);
/// Checks if a file or directory is a symbolic link.
bool IsSymbolicLink(const char* path);
/// Deletes a symbolic link (either a file or directory).
bool DeleteSymbolicLink(const char* path, Error* error = nullptr);
#ifdef _WIN32 #ifdef _WIN32
// Path limit remover, but also converts to a wide string at the same time. // Path limit remover, but also converts to a wide string at the same time.
bool GetWin32Path(std::wstring* dest, std::string_view str); bool GetWin32Path(std::wstring* dest, std::string_view str);