--- 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