diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
commit | 6352e8e3196f78388b6c771073f9e03eaa612673 (patch) | |
tree | e23772f79a7fbc41bc9108951e9e136857484bf4 /source/core/StarFile_unix.cpp | |
parent | 6741a057e5639280d85d0f88ba26f000baa58f61 (diff) |
everything everywhere
all at once
Diffstat (limited to 'source/core/StarFile_unix.cpp')
-rw-r--r-- | source/core/StarFile_unix.cpp | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/source/core/StarFile_unix.cpp b/source/core/StarFile_unix.cpp new file mode 100644 index 0000000..aa22bc8 --- /dev/null +++ b/source/core/StarFile_unix.cpp @@ -0,0 +1,295 @@ +#include "StarFile.hpp" +#include "StarFormat.hpp" +#include "StarRandom.hpp" +#include "StarEncode.hpp" + +#include <errno.h> +#include <string.h> +#include <limits.h> +#include <stdlib.h> +#include <dirent.h> +#include <unistd.h> +#include <libgen.h> +#include <fcntl.h> +#include <sys/stat.h> + +#ifdef STAR_SYSTEM_MACOSX +#include <mach-o/dyld.h> +#elif defined STAR_SYSTEM_FREEBSD +#include <sys/types.h> +#include <sys/sysctl.h> +#endif + +namespace Star { + +namespace { + int fdFromHandle(void* ptr) { + return (int)(intptr_t)ptr; + } + + void* handleFromFd(int handle) { + return (void*)(intptr_t)handle; + } +} + +String File::convertDirSeparators(String const& path) { + return path.replace("\\", "/"); +} + +String File::currentDirectory() { + char buffer[PATH_MAX]; + if (::getcwd(buffer, PATH_MAX) == NULL) + throw IOException("getcwd failed"); + + return String(buffer); +} + +void File::changeDirectory(const String& dirName) { + if (::chdir(dirName.utf8Ptr()) != 0) + throw IOException(strf("could not change directory to %s", dirName)); +} + +void File::makeDirectory(String const& dirName) { + if (::mkdir(dirName.utf8Ptr(), 0777) != 0) + throw IOException(strf("could not create directory '%s', %s", dirName, strerror(errno))); +} + +List<pair<String, bool>> File::dirList(const String& dirName, bool skipDots) { + List<std::pair<String, bool>> fileList; + DIR* directory = ::opendir(dirName.utf8Ptr()); + if (directory == NULL) + throw IOException::format("dirList failed on dir: '%s'", dirName); + + for (dirent* entry = ::readdir(directory); entry != NULL; entry = ::readdir(directory)) { + String entryString = entry->d_name; + if (!skipDots || (entryString != "." && entryString != "..")) { + bool isDirectory = false; + if (entry->d_type == DT_DIR) { + isDirectory = true; + } else if (entry->d_type == DT_LNK || entry->d_type == DT_UNKNOWN) { + isDirectory = File::isDirectory(File::relativeTo(dirName, entryString)); + } + fileList.append({entryString, isDirectory}); + } + } + ::closedir(directory); + + return fileList; +} + +String File::baseName(const String& fileName) { + String ret; + + std::string file = fileName.utf8(); + char* fn = new char[file.size() + 1]; + std::copy(file.begin(), file.end(), fn); + fn[file.size()] = 0; + ret = String(::basename(fn)); + delete[] fn; + + return ret; +} + +String File::dirName(const String& fileName) { + String ret; + + std::string file = fileName.utf8(); + char* fn = new char[file.size() + 1]; + std::copy(file.begin(), file.end(), fn); + fn[file.size()] = 0; + ret = String(::dirname(fn)); + delete[] fn; + + return ret; +} + +String File::relativeTo(String const& relativeTo, String const& path) { + if (path.beginsWith("/")) + return path; + return relativeTo.trimEnd("/") + '/' + path; +} + +String File::fullPath(const String& fileName) { + char buffer[PATH_MAX]; + + if (::realpath(fileName.utf8Ptr(), buffer) == NULL) + throw IOException::format("realpath failed on file: '%s' problem path was: '%s'", fileName, buffer); + + return String(buffer); +} + +String File::temporaryFileName() { + return relativeTo(P_tmpdir, strf("starbound.tmpfile.%s", hexEncode(Random::randBytes(16)))); +} + +FilePtr File::temporaryFile() { + return open(temporaryFileName(), IOMode::ReadWrite); +} + +FilePtr File::ephemeralFile() { + auto file = make_shared<File>(); + ByteArray path = ByteArray::fromCStringWithNull(relativeTo(P_tmpdir, "starbound.tmpfile.XXXXXXXX").utf8Ptr()); + auto res = mkstemp(path.ptr()); + if (res < 0) + throw IOException::format("tmpfile error: %s", strerror(errno)); + if (::unlink(path.ptr()) < 0) + throw IOException::format("Could not remove mkstemp file when creating ephemeralFile: %s", strerror(errno)); + file->m_file = handleFromFd(res); + file->setMode(IOMode::ReadWrite); + return file; +} + +String File::temporaryDirectory() { + String dirname = relativeTo(P_tmpdir, strf("starbound.tmpdir.%s", hexEncode(Random::randBytes(16)))); + makeDirectory(dirname); + return dirname; +} + +bool File::exists(String const& path) { + struct stat st_buf; + int status = stat(path.utf8Ptr(), &st_buf); + return status == 0; +} + +bool File::isFile(String const& path) { + struct stat st_buf; + int status = stat(path.utf8Ptr(), &st_buf); + if (status != 0) + return false; + + return S_ISREG(st_buf.st_mode); +} + +bool File::isDirectory(String const& path) { + struct stat st_buf; + int status = stat(path.utf8Ptr(), &st_buf); + if (status != 0) + return false; + + return S_ISDIR(st_buf.st_mode); +} + +void File::remove(String const& filename) { + if (::remove(filename.utf8Ptr()) < 0) + throw IOException::format("remove error: %s", strerror(errno)); +} + +void File::rename(String const& source, String const& target) { + if (::rename(source.utf8Ptr(), target.utf8Ptr()) < 0) + throw IOException::format("rename error: %s", strerror(errno)); +} + +void File::overwriteFileWithRename(char const* data, size_t len, String const& filename, String const& newSuffix) { + String newFile = filename + newSuffix; + writeFile(data, len, newFile); + File::rename(newFile, filename); +} + +void* File::fopen(char const* filename, IOMode mode) { + int oflag = 0; + + if (mode & IOMode::Read && mode & IOMode::Write) + oflag |= O_RDWR | O_CREAT; + else if (mode & IOMode::Read) + oflag |= O_RDONLY; + else if (mode & IOMode::Write) + oflag |= O_WRONLY | O_CREAT; + + if (mode & IOMode::Truncate) + oflag |= O_TRUNC; + + int fd = ::open(filename, oflag, 0666); + if (fd < 0) + throw IOException::format("Error opening file '%s', error: %s", filename, strerror(errno)); + + if (mode & IOMode::Append) { + if (lseek(fd, 0, SEEK_END) < 0) + throw IOException::format("Error opening file '%s', cannot seek: %s", filename, strerror(errno)); + } + + return handleFromFd(fd); +} + +void File::fseek(void* f, StreamOffset offset, IOSeek seekMode) { + auto fd = fdFromHandle(f); + int retCode; + if (seekMode == IOSeek::Relative) + retCode = lseek(fd, offset, SEEK_CUR); + else if (seekMode == IOSeek::Absolute) + retCode = lseek(fd, offset, SEEK_SET); + else + retCode = lseek(fd, offset, SEEK_END); + + if (retCode < 0) + throw IOException::format("Seek error: %s", strerror(errno)); +} + +StreamOffset File::ftell(void* f) { + return lseek(fdFromHandle(f), 0, SEEK_CUR); +} + +size_t File::fread(void* file, char* data, size_t len) { + if (len == 0) + return 0; + + auto fd = fdFromHandle(file); + auto ret = ::read(fd, data, len); + if (ret < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; + throw IOException::format("Read error: %s", strerror(errno)); + } else { + return ret; + } +} + +size_t File::fwrite(void* file, char const* data, size_t len) { + if (len == 0) + return 0; + + auto fd = fdFromHandle(file); + auto ret = ::write(fd, data, len); + if (ret < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; + throw IOException::format("Write error: %s", strerror(errno)); + } else { + return ret; + } +} + +void File::fsync(void* file) { + auto fd = fdFromHandle(file); +#ifdef STAR_SYSTEM_LINUX + ::fdatasync(fd); +#else + ::fsync(fd); +#endif +} + +void File::fclose(void* file) { + if (::close(fdFromHandle(file)) < 0) + throw IOException::format("Close error: %s", strerror(errno)); +} + +StreamOffset File::fsize(void* file) { + StreamOffset pos = ftell(file); + StreamOffset size = lseek(fdFromHandle(file), 0, SEEK_END); + lseek(fdFromHandle(file), pos, SEEK_SET); + return size; +} + +size_t File::pread(void* file, char* data, size_t len, StreamOffset position) { + return ::pread(fdFromHandle(file), data, len, position); +} + +size_t File::pwrite(void* file, char const* data, size_t len, StreamOffset position) { + return ::pwrite(fdFromHandle(file), data, len, position); +} + +void File::resize(void* f, StreamOffset size) { + if (::ftruncate(fdFromHandle(f), size) < 0) + throw IOException::format("resize error: %s", strerror(errno)); +} + +} |