Merge branch 'jc/reopen-lock-file'
authorJunio C Hamano <gitster@pobox.com>
Tue, 2 Sep 2014 20:20:12 +0000 (13:20 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 2 Sep 2014 20:20:13 +0000 (13:20 -0700)
There are cases where you lock and open to write a file, close it to
show the updated contents to external processes, and then have to
update the file again while still holding the lock, but the lockfile
API lacked support for such an access pattern.

* jc/reopen-lock-file:
lockfile: allow reopening a closed but still locked file

1  2 
cache.h
lockfile.c
diff --combined cache.h
index fcb511db70f7703f2b29dbc89dcf703065c823fe,b780794d6c7870146abd1ce2e28b71355c64a198..30268b6eed673dbec81bb3037bf3a0fe7679c52e
+++ b/cache.h
@@@ -7,7 -7,6 +7,7 @@@
  #include "advice.h"
  #include "gettext.h"
  #include "convert.h"
 +#include "trace.h"
  
  #include SHA1_HEADER
  #ifndef git_SHA_CTX
@@@ -75,21 -74,6 +75,21 @@@ unsigned long git_deflate_bound(git_zst
  #define S_IFGITLINK   0160000
  #define S_ISGITLINK(m)        (((m) & S_IFMT) == S_IFGITLINK)
  
 +/*
 + * Some mode bits are also used internally for computations.
 + *
 + * They *must* not overlap with any valid modes, and they *must* not be emitted
 + * to outside world - i.e. appear on disk or network. In other words, it's just
 + * temporary fields, which we internally use, but they have to stay in-house.
 + *
 + * ( such approach is valid, as standard S_IF* fits into 16 bits, and in Git
 + *   codebase mode is `unsigned int` which is assumed to be at least 32 bits )
 + */
 +
 +/* used internally in tree-diff */
 +#define S_DIFFTREE_IFXMIN_NEQ 0x80000000
 +
 +
  /*
   * Intensive research over the course of many years has shown that
   * port 9418 is totally unused by anything else. Or
@@@ -579,12 -563,11 +579,13 @@@ struct lock_file 
  #define LOCK_DIE_ON_ERROR 1
  #define LOCK_NODEREF 2
  extern int unable_to_lock_error(const char *path, int err);
 +extern void unable_to_lock_message(const char *path, int err,
 +                                 struct strbuf *buf);
  extern NORETURN void unable_to_lock_index_die(const char *path, int err);
  extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
  extern int hold_lock_file_for_append(struct lock_file *, const char *path, int);
  extern int commit_lock_file(struct lock_file *);
+ extern int reopen_lock_file(struct lock_file *);
  extern void update_index_if_able(struct index_state *, struct lock_file *);
  
  extern int hold_locked_index(struct lock_file *, int);
@@@ -639,7 -622,6 +640,7 @@@ extern int precomposed_unicode
   * that is subject to stripspace.
   */
  extern char comment_line_char;
 +extern int auto_comment_line_char;
  
  enum branch_track {
        BRANCH_TRACK_UNSPECIFIED = -1,
@@@ -847,6 -829,7 +848,6 @@@ int normalize_path_copy(char *dst, cons
  int longest_ancestor_length(const char *path, struct string_list *prefixes);
  char *strip_path_suffix(const char *path, const char *suffix);
  int daemon_avoid_alias(const char *path);
 -int offset_1st_component(const char *path);
  
  /* object replacement */
  #define LOOKUP_REPLACE_OBJECT 1
@@@ -998,7 -981,7 +999,7 @@@ extern int read_ref(const char *refname
   * NULL.  If more than MAXDEPTH recursive symbolic lookups are needed,
   * give up and return NULL.
   *
 - * errno is sometimes set on errors, but not always.
 + * errno is set to something meaningful on error.
   */
  extern const char *resolve_ref_unsafe(const char *ref, unsigned char *sha1, int reading, int *flag);
  extern char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag);
@@@ -1020,7 -1003,7 +1021,7 @@@ extern int validate_headref(const char 
  
  extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
  extern int df_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
 -extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
 +extern int name_compare(const char *name1, size_t len1, const char *name2, size_t len2);
  extern int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2);
  
  extern void *read_object_with_reference(const unsigned char *sha1,
@@@ -1082,13 -1065,6 +1083,13 @@@ struct ident_split 
   */
  extern int split_ident_line(struct ident_split *, const char *, int);
  
 +/*
 + * Like show_date, but pull the timestamp and tz parameters from
 + * the ident_split. It will also sanity-check the values and produce
 + * a well-known sentinel date if they appear bogus.
 + */
 +const char *show_ident_date(const struct ident_split *id, enum date_mode mode);
 +
  /*
   * Compare split idents for equality or strict ordering. Note that we
   * compare only the ident part of the line, ignoring any timestamp.
@@@ -1112,16 -1088,12 +1113,16 @@@ struct checkout 
  extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
  
  struct cache_def {
 -      char path[PATH_MAX + 1];
 -      int len;
 +      struct strbuf path;
        int flags;
        int track_flags;
        int prefix_len_stat_func;
  };
 +#define CACHE_DEF_INIT { STRBUF_INIT, 0, 0, 0 }
 +static inline void cache_def_clear(struct cache_def *cache)
 +{
 +      strbuf_release(&cache->path);
 +}
  
  extern int has_symlink_leading_path(const char *name, int len);
  extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
@@@ -1320,8 -1292,8 +1321,8 @@@ extern int check_repository_format_vers
  extern int git_env_bool(const char *, int);
  extern int git_config_system(void);
  extern int config_error_nonbool(const char *);
 -#if defined(__GNUC__) && ! defined(__clang__)
 -#define config_error_nonbool(s) (config_error_nonbool(s), -1)
 +#if defined(__GNUC__)
 +#define config_error_nonbool(s) (config_error_nonbool(s), const_error())
  #endif
  extern const char *get_log_output_encoding(void);
  extern const char *get_commit_output_encoding(void);
@@@ -1371,8 -1343,6 +1372,8 @@@ extern void fsync_or_die(int fd, const 
  
  extern ssize_t read_in_full(int fd, void *buf, size_t count);
  extern ssize_t write_in_full(int fd, const void *buf, size_t count);
 +extern ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset);
 +
  static inline ssize_t write_str_in_full(int fd, const char *str)
  {
        return write_in_full(fd, str, strlen(str));
@@@ -1402,9 -1372,18 +1403,9 @@@ extern void *alloc_commit_node(void)
  extern void *alloc_tag_node(void);
  extern void *alloc_object_node(void);
  extern void alloc_report(void);
 +extern unsigned int alloc_commit_index(void);
  
 -/* trace.c */
 -__attribute__((format (printf, 1, 2)))
 -extern void trace_printf(const char *format, ...);
 -__attribute__((format (printf, 2, 3)))
 -extern void trace_argv_printf(const char **argv, const char *format, ...);
 -extern void trace_repo_setup(const char *prefix);
 -extern int trace_want(const char *key);
 -__attribute__((format (printf, 2, 3)))
 -extern void trace_printf_key(const char *key, const char *fmt, ...);
 -extern void trace_strbuf(const char *key, const struct strbuf *buf);
 -
 +/* pkt-line.c */
  void packet_trace_identity(const char *prog);
  
  /* add */
diff --combined lockfile.c
index 2564a7f5447b904585f629f0d1233c8a59483a40,9c12ec5ca6da8af4384676cc7893d6eec57c9fcf..2a800cef33ed7fb1ba7d3499459eccd824ab33e4
@@@ -120,7 -120,7 +120,7 @@@ static char *resolve_symlink(char *p, s
        return p;
  }
  
 -
 +/* Make sure errno contains a meaningful value on error */
  static int lock_file(struct lock_file *lk, const char *path, int flags)
  {
        /*
         */
        static const size_t max_path_len = sizeof(lk->filename) - 5;
  
 -      if (strlen(path) >= max_path_len)
 +      if (strlen(path) >= max_path_len) {
 +              errno = ENAMETOOLONG;
                return -1;
 +      }
        strcpy(lk->filename, path);
        if (!(flags & LOCK_NODEREF))
                resolve_symlink(lk->filename, max_path_len);
                        lock_file_list = lk;
                        lk->on_list = 1;
                }
 -              if (adjust_shared_perm(lk->filename))
 -                      return error("cannot fix permission bits on %s",
 -                                   lk->filename);
 +              if (adjust_shared_perm(lk->filename)) {
 +                      int save_errno = errno;
 +                      error("cannot fix permission bits on %s",
 +                            lk->filename);
 +                      errno = save_errno;
 +                      return -1;
 +              }
        }
        else
                lk->filename[0] = 0;
        return lk->fd;
  }
  
 -static char *unable_to_lock_message(const char *path, int err)
 +void unable_to_lock_message(const char *path, int err, struct strbuf *buf)
  {
 -      struct strbuf buf = STRBUF_INIT;
 -
        if (err == EEXIST) {
 -              strbuf_addf(&buf, "Unable to create '%s.lock': %s.\n\n"
 +              strbuf_addf(buf, "Unable to create '%s.lock': %s.\n\n"
                    "If no other git process is currently running, this probably means a\n"
                    "git process crashed in this repository earlier. Make sure no other git\n"
                    "process is running and remove the file manually to continue.",
                            absolute_path(path), strerror(err));
        } else
 -              strbuf_addf(&buf, "Unable to create '%s.lock': %s",
 +              strbuf_addf(buf, "Unable to create '%s.lock': %s",
                            absolute_path(path), strerror(err));
 -      return strbuf_detach(&buf, NULL);
  }
  
  int unable_to_lock_error(const char *path, int err)
  {
 -      char *msg = unable_to_lock_message(path, err);
 -      error("%s", msg);
 -      free(msg);
 +      struct strbuf buf = STRBUF_INIT;
 +
 +      unable_to_lock_message(path, err, &buf);
 +      error("%s", buf.buf);
 +      strbuf_release(&buf);
        return -1;
  }
  
  NORETURN void unable_to_lock_index_die(const char *path, int err)
  {
 -      die("%s", unable_to_lock_message(path, err));
 +      struct strbuf buf = STRBUF_INIT;
 +
 +      unable_to_lock_message(path, err, &buf);
 +      die("%s", buf.buf);
  }
  
 +/* This should return a meaningful errno on failure */
  int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
  {
        int fd = lock_file(lk, path, flags);
@@@ -237,6 -228,16 +237,16 @@@ int close_lock_file(struct lock_file *l
        return close(fd);
  }
  
+ int reopen_lock_file(struct lock_file *lk)
+ {
+       if (0 <= lk->fd)
+               die(_("BUG: reopen a lockfile that is still open"));
+       if (!lk->filename[0])
+               die(_("BUG: reopen a lockfile that has been committed"));
+       lk->fd = open(lk->filename, O_WRONLY);
+       return lk->fd;
+ }
  int commit_lock_file(struct lock_file *lk)
  {
        char result_file[PATH_MAX];