]> git.ipfire.org Git - thirdparty/git.git/commitdiff
tempfile: add mks_tempfile_dt()
authorRené Scharfe <l.s.r@web.de>
Wed, 20 Apr 2022 20:26:09 +0000 (22:26 +0200)
committerJunio C Hamano <gitster@pobox.com>
Wed, 20 Apr 2022 23:17:33 +0000 (16:17 -0700)
Add a function to create a temporary file with a certain name in a
temporary directory created using mkdtemp(3).  Its result is more
sightly than the paths created by mks_tempfile_ts(), which include
a random prefix.  That's useful for files passed to a program that
displays their name, e.g. an external diff tool.

Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
tempfile.c
tempfile.h

index 94aa18f3f7db211482f8392a5ecc2a3da786fc18..2024c82691fe4a1a1c9b5c8ebd31d6c382fe8bfc 100644 (file)
 
 static VOLATILE_LIST_HEAD(tempfile_list);
 
+static void remove_template_directory(struct tempfile *tempfile,
+                                     int in_signal_handler)
+{
+       if (tempfile->directorylen > 0 &&
+           tempfile->directorylen < tempfile->filename.len &&
+           tempfile->filename.buf[tempfile->directorylen] == '/') {
+               strbuf_setlen(&tempfile->filename, tempfile->directorylen);
+               if (in_signal_handler)
+                       rmdir(tempfile->filename.buf);
+               else
+                       rmdir_or_warn(tempfile->filename.buf);
+       }
+}
+
 static void remove_tempfiles(int in_signal_handler)
 {
        pid_t me = getpid();
@@ -74,6 +88,7 @@ static void remove_tempfiles(int in_signal_handler)
                        unlink(p->filename.buf);
                else
                        unlink_or_warn(p->filename.buf);
+               remove_template_directory(p, in_signal_handler);
 
                p->active = 0;
        }
@@ -100,6 +115,7 @@ static struct tempfile *new_tempfile(void)
        tempfile->owner = 0;
        INIT_LIST_HEAD(&tempfile->list);
        strbuf_init(&tempfile->filename, 0);
+       tempfile->directorylen = 0;
        return tempfile;
 }
 
@@ -198,6 +214,52 @@ struct tempfile *mks_tempfile_tsm(const char *filename_template, int suffixlen,
        return tempfile;
 }
 
+struct tempfile *mks_tempfile_dt(const char *directory_template,
+                                const char *filename)
+{
+       struct tempfile *tempfile;
+       const char *tmpdir;
+       struct strbuf sb = STRBUF_INIT;
+       int fd;
+       size_t directorylen;
+
+       if (!ends_with(directory_template, "XXXXXX")) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       tmpdir = getenv("TMPDIR");
+       if (!tmpdir)
+               tmpdir = "/tmp";
+
+       strbuf_addf(&sb, "%s/%s", tmpdir, directory_template);
+       directorylen = sb.len;
+       if (!mkdtemp(sb.buf)) {
+               int orig_errno = errno;
+               strbuf_release(&sb);
+               errno = orig_errno;
+               return NULL;
+       }
+
+       strbuf_addf(&sb, "/%s", filename);
+       fd = open(sb.buf, O_CREAT | O_EXCL | O_RDWR, 0600);
+       if (fd < 0) {
+               int orig_errno = errno;
+               strbuf_setlen(&sb, directorylen);
+               rmdir(sb.buf);
+               strbuf_release(&sb);
+               errno = orig_errno;
+               return NULL;
+       }
+
+       tempfile = new_tempfile();
+       strbuf_swap(&tempfile->filename, &sb);
+       tempfile->directorylen = directorylen;
+       tempfile->fd = fd;
+       activate_tempfile(tempfile);
+       return tempfile;
+}
+
 struct tempfile *xmks_tempfile_m(const char *filename_template, int mode)
 {
        struct tempfile *tempfile;
@@ -316,6 +378,7 @@ void delete_tempfile(struct tempfile **tempfile_p)
 
        close_tempfile_gently(tempfile);
        unlink_or_warn(tempfile->filename.buf);
+       remove_template_directory(tempfile, 0);
        deactivate_tempfile(tempfile);
        *tempfile_p = NULL;
 }
index 4de3bc77d246ef5ceceabc42e64ae35a9960b26a..d7804a214abb60ee60496ef34a9fc8be110344ea 100644 (file)
@@ -82,6 +82,7 @@ struct tempfile {
        FILE *volatile fp;
        volatile pid_t owner;
        struct strbuf filename;
+       size_t directorylen;
 };
 
 /*
@@ -198,6 +199,18 @@ static inline struct tempfile *xmks_tempfile(const char *filename_template)
        return xmks_tempfile_m(filename_template, 0600);
 }
 
+/*
+ * Attempt to create a temporary directory in $TMPDIR and to create and
+ * open a file in that new directory. Derive the directory name from the
+ * template in the manner of mkdtemp(). Arrange for directory and file
+ * to be deleted if the program exits before they are deleted
+ * explicitly. On success return a tempfile whose "filename" member
+ * contains the full path of the file and its "fd" member is open for
+ * writing the file. On error return NULL and set errno appropriately.
+ */
+struct tempfile *mks_tempfile_dt(const char *directory_template,
+                                const char *filename);
+
 /*
  * Associate a stdio stream with the temporary file (which must still
  * be open). Return `NULL` (*without* deleting the file) on error. The