/** * @file lfile.c * * @brief Handle read/write abstractions to the users directory. * * @todo Add support for windows and mac OS. */ #include #include #include #if defined(LINUX) || defined(FREEBSD) #include #include #include #include #include #include #endif #include "lephisto.h" #include "log.h" #include "lfile.h" static char lephisto_base[PATH_MAX] = "\0"; /**< Store Lephisto's base path. */ /** * @fn char* lfile_basePath(void) * * @brief Get Lephisto's base path (for saves etc..). * @return The base path to Lephisto. */ char* lfile_basePath(void) { char* home; if(lephisto_base[0] == '\0') { #if defined(LINUX) || defined(FREEBSD) home = getenv("HOME"); snprintf(lephisto_base, PATH_MAX, "%s/.lephisto/", home); #else FILE* f; /* Try to open the file, C89 compliant, but not as precise as stat. */ f = fopen(file, 'r'); if(f != NULL) { fclose(f); return 1; } #endif } return lephisto_base; } /** * @fn int lfile_dirMakeExist(const char* path) * * @brief Create a directory if it doesn't exist. * * Uses relative path to basePath. * @param path Path to create directory if it doesn't exist. * @return 0 on success. */ int lfile_dirMakeExist(const char* path, ...) { char file[PATH_MAX]; va_list ap; if(path == NULL) return -1; else { /* Get the message. */ va_start(ap, path); vsnprintf(file, PATH_MAX, path, ap); va_end(ap); } #if defined(LINUX) || defined(FREEBSD) struct stat buf; stat(file, &buf); if(!S_ISDIR(buf.st_mode)) if(mkdir(file, S_IRWXU | S_IRWXG | S_IRWXO) < 0) { WARN("Dir '%s' does not exist and unable to create", file); return -1; } #else #error "Needs implentation." #endif return 0; } /** * @fn int lfile_fileExists(const char* path, ...) * * @brief Check to see if a file exists. * @param path printf formatted string pointing to the file to check for existance. * @return 1 if file exists, 0 if it doesn't or -1 on error. */ int lfile_fileExists(const char* path, ...) { char file[PATH_MAX]; va_list ap; if(path == NULL) return -1; else { /* Get the message. */ va_start(ap, path); vsnprintf(file, PATH_MAX, path, ap); va_end(ap); } #if defined(LINUX) || defined(FREEBSD) struct stat buf; if(stat(file, &buf)==0) /* Stat worked, file must exist. */ return 1; #else #error "Needs implementation." #endif return 0; } /** * @fn char** lfile_readDir(int* lfiles, const char* path) * * @brief Lists all the visible files in a directory. * * Should also sort by last modified but thats up to the OS in question. * Paths are relative to base directory. * @param[out] lfiles Returns how many files there are. * @param path Directory to read. */ char** lfile_readDir(int* lfiles, const char* path, ...) { char file[PATH_MAX], base[PATH_MAX]; char** files; va_list ap; if(path == NULL) { *lfiles = 0; return NULL; } else { /* Get the message. */ va_start(ap, path); vsnprintf(base, PATH_MAX, path, ap); va_end(ap); } #if defined(LINUX) || defined(FREEBSD) int i, j, k, n; DIR* d; struct dirent *dir; char* name; int mfiles; struct stat sb; time_t* tt, *ft; char** tfiles; (*lfiles) = 0; mfiles = 100; tfiles = malloc(sizeof(char*)*mfiles); tt = malloc(sizeof(time_t)*mfiles); d = opendir(base); if(d == NULL) return NULL; /* Get the file list. */ while((dir = readdir(d)) != NULL) { name = dir->d_name; /* Skip hidden directories. */ if(name[0] == '.') continue; /* Stat the file. */ snprintf(file, PATH_MAX, "%s/%s", base, name); if(stat(file, &sb) == -1) continue; /* Unable to stat. */ /* Enough memory? */ if((*lfiles)+1 > mfiles) { mfiles += 100; tfiles = realloc(files, sizeof(char*) * mfiles); tt = realloc(tt, sizeof(time_t) * mfiles); } /* Write the information. */ tfiles[(*lfiles)] = strdup(name); tt[(*lfiles)] = sb.st_mtime; (*lfiles)++; } closedir(d); /* Sort by last changed date. */ if((*lfiles) > 0) { /* Need to allocate some stuff. */ files = malloc(sizeof(char*)*(*lfiles)); ft = malloc(sizeof(time_t)*(*lfiles)); /* Fill the list. */ for(i = 0; i < (*lfiles); i++) { n = -1; /* Get the next lowest. */ for(j = 0; j < (*lfiles); j++) { /* Is lower? */ if((n == -1) || (tt[j] > tt[n])) { /* Check if it's already there. */ for(k = 0; k < i; k++) if(strcmp(files[k], tfiles[j])==0) break; /* New lowest. */ if(k >= i) n = j; } } files[i] = tfiles[n]; ft[i] = tt[n]; } free(ft); } else files = NULL; /* Free temp stuff. */ free(tfiles); free(tt); #else #error "Needs implementation." #endif /* What if we find nothing? */ if((*lfiles) == 0) { free(files); files = NULL; } return files; } /** * @brief Tries to create the file if it doesn't exist. * @param path Path of the file to create. */ int lfile_touch(const char* path, ...) { char file[PATH_MAX]; va_list ap; FILE* f; if(path == NULL) return -1; else { /* Get the message. */ va_start(ap, path); vsnprintf(file, PATH_MAX, path, ap); va_end(ap); } /* Try to open the file, C89 cmpliant, but not as precise as stat. */ f = fopen(file, "a+"); if(f == NULL) { WARN("Unable to touch file '%s': %s", file, strerror(errno)); return -1; } fclose(f); return 0; }