summaryrefslogtreecommitdiff
path: root/src/rmd_cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rmd_cache.c')
-rw-r--r--src/rmd_cache.c211
1 files changed, 187 insertions, 24 deletions
diff --git a/src/rmd_cache.c b/src/rmd_cache.c
index bef6a83..94c0b68 100644
--- a/src/rmd_cache.c
+++ b/src/rmd_cache.c
@@ -37,6 +37,107 @@
#include <string.h>
#include <sys/stat.h>
+#define CACHE_FILE_SIZE_LIMIT (500 * 1024 * 1024)
+
+
+/* open file @ path storing the file handles in *file,
+ * this doesn't store the new path since it's primarily
+ * for the purposes of opening new chapters for the same
+ * base path.
+ */
+static int _rmdCacheFileOpen(CacheFile *file, const char *path)
+{
+ const char *modestr = "rb";
+
+ assert(file);
+
+ if (file->mode == RMD_CACHE_FILE_MODE_WRITE) {
+ modestr = "wb";
+
+ if (file->compressed)
+ modestr = "wb0f";
+ }
+
+ if (file->compressed) {
+ file->gzfp = gzopen(path, modestr);
+ } else {
+ file->fp = fopen(path, modestr);
+ }
+
+ if (!file->gzfp && !file->fp)
+ return -1;
+
+ file->chapter_n_bytes = 0;
+
+ return 0;
+}
+
+
+/* only close the internal file handle, but don't free file */
+static int _rmdCacheFileClose(CacheFile *file)
+{
+ assert(file);
+
+ /* TODO: return meaningful -errno on errors? */
+ if (file->gzfp) {
+ if (gzclose(file->gzfp) != Z_OK)
+ return -1;
+
+ file->gzfp = NULL;
+ } else if (file->fp) {
+ if (fclose(file->fp))
+ return -1;
+
+ file->fp = NULL;
+ }
+
+ return 0;
+}
+
+
+/* open a CacheFile @ path, in the specified mode, returns NULL on error */
+CacheFile * rmdCacheFileOpen(ProgData *pdata, const char *path, CacheFileMode mode)
+{
+ CacheFile *f;
+
+ assert(pdata);
+ assert(path);
+
+ f = calloc(1, sizeof(*f));
+ if (!f)
+ return NULL;
+
+ f->path = strdup(path);
+ if (!f->path) {
+ free(f);
+ return NULL;
+ }
+
+ f->mode = mode;
+ if (!pdata->args.zerocompression)
+ f->compressed = 1;
+
+ if (_rmdCacheFileOpen(f, path) < 0)
+ return NULL;
+
+ return f;
+}
+
+
+/* close a CacheFile, returns < 0 on error */
+int rmdCacheFileClose(CacheFile *file)
+{
+ assert(file);
+
+ if (_rmdCacheFileClose(file) < 0)
+ return -1;
+
+ free(file->path);
+ free(file);
+
+ return 0;
+}
+
/**
*Construct an number postfixed name
@@ -48,7 +149,7 @@
* \n number to be used as a postfix
*
*/
-static void rmdCacheFileN(char *name, char **newname, int n) // Nth cache file
+static void _rmdCacheFileN(char *name, char **newname, int n) // Nth cache file
{
char numbuf[8];
@@ -58,42 +159,104 @@ static void rmdCacheFileN(char *name, char **newname, int n) // Nth cache file
strcat(*newname, numbuf);
}
-int rmdSwapCacheFilesWrite(char *name, int n, gzFile *fp, FILE **ucfp)
+
+/* read from a CacheFile, identical to gzread() */
+ssize_t rmdCacheFileRead(CacheFile *file, void *ptr, size_t len)
{
- char *newname = malloc(strlen(name) + 10);
+ ssize_t ret, read_n_bytes = 0;
+
+ assert(file);
+ assert(ptr);
- rmdCacheFileN(name, &newname, n);
- if (*fp == NULL) {
- fflush(*ucfp);
- fclose(*ucfp);
- *ucfp = fopen(newname, "wb");
+ assert(file->mode == RMD_CACHE_FILE_MODE_READ);
+
+retry:
+ if (file->gzfp) {
+ int r;
+
+ r = gzread(file->gzfp, ptr + read_n_bytes, len);
+ if (r < 0)
+ return -1;
+
+ ret = r;
} else {
- gzflush(*fp, Z_FINISH);
- gzclose(*fp);
- *fp = gzopen(newname, "wb0f");
+ ret = fread(ptr + read_n_bytes, 1, len, file->fp);
+ }
+
+ read_n_bytes += ret;
+ file->chapter_n_bytes += read_n_bytes;
+ file->total_n_bytes += read_n_bytes;
+
+ if (ret < len) {
+ char *newpath = malloc(strlen(file->path) + 10);
+
+ len -= ret;
+
+ if (_rmdCacheFileClose(file) < 0) {
+ free(newpath);
+ return -1;
+ }
+
+ /* look for next chapter */
+ _rmdCacheFileN(file->path, &newpath, file->chapter + 1);
+ if (_rmdCacheFileOpen(file, newpath) == 0) {
+ file->chapter++;
+ free(newpath);
+ goto retry;
+ }
+
+ free(newpath);
}
- free(newname);
- return ((*fp == NULL) && (*ucfp == NULL));
+ return read_n_bytes;
}
-int rmdSwapCacheFilesRead(char *name, int n, gzFile *fp, FILE **ucfp)
+
+/* write to a CacheFile, identical to gzwrite() */
+ssize_t rmdCacheFileWrite(CacheFile *file, const void *ptr, size_t len)
{
- char *newname = malloc(strlen(name) + 10);
+ ssize_t ret;
+
+ assert(file);
+ assert(ptr);
+
+ assert(file->mode == RMD_CACHE_FILE_MODE_WRITE);
+
+ /* transparently open next chapter if needed */
+ if (file->chapter_n_bytes > CACHE_FILE_SIZE_LIMIT) {
+ char *newpath = malloc(strlen(file->path) + 10);
+
+ if (_rmdCacheFileClose(file) < 0)
+ return -1;
- rmdCacheFileN(name, &newname, n);
- if (*fp == NULL) {
- fclose(*ucfp);
- *ucfp = fopen(newname, "rb");
+ file->chapter++;
+
+ _rmdCacheFileN(file->path, &newpath, file->chapter);
+ if (_rmdCacheFileOpen(file, newpath) < 0) {
+ free(newpath);
+ return -1;
+ }
+ }
+
+ if (file->gzfp) {
+ int r;
+
+ r = gzwrite(file->gzfp, ptr, len);
+ if (r < 0)
+ return -1;
+
+ ret = r;
} else {
- gzclose(*fp);
- *fp = gzopen(newname, "rb");
+ ret = fwrite(ptr, 1, len, file->fp);
}
- free(newname);
- return ((*fp == NULL) && (*ucfp == NULL));
+ file->chapter_n_bytes += ret;
+ file->total_n_bytes += ret;
+
+ return ret;
}
+
int rmdPurgeCache(CacheData *cache_data_t, int sound)
{
struct stat buff;
@@ -109,7 +272,7 @@ int rmdPurgeCache(CacheData *cache_data_t, int sound)
fprintf(stderr, "Couldn't remove temporary file %s", cache_data_t->imgdata);
exit_value = 1;
}
- rmdCacheFileN(cache_data_t->imgdata, &fname, nth_cache);
+ _rmdCacheFileN(cache_data_t->imgdata, &fname, nth_cache);
nth_cache++;
}
© All Rights Reserved