Merge branch 'bw/mingw-avoid-inheriting-fd-to-lockfile' into maint
authorJunio C Hamano <gitster@pobox.com>
Fri, 9 Sep 2016 04:35:56 +0000 (21:35 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 9 Sep 2016 04:35:56 +0000 (21:35 -0700)
The tempfile (hence its user lockfile) API lets the caller to open
a file descriptor to a temporary file, write into it and then
finalize it by first closing the filehandle and then either
removing or renaming the temporary file. When the process spawns a
subprocess after obtaining the file descriptor, and if the
subprocess has not exited when the attempt to remove or rename is
made, the last step fails on Windows, because the subprocess has
the file descriptor still open. Open tempfile with O_CLOEXEC flag
to avoid this (on Windows, this is mapped to O_NOINHERIT).

* bw/mingw-avoid-inheriting-fd-to-lockfile:
mingw: ensure temporary file handles are not inherited by child processes
t6026-merge-attr: child processes must not inherit index.lock handles

compat/mingw.h
git-compat-util.h
lockfile.h
t/t6026-merge-attr.sh
tempfile.c
tempfile.h
index 2cadb816eebf305e84181379f48aec061ea158f7..034fff9479d03d2a2e3c7017a4fe4131461f0ec6 100644 (file)
@@ -67,6 +67,10 @@ typedef int pid_t;
 #define F_SETFD 2
 #define FD_CLOEXEC 0x1
 
+#if !defined O_CLOEXEC && defined O_NOINHERIT
+#define O_CLOEXEC      O_NOINHERIT
+#endif
+
 #ifndef EAFNOSUPPORT
 #define EAFNOSUPPORT WSAEAFNOSUPPORT
 #endif
index 1930444ef092f2b5834d12b73b4d2d0c050f3551..9eab471264ab6a22af3e5eb4a0a97f510de19a7e 100644 (file)
@@ -650,6 +650,10 @@ void *gitmemmem(const void *haystack, size_t haystacklen,
 #define getpagesize() sysconf(_SC_PAGESIZE)
 #endif
 
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
 #ifdef FREAD_READS_DIRECTORIES
 #ifdef fopen
 #undef fopen
index 3d301937b0a7e84ccfb03798be1be4047f0654cd..d26ad27b2b2df207872cb20ce9cc0299ee0aff8e 100644 (file)
  *   * calling `fdopen_lock_file()` to get a `FILE` pointer for the
  *     open file and writing to the file using stdio.
  *
+ *   Note that the file descriptor returned by hold_lock_file_for_update()
+ *   is marked O_CLOEXEC, so the new contents must be written by the
+ *   current process, not a spawned one.
+ *
  * When finished writing, the caller can:
  *
  * * Close the file descriptor and rename the lockfile to its final
index ef0cbceafe855cfb7b0ce4d1cb5050875d587253..dd8f88d18782f15e35aa3105668d9a713ba9fe3b 100755 (executable)
@@ -181,4 +181,17 @@ test_expect_success 'up-to-date merge without common ancestor' '
        )
 '
 
+test_expect_success 'custom merge does not lock index' '
+       git reset --hard anchor &&
+       write_script sleep-one-second.sh <<-\EOF &&
+               sleep 1 &
+       EOF
+
+       test_write_lines >.gitattributes \
+               "* merge=ours" "text merge=sleep-one-second" &&
+       test_config merge.ours.driver true &&
+       test_config merge.sleep-one-second.driver ./sleep-one-second.sh &&
+       git merge master
+'
+
 test_done
index 0af7ebf016745c4a114a12d207381342b29ccf4f..2990c92424832d288d5bbab2dfe79b5db361e0b0 100644 (file)
@@ -120,7 +120,12 @@ int create_tempfile(struct tempfile *tempfile, const char *path)
        prepare_tempfile_object(tempfile);
 
        strbuf_add_absolute_path(&tempfile->filename, path);
-       tempfile->fd = open(tempfile->filename.buf, O_RDWR | O_CREAT | O_EXCL, 0666);
+       tempfile->fd = open(tempfile->filename.buf,
+                           O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0666);
+       if (O_CLOEXEC && tempfile->fd < 0 && errno == EINVAL)
+               /* Try again w/o O_CLOEXEC: the kernel might not support it */
+               tempfile->fd = open(tempfile->filename.buf,
+                                   O_RDWR | O_CREAT | O_EXCL, 0666);
        if (tempfile->fd < 0) {
                strbuf_reset(&tempfile->filename);
                return -1;
index 4219fe41bd3e2ad16f0b1caf55eedca0b2d9986e..2f0038decd5b6d00b55fa03ec8988a3810d1784f 100644 (file)
  *   * calling `fdopen_tempfile()` to get a `FILE` pointer for the
  *     open file and writing to the file using stdio.
  *
+ *   Note that the file descriptor returned by create_tempfile()
+ *   is marked O_CLOEXEC, so the new contents must be written by
+ *   the current process, not any spawned one.
+ *
  * When finished writing, the caller can:
  *
  * * Close the file descriptor and remove the temporary file by