[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. * @brief Abstracts around packfiles.
*/ */
struct Packfile_s { struct Packfile_s {
@ -46,8 +44,36 @@ struct Packfile_s {
uint32_t pos; /**< Cursor position. */ uint32_t pos; /**< Cursor position. */
uint32_t start; /**< File start. */ uint32_t start; /**< File start. */
uint32_t end; /**< File end. */ 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. */ #undef DEBUG /* This will be spammy. */
#define DEBUG(str, args...) do{;} while(0) #define DEBUG(str, args...) do{;} while(0)
@ -62,9 +88,142 @@ struct Packfile_s {
const uint64_t magic = 0x25524573; /**< File magic number: sER% */ 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. * @brief Get the file size.
* @param filename File to get the size of. * @param filename File to get the size of.
* @return The size of the file. * @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 #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. * @brief Open a file in the packfile for reading.
* @param file Packfile to store data into. * @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) { Packfile_t* pack_open(const char* packfile, const char* filename) {
int j; int j;
uint32_t nfiles, i; uint32_t nfiles, i;
char* buf = malloc(PATH_MAX); char buf[PATH_MAX];
Packfile_t* file; Packfile_t* file;
/* Allocate memory. */ /* Allocate memory. */
file = malloc(sizeof(Packfile_t)); file = malloc(sizeof(Packfile_t));
memset(file, 0, sizeof(Packfile_t)); memset(file, 0, sizeof(Packfile_t));
buf = malloc(PATH_MAX);
#ifdef _POSIX_SOURCE #ifdef _POSIX_SOURCE
file->fd = open(packfile, O_RDONLY); file->fd = open(packfile, O_RDONLY);
@ -307,23 +456,23 @@ Packfile_t* pack_open(const char* packfile, const char* filename) {
return NULL; 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))) { if(memcmp(buf, &magic, sizeof(magic))) {
ERR("File %s is not a valid packfile", filename); ERR("File %s is not a valid packfile", filename);
return NULL; return NULL;
} }
READ(&nfiles, 4); READ(file, &nfiles, 4);
for(i = 0; i < nfiles; i++) { for(i = 0; i < nfiles; i++) {
/* Start to search files. */ /* Start to search files. */
j = 0; j = 0;
READ(&buf[j], 1); /* Get the name. */ READ(file, &buf[j], 1); /* Get the name. */
while(buf[j++] != '\0') while(buf[j++] != '\0')
READ(&buf[j], 1); READ(file, &buf[j], 1);
if(strcmp(filename, buf) == 0) { if(strcmp(filename, buf) == 0) {
/* We found the file. */ /* We found the file. */
READ(&file->start, 4); READ(file, &file->start, 4);
DEBUG("'%s' found at %d", filename, file->start); DEBUG("'%s' found at %d", filename, file->start);
break; break;
} }
@ -333,7 +482,6 @@ Packfile_t* pack_open(const char* packfile, const char* filename) {
fseek(file->fp, 4, SEEK_CUR); fseek(file->fp, 4, SEEK_CUR);
#endif #endif
} }
free(buf);
if(file->start) { if(file->start) {
/* Go to the beginning of the file. */ /* 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)); ERR("Failure to seek to file start: %s", strerror(errno));
return NULL; return NULL;
} }
READ(&file->end, 4); READ(file, &file->end, 4);
DEBUG("\t%d bytes", file->end); DEBUG("\t%d bytes", file->end);
file->pos = file->start; file->pos = file->start;
file->end += file->start; file->end += file->start;
@ -356,7 +504,6 @@ Packfile_t* pack_open(const char* packfile, const char* filename) {
} }
return file; return file;
} }
#undef READ
/** /**
* @brief Reads data from a packfile. * @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. * @return Bytes to read or -1 on error.
*/ */
ssize_t pack_read(Packfile_t* file, void* buf, size_t count) { ssize_t pack_read(Packfile_t* file, void* buf, size_t count) {
int bytes;
if(file->pos + count > file->end) if(file->pos + count > file->end)
count = file->end - file->pos; /* Can't go past the end! */ count = file->end - file->pos; /* Can't go past the end! */
if(count == 0) return 0; if(count == 0) return 0;
int bytes;
#ifdef _POSIX_SOURCE #ifdef _POSIX_SOURCE
if((bytes = read(file->fd, buf, count)) == -1) { if((bytes = read(file->fd, buf, count)) == -1) {
#else #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. * @param nfiles Stores the amount of files in packfile.
* @return An array of filenames 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) { char** pack_listfiles(const char* packfile, uint32_t* nfiles) {
#ifdef _POSIX_SOURCE
int fd;
#else
FILE* fp;
#endif
int j; int j;
uint32_t i; uint32_t i;
Packfile_t file;
char** filenames; char** filenames;
char* buf = malloc(sizeof(magic)); char* buf = malloc(sizeof(magic));
*nfiles = 0; *nfiles = 0;
#ifdef _POSIX_SOURCE #ifdef _POSIX_SOURCE
fd = open(packfile, O_RDONLY); file.fd = open(packfile, O_RDONLY);
if(fd == -1) { if(file.fd == -1) {
#else #else
fp = fopen(packfile, "rb"); file.fp = fopen(packfile, "rb");
if(fp == NULL) { if(file.fp == NULL) {
#endif #endif
ERR("opening %s: %s", packfile, strerror(errno)); ERR("opening %s: %s", packfile, strerror(errno));
return NULL; 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))) { if(memcmp(buf, &magic, sizeof(magic))) {
ERR("File %s is not a valid packfile", packfile); ERR("File %s is not a valid packfile", packfile);
return NULL; return NULL;
} }
READ(nfiles, 4); READ(&file, nfiles, 4);
filenames = malloc(((*nfiles)+1)*sizeof(char*)); filenames = malloc(((*nfiles)+1)*sizeof(char*));
for(i = 0; i < *nfiles; i++) { for(i = 0; i < *nfiles; i++) {
/* Start searching files. */ /* Start searching files. */
j = 0; j = 0;
filenames[i] = malloc(PATH_MAX * sizeof(char)); 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') while(filenames[i][j++] != '\0')
READ(&filenames[i][j], 1); READ(&file, &filenames[i][j], 1);
READ(buf, 4); /* skip the location. */ READ(&file, buf, 4); /* skip the location. */
} }
free(buf); free(buf);
#ifdef _POSIX_SOURCE #ifdef _POSIX_SOURCE
close(fd); close(file.fd);
#else #else
fclose(fp); fclose(file.fp);
#endif #endif
return filenames; return filenames;
} }
#undef READ
/** /**
* @brief Closes a packfile. * @brief Closes a packfile.
@ -609,7 +742,10 @@ int pack_close(Packfile_t* file) {
#ifdef _POSIX_SOURCE #ifdef _POSIX_SOURCE
i = close(file->fd); i = close(file->fd);
#else #else
i = fclose(file->fp); if(file->flags & PACKFILE_FROMCACHE)
i = 0;
else
i = fclose(file->fp);
#endif #endif
return (i) ? -1 : 0; return (i) ? -1 : 0;
} }

View File

@ -9,6 +9,16 @@
struct Packfile_s; struct Packfile_s;
typedef struct Packfile_s Packfile_t; 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). */ /* Packfile manipulation. Automatically allocated and freed (with open and close). */
/* Basic. */ /* Basic. */