The following commit has been merged in the master branch:
commit 20fdb395cc721a5060c5623eda956d73ea840a21
Author: Guillem Jover <[email protected]>
Date: Thu Mar 11 21:35:25 2010 +0100
Do an fsync on database directories
After creating, renaming or unlinking database files sync its
containing directory, to guarantee the new file entry is correctly
listed in the directory.
Closes: #567089
Base-on-patch-by: Jean-Baptiste Lallement <[email protected]>
diff --git a/debian/changelog b/debian/changelog
index 8bd229f..8c72c5a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -167,6 +167,10 @@ dpkg (1.15.6) UNRELEASED; urgency=low
guarantees when doing rename(2). Based on a patch by
Jean-Baptiste Lallement <[email protected]>.
Closes: #430958
+ * Call fsync(2) on database directories after creating, renaming or
+ unlinking files, to guarantee the new file entry is correctly listed
+ in the directory. Base on a patch by
+ Jean-Baptiste Lallement <[email protected]>.
* Document in the man page the effects of setting TMPDIR for dpkg and
dpkg-deb, HOME for dselect and dpkg and PAGER for dpkg. Closes: #572836
* Document the exit codes for dpkg-query. Closes: #571798
diff --git a/dpkg-split/queue.c b/dpkg-split/queue.c
index dae30c4..e8c02a6 100644
--- a/dpkg-split/queue.c
+++ b/dpkg-split/queue.c
@@ -44,6 +44,7 @@
#include <dpkg/i18n.h>
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
+#include <dpkg/dir.h>
#include <dpkg/myopt.h>
#include "dpkg-split.h"
@@ -180,6 +181,7 @@ void do_auto(const char *const *argv) {
printf("%s%d", !ap++ ? "" : i == (unsigned int)j ? _(" and ") : ", ",
i + 1);
printf(").\n");
+ dir_sync_path(depotdir);
} else {
/* We have all the parts. */
diff --git a/lib/dpkg/Makefile.am b/lib/dpkg/Makefile.am
index e9b54ba..69c7e70 100644
--- a/lib/dpkg/Makefile.am
+++ b/lib/dpkg/Makefile.am
@@ -29,6 +29,7 @@ libdpkg_a_SOURCES = \
compress.c \
database.c \
dbmodify.c \
+ dir.c \
dump.c \
ehandle.c \
file.c \
@@ -63,6 +64,7 @@ pkginclude_HEADERS = \
buffer.h \
command.h \
compress.h \
+ dir.h \
dpkg.h \
dpkg-db.h \
file.h \
diff --git a/lib/dpkg/dbmodify.c b/lib/dpkg/dbmodify.c
index 25860d6..6af9804 100644
--- a/lib/dpkg/dbmodify.c
+++ b/lib/dpkg/dbmodify.c
@@ -42,6 +42,7 @@
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
#include <dpkg/file.h>
+#include <dpkg/dir.h>
char *statusfile=NULL, *availablefile=NULL;
@@ -98,6 +99,8 @@ static void cleanupdates(void) {
ohshite(_("failed to remove incorporated update file
%.255s"),updatefnbuf);
free(cdlist[i]);
}
+
+ dir_sync_path(updatesdir);
}
}
@@ -248,6 +251,9 @@ void modstatdb_checkpoint(void) {
if (unlink(updatefnbuf))
ohshite(_("failed to remove my own update file %.255s"),updatefnbuf);
}
+
+ dir_sync_path(updatesdir);
+
nextupdate= 0;
}
@@ -297,6 +303,8 @@ modstatdb_note_core(struct pkginfo *pkg)
if (rename(importanttmpfile, updatefnbuf))
ohshite(_("unable to install updated status of `%.250s'"), pkg->name);
+ dir_sync_path(updatesdir);
+
/* Have we made a real mess? */
assert(strlen(updatefnrest) <= IMPORTANTMAXLEN);
diff --git a/lib/dpkg/dir.c b/lib/dpkg/dir.c
new file mode 100644
index 0000000..bcfdd61
--- /dev/null
+++ b/lib/dpkg/dir.c
@@ -0,0 +1,124 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * dir.c - directory handling functions
+ *
+ * Copyright © 2010 Guillem Jover <[email protected]>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <compat.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <dpkg/dpkg.h>
+#include <dpkg/i18n.h>
+#include <dpkg/varbuf.h>
+#include <dpkg/dir.h>
+
+void
+dir_sync(DIR *dir, const char *path)
+{
+ int fd;
+
+ fd = dirfd(dir);
+ if (fd < 0)
+ ohshite(_("unable to get file descriptor for directory '%s'"),
+ path);
+
+ if (fsync(fd))
+ ohshite(_("unable to sync directory '%s'"), path);
+}
+
+void
+dir_sync_path(const char *path)
+{
+ DIR *dir;
+
+ dir = opendir(path);
+ if (!dir)
+ ohshite(_("unable to open directory '%s'"), path);
+
+ dir_sync(dir, path);
+
+ closedir(dir);
+}
+
+void
+dir_sync_path_parent(const char *path)
+{
+ char *dirname, *slash;
+
+ dirname = m_strdup(path);
+
+ slash = strrchr(dirname, '/');
+ if (slash != NULL) {
+ *slash = '\0';
+ dir_sync_path(dirname);
+ }
+
+ free(dirname);
+}
+
+/* FIXME: Ideally we'd use openat() here, to avoid the path mangling, but
+ * it's not widely available yet, so this will do for now. */
+static void
+dir_file_sync(const char *dir, const char *filename)
+{
+ struct varbuf path = VARBUF_INIT;
+ int fd;
+
+ varbufprintf(&path, "%s/%s", dir, filename);
+
+ fd = open(path.buf, O_WRONLY);
+ if (fd < 0)
+ ohshite(_("unable to open file '%s'"), path.buf);
+ if (fsync(fd))
+ ohshite(_("unable to sync file '%s'"), path.buf);
+ if (close(fd))
+ ohshite(_("unable to close file '%s'"), path.buf);
+
+ varbuf_destroy(&path);
+}
+
+void
+dir_sync_contents(const char *path)
+{
+ DIR *dir;
+ struct dirent *dent;
+
+ dir = opendir(path);
+ if (!dir)
+ ohshite(_("unable to open directory '%s'"), path);
+
+ while ((dent = readdir(dir)) != NULL) {
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+
+ dir_file_sync(path, dent->d_name);
+ }
+
+ dir_sync(dir, path);
+
+ closedir(dir);
+}
diff --git a/lib/dpkg/ar.h b/lib/dpkg/dir.h
similarity index 73%
copy from lib/dpkg/ar.h
copy to lib/dpkg/dir.h
index 367ac72..560abf8 100644
--- a/lib/dpkg/ar.h
+++ b/lib/dpkg/dir.h
@@ -1,6 +1,6 @@
/*
* libdpkg - Debian packaging suite library routines
- * ar.c - primitives for ar handling
+ * dir.h - directory handling routines
*
* Copyright © 2010 Guillem Jover <[email protected]>
*
@@ -18,17 +18,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef LIBDPKG_AR_H
-#define LIBDPKG_AR_H
-
-#include <ar.h>
+#ifndef LIBDPKG_DIR_H
+#define LIBDPKG_DIR_H
#include <dpkg/macros.h>
+#include <dirent.h>
+
DPKG_BEGIN_DECLS
-void dpkg_ar_normalize_name(struct ar_hdr *arh);
+void dir_sync(DIR *dir, const char *path);
+void dir_sync_path(const char *path);
+void dir_sync_path_parent(const char *path);
+void dir_sync_contents(const char *path);
DPKG_END_DECLS
-#endif /* LIBDPKG_AR_H */
+#endif /* LIBDPKG_DIR_H */
diff --git a/lib/dpkg/dump.c b/lib/dpkg/dump.c
index eeddc69..6c63354 100644
--- a/lib/dpkg/dump.c
+++ b/lib/dpkg/dump.c
@@ -37,6 +37,7 @@
#include <dpkg/i18n.h>
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
+#include <dpkg/dir.h>
#include <dpkg/parsedump.h>
void w_name(struct varbuf *vb,
@@ -409,6 +410,10 @@ void writedb(const char *filename, int available, int
mustsync) {
if (rename(newfn,filename))
ohshite(_("failed to install '%.250s' as '%.250s' containing %s database"),
newfn, filename, which);
+
+ if (mustsync)
+ dir_sync_path_parent(filename);
+
free(newfn);
free(oldfn);
}
diff --git a/lib/dpkg/trigdeferred.l b/lib/dpkg/trigdeferred.l
index 0b53e1a..ee7d6d3 100644
--- a/lib/dpkg/trigdeferred.l
+++ b/lib/dpkg/trigdeferred.l
@@ -44,6 +44,7 @@
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
#include <dpkg/file.h>
+#include <dpkg/dir.h>
#define YY_NO_INPUT
@@ -216,6 +217,8 @@ trigdef_process_done(void)
if (rename(newfn.buf, fn.buf))
ohshite(_("unable to install new triggers deferred "
"file `%.250s'"), fn.buf);
+
+ dir_sync_path(triggersdir);
}
/* Unlock. */
diff --git a/lib/dpkg/triglib.c b/lib/dpkg/triglib.c
index 6fc49d5..5ce9a8d 100644
--- a/lib/dpkg/triglib.c
+++ b/lib/dpkg/triglib.c
@@ -35,6 +35,7 @@
#include <dpkg/dpkg-db.h>
#include <dpkg/pkg-list.h>
#include <dpkg/dlist.h>
+#include <dpkg/dir.h>
const char *
illegal_triggername(const char *p)
@@ -435,6 +436,8 @@ trk_explicit_interest_change(const char *trig, struct
pkginfo *pkg, int signum)
if (rename(newfn.buf, trk_explicit_fn.buf))
ohshite(_("unable to install new trigger interest file
`%.250s'"),
trk_explicit_fn.buf);
+
+ dir_sync_path(triggersdir);
}
static const struct trigkindinfo tki_explicit = {
@@ -544,6 +547,8 @@ trig_file_interests_save(void)
ohshite(_("unable to install new file triggers file as
`%.250s'"),
triggersfilefile);
+ dir_sync_path(triggersdir);
+
filetriggers_edited = 0;
}
diff --git a/src/filesdb.c b/src/filesdb.c
index 3d214e1..ce03fda 100644
--- a/src/filesdb.c
+++ b/src/filesdb.c
@@ -43,6 +43,7 @@
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
#include <dpkg/path.h>
+#include <dpkg/dir.h>
#include <dpkg/buffer.h>
#include <dpkg/pkg-array.h>
#include <dpkg/progress.h>
@@ -436,6 +437,8 @@ void write_filelist_except(struct pkginfo *pkg, struct
fileinlist *list, int lea
if (rename(newvb.buf,vb.buf))
ohshite(_("failed to install updated files list file for package
%s"),pkg->name);
+ dir_sync_path(pkgadmindir());
+
note_must_reread_files_inpackage(pkg);
}
diff --git a/src/processarc.c b/src/processarc.c
index 62011ba..627bbd2 100644
--- a/src/processarc.c
+++ b/src/processarc.c
@@ -43,6 +43,7 @@
#include <dpkg/path.h>
#include <dpkg/buffer.h>
#include <dpkg/subproc.h>
+#include <dpkg/dir.h>
#include <dpkg/tarfn.h>
#include <dpkg/myopt.h>
@@ -220,6 +221,14 @@ void process_archive(const char *filename) {
ohshite(_("failed to exec dpkg-deb to extract control information"));
}
subproc_wait_check(c1, BACKEND " --control", 0);
+
+ /* We want to guarantee the extracted files are on the disk, so that the
+ * subsequent renames to the info database do not end up with old or zero
+ * length files in case of a system crash. As neither dpkg-deb nor tar do
+ * explicit fsync()s, we have to do them here.
+ * XXX: This could be avoided by switching to an internal tar extractor. */
+ dir_sync_contents(cidir);
+
strcpy(cidirrest,CONTROLFILE);
parsedb(cidir, pdb_recordavailable | pdb_rejectstatus | pdb_ignorefiles,
@@ -887,6 +896,10 @@ void process_archive(const char *filename) {
debug(dbg_scripts,"process_archive tmp.ci script/file `%s' installed as
`%s'",
cidir, newinfofilename);
}
+
+ /* Sync the info database directory. */
+ dir_sync(dsd, cidir);
+
pop_cleanup(ehflag_normaltidy); /* closedir */
/* Update the status database.
@@ -1085,6 +1098,10 @@ void process_archive(const char *filename) {
ohshite(_("unable to delete disappearing control info file
`%.250s'"),fnvb.buf);
debug(dbg_scripts, "process_archive info unlinked %s",fnvb.buf);
}
+
+ /* Sync the info database directory. */
+ dir_sync(dsd, fnvb.buf);
+
pop_cleanup(ehflag_normaltidy); /* closedir */
otherpkg->status= stat_notinstalled;
diff --git a/src/remove.c b/src/remove.c
index 9c8c36b..e68395f 100644
--- a/src/remove.c
+++ b/src/remove.c
@@ -37,6 +37,7 @@
#include <dpkg/i18n.h>
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
+#include <dpkg/dir.h>
#include <dpkg/myopt.h>
#include "filesdb.h"
@@ -293,6 +294,10 @@ static void removal_bulk_remove_files(
ohshite(_("unable to delete control info file `%.250s'"),fnvb.buf);
debug(dbg_scripts, "removal_bulk info unlinked %s",fnvb.buf);
}
+
+ /* Sync the info database directory. */
+ dir_sync(dsd, fnvb.buf);
+
pop_cleanup(ehflag_normaltidy); /* closedir */
pkg->status= stat_configfiles;
diff --git a/src/statcmd.c b/src/statcmd.c
index 6f24c18..15c9024 100644
--- a/src/statcmd.c
+++ b/src/statcmd.c
@@ -41,6 +41,7 @@
#include <dpkg/dpkg.h>
#include <dpkg/dpkg-db.h>
#include <dpkg/path.h>
+#include <dpkg/dir.h>
#include <dpkg/myopt.h>
#include "main.h"
@@ -243,6 +244,8 @@ statdb_write(void)
if (rename(dbname_new.buf, dbname.buf))
ohshite(_("error installing new statoverride"));
+ dir_sync_path(admindir);
+
varbuf_destroy(&dbname);
varbuf_destroy(&dbname_new);
varbuf_destroy(&dbname_old);
--
dpkg's main repository
--
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]