diff --git a/src/cache.c b/src/cache.c index 37bbc95..e0ba293 100644 --- a/src/cache.c +++ b/src/cache.c @@ -1,30 +1,89 @@ #include "cache.h" -long Cache_read(const char *filepath, long offset, long len) +#include +#include +#include +#include +#include +#include +#include + +#define MAX_PATH_LEN 4096 + +/** + * \brief The metadata directory + */ +char *META_DIR; + +/** + * \brief The data directory + */ +char *DATA_DIR; + +/** + * \brief strndup with concatenation + * \details This function creates a new string, and concatenate string a and + * string b together. + * \note The maximum length of string a and string b is half the length of the + * maximum length of the output string. + * \param[in] a the first string + * \param[in] b the second string + * \param[n] c the maximum length of the output string + */ +char *strndupcat(const char *a, const char *b, int n) { + int na = strnlen(a, n/2); + int nb = strnlen(b, n/2); + int nc = na + nb + 1; + char *c = calloc(nc, sizeof(char)); + if (!c) { + fprintf(stderr, "strndupcat(): calloc failure!\n"); + } + strncpy(c, a, na); + strncat(c, b, nb); + return c; } -long Cache_write(const char *filepath, long offset, long len, - const uint8_t *content) +void Cache_init(const char *dir) { + META_DIR = strndupcat(dir, "meta/", MAX_PATH_LEN); + DATA_DIR = strndupcat(dir, "data/", MAX_PATH_LEN); } -Cache *Cache_create(const char *filepath, long len) +Cache *Cache_create(const char *fn, long len) { } +Cache *Cache_open(const char *fn) +{ + Cache *cf = malloc(sizeof(Cache)); + char *metafn = strndupcat(META_DIR, fn); + char *datafn = strndupcat(DATA_DIR, fn); + + /* Check if both metadata and the data file exist */ + if(access(cf->metafn, F_OK ) && access(cf->datafn, F_OK)) { + return NULL; + } + + free(metafn); + free(datafn); +} -Cache *Cache_open(const char *filepath) + +long Cache_read(const char *fn, long offset, long len, uint8_t *buf) +{ +} + +long Cache_write(const char *fn, long offset, long len, + const uint8_t *buf) { } void Cache_free(Cache *cf) { free(cf->filename); - free(cf->metapath); - free(cf->datapath); free(cf->seg); free(cf); } @@ -32,67 +91,106 @@ void Cache_free(Cache *cf) int Meta_read(Cache *cf) { FILE *fp; - fp = fopen(cf->metapath, "r"); + char *metafn = strndupcat(META_DIR, cf->filename, MAX_PATH_LEN); + fp = fopen(metafn, "r"); + free(metafn); + int res = 1; if (!fp) { /* The metadata file does not exist */ fprintf(stderr, "Meta_read(): fopen(): %s\n", strerror(errno)); - return -1; + return 0; } - fread((void *) &(cf->len), sizeof(long), 1, fp); - fread((void *) &(cf->nseg), sizeof(int), 1, fp); + fread(&(cf->len), sizeof(long), 1, fp); + fread(&(cf->time), sizeof(long), 1, fp); + fread(&(cf->nseg), sizeof(int), 1, fp); /* Allocate some memory for the segment */ cf->seg = malloc(cf->nseg * sizeof(Seg)); /* Read all the segment */ - fread((void *) cf->seg, sizeof(Seg), cf->nseg, fp); + int nmemb = fread(cf->seg, sizeof(Seg), cf->nseg, fp); - /* Simplified error checking */ + /* Error checking for fread */ if (ferror(fp)) { fprintf(stderr, "Meta_read(): fread(): encountered error (from ferror)!\n"); + res = 0; + } + + /* Check for inconsistent metadata file */ + if (nmemb != cf-> nseg) { + fprintf(stderr, + "Meta_read(): corrupted metadata!\n"); + res = 0; } if (fclose(fp)) { fprintf(stderr, "Meta_read(): fclose(): %s\n", strerror(errno)); - return -1; } + + return res; } int Meta_write(const Cache *cf) { FILE *fp; - fp = fopen(cf->metapath, "w"); + char *metafn = strndupcat(META_DIR, cf->filename, MAX_PATH_LEN); + fp = fopen(metafn, "w"); + free(metafn); + int res = 1; if (!fp) { - /* The metadata file does not exist */ + /* Cannot create the metadata file */ fprintf(stderr, "Meta_write(): fopen(): %s\n", strerror(errno)); - return -1; + return 0; } - /* We log the length of the file just in case */ - fwrite((const void *) cf->len, sizeof(long), 1, fp); - fwrite((const void *) cf->nseg, sizeof(int), 1, fp); + fwrite(&(cf->len), sizeof(long), 1, fp); + fwrite(&(cf->time), sizeof(long), 1, fp); + fwrite(&(cf->nseg), sizeof(int), 1, fp); /* Finally write segments to the file */ - fwrite((const void *) cf->seg, sizeof(Seg), cf->nseg, fp); + fwrite(cf->seg, sizeof(Seg), cf->nseg, fp); - /* Simplified error checking */ + /* Error checking for fwrite */ if (ferror(fp)) { fprintf(stderr, "Meta_write(): fwrite(): encountered error (from ferror)!\n"); + res = 0; } if (fclose(fp)) { fprintf(stderr, "Meta_write(): fclose(): %s\n", strerror(errno)); - return -1; } + return res; +} + +int Data_create(Cache *cf) +{ + int fd; + int mode; + + mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + char *datafn = strndupcat(DATA_DIR, cf->filename, MAX_PATH_LEN); + fd = open(datafn, O_WRONLY | O_CREAT, mode); + free(datafn); + if (fd == -1) { + fprintf(stderr, "Data_create(): open(): %s\n", strerror(errno)); + return 0; + } + if (ftruncate(fd, cf->len) == -1) { + fprintf(stderr, "Data_create(): ftruncate(): %s\n", strerror(errno)); + } + if (close(fd) == -1) { + fprintf(stderr, "Data_create(): close:(): %s\n", strerror(errno)); + } + return 1; } long Data_read(const Cache *cf, long offset, long len, - uint8_t *buf); + uint8_t *buf) { if (len == 0) { fprintf(stderr, "Data_read(): requested to read 0 byte!\n"); @@ -100,10 +198,13 @@ long Data_read(const Cache *cf, long offset, long len, } FILE *fp; - fp = fopen(cf->datapath, "r"); + char *datafn = strndupcat(DATA_DIR, cf->filename, MAX_PATH_LEN); + fp = fopen(datafn, "r"); + free(datafn); + long byte_read = -1; if (!fp) { - /* The data file does not exist */ + /* Failed to open the data file */ fprintf(stderr, "Data_read(): fopen(): %s\n", strerror(errno)); return -1; } @@ -111,13 +212,13 @@ long Data_read(const Cache *cf, long offset, long len, if (fseek(fp, offset, SEEK_SET) == -1) { /* fseek failed */ fprintf(stderr, "Data_read(): fseek(): %s\n", strerror(errno)); - return -1; + goto cleanup; } - long byte_read = fread((void *) buf, sizeof(uint8_t), len, fp); + byte_read = fread(buf, sizeof(uint8_t), len, fp); if (byte_read != len) { fprintf(stderr, - "Data_read(): fread(): requested %ld, returned %llu!\n", + "Data_read(): fread(): requested %ld, returned %ld!\n", len, byte_read); if (feof(fp)) { /* reached EOF */ @@ -130,14 +231,16 @@ long Data_read(const Cache *cf, long offset, long len, "Data_read(): fread(): encountered error (from ferror)!\n"); } } + + cleanup: if (fclose(fp)) { fprintf(stderr, "Data_read(): fclose(): %s\n", strerror(errno)); - return -1; } + return byte_read; } long Data_write(const Cache *cf, long offset, long len, - const uint8_t *buf); + const uint8_t *buf) { if (len == 0) { fprintf(stderr, "Data_write(): requested to write 0 byte!\n"); @@ -145,23 +248,27 @@ long Data_write(const Cache *cf, long offset, long len, } FILE *fp; - fp = fopen(cf->datapath, "r+"); + char *datafn = strndupcat(DATA_DIR, cf->filename, MAX_PATH_LEN); + fp = fopen(datafn, "r+"); + free(datafn); + long byte_written = -1; if (!fp) { - /* The data file does not exist */ + /* Failed to open the data file */ + fprintf(stderr, "Data_write(): fopen(): %s\n", strerror(errno)); return -1; } if (fseek(fp, offset, SEEK_SET) == -1) { /* fseek failed */ fprintf(stderr, "Data_write(): fseek(): %s\n", strerror(errno)); - return -1; + goto cleanup; } - long byte_written = fwrite((const void *) buf, sizeof(uint8_t), len, fp); + byte_written = fwrite(buf, sizeof(uint8_t), len, fp); if (byte_written != len) { fprintf(stderr, - "Data_write(): fwrite(): requested %ld, returned %llu!\n", + "Data_write(): fwrite(): requested %ld, returned %ld!\n", len, byte_written); if (feof(fp)) { /* reached EOF */ @@ -174,30 +281,12 @@ long Data_write(const Cache *cf, long offset, long len, "Data_write(): fwrite(): encountered error (from ferror)!\n"); } } + + cleanup: if (fclose(fp)) { fprintf(stderr, "Data_write(): fclose(): %s\n", strerror(errno)); - return -1; } + return byte_written; } -int Data_create(Cache *cf, long len) -{ - int fd; - int mode; - mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - fd = open(cf->filepath, O_WRONLY | O_CREAT, mode); - if (fd == -1) { - fprintf(stderr, "Data_create(): %s\n", strerror(errno)); - return 0; - } - if (ftruncate(fd, cf->len) == -1) { - fprintf(stderr, "Data_create(): %s\n", strerror(errno)); - return 0; - } - if (close(fd) == -1) { - fprintf(stderr, "Data_create(): %s\n", strerror(errno)); - return 0; - } - return 1; -} diff --git a/src/cache.h b/src/cache.h index f487b3e..16f846b 100644 --- a/src/cache.h +++ b/src/cache.h @@ -1,6 +1,7 @@ #ifndef CACHE_H #define CACHE_H +#include #include /** @@ -16,10 +17,6 @@ * - individual segments (array of seg) * * \note - * - apologies for whoever is going to be reading this. Sorry for being so - * verbose in this header file, this is probably one of the most challenging - * thing I have ever written so far! Yes I am doing a PhD in computer science, - * but it doesn't imply that I am good at computer science or programming! * - We are using 'long' to store file size, because the offset in fseek() is * in long, because the way we use the cache system, you cannot seek past * long. So the biggest file size has to be able to be stored in long. This @@ -27,7 +24,6 @@ * dependency to fseek(). */ - /** * \brief a cache segment */ @@ -41,23 +37,27 @@ typedef struct { * \note fanf2@cam.ac.uk told me to use an array rather than linked list! */ typedef struct { - const char *filename; /**< the filename from the http server */ - const char *metapath; /**< the path to the metadata file*/ - const char *datapath; /**< the path to the cache file */ + char *filename; /**< the filename from the http server */ long len; /**