#include "../include/FileUtil.hpp" #include "../include/env.hpp" #include #if OS_FAMILY == OS_FAMILY_POSIX #include #include #include #include #endif using namespace std; namespace sibs { FileType getFileType(const char *path) { tinydir_file file; if(tinydir_file_open(&file, path) == 0) { return file.is_dir ? FileType::DIRECTORY : FileType::REGULAR; } else { return FileType::FILE_NOT_FOUND; } } // TODO: Handle failure (directory doesn't exist, no permission etc) void walkDir(const char *directory, FileWalkCallbackFunc callbackFunc) { tinydir_dir dir; tinydir_open(&dir, directory); while (dir.has_next) { tinydir_file file; tinydir_readfile(&dir, &file); if(_tinydir_strcmp(file.name, ".") != 0 && _tinydir_strcmp(file.name, "..") != 0) callbackFunc(&file); tinydir_next(&dir); } tinydir_close(&dir); } // TODO: Handle failure (directory doesn't exist, no permission etc) void walkDirFiles(const char *directory, FileWalkCallbackFunc callbackFunc) { tinydir_dir dir; tinydir_open(&dir, directory); while (dir.has_next) { tinydir_file file; tinydir_readfile(&dir, &file); if(file.is_reg) callbackFunc(&file); tinydir_next(&dir); } tinydir_close(&dir); } // TODO: Handle failure (directory doesn't exist, no permission etc) void walkDirFilesRecursive(const char *directory, FileWalkCallbackFunc callbackFunc) { tinydir_dir dir; tinydir_open(&dir, directory); while (dir.has_next) { tinydir_file file; tinydir_readfile(&dir, &file); if(file.is_reg) callbackFunc(&file); else if(_tinydir_strcmp(file.name, ".") != 0 && _tinydir_strcmp(file.name, "..") != 0) walkDirFilesRecursive(file.path, callbackFunc); tinydir_next(&dir); } tinydir_close(&dir); } Result getFileContent(const char *filepath) { FILE *file = fopen(filepath, "rb"); if(!file) { int error = errno; string errMsg = "Failed to open file: "; errMsg += filepath; errMsg += "; reason: "; errMsg += strerror(error); return Result::Err(errMsg); } fseek(file, 0, SEEK_END); size_t fileSize = ftell(file); fseek(file, 0, SEEK_SET); // TODO: Change this to string so it can be deallocated and use std::move to prevent copies char *result = (char*)malloc(fileSize + 1); if(!result) { std::string errMsg = "Failed to load file content from file: "; errMsg += filepath; throw std::runtime_error(errMsg); } result[fileSize] = '\0'; fread(result, 1, fileSize, file); fclose(file); return Result::Ok(StringView(result, fileSize)); } Result fileOverwrite(const char *filepath, StringView data) { FILE *file = fopen(filepath, "wb"); if(!file) { int error = errno; string errMsg = "Failed to overwrite file: "; errMsg += filepath; errMsg += "; reason: "; errMsg += strerror(error); return Result::Err(errMsg); } setbuf(file, NULL); fwrite(data.data, 1, data.size, file); fclose(file); return Result::Ok(true); } const char* getHomeDir() { const char *homeDir = getenv("HOME"); if(!homeDir) { passwd *pw = getpwuid(getuid()); homeDir = pw->pw_dir; } return homeDir; } Result getCwd() { string cwd; cwd.reserve(PATH_MAX); if(getcwd(&cwd[0], PATH_MAX) != 0) { if(cwd.empty()) cwd = "."; return Result::Ok(cwd); } return Result::Err(strerror(errno)); } #if OS_FAMILY == OS_FAMILY_POSIX Result createDirectoryRecursive(const char *path) { char pathBuffer[PATH_MAX]; size_t pathLength = strlen(path); if(pathLength > sizeof(pathBuffer) - 1) { string errMsg = "Directory path too long: "; errMsg += string(path, pathLength); return Result::Err(errMsg, ENAMETOOLONG); } strcpy(pathBuffer, path); char *p = pathBuffer; for(size_t i = 0; i < pathLength; ++i) { if(i > 0 && *p == '/') { *p = '\0'; if(mkdir(pathBuffer, S_IRWXU) != 0) { int error = errno; if(error != EEXIST) { string errMsg = "Failed to create directory: "; errMsg += pathBuffer; errMsg += "; reason: "; errMsg += strerror(error); return Result::Err(errMsg, error); } } *p = '/'; } ++p; } if(mkdir(pathBuffer, S_IRWXU) != 0) { int error = errno; if(error != EEXIST) { string errMsg = "Failed to create directory: "; errMsg += pathBuffer; errMsg += "; reason: "; errMsg += strerror(error); return Result::Err(errMsg, error); } } return Result::Ok(true); } Result getRealPath(const char *path) { // TODO: Verify NULL can be passed as 'resolved' argument with different compilers and operating systems (clang, freebsd etc) char *resolved = realpath(path, nullptr); if(!resolved) { int error = errno; string errMsg = "Failed to get real path for \""; errMsg += path; errMsg += "\": "; errMsg += strerror(error); return Result::Err(errMsg, error); } string result = resolved; free(resolved); return Result::Ok(result); } #else #error "TODO: Implement createDirectoryRecursive and getRealPath on windows" #endif }