Guillem Jover wrote: > This is misleading on Linux, but it's not a safe portable assumption > to make on POSIX in general as that behaviour is not specified and as > such is implementation specific, some Unix systems do actually fail > on read-only file descriptors, for example: > > > <http://publib.boulder.ibm.com/infocenter/aix/v6r1/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/fsync.htm>
Right. Actually, there's another bug lurking here: files marked as hard links in the tarfile get installed before the corresponding fsync(), with corresponding risk of 0-length files and so on. How about this? Untested. --- debian/changelog | 10 ++++++++++ src/archives.c | 37 ++++++++++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/debian/changelog b/debian/changelog index 20c296d5..44dfc9d7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -186,6 +186,16 @@ dpkg (1.16.1~jrn) local; urgency=low * Add new --raw-extract option to dpkg-deb combining --control and --extract. Closes: #552123 + [ Jonathan Nieder ] + * Defer installing hard links with their final name until the file has + been fsynced. This avoids a small window in which the content of the + file is undefined. + * Skip fsync if a file being installed cannot be opened for writing and + errno is ETXTBSY, under the assumption that another link must have been + fsynced renamed into place already. For example, this happens when + upgrading the /usr/bin/perl hard link. Regression introduced in + 1.15.6.1. Closes: #635683 + [ Updated dpkg translations ] * German (Sven Joachim). Closes: #620312 * Swedish (Peter Krefting). diff --git a/src/archives.c b/src/archives.c index f060e706..88821c60 100644 --- a/src/archives.c +++ b/src/archives.c @@ -851,7 +851,8 @@ tarobject(void *ctx, struct tar_entry *ti) * in .dpkg-new. */ - if (ti->type == tar_filetype_file || ti->type == tar_filetype_symlink) { + if (ti->type == tar_filetype_file || ti->type == tar_filetype_symlink || + ti->type == tar_filetype_hardlink) { nifd->namenode->flags |= fnnf_deferred_rename; debug(dbg_eachfiledetail, "tarobject done and installation deferred"); @@ -938,12 +939,34 @@ tar_deferred_extract(struct fileinlist *files, struct pkginfo *pkg) debug(dbg_eachfiledetail, "deferred extract needs fsync"); fd = open(fnamenewvb.buf, O_WRONLY); - if (fd < 0) - ohshite(_("unable to open '%.255s'"), fnamenewvb.buf); - if (fsync(fd)) - ohshite(_("unable to sync file '%.255s'"), fnamenewvb.buf); - if (close(fd)) - ohshite(_("error closing/writing `%.255s'"), fnamenewvb.buf); + if (fd < 0 && errno == ETXTBSY) { + /* + * The file wasn't renamed yet. Why would someone map its + * text so early? + * + * Most likely, this is a second hard link to a binary + * that already _was_ renamed into place. For example, by + * the time we prepare to rename /usr/bin/perl5.x.dpkg-new, + * the other link /usr/bin/perl can be in use. Luckily, + * that means the file was already synchronized to disk + * before renaming the first link and it is safe to skip + * the fsync this time around. + * + * The other possibility is that someone executed the + * .dpkg-new file directly. The file will not be + * synchronized, but that's ok --- no need to error out. + */ + + debug(dbg_eachfiledetail, + "deferred extract skipping fsync (text is busy)"); + } else { + if (fd < 0) + ohshite(_("unable to open '%.255s'"), fnamenewvb.buf); + if (fsync(fd)) + ohshite(_("unable to sync file '%.255s'"), fnamenewvb.buf); + if (close(fd)) + ohshite(_("error closing/writing `%.255s'"), fnamenewvb.buf); + } cfile->namenode->flags &= ~fnnf_deferred_fsync; } -- 1.7.6 -- To UNSUBSCRIBE, email to debian-dpkg-bugs-requ...@lists.debian.org with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org