#include "system_utils.hpp" #include #include #include #include #ifdef _WIN32 #include #include #include // Evitar conflictos con macros de Windows #ifdef ERROR_ALREADY_EXISTS #undef ERROR_ALREADY_EXISTS #endif #else #include #include #endif namespace SystemUtils { // Función auxiliar para crear una carpeta individual auto createSingleFolder(const std::string& path, int permissions) -> Result { struct stat st = {.st_dev = 0}; // Verificar si ya existe if (stat(path.c_str(), &st) == 0) { return Result::SUCCESS; // Ya existe, no es error por defecto } // Intentar crear la carpeta int result; #ifdef _WIN32 result = _mkdir(path.c_str()); #else result = mkdir(path.c_str(), permissions); #endif if (result == -1) { switch (errno) { case EACCES: return Result::PERMISSION_DENIED; case EEXIST: return Result::ALREADY_EXISTS; case ENAMETOOLONG: return Result::PATH_TOO_LONG; default: return Result::UNKNOWN_ERROR; } } return Result::SUCCESS; } // Función auxiliar para crear carpetas padre recursivamente auto createParentFolders(const std::string& path, int permissions) -> Result { size_t pos = 0; while ((pos = path.find('/', pos + 1)) != std::string::npos) { std::string parent = path.substr(0, pos); if (!parent.empty() && !folderExists(parent)) { Result result = createSingleFolder(parent, permissions); if (result != Result::SUCCESS && result != Result::ALREADY_EXISTS) { return result; } } } return Result::SUCCESS; } auto createApplicationFolder(const std::string& app_name, std::string& out_path) -> Result { FolderConfig config; return createApplicationFolder(app_name, out_path, config); } auto createApplicationFolder(const std::string& app_name, std::string& out_path, const FolderConfig& config) -> Result { out_path = getApplicationDataPath(app_name); return createFolder(out_path, config); } auto createFolder(const std::string& path) -> Result { FolderConfig config; return createFolder(path, config); } auto createFolder(const std::string& path, const FolderConfig& config) -> Result { if (path.empty()) { return Result::INVALID_PATH; } // Verificar si ya existe y si eso es un error if (folderExists(path) && config.fail_if_exists) { return Result::ALREADY_EXISTS; } // Crear carpetas padre si es necesario if (config.create_parents) { Result parent_result = createParentFolders(path, config.permissions); if (parent_result != Result::SUCCESS) { return parent_result; } } // Crear la carpeta final return createSingleFolder(path, config.permissions); } auto getApplicationDataPath(const std::string& app_name) -> std::string { #ifdef _WIN32 char* appdata = getenv("APPDATA"); if (appdata) { return std::string(appdata) + "/" + app_name; } return "C:/Users/Default/AppData/Roaming/" + app_name; #elif __APPLE__ std::string home = getHomeDirectory(); return home + "/Library/Application Support/" + app_name; #elif __linux__ std::string home = getHomeDirectory(); return home + "/.config/" + app_name; #else // Fallback genérico std::string home = getHomeDirectory(); return home + "/." + app_name; #endif } auto folderExists(const std::string& path) -> bool { struct stat st = {.st_dev = 0}; return (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)); } auto resultToString(Result result) -> const char* { switch (result) { case Result::SUCCESS: return "Operación exitosa"; case Result::PERMISSION_DENIED: return "Error: Permisos insuficientes"; case Result::PATH_TOO_LONG: return "Error: Ruta demasiado larga"; case Result::ALREADY_EXISTS: return "Error: La carpeta ya existe"; case Result::INVALID_PATH: return "Error: Ruta inválida"; case Result::UNKNOWN_ERROR: return "Error desconocido"; default: return "Error no identificado"; } } auto getHomeDirectory() -> std::string { #ifdef _WIN32 char* userprofile = getenv("USERPROFILE"); if (userprofile) { return std::string(userprofile); } return "C:/Users/Default"; #else struct passwd* pw = getpwuid(getuid()); if ((pw != nullptr) && (pw->pw_dir != nullptr)) { return {pw->pw_dir}; } // Fallback char* home = getenv("HOME"); if (home != nullptr) { return {home}; } return "/tmp"; #endif } auto getTempDirectory() -> std::string { #ifdef _WIN32 char* temp = getenv("TEMP"); if (temp) { return std::string(temp); } return "C:/Windows/Temp"; #else return "/tmp"; #endif } } // namespace SystemUtils