---
 lib/dpkg/Makefile.am        |  1 +
 lib/dpkg/db-fsys-common.c   | 87 +++++++++++++++++++++++++++++++++++++
 lib/dpkg/db-fsys-divert.c   | 43 ++++--------------
 lib/dpkg/db-fsys-override.c | 50 +++++----------------
 lib/dpkg/dpkg-db.h          | 13 ++++++
 5 files changed, 120 insertions(+), 74 deletions(-)
 create mode 100644 lib/dpkg/db-fsys-common.c

diff --git a/lib/dpkg/Makefile.am b/lib/dpkg/Makefile.am
index 9ef3a37f7..9ab402cf5 100644
--- a/lib/dpkg/Makefile.am
+++ b/lib/dpkg/Makefile.am
@@ -73,6 +73,7 @@ libdpkg_la_SOURCES = \
        db-ctrl-access.c \
        db-ctrl-format.c \
        db-ctrl-upgrade.c \
+       db-fsys-common.c \
        db-fsys-digest.c \
        db-fsys-divert.c \
        db-fsys-files.c \
diff --git a/lib/dpkg/db-fsys-common.c b/lib/dpkg/db-fsys-common.c
new file mode 100644
index 000000000..be106aff6
--- /dev/null
+++ b/lib/dpkg/db-fsys-common.c
@@ -0,0 +1,87 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * db-fsys-common.c - Common handling for admindb files
+ *
+ * Copyright © 2008-2012 Guillem Jover <guil...@debian.org>
+ * Copyright © 2022 Simon Richter <s...@debian.org>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <compat.h>
+
+#include "dpkg-db.h"
+#include "dpkg.h"
+#include "i18n.h"
+#include "debug.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <assert.h>
+
+FILE *dpkg_db_reopen(
+               struct dbinfo *info,
+               char const *filename,
+               bool *out_unchanged)
+{
+       struct stat sb_next;
+       FILE *file_next;
+
+       assert(info);
+       assert(filename);
+
+       onerr_abort++;
+
+       file_next = fopen(filename, "r");
+       if (!file_next) {
+               if (errno != ENOENT)
+                       ohshite(_("failed to open %s"), filename);
+       } else {
+               setcloexec(fileno(file_next), filename);
+
+               if (fstat(fileno(file_next), &sb_next))
+                       ohshite(_("failed to fstat %s"), filename);
+
+               /*
+                * We need to keep the database file open so that the
+                * filesystem cannot reuse the inode number (f.ex. during
+                * multiple dpkg-divert invocations in a maintainer script),
+                * otherwise the following check might turn true, and we
+                * would skip reloading a modified database.
+                */
+               if (info->file &&
+                   info->sb.st_dev == sb_next.st_dev &&
+                   info->sb.st_ino == sb_next.st_ino) {
+                       fclose(file_next);
+                       onerr_abort--;
+                       debug(dbg_general, "%s: %s is unchanged, skipping",
+                                       __func__, filename);
+                       if(out_unchanged)
+                               *out_unchanged = true;
+                       return NULL;
+               }
+               info->sb = sb_next;
+       }
+       if (info->file)
+               fclose(info->file);
+       info->file = file_next;
+
+       onerr_abort--;
+       if(out_unchanged)
+               *out_unchanged = false;
+       return file_next;
+}
diff --git a/lib/dpkg/db-fsys-divert.c b/lib/dpkg/db-fsys-divert.c
index e0054bb35..2198685ad 100644
--- a/lib/dpkg/db-fsys-divert.c
+++ b/lib/dpkg/db-fsys-divert.c
@@ -23,7 +23,6 @@
 #include <compat.h>
 
 #include <sys/types.h>
-#include <sys/stat.h>
 
 #include <errno.h>
 #include <string.h>
@@ -45,54 +44,28 @@ static char *diversionsname;
 void
 ensure_diversions(void)
 {
-       static struct stat sb_prev;
-       struct stat sb_next;
+       static struct dbinfo dbi;
+       bool unchanged;
        char linebuf[MAXDIVERTFILENAME];
-       static FILE *file_prev;
        FILE *file;
        struct fsys_diversion *ov, *oicontest, *oialtname;
 
        if (diversionsname == NULL)
                diversionsname = dpkg_db_get_path(DIVERSIONSFILE);
 
-       onerr_abort++;
+       file = dpkg_db_reopen(&dbi, diversionsname, &unchanged);
 
-       file = fopen(diversionsname, "r");
-       if (!file) {
-               if (errno != ENOENT)
-                       ohshite(_("failed to open diversions file"));
-       } else {
-               setcloexec(fileno(file), diversionsname);
-
-               if (fstat(fileno(file), &sb_next))
-                       ohshite(_("failed to fstat diversions file"));
-
-               /*
-                * We need to keep the database file open so that the
-                * filesystem cannot reuse the inode number (f.ex. during
-                * multiple dpkg-divert invocations in a maintainer script),
-                * otherwise the following check might turn true, and we
-                * would skip reloading a modified database.
-                */
-               if (file_prev &&
-                   sb_prev.st_dev == sb_next.st_dev &&
-                   sb_prev.st_ino == sb_next.st_ino) {
-                       fclose(file);
-                       onerr_abort--;
-                       debug(dbg_general, "%s: same, skipping", __func__);
-                       return;
-               }
-               sb_prev = sb_next;
-       }
-       if (file_prev)
-               fclose(file_prev);
-       file_prev = file;
+       if (unchanged)
+               return;
+
+       onerr_abort++;
 
        for (ov = diversions; ov; ov = ov->next) {
                ov->useinstead->divert->camefrom->divert = NULL;
                ov->useinstead->divert = NULL;
        }
        diversions = NULL;
+
        if (!file) {
                onerr_abort--;
                debug(dbg_general, "%s: none, resetting", __func__);
diff --git a/lib/dpkg/db-fsys-override.c b/lib/dpkg/db-fsys-override.c
index b74f6cbc2..b3163ec78 100644
--- a/lib/dpkg/db-fsys-override.c
+++ b/lib/dpkg/db-fsys-override.c
@@ -24,7 +24,6 @@
 #include <compat.h>
 
 #include <sys/types.h>
-#include <sys/stat.h>
 
 #include <errno.h>
 #include <string.h>
@@ -111,9 +110,8 @@ statdb_parse_mode(const char *str)
 void
 ensure_statoverrides(enum statdb_parse_flags flags)
 {
-       static struct stat sb_prev;
-       struct stat sb_next;
-       static FILE *file_prev;
+       static struct dbinfo dbi;
+       bool unchanged;
        FILE *file;
        char *loaded_list, *loaded_list_end, *thisline, *nextline, *ptr;
        struct file_stat *fso;
@@ -123,38 +121,12 @@ ensure_statoverrides(enum statdb_parse_flags flags)
        if (statoverridename == NULL)
                statoverridename = dpkg_db_get_path(STATOVERRIDEFILE);
 
-       onerr_abort++;
+       file = dpkg_db_reopen(&dbi, statoverridename, &unchanged);
 
-       file = fopen(statoverridename, "r");
-       if (!file) {
-               if (errno != ENOENT)
-                       ohshite(_("failed to open statoverride file"));
-       } else {
-               setcloexec(fileno(file), statoverridename);
-
-               if (fstat(fileno(file), &sb_next))
-                       ohshite(_("failed to fstat statoverride file"));
-
-               /*
-                * We need to keep the database file open so that the
-                * filesystem cannot reuse the inode number (f.ex. during
-                * multiple dpkg-statoverride invocations in a maintainer
-                * script), otherwise the following check might turn true,
-                * and we would skip reloading a modified database.
-                */
-               if (file_prev &&
-                   sb_prev.st_dev == sb_next.st_dev &&
-                   sb_prev.st_ino == sb_next.st_ino) {
-                       fclose(file);
-                       onerr_abort--;
-                       debug(dbg_general, "%s: same, skipping", __func__);
-                       return;
-               }
-               sb_prev = sb_next;
-       }
-       if (file_prev)
-               fclose(file_prev);
-       file_prev = file;
+       if (unchanged)
+               return;
+
+       onerr_abort++;
 
        /* Reset statoverride information. */
        iter = fsys_hash_iter_new();
@@ -171,15 +143,15 @@ ensure_statoverrides(enum statdb_parse_flags flags)
 
        /* If the statoverride list is empty we don't need to bother
         * reading it. */
-       if (!sb_next.st_size) {
+       if (!dbi.sb.st_size) {
                onerr_abort--;
                return;
        }
 
-       loaded_list = m_malloc(sb_next.st_size);
-       loaded_list_end = loaded_list + sb_next.st_size;
+       loaded_list = m_malloc(dbi.sb.st_size);
+       loaded_list_end = loaded_list + dbi.sb.st_size;
 
-       if (fd_read(fileno(file), loaded_list, sb_next.st_size) < 0)
+       if (fd_read(fileno(file), loaded_list, dbi.sb.st_size) < 0)
                ohshite(_("reading statoverride file '%.250s'"), 
statoverridename);
 
        thisline = loaded_list;
diff --git a/lib/dpkg/dpkg-db.h b/lib/dpkg/dpkg-db.h
index 61f220506..4d602cb00 100644
--- a/lib/dpkg/dpkg-db.h
+++ b/lib/dpkg/dpkg-db.h
@@ -24,6 +24,7 @@
 #define LIBDPKG_DPKG_DB_H
 
 #include <sys/types.h>
+#include <sys/stat.h>
 
 #include <stdbool.h>
 #include <stdio.h>
@@ -259,6 +260,18 @@ const char *dpkg_db_set_dir(const char *dir);
 const char *dpkg_db_get_dir(void);
 char *dpkg_db_get_path(const char *pathpart);
 
+/*** from db-fsys-common.c ***/
+
+struct dbinfo {
+  FILE *file;
+  struct stat sb;
+};
+
+FILE *dpkg_db_reopen(
+  struct dbinfo *info,
+  char const *filename,
+  bool *unchanged);
+
 #include <dpkg/atomic-file.h>
 
 /*** from dbmodify.c ***/
-- 
2.39.2

Reply via email to