Implement proper locking
authorJ. Ali Harlow <ali@juiblex.co.uk>
Thu, 1 Oct 2009 17:51:02 +0000 (18:51 +0100)
committerJ. Ali Harlow <ali@juiblex.co.uk>
Thu, 1 Oct 2009 19:02:12 +0000 (20:02 +0100)
librazor/razor-internal.h
librazor/razor.c
librazor/root.c

index d2f77c7..bc2b7bf 100644 (file)
@@ -119,6 +119,7 @@ struct razor_set {
        struct array file_string_pool;
        struct array details_string_pool;
        struct razor_mapped_file *mapped_files;
+       int lock_fd;
 };
 
 struct import_entry {
@@ -170,6 +171,9 @@ struct razor_file_iterator {
        int post_order;
 };
 
+int
+razor_set_aquire_lock(struct razor_set *set, const char *path, int exclusive);
+
 struct razor_entry *
 razor_set_find_entry(struct razor_set *set,
                     struct razor_entry *dir, const char *pattern);
index cdbb693..b3f9c6a 100644 (file)
@@ -37,6 +37,9 @@
 #include <fnmatch.h>
 #include <limits.h>
 #include <assert.h>
+#ifdef MSWIN_API
+#include <windows.h>
+#endif
 
 #include "razor-internal.h"
 #include "razor.h"
@@ -93,6 +96,8 @@ razor_set_create_without_root(void)
        empty = array_add(&set->string_pool, 1);
        *empty = '\0';
 
+       set->lock_fd = -1;
+
        return set;
 }
 
@@ -138,6 +143,13 @@ razor_set_bind_sections(struct razor_set *set, const char *filename)
                return -1;
        }
 
+       if (set->mapped_files == NULL) {
+               for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
+                       array = (void *) set + razor_sections[i].offset;
+                       array_release(array);
+               }
+       }
+
        file->next = set->mapped_files;
        set->mapped_files = file;
 
@@ -167,6 +179,7 @@ razor_set_open(const char *filename)
        struct razor_set *set;
 
        set = zalloc(sizeof *set);
+       set->lock_fd = -1;
        if (razor_set_bind_sections(set, filename)){
                free(set);
                return NULL;
@@ -174,6 +187,56 @@ razor_set_open(const char *filename)
        return set;
 }
 
+int
+razor_set_aquire_lock(struct razor_set *set, const char *path, int exclusive)
+{
+       int fd;
+       assert(set != NULL);
+
+       if (path) {
+               fd = open(path, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, 0666);
+               if (fd < 0)
+                       return -1;
+       } else {
+               fd = -1;
+       }
+
+#ifdef MSWIN_API
+       DWORD flags = LOCKFILE_FAIL_IMMEDIATELY;
+       OVERLAPPED lock = {0};
+
+       if (exclusive)
+               flags |= LOCKFILE_EXCLUSIVE_LOCK;
+       if (fd >= 0 && !LockFileEx(_get_osfhandle(fd), flags, 0, 1, 0, &lock)) {
+               close(fd);
+               return -1;
+       }
+       if (set->lock_fd >= 0)
+               (void)UnlockFile(_get_osfhandle(set->lock_fd), 0, 0, 1, 0);
+#else
+       struct flock lock = {0};
+
+       lock.l_type = exclusive ? F_WRLCK : F_RDLCK;
+       lock.l_whence = SEEK_SET;
+       lock.l_start = 0;
+       lock.l_len = 0;
+       if (fd >= 0 && fcntl(fd, F_SETLK, &lock) < 0) {
+               close(fd);
+               return -1;
+       }
+       if (set->lock_fd >= 0) {
+               lock.l_type = F_UNLCK;
+               (void)fcntl(set->lock_fd, F_SETLK, &lock);
+       }
+#endif
+
+       if (set->lock_fd >= 0)
+               close(set->lock_fd);
+       set->lock_fd = fd;
+
+       return 0;
+}
+
 RAZOR_EXPORT void
 razor_set_destroy(struct razor_set *set)
 {
@@ -196,6 +259,7 @@ razor_set_destroy(struct razor_set *set)
                }
        }
 
+       razor_set_aquire_lock(set, NULL, 0);
        free(set);
 }
 
index d80cbec..3ca58cf 100644 (file)
 #endif
 
 static const char system_repo_filename[] = "system.rzdb";
-static const char next_repo_filename[] = "system-next.rzdb";
+/*
+ * system_lock_filename is chosen to be the same as the pre v0.3
+ * next_repo_filename. This means that once a system has been
+ * updated by a v0.3+ copy of razor all pre v0.3 versions of razor
+ * will see the system as permenantly locked.
+ */
+static const char system_lock_filename[] = "system-next.rzdb";
+static const char system_tmp_filename[] = "system.tmp";
 #ifdef MSWIN_API
 #define RAZOR_ROOT_PATH        NULL
 #else
@@ -129,6 +136,7 @@ RAZOR_EXPORT struct razor_root *
 razor_root_open(const char *root)
 {
        struct razor_root *image;
+       char lock_path[PATH_MAX];
 
        assert (root != NULL);
 
@@ -137,21 +145,28 @@ razor_root_open(const char *root)
        if (image == NULL)
                return NULL;
 
-       /* Create the new next repo file up front to ensure exclusive
-        * access. */
+       image->system = razor_set_create_without_root();
+       if (image->system == NULL) {
+               free(image);
+               return NULL;
+       }
+
+       snprintf(lock_path, sizeof lock_path,
+                "%s%s/%s", root, razor_root_path, system_lock_filename);
+
+       if (razor_set_aquire_lock(image->system, lock_path, 1) < 0) {
+               razor_set_destroy(image->system);
+               free(image);
+               return NULL;
+       }
+
        snprintf(image->new_path, sizeof image->new_path,
-                "%s%s/%s", root, razor_root_path, next_repo_filename);
+                "%s%s/%s", root, razor_root_path, system_tmp_filename);
        image->fd = open(image->new_path,
-                        O_CREAT | O_WRONLY | O_TRUNC | O_EXCL | O_BINARY,
+                        O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
                         0666);
        if (image->fd < 0) {
-               fprintf(stderr, "failed to get lock file, "
-                       "maybe previous operation crashed?\n");
-
-               /* FIXME: Use fcntl advisory locking on the system
-                * package set file to figure out whether previous
-                * operation crashed or is still in progress. */
-
+               razor_set_destroy(image->system);
                free(image);
                return NULL;
        }
@@ -159,10 +174,10 @@ razor_root_open(const char *root)
        snprintf(image->path, sizeof image->path,
                 "%s%s/%s", root, razor_root_path, system_repo_filename);
 
-       image->system = razor_set_open(image->path);
-       if (image->system == NULL) {
-               unlink(image->new_path);
+       if (razor_set_bind_sections(image->system, image->path)) {
                close(image->fd);
+               unlink(image->new_path);
+               razor_set_destroy(image->system);
                free(image);
                return NULL;
        }
@@ -174,14 +189,31 @@ RAZOR_EXPORT struct razor_set *
 razor_root_open_read_only(const char *root)
 {
        char path[PATH_MAX];
+       struct razor_set *set;
 
        assert (root != NULL);
 
        razor_root_init();
+       set = razor_set_create_without_root();
+       if (set == NULL)
+               return NULL;
+
+       snprintf(path, sizeof path,
+                "%s%s/%s", root, razor_root_path, system_lock_filename);
+       if (razor_set_aquire_lock(set, path, 0) < 0) {
+               razor_set_destroy(set);
+               return NULL;
+       }
+
        snprintf(path, sizeof path, "%s%s/%s",
                 root, razor_root_path, system_repo_filename);
 
-       return razor_set_open(path);
+       if (razor_set_bind_sections(set, path)) {
+               razor_set_destroy(set);
+               return NULL;
+       }
+
+       return set;
 }
 
 RAZOR_EXPORT struct razor_set *