summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2022-05-20 22:26:55 (GMT)
committerJunio C Hamano <gitster@pobox.com>2022-05-20 22:26:55 (GMT)
commit2e969751ec29bf948ce8ab3eef111d01b4293a42 (patch)
treefb583b77e158f25f310fdfb85f7e1e777fa88cc5
parent586f23705c639d08fc3c1f1489cdec57e18a1fe9 (diff)
parent8af759374ec174372b841d2f8bc24edcba385418 (diff)
downloadgit-2e969751ec29bf948ce8ab3eef111d01b4293a42.zip
git-2e969751ec29bf948ce8ab3eef111d01b4293a42.tar.gz
git-2e969751ec29bf948ce8ab3eef111d01b4293a42.tar.bz2
Merge branch 'rs/external-diff-tempfile'
The temporary files fed to external diff command are now generated inside a new temporary directory under the same basename. * rs/external-diff-tempfile: diff: use mks_tempfile_dt() tempfile: add mks_tempfile_dt()
-rw-r--r--diff.c8
-rwxr-xr-xt/t4020-diff-external.sh8
-rw-r--r--tempfile.c63
-rw-r--r--tempfile.h13
4 files changed, 81 insertions, 11 deletions
diff --git a/diff.c b/diff.c
index ef71599..e71cf75 100644
--- a/diff.c
+++ b/diff.c
@@ -4136,18 +4136,13 @@ static void prep_temp_blob(struct index_state *istate,
int mode)
{
struct strbuf buf = STRBUF_INIT;
- struct strbuf tempfile = STRBUF_INIT;
char *path_dup = xstrdup(path);
const char *base = basename(path_dup);
struct checkout_metadata meta;
init_checkout_metadata(&meta, NULL, NULL, oid);
- /* Generate "XXXXXX_basename.ext" */
- strbuf_addstr(&tempfile, "XXXXXX_");
- strbuf_addstr(&tempfile, base);
-
- temp->tempfile = mks_tempfile_ts(tempfile.buf, strlen(base) + 1);
+ temp->tempfile = mks_tempfile_dt("git-blob-XXXXXX", base);
if (!temp->tempfile)
die_errno("unable to create temp-file");
if (convert_to_working_tree(istate, path,
@@ -4162,7 +4157,6 @@ static void prep_temp_blob(struct index_state *istate,
oid_to_hex_r(temp->hex, oid);
xsnprintf(temp->mode, sizeof(temp->mode), "%06o", mode);
strbuf_release(&buf);
- strbuf_release(&tempfile);
free(path_dup);
}
diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh
index 1219f8b..858a552 100755
--- a/t/t4020-diff-external.sh
+++ b/t/t4020-diff-external.sh
@@ -206,17 +206,17 @@ test_expect_success 'GIT_EXTERNAL_DIFF path counter/total' '
'
test_expect_success 'GIT_EXTERNAL_DIFF generates pretty paths' '
+ test_when_finished "git rm -f file.ext" &&
touch file.ext &&
git add file.ext &&
echo with extension > file.ext &&
cat >expect <<-EOF &&
- file.ext file $(git rev-parse --verify HEAD:file) 100644 file.ext $(test_oid zero) 100644
+ file.ext
EOF
GIT_EXTERNAL_DIFF=echo git diff file.ext >out &&
- cut -d" " -f1,3- <out >actual &&
- git update-index --force-remove file.ext &&
- rm file.ext
+ basename $(cut -d" " -f2 <out) >actual &&
+ test_cmp expect actual
'
echo "#!$SHELL_PATH" >fake-diff.sh
diff --git a/tempfile.c b/tempfile.c
index 94aa18f..2024c82 100644
--- a/tempfile.c
+++ b/tempfile.c
@@ -56,6 +56,20 @@
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;
}
diff --git a/tempfile.h b/tempfile.h
index 4de3bc7..d7804a2 100644
--- a/tempfile.h
+++ b/tempfile.h
@@ -82,6 +82,7 @@ struct tempfile {
FILE *volatile fp;
volatile pid_t owner;
struct strbuf filename;
+ size_t directorylen;
};
/*
@@ -199,6 +200,18 @@ static inline struct tempfile *xmks_tempfile(const char *filename_template)
}
/*
+ * 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
* stream is closed automatically when `close_tempfile_gently()` is called or