]> git.ipfire.org Git - thirdparty/kmod.git/commitdiff
depmod: add tmpfile-util to generate temporary file
authorWang, Wenjie2 <wenjie2.wang@intel.com>
Wed, 19 Mar 2025 01:54:08 +0000 (01:54 +0000)
committerLucas De Marchi <lucas.de.marchi@gmail.com>
Thu, 3 Apr 2025 04:23:28 +0000 (23:23 -0500)
* 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 <wenjie2.wang@intel.com>
Signed-off-by: Wenjie Wang <wenjie2.wang@intel.com>
Co-developed-by: Gongjun Song <gongjun.song@intel.com>
Signed-off-by: Gongjun Song <gongjun.song@intel.com>
Signed-off-by: Dan He <dan.h.he@intel.com>
Signed-off-by: Qingqing Li <qingqing.li@intel.com>
Signed-off-by: Yuchi Chen <yuchi.chen@intel.com>
Link: https://github.com/kmod-project/kmod/pull/305
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
meson.build
shared/tmpfile-util.c [new file with mode: 0644]
shared/tmpfile-util.h [new file with mode: 0644]
shared/util.c
shared/util.h
tools/depmod.c

index 8cfbf796dd430eaa2e5c472b97f043e11609d3bb..811c9d0840c14b9d8c5ee71941103f2b63075f08 100644 (file)
@@ -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 (file)
index 0000000..06d2c6c
--- /dev/null
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * Copyright (C) 2025  Intel Corporation.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <shared/macro.h>
+#include <shared/missing.h>
+#include <shared/tmpfile-util.h>
+#include <shared/util.h>
+
+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 (file)
index 0000000..a3e23b1
--- /dev/null
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * Copyright (C) 2025  Intel Corporation.
+ */
+
+#pragma once
+
+#include <stdio.h>
+#include <linux/limits.h>
+
+#include <shared/macro.h>
+
+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);
index 4e3e7b5d3bc4e19de958636cf4eae070e770e31d..b10122ce06e3cd4806274fe88f370d324e3ee53c 100644 (file)
@@ -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 +
index c6af2e3a361cd5db9fd674617a1037ef42595299..c36d39e5392608491901786857c04991df628734 100644 (file)
@@ -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
  * ************************************************************************ */
index 3d3cd7bcd219db5a73e7dad1b5b5d2c1a0c83d39..30622932f0452530b79ef5665953d8eb8dc86097 100644 (file)
@@ -24,6 +24,7 @@
 #include <shared/hash.h>
 #include <shared/macro.h>
 #include <shared/strbuf.h>
+#include <shared/tmpfile-util.h>
 #include <shared/util.h>
 
 #include <libkmod/libkmod-internal.h>
@@ -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;
                }