[ Ccing the fdm-users mailing list. Please reply to all addresses in ]
[ To: and Cc: in order to keep all involved parties and the debian ]
[ BTS in the loop. ]
A new bug report via the debian BTS, which includes a suggestion for a
fix.
The referenced bug #352589 can be found here:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=352589
Regards, Frank
Louis Opter <[email protected]>:
> 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:
--
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]