From aae48bc9f73a1bce726871027f73cbc0543c65d4 Mon Sep 17 00:00:00 2001 From: "Wang, Wenjie2" Date: Wed, 19 Mar 2025 01:54:08 +0000 Subject: [PATCH] depmod: add tmpfile-util to generate temporary file * we use `mkstemp` to create the temporary file since it's a general function in linux system and O_TMPFILE is not supported on all linux system. * add `struct tmpfile` to keep the `dirfd`, temp file `fd` and the filename. Co-developed-by: Wenjie Wang Signed-off-by: Wenjie Wang Co-developed-by: Gongjun Song Signed-off-by: Gongjun Song Signed-off-by: Dan He Signed-off-by: Qingqing Li Signed-off-by: Yuchi Chen Link: https://github.com/kmod-project/kmod/pull/305 Signed-off-by: Lucas De Marchi --- meson.build | 2 + shared/tmpfile-util.c | 85 +++++++++++++++++++++++++++++++++++++++++++ shared/tmpfile-util.h | 33 +++++++++++++++++ shared/util.c | 23 ++++++++++++ shared/util.h | 1 + tools/depmod.c | 40 +++++--------------- 6 files changed, 154 insertions(+), 30 deletions(-) create mode 100644 shared/tmpfile-util.c create mode 100644 shared/tmpfile-util.h diff --git a/meson.build b/meson.build index 8cfbf796..811c9d08 100644 --- a/meson.build +++ b/meson.build @@ -372,6 +372,8 @@ libshared = static_library( 'shared/strbuf.h', 'shared/util.c', 'shared/util.h', + 'shared/tmpfile-util.c', + 'shared/tmpfile-util.h', ), gnu_symbol_visibility : 'hidden', install : false, diff --git a/shared/tmpfile-util.c b/shared/tmpfile-util.c new file mode 100644 index 00000000..06d2c6c7 --- /dev/null +++ b/shared/tmpfile-util.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2025 Intel Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +FILE *tmpfile_openat(int dirfd, mode_t mode, struct tmpfile *file) +{ + const char *tmpname_tmpl = "tmpfileXXXXXX"; + const char *tmpname; + char tmpfile_path[PATH_MAX]; + int fd, n; + _cleanup_free_ char *targetdir; + FILE *fp; + + targetdir = fd_lookup_path(dirfd); + if (targetdir == NULL) + goto create_fail; + + n = snprintf(tmpfile_path, PATH_MAX, "%s/%s", targetdir, tmpname_tmpl); + if (n < 0 || n >= PATH_MAX) + goto create_fail; + + fd = mkstemp(tmpfile_path); + if (fd < 0) + goto create_fail; + + if (fchmod(fd, mode) < 0) + goto checkout_fail; + + fp = fdopen(fd, "wb"); + if (fp == NULL) + goto checkout_fail; + + tmpname = basename(tmpfile_path); + memcpy(file->tmpname, tmpname, strlen(tmpname) + 1); + + file->dirfd = dirfd; + file->fd = fd; + + return fp; + +checkout_fail: + close(fd); + remove(tmpfile_path); + +create_fail: + return NULL; +} + +int tmpfile_publish(struct tmpfile *file, const char *targetname) +{ + if (renameat(file->dirfd, file->tmpname, file->dirfd, targetname) != 0) + return -errno; + + file->fd = -1; + file->dirfd = -1; + memset(file->tmpname, 0, PATH_MAX); + + return 0; +} + +void tmpfile_release(struct tmpfile *file) +{ + unlinkat(file->dirfd, file->tmpname, 0); + + file->fd = -1; + file->dirfd = -1; + file->tmpname[0] = '\0'; +} diff --git a/shared/tmpfile-util.h b/shared/tmpfile-util.h new file mode 100644 index 00000000..a3e23b17 --- /dev/null +++ b/shared/tmpfile-util.h @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2025 Intel Corporation. + */ + +#pragma once + +#include +#include + +#include + +struct tmpfile { + char tmpname[PATH_MAX]; + int dirfd; + int fd; +}; + +/* + * Create a temporary file at the directory of `dirfd` +*/ +_must_check_ _nonnull_(3) FILE *tmpfile_openat(int dirfd, mode_t mode, + struct tmpfile *file); + +/* + * Move the temporary file to `targetname` +*/ +_nonnull_all_ int tmpfile_publish(struct tmpfile *file, const char *targetname); + +/* + * Delete the temporary file +*/ +_nonnull_all_ void tmpfile_release(struct tmpfile *file); diff --git a/shared/util.c b/shared/util.c index 4e3e7b5d..b10122ce 100644 --- a/shared/util.c +++ b/shared/util.c @@ -476,6 +476,29 @@ int mkdir_parents(const char *path, mode_t mode) return mkdir_p(path, end - path, mode); } +char *fd_lookup_path(int fd) +{ + char proc_path[PATH_MAX]; + char fd_path[PATH_MAX]; + ssize_t len; + + len = snprintf(proc_path, sizeof(proc_path), "/proc/self/fd/%d", fd); + if (len < 0 || len >= (ssize_t)sizeof(proc_path)) + return NULL; + + /* + * We are using mkstemp to create a temporary file. We need to read the link since + * the mkstemp creates file with an absolute path + */ + len = readlink(proc_path, fd_path, sizeof(fd_path) - 1); + if (len < 0 || len >= (ssize_t)sizeof(fd_path)) + return NULL; + + fd_path[len] = '\0'; + + return strdup(fd_path); +} + static unsigned long long ts_usec(const struct timespec *ts) { return (unsigned long long)ts->tv_sec * USEC_PER_SEC + diff --git a/shared/util.h b/shared/util.h index c6af2e3a..c36d39e5 100644 --- a/shared/util.h +++ b/shared/util.h @@ -54,6 +54,7 @@ static inline _must_check_ _nonnull_all_ bool path_is_absolute(const char *p) int mkdir_p(const char *path, int len, mode_t mode); int mkdir_parents(const char *path, mode_t mode); unsigned long long stat_mstamp(const struct stat *st); +char *fd_lookup_path(int fd); /* time-related functions * ************************************************************************ */ diff --git a/tools/depmod.c b/tools/depmod.c index 3d3cd7bc..30622932 100644 --- a/tools/depmod.c +++ b/tools/depmod.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -2606,34 +2607,15 @@ static int depmod_output(struct depmod *depmod, FILE *out) for (itr = depfiles; itr->name != NULL; itr++) { FILE *fp = out; - char tmp[NAME_MAX] = ""; + struct tmpfile file; int r, ferr; if (fp == NULL) { - int flags = O_CREAT | O_EXCL | O_WRONLY; - int mode = 0644; - int fd; - int n; - - n = snprintf(tmp, sizeof(tmp), "%s.%i.%lli.%lli", itr->name, - getpid(), (long long)tv.tv_usec, - (long long)tv.tv_sec); - if (n >= (int)sizeof(tmp)) { - ERR("bad filename: %s.%i.%lli.%lli: path too long\n", - itr->name, getpid(), (long long)tv.tv_usec, - (long long)tv.tv_sec); - continue; - } - fd = openat(dfd, tmp, flags, mode); - if (fd < 0) { - ERR("openat(%s, %s, %o, %o): %m\n", dname, tmp, flags, - mode); - continue; - } - fp = fdopen(fd, "wb"); + mode_t mode = 0644; + + fp = tmpfile_openat(dfd, mode, &file); if (fp == NULL) { - ERR("fdopen(%d=%s/%s): %m\n", fd, dname, tmp); - close(fd); + ERR("Could not create temporary file at '%s'\n", dname); continue; } } @@ -2645,18 +2627,16 @@ static int depmod_output(struct depmod *depmod, FILE *out) ferr = ferror(fp) | fclose(fp); if (r < 0) { - if (unlinkat(dfd, tmp, 0) != 0) - ERR("unlinkat(%s, %s): %m\n", dname, tmp); + tmpfile_release(&file); ERR("Could not write index '%s': %s\n", itr->name, strerror(-r)); err = -errno; break; } - if (renameat(dfd, tmp, dfd, itr->name) != 0) { - err = -errno; - CRIT("renameat(%s, %s, %s, %s): %m\n", dname, tmp, dname, - itr->name); + err = tmpfile_publish(&file, itr->name); + if (err != 0) { + CRIT("publish temporary from %s to %s\n", file.tmpname, itr->name); break; } -- 2.47.2