diff options
author | Junio C Hamano <gitster@pobox.com> | 2022-05-20 22:26:55 (GMT) |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2022-05-20 22:26:55 (GMT) |
commit | 2e969751ec29bf948ce8ab3eef111d01b4293a42 (patch) | |
tree | fb583b77e158f25f310fdfb85f7e1e777fa88cc5 | |
parent | 586f23705c639d08fc3c1f1489cdec57e18a1fe9 (diff) | |
parent | 8af759374ec174372b841d2f8bc24edcba385418 (diff) | |
download | git-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.c | 8 | ||||
-rwxr-xr-x | t/t4020-diff-external.sh | 8 | ||||
-rw-r--r-- | tempfile.c | 63 | ||||
-rw-r--r-- | tempfile.h | 13 |
4 files changed, 81 insertions, 11 deletions
@@ -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 @@ -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; } @@ -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 |