From: J. Ali Harlow Date: Thu, 1 Oct 2009 17:51:02 +0000 (+0100) Subject: Implement proper locking X-Git-Tag: 0.3~2 X-Git-Url: http://project.juiblex.co.uk/git/?a=commitdiff_plain;h=1eed43715416c90e4c0f926eed390d8bc6fd8b53;p=razor2.git%2F.git Implement proper locking --- diff --git a/librazor/razor-internal.h b/librazor/razor-internal.h index d2f77c7..bc2b7bf 100644 --- a/librazor/razor-internal.h +++ b/librazor/razor-internal.h @@ -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); diff --git a/librazor/razor.c b/librazor/razor.c index cdbb693..b3f9c6a 100644 --- a/librazor/razor.c +++ b/librazor/razor.c @@ -37,6 +37,9 @@ #include #include #include +#ifdef MSWIN_API +#include +#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); } diff --git a/librazor/root.c b/librazor/root.c index d80cbec..3ca58cf 100644 --- a/librazor/root.c +++ b/librazor/root.c @@ -42,7 +42,14 @@ #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 *