pt_cache_update checks mode, aborts .tmp, and use O_EXCL for opening the .tmp
authorTero Marttila <terom@fixme.fi>
Mon, 25 Jan 2010 02:19:10 +0200
changeset 66 55949307182c
parent 65 e02bede4a6e4
child 67 d8d9aa430ecc
pt_cache_update checks mode, aborts .tmp, and use O_EXCL for opening the .tmp
src/lib/cache.c
--- a/src/lib/cache.c	Mon Jan 25 02:09:43 2010 +0200
+++ b/src/lib/cache.c	Mon Jan 25 02:19:10 2010 +0200
@@ -200,6 +200,15 @@
     }
 }
 
+static int pt_cache_tmp_name (struct pt_cache *cache, char tmp_path[1024])
+{
+    // get .tmp path
+    if (path_with_fext(cache->path, tmp_path, sizeof(tmp_path), ".tmp"))
+        RETURN_ERROR(PT_ERR_PATH);
+
+    return 0;
+}
+
 /**
  * Open the .tmp cache file as an fd for writing
  */
@@ -207,14 +216,14 @@
 {
     int fd;
     char tmp_path[1024];
-    
+    int err;
+
     // get .tmp path
-    if (path_with_fext(cache->path, tmp_path, sizeof(tmp_path), ".tmp"))
-        RETURN_ERROR(PT_ERR_PATH);
+    if ((err = pt_cache_tmp_name(cache, tmp_path)))
+        return err;
 
-    // open for write, create
-    // XXX: locking? At least O_EXCL...
-    if ((fd = open(tmp_path, O_RDWR | O_CREAT, 0644)) < 0)
+    // open for write, create, fail if someone else already opened it for update
+    if ((fd = open(tmp_path, O_RDWR | O_CREAT | O_EXCL, 0644)) < 0)
         RETURN_ERROR(PT_ERR_CACHE_OPEN_TMP);
 
     // ok
@@ -322,9 +331,7 @@
 {
     int err;
 
-    // no access
-    if (!(cache->mode & PT_OPEN_UPDATE))
-        RETURN_ERROR(PT_ERR_OPEN_MODE);
+    assert(cache->mode & PT_OPEN_UPDATE);
 
     // open as .tmp
     if ((err = pt_cache_open_tmp_fd(cache, &cache->fd)))
@@ -358,10 +365,11 @@
 static int pt_cache_create_done (struct pt_cache *cache)
 {
     char tmp_path[1024];
+    int err;
     
     // get .tmp path
-    if (path_with_fext(cache->path, tmp_path, sizeof(tmp_path), ".tmp"))
-        RETURN_ERROR(PT_ERR_PATH);
+    if ((err = pt_cache_tmp_name(cache, tmp_path)))
+        return err;
 
     // rename
     if (rename(tmp_path, cache->path) < 0)
@@ -371,13 +379,41 @@
     return 0;
 }
 
+/**
+ * Abort a failed cache update after cache_create
+ */
+static void pt_cache_create_abort (struct pt_cache *cache)
+{
+    char tmp_path[1024];
+    int err;
+    
+    // close open stuff
+    pt_cache_abort(cache);
+
+    // get .tmp path
+    if ((err = pt_cache_tmp_name(cache, tmp_path))) {
+        log_warn_errno("pt_cache_tmp_name: %s: %s", cache->path, pt_strerror(err));
+        
+        return;
+    }
+
+    // remove .tmp
+    if (unlink(tmp_path))
+        log_warn_errno("unlink: %s", tmp_path);
+}
+
 int pt_cache_update (struct pt_cache *cache, struct pt_png_img *img, const struct pt_image_params *params)
 {
     struct pt_cache_header header;
     int err;
-    
-    // XXX: check cache_mode
-    // XXX: close any already-opened cache file
+
+    // check mode
+    if (!(cache->mode & PT_OPEN_UPDATE))
+        RETURN_ERROR(PT_ERR_OPEN_MODE);
+
+    // close if open
+    if ((err = pt_cache_close(cache)))
+        return err;
     
     // prep header
     header.version = PT_CACHE_VERSION;
@@ -397,14 +433,19 @@
 
     // decode to disk
     if ((err = pt_png_decode(img, &cache->file->header.png, &cache->file->header.params, cache->file->data)))
-        return err;
+        goto error;
 
     // done, commit .tmp
     if ((err = pt_cache_create_done(cache)))
-        // XXX: pt_cache_abort?
-        return err;
+        goto error;
+    
+    return 0;
 
-    return 0;
+error:
+    // cleanup .tmp
+    pt_cache_create_abort(cache);
+
+    return err;
 }
 
 int pt_cache_tile (struct pt_cache *cache, struct pt_tile *tile)