all the functions written so far compile fine, working on Cache_open
This commit is contained in:
parent
9f1b963014
commit
7ae6d6fe1b
203
src/cache.c
203
src/cache.c
|
@ -1,30 +1,89 @@
|
|||
#include "cache.h"
|
||||
|
||||
long Cache_read(const char *filepath, long offset, long len)
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
56
src/cache.h
56
src/cache.h
|
@ -1,6 +1,7 @@
|
|||
#ifndef CACHE_H
|
||||
#define CACHE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
|
@ -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; /**<the size of the file */
|
||||
long time; /**<the modified time of the file */
|
||||
int nseg; /**<the number of segments */
|
||||
Seg *seg; /**< the detail of each segment */
|
||||
} Cache;
|
||||
} Cache;
|
||||
|
||||
/***************************** To be completed ******************************/
|
||||
|
||||
/**
|
||||
* \brief create a cache file set
|
||||
*/
|
||||
Cache *Cache_create(const char *fn, long len);
|
||||
|
||||
/**
|
||||
* \brief Read from a cache file set
|
||||
* \details This function performs the following two things:
|
||||
* - check again the metafile to see which segments are available
|
||||
* - return the available segments
|
||||
*/
|
||||
long Cache_read(const char *filepath, long offset, long len);
|
||||
long Cache_read(const char *fn, long offset, long len, uint8_t *buf);
|
||||
|
||||
/**
|
||||
* \brief Write to a cache file set
|
||||
|
@ -65,21 +65,24 @@ long Cache_read(const char *filepath, long offset, long len);
|
|||
* - Write to the data file
|
||||
* - Update the metadata file
|
||||
*/
|
||||
long Cache_write(const char *filepath, long offset, long len,
|
||||
const uint8_t *content);
|
||||
long Cache_write(const char *fn, long offset, long len,
|
||||
const uint8_t *buf);
|
||||
/****************************** Work in progress *****************************/
|
||||
|
||||
/**
|
||||
* \brief create a cache file
|
||||
* \brief open a cache file set
|
||||
*/
|
||||
Cache *Cache_create(const char *filepath, long len);
|
||||
|
||||
/**
|
||||
* \brief open a cache file
|
||||
*/
|
||||
Cache *Cache_open(const char *filepath);
|
||||
Cache *Cache_open(const char *fn);
|
||||
|
||||
/**************************** Completed functions ****************************/
|
||||
|
||||
/**
|
||||
* \brief initialise the cache system
|
||||
* \details This function basically sets up the following variables:
|
||||
* - META_DIR
|
||||
* - DATA_DIR
|
||||
*/
|
||||
void Cache_init(const char *dir);
|
||||
|
||||
/**
|
||||
* \brief free a cache data structure
|
||||
|
@ -93,25 +96,34 @@ int Meta_write(const Cache *cf);
|
|||
|
||||
/**
|
||||
* \brief read a metadata file
|
||||
* \return 0 on error, 1 on success
|
||||
*/
|
||||
int Meta_read(Cache *cf);
|
||||
|
||||
/**
|
||||
* \brief create a data file
|
||||
* \details We use sparse creation here
|
||||
* \return 1 on success, 0 on failure
|
||||
* \return
|
||||
* - 1 on successful creation of the data file, note that the result of
|
||||
* the ftruncate() is ignored.
|
||||
* - 0 on failure to create the data file.
|
||||
*/
|
||||
int Data_create(Cache *cf, long len);
|
||||
int Data_create(Cache *cf);
|
||||
|
||||
/**
|
||||
* \brief read a data file
|
||||
* \return -1 when the data file does not exist
|
||||
* \return
|
||||
* - -1 when the data file does not exist
|
||||
* - otherwise, the number of bytes read.
|
||||
*/
|
||||
long Data_read(const Cache *cf, long offset, long len,
|
||||
uint8_t *buf);
|
||||
|
||||
/**
|
||||
* \brief write to a data file
|
||||
* \return
|
||||
* - -1 when the data file does not exist
|
||||
* - otherwise, the number of bytes written.
|
||||
*/
|
||||
long Data_write(const Cache *cf, long offset, long len,
|
||||
const uint8_t *buf);
|
||||
|
|
Loading…
Reference in New Issue