264 lines
5.4 KiB
C
264 lines
5.4 KiB
C
/**
|
|
* @file lfile.c
|
|
*
|
|
* @brief Handle read/write abstractions to the users directory.
|
|
*
|
|
* @todo Add support for windows and mac OS.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#ifdef LINUX
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#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') {
|
|
#ifdef LINUX
|
|
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);
|
|
}
|
|
|
|
#ifdef LINUX
|
|
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);
|
|
}
|
|
|
|
#ifdef LINUX
|
|
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);
|
|
}
|
|
|
|
#ifdef LINUX
|
|
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;
|
|
}
|
|
|