Merge branch 'jc/ignore-epipe-in-filter'
authorJunio C Hamano <gitster@pobox.com>
Fri, 22 May 2015 19:41:57 +0000 (12:41 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 22 May 2015 19:41:57 +0000 (12:41 -0700)
Filter scripts were run with SIGPIPE disabled on the Git side,
expecting that they may not read what Git feeds them to filter.
We however treated a filter that does not read its input fully
before exiting as an error.

This changes semantics, but arguably in a good way. If a filter
can produce its output without consuming its input using whatever
magic, we now let it do so, instead of diagnosing it as a
programming error.

* jc/ignore-epipe-in-filter:
filter_buffer_or_fd(): ignore EPIPE
copy.c: make copy_fd() report its status silently

1  2 
cache.h
lockfile.c
diff --combined cache.h
index c97d8071e14c1a9c41c39873450ca0d17565daa9,2981eec7f87dcc24dd0edf58005e164d843e059c..1f4226be1580e368b22d62a6e27aa55d37a4dbd7
+++ b/cache.h
@@@ -43,14 -43,6 +43,14 @@@ int git_deflate_end_gently(git_zstream 
  int git_deflate(git_zstream *, int flush);
  unsigned long git_deflate_bound(git_zstream *, unsigned long);
  
 +/* The length in bytes and in hex digits of an object name (SHA-1 value). */
 +#define GIT_SHA1_RAWSZ 20
 +#define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)
 +
 +struct object_id {
 +      unsigned char hash[GIT_SHA1_RAWSZ];
 +};
 +
  #if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
  #define DTYPE(de)     ((de)->d_type)
  #else
   *
   * The value 0160000 is not normally a valid mode, and
   * also just happens to be S_IFDIR + S_IFLNK
 - *
 - * NOTE! We *really* shouldn't depend on the S_IFxxx macros
 - * always having the same values everywhere. We should use
 - * our internal git values for these things, and then we can
 - * translate that to the OS-specific value. It just so
 - * happens that everybody shares the same bit representation
 - * in the UNIX world (and apparently wider too..)
   */
  #define S_IFGITLINK   0160000
  #define S_ISGITLINK(m)        (((m) & S_IFMT) == S_IFGITLINK)
@@@ -378,7 -377,6 +378,7 @@@ static inline enum object_type object_t
  
  /* Double-check local_repo_env below if you add to this list. */
  #define GIT_DIR_ENVIRONMENT "GIT_DIR"
 +#define GIT_COMMON_DIR_ENVIRONMENT "GIT_COMMON_DIR"
  #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
  #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
  #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
@@@ -432,13 -430,11 +432,13 @@@ extern int is_inside_git_dir(void)
  extern char *git_work_tree_cfg;
  extern int is_inside_work_tree(void);
  extern const char *get_git_dir(void);
 +extern const char *get_git_common_dir(void);
  extern int is_git_directory(const char *path);
  extern char *get_object_directory(void);
  extern char *get_index_file(void);
  extern char *get_graft_file(void);
  extern int set_git_dir(const char *path);
 +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_git_work_tree(void);
@@@ -579,7 -575,7 +579,7 @@@ extern void update_index_if_able(struc
  extern int hold_locked_index(struct lock_file *, int);
  extern void set_alternate_index_output(const char *);
  
 -extern int delete_ref(const char *, const unsigned char *sha1, int delopt);
 +extern int delete_ref(const char *, const unsigned char *sha1, unsigned int flags);
  
  /* Environment bits from configuration mechanism */
  extern int trust_executable_bit;
@@@ -623,15 -619,6 +623,15 @@@ extern int core_apply_sparse_checkout
  extern int precomposed_unicode;
  extern int protect_hfs;
  extern int protect_ntfs;
 +extern int git_db_env, git_index_env, git_graft_env, git_common_dir_env;
 +
 +/*
 + * Include broken refs in all ref iterations, which will
 + * generally choke dangerous operations rather than letting
 + * them silently proceed without taking the broken ref into
 + * account.
 + */
 +extern int ref_paranoia;
  
  /*
   * The character that begins a commented line in user-editable file
@@@ -694,19 -681,18 +694,19 @@@ extern int check_repository_format(void
  
  extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
        __attribute__((format (printf, 3, 4)));
 -extern char *git_snpath(char *buf, size_t n, const char *fmt, ...)
 -      __attribute__((format (printf, 3, 4)));
 +extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
 +      __attribute__((format (printf, 2, 3)));
  extern char *git_pathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
  extern char *mkpathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
  
  /* Return a statically allocated filename matching the sha1 signature */
 -extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 -extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 -extern char *git_path_submodule(const char *path, const char *fmt, ...)
 +extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 +extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 +extern const char *git_path_submodule(const char *path, const char *fmt, ...)
        __attribute__((format (printf, 2, 3)));
 +extern void report_linked_checkout_garbage(void);
  
  /*
   * Return the name of the file in the local object database that would
@@@ -731,13 -717,13 +731,13 @@@ extern char *sha1_pack_name(const unsig
  extern char *sha1_pack_index_name(const unsigned char *sha1);
  
  extern const char *find_unique_abbrev(const unsigned char *sha1, int);
 -extern const unsigned char null_sha1[20];
 +extern const unsigned char null_sha1[GIT_SHA1_RAWSZ];
  
  static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
  {
        int i;
  
 -      for (i = 0; i < 20; i++, sha1++, sha2++) {
 +      for (i = 0; i < GIT_SHA1_RAWSZ; i++, sha1++, sha2++) {
                if (*sha1 != *sha2)
                        return *sha1 - *sha2;
        }
        return 0;
  }
  
 +static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2)
 +{
 +      return hashcmp(oid1->hash, oid2->hash);
 +}
 +
  static inline int is_null_sha1(const unsigned char *sha1)
  {
        return !hashcmp(sha1, null_sha1);
  }
  
 +static inline int is_null_oid(const struct object_id *oid)
 +{
 +      return !hashcmp(oid->hash, null_sha1);
 +}
 +
  static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)
  {
 -      memcpy(sha_dst, sha_src, 20);
 +      memcpy(sha_dst, sha_src, GIT_SHA1_RAWSZ);
  }
 +
 +static inline void oidcpy(struct object_id *dst, const struct object_id *src)
 +{
 +      hashcpy(dst->hash, src->hash);
 +}
 +
  static inline void hashclr(unsigned char *hash)
  {
 -      memset(hash, 0, 20);
 +      memset(hash, 0, GIT_SHA1_RAWSZ);
  }
  
 +static inline void oidclr(struct object_id *oid)
 +{
 +      hashclr(oid->hash);
 +}
 +
 +
  #define EMPTY_TREE_SHA1_HEX \
        "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
  #define EMPTY_TREE_SHA1_BIN_LITERAL \
@@@ -851,6 -815,7 +851,6 @@@ enum scld_error safe_create_leading_dir
  enum scld_error safe_create_leading_directories_const(const char *path);
  
  int mkdir_in_gitdir(const char *path);
 -extern void home_config_paths(char **global, char **xdg, char *file);
  extern char *expand_user_path(const char *path);
  const char *enter_repo(const char *path, int strict);
  static inline int is_absolute_path(const char *path)
@@@ -870,16 -835,8 +870,16 @@@ char *strip_path_suffix(const char *pat
  int daemon_avoid_alias(const char *path);
  extern int is_ntfs_dotgit(const char *name);
  
 +/**
 + * Return a newly allocated string with the evaluation of
 + * "$XDG_CONFIG_HOME/git/$filename" if $XDG_CONFIG_HOME is non-empty, otherwise
 + * "$HOME/.config/git/$filename". Return NULL upon error.
 + */
 +extern char *xdg_config_home(const char *filename);
 +
  /* object replacement */
  #define LOOKUP_REPLACE_OBJECT 1
 +#define LOOKUP_UNKNOWN_OBJECT 2
  extern void *read_sha1_file_extended(const unsigned char *sha1, enum object_type *type, unsigned long *size, unsigned flag);
  static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
  {
@@@ -916,7 -873,6 +916,7 @@@ static inline const unsigned char *look
  extern int sha1_object_info(const unsigned char *, unsigned long *);
  extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
  extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
 +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);
@@@ -995,10 -951,8 +995,10 @@@ extern int for_each_abbrev(const char *
   * null-terminated string.
   */
  extern int get_sha1_hex(const char *hex, unsigned char *sha1);
 +extern int get_oid_hex(const char *hex, struct object_id *sha1);
  
  extern char *sha1_to_hex(const unsigned char *sha1);  /* static buffer result! */
 +extern char *oid_to_hex(const struct object_id *oid); /* same static buffer as sha1_to_hex */
  extern int read_ref_full(const char *refname, int resolve_flags,
                         unsigned char *sha1, int *flags);
  extern int read_ref(const char *refname, unsigned char *sha1);
@@@ -1219,7 -1173,6 +1219,7 @@@ extern struct packed_git 
        int pack_fd;
        unsigned pack_local:1,
                 pack_keep:1,
 +               freshened:1,
                 do_not_close:1;
        unsigned char sha1[20];
        /* something like ".git/objects/pack/xxxxx.pack" */
@@@ -1308,10 -1261,6 +1308,10 @@@ extern int unpack_object_header(struct 
   *
   * Any callback that is NULL will be ignored. Callbacks returning non-zero
   * will end the iteration.
 + *
 + * In the "buf" variant, "path" is a strbuf which will also be used as a
 + * scratch buffer, but restored to its original contents before
 + * the function returns.
   */
  typedef int each_loose_object_fn(const unsigned char *sha1,
                                 const char *path,
@@@ -1327,24 -1276,17 +1327,24 @@@ int for_each_loose_file_in_objdir(cons
                                  each_loose_cruft_fn cruft_cb,
                                  each_loose_subdir_fn subdir_cb,
                                  void *data);
 +int for_each_loose_file_in_objdir_buf(struct strbuf *path,
 +                                    each_loose_object_fn obj_cb,
 +                                    each_loose_cruft_fn cruft_cb,
 +                                    each_loose_subdir_fn subdir_cb,
 +                                    void *data);
  
  /*
   * Iterate over loose and packed objects in both the local
 - * repository and any alternates repositories.
 + * repository and any alternates repositories (unless the
 + * LOCAL_ONLY flag is set).
   */
 +#define FOR_EACH_OBJECT_LOCAL_ONLY 0x1
  typedef int each_packed_object_fn(const unsigned char *sha1,
                                  struct packed_git *pack,
                                  uint32_t pos,
                                  void *data);
 -extern int for_each_loose_object(each_loose_object_fn, void *);
 -extern int for_each_packed_object(each_packed_object_fn, void *);
 +extern int for_each_loose_object(each_loose_object_fn, void *, unsigned flags);
 +extern int for_each_packed_object(each_packed_object_fn, void *, unsigned flags);
  
  struct object_info {
        /* Request */
        unsigned long *sizep;
        unsigned long *disk_sizep;
        unsigned char *delta_base_sha1;
 +      struct strbuf *typename;
  
        /* Response */
        enum {
@@@ -1541,9 -1482,13 +1541,13 @@@ extern const char *git_mailmap_blob
  extern void maybe_flush_or_die(FILE *, const char *);
  __attribute__((format (printf, 2, 3)))
  extern void fprintf_or_die(FILE *, const char *fmt, ...);
+ #define COPY_READ_ERROR (-2)
+ #define COPY_WRITE_ERROR (-3)
  extern int copy_fd(int ifd, int ofd);
  extern int copy_file(const char *dst, const char *src, int mode);
  extern int copy_file_with_time(const char *dst, const char *src, int mode);
  extern void write_or_die(int fd, const void *buf, size_t count);
  extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
  extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
@@@ -1557,8 -1502,6 +1561,8 @@@ static inline ssize_t write_str_in_full
  {
        return write_in_full(fd, str, strlen(str));
  }
 +__attribute__((format (printf, 3, 4)))
 +extern int write_file(const char *path, int fatal, const char *fmt, ...);
  
  /* pager.c */
  extern void setup_pager(void);
@@@ -1566,7 -1509,7 +1570,7 @@@ extern const char *pager_program
  extern int pager_in_use(void);
  extern int pager_use_color;
  extern int term_columns(void);
 -extern int decimal_width(int);
 +extern int decimal_width(uintmax_t);
  extern int check_pager_config(const char *cmd);
  
  extern const char *editor_program;
@@@ -1628,6 -1571,7 +1632,6 @@@ extern int ws_blank_line(const char *li
  #define ws_tab_width(rule)     ((rule) & WS_TAB_WIDTH_MASK)
  
  /* ls-files */
 -int report_path_error(const char *ps_matched, const struct pathspec *pathspec, const char *prefix);
  void overlay_tree_on_cache(const char *tree_name, const char *prefix);
  
  char *alias_lookup(const char *alias);
diff --combined lockfile.c
index 30e65e9d22566ada51cffb36642e0a27ea4507dc,beba0ed48038f020e7992187dee1a09cfc9c2c9f..5a93bc7bc2425bf01e88f55024854225d6a78aca
@@@ -128,17 -128,9 +128,17 @@@ static int lock_file(struct lock_file *
                    path);
        }
  
 -      strbuf_add(&lk->filename, path, pathlen);
 -      if (!(flags & LOCK_NO_DEREF))
 -              resolve_symlink(&lk->filename);
 +      if (flags & LOCK_NO_DEREF) {
 +              strbuf_add_absolute_path(&lk->filename, path);
 +      } else {
 +              struct strbuf resolved_path = STRBUF_INIT;
 +
 +              strbuf_add(&resolved_path, path, pathlen);
 +              resolve_symlink(&resolved_path);
 +              strbuf_add_absolute_path(&lk->filename, resolved_path.buf);
 +              strbuf_release(&resolved_path);
 +      }
 +
        strbuf_addstr(&lk->filename, LOCK_SUFFIX);
        lk->fd = open(lk->filename.buf, O_RDWR | O_CREAT | O_EXCL, 0666);
        if (lk->fd < 0) {
        return lk->fd;
  }
  
 +static int sleep_microseconds(long us)
 +{
 +      struct timeval tv;
 +      tv.tv_sec = 0;
 +      tv.tv_usec = us;
 +      return select(0, NULL, NULL, NULL, &tv);
 +}
 +
 +/*
 + * Constants defining the gaps between attempts to lock a file. The
 + * first backoff period is approximately INITIAL_BACKOFF_MS
 + * milliseconds. The longest backoff period is approximately
 + * (BACKOFF_MAX_MULTIPLIER * INITIAL_BACKOFF_MS) milliseconds.
 + */
 +#define INITIAL_BACKOFF_MS 1L
 +#define BACKOFF_MAX_MULTIPLIER 1000
 +
 +/*
 + * Try locking path, retrying with quadratic backoff for at least
 + * timeout_ms milliseconds. If timeout_ms is 0, try locking the file
 + * exactly once. If timeout_ms is -1, try indefinitely.
 + */
 +static int lock_file_timeout(struct lock_file *lk, const char *path,
 +                           int flags, long timeout_ms)
 +{
 +      int n = 1;
 +      int multiplier = 1;
 +      long remaining_us = 0;
 +      static int random_initialized = 0;
 +
 +      if (timeout_ms == 0)
 +              return lock_file(lk, path, flags);
 +
 +      if (!random_initialized) {
 +              srandom((unsigned int)getpid());
 +              random_initialized = 1;
 +      }
 +
 +      if (timeout_ms > 0) {
 +              /* avoid overflow */
 +              if (timeout_ms <= LONG_MAX / 1000)
 +                      remaining_us = timeout_ms * 1000;
 +              else
 +                      remaining_us = LONG_MAX;
 +      }
 +
 +      while (1) {
 +              long backoff_ms, wait_us;
 +              int fd;
 +
 +              fd = lock_file(lk, path, flags);
 +
 +              if (fd >= 0)
 +                      return fd; /* success */
 +              else if (errno != EEXIST)
 +                      return -1; /* failure other than lock held */
 +              else if (timeout_ms > 0 && remaining_us <= 0)
 +                      return -1; /* failure due to timeout */
 +
 +              backoff_ms = multiplier * INITIAL_BACKOFF_MS;
 +              /* back off for between 0.75*backoff_ms and 1.25*backoff_ms */
 +              wait_us = (750 + random() % 500) * backoff_ms;
 +              sleep_microseconds(wait_us);
 +              remaining_us -= wait_us;
 +
 +              /* Recursion: (n+1)^2 = n^2 + 2n + 1 */
 +              multiplier += 2*n + 1;
 +              if (multiplier > BACKOFF_MAX_MULTIPLIER)
 +                      multiplier = BACKOFF_MAX_MULTIPLIER;
 +              else
 +                      n++;
 +      }
 +}
 +
  void unable_to_lock_message(const char *path, int err, struct strbuf *buf)
  {
        if (err == EEXIST) {
@@@ -253,10 -171,9 +253,10 @@@ NORETURN void unable_to_lock_die(const 
  }
  
  /* This should return a meaningful errno on failure */
 -int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
 +int hold_lock_file_for_update_timeout(struct lock_file *lk, const char *path,
 +                                    int flags, long timeout_ms)
  {
 -      int fd = lock_file(lk, path, flags);
 +      int fd = lock_file_timeout(lk, path, flags, timeout_ms);
        if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
                unable_to_lock_die(path, errno);
        return fd;
@@@ -289,7 -206,7 +289,7 @@@ int hold_lock_file_for_append(struct lo
                int save_errno = errno;
  
                if (flags & LOCK_DIE_ON_ERROR)
-                       exit(128);
+                       die("failed to prepare '%s' for appending", path);
                close(orig_fd);
                rollback_lock_file(lk);
                errno = save_errno;