Package: fdm
Version: 1.5-3
Severity: important
Tags: patch

Dear maintainer,

link() fails with EXDEV when you try to link files accross file systems.

On the AFS file system, this also occurs between directories :
http://docs.openafs.org/AdminGuide/ch02.html#HDRWQ32

This special case breaks fdm when using maildirs on OpenAFS.

I suggest a patch which workaround EXDEV by using stat() and rename().

I haven't run fdm's regressions tests on it. I have just checked it on
AFS and ext3.

A similar issue has been fixed in openssh (see #352589).

The same bug certainly exists in other parts of fdm.

Here is the code :

--- fdm-1.5.orig/deliver-maildir.c      2008-03-06 10:25:32.000000000 +0100
+++ fdm-1.5-3.debian.louis/deliver-maildir.c    2009-07-23 21:28:34.418851829 
+0200
@@ -146,6 +146,7 @@
        char                             src[MAXPATHLEN], dst[MAXPATHLEN];
        int                              fd;
        ssize_t                          n;
+       struct stat                      sb;
 
        name = NULL;
        fd = -1;
@@ -195,28 +196,52 @@
        fd = -1;
 
        /*
-        * Create the new path and attempt to link it. A failed link jumps
-        * back to find another name in the tmp directory.
+        * Create the new path and attempt to link it. A failed link on EEXIST
+        * jumps back to find another name in the tmp directory.
         */
        if (ppath(dst, sizeof dst, "%s/new/%s", path, name) != 0)
                goto error_unlink;
        log_debug2(
            "%s: linking .../tmp/%s to .../new/%s", a->name, name, name);
        if (link(src, dst) != 0) {
-               if (errno == EEXIST) {
-                       log_debug2("%s: %s: link failed", a->name, src);
+               log_debug2("%s: %s: link failed", a->name, src);
+               /*
+                * EXDEV must also be handled, especially for the AFS filesystem
+                * where hardlinks can't traverse directories :
+                * http://docs.openafs.org/AdminGuide/ch02.html#HDRWQ32
+                */
+               if (errno == EXDEV) {
+                       log_debug2("%s: renaming .../tmp/%s to .../new/%s",
+                               a->name, name, name);
+                       /*
+                        * But stat + rename can be racy.
+                        */
+                       if (stat(dst, &sb) == -1) {
+                               if (errno != ENOENT || rename(src, dst) != 0) {
+                                       log_debug2("%s: %s: rename failed",
+                                               a->name, src);
+                                       goto error_cleanup;
+                               }
+                       } else { /* EEXIST */
+                               if (unlink(src) != 0)
+                                       fatal("unlink failed");
+                               cleanup_deregister(src);
+                               goto restart;
+                       }
+               } else if (errno == EEXIST) {
                        if (unlink(src) != 0)
                                fatal("unlink failed");
                        cleanup_deregister(src);
                        goto restart;
-               }
-               goto error_unlink;
+               } else /* Dot it only if we are not on EXDEV */
+                       goto error_unlink;
+       } else {
+               /* Unlink the original tmp file. */
+               log_debug2("%s: unlinking .../tmp/%s", a->name, name);
+               if (unlink(src) != 0)
+                       goto error_unlink;
        }
 
-       /* Unlink the original tmp file. */
-       log_debug2("%s: unlinking .../tmp/%s", a->name, name);
-       if (unlink(src) != 0)
-               goto error_unlink;
        cleanup_deregister(src);
 
        /* Save the mail file as a tag. */
@@ -229,6 +254,7 @@
 error_unlink:
        if (unlink(src) != 0)
                fatal("unlink failed");
+error_cleanup:
        cleanup_deregister(src);
 
 error_log:

Please, tell me any suggestion.

Best regards, Louis Opter.

-- System Information:
Debian Release: 5.0.2
  APT prefers stable
  APT policy: (500, 'stable')
Architecture: amd64 (x86_64)

Kernel: Linux 2.6.26-2-amd64 (SMP w/2 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash

Versions of packages fdm depends on:
ii  adduser              3.110               add and remove users and groups
ii  libc6                2.7-18              GNU C Library: Shared libraries
ii  libpcre3             7.6-2.1             Perl 5 Compatible Regular Expressi
ii  libssl0.9.8          0.9.8g-15+lenny1    SSL shared libraries
ii  libtdb1              1.1.2~git20080615-1 Trivial Database - shared library
ii  zlib1g               1:1.2.3.3.dfsg-12   compression library - runtime

fdm recommends no packages.

fdm suggests no packages.

-- no debconf information



-- 
To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org

Reply via email to