From: Eric Biggers Date: Thu, 22 Nov 2012 04:25:04 +0000 (-0600) Subject: Implement advisory locking for WIM overwrites X-Git-Tag: v1.2.0~17 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=7c83ef53090441de11cc78d8d26dc337cd7ac475 Implement advisory locking for WIM overwrites --- diff --git a/config.h.in b/config.h.in index 05d6092e..7b52011b 100644 --- a/config.h.in +++ b/config.h.in @@ -48,6 +48,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_ERRNO_H +/* Define to 1 if you have the `flock' function. */ +#undef HAVE_FLOCK + /* Define if you have the iconv() function and it works. */ #undef HAVE_ICONV @@ -87,6 +90,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_ENDIAN_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FILE_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H diff --git a/configure.ac b/configure.ac index 03b44e6c..c35b62ab 100644 --- a/configure.ac +++ b/configure.ac @@ -29,10 +29,10 @@ AC_CONFIG_FILES([Makefile AC_PROG_CC AM_PROG_CC_C_O -AC_CHECK_FUNCS([utimensat lutimes utime]) +AC_CHECK_FUNCS([utimensat lutimes utime flock]) AC_CHECK_HEADERS([endian.h byteswap.h sys/byteorder.h sys/endian.h \ sys/param.h machine/endian.h alloca.h stdlib.h stdarg.h \ - errno.h attr/xattr.h utime.h]) + errno.h attr/xattr.h utime.h sys/file.h]) AM_ICONV diff --git a/src/util.c b/src/util.c index faa0d0bf..3dbb5cdc 100644 --- a/src/util.c +++ b/src/util.c @@ -108,6 +108,8 @@ WIMLIBAPI int wimlib_set_print_errors(bool show_error_messages) static const char *error_strings[] = { [WIMLIB_ERR_SUCCESS] = "Success", + [WIMLIB_ERR_ALREADY_LOCKED] + = "The WIM is already locked for writing", [WIMLIB_ERR_COMPRESSED_LOOKUP_TABLE] = "Lookup table is compressed", [WIMLIB_ERR_DECOMPRESSION] @@ -379,17 +381,19 @@ ssize_t full_write(int fd, const void *buf, size_t n) static bool seeded = false; +static void seed_random() +{ + srand(time(NULL) * getpid()); + seeded = true; +} + /* Fills @n bytes pointed to by @p with random alphanumeric characters. */ void randomize_char_array_with_alnum(char p[], size_t n) { - int r; - - if (!seeded) { - srand(time(NULL)); - seeded = true; - } + if (!seeded) + seed_random(); while (n--) { - r = rand() % 62; + int r = rand() % 62; if (r < 26) *p++ = r + 'a'; else if (r < 52) @@ -402,10 +406,8 @@ void randomize_char_array_with_alnum(char p[], size_t n) /* Fills @n bytes pointer to by @p with random numbers. */ void randomize_byte_array(u8 *p, size_t n) { - if (!seeded) { - srand(time(NULL)); - seeded = true; - } + if (!seeded) + seed_random(); while (n--) *p++ = rand(); } diff --git a/src/wim.c b/src/wim.c index 500fc1eb..44653f19 100644 --- a/src/wim.c +++ b/src/wim.c @@ -43,7 +43,6 @@ #include "lookup_table.h" #include "xml.h" - static int print_metadata(WIMStruct *w) { DEBUG("Printing metadata for image %d", w->current_image); @@ -421,7 +420,7 @@ WIMLIBAPI int wimlib_get_boot_idx(const WIMStruct *w) } /* Opens a WIM readable */ -int open_wim_readable(WIMStruct *w, const char *path) +static int open_wim_readable(WIMStruct *w, const char *path) { if (w->fp != NULL) fclose(w->fp); @@ -435,30 +434,6 @@ int open_wim_readable(WIMStruct *w, const char *path) return 0; } -/* Opens a WIM writable */ -int open_wim_writable(WIMStruct *w, const char *path, - bool trunc, bool readable) -{ - const char *mode; - if (trunc) - if (readable) - mode = "w+b"; - else - mode = "wb"; - else - mode = "r+b"; - - DEBUG("Opening `%s' read-write", path); - wimlib_assert(w->out_fp == NULL); - wimlib_assert(path != NULL); - w->out_fp = fopen(path, mode); - if (!w->out_fp) { - ERROR_WITH_ERRNO("Failed to open `%s' for writing", path); - return WIMLIB_ERR_OPEN; - } - return 0; -} - /* * Begins the reading of a WIM file; opens the file and reads its header and * lookup table, and optionally checks the integrity. diff --git a/src/wimlib.h b/src/wimlib.h index 690f9dee..0b0f04bf 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -667,6 +667,7 @@ typedef int (*wimlib_progress_func_t)(enum wimlib_progress_msg msg_type, */ enum wimlib_error_code { WIMLIB_ERR_SUCCESS = 0, + WIMLIB_ERR_ALREADY_LOCKED, WIMLIB_ERR_COMPRESSED_LOOKUP_TABLE, WIMLIB_ERR_DECOMPRESSION, WIMLIB_ERR_DELETE_STAGING_DIR, @@ -1575,6 +1576,11 @@ extern int wimlib_open_wim(const char *wim_file, int open_flags, * * @return 0 on success; nonzero on error. This function may return any value * returned by wimlib_write() as well as the following error codes: + * @retval ::WIMLIB_ERR_ALREADY_LOCKED + * The append-only overwrite mode was going to be used, but an exclusive + * advisory lock on the on-disk WIM file could not be acquired, probably + * because another thread or process was calling wimlib_overwrite() on the + * same underlying on-disk file at the same time. * @retval ::WIMLIB_ERR_NO_FILENAME * @a wim corresponds to a WIM created with wimlib_create_new_wim() rather * than a WIM read with wimlib_open_wim(). @@ -1744,8 +1750,8 @@ extern void wimlib_print_wim_information(const WIMStruct *wim); * image, indexed starting at 1, is returned. If the keyword "all" or "*" * was specified, ::WIMLIB_ALL_IMAGES is returned. Otherwise, * ::WIMLIB_NO_IMAGE is returned. If @a image_name_or_num was @c NULL or - * the empty string, ::WIM_NO_IMAGE is returned, even if one or more images - * in @a wim has no name. + * the empty string, ::WIMLIB_NO_IMAGE is returned, even if one or more + * images in @a wim has no name. */ extern int wimlib_resolve_image(WIMStruct *wim, const char *image_name_or_num); diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index ac35c4fc..19497834 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -526,9 +526,6 @@ extern WIMStruct *new_wim_struct(); extern int select_wim_image(WIMStruct *w, int image); extern int wim_hdr_flags_compression_type(int wim_hdr_flags); extern int for_image(WIMStruct *w, int image, int (*visitor)(WIMStruct *)); -extern int open_wim_readable(WIMStruct *w, const char *path); -extern int open_wim_writable(WIMStruct *w, const char *path, - bool trunc, bool readable); /* Internal use only */ #define WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE 0x80000000 diff --git a/src/write.c b/src/write.c index b143f16d..773de0b7 100644 --- a/src/write.c +++ b/src/write.c @@ -55,6 +55,11 @@ #include #endif +#if defined(HAVE_SYS_FILE_H) && defined(HAVE_FLOCK) +#include +#endif + + static int do_fflush(FILE *fp) { int ret = fflush(fp); @@ -1487,6 +1492,49 @@ out: return ret; } +static int open_wim_writable(WIMStruct *w, const char *path, + bool trunc, bool readable) +{ + const char *mode; + int ret = 0; + if (trunc) + if (readable) + mode = "w+b"; + else + mode = "wb"; + else + mode = "r+b"; + + DEBUG("Opening `%s' read-write", path); + wimlib_assert(w->out_fp == NULL); + wimlib_assert(path != NULL); + w->out_fp = fopen(path, mode); + if (!w->out_fp) { + ERROR_WITH_ERRNO("Failed to open `%s' for writing", path); + return WIMLIB_ERR_OPEN; + } +#if defined(HAVE_SYS_FILE_H) && defined(HAVE_FLOCK) + if (!trunc) { + ret = flock(fileno(w->out_fp), LOCK_EX | LOCK_NB); + if (ret != 0) { + if (errno == EWOULDBLOCK) { + ERROR("`%s' is already being modified " + "by another process", path); + ret = WIMLIB_ERR_ALREADY_LOCKED; + fclose(w->out_fp); + w->out_fp = NULL; + } else { + WARNING("Failed to lock `%s': %s", + path, strerror(errno)); + ret = 0; + } + } + } +#endif + return ret; +} + + static void close_wim_writable(WIMStruct *w) { if (w->out_fp) {