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 [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]