#include #include #include #include #include "pcompiler.h" #include "pfile.h" #include "plibs.h" #include "pmem.h" #include "ppath.h" #include "psettings.h" #include "psql.h" char *ppath_default_db() { char *pcdir, *dbp, *home, *oldp; struct stat st; pcdir = ppath_pcloud(); if (!pcdir) { return NULL; } dbp = putil_strcat(pcdir, "/", PSYNC_DEFAULT_DB_NAME, NULL); pmem_free(PMEM_SUBSYS_OTHER, pcdir); if (stat(dbp, &st)) { // Inline the old database path function here if ((home = ppath_home())) { oldp = putil_strcat(home, "/", PSYNC_DEFAULT_POSIX_DBNAME, NULL); pmem_free(PMEM_SUBSYS_OTHER, home); if (oldp) { if (!stat(oldp, &st)) { if (psql_reopen(oldp)) { pmem_free(PMEM_SUBSYS_OTHER, dbp); return oldp; } else { pfile_rename(oldp, dbp); } } pmem_free(PMEM_SUBSYS_OTHER, oldp); } } } return dbp; } int64_t ppath_free_space(const char *path) { struct statvfs buf; if (pdbg_unlikely(statvfs(path, &buf))) return -1; else return (int64_t)buf.f_bavail * (int64_t)buf.f_frsize; } char *ppath_home() { struct stat st; const char *dir; /* buff must be function-scoped: dir may point into it (via pw_dir) and * must remain valid through the putil_strdup(dir) call below. */ char buff[4096]; dir = getenv("HOME"); if (pdbg_unlikely(!dir) || pdbg_unlikely(stat(dir, &st)) || pdbg_unlikely(!pfile_stat_mode_ok(&st, 7))) { struct passwd pwd; struct passwd *result; if (pdbg_unlikely(getpwuid_r(getuid(), &pwd, buff, sizeof(buff), &result)) || pdbg_unlikely(stat(result->pw_dir, &st)) || pdbg_unlikely(!pfile_stat_mode_ok(&st, 7))) return NULL; dir = result->pw_dir; } return putil_strdup(dir); } int ppath_ls(const char *path, ppath_ls_cb callback, void *ptr) { ppath_stat pst; DIR *dh; char *cpath; size_t pl; struct dirent *de; dh = opendir(path); if (unlikely(!dh)) { pdbg_logf(D_WARNING, "could not open directory %s", path); psync_error = PERROR_LOCAL_FOLDER_NOT_FOUND; return -1; } pl = strlen(path); cpath = (char *)pmem_malloc(PMEM_SUBSYS_OTHER, pl + NAME_MAX + 2); memcpy(cpath, path, pl); if (!pl || cpath[pl - 1] != '/') cpath[pl++] = '/'; pst.path = cpath; while ((de = readdir(dh))) { // Skip . and .. entries if (de->d_name[0] == '.' && (de->d_name[1] == 0 || (de->d_name[1] == '.' && de->d_name[2] == 0))) continue; putil_strlcpy(cpath + pl, de->d_name, NAME_MAX + 1); if (pdbg_likely(!lstat(cpath, &pst.stat)) && (S_ISREG(pst.stat.st_mode) || S_ISDIR(pst.stat.st_mode))) { pst.name = de->d_name; callback(ptr, &pst); } } pmem_free(PMEM_SUBSYS_OTHER, cpath); closedir(dh); return 0; } int ppath_ls_fast(const char *path, ppath_ls_fast_cb callback, void *ptr) { ppath_fast_stat pst; struct stat st; DIR *dh; char *cpath; size_t pl; struct dirent *de; dh = opendir(path); if (pdbg_unlikely(!dh)) { psync_error = PERROR_LOCAL_FOLDER_NOT_FOUND; return -1; } pl = strlen(path); cpath = (char *)pmem_malloc(PMEM_SUBSYS_OTHER, pl + NAME_MAX + 2); memcpy(cpath, path, pl); if (!pl || cpath[pl - 1] != '/') cpath[pl++] = '/'; while ((de = readdir(dh))) { // Skip . and .. entries if (de->d_name[0] == '.' && (de->d_name[1] == 0 || (de->d_name[1] == '.' && de->d_name[2] == 0))) continue; pst.name = de->d_name; if (de->d_type == DT_DIR) { pst.isfolder = 1; callback(ptr, &pst); } else if (de->d_type == DT_REG) { pst.isfolder = 0; callback(ptr, &pst); } else if (de->d_type == DT_UNKNOWN) { // Fall back to lstat for unknown file types putil_strlcpy(cpath + pl, de->d_name, NAME_MAX + 1); if (!pdbg_unlikely(lstat(cpath, &st))) { pst.isfolder = S_ISDIR(st.st_mode); callback(ptr, &pst); } } // Ignore other file types } pmem_free(PMEM_SUBSYS_OTHER, cpath); closedir(dh); return 0; } char *ppath_pcloud() { char *homedir, *path; struct stat st; if (!(homedir = ppath_home())) { return NULL; } path = putil_strcat(homedir, "/", PSYNC_DEFAULT_POSIX_DIR, NULL); pmem_free(PMEM_SUBSYS_OTHER, homedir); if (pdbg_unlikely(!path)) { return NULL; } if (stat(path, &st) && pdbg_unlikely(mkdir(path, PSYNC_DEFAULT_POSIX_FOLDER_MODE))) { pmem_free(PMEM_SUBSYS_OTHER, path); return NULL; } return path; } char *ppath_private(char *name) { char *path, *rpath; struct stat st; path = ppath_pcloud(); if (!path) return NULL; rpath = putil_strcat(path, "/", name, NULL); if (stat(rpath, &st) && mkdir(path, PSYNC_DEFAULT_POSIX_FOLDER_MODE)) { pmem_free(PMEM_SUBSYS_OTHER, rpath); pmem_free(PMEM_SUBSYS_OTHER, path); return NULL; } pmem_free(PMEM_SUBSYS_OTHER, path); return rpath; } char *ppath_private_tmp() { return ppath_private(PSYNC_DEFAULT_TMP_DIR); }