diff --git a/Source/Engine/Platform/Apple/AppleFileSystem.cpp b/Source/Engine/Platform/Apple/AppleFileSystem.cpp index 6e596bf1b..450507009 100644 --- a/Source/Engine/Platform/Apple/AppleFileSystem.cpp +++ b/Source/Engine/Platform/Apple/AppleFileSystem.cpp @@ -7,10 +7,6 @@ #include "Engine/Platform/File.h" #include "Engine/Core/Types/String.h" #include "Engine/Core/Types/StringView.h" -#include "Engine/Core/Types/TimeSpan.h" -#include "Engine/Core/Collections/Array.h" -#include "Engine/Core/Math/Math.h" -#include "Engine/Core/Log.h" #include "Engine/Utilities/StringConverter.h" #include #include @@ -18,281 +14,9 @@ #include #include #include -#include #include #include -const DateTime UnixEpoch(1970, 1, 1); - -bool AppleFileSystem::CreateDirectory(const StringView& path) -{ - const StringAsANSI<> pathAnsi(*path, path.Length()); - - // Skip if already exists - struct stat fileInfo; - if (stat(pathAnsi.Get(), &fileInfo) != -1 && S_ISDIR(fileInfo.st_mode)) - { - return false; - } - - // Recursively do it all again for the parent directory, if any - const int32 slashIndex = path.FindLast('/'); - if (slashIndex > 1) - { - if (CreateDirectory(path.Substring(0, slashIndex))) - { - return true; - } - } - - // Create the last directory on the path (the recursive calls will have taken care of the parent directories by now) - return mkdir(pathAnsi.Get(), 0755) != 0 && errno != EEXIST; -} - -bool DeletePathTree(const char* path) -{ - size_t pathLength; - DIR* dir; - struct stat statPath, statEntry; - struct dirent* entry; - - // Stat for the path - stat(path, &statPath); - - // If path does not exists or is not dir - exit with status -1 - if (S_ISDIR(statPath.st_mode) == 0) - { - // Is not directory - return true; - } - - // If not possible to read the directory for this user - if ((dir = opendir(path)) == NULL) - { - // Cannot open directory - return true; - } - - // The length of the path - pathLength = strlen(path); - - // Iteration through entries in the directory - while ((entry = readdir(dir)) != NULL) - { - // Skip entries "." and ".." - if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) - continue; - - // Determinate a full path of an entry - char full_path[256]; - ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(full_path)); - strcpy(full_path, path); - strcat(full_path, "/"); - strcat(full_path, entry->d_name); - - // Stat for the entry - stat(full_path, &statEntry); - - // Recursively remove a nested directory - if (S_ISDIR(statEntry.st_mode) != 0) - { - if (DeletePathTree(full_path)) - return true; - continue; - } - - // Remove a file object - if (unlink(full_path) != 0) - return true; - } - - // Remove the devastated directory and close the object of it - if (rmdir(path) != 0) - return true; - - closedir(dir); - - return false; -} - -bool AppleFileSystem::DeleteDirectory(const String& path, bool deleteContents) -{ - const StringAsANSI<> pathANSI(*path, path.Length()); - if (deleteContents) - return DeletePathTree(pathANSI.Get()); - return rmdir(pathANSI.Get()) != 0; -} - -bool AppleFileSystem::DirectoryExists(const StringView& path) -{ - struct stat fileInfo; - const StringAsANSI<> pathANSI(*path, path.Length()); - if (stat(pathANSI.Get(), &fileInfo) != -1) - { - return S_ISDIR(fileInfo.st_mode); - } - return false; -} - -bool AppleFileSystem::DirectoryGetFiles(Array& results, const String& path, const Char* searchPattern, DirectorySearchOption option) -{ - const StringAsANSI<> pathANSI(*path, path.Length()); - const StringAsANSI<> searchPatternANSI(searchPattern); - - // Check if use only top directory - if (option == DirectorySearchOption::TopDirectoryOnly) - return getFilesFromDirectoryTop(results, pathANSI.Get(), searchPatternANSI.Get()); - return getFilesFromDirectoryAll(results, pathANSI.Get(), searchPatternANSI.Get()); -} - -bool AppleFileSystem::GetChildDirectories(Array& results, const String& path) -{ - size_t pathLength; - DIR* dir; - struct stat statPath, statEntry; - struct dirent* entry; - const StringAsANSI<> pathANSI(*path, path.Length()); - const char* pathStr = pathANSI.Get(); - - // Stat for the path - stat(pathStr, &statPath); - - // If path does not exist or is not dir - exit with status -1 - if (S_ISDIR(statPath.st_mode) == 0) - { - // Is not directory - return true; - } - - // If not possible to read the directory for this user - if ((dir = opendir(pathStr)) == NULL) - { - // Cannot open directory - return true; - } - - // The length of the path - pathLength = strlen(pathStr); - - // Iteration through entries in the directory - while ((entry = readdir(dir)) != NULL) - { - // Skip entries "." and ".." - if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) - continue; - - // Determinate a full path of an entry - char fullPath[256]; - ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(fullPath)); - strcpy(fullPath, pathStr); - strcat(fullPath, "/"); - strcat(fullPath, entry->d_name); - - // Stat for the entry - stat(fullPath, &statEntry); - - // Check for directory - if (S_ISDIR(statEntry.st_mode) != 0) - { - // Add directory - results.Add(String(fullPath)); - } - } - - closedir(dir); - - return false; -} - -bool AppleFileSystem::FileExists(const StringView& path) -{ - struct stat fileInfo; - const StringAsANSI<> pathANSI(*path, path.Length()); - if (stat(pathANSI.Get(), &fileInfo) != -1) - { - return S_ISREG(fileInfo.st_mode); - } - return false; -} - -bool AppleFileSystem::DeleteFile(const StringView& path) -{ - const StringAsANSI<> pathANSI(*path, path.Length()); - return unlink(pathANSI.Get()) != 0; -} - -uint64 AppleFileSystem::GetFileSize(const StringView& path) -{ - struct stat fileInfo; - fileInfo.st_size = 0; - const StringAsANSI<> pathANSI(*path, path.Length()); - if (stat(pathANSI.Get(), &fileInfo) != -1) - { - // Check for directories - if (S_ISDIR(fileInfo.st_mode)) - { - fileInfo.st_size = 0; - } - } - return fileInfo.st_size; -} - -bool AppleFileSystem::IsReadOnly(const StringView& path) -{ - const StringAsANSI<> pathANSI(*path, path.Length()); - if (access(pathANSI.Get(), W_OK) == -1) - { - return errno == EACCES; - } - return false; -} - -bool AppleFileSystem::SetReadOnly(const StringView& path, bool isReadOnly) -{ - const StringAsANSI<> pathANSI(*path, path.Length()); - struct stat fileInfo; - if (stat(pathANSI.Get(), &fileInfo) != -1) - { - if (isReadOnly) - { - fileInfo.st_mode &= ~S_IWUSR; - } - else - { - fileInfo.st_mode |= S_IWUSR; - } - return chmod(pathANSI.Get(), fileInfo.st_mode) == 0; - } - return false; -} - -bool AppleFileSystem::MoveFile(const StringView& dst, const StringView& src, bool overwrite) -{ - if (!overwrite && FileExists(dst)) - { - // Already exists - return true; - } - - if (overwrite) - { - unlink(StringAsANSI<>(*dst, dst.Length()).Get()); - } - if (rename(StringAsANSI<>(*src, src.Length()).Get(), StringAsANSI<>(*dst, dst.Length()).Get()) != 0) - { - if (errno == EXDEV) - { - if (!CopyFile(dst, src)) - { - unlink(StringAsANSI<>(*src, src.Length()).Get()); - return false; - } - } - return true; - } - return false; -} - bool AppleFileSystem::CopyFile(const StringView& dst, const StringView& src) { const StringAsANSI<> srcANSI(*src, src.Length()); @@ -352,156 +76,6 @@ out_error: return true; } -bool AppleFileSystem::getFilesFromDirectoryTop(Array& results, const char* path, const char* searchPattern) -{ - size_t pathLength; - struct stat statPath, statEntry; - struct dirent* entry; - - // Stat for the path - stat(path, &statPath); - - // If path does not exists or is not dir - exit with status -1 - if (S_ISDIR(statPath.st_mode) == 0) - { - // Is not directory - return true; - } - - // If not possible to read the directory for this user - DIR* dir = opendir(path); - if (dir == NULL) - { - // Cannot open directory - return true; - } - - // The length of the path - pathLength = strlen(path); - - // Iteration through entries in the directory - while ((entry = readdir(dir)) != NULL) - { - // Skip entries "." and ".." - if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) - continue; - - // Determinate a full path of an entry - char fullPath[256]; - ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(fullPath)); - strcpy(fullPath, path); - strcat(fullPath, "/"); - strcat(fullPath, entry->d_name); - - // Stat for the entry - stat(fullPath, &statEntry); - - // Check for file - if (S_ISREG(statEntry.st_mode) != 0) - { - // Validate with filter - const int32 fullPathLength = StringUtils::Length(fullPath); - const int32 searchPatternLength = StringUtils::Length(searchPattern); - if (searchPatternLength == 0 || StringUtils::Compare(searchPattern, "*") == 0) - { - // All files - } - else if (searchPattern[0] == '*' && searchPatternLength < fullPathLength && StringUtils::Compare(fullPath + fullPathLength - searchPatternLength + 1, searchPattern + 1, searchPatternLength - 1) == 0) - { - // Path ending - } - else - { - // TODO: implement all cases in a generic way - continue; - } - - // Add file - results.Add(String(fullPath)); - } - } - - closedir(dir); - - return false; -} - -bool AppleFileSystem::getFilesFromDirectoryAll(Array& results, const char* path, const char* searchPattern) -{ - // Find all files in this directory - getFilesFromDirectoryTop(results, path, searchPattern); - - size_t pathLength; - DIR* dir; - struct stat statPath, statEntry; - struct dirent* entry; - - // Stat for the path - stat(path, &statPath); - - // If path does not exists or is not dir - exit with status -1 - if (S_ISDIR(statPath.st_mode) == 0) - { - // Is not directory - return true; - } - - // If not possible to read the directory for this user - if ((dir = opendir(path)) == NULL) - { - // Cannot open directory - return true; - } - - // The length of the path - pathLength = strlen(path); - - // Iteration through entries in the directory - while ((entry = readdir(dir)) != NULL) - { - // Skip entries "." and ".." - if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) - continue; - - // Determinate a full path of an entry - char full_path[256]; - ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(full_path)); - strcpy(full_path, path); - strcat(full_path, "/"); - strcat(full_path, entry->d_name); - - // Stat for the entry - stat(full_path, &statEntry); - - // Check for directory - if (S_ISDIR(statEntry.st_mode) != 0) - { - if (getFilesFromDirectoryAll(results, full_path, searchPattern)) - { - closedir(dir); - return true; - } - } - } - - closedir(dir); - - return false; -} - -DateTime AppleFileSystem::GetFileLastEditTime(const StringView& path) -{ - struct stat fileInfo; - const StringAsANSI<> pathANSI(*path, path.Length()); - if (stat(pathANSI.Get(), &fileInfo) == -1) - { - return DateTime::MinValue(); - } - - const TimeSpan timeSinceEpoch(0, 0, 0, fileInfo.st_mtime); - return UnixEpoch + timeSinceEpoch; -} - void AppleFileSystem::GetSpecialFolderPath(const SpecialFolder type, String& result) { String home; diff --git a/Source/Engine/Platform/Apple/AppleFileSystem.h b/Source/Engine/Platform/Apple/AppleFileSystem.h index 5fa6ad1b7..45d9e4df6 100644 --- a/Source/Engine/Platform/Apple/AppleFileSystem.h +++ b/Source/Engine/Platform/Apple/AppleFileSystem.h @@ -4,33 +4,17 @@ #if PLATFORM_MAC || PLATFORM_IOS -#include "Engine/Platform/Base/FileSystemBase.h" +#include "Engine/Platform/Unix/UnixFileSystem.h" /// /// Apple platform implementation of filesystem service. /// -class FLAXENGINE_API AppleFileSystem : public FileSystemBase +class FLAXENGINE_API AppleFileSystem : public UnixFileSystem { public: // [FileSystemBase] - static bool CreateDirectory(const StringView& path); - static bool DeleteDirectory(const String& path, bool deleteContents = true); - static bool DirectoryExists(const StringView& path); - static bool DirectoryGetFiles(Array& results, const String& path, const Char* searchPattern = TEXT("*"), DirectorySearchOption option = DirectorySearchOption::AllDirectories); - static bool GetChildDirectories(Array& results, const String& path); - static bool FileExists(const StringView& path); - static bool DeleteFile(const StringView& path); - static uint64 GetFileSize(const StringView& path); - static bool IsReadOnly(const StringView& path); - static bool SetReadOnly(const StringView& path, bool isReadOnly); - static bool MoveFile(const StringView& dst, const StringView& src, bool overwrite = false); static bool CopyFile(const StringView& dst, const StringView& src); - static DateTime GetFileLastEditTime(const StringView& path); static void GetSpecialFolderPath(const SpecialFolder type, String& result); - -private: - static bool getFilesFromDirectoryTop(Array& results, const char* path, const char* searchPattern); - static bool getFilesFromDirectoryAll(Array& results, const char* path, const char* searchPattern); }; #endif diff --git a/Source/Engine/Platform/Linux/LinuxFileSystem.cpp b/Source/Engine/Platform/Linux/LinuxFileSystem.cpp index 3e2055572..9b31dc28f 100644 --- a/Source/Engine/Platform/Linux/LinuxFileSystem.cpp +++ b/Source/Engine/Platform/Linux/LinuxFileSystem.cpp @@ -4,22 +4,16 @@ #include "LinuxFileSystem.h" #include "Engine/Platform/File.h" -#include "Engine/Platform/StringUtils.h" -#include "Engine/Core/Types/String.h" #include "Engine/Core/Types/StringBuilder.h" -#include "Engine/Core/Types/StringView.h" -#include "Engine/Core/Types/TimeSpan.h" #include "Engine/Core/Collections/Array.h" #include "Engine/Core/Math/Math.h" #include "Engine/Core/Log.h" #include "Engine/Utilities/StringConverter.h" -#include #include #include #include #include #include -#include #include #include #include @@ -165,280 +159,6 @@ bool LinuxFileSystem::ShowFileExplorer(const StringView& path) return false; } -bool LinuxFileSystem::CreateDirectory(const StringView& path) -{ - const StringAsUTF8<> pathAnsi(*path, path.Length()); - - // Skip if already exists - struct stat fileInfo; - if (stat(pathAnsi.Get(), &fileInfo) != -1 && S_ISDIR(fileInfo.st_mode)) - { - return false; - } - - // Recursively do it all again for the parent directory, if any - const int32 slashIndex = path.FindLast('/'); - if (slashIndex > 1) - { - if (CreateDirectory(path.Substring(0, slashIndex))) - { - return true; - } - } - - // Create the last directory on the path (the recursive calls will have taken care of the parent directories by now) - return mkdir(pathAnsi.Get(), 0755) != 0 && errno != EEXIST; -} - -bool DeleteUnixPathTree(const char* path) -{ - size_t pathLength; - DIR* dir; - struct stat statPath, statEntry; - struct dirent* entry; - - // Stat for the path - stat(path, &statPath); - - // If path does not exists or is not dir - exit with status -1 - if (S_ISDIR(statPath.st_mode) == 0) - { - // Is not directory - return true; - } - - // If not possible to read the directory for this user - if ((dir = opendir(path)) == NULL) - { - // Cannot open directory - return true; - } - - // The length of the path - pathLength = strlen(path); - - // Iteration through entries in the directory - while ((entry = readdir(dir)) != NULL) - { - // Skip entries "." and ".." - if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) - continue; - - // Determinate a full path of an entry - char full_path[256]; - ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(full_path)); - strcpy(full_path, path); - strcat(full_path, "/"); - strcat(full_path, entry->d_name); - - // Stat for the entry - stat(full_path, &statEntry); - - // Recursively remove a nested directory - if (S_ISDIR(statEntry.st_mode) != 0) - { - if (DeleteUnixPathTree(full_path)) - return true; - continue; - } - - // Remove a file object - if (unlink(full_path) != 0) - return true; - } - - // Remove the devastated directory and close the object of it - if (rmdir(path) != 0) - return true; - - closedir(dir); - - return false; -} - -bool LinuxFileSystem::DeleteDirectory(const String& path, bool deleteContents) -{ - const StringAsUTF8<> pathANSI(*path, path.Length()); - if (deleteContents) - { - return DeleteUnixPathTree(pathANSI.Get()); - } - else - { - return rmdir(pathANSI.Get()) != 0; - } -} - -bool LinuxFileSystem::DirectoryExists(const StringView& path) -{ - struct stat fileInfo; - const StringAsUTF8<> pathANSI(*path, path.Length()); - if (stat(pathANSI.Get(), &fileInfo) != -1) - { - return S_ISDIR(fileInfo.st_mode); - } - return false; -} - -bool LinuxFileSystem::DirectoryGetFiles(Array& results, const String& path, const Char* searchPattern, DirectorySearchOption option) -{ - const StringAsUTF8<> pathANSI(*path, path.Length()); - const StringAsUTF8<> searchPatternANSI(searchPattern); - - // Check if use only top directory - if (option == DirectorySearchOption::TopDirectoryOnly) - return getFilesFromDirectoryTop(results, pathANSI.Get(), searchPatternANSI.Get()); - return getFilesFromDirectoryAll(results, pathANSI.Get(), searchPatternANSI.Get()); -} - -bool LinuxFileSystem::GetChildDirectories(Array& results, const String& path) -{ - size_t pathLength; - DIR* dir; - struct stat statPath, statEntry; - struct dirent* entry; - const StringAsUTF8<> pathANSI(*path, path.Length()); - const char* pathStr = pathANSI.Get(); - - // Stat for the path - stat(pathStr, &statPath); - - // If path does not exists or is not dir - exit with status -1 - if (S_ISDIR(statPath.st_mode) == 0) - { - // Is not directory - return true; - } - - // If not possible to read the directory for this user - if ((dir = opendir(pathStr)) == NULL) - { - // Cannot open directory - return true; - } - - // The length of the path - pathLength = strlen(pathStr); - - // Iteration through entries in the directory - while ((entry = readdir(dir)) != NULL) - { - // Skip entries "." and ".." - if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) - continue; - - // Determinate a full path of an entry - char fullPath[256]; - ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(fullPath)); - strcpy(fullPath, pathStr); - strcat(fullPath, "/"); - strcat(fullPath, entry->d_name); - - // Stat for the entry - stat(fullPath, &statEntry); - - // Check for directory - if (S_ISDIR(statEntry.st_mode) != 0) - { - // Add directory - results.Add(String(fullPath)); - } - } - - closedir(dir); - - return false; -} - -bool LinuxFileSystem::FileExists(const StringView& path) -{ - struct stat fileInfo; - const StringAsUTF8<> pathANSI(*path, path.Length()); - if (stat(pathANSI.Get(), &fileInfo) != -1) - { - return S_ISREG(fileInfo.st_mode); - } - return false; -} - -bool LinuxFileSystem::DeleteFile(const StringView& path) -{ - const StringAsUTF8<> pathANSI(*path, path.Length()); - return unlink(pathANSI.Get()) != 0; -} - -uint64 LinuxFileSystem::GetFileSize(const StringView& path) -{ - struct stat fileInfo; - fileInfo.st_size = 0; - const StringAsUTF8<> pathANSI(*path, path.Length()); - if (stat(pathANSI.Get(), &fileInfo) != -1) - { - // Check for directories - if (S_ISDIR(fileInfo.st_mode)) - { - fileInfo.st_size = 0; - } - } - return fileInfo.st_size; -} - -bool LinuxFileSystem::IsReadOnly(const StringView& path) -{ - const StringAsUTF8<> pathANSI(*path, path.Length()); - if (access(pathANSI.Get(), W_OK) == -1) - { - return errno == EACCES; - } - return false; -} - -bool LinuxFileSystem::SetReadOnly(const StringView& path, bool isReadOnly) -{ - const StringAsUTF8<> pathANSI(*path, path.Length()); - struct stat fileInfo; - if (stat(pathANSI.Get(), &fileInfo) != -1) - { - if (isReadOnly) - { - fileInfo.st_mode &= ~S_IWUSR; - } - else - { - fileInfo.st_mode |= S_IWUSR; - } - return chmod(pathANSI.Get(), fileInfo.st_mode) == 0; - } - return false; -} - -bool LinuxFileSystem::MoveFile(const StringView& dst, const StringView& src, bool overwrite) -{ - if (!overwrite && FileExists(dst)) - { - // Already exists - return true; - } - - if (overwrite) - { - unlink(StringAsUTF8<>(*dst, dst.Length()).Get()); - } - if (rename(StringAsUTF8<>(*src, src.Length()).Get(), StringAsUTF8<>(*dst, dst.Length()).Get()) != 0) - { - if (errno == EXDEV) - { - if (!CopyFile(dst, src)) - { - unlink(StringAsUTF8<>(*src, src.Length()).Get()); - return false; - } - } - return true; - } - return false; -} - bool LinuxFileSystem::CopyFile(const StringView& dst, const StringView& src) { const StringAsUTF8<> srcANSI(*src, src.Length()); @@ -612,156 +332,6 @@ bool LinuxFileSystem::UrnEncodePath(const char *path, char *result, const int ma return true; } -bool LinuxFileSystem::getFilesFromDirectoryTop(Array& results, const char* path, const char* searchPattern) -{ - size_t pathLength; - struct stat statPath, statEntry; - struct dirent* entry; - - // Stat for the path - stat(path, &statPath); - - // If path does not exists or is not dir - exit with status -1 - if (S_ISDIR(statPath.st_mode) == 0) - { - // Is not directory - return true; - } - - // If not possible to read the directory for this user - DIR* dir = opendir(path); - if (dir == NULL) - { - // Cannot open directory - return true; - } - - // The length of the path - pathLength = strlen(path); - - // Iteration through entries in the directory - while ((entry = readdir(dir)) != NULL) - { - // Skip entries "." and ".." - if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) - continue; - - // Determinate a full path of an entry - char fullPath[256]; - ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(fullPath)); - strcpy(fullPath, path); - strcat(fullPath, "/"); - strcat(fullPath, entry->d_name); - - // Stat for the entry - stat(fullPath, &statEntry); - - // Check for file - if (S_ISREG(statEntry.st_mode) != 0) - { - // Validate with filter - const int32 fullPathLength = StringUtils::Length(fullPath); - const int32 searchPatternLength = StringUtils::Length(searchPattern); - if (searchPatternLength == 0 || StringUtils::Compare(searchPattern, "*") == 0) - { - // All files - } - else if (searchPattern[0] == '*' && searchPatternLength < fullPathLength && StringUtils::Compare(fullPath + fullPathLength - searchPatternLength + 1, searchPattern + 1, searchPatternLength - 1) == 0) - { - // Path ending - } - else - { - // TODO: implement all cases in a generic way - continue; - } - - // Add file - results.Add(String(fullPath)); - } - } - - closedir(dir); - - return false; -} - -bool LinuxFileSystem::getFilesFromDirectoryAll(Array& results, const char* path, const char* searchPattern) -{ - // Find all files in this directory - getFilesFromDirectoryTop(results, path, searchPattern); - - size_t pathLength; - DIR* dir; - struct stat statPath, statEntry; - struct dirent* entry; - - // Stat for the path - stat(path, &statPath); - - // If path does not exists or is not dir - exit with status -1 - if (S_ISDIR(statPath.st_mode) == 0) - { - // Is not directory - return true; - } - - // If not possible to read the directory for this user - if ((dir = opendir(path)) == NULL) - { - // Cannot open directory - return true; - } - - // The length of the path - pathLength = strlen(path); - - // Iteration through entries in the directory - while ((entry = readdir(dir)) != NULL) - { - // Skip entries "." and ".." - if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) - continue; - - // Determinate a full path of an entry - char full_path[256]; - ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(full_path)); - strcpy(full_path, path); - strcat(full_path, "/"); - strcat(full_path, entry->d_name); - - // Stat for the entry - stat(full_path, &statEntry); - - // Check for directory - if (S_ISDIR(statEntry.st_mode) != 0) - { - if (getFilesFromDirectoryAll(results, full_path, searchPattern)) - { - closedir(dir); - return true; - } - } - } - - closedir(dir); - - return false; -} - -DateTime LinuxFileSystem::GetFileLastEditTime(const StringView& path) -{ - struct stat fileInfo; - const StringAsUTF8<> pathANSI(*path, path.Length()); - if (stat(pathANSI.Get(), &fileInfo) == -1) - { - return DateTime::MinValue(); - } - - const TimeSpan timeSinceEpoch(0, 0, 0, fileInfo.st_mtime); - return UnixEpoch + timeSinceEpoch; -} - void LinuxFileSystem::GetSpecialFolderPath(const SpecialFolder type, String& result) { const String& home = LinuxPlatform::GetHomeDirectory(); diff --git a/Source/Engine/Platform/Linux/LinuxFileSystem.h b/Source/Engine/Platform/Linux/LinuxFileSystem.h index f77c3dd4f..377bbbd99 100644 --- a/Source/Engine/Platform/Linux/LinuxFileSystem.h +++ b/Source/Engine/Platform/Linux/LinuxFileSystem.h @@ -4,38 +4,24 @@ #if PLATFORM_LINUX -#include "Engine/Platform/Base/FileSystemBase.h" +#include "Engine/Platform/Unix/UnixFileSystem.h" /// /// Linux platform implementation of filesystem service. /// -class FLAXENGINE_API LinuxFileSystem : public FileSystemBase +class FLAXENGINE_API LinuxFileSystem : public UnixFileSystem { public: // [FileSystemBase] static bool ShowOpenFileDialog(Window* parentWindow, const StringView& initialDirectory, const StringView& filter, bool multiSelect, const StringView& title, Array& filenames); static bool ShowBrowseFolderDialog(Window* parentWindow, const StringView& initialDirectory, const StringView& title, String& path); static bool ShowFileExplorer(const StringView& path); - static bool CreateDirectory(const StringView& path); - static bool DeleteDirectory(const String& path, bool deleteContents = true); - static bool DirectoryExists(const StringView& path); - static bool DirectoryGetFiles(Array& results, const String& path, const Char* searchPattern = TEXT("*"), DirectorySearchOption option = DirectorySearchOption::AllDirectories); - static bool GetChildDirectories(Array& results, const String& path); - static bool FileExists(const StringView& path); - static bool DeleteFile(const StringView& path); - static bool MoveFileToRecycleBin(const StringView& path); - static uint64 GetFileSize(const StringView& path); - static bool IsReadOnly(const StringView& path); - static bool SetReadOnly(const StringView& path, bool isReadOnly); - static bool MoveFile(const StringView& dst, const StringView& src, bool overwrite = false); static bool CopyFile(const StringView& dst, const StringView& src); - static DateTime GetFileLastEditTime(const StringView& path); + static bool MoveFileToRecycleBin(const StringView& path); static void GetSpecialFolderPath(const SpecialFolder type, String& result); private: static bool UrnEncodePath(const char *path, char *result, int maxLength); - static bool getFilesFromDirectoryTop(Array& results, const char* path, const char* searchPattern); - static bool getFilesFromDirectoryAll(Array& results, const char* path, const char* searchPattern); static String getBaseName(const StringView& path); static String getNameWithoutExtension(const StringView& path); }; diff --git a/Source/Engine/Platform/Unix/UnixFileSystem.cpp b/Source/Engine/Platform/Unix/UnixFileSystem.cpp new file mode 100644 index 000000000..1fb47f0f5 --- /dev/null +++ b/Source/Engine/Platform/Unix/UnixFileSystem.cpp @@ -0,0 +1,470 @@ +// Copyright (c) Wojciech Figat. All rights reserved. + +#if PLATFORM_UNIX + +#include "UnixFileSystem.h" +#include "Engine/Platform/File.h" +#include "Engine/Core/Types/TimeSpan.h" +#include "Engine/Core/Collections/Array.h" +#include "Engine/Core/Math/Math.h" +#include "Engine/Core/Log.h" +#include "Engine/Utilities/StringConverter.h" +#include +#include +#include +#include +#include + +#if PLATFORM_MAC || PLATFORM_IOS +typedef StringAsANSI<> UnixString; +#else +typedef StringAsUTF8<> UnixString; +#endif + +const DateTime UnixEpoch(1970, 1, 1); + +bool UnixFileSystem::CreateDirectory(const StringView& path) +{ + const UnixString pathAnsi(*path, path.Length()); + + // Skip if already exists + struct stat fileInfo; + if (stat(pathAnsi.Get(), &fileInfo) != -1 && S_ISDIR(fileInfo.st_mode)) + { + return false; + } + + // Recursively do it all again for the parent directory, if any + const int32 slashIndex = path.FindLast('/'); + if (slashIndex > 1) + { + if (CreateDirectory(path.Substring(0, slashIndex))) + { + return true; + } + } + + // Create the last directory on the path (the recursive calls will have taken care of the parent directories by now) + return mkdir(pathAnsi.Get(), 0755) != 0 && errno != EEXIST; +} + +bool DeleteUnixPathTree(const char* path) +{ + size_t pathLength; + DIR* dir; + struct stat statPath, statEntry; + struct dirent* entry; + + // Stat for the path + stat(path, &statPath); + + // If path does not exists or is not dir - exit with status -1 + if (S_ISDIR(statPath.st_mode) == 0) + { + // Is not directory + return true; + } + + // If not possible to read the directory for this user + if ((dir = opendir(path)) == NULL) + { + // Cannot open directory + return true; + } + + // The length of the path + pathLength = strlen(path); + + // Iteration through entries in the directory + while ((entry = readdir(dir)) != NULL) + { + // Skip entries "." and ".." + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) + continue; + + // Determinate a full path of an entry + char full_path[256]; + ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(full_path)); + strcpy(full_path, path); + strcat(full_path, "/"); + strcat(full_path, entry->d_name); + + // Stat for the entry + stat(full_path, &statEntry); + + // Recursively remove a nested directory + if (S_ISDIR(statEntry.st_mode) != 0) + { + if (DeleteUnixPathTree(full_path)) + return true; + continue; + } + + // Remove a file object + if (unlink(full_path) != 0) + return true; + } + + // Remove the devastated directory and close the object of it + if (rmdir(path) != 0) + return true; + + closedir(dir); + + return false; +} + +bool UnixFileSystem::DeleteDirectory(const String& path, bool deleteContents) +{ + const UnixString pathANSI(*path, path.Length()); + if (deleteContents) + { + return DeleteUnixPathTree(pathANSI.Get()); + } + else + { + return rmdir(pathANSI.Get()) != 0; + } +} + +bool UnixFileSystem::DirectoryExists(const StringView& path) +{ + struct stat fileInfo; + const UnixString pathANSI(*path, path.Length()); + if (stat(pathANSI.Get(), &fileInfo) != -1) + { + return S_ISDIR(fileInfo.st_mode); + } + return false; +} + +bool UnixFileSystem::DirectoryGetFiles(Array& results, const String& path, const Char* searchPattern, DirectorySearchOption option) +{ + const UnixString pathANSI(*path, path.Length()); + const UnixString searchPatternANSI(searchPattern); + + // Check if use only top directory + if (option == DirectorySearchOption::TopDirectoryOnly) + return getFilesFromDirectoryTop(results, pathANSI.Get(), searchPatternANSI.Get()); + return getFilesFromDirectoryAll(results, pathANSI.Get(), searchPatternANSI.Get()); +} + +bool UnixFileSystem::GetChildDirectories(Array& results, const String& path) +{ + size_t pathLength; + DIR* dir; + struct stat statPath, statEntry; + struct dirent* entry; + const UnixString pathANSI(*path, path.Length()); + const char* pathStr = pathANSI.Get(); + + // Stat for the path + stat(pathStr, &statPath); + + // If path does not exists or is not dir - exit with status -1 + if (S_ISDIR(statPath.st_mode) == 0) + { + // Is not directory + return true; + } + + // If not possible to read the directory for this user + if ((dir = opendir(pathStr)) == NULL) + { + // Cannot open directory + return true; + } + + // The length of the path + pathLength = strlen(pathStr); + + // Iteration through entries in the directory + while ((entry = readdir(dir)) != NULL) + { + // Skip entries "." and ".." + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) + continue; + + // Determinate a full path of an entry + char fullPath[256]; + ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(fullPath)); + strcpy(fullPath, pathStr); + strcat(fullPath, "/"); + strcat(fullPath, entry->d_name); + + // Stat for the entry + stat(fullPath, &statEntry); + + // Check for directory + if (S_ISDIR(statEntry.st_mode) != 0) + { + // Add directory + results.Add(String(fullPath)); + } + } + + closedir(dir); + + return false; +} + +bool UnixFileSystem::FileExists(const StringView& path) +{ + struct stat fileInfo; + const UnixString pathANSI(*path, path.Length()); + if (stat(pathANSI.Get(), &fileInfo) != -1) + { + return S_ISREG(fileInfo.st_mode); + } + return false; +} + +bool UnixFileSystem::DeleteFile(const StringView& path) +{ + const UnixString pathANSI(*path, path.Length()); + return unlink(pathANSI.Get()) != 0; +} + +uint64 UnixFileSystem::GetFileSize(const StringView& path) +{ + struct stat fileInfo; + fileInfo.st_size = 0; + const UnixString pathANSI(*path, path.Length()); + if (stat(pathANSI.Get(), &fileInfo) != -1) + { + // Check for directories + if (S_ISDIR(fileInfo.st_mode)) + { + fileInfo.st_size = 0; + } + } + return fileInfo.st_size; +} + +bool UnixFileSystem::IsReadOnly(const StringView& path) +{ + const UnixString pathANSI(*path, path.Length()); + if (access(pathANSI.Get(), W_OK) == -1) + { + return errno == EACCES; + } + return false; +} + +bool UnixFileSystem::SetReadOnly(const StringView& path, bool isReadOnly) +{ + const UnixString pathANSI(*path, path.Length()); + struct stat fileInfo; + if (stat(pathANSI.Get(), &fileInfo) != -1) + { + if (isReadOnly) + { + fileInfo.st_mode &= ~S_IWUSR; + } + else + { + fileInfo.st_mode |= S_IWUSR; + } + return chmod(pathANSI.Get(), fileInfo.st_mode) == 0; + } + return false; +} + +bool UnixFileSystem::MoveFile(const StringView& dst, const StringView& src, bool overwrite) +{ + if (!overwrite && FileExists(dst)) + { + // Already exists + return true; + } + + if (overwrite) + { + unlink(UnixString(*dst, dst.Length()).Get()); + } + if (rename(UnixString(*src, src.Length()).Get(), UnixString(*dst, dst.Length()).Get()) != 0) + { + if (errno == EXDEV) + { + if (!CopyFile(dst, src)) + { + unlink(UnixString(*src, src.Length()).Get()); + return false; + } + } + return true; + } + return false; +} + +bool UnixFileSystem::getFilesFromDirectoryTop(Array& results, const char* path, const char* searchPattern) +{ + size_t pathLength; + struct stat statPath, statEntry; + struct dirent* entry; + + // Stat for the path + stat(path, &statPath); + + // If path does not exists or is not dir - exit with status -1 + if (S_ISDIR(statPath.st_mode) == 0) + { + // Is not directory + return true; + } + + // If not possible to read the directory for this user + DIR* dir = opendir(path); + if (dir == NULL) + { + // Cannot open directory + return true; + } + + // The length of the path + pathLength = strlen(path); + + // Iteration through entries in the directory + while ((entry = readdir(dir)) != NULL) + { + // Skip entries "." and ".." + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) + continue; + + // Determinate a full path of an entry + char fullPath[256]; + const int32 pathLength = strlen(entry->d_name); + ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(fullPath)); + strcpy(fullPath, path); + strcat(fullPath, "/"); + strcat(fullPath, entry->d_name); + + // Stat for the entry + stat(fullPath, &statEntry); + + // Check for file + if (S_ISREG(statEntry.st_mode) != 0) + { + // Validate with filter + const int32 fullPathLength = StringUtils::Length(fullPath); + const int32 searchPatternLength = StringUtils::Length(searchPattern); + if (searchPatternLength == 0 || + StringUtils::Compare(searchPattern, "*") == 0 || + StringUtils::Compare(searchPattern, "*.*") == 0) + { + // All files + } + else if (searchPattern[0] == '*' && searchPatternLength < fullPathLength && StringUtils::Compare(fullPath + fullPathLength - searchPatternLength + 1, searchPattern + 1, searchPatternLength - 1) == 0) + { + // Path ending + } + else if (searchPattern[0] == '*' && searchPatternLength > 2 && searchPattern[searchPatternLength-1] == '*') + { + // Contains pattern + bool match = false; + for (int32 i = 0; i < pathLength - searchPatternLength - 1; i++) + { + int32 len = Math::Min(searchPatternLength - 2, pathLength - i); + if (StringUtils::Compare(&entry->d_name[i], &searchPattern[1], len) == 0) + { + match = true; + break; + } + } + if (!match) + continue; + } + else + { + // TODO: implement all cases in a generic way + LOG(Warning, "DirectoryGetFiles: Wildcard filter is not implemented"); + continue; + } + + // Add file + results.Add(String(fullPath)); + } + } + + closedir(dir); + + return false; +} + +bool UnixFileSystem::getFilesFromDirectoryAll(Array& results, const char* path, const char* searchPattern) +{ + // Find all files in this directory + getFilesFromDirectoryTop(results, path, searchPattern); + + size_t pathLength; + DIR* dir; + struct stat statPath, statEntry; + struct dirent* entry; + + // Stat for the path + stat(path, &statPath); + + // If path does not exists or is not dir - exit with status -1 + if (S_ISDIR(statPath.st_mode) == 0) + { + // Is not directory + return true; + } + + // If not possible to read the directory for this user + if ((dir = opendir(path)) == NULL) + { + // Cannot open directory + return true; + } + + // The length of the path + pathLength = strlen(path); + + // Iteration through entries in the directory + while ((entry = readdir(dir)) != NULL) + { + // Skip entries "." and ".." + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) + continue; + + // Determinate a full path of an entry + char full_path[256]; + ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(full_path)); + strcpy(full_path, path); + strcat(full_path, "/"); + strcat(full_path, entry->d_name); + + // Stat for the entry + stat(full_path, &statEntry); + + // Check for directory + if (S_ISDIR(statEntry.st_mode) != 0) + { + if (getFilesFromDirectoryAll(results, full_path, searchPattern)) + { + closedir(dir); + return true; + } + } + } + + closedir(dir); + + return false; +} + +DateTime UnixFileSystem::GetFileLastEditTime(const StringView& path) +{ + struct stat fileInfo; + const UnixString pathANSI(*path, path.Length()); + if (stat(pathANSI.Get(), &fileInfo) == -1) + { + return DateTime::MinValue(); + } + + const TimeSpan timeSinceEpoch(0, 0, 0, fileInfo.st_mtime); + return UnixEpoch + timeSinceEpoch; +} + +#endif diff --git a/Source/Engine/Platform/Unix/UnixFileSystem.h b/Source/Engine/Platform/Unix/UnixFileSystem.h new file mode 100644 index 000000000..4c7256aca --- /dev/null +++ b/Source/Engine/Platform/Unix/UnixFileSystem.h @@ -0,0 +1,35 @@ +// Copyright (c) Wojciech Figat. All rights reserved. + +#pragma once + +#if PLATFORM_UNIX + +#include "Engine/Platform/Base/FileSystemBase.h" + +/// +/// Unix platform implementation of filesystem service. +/// +class FLAXENGINE_API UnixFileSystem : public FileSystemBase +{ +public: + // [FileSystemBase] + static bool CreateDirectory(const StringView& path); + static bool DeleteDirectory(const String& path, bool deleteContents = true); + static bool DirectoryExists(const StringView& path); + static bool DirectoryGetFiles(Array& results, const String& path, const Char* searchPattern = TEXT("*"), DirectorySearchOption option = DirectorySearchOption::AllDirectories); + static bool GetChildDirectories(Array& results, const String& path); + static bool FileExists(const StringView& path); + static bool DeleteFile(const StringView& path); + static bool MoveFileToRecycleBin(const StringView& path); + static uint64 GetFileSize(const StringView& path); + static bool IsReadOnly(const StringView& path); + static bool SetReadOnly(const StringView& path, bool isReadOnly); + static bool MoveFile(const StringView& dst, const StringView& src, bool overwrite = false); + static DateTime GetFileLastEditTime(const StringView& path); + +private: + static bool getFilesFromDirectoryTop(Array& results, const char* path, const char* searchPattern); + static bool getFilesFromDirectoryAll(Array& results, const char* path, const char* searchPattern); +}; + +#endif