--- a/src/lib/cache.c Sun Dec 27 22:01:17 2009 +0200
+++ b/src/lib/cache.c Sun Dec 27 23:14:10 2009 +0200
@@ -1,55 +1,234 @@
#include "cache.h"
-static int pt_cache_new (struct pt_cache **cache_ptr)
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+
+
+static int pt_cache_new (struct pt_cache **cache_ptr, const char *path)
{
struct pt_cache *cache;
+ // alloc
if ((cache = calloc(1, sizeof(*cache))) == NULL)
return -1;
+ if ((cache->path = strdup(path)) == NULL)
+ goto error;
+
+ // init
+ cache->fd = -1;
+
+ // ok
+ *cache_ptr = cache;
+
+ return 0;
+
+error:
+ // cleanup
+ if (cache)
+ pt_cache_destroy(cache);
+
+ return -1;
+}
+
+int pt_cache_open (struct pt_cache **cache_ptr, const char *path, int mode)
+{
+ struct pt_cache *cache;
+
+ // alloc
+ if (pt_cache_new(&cache, path))
+ return -1;
+
// ok
*cache_ptr = cache;
return 0;
}
-int pt_cache_open (struct pt_cache **cache_ptr, struct pt_image *img, int mode)
-{
- struct pt_cache *cache;
-
- // alloc
- if (pt_cache_new(&cache))
- return -1;
-
-
-}
-
-bool pt_cache_fresh (struct pt_cache *cache)
+int pt_cache_stale (struct pt_cache *cache, const char *orig_path)
{
// TODO: stat + mtime
return false;
}
/**
+ * Abort any incomplete open operation, cleaning up
+ */
+static void pt_cache_abort (struct pt_cache *cache)
+{
+ if (cache->mmap != NULL) {
+ munmap(cache->mmap, cache->size);
+
+ cache->mmap = NULL;
+ }
+
+ if (cache->fd >= 0) {
+ close(cache->fd);
+
+ cache->fd = -1;
+ }
+}
+
+/**
+ * Open the cache file as an fd.
+ *
+ * XXX: needs locking
+ */
+static int pt_cache_open_fd (struct pt_cache *cache, int *fd_ptr)
+{
+ int fd;
+ int flags = 0;
+
+ // determine open flags
+ // XXX: O_RDONLY | O_WRONLY == O_RDWR?
+ if (cache->mode & PT_IMG_READ)
+ flags |= O_RDONLY;
+
+ if (cache->mode & PT_IMG_WRITE)
+ flags |= (O_WRONLY | O_CREAT);
+
+ // actual open()
+ if ((fd = open(cache->path, flags)) < 0)
+ return -1;
+
+ // ok
+ *fd_ptr = fd;
+
+ return 0;
+}
+
+/**
+ * Mmap the opened cache file from offset PT_CACHE_PAGE, using the calculated size stored in cache->size
+ */
+static int pt_cache_open_mmap (struct pt_cache *cache, void **addr_ptr)
+{
+ int prot = 0;
+ void *addr;
+
+ // determine prot
+ if (cache->mode & PT_IMG_READ)
+ prot |= PROT_READ;
+
+ if (cache->mode & PT_IMG_WRITE)
+ prot |= PROT_WRITE;
+
+ // perform mmap() from second page on
+ if ((addr = mmap(NULL, cache->size, prot, MAP_SHARED, cache->fd, PT_CACHE_PAGE)) == MAP_FAILED)
+ return -1;
+
+ // ok
+ *addr_ptr = addr;
+
+ return 0;
+}
+
+/**
+ * Write out the cache header into the opened file
+ */
+static int pt_cache_write_header (struct pt_cache *cache, const struct pt_cache_header *header)
+{
+ size_t len = sizeof(*header);
+ const char *buf = (const char *) header;
+
+ // seek to start
+ if (lseek(cache->fd, 0, SEEK_SET) != 0)
+ return -1;
+
+ // write out full header
+ while (len) {
+ ssize_t ret;
+
+ // try and write out the header
+ if ((ret = write(cache->fd, buf, len)) < 0)
+ return -1;
+
+ // update offset
+ buf += ret;
+ len -= ret;
+ }
+
+ // done
+ return 0;
+}
+
+/**
* Create a new cache file, open it, and write out the header.
*/
-static int pt_cache_create (struct pt_cache *cache, struct pt_cache_header *header)
+static int pt_cache_open_create (struct pt_cache *cache, struct pt_cache_header *header)
{
-
+ // open
+ if (pt_cache_open_fd(cache, &cache->fd))
+ return -1;
+
+ // calculate data size
+ cache->size = sizeof(*header) + header->height * header->row_bytes;
+
+ // grow file
+ if (ftruncate(cache->fd, PT_CACHE_PAGE + cache->size) < 0)
+ goto error;
+
+ // open mmap
+ if (pt_cache_open_mmap(cache, (void **) &cache->mmap))
+ goto error;
+
+ // write header
+ if (pt_cache_write_header(cache, header))
+ goto error;
+
+ // done
+ return 0;
+
+error:
+ // cleanup
+ pt_cache_abort(cache);
+
+ return -1;
}
int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info)
{
struct pt_cache_header header;
+
+ // XXX: check cache_mode
+ // XXX: check image doesn't use any options we don't handle
memset(&header, 0, sizeof(header));
// fill in basic info
- header->width = png_get_image_width(png, info);
- header->height = png_get_image_height(png, info);
- header->bit_depth = png_get_bit_depth(png, info);
- header->color_type = png_get_color_type(png, info);
+ header.width = png_get_image_width(png, info);
+ header.height = png_get_image_height(png, info);
+ header.bit_depth = png_get_bit_depth(png, info);
+ header.color_type = png_get_color_type(png, info);
// fill in other info
- header->row_bytes = png_get_rowbytes(png, info);
+ header.row_bytes = png_get_rowbytes(png, info);
+
+ // create and write out header
+ if (pt_cache_open_create(cache, &header))
+ return -1;
+
+ // XXX: pallette etc.
+
+ // write out raw image data a row at a time
+ for (size_t row = 0; row < header.height; row++) {
+ // read row data, non-interlaced
+ png_read_row(png, cache->mmap + row * header.row_bytes, NULL);
+ }
+
+ // done!
+ return 0;
}
+
+void pt_cache_destroy (struct pt_cache *cache)
+{
+ free(cache->path);
+
+ pt_cache_abort(cache);
+
+ free(cache);
+}