Merge branch 'lt/config-fsync'
authorJunio C Hamano <gitster@pobox.com>
Wed, 25 Jun 2008 20:19:49 +0000 (13:19 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 25 Jun 2008 20:19:49 +0000 (13:19 -0700)
* lt/config-fsync:
Add config option to enable 'fsync()' of object files
Split up default "i18n" and "branch" config parsing into helper routines
Split up default "user" config parsing into helper routine
Split up default "core" config parsing into helper routine

1  2 
Documentation/config.txt
cache.h
config.c
environment.c
sha1_file.c
diff --combined Documentation/config.txt
index 1e09a57c8c5aeb5d49367a4c96f32ebafe07d410,2466ecfc6b2be075e88c1b1a48e814c726e228f5..90c8a45a2f8dc70e61b32d5e3e10d7054c67e3ad
@@@ -372,6 -372,14 +372,14 @@@ core.whitespace:
    does not trigger if the character before such a carriage-return
    is not a whitespace (not enabled by default).
  
+ core.fsyncobjectfiles::
+       This boolean will enable 'fsync()' when writing object files.
+ +
+ This is a total waste of time and effort on a filesystem that orders
+ data writes properly, but can be useful for filesystems that do not use
+ journalling (traditional UNIX filesystems) or that only journal metadata
+ and not file contents (OS X's HFS+, or Linux ext3 with "data=writeback").
  alias.*::
        Command aliases for the linkgit:git[1] command wrapper - e.g.
        after defining "alias.last = cat-file commit HEAD", the invocation
@@@ -1013,25 -1021,6 +1021,25 @@@ status.relativePaths:
        relative to the repository root (this was the default for git
        prior to v1.5.4).
  
 +status.showUntrackedFiles::
 +      By default, linkgit:git-status[1] and linkgit:git-commit[1] show
 +      files which are not currently tracked by Git. Directories which
 +      contain only untracked files, are shown with the directory name
 +      only. Showing untracked files means that Git needs to lstat() all
 +      all the files in the whole repository, which might be slow on some
 +      systems. So, this variable controls how the commands displays
 +      the untracked files. Possible values are:
 ++
 +--
 +      - 'no'     - Show no untracked files
 +      - 'normal' - Shows untracked files and directories
 +      - 'all'    - Shows also individual files in untracked directories.
 +--
 ++
 +If this variable is not specified, it defaults to 'normal'.
 +This variable can be overridden with the -u|--untracked-files option
 +of linkgit:git-status[1] and linkgit:git-commit[1].
 +
  tar.umask::
        This variable can be used to restrict the permission bits of
        tar archive entries.  The default is 0002, which turns off the
diff --combined cache.h
index c8954ef15f28e83e4029481b1cb3cd793f7f3d58,01c8502afb3afe19b59ea2dad8cf64e154aa3612..64ef86e129337fde851d701a30e70cb84b54ecb3
+++ b/cache.h
@@@ -311,6 -311,7 +311,6 @@@ extern char *git_work_tree_cfg
  extern int is_inside_work_tree(void);
  extern const char *get_git_dir(void);
  extern char *get_object_directory(void);
 -extern char *get_refs_directory(void);
  extern char *get_index_file(void);
  extern char *get_graft_file(void);
  extern int set_git_dir(const char *path);
@@@ -434,6 -435,7 +434,7 @@@ extern size_t packed_git_window_size
  extern size_t packed_git_limit;
  extern size_t delta_base_cache_limit;
  extern int auto_crlf;
+ extern int fsync_object_files;
  
  enum safe_crlf {
        SAFE_CRLF_FALSE = 0,
@@@ -517,7 -519,6 +518,7 @@@ enum sharedrepo 
  int git_config_perm(const char *var, const char *value);
  int adjust_shared_perm(const char *path);
  int safe_create_leading_directories(char *path);
 +int safe_create_leading_directories_const(const char *path);
  char *enter_repo(char *path, int strict);
  static inline int is_absolute_path(const char *path)
  {
  }
  const char *make_absolute_path(const char *path);
  const char *make_nonrelative_path(const char *path);
 +const char *make_relative_path(const char *abs, const char *base);
  
  /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
  extern int sha1_object_info(const unsigned char *, unsigned long *);
@@@ -642,8 -642,6 +643,8 @@@ extern struct packed_git 
        const void *index_data;
        size_t index_size;
        uint32_t num_objects;
 +      uint32_t num_bad_objects;
 +      unsigned char *bad_object_sha1;
        int index_version;
        time_t mtime;
        int pack_fd;
@@@ -712,7 -710,6 +713,7 @@@ extern void close_pack_windows(struct p
  extern void unuse_pack(struct pack_window **);
  extern struct packed_git *add_packed_git(const char *, int, int);
  extern const unsigned char *nth_packed_object_sha1(struct packed_git *, uint32_t);
 +extern off_t nth_packed_object_offset(const struct packed_git *, uint32_t);
  extern off_t find_pack_entry_one(const unsigned char *, struct packed_git *);
  extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsigned long *);
  extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
@@@ -739,6 -736,7 +740,6 @@@ extern int git_config_set_multivar(cons
  extern int git_config_rename_section(const char *, const char *);
  extern const char *git_etc_gitconfig(void);
  extern int check_repository_format_version(const char *var, const char *value, void *cb);
 -extern int git_env_bool(const char *, int);
  extern int git_config_system(void);
  extern int git_config_global(void);
  extern int config_error_nonbool(const char *);
diff --combined config.c
index 04d97e3d0b3a202868d3a8645710cc387f14443f,b2d5b4e4e35b467147ddb9374ef13d0523b4b58d..58749bf41627e3a18b4808f92f5317528e85599f
+++ b/config.c
@@@ -332,7 -332,7 +332,7 @@@ int git_config_string(const char **dest
        return 0;
  }
  
int git_default_config(const char *var, const char *value, void *dummy)
static int git_default_core_config(const char *var, const char *value)
  {
        /* This needs a better name */
        if (!strcmp(var, "core.filemode")) {
                return 0;
        }
  
+       if (!strcmp(var, "core.pager"))
+               return git_config_string(&pager_program, var, value);
+       if (!strcmp(var, "core.editor"))
+               return git_config_string(&editor_program, var, value);
+       if (!strcmp(var, "core.excludesfile"))
+               return git_config_string(&excludes_file, var, value);
+       if (!strcmp(var, "core.whitespace")) {
+               if (!value)
+                       return config_error_nonbool(var);
+               whitespace_rule_cfg = parse_whitespace_rule(value);
+               return 0;
+       }
+       if (!strcmp(var, "core.fsyncobjectfiles")) {
+               fsync_object_files = git_config_bool(var, value);
+               return 0;
+       }
+       /* Add other config variables here and to Documentation/config.txt. */
+       return 0;
+ }
+ static int git_default_user_config(const char *var, const char *value)
+ {
        if (!strcmp(var, "user.name")) {
                if (!value)
                        return config_error_nonbool(var);
                return 0;
        }
  
+       /* Add other config variables here and to Documentation/config.txt. */
+       return 0;
+ }
+ static int git_default_i18n_config(const char *var, const char *value)
+ {
        if (!strcmp(var, "i18n.commitencoding"))
                return git_config_string(&git_commit_encoding, var, value);
  
        if (!strcmp(var, "i18n.logoutputencoding"))
                return git_config_string(&git_log_output_encoding, var, value);
  
-       if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
-               pager_use_color = git_config_bool(var,value);
-               return 0;
-       }
-       if (!strcmp(var, "core.pager"))
-               return git_config_string(&pager_program, var, value);
-       if (!strcmp(var, "core.editor"))
-               return git_config_string(&editor_program, var, value);
-       if (!strcmp(var, "core.excludesfile"))
-               return git_config_string(&excludes_file, var, value);
+       /* Add other config variables here and to Documentation/config.txt. */
+       return 0;
+ }
  
-       if (!strcmp(var, "core.whitespace")) {
-               if (!value)
-                       return config_error_nonbool(var);
-               whitespace_rule_cfg = parse_whitespace_rule(value);
-               return 0;
-       }
+ static int git_default_branch_config(const char *var, const char *value)
+ {
        if (!strcmp(var, "branch.autosetupmerge")) {
                if (value && !strcasecmp(value, "always")) {
                        git_branch_track = BRANCH_TRACK_ALWAYS;
        return 0;
  }
  
+ int git_default_config(const char *var, const char *value, void *dummy)
+ {
+       if (!prefixcmp(var, "core."))
+               return git_default_core_config(var, value);
+       if (!prefixcmp(var, "user."))
+               return git_default_user_config(var, value);
+       if (!prefixcmp(var, "i18n."))
+               return git_default_i18n_config(var, value);
+       if (!prefixcmp(var, "branch."))
+               return git_default_branch_config(var, value);
+       if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
+               pager_use_color = git_config_bool(var,value);
+               return 0;
+       }
+       /* Add other config variables here and to Documentation/config.txt. */
+       return 0;
+ }
  int git_config_from_file(config_fn_t fn, const char *filename, void *data)
  {
        int ret;
@@@ -549,7 -591,7 +591,7 @@@ const char *git_etc_gitconfig(void
        return system_wide;
  }
  
 -int git_env_bool(const char *k, int def)
 +static int git_env_bool(const char *k, int def)
  {
        const char *v = getenv(k);
        return v ? git_config_bool(k, v) : def;
diff --combined environment.c
index 187248bf5d027c8d860ccbf839bc6296d0a42436,d5c3e29e9766d8d1b58c9d4ec6a059926cefce46..084ac8a4361d5486456813149a1e673c07a7a0b2
@@@ -29,6 -29,7 +29,7 @@@ const char *apply_default_whitespace
  int zlib_compression_level = Z_BEST_SPEED;
  int core_compression_level;
  int core_compression_seen;
+ int fsync_object_files;
  size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
  size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
  size_t delta_base_cache_limit = 16 * 1024 * 1024;
@@@ -129,6 -130,13 +130,6 @@@ char *get_object_directory(void
        return git_object_dir;
  }
  
 -char *get_refs_directory(void)
 -{
 -      if (!git_refs_dir)
 -              setup_git_env();
 -      return git_refs_dir;
 -}
 -
  char *get_index_file(void)
  {
        if (!git_index_file)
diff --combined sha1_file.c
index e79b2c1145e800e88c0f6e79338d2befa2443494,fe4ee3ece57ae8627572554c1e9af9f292c67ac6..dd8327c941dd012d890fcb20313a3f0e682d1fa2
@@@ -116,15 -116,6 +116,15 @@@ int safe_create_leading_directories(cha
        return 0;
  }
  
 +int safe_create_leading_directories_const(const char *path)
 +{
 +      /* path points to cache entries, so xstrdup before messing with it */
 +      char *buf = xstrdup(path);
 +      int result = safe_create_leading_directories(buf);
 +      free(buf);
 +      return result;
 +}
 +
  char *sha1_to_hex(const unsigned char *sha1)
  {
        static int bufno;
@@@ -801,28 -792,18 +801,28 @@@ unsigned char* use_pack(struct packed_g
        return win->base + offset;
  }
  
 +static struct packed_git *alloc_packed_git(int extra)
 +{
 +      struct packed_git *p = xmalloc(sizeof(*p) + extra);
 +      memset(p, 0, sizeof(*p));
 +      p->pack_fd = -1;
 +      return p;
 +}
 +
  struct packed_git *add_packed_git(const char *path, int path_len, int local)
  {
        struct stat st;
 -      struct packed_git *p = xmalloc(sizeof(*p) + path_len + 2);
 +      struct packed_git *p = alloc_packed_git(path_len + 2);
  
        /*
         * Make sure a corresponding .pack file exists and that
         * the index looks sane.
         */
        path_len -= strlen(".idx");
 -      if (path_len < 1)
 +      if (path_len < 1) {
 +              free(p);
                return NULL;
 +      }
        memcpy(p->pack_name, path, path_len);
        strcpy(p->pack_name + path_len, ".pack");
        if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode)) {
        /* ok, it looks sane as far as we can check without
         * actually mapping the pack file.
         */
 -      p->index_version = 0;
 -      p->index_data = NULL;
 -      p->index_size = 0;
 -      p->num_objects = 0;
        p->pack_size = st.st_size;
 -      p->next = NULL;
 -      p->windows = NULL;
 -      p->pack_fd = -1;
        p->pack_local = local;
        p->mtime = st.st_mtime;
        if (path_len < 40 || get_sha1_hex(path + path_len - 40, p->sha1))
@@@ -845,15 -833,19 +845,15 @@@ struct packed_git *parse_pack_index(uns
  {
        const char *idx_path = sha1_pack_index_name(sha1);
        const char *path = sha1_pack_name(sha1);
 -      struct packed_git *p = xmalloc(sizeof(*p) + strlen(path) + 2);
 +      struct packed_git *p = alloc_packed_git(strlen(path) + 1);
  
 +      strcpy(p->pack_name, path);
 +      hashcpy(p->sha1, sha1);
        if (check_packed_git_idx(idx_path, p)) {
                free(p);
                return NULL;
        }
  
 -      strcpy(p->pack_name, path);
 -      p->pack_size = 0;
 -      p->next = NULL;
 -      p->windows = NULL;
 -      p->pack_fd = -1;
 -      hashcpy(p->sha1, sha1);
        return p;
  }
  
@@@ -990,18 -982,6 +990,18 @@@ void reprepare_packed_git(void
        prepare_packed_git();
  }
  
 +static void mark_bad_packed_object(struct packed_git *p,
 +                                 const unsigned char *sha1)
 +{
 +      unsigned i;
 +      for (i = 0; i < p->num_bad_objects; i++)
 +              if (!hashcmp(sha1, p->bad_object_sha1 + 20 * i))
 +                      return;
 +      p->bad_object_sha1 = xrealloc(p->bad_object_sha1, 20 * (p->num_bad_objects + 1));
 +      hashcpy(p->bad_object_sha1 + 20 * p->num_bad_objects, sha1);
 +      p->num_bad_objects++;
 +}
 +
  int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long size, const char *type)
  {
        unsigned char real_sha1[20];
@@@ -1320,17 -1300,20 +1320,17 @@@ static off_t get_delta_base(struct pack
                while (c & 128) {
                        base_offset += 1;
                        if (!base_offset || MSB(base_offset, 7))
 -                              die("offset value overflow for delta base object");
 +                              return 0;  /* overflow */
                        c = base_info[used++];
                        base_offset = (base_offset << 7) + (c & 127);
                }
                base_offset = delta_obj_offset - base_offset;
                if (base_offset >= delta_obj_offset)
 -                      die("delta base offset out of bound");
 +                      return 0;  /* out of bound */
                *curpos += used;
        } else if (type == OBJ_REF_DELTA) {
                /* The base entry _must_ be in the same pack */
                base_offset = find_pack_entry_one(base_info, p);
 -              if (!base_offset)
 -                      die("failed to find delta-pack base object %s",
 -                              sha1_to_hex(base_info));
                *curpos += 20;
        } else
                die("I am totally screwed");
@@@ -1423,9 -1406,6 +1423,9 @@@ const char *packed_object_info_detail(s
                        return typename(type);
                case OBJ_OFS_DELTA:
                        obj_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset);
 +                      if (!obj_offset)
 +                              die("pack %s contains bad delta base reference of type %s",
 +                                  p->pack_name, typename(type));
                        if (*delta_chain_length == 0) {
                                revidx = find_pack_revindex(p, obj_offset);
                                hashcpy(base_sha1, nth_packed_object_sha1(p, revidx->nr));
@@@ -1620,41 -1600,17 +1620,41 @@@ static void *unpack_delta_entry(struct 
        off_t base_offset;
  
        base_offset = get_delta_base(p, w_curs, &curpos, *type, obj_offset);
 +      if (!base_offset) {
 +              error("failed to validate delta base reference "
 +                    "at offset %"PRIuMAX" from %s",
 +                    (uintmax_t)curpos, p->pack_name);
 +              return NULL;
 +      }
        base = cache_or_unpack_entry(p, base_offset, &base_size, type, 0);
 -      if (!base)
 -              die("failed to read delta base object"
 -                  " at %"PRIuMAX" from %s",
 -                  (uintmax_t)base_offset, p->pack_name);
 +      if (!base) {
 +              /*
 +               * We're probably in deep shit, but let's try to fetch
 +               * the required base anyway from another pack or loose.
 +               * This is costly but should happen only in the presence
 +               * of a corrupted pack, and is better than failing outright.
 +               */
 +              struct revindex_entry *revidx = find_pack_revindex(p, base_offset);
 +              const unsigned char *base_sha1 =
 +                                      nth_packed_object_sha1(p, revidx->nr);
 +              error("failed to read delta base object %s"
 +                    " at offset %"PRIuMAX" from %s",
 +                    sha1_to_hex(base_sha1), (uintmax_t)base_offset,
 +                    p->pack_name);
 +              mark_bad_packed_object(p, base_sha1);
 +              base = read_sha1_file(base_sha1, type, &base_size);
 +              if (!base)
 +                      return NULL;
 +      }
  
        delta_data = unpack_compressed_entry(p, w_curs, curpos, delta_size);
 -      if (!delta_data)
 -              die("failed to unpack compressed delta"
 -                  " at %"PRIuMAX" from %s",
 -                  (uintmax_t)curpos, p->pack_name);
 +      if (!delta_data) {
 +              error("failed to unpack compressed delta "
 +                    "at offset %"PRIuMAX" from %s",
 +                    (uintmax_t)curpos, p->pack_name);
 +              free(base);
 +              return NULL;
 +      }
        result = patch_delta(base, base_size,
                             delta_data, delta_size,
                             sizep);
@@@ -1686,9 -1642,7 +1686,9 @@@ void *unpack_entry(struct packed_git *p
                data = unpack_compressed_entry(p, &w_curs, curpos, *sizep);
                break;
        default:
 -              die("unknown object type %i in %s", *type, p->pack_name);
 +              data = NULL;
 +              error("unknown object type %i at offset %"PRIuMAX" in %s",
 +                    *type, (uintmax_t)obj_offset, p->pack_name);
        }
        unuse_pack(&w_curs);
        return data;
@@@ -1714,7 -1668,7 +1714,7 @@@ const unsigned char *nth_packed_object_
        }
  }
  
 -static off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n)
 +off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n)
  {
        const unsigned char *index = p->index_data;
        index += 4 * 256;
@@@ -1834,13 -1788,6 +1834,13 @@@ static int find_pack_entry(const unsign
                                goto next;
                }
  
 +              if (p->num_bad_objects) {
 +                      unsigned i;
 +                      for (i = 0; i < p->num_bad_objects; i++)
 +                              if (!hashcmp(sha1, p->bad_object_sha1 + 20 * i))
 +                                      goto next;
 +              }
 +
                offset = find_pack_entry_one(sha1, p);
                if (offset) {
                        /*
@@@ -1925,24 -1872,11 +1925,24 @@@ static void *read_packed_sha1(const uns
                              enum object_type *type, unsigned long *size)
  {
        struct pack_entry e;
 +      void *data;
  
        if (!find_pack_entry(sha1, &e, NULL))
                return NULL;
 -      else
 -              return cache_or_unpack_entry(e.p, e.offset, size, type, 1);
 +      data = cache_or_unpack_entry(e.p, e.offset, size, type, 1);
 +      if (!data) {
 +              /*
 +               * We're probably in deep shit, but let's try to fetch
 +               * the required object anyway from another pack or loose.
 +               * This should happen only in the presence of a corrupted
 +               * pack, and is better than failing outright.
 +               */
 +              error("failed to read object %s at offset %"PRIuMAX" from %s",
 +                    sha1_to_hex(sha1), (uintmax_t)e.offset, e.p->pack_name);
 +              mark_bad_packed_object(e.p, sha1);
 +              data = read_sha1_file(sha1, type, size);
 +      }
 +      return data;
  }
  
  /*
@@@ -2149,7 -2083,8 +2149,8 @@@ int hash_sha1_file(const void *buf, uns
  /* Finalize a file on disk, and close it. */
  static void close_sha1_file(int fd)
  {
-       /* For safe-mode, we could fsync_or_die(fd, "sha1 file") here */
+       if (fsync_object_files)
+               fsync_or_die(fd, "sha1 file");
        fchmod(fd, 0444);
        if (close(fd) != 0)
                die("unable to write sha1 file");
@@@ -2184,7 -2119,6 +2185,7 @@@ static int create_tmpfile(char *buffer
        fd = mkstemp(buffer);
        if (fd < 0 && dirlen) {
                /* Make sure the directory exists */
 +              memcpy(buffer, filename, dirlen);
                buffer[dirlen-1] = 0;
                if (mkdir(buffer, 0777) || adjust_shared_perm(buffer))
                        return -1;