Merge branch 'ls/git-open-cloexec'
authorJunio C Hamano <gitster@pobox.com>
Mon, 31 Oct 2016 20:15:21 +0000 (13:15 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 31 Oct 2016 20:15:21 +0000 (13:15 -0700)
Git generally does not explicitly close file descriptors that were
open in the parent process when spawning a child process, but most
of the time the child does not want to access them. As Windows does
not allow removing or renaming a file that has a file descriptor
open, a slow-to-exit child can even break the parent process by
holding onto them. Use O_CLOEXEC flag to open files in various
codepaths.

* ls/git-open-cloexec:
read-cache: make sure file handles are not inherited by child processes
sha1_file: open window into packfiles with O_CLOEXEC
sha1_file: rename git_open_noatime() to git_open()

1  2 
cache.h
sha1_file.c
diff --combined cache.h
index 1be6526d14fd66f2c854cdb01d0ef20d9151d6e1,a902ca1f8e4d63ebc2a4605b03ac4369eaaaa566..a50a61a19787de94daa9d66caa9fcccca58081fe
+++ b/cache.h
@@@ -409,7 -409,6 +409,7 @@@ static inline enum object_type object_t
  #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
  #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
  #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
 +#define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX"
  #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
  #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
  #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
  #define GIT_GLOB_PATHSPECS_ENVIRONMENT "GIT_GLOB_PATHSPECS"
  #define GIT_NOGLOB_PATHSPECS_ENVIRONMENT "GIT_NOGLOB_PATHSPECS"
  #define GIT_ICASE_PATHSPECS_ENVIRONMENT "GIT_ICASE_PATHSPECS"
 +#define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
  
  /*
   * This environment variable is expected to contain a boolean indicating
@@@ -477,7 -475,6 +477,7 @@@ extern int get_common_dir_noenv(struct 
  extern int get_common_dir(struct strbuf *sb, const char *gitdir);
  extern const char *get_git_namespace(void);
  extern const char *strip_namespace(const char *namespaced_ref);
 +extern const char *get_super_prefix(void);
  extern const char *get_git_work_tree(void);
  
  /*
@@@ -903,8 -900,8 +903,8 @@@ extern char *sha1_pack_index_name(cons
   * The result will be at least `len` characters long, and will be NUL
   * terminated.
   *
 - * The non-`_r` version returns a static buffer which will be overwritten by
 - * subsequent calls.
 + * The non-`_r` version returns a static buffer which remains valid until 4
 + * more calls to find_unique_abbrev are made.
   *
   * The `_r` variant writes to a buffer supplied by the caller, which must be at
   * least `GIT_SHA1_HEXSZ + 1` bytes. The return value is the number of bytes
@@@ -1125,7 -1122,7 +1125,7 @@@ extern int write_sha1_file(const void *
  extern int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type, unsigned char *sha1, unsigned flags);
  extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
  extern int force_object_loose(const unsigned char *sha1, time_t mtime);
- extern int git_open_noatime(const char *name);
+ extern int git_open(const char *name);
  extern void *map_sha1_file(const unsigned char *sha1, unsigned long *size);
  extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz);
  extern int parse_sha1_header(const char *hdr, unsigned long *sizep);
@@@ -1157,7 -1154,6 +1157,7 @@@ static inline int has_sha1_file(const u
  
  /* Same as the above, except for struct object_id. */
  extern int has_object_file(const struct object_id *oid);
 +extern int has_object_file_with_flags(const struct object_id *oid, int flags);
  
  /*
   * Return true iff an alternate object database has a loose object
@@@ -1190,9 -1186,6 +1190,9 @@@ static inline int hex2chr(const char *s
  #define MINIMUM_ABBREV minimum_abbrev
  #define DEFAULT_ABBREV default_abbrev
  
 +/* used when the code does not know or care what the default abbrev is */
 +#define FALLBACK_DEFAULT_ABBREV 7
 +
  struct object_context {
        unsigned char tree[20];
        char path[PATH_MAX];
@@@ -1493,12 -1486,6 +1493,12 @@@ extern void prepare_packed_git(void)
  extern void reprepare_packed_git(void);
  extern void install_packed_git(struct packed_git *pack);
  
 +/*
 + * Give a rough count of objects in the repository. This sacrifices accuracy
 + * for speed.
 + */
 +unsigned long approximate_object_count(void);
 +
  extern struct packed_git *find_sha1_pack(const unsigned char *sha1,
                                         struct packed_git *packs);
  
diff --combined sha1_file.c
index 1e41954a8480ab78366da6b302430ac090ee1aea,09045df1dcd8cf3dcda47ef6114ee68eb4c5f3be..5457314e6aaaf1a30d33f68c8e1005f8db584564
@@@ -370,7 -370,7 +370,7 @@@ void read_info_alternates(const char * 
        int fd;
  
        path = xstrfmt("%s/info/alternates", relative_base);
-       fd = git_open_noatime(path);
+       fd = git_open(path);
        free(path);
        if (fd < 0)
                return;
@@@ -663,7 -663,7 +663,7 @@@ static int check_packed_git_idx(const c
        struct pack_idx_header *hdr;
        size_t idx_size;
        uint32_t version, nr, i, *index;
-       int fd = git_open_noatime(path);
+       int fd = git_open(path);
        struct stat st;
  
        if (fd < 0)
@@@ -1069,7 -1069,7 +1069,7 @@@ static int open_packed_git_1(struct pac
        while (pack_max_fds <= pack_open_fds && close_one_pack())
                ; /* nothing */
  
-       p->pack_fd = git_open_noatime(p->pack_name);
+       p->pack_fd = git_open(p->pack_name);
        if (p->pack_fd < 0 || fstat(p->pack_fd, &st))
                return -1;
        pack_open_fds++;
@@@ -1410,32 -1410,6 +1410,32 @@@ static void prepare_packed_git_one(cha
        strbuf_release(&path);
  }
  
 +static int approximate_object_count_valid;
 +
 +/*
 + * Give a fast, rough count of the number of objects in the repository. This
 + * ignores loose objects completely. If you have a lot of them, then either
 + * you should repack because your performance will be awful, or they are
 + * all unreachable objects about to be pruned, in which case they're not really
 + * interesting as a measure of repo size in the first place.
 + */
 +unsigned long approximate_object_count(void)
 +{
 +      static unsigned long count;
 +      if (!approximate_object_count_valid) {
 +              struct packed_git *p;
 +
 +              prepare_packed_git();
 +              count = 0;
 +              for (p = packed_git; p; p = p->next) {
 +                      if (open_pack_index(p))
 +                              continue;
 +                      count += p->num_objects;
 +              }
 +      }
 +      return count;
 +}
 +
  static void *get_next_packed_git(const void *p)
  {
        return ((const struct packed_git *)p)->next;
@@@ -1507,7 -1481,6 +1507,7 @@@ void prepare_packed_git(void
  
  void reprepare_packed_git(void)
  {
 +      approximate_object_count_valid = 0;
        prepare_packed_git_run_once = 0;
        prepare_packed_git();
  }
@@@ -1586,9 -1559,9 +1586,9 @@@ int check_sha1_signature(const unsigne
        return hashcmp(sha1, real_sha1) ? -1 : 0;
  }
  
- int git_open_noatime(const char *name)
+ int git_open(const char *name)
  {
-       static int sha1_file_open_flag = O_NOATIME;
+       static int sha1_file_open_flag = O_NOATIME | O_CLOEXEC;
  
        for (;;) {
                int fd;
                if (fd >= 0)
                        return fd;
  
-               /* Might the failure be due to O_NOATIME? */
-               if (errno != ENOENT && sha1_file_open_flag) {
-                       sha1_file_open_flag = 0;
+               /* Try again w/o O_CLOEXEC: the kernel might not support it */
+               if ((sha1_file_open_flag & O_CLOEXEC) && errno == EINVAL) {
+                       sha1_file_open_flag &= ~O_CLOEXEC;
                        continue;
                }
  
+               /* Might the failure be due to O_NOATIME? */
+               if (errno != ENOENT && (sha1_file_open_flag & O_NOATIME)) {
+                       sha1_file_open_flag &= ~O_NOATIME;
+                       continue;
+               }
                return -1;
        }
  }
@@@ -1632,7 -1610,7 +1637,7 @@@ static int open_sha1_file(const unsigne
        struct alternate_object_database *alt;
        int most_interesting_errno;
  
-       fd = git_open_noatime(sha1_file_name(sha1));
+       fd = git_open(sha1_file_name(sha1));
        if (fd >= 0)
                return fd;
        most_interesting_errno = errno;
        prepare_alt_odb();
        for (alt = alt_odb_list; alt; alt = alt->next) {
                const char *path = alt_sha1_path(alt, sha1);
-               fd = git_open_noatime(path);
+               fd = git_open(path);
                if (fd >= 0)
                        return fd;
                if (most_interesting_errno == ENOENT)
@@@ -3362,11 -3340,6 +3367,11 @@@ int has_object_file(const struct object
        return has_sha1_file(oid->hash);
  }
  
 +int has_object_file_with_flags(const struct object_id *oid, int flags)
 +{
 +      return has_sha1_file_with_flags(oid->hash, flags);
 +}
 +
  static void check_tree(const void *buf, size_t size)
  {
        struct tree_desc desc;