[Add] Started to work on cacheing the packfile.

This commit is contained in:
Allanis 2014-04-26 19:47:10 +01:00
parent 22b3f2085e
commit ba26575890
2 changed files with 198 additions and 52 deletions

View File

@ -33,8 +33,6 @@
*/
/**
* @struct Packfile
*
* @brief Abstracts around packfiles.
*/
struct Packfile_s {
@ -46,8 +44,36 @@ struct Packfile_s {
uint32_t pos; /**< Cursor position. */
uint32_t start; /**< File start. */
uint32_t end; /**< File end. */
uint32_t flags; /**< Special control flags. */
};
/**
* @brief Allows much faster creation of packfiles.
*/
struct Packcache_s {
#ifdef _POSIX_SOURCE
int fd; /**< File descriptor. */
#else
FILE* fp; /* For non-posix. */
#endif
char** index; /**< Cached index for faster lookups. */
uint32_t* start; /**< Cached index starts. */
uint32_t* nindex; /**< Number of index entries. */
};
/* Helper defines. */
#ifdef _POSIX_SOURCE
#define READ(f, b, n) if(read((f)->fd, (b), (n)) != (n)) { \
ERR("Fewer bytes read then expected"); \
return NULL; }
#else
#define READ(f, b, n) if(fread((b), 1, (n),(f)->fp) != (n)) { \
ERR("Fewer bytes read then expected"); \
return NULL; }
#endif
#undef DEBUG /* This will be spammy. */
#define DEBUG(str, args...) do{;} while(0)
@ -62,9 +88,142 @@ struct Packfile_s {
const uint64_t magic = 0x25524573; /**< File magic number: sER% */
/* Flags. */
#define PACKFILE_FROMCACHE (1<<0) /**< Packfile comes from a packcache. */
static off_t getfilesize(const char* filename);
/**
* @brief Open a packfile as a cache.
* @param packfile Name of the packfile to cache.
* @return NULL if an error occured or the Packcache.
*/
Packcache_t* pack_openCache(const char* packfile) {
int j;
uint32_t i;
char buf[PATH_MAX];
Packcache_t* cache;
/* Allocate memory. */
cache = calloc(1, sizeof(Packcache_t));
if(cache == NULL) {
ERR("Out of memory.");
return NULL;
}
/* Open file. */
#ifdef _POSIX_SOURCE
cache->fd = open(packfile, O_RDONLY);
if(cache->fd == -1) {
#else
cache->fp = fopen(packfile, "rb");
if(cache->fp == NULL) {
#endif
ERR("Error opening %s: %s", packfile, strerror(errno));
return NULL;
}
/* Check for validity. */
READ(cache, buf, sizeof(magic));
if(memcmp(buf, &magic, sizeof(magic))) {
ERR("File %s is not a valid packfile", packfile);
return NULL;
}
/* Get the number of files and allocate memory. */
READ(cache, &cache->nindex, 4);
cache->index = calloc(cache->nindex, sizeof(char*));
cache->start = calloc(cache->nindex, sizeof(uint32_t));
/* Read index. */
for(i = 0; i < cache->nindex; i++) { /* Start to search files. */
j = 0;
READ(cache, &buf[j], 1); /* Get the name. */
while(buf[j++] != '\0')
READ(cache, &buf[j], 1);
cache->index[i] = strdup(buf);
READ(cache, &cache->start[i], 4);
DEBUG("'%s' found at %d", filename, cache->start[i]);
break;
}
/* Return the built cache. */
return cache;
}
/**
* @brief Close a Packcache.
* @param cache Packcache to close.
*/
void pack_closeCache(Packcache_t* cache) {
uint32_t i;
/* Close file. */
#ifdef _POSIX_SOURCE
close(cache->fd);
#else
fclose(cache->fp);
#endif
/* Free memory. */
if(cache->nindex > 0) {
for(i = 0; i < cache->nindex; i++)
free(cache->index[i]);
free(cache->index);
free(cache->start);
}
}
/**
* @brief Open a packfile from a Packcache.
* @param cache Packcache to create Packfile from.
* @param filename Name of the file to open in the Cache.
* @return A packfile for filename from cache.
*/
Packfile_t* pack_openFromCache(Packcache_t* cache, const char* filename) {
uint32_t i;
Packfile_t* file;
file = calloc(1, sizeof(Packfile_t));
for(i = 0; i < cache->nindex; i++) {
if(strcmp(cache->index[i], filename)==0) {
/* Copy file. */
#ifdef _POSIX_SOURCE
file->fd = dup(cache->fd);
#else
file->fp = cache->fp;
#endif
/* Copy information. */
file->flags |= PACKFILE_FROMCACHE;
file->start = cache->start[i];
/* Seek. */
if(file->start) { /* Go to the beginning of the file. */
#ifdef _POSIX_SOURCE
if((uint32_t)lseek(file->fd, file->start, SEEK_SET) != file->start) {
#else
fseek(file->fp, file->start, SEEK_SET);
if(errno) {
#endif
ERR("Failure to seek to file start: %s", strerror(errno));
return NULL;
}
READ(file, &file->end, 4);
DEBUG("\t%d bytes", file->end);
file->pos = file->start;
file->end += file->start;
}
break;
}
}
return NULL;
}
/**
* @fn static off_t getfilesize(const char* filename)
*
* @brief Get the file size.
* @param filename File to get the size of.
* @return The size of the file.
@ -269,15 +428,6 @@ int pack_files(const char* outfile, const char** infiles, const uint32_t nfiles)
}
#undef WRITE
#ifdef _POSIX_SOURCE
#define READ(b,n) if(read(file->fd, (b), (n))!=(n)) { \
ERR("Fewer bytes read than expected."); \
free(buf); return NULL; }
#else
#define READ(b,n) if(fread((b), 1, (n), file->fp)!=(n)) { \
ERR("Fewer bytes read then expected"); \
free(buf); return NULL; }
#endif
/**
* @brief Open a file in the packfile for reading.
* @param file Packfile to store data into.
@ -288,13 +438,12 @@ int pack_files(const char* outfile, const char** infiles, const uint32_t nfiles)
Packfile_t* pack_open(const char* packfile, const char* filename) {
int j;
uint32_t nfiles, i;
char* buf = malloc(PATH_MAX);
char buf[PATH_MAX];
Packfile_t* file;
/* Allocate memory. */
file = malloc(sizeof(Packfile_t));
memset(file, 0, sizeof(Packfile_t));
buf = malloc(PATH_MAX);
#ifdef _POSIX_SOURCE
file->fd = open(packfile, O_RDONLY);
@ -307,23 +456,23 @@ Packfile_t* pack_open(const char* packfile, const char* filename) {
return NULL;
}
READ(buf, sizeof(magic)); /* Make sure it's a packfile. */
READ(file, buf, sizeof(magic)); /* Make sure it's a packfile. */
if(memcmp(buf, &magic, sizeof(magic))) {
ERR("File %s is not a valid packfile", filename);
return NULL;
}
READ(&nfiles, 4);
READ(file, &nfiles, 4);
for(i = 0; i < nfiles; i++) {
/* Start to search files. */
j = 0;
READ(&buf[j], 1); /* Get the name. */
READ(file, &buf[j], 1); /* Get the name. */
while(buf[j++] != '\0')
READ(&buf[j], 1);
READ(file, &buf[j], 1);
if(strcmp(filename, buf) == 0) {
/* We found the file. */
READ(&file->start, 4);
READ(file, &file->start, 4);
DEBUG("'%s' found at %d", filename, file->start);
break;
}
@ -333,7 +482,6 @@ Packfile_t* pack_open(const char* packfile, const char* filename) {
fseek(file->fp, 4, SEEK_CUR);
#endif
}
free(buf);
if(file->start) {
/* Go to the beginning of the file. */
@ -346,7 +494,7 @@ Packfile_t* pack_open(const char* packfile, const char* filename) {
ERR("Failure to seek to file start: %s", strerror(errno));
return NULL;
}
READ(&file->end, 4);
READ(file, &file->end, 4);
DEBUG("\t%d bytes", file->end);
file->pos = file->start;
file->end += file->start;
@ -356,7 +504,6 @@ Packfile_t* pack_open(const char* packfile, const char* filename) {
}
return file;
}
#undef READ
/**
* @brief Reads data from a packfile.
@ -368,12 +515,12 @@ Packfile_t* pack_open(const char* packfile, const char* filename) {
* @return Bytes to read or -1 on error.
*/
ssize_t pack_read(Packfile_t* file, void* buf, size_t count) {
int bytes;
if(file->pos + count > file->end)
count = file->end - file->pos; /* Can't go past the end! */
if(count == 0) return 0;
int bytes;
#ifdef _POSIX_SOURCE
if((bytes = read(file->fd, buf, count)) == -1) {
#else
@ -538,66 +685,52 @@ void* pack_readfile(const char* packfile, const char* filename, uint32_t* filesi
* @param nfiles Stores the amount of files in packfile.
* @return An array of filenames in packfile.
*/
#ifdef _POSIX_SOURCE
#define READ(b,n) if(read(fd, (b), (n))!=(n)) { \
ERR("Too few bytes read"); \
return NULL; }
#else
#define READ(b,n) if(fread((b), 1, (n), fp) != (n)) { \
ERR("Too few bytes read"); \
return NULL; }
#endif
char** pack_listfiles(const char* packfile, uint32_t* nfiles) {
#ifdef _POSIX_SOURCE
int fd;
#else
FILE* fp;
#endif
int j;
uint32_t i;
Packfile_t file;
char** filenames;
char* buf = malloc(sizeof(magic));
*nfiles = 0;
#ifdef _POSIX_SOURCE
fd = open(packfile, O_RDONLY);
if(fd == -1) {
file.fd = open(packfile, O_RDONLY);
if(file.fd == -1) {
#else
fp = fopen(packfile, "rb");
if(fp == NULL) {
file.fp = fopen(packfile, "rb");
if(file.fp == NULL) {
#endif
ERR("opening %s: %s", packfile, strerror(errno));
return NULL;
}
READ(buf, sizeof(magic)); /* Make sure it is a packfile. */
READ(&file, buf, sizeof(magic)); /* Make sure it's a packfile. */
if(memcmp(buf, &magic, sizeof(magic))) {
ERR("File %s is not a valid packfile", packfile);
return NULL;
}
READ(nfiles, 4);
READ(&file, nfiles, 4);
filenames = malloc(((*nfiles)+1)*sizeof(char*));
for(i = 0; i < *nfiles; i++) {
/* Start searching files. */
j = 0;
filenames[i] = malloc(PATH_MAX * sizeof(char));
READ(&filenames[i][j], 1); /* Get the name. */
READ(&file, &filenames[i][j], 1); /* Get the name. */
while(filenames[i][j++] != '\0')
READ(&filenames[i][j], 1);
READ(buf, 4); /* skip the location. */
READ(&file, &filenames[i][j], 1);
READ(&file, buf, 4); /* skip the location. */
}
free(buf);
#ifdef _POSIX_SOURCE
close(fd);
close(file.fd);
#else
fclose(fp);
fclose(file.fp);
#endif
return filenames;
}
#undef READ
/**
* @brief Closes a packfile.
@ -609,6 +742,9 @@ int pack_close(Packfile_t* file) {
#ifdef _POSIX_SOURCE
i = close(file->fd);
#else
if(file->flags & PACKFILE_FROMCACHE)
i = 0;
else
i = fclose(file->fp);
#endif
return (i) ? -1 : 0;

View File

@ -9,6 +9,16 @@
struct Packfile_s;
typedef struct Packfile_s Packfile_t;
struct Packcache_s;
typedef struct Packcache_s Packcache_t;
/*
* Packcache manipulation.
*/
Packcache_t* pack_openCache(const char* packfile);
void pack_closeCache(Packcache_t* cache);
Packfile_t* pack_openFromCache(Packcache_t* cache, const char* filename);
/* Packfile manipulation. Automatically allocated and freed (with open and close). */
/* Basic. */