--- sylpheed/src/inc.c.alt-mboxlock 2006-03-09 09:37:55 +0300 +++ sylpheed/src/inc.c 2006-05-27 23:10:03 +0400 @@ -1257,7 +1257,7 @@ static gint inc_spool(void) static gint get_spool(FolderItem *dest, const gchar *mbox) { gint msgs, size; - gint lockfd; + FILE *mbox_fp; gchar tmp_mbox[MAXPATHLEN + 1]; GHashTable *folder_table = NULL; @@ -1270,14 +1270,14 @@ static gint get_spool(FolderItem *dest, } else if (size < 0) return -1; - if ((lockfd = lock_mbox(mbox, LOCK_FLOCK)) < 0) + if ((mbox_fp = open_and_lock_mbox(mbox, LOCK_FLOCK)) == NULL) return -1; g_snprintf(tmp_mbox, sizeof(tmp_mbox), "%s%ctmpmbox.%p", get_tmp_dir(), G_DIR_SEPARATOR, mbox); - if (copy_mbox(mbox, tmp_mbox) < 0) { - unlock_mbox(mbox, lockfd, LOCK_FLOCK); + if (copy_mbox(mbox, mbox_fp, tmp_mbox) < 0) { + unlock_and_close_mbox(mbox, mbox_fp, LOCK_FLOCK); return -1; } @@ -1289,8 +1289,8 @@ static gint get_spool(FolderItem *dest, msgs = proc_mbox(dest, tmp_mbox, folder_table); g_unlink(tmp_mbox); - if (msgs >= 0) empty_mbox(mbox); - unlock_mbox(mbox, lockfd, LOCK_FLOCK); + if (msgs >= 0) empty_mbox(mbox, mbox_fp); + unlock_and_close_mbox(mbox, mbox_fp, LOCK_FLOCK); if (folder_table) { if (!prefs_common.scan_all_after_inc) { --- sylpheed/configure.in.alt-mboxlock 2006-05-26 13:19:30 +0400 +++ sylpheed/configure.in 2006-05-27 23:10:58 +0400 @@ -343,6 +343,14 @@ if test $ac_cv_dirent_d_type = yes; then fi +dnl Select spool locking type +AC_ARG_ENABLE(flock, + [ --enable-flock Lock spool mailbox with flock], + [ac_cv_enable_flock=$enableval], [ac_cv_enable_flock=maybe]) +AC_ARG_ENABLE(fcntl, + [ --enable-fcntl Lock spool mailbox with fcntl], + [ac_cv_enable_fcntl=$enableval], [ac_cv_enable_fcntl=maybe]) + dnl Checks for header files. AC_HEADER_DIRENT AC_HEADER_STDC @@ -370,7 +378,40 @@ dnl Checks for library functions. AC_FUNC_ALLOCA AC_CHECK_FUNCS(gethostname mkdir mktime socket strstr strchr \ uname flock lockf inet_aton inet_addr \ - fchmod truncate getuid regcomp mlock) + fchmod truncate ftruncate getuid regcomp mlock) + +dnl Finish locking decision + +dnl Turn off unavailable methods +if test x"$ac_cv_have_flock" = xno; then + ac_cv_enable_flock=no +fi +if test x"$ac_cv_have_fcntl" = xno; then + ac_cv_enable_fcntl=no +fi + +dnl If no --enable-... is given, prefer flock to fcntl +dnl (compatible with the previous behavior) +if test x"$ac_cv_enable_flock" = xmaybe; then + ac_cv_enable_flock=yes +fi +if test x"$ac_cv_enable_fcntl" = xmaybe; then + if test x"$ac_cv_enable_flock" = xno; then + ac_cv_enable_fcntl=yes + else + ac_cv_enable_fcntl=no + fi +fi + +dnl Define the macros +if test x"$ac_cv_enable_flock" = xyes; then + AC_DEFINE(LOCK_WITH_FLOCK, 1, + [Define to use the flock function for mailbox locking]) +fi +if test x"$ac_cv_enable_fcntl" = xyes; then + AC_DEFINE(LOCK_WITH_FCNTL, 1, + [Define to use the fcntl function for mailbox locking]) +fi AC_OUTPUT([ Makefile @@ -403,6 +444,8 @@ echo "OpenSSL : $ac_cv_enable_ssl" echo "iconv : $am_cv_func_iconv" echo "compface : $ac_cv_enable_compface" echo "IPv6 : $ac_cv_enable_ipv6" +echo "flock locking : $ac_cv_enable_flock" +echo "fcntl locking : $ac_cv_enable_fcntl" echo "GtkSpell : $ac_cv_enable_gtkspell" echo "" echo "The binary will be installed in $prefix/bin" --- sylpheed/libsylph/mbox.h.alt-mboxlock 2005-09-13 12:18:44 +0400 +++ sylpheed/libsylph/mbox.h 2006-05-27 22:56:39 +0400 @@ -21,6 +21,7 @@ #define __MBOX_H__ #include +#include #include "folder.h" @@ -29,19 +30,21 @@ typedef enum { LOCK_FLOCK } LockType; -gint proc_mbox (FolderItem *dest, - const gchar *mbox, - GHashTable *folder_table); -gint lock_mbox (const gchar *base, - LockType type); -gint unlock_mbox (const gchar *base, - gint fd, - LockType type); -gint copy_mbox (const gchar *src, - const gchar *dest); -void empty_mbox (const gchar *mbox); +gint proc_mbox (FolderItem *dest, + const gchar *mbox, + GHashTable *folder_table); +FILE * open_and_lock_mbox (const gchar *base, + LockType type); +gint unlock_and_close_mbox (const gchar *base, + FILE *fp, + LockType type); +gint copy_mbox (const gchar *src, + FILE *src_fp, + const gchar *dest); +void empty_mbox (const gchar *mbox, + FILE *mbox_fp); -gint export_to_mbox (FolderItem *src, - const gchar *mbox); +gint export_to_mbox (FolderItem *src, + const gchar *mbox); #endif /* __MBOX_H__ */ --- sylpheed/libsylph/utils.h.alt-mboxlock 2006-03-27 12:19:53 +0400 +++ sylpheed/libsylph/utils.h 2006-05-27 23:03:14 +0400 @@ -407,6 +407,10 @@ gint remove_expired_files (const gchar * gint remove_dir_recursive (const gchar *dir); gint rename_force (const gchar *oldpath, const gchar *newpath); +gint copy_open_file (const gchar *src, + FILE *src_fp, + const gchar *dest, + gboolean keep_backup); gint copy_file (const gchar *src, const gchar *dest, gboolean keep_backup); --- sylpheed/libsylph/mbox.c.alt-mboxlock 2005-11-14 13:00:00 +0300 +++ sylpheed/libsylph/mbox.c 2006-05-27 23:29:15 +0400 @@ -252,142 +252,206 @@ gint proc_mbox(FolderItem *dest, const g return msgs; } -gint lock_mbox(const gchar *base, LockType type) +static gint lock_dotlock(const gchar *base) { -#ifdef G_OS_UNIX - gint retval = 0; +#ifdef LOCK_WITH_DOTLOCK + gchar *lockfile, *locklink; + gint retry = 0; + FILE *lockfp; + + lockfile = g_strdup_printf("%s.%d", base, getpid()); + if ((lockfp = g_fopen(lockfile, "wb")) == NULL) { + FILE_OP_ERROR(lockfile, "fopen"); + g_warning(_("can't create lock file %s\n"), lockfile); + g_warning(_("use 'flock' instead of 'file' if possible.\n")); + g_free(lockfile); + return NULL; + } - if (type == LOCK_FILE) { - gchar *lockfile, *locklink; - gint retry = 0; - FILE *lockfp; - - lockfile = g_strdup_printf("%s.%d", base, getpid()); - if ((lockfp = g_fopen(lockfile, "wb")) == NULL) { - FILE_OP_ERROR(lockfile, "fopen"); - g_warning(_("can't create lock file %s\n"), lockfile); - g_warning(_("use 'flock' instead of 'file' if possible.\n")); + fprintf(lockfp, "%d\n", getpid()); + fclose(lockfp); + + locklink = g_strconcat(base, ".lock", NULL); + while (link(lockfile, locklink) < 0) { + FILE_OP_ERROR(lockfile, "link"); + if (retry >= 5) { + g_warning(_("can't create %s\n"), lockfile); + g_unlink(lockfile); g_free(lockfile); return -1; } + if (retry == 0) + g_warning(_("mailbox is owned by another" + " process, waiting...\n")); + retry++; + sleep(5); + } + g_unlink(lockfile); + g_free(lockfile); +#endif /* LOCK_WITH_DOTLOCK */ - fprintf(lockfp, "%d\n", getpid()); - fclose(lockfp); + return 0; +} - locklink = g_strconcat(base, ".lock", NULL); - while (link(lockfile, locklink) < 0) { - FILE_OP_ERROR(lockfile, "link"); - if (retry >= 5) { - g_warning(_("can't create %s\n"), lockfile); - g_unlink(lockfile); - g_free(lockfile); - return -1; - } - if (retry == 0) - g_warning(_("mailbox is owned by another" - " process, waiting...\n")); - retry++; - sleep(5); - } - g_unlink(lockfile); +static gint unlock_dotlock(const gchar *base) +{ +#ifdef LOCK_WITH_DOTLOCK + gchar *lockfile; + + lockfile = g_strconcat(base, ".lock", NULL); + if (g_unlink(lockfile) < 0) { + FILE_OP_ERROR(lockfile, "unlink"); g_free(lockfile); - } else if (type == LOCK_FLOCK) { - gint lockfd; + return -1; + } + g_free(lockfile); +#endif /* LOCK_WITH_DOTLOCK */ -#if HAVE_FLOCK - if ((lockfd = open(base, O_RDONLY)) < 0) { -#else - if ((lockfd = open(base, O_RDWR)) < 0) { -#endif - FILE_OP_ERROR(base, "open"); + return 0; +} + +static gint lock_fcntl(const gchar *base, gint fd) +{ +#ifdef LOCK_WITH_FCNTL + struct flock lck; + + memset(&lck, 0, sizeof (struct flock)); + lck.l_type = F_WRLCK; + lck.l_whence = SEEK_SET; + + if (fcntl(fd, F_SETLK, &lck) == -1) { + if (errno != EAGAIN && errno != EACCES) { + FILE_OP_ERROR(base, "fcntl lock"); return -1; } -#if HAVE_FLOCK - if (flock(lockfd, LOCK_EX|LOCK_NB) < 0) { - perror("flock"); -#else -#if HAVE_LOCKF - if (lockf(lockfd, F_TLOCK, 0) < 0) { - perror("lockf"); -#else - { -#endif -#endif /* HAVE_FLOCK */ - g_warning(_("can't lock %s\n"), base); - if (close(lockfd) < 0) - perror("close"); + + g_warning(_("can't lock %s with fcntl\n"), base); + return -1; + } +#endif /* LOCK_WITH_FCNTL */ + + return 0; +} + +static gint unlock_fcntl(const gchar *base, gint fd) +{ +#ifdef LOCK_WITH_FCNTL + struct flock lck; + + memset(&lck, 0, sizeof (struct flock)); + lck.l_type = F_UNLCK; + lck.l_whence = SEEK_SET; + if (fcntl(fd, F_SETLK, &lck) == -1) { + FILE_OP_ERROR(base, "fcntl unlock"); + return -1; + } +#endif /* LOCK_WITH_FCNTL */ + + return 0; +} + +static gint lock_flock(const gchar *base, gint fd) +{ +#ifdef LOCK_WITH_FLOCK + if (flock(fd, LOCK_EX | LOCK_NB) == -1) + { + if (errno != EWOULDBLOCK) { + FILE_OP_ERROR(base, "flock lock"); return -1; } - retval = lockfd; - } else { - g_warning(_("invalid lock type\n")); + + g_warning(_("can't lock %s with flock\n"), base); return -1; } +#endif /* LOCK_WITH_FLOCK */ - return retval; -#else - return -1; -#endif /* G_OS_UNIX */ + return 0; } -gint unlock_mbox(const gchar *base, gint fd, LockType type) +static gint unlock_flock(const gchar *base, gint fd) { - if (type == LOCK_FILE) { - gchar *lockfile; +#ifdef LOCK_WITH_FLOCK + if (flock(fd, LOCK_UN) == -1) { + FILE_OP_ERROR(base, "flock unlock"); + return -1; + } +#endif /* LOCK_WITH_FLOCK */ - lockfile = g_strconcat(base, ".lock", NULL); - if (g_unlink(lockfile) < 0) { - FILE_OP_ERROR(lockfile, "unlink"); - g_free(lockfile); - return -1; + return 0; +} + +FILE *open_and_lock_mbox(const gchar *base, LockType type) +{ +#ifdef G_OS_UNIX + FILE *mbox_fp; + gint fd; + + mbox_fp = g_fopen(base, "rb+"); + if (mbox_fp == NULL) { + FILE_OP_ERROR(base, "fopen"); + return NULL; + } + fd = fileno(mbox_fp); + + if (lock_fcntl(base, fd) == -1) { + fclose(mbox_fp); + return NULL; + } + + if (lock_flock(base, fd) == -1) { + unlock_fcntl(base, fd); + fclose(mbox_fp); + return NULL; + } + + if (type == LOCK_FILE) { + if (lock_dotlock(base) == -1) { + unlock_flock(base, fd); + unlock_fcntl(base, fd); + fclose(mbox_fp); + return NULL; } - g_free(lockfile); + } - return 0; - } else if (type == LOCK_FLOCK) { -#if HAVE_FLOCK - if (flock(fd, LOCK_UN) < 0) { - perror("flock"); -#else -#if HAVE_LOCKF - if (lockf(fd, F_ULOCK, 0) < 0) { - perror("lockf"); + return mbox_fp; #else - { -#endif -#endif /* HAVE_FLOCK */ - g_warning(_("can't unlock %s\n"), base); - if (close(fd) < 0) - perror("close"); - return -1; - } + return NULL; +#endif /* G_OS_UNIX */ +} - if (close(fd) < 0) { - perror("close"); - return -1; - } +gint unlock_and_close_mbox(const gchar *base, FILE *mbox_fp, LockType type) +{ + gint fd = fileno(mbox_fp); - return 0; + unlock_fcntl(base, fd); + unlock_flock(base, fd); + if (type == LOCK_FILE) + unlock_dotlock(base); + + if (fclose(mbox_fp) == EOF) { + FILE_OP_ERROR(base, "fclose"); + return -1; } - g_warning(_("invalid lock type\n")); - return -1; + return 0; } -gint copy_mbox(const gchar *src, const gchar *dest) +gint copy_mbox(const gchar *src, FILE *src_fp, const gchar *dest) { - return copy_file(src, dest, TRUE); + return copy_open_file(src, src_fp, dest, TRUE); } -void empty_mbox(const gchar *mbox) +void empty_mbox(const gchar *mbox, FILE *mbox_fp) { -#if HAVE_TRUNCATE - if (truncate(mbox, 0) < 0) { +#if HAVE_FTRUNCATE + int fd = fileno(mbox_fp); + + if (ftruncate(fd, 0) < 0) { #endif FILE *fp; -#if HAVE_TRUNCATE - FILE_OP_ERROR(mbox, "truncate"); +#if HAVE_FTRUNCATE + FILE_OP_ERROR(mbox, "ftruncate"); #endif if ((fp = g_fopen(mbox, "wb")) == NULL) { FILE_OP_ERROR(mbox, "fopen"); @@ -395,7 +459,7 @@ void empty_mbox(const gchar *mbox) return; } fclose(fp); -#if HAVE_TRUNCATE +#if HAVE_FTRUNCATE } #endif } --- sylpheed/libsylph/utils.c.alt-mboxlock 2006-03-27 12:19:53 +0400 +++ sylpheed/libsylph/utils.c 2006-05-27 23:08:03 +0400 @@ -2423,23 +2423,19 @@ gint rename_force(const gchar *oldpath, return g_rename(oldpath, newpath); } -gint copy_file(const gchar *src, const gchar *dest, gboolean keep_backup) +gint copy_open_file(const gchar *src, FILE *src_fp, const gchar *dest, + gboolean keep_backup) { - FILE *src_fp, *dest_fp; + FILE *dest_fp; gint n_read; gchar buf[BUFSIZ]; gchar *dest_bak = NULL; gboolean err = FALSE; - if ((src_fp = g_fopen(src, "rb")) == NULL) { - FILE_OP_ERROR(src, "fopen"); - return -1; - } if (is_file_exist(dest)) { dest_bak = g_strconcat(dest, ".bak", NULL); if (rename_force(dest, dest_bak) < 0) { FILE_OP_ERROR(dest, "rename"); - fclose(src_fp); g_free(dest_bak); return -1; } @@ -2447,7 +2443,6 @@ gint copy_file(const gchar *src, const g if ((dest_fp = g_fopen(dest, "wb")) == NULL) { FILE_OP_ERROR(dest, "fopen"); - fclose(src_fp); if (dest_bak) { if (rename_force(dest_bak, dest) < 0) FILE_OP_ERROR(dest_bak, "rename"); @@ -2467,7 +2462,6 @@ gint copy_file(const gchar *src, const g if (fwrite(buf, n_read, 1, dest_fp) < 1) { g_warning(_("writing to %s failed.\n"), dest); fclose(dest_fp); - fclose(src_fp); g_unlink(dest); if (dest_bak) { if (rename_force(dest_bak, dest) < 0) @@ -2482,7 +2476,6 @@ gint copy_file(const gchar *src, const g FILE_OP_ERROR(src, "fread"); err = TRUE; } - fclose(src_fp); if (fclose(dest_fp) == EOF) { FILE_OP_ERROR(dest, "fclose"); err = TRUE; @@ -2506,6 +2499,20 @@ gint copy_file(const gchar *src, const g return 0; } +gint copy_file(const gchar *src, const gchar *dest, gboolean keep_backup) +{ + FILE *src_fp; + gint result; + + if ((src_fp = g_fopen(src, "rb")) == NULL) { + FILE_OP_ERROR(src, "fopen"); + return -1; + } + result = copy_open_file(src, src_fp, dest, keep_backup); + fclose(src_fp); + return result; +} + gint copy_dir(const gchar *src, const gchar *dest) { GDir *dir;