#include "filesystem.hpp" #include "path.hpp" #ifdef _WIN32 #include <windows.h> #include <direct.h> #include <io.h> #define PATH_MAX MAX_PATH #define chdir _chdir #define getcwd _getcwd #define fileno _fileno #define isatty _isatty #define access _access #define F_OK 0 #define R_OK 2 #define W_OK 4 #define X_OK 0 //X_OK equivalent to F_OK on Windows #define chmod _chmod #define putenv _putenv #define rmdir _rmdir #define tempnam _tempnam #include <process.h> #define getpid _getpid #else #include <limits.h> #include <unistd.h> #endif #include <sys/stat.h> #include <stdlib.h> #include <stdio.h> //Lot of string.GetOwned() in use here... //If there's an external buffer being referenced and string.length() != strlen(buffer) these things won't behave as expected. //Thus if it's referencing an external buffer, we have to get an owned version of it so we can safely add the \0 in the right place. //We technically COULD modify the buffer directly to add that \0, but that isn't thread safe, so we won't. void sprawl::filesystem::Chdir(String const& path) { chdir(path.GetOwned().c_str()); } sprawl::String sprawl::filesystem::GetCwd() { char cwd[PATH_MAX]; getcwd(cwd, PATH_MAX); return sprawl::String(cwd); } sprawl::filesystem::File sprawl::filesystem::Open(String const& path, char const* const mode) { return File( fopen( path.GetOwned().c_str(), mode ), sprawl::String(mode) ); } sprawl::filesystem::File::File(sprawl::filesystem::File const& other) : m_file(other.m_file) , m_mode(other.m_mode) , m_refCount(other.m_refCount) { if(m_refCount) { ++(*m_refCount); } } void sprawl::filesystem::File::operator=(sprawl::filesystem::File const& other) { if(m_file) { if(--(*m_refCount) == 0) { fclose(m_file); } } m_file = other.m_file; m_mode = other.m_mode; m_refCount = other.m_refCount; if(m_refCount) { ++(*m_refCount); } } sprawl::filesystem::File::~File() { if(m_file) { if(--(*m_refCount) == 0) { fclose(m_file); delete m_refCount; } } } void sprawl::filesystem::File::Close() { *m_refCount = 0; fclose(m_file); m_file = nullptr; } void sprawl::filesystem::File::Sync() { #ifdef _WIN32 _commit(FileNo()); #else fsync(FileNo()); #endif } void sprawl::filesystem::File::Flush() { fflush(m_file); } int sprawl::filesystem::File::FileNo() { return fileno(m_file); } bool sprawl::filesystem::File::IsATTY() { return isatty(FileNo()); } sprawl::String sprawl::filesystem::File::Read(int numBytes) { if(numBytes == -1) { numBytes = FileSize() - Tell(); } if(numBytes < 0) { return ""; } char* buffer = (char*)malloc(numBytes); size_t size = fread(buffer, 1, numBytes, m_file); sprawl::String ret(buffer, size); free(buffer); return std::move(ret); } sprawl::String sprawl::filesystem::File::ReadLine(int numBytes) { if(numBytes == -1) { numBytes = FileSize() - Tell(); } if(numBytes < 0) { return ""; } numBytes += 1; char* buffer = (char*)malloc(numBytes); fgets(buffer, numBytes, m_file); sprawl::String ret(buffer); free(buffer); return std::move(ret); } void sprawl::filesystem::File::Seek(int offset, RelativeTo relativeTo) { switch(relativeTo) { case RelativeTo::Beginning: { fseek(m_file, offset, SEEK_SET); return; } case RelativeTo::CurrentPosition: { fseek(m_file, offset, SEEK_CUR); return; } case RelativeTo::End: { fseek(m_file, offset, SEEK_END); return; } } } int sprawl::filesystem::File::Tell() { return int(ftell(m_file)); } void sprawl::filesystem::File::Truncate(int size) { if(size == -1) { size = Tell(); } if(Tell() > size) { Seek(size, RelativeTo::Beginning); } #ifdef _WIN32 _chsize(FileNo(), size); #else ftruncate(FileNo(), size); #endif } void sprawl::filesystem::File::Write(String const& str) { fwrite(str.c_str(), 1, str.length(), m_file); } bool sprawl::filesystem::File::IsClosed() { return m_refCount == nullptr || m_file == nullptr || *m_refCount <= 0; } sprawl::String const& sprawl::filesystem::File::Mode() { return m_mode; } int sprawl::filesystem::File::FileSize() { int current = Tell(); Seek(0, RelativeTo::End); int size = Tell(); Seek(current, RelativeTo::Beginning); return size; } bool sprawl::filesystem::Access(String const& path, sprawl::filesystem::AccessType::Type type) { int flags = F_OK; if(type & AccessType::Read) { flags |= R_OK; } if(type & AccessType::Write) { flags |= W_OK; } if(type & AccessType::Execute) { flags |= X_OK; } return access(path.GetOwned().c_str(), flags) == 0; } static int TranslateMode(sprawl::filesystem::PermissionType::Type type) { int mode = 0; #ifdef _WIN32 if(type & sprawl::filesystem::PermissionType::OwnerRead) { mode |= _S_IREAD; } if(type & sprawl::filesystem::PermissionType::OwnerWrite) { mode |= _S_IWRITE; } #else if(type & sprawl::filesystem::PermissionType::OwnerRead) { mode |= S_IRUSR; } if(type & sprawl::filesystem::PermissionType::OwnerWrite) { mode |= S_IWUSR; } if(type & sprawl::filesystem::PermissionType::OwnerExecute) { mode |= S_IXUSR; } if(type & sprawl::filesystem::PermissionType::GroupRead) { mode |= S_IRGRP; } if(type & sprawl::filesystem::PermissionType::GroupWrite) { mode |= S_IWGRP; } if(type & sprawl::filesystem::PermissionType::GroupExecute) { mode |= S_IXGRP; } if(type & sprawl::filesystem::PermissionType::AllRead) { mode |= S_IROTH; } if(type & sprawl::filesystem::PermissionType::AllWrite) { mode |= S_IWOTH; } if(type & sprawl::filesystem::PermissionType::AllExecute) { mode |= S_IXOTH; } #endif return mode; } void sprawl::filesystem::ChMod(sprawl::String const& path, sprawl::filesystem::PermissionType::Type type) { chmod(path.GetOwned().c_str(), TranslateMode(type)); } void sprawl::filesystem::PutEnv(sprawl::String const& name, sprawl::String const& value) { #ifdef _WIN32 sprawl::String envstr = sprawl::Format("{}={}", name, value); putenv(envstr.GetOwned().c_str()); #else if(value.empty()) { unsetenv(name.GetOwned().c_str()); } else { setenv(name.GetOwned().c_str(), value.GetOwned().c_str(), true); } #endif } sprawl::String sprawl::filesystem::GetEnv(sprawl::String const& name, sprawl::String const& defaultValue) { char const* result = getenv(name.GetOwned().c_str()); if(result) { return sprawl::String(result); } return defaultValue; } void sprawl::filesystem::UnsetEnv(sprawl::String const& name) { #ifdef _WIN32 sprawl::String envstr = sprawl::Format("{}=", name); putenv(envstr.GetOwned().c_str()); #else unsetenv(name.GetOwned().c_str()); #endif } bool sprawl::filesystem::MkDir(sprawl::String const& path, sprawl::filesystem::PermissionType::Type mode) { #ifdef _WIN32 if(_mkdir(path.GetOwned().c_str()) == 0) { ChMod(path.GetOwned().c_str(), mode); return true; } return false; #else return (mkdir(path.GetOwned().c_str(), TranslateMode(mode)) == 0); #endif } bool sprawl::filesystem::MakeDirs(sprawl::String const& path, sprawl::filesystem::PermissionType::Type mode) { char const* const start = path.c_str(); char const* ptr = start; char const* const end = start + path.length(); char const sep = path::Separator(); char const altSep = path::AltSeparator(); while(ptr < end) { if(*ptr == sep || *ptr == altSep) { sprawl::String str(start, ptr - start); if(!path::Exists(str)) { if(!MkDir(str, mode)) { return false; } } else if(!path::IsDirectory(str)) { return false; } } ++ptr; } sprawl::String str(start, ptr - start); if(!path::Exists(str)) { if(!MkDir(str, mode)) { return false; } } else if(!path::IsDirectory(str)) { return false; } return true; } bool sprawl::filesystem::Remove(sprawl::String const& path) { #ifdef _WIN32 //Consistent behavior between windows and posix... symlinks should always be removed with Remove() and not RmDir() //Though Windows wants it differently, choosing Posix because they've been doing this longer. if (path::IsLink(path) && (GetFileAttributesA(path.c_str()) & FILE_ATTRIBUTE_DIRECTORY) != 0) { return (rmdir(path.GetOwned().c_str()) == 0); } #endif return (remove(path.GetOwned().c_str()) == 0); } bool sprawl::filesystem::RemoveDirs(sprawl::String const& path) { char const* const start = path.c_str(); char const* end = start + path.length() - 1; char const sep = path::Separator(); char const altSep = path::AltSeparator(); bool retcode = false; while (*end == sep || *end == altSep) { --end; } while(end > start) { if(!RmDir(sprawl::String(start, end - start + 1))) { return retcode; } retcode = true; //Backtrack to last separator while (*end != sep && *end != altSep) { --end; } //And beyond it while(*end == sep || *end == altSep) { --end; } } return true; } bool sprawl::filesystem::Rename(sprawl::String const& path, String const& newName) { return (rename(path.GetOwned().c_str(), newName.GetOwned().c_str()) == 0); } bool sprawl::filesystem::Renames(sprawl::String const& path, String const& newName) { if(!MakeDirs(path::Dirname(newName), 0777)) { return false; } return Rename(path, newName); } bool sprawl::filesystem::RmDir(sprawl::String const& path) { #ifdef _WIN32 //Consistent behavior between windows and posix... symlinks should always be removed with Remove() and not RmDir() //Though Windows wants it differently, choosing Posix because they've been doing this longer. if (path::IsLink(path)) { return false; } #endif return (rmdir(path.GetOwned().c_str()) == 0); } bool sprawl::filesystem::RmTree(sprawl::String const& path) { if(!path::IsDirectory(path)) { return Remove(path); } auto dirList = ListDir(path); for(auto& entry : dirList) { entry = path::Join(path, entry); if(path::IsDirectory(entry) && !path::IsLink(entry)) { if(!RmTree(entry)) { return false; } } else { if(!Remove(entry)) { return false; } } } if(!RmDir(path)) { return false; } return true; } int sprawl::filesystem::GetPid() { return getpid(); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 18645 | brandon_m_bare | Integrated latest version of libsprawl. | ||
#1 | 15089 | brandon_m_bare | First integration of sprawl. | ||
//guest/ShadauxCat/Sprawl/Mainline/filesystem/filesystem.cpp | |||||
#7 | 14822 | ShadauxCat |
Last batch of filesystem code for now, added MakeSymlink and GetPid, removed other todo functions for the time being. Also fixed some bugs: -Linux IsLink() implementation not using lstat = broken -File::IsClosed() would crash if file were created via default constructor or null handle -Remove() and RmDir() on Windows were inconsistent with Linux - in Linux all symlinks are removed with Remove() even if they point to directories. Forced windows to work the same way. -Asked RmTree to please not descend into symbolic links to directories, but just to remove them, thanks. -Removed starting \\?\ from result of RealPath() on Windows -Fixed IsFile() on Windows just not working - assuming anything that's not a directory is a file now. -Fixed StringBuilder only printing the first character if you passed it type char* instead of type char const* #review-14823 |
||
#6 | 14816 | ShadauxCat |
Filled in some more filesystem functions, added appropriate unit tests. Only a few remain. #review-14817 |
||
#5 | 14785 | ShadauxCat |
-Fixed search/replace mishap in const movement -Fixed a couple of missing windows headers -Adjusted PutEnv() so that Linux and Windows have matching functionality - empty string is equivalent to UnsetEnv. #review-14786 |
||
#4 | 14781 | ShadauxCat |
-Finished path library -Added some more functionality to filesystem library -Added a few more unit tests, still more needed for path #review-14782 |
||
#3 | 14767 | ShadauxCat |
Fix memory leak and unused variable. #review-14768 |
||
#2 | 14765 | ShadauxCat |
For-really fixing os x compile issues. Probably. #review-14766 |
||
#1 | 14761 | ShadauxCat |
First drop of code for sprawl::filesystem and sprawl::path. Library will continue to grow. Also fixed a warning on linux. #review-14762 |