Merge branch 'jk/sha1-file-reduce-useless-warnings' into maint
authorJunio C Hamano <gitster@pobox.com>
Fri, 5 Jun 2015 19:00:07 +0000 (12:00 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 5 Jun 2015 19:00:07 +0000 (12:00 -0700)
* jk/sha1-file-reduce-useless-warnings:
sha1_file: squelch "packfile cannot be accessed" warnings

1  2 
builtin/pack-objects.c
sha1_file.c
diff --combined builtin/pack-objects.c
index c3a75166bd10918d21d3df19832880c4373dc8d7,8861b88be459e6147afbfb1c50723e1ecad189f5..c067107a6a6b8d6f797854d1e3a7cc9ce5da0cdc
@@@ -20,9 -20,6 +20,9 @@@
  #include "streaming.h"
  #include "thread-utils.h"
  #include "pack-bitmap.h"
 +#include "reachable.h"
 +#include "sha1-array.h"
 +#include "argv-array.h"
  
  static const char *pack_usage[] = {
        N_("git pack-objects --stdout [options...] [< ref-list | < object-list]"),
@@@ -92,7 -89,8 +92,7 @@@ static void index_commit_for_bitmap(str
  {
        if (indexed_commits_nr >= indexed_commits_alloc) {
                indexed_commits_alloc = (indexed_commits_alloc + 32) * 2;
 -              indexed_commits = xrealloc(indexed_commits,
 -                      indexed_commits_alloc * sizeof(struct commit *));
 +              REALLOC_ARRAY(indexed_commits, indexed_commits_alloc);
        }
  
        indexed_commits[indexed_commits_nr++] = commit;
@@@ -125,6 -123,7 +125,6 @@@ static unsigned long do_compress(void *
        void *in, *out;
        unsigned long maxsize;
  
 -      memset(&stream, 0, sizeof(stream));
        git_deflate_init(&stream, pack_compression_level);
        maxsize = git_deflate_bound(&stream, size);
  
@@@ -152,6 -151,7 +152,6 @@@ static unsigned long write_large_blob_d
        unsigned char obuf[1024 * 16];
        unsigned long olen = 0;
  
 -      memset(&stream, 0, sizeof(stream));
        git_deflate_init(&stream, pack_compression_level);
  
        for (;;) {
@@@ -812,7 -812,6 +812,7 @@@ static void write_pack_file(void
                        fixup_pack_header_footer(fd, sha1, pack_tmp_name,
                                                 nr_written, sha1, offset);
                        close(fd);
 +                      write_bitmap_index = 0;
                }
  
                if (!pack_to_stdout) {
@@@ -961,10 -960,8 +961,8 @@@ static int want_object_in_pack(const un
                off_t offset = find_pack_entry_one(sha1, p);
                if (offset) {
                        if (!*found_pack) {
-                               if (!is_pack_valid(p)) {
-                                       warning("packfile %s cannot be accessed", p->pack_name);
+                               if (!is_pack_valid(p))
                                        continue;
-                               }
                                *found_offset = offset;
                                *found_pack = p;
                        }
@@@ -1974,6 -1971,8 +1972,6 @@@ static void ll_find_deltas(struct objec
  
        init_threaded_search();
  
 -      if (!delta_search_threads)      /* --threads=0 means autodetect */
 -              delta_search_threads = online_cpus();
        if (delta_search_threads <= 1) {
                find_deltas(list, &list_size, window, depth, processed);
                cleanup_threaded_search();
@@@ -2213,6 -2212,10 +2211,6 @@@ static int git_pack_config(const char *
                cache_max_small_delta_size = git_config_int(k, v);
                return 0;
        }
 -      if (!strcmp(k, "pack.writebitmaps")) {
 -              write_bitmap_index = git_config_bool(k, v);
 -              return 0;
 -      }
        if (!strcmp(k, "pack.writebitmaphashcache")) {
                if (git_config_bool(k, v))
                        write_bitmap_options |= BITMAP_OPT_HASH_CACHE;
@@@ -2407,27 -2410,6 +2405,27 @@@ static int has_sha1_pack_kept_or_nonloc
        return 0;
  }
  
 +/*
 + * Store a list of sha1s that are should not be discarded
 + * because they are either written too recently, or are
 + * reachable from another object that was.
 + *
 + * This is filled by get_object_list.
 + */
 +static struct sha1_array recent_objects;
 +
 +static int loosened_object_can_be_discarded(const unsigned char *sha1,
 +                                          unsigned long mtime)
 +{
 +      if (!unpack_unreachable_expiration)
 +              return 0;
 +      if (mtime > unpack_unreachable_expiration)
 +              return 0;
 +      if (sha1_array_lookup(&recent_objects, sha1) >= 0)
 +              return 0;
 +      return 1;
 +}
 +
  static void loosen_unused_packed_objects(struct rev_info *revs)
  {
        struct packed_git *p;
                if (!p->pack_local || p->pack_keep)
                        continue;
  
 -              if (unpack_unreachable_expiration &&
 -                  p->mtime < unpack_unreachable_expiration)
 -                      continue;
 -
                if (open_pack_index(p))
                        die("cannot open pack index");
  
                for (i = 0; i < p->num_objects; i++) {
                        sha1 = nth_packed_object_sha1(p, i);
                        if (!packlist_find(&to_pack, sha1, NULL) &&
 -                              !has_sha1_pack_kept_or_nonlocal(sha1))
 +                          !has_sha1_pack_kept_or_nonlocal(sha1) &&
 +                          !loosened_object_can_be_discarded(sha1, p->mtime))
                                if (force_object_loose(sha1, p->mtime))
                                        die("unable to force loose object");
                }
@@@ -2481,19 -2466,6 +2479,19 @@@ static int get_object_list_from_bitmap(
        return 0;
  }
  
 +static void record_recent_object(struct object *obj,
 +                               const struct name_path *path,
 +                               const char *last,
 +                               void *data)
 +{
 +      sha1_array_append(&recent_objects, obj->sha1);
 +}
 +
 +static void record_recent_commit(struct commit *commit, void *data)
 +{
 +      sha1_array_append(&recent_objects, commit->object.sha1);
 +}
 +
  static void get_object_list(int ac, const char **av)
  {
        struct rev_info revs;
                                if (get_sha1_hex(line + 10, sha1))
                                        die("not an SHA-1 '%s'", line + 10);
                                register_shallow(sha1);
 +                              use_bitmap_index = 0;
                                continue;
                        }
                        die("not a rev '%s'", line);
        mark_edges_uninteresting(&revs, show_edge);
        traverse_commit_list(&revs, show_commit, show_object, NULL);
  
 +      if (unpack_unreachable_expiration) {
 +              revs.ignore_missing_links = 1;
 +              if (add_unseen_recent_objects_to_traversal(&revs,
 +                              unpack_unreachable_expiration))
 +                      die("unable to add recent objects");
 +              if (prepare_revision_walk(&revs))
 +                      die("revision walk setup failed");
 +              traverse_commit_list(&revs, record_recent_commit,
 +                                   record_recent_object, NULL);
 +      }
 +
        if (keep_unreachable)
                add_objects_in_unpacked_packs(&revs);
        if (unpack_unreachable)
                loosen_unused_packed_objects(&revs);
 +
 +      sha1_array_clear(&recent_objects);
  }
  
  static int option_parse_index_version(const struct option *opt,
@@@ -2611,11 -2569,10 +2609,11 @@@ int cmd_pack_objects(int argc, const ch
  {
        int use_internal_rev_list = 0;
        int thin = 0;
 +      int shallow = 0;
        int all_progress_implied = 0;
 -      const char *rp_av[6];
 -      int rp_ac = 0;
 +      struct argv_array rp = ARGV_ARRAY_INIT;
        int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0;
 +      int rev_list_index = 0;
        struct option pack_objects_options[] = {
                OPT_SET_INT('q', "quiet", &progress,
                            N_("do not show progress meter"), 0),
                { OPTION_SET_INT, 0, "reflog", &rev_list_reflog, NULL,
                  N_("include objects referred by reflog entries"),
                  PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
 +              { OPTION_SET_INT, 0, "indexed-objects", &rev_list_index, NULL,
 +                N_("include objects referred to by the index"),
 +                PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
                OPT_BOOL(0, "stdout", &pack_to_stdout,
                         N_("output pack to stdout")),
                OPT_BOOL(0, "include-tag", &include_tag,
                  PARSE_OPT_OPTARG, option_parse_unpack_unreachable },
                OPT_BOOL(0, "thin", &thin,
                         N_("create thin packs")),
 +              OPT_BOOL(0, "shallow", &shallow,
 +                       N_("create packs suitable for shallow fetches")),
                OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep,
                         N_("ignore packs that have companion .keep file")),
                OPT_INTEGER(0, "compression", &pack_compression_level,
        if (pack_to_stdout != !base_name || argc)
                usage_with_options(pack_usage, pack_objects_options);
  
 -      rp_av[rp_ac++] = "pack-objects";
 +      argv_array_push(&rp, "pack-objects");
        if (thin) {
                use_internal_rev_list = 1;
 -              rp_av[rp_ac++] = "--objects-edge";
 +              argv_array_push(&rp, shallow
 +                              ? "--objects-edge-aggressive"
 +                              : "--objects-edge");
        } else
 -              rp_av[rp_ac++] = "--objects";
 +              argv_array_push(&rp, "--objects");
  
        if (rev_list_all) {
                use_internal_rev_list = 1;
 -              rp_av[rp_ac++] = "--all";
 +              argv_array_push(&rp, "--all");
        }
        if (rev_list_reflog) {
                use_internal_rev_list = 1;
 -              rp_av[rp_ac++] = "--reflog";
 +              argv_array_push(&rp, "--reflog");
 +      }
 +      if (rev_list_index) {
 +              use_internal_rev_list = 1;
 +              argv_array_push(&rp, "--indexed-objects");
        }
        if (rev_list_unpacked) {
                use_internal_rev_list = 1;
 -              rp_av[rp_ac++] = "--unpacked";
 +              argv_array_push(&rp, "--unpacked");
        }
  
        if (!reuse_object)
                pack_compression_level = Z_DEFAULT_COMPRESSION;
        else if (pack_compression_level < 0 || pack_compression_level > Z_BEST_COMPRESSION)
                die("bad pack compression level %d", pack_compression_level);
 +
 +      if (!delta_search_threads)      /* --threads=0 means autodetect */
 +              delta_search_threads = online_cpus();
 +
  #ifdef NO_PTHREADS
        if (delta_search_threads != 1)
                warning("no threads support, ignoring --threads");
  
        if (keep_unreachable && unpack_unreachable)
                die("--keep-unreachable and --unpack-unreachable are incompatible.");
 +      if (!rev_list_all || !rev_list_reflog || !rev_list_index)
 +              unpack_unreachable_expiration = 0;
  
        if (!use_internal_rev_list || !pack_to_stdout || is_repository_shallow())
                use_bitmap_index = 0;
        if (!use_internal_rev_list)
                read_object_list_from_stdin();
        else {
 -              rp_av[rp_ac] = NULL;
 -              get_object_list(rp_ac, rp_av);
 +              get_object_list(rp.argc, rp.argv);
 +              argv_array_clear(&rp);
        }
        cleanup_preferred_base();
        if (include_tag && nr_result)
diff --combined sha1_file.c
index 47f56f2e89d99b58a6d43bb44828c442577424cf,fef54a8811a12c2da45765d4fc014eb0c40aacea..001537c9359bf83fdc4d6c59426a25424be2e803
@@@ -8,7 -8,6 +8,7 @@@
   */
  #include "cache.h"
  #include "string-list.h"
 +#include "lockfile.h"
  #include "delta.h"
  #include "pack.h"
  #include "blob.h"
@@@ -37,6 -36,9 +37,6 @@@ static inline uintmax_t sz_fmt(size_t s
  
  const unsigned char null_sha1[20];
  
 -static const char *no_log_pack_access = "no_log_pack_access";
 -static const char *log_pack_access;
 -
  /*
   * This is meant to hold a *small* number of objects that you would
   * want read_sha1_file() to be able to return, but yet you do not want
@@@ -266,9 -268,9 +266,9 @@@ static struct alternate_object_databas
   * SHA1, an extra slash for the first level indirection, and the
   * terminating NUL.
   */
 -static int link_alt_odb_entry(const char *entry, const char *relative_base, int depth)
 +static int link_alt_odb_entry(const char *entry, const char *relative_base,
 +      int depth, const char *normalized_objdir)
  {
 -      const char *objdir = get_object_directory();
        struct alternate_object_database *ent;
        struct alternate_object_database *alt;
        int pfxlen, entlen;
         * thing twice, or object directory itself.
         */
        for (alt = alt_odb_list; alt; alt = alt->next) {
 -              if (!memcmp(ent->base, alt->base, pfxlen)) {
 +              if (pfxlen == alt->name - alt->base - 1 &&
 +                  !memcmp(ent->base, alt->base, pfxlen)) {
                        free(ent);
                        return -1;
                }
        }
 -      if (!strcmp(ent->base, objdir)) {
 +      if (!strcmp_icase(ent->base, normalized_objdir)) {
                free(ent);
                return -1;
        }
@@@ -343,7 -344,6 +343,7 @@@ static void link_alt_odb_entries(const 
        struct string_list entries = STRING_LIST_INIT_NODUP;
        char *alt_copy;
        int i;
 +      struct strbuf objdirbuf = STRBUF_INIT;
  
        if (depth > 5) {
                error("%s: ignoring alternate object stores, nesting too deep.",
                return;
        }
  
 +      strbuf_add_absolute_path(&objdirbuf, get_object_directory());
 +      normalize_path_copy(objdirbuf.buf, objdirbuf.buf);
 +
        alt_copy = xmemdupz(alt, len);
        string_list_split_in_place(&entries, alt_copy, sep, -1);
        for (i = 0; i < entries.nr; i++) {
                        error("%s: ignoring relative alternate object store %s",
                                        relative_base, entry);
                } else {
 -                      link_alt_odb_entry(entry, relative_base, depth);
 +                      link_alt_odb_entry(entry, relative_base, depth, objdirbuf.buf);
                }
        }
        string_list_clear(&entries, 0);
        free(alt_copy);
 +      strbuf_release(&objdirbuf);
  }
  
  void read_info_alternates(const char * relative_base, int depth)
@@@ -413,18 -409,14 +413,18 @@@ void add_to_alternates_file(const char 
                link_alt_odb_entries(alt, strlen(alt), '\n', NULL, 0);
  }
  
 -void foreach_alt_odb(alt_odb_fn fn, void *cb)
 +int foreach_alt_odb(alt_odb_fn fn, void *cb)
  {
        struct alternate_object_database *ent;
 +      int r = 0;
  
        prepare_alt_odb();
 -      for (ent = alt_odb_list; ent; ent = ent->next)
 -              if (fn(ent, cb))
 -                      return;
 +      for (ent = alt_odb_list; ent; ent = ent->next) {
 +              r = fn(ent, cb);
 +              if (r)
 +                      break;
 +      }
 +      return r;
  }
  
  void prepare_alt_odb(void)
        read_info_alternates(get_object_directory(), 0);
  }
  
 -static int has_loose_object_local(const unsigned char *sha1)
 +static int freshen_file(const char *fn)
  {
 -      return !access(sha1_file_name(sha1), F_OK);
 +      struct utimbuf t;
 +      t.actime = t.modtime = time(NULL);
 +      return !utime(fn, &t);
  }
  
 -int has_loose_object_nonlocal(const unsigned char *sha1)
 +static int check_and_freshen_file(const char *fn, int freshen)
 +{
 +      if (access(fn, F_OK))
 +              return 0;
 +      if (freshen && freshen_file(fn))
 +              return 0;
 +      return 1;
 +}
 +
 +static int check_and_freshen_local(const unsigned char *sha1, int freshen)
 +{
 +      return check_and_freshen_file(sha1_file_name(sha1), freshen);
 +}
 +
 +static int check_and_freshen_nonlocal(const unsigned char *sha1, int freshen)
  {
        struct alternate_object_database *alt;
        prepare_alt_odb();
        for (alt = alt_odb_list; alt; alt = alt->next) {
                fill_sha1_path(alt->name, sha1);
 -              if (!access(alt->base, F_OK))
 +              if (check_and_freshen_file(alt->base, freshen))
                        return 1;
        }
        return 0;
  }
  
 +static int check_and_freshen(const unsigned char *sha1, int freshen)
 +{
 +      return check_and_freshen_local(sha1, freshen) ||
 +             check_and_freshen_nonlocal(sha1, freshen);
 +}
 +
 +int has_loose_object_nonlocal(const unsigned char *sha1)
 +{
 +      return check_and_freshen_nonlocal(sha1, 0);
 +}
 +
  static int has_loose_object(const unsigned char *sha1)
  {
 -      return has_loose_object_local(sha1) ||
 -             has_loose_object_nonlocal(sha1);
 +      return check_and_freshen(sha1, 0);
  }
  
  static unsigned int pack_used_ctr;
@@@ -694,26 -660,10 +694,26 @@@ void release_pack_memory(size_t need
                ; /* nothing */
  }
  
 +static void mmap_limit_check(size_t length)
 +{
 +      static size_t limit = 0;
 +      if (!limit) {
 +              limit = git_env_ulong("GIT_MMAP_LIMIT", 0);
 +              if (!limit)
 +                      limit = SIZE_MAX;
 +      }
 +      if (length > limit)
 +              die("attempting to mmap %"PRIuMAX" over limit %"PRIuMAX,
 +                  (uintmax_t)length, (uintmax_t)limit);
 +}
 +
  void *xmmap(void *start, size_t length,
        int prot, int flags, int fd, off_t offset)
  {
 -      void *ret = mmap(start, length, prot, flags, fd, offset);
 +      void *ret;
 +
 +      mmap_limit_check(length);
 +      ret = mmap(start, length, prot, flags, fd, offset);
        if (ret == MAP_FAILED) {
                if (!length)
                        return NULL;
@@@ -1198,7 -1148,7 +1198,7 @@@ static void report_pack_garbage(struct 
        if (!report_garbage)
                return;
  
 -      sort_string_list(list);
 +      string_list_sort(list);
  
        for (i = 0; i < list->nr; i++) {
                const char *path = list->items[i].string;
  
  static void prepare_packed_git_one(char *objdir, int local)
  {
 -      /* Ensure that this buffer is large enough so that we can
 -         append "/pack/" without clobbering the stack even if
 -         strlen(objdir) were PATH_MAX.  */
 -      char path[PATH_MAX + 1 + 4 + 1 + 1];
 -      int len;
 +      struct strbuf path = STRBUF_INIT;
 +      size_t dirnamelen;
        DIR *dir;
        struct dirent *de;
        struct string_list garbage = STRING_LIST_INIT_DUP;
  
 -      sprintf(path, "%s/pack", objdir);
 -      len = strlen(path);
 -      dir = opendir(path);
 +      strbuf_addstr(&path, objdir);
 +      strbuf_addstr(&path, "/pack");
 +      dir = opendir(path.buf);
        if (!dir) {
                if (errno != ENOENT)
                        error("unable to open object pack directory: %s: %s",
 -                            path, strerror(errno));
 +                            path.buf, strerror(errno));
 +              strbuf_release(&path);
                return;
        }
 -      path[len++] = '/';
 +      strbuf_addch(&path, '/');
 +      dirnamelen = path.len;
        while ((de = readdir(dir)) != NULL) {
 -              int namelen = strlen(de->d_name);
                struct packed_git *p;
 -
 -              if (len + namelen + 1 > sizeof(path)) {
 -                      if (report_garbage) {
 -                              struct strbuf sb = STRBUF_INIT;
 -                              strbuf_addf(&sb, "%.*s/%s", len - 1, path, de->d_name);
 -                              report_garbage("path too long", sb.buf);
 -                              strbuf_release(&sb);
 -                      }
 -                      continue;
 -              }
 +              size_t base_len;
  
                if (is_dot_or_dotdot(de->d_name))
                        continue;
  
 -              strcpy(path + len, de->d_name);
 +              strbuf_setlen(&path, dirnamelen);
 +              strbuf_addstr(&path, de->d_name);
  
 -              if (has_extension(de->d_name, ".idx")) {
 +              base_len = path.len;
 +              if (strip_suffix_mem(path.buf, &base_len, ".idx")) {
                        /* Don't reopen a pack we already have. */
                        for (p = packed_git; p; p = p->next) {
 -                              if (!memcmp(path, p->pack_name, len + namelen - 4))
 +                              size_t len;
 +                              if (strip_suffix(p->pack_name, ".pack", &len) &&
 +                                  len == base_len &&
 +                                  !memcmp(p->pack_name, path.buf, len))
                                        break;
                        }
                        if (p == NULL &&
                             * See if it really is a valid .idx file with
                             * corresponding .pack file that we can map.
                             */
 -                          (p = add_packed_git(path, len + namelen, local)) != NULL)
 +                          (p = add_packed_git(path.buf, path.len, local)) != NULL)
                                install_packed_git(p);
                }
  
                if (!report_garbage)
                        continue;
  
 -              if (has_extension(de->d_name, ".idx") ||
 -                  has_extension(de->d_name, ".pack") ||
 -                  has_extension(de->d_name, ".bitmap") ||
 -                  has_extension(de->d_name, ".keep"))
 -                      string_list_append(&garbage, path);
 +              if (ends_with(de->d_name, ".idx") ||
 +                  ends_with(de->d_name, ".pack") ||
 +                  ends_with(de->d_name, ".bitmap") ||
 +                  ends_with(de->d_name, ".keep"))
 +                      string_list_append(&garbage, path.buf);
                else
 -                      report_garbage("garbage found", path);
 +                      report_garbage("garbage found", path.buf);
        }
        closedir(dir);
        report_pack_garbage(&garbage);
        string_list_clear(&garbage, 0);
 +      strbuf_release(&path);
  }
  
  static int sort_pack(const void *a_, const void *b_)
@@@ -1482,23 -1437,19 +1482,23 @@@ static int open_sha1_file(const unsigne
  {
        int fd;
        struct alternate_object_database *alt;
 +      int most_interesting_errno;
  
        fd = git_open_noatime(sha1_file_name(sha1));
        if (fd >= 0)
                return fd;
 +      most_interesting_errno = errno;
  
        prepare_alt_odb();
 -      errno = ENOENT;
        for (alt = alt_odb_list; alt; alt = alt->next) {
                fill_sha1_path(alt->name, sha1);
                fd = git_open_noatime(alt->base);
                if (fd >= 0)
                        return fd;
 +              if (most_interesting_errno == ENOENT)
 +                      most_interesting_errno = errno;
        }
 +      errno = most_interesting_errno;
        return -1;
  }
  
@@@ -1970,9 -1921,7 +1970,9 @@@ static void *unpack_compressed_entry(st
        git_zstream stream;
        unsigned char *buffer, *in;
  
 -      buffer = xmallocz(size);
 +      buffer = xmallocz_gently(size);
 +      if (!buffer)
 +              return NULL;
        memset(&stream, 0, sizeof(stream));
        stream.next_out = buffer;
        stream.avail_out = size + 1;
@@@ -2132,9 -2081,27 +2132,9 @@@ static void *read_object(const unsigne
  
  static void write_pack_access_log(struct packed_git *p, off_t obj_offset)
  {
 -      static FILE *log_file;
 -
 -      if (!log_pack_access)
 -              log_pack_access = getenv("GIT_TRACE_PACK_ACCESS");
 -      if (!log_pack_access)
 -              log_pack_access = no_log_pack_access;
 -      if (log_pack_access == no_log_pack_access)
 -              return;
 -
 -      if (!log_file) {
 -              log_file = fopen(log_pack_access, "w");
 -              if (!log_file) {
 -                      error("cannot open pack access log '%s' for writing: %s",
 -                            log_pack_access, strerror(errno));
 -                      log_pack_access = no_log_pack_access;
 -                      return;
 -              }
 -      }
 -      fprintf(log_file, "%s %"PRIuMAX"\n",
 -              p->pack_name, (uintmax_t)obj_offset);
 -      fflush(log_file);
 +      static struct trace_key pack_access = TRACE_KEY_INIT(PACK_ACCESS);
 +      trace_printf_key(&pack_access, "%s %"PRIuMAX"\n",
 +                       p->pack_name, (uintmax_t)obj_offset);
  }
  
  int do_check_packed_object_crc;
@@@ -2159,7 -2126,8 +2159,7 @@@ void *unpack_entry(struct packed_git *p
        int delta_stack_nr = 0, delta_stack_alloc = UNPACK_ENTRY_STACK_PREALLOC;
        int base_from_cache = 0;
  
 -      if (log_pack_access != no_log_pack_access)
 -              write_pack_access_log(p, obj_offset);
 +      write_pack_access_log(p, obj_offset);
  
        /* PHASE 1: drill down to the innermost base object */
        for (;;) {
@@@ -2473,10 -2441,8 +2473,8 @@@ static int fill_pack_entry(const unsign
         * answer, as it may have been deleted since the index was
         * loaded!
         */
-       if (!is_pack_valid(p)) {
-               warning("packfile %s cannot be accessed", p->pack_name);
+       if (!is_pack_valid(p))
                return 0;
-       }
        e->offset = offset;
        e->p = p;
        hashcpy(e->sha1, sha1);
@@@ -2943,6 -2909,7 +2941,6 @@@ static int write_loose_object(const uns
        }
  
        /* Set it up */
 -      memset(&stream, 0, sizeof(stream));
        git_deflate_init(&stream, zlib_compression_level);
        stream.next_out = compressed;
        stream.avail_out = sizeof(compressed);
        return move_temp_to_file(tmp_file, filename);
  }
  
 -int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
 +static int freshen_loose_object(const unsigned char *sha1)
 +{
 +      return check_and_freshen(sha1, 1);
 +}
 +
 +static int freshen_packed_object(const unsigned char *sha1)
 +{
 +      struct pack_entry e;
 +      if (!find_pack_entry(sha1, &e))
 +              return 0;
 +      if (e.p->freshened)
 +              return 1;
 +      if (!freshen_file(e.p->pack_name))
 +              return 0;
 +      e.p->freshened = 1;
 +      return 1;
 +}
 +
 +int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1)
  {
 -      unsigned char sha1[20];
        char hdr[32];
        int hdrlen;
  
         * it out into .git/objects/??/?{38} file.
         */
        write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
 -      if (returnsha1)
 -              hashcpy(returnsha1, sha1);
 -      if (has_sha1_file(sha1))
 +      if (freshen_packed_object(sha1) || freshen_loose_object(sha1))
                return 0;
        return write_loose_object(sha1, hdr, hdrlen, buf, len, 0);
  }
  
 +int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type,
 +                           unsigned char *sha1, unsigned flags)
 +{
 +      char *header;
 +      int hdrlen, status = 0;
 +
 +      /* type string, SP, %lu of the length plus NUL must fit this */
 +      header = xmalloc(strlen(type) + 32);
 +      write_sha1_file_prepare(buf, len, type, sha1, header, &hdrlen);
 +
 +      if (!(flags & HASH_WRITE_OBJECT))
 +              goto cleanup;
 +      if (freshen_packed_object(sha1) || freshen_loose_object(sha1))
 +              goto cleanup;
 +      status = write_loose_object(sha1, header, hdrlen, buf, len, 0);
 +
 +cleanup:
 +      free(header);
 +      return status;
 +}
 +
  int force_object_loose(const unsigned char *sha1, time_t mtime)
  {
        void *buf;
@@@ -3158,29 -3089,6 +3156,29 @@@ static int index_mem(unsigned char *sha
        return ret;
  }
  
 +static int index_stream_convert_blob(unsigned char *sha1, int fd,
 +                                   const char *path, unsigned flags)
 +{
 +      int ret;
 +      const int write_object = flags & HASH_WRITE_OBJECT;
 +      struct strbuf sbuf = STRBUF_INIT;
 +
 +      assert(path);
 +      assert(would_convert_to_git_filter_fd(path));
 +
 +      convert_to_git_filter_fd(path, fd, &sbuf,
 +                               write_object ? safe_crlf : SAFE_CRLF_FALSE);
 +
 +      if (write_object)
 +              ret = write_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
 +                                    sha1);
 +      else
 +              ret = hash_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
 +                                   sha1);
 +      strbuf_release(&sbuf);
 +      return ret;
 +}
 +
  static int index_pipe(unsigned char *sha1, int fd, enum object_type type,
                      const char *path, unsigned flags)
  {
@@@ -3246,22 -3154,15 +3244,22 @@@ int index_fd(unsigned char *sha1, int f
             enum object_type type, const char *path, unsigned flags)
  {
        int ret;
 -      size_t size = xsize_t(st->st_size);
  
 -      if (!S_ISREG(st->st_mode))
 +      /*
 +       * Call xsize_t() only when needed to avoid potentially unnecessary
 +       * die() for large files.
 +       */
 +      if (type == OBJ_BLOB && path && would_convert_to_git_filter_fd(path))
 +              ret = index_stream_convert_blob(sha1, fd, path, flags);
 +      else if (!S_ISREG(st->st_mode))
                ret = index_pipe(sha1, fd, type, path, flags);
 -      else if (size <= big_file_threshold || type != OBJ_BLOB ||
 -               (path && would_convert_to_git(path, NULL, 0, 0)))
 -              ret = index_core(sha1, fd, size, type, path, flags);
 +      else if (st->st_size <= big_file_threshold || type != OBJ_BLOB ||
 +               (path && would_convert_to_git(path)))
 +              ret = index_core(sha1, fd, xsize_t(st->st_size), type, path,
 +                               flags);
        else
 -              ret = index_stream(sha1, fd, size, type, path, flags);
 +              ret = index_stream(sha1, fd, xsize_t(st->st_size), type, path,
 +                                 flags);
        close(fd);
        return ret;
  }
@@@ -3326,172 -3227,3 +3324,172 @@@ void assert_sha1_type(const unsigned ch
                die("%s is not a valid '%s' object", sha1_to_hex(sha1),
                    typename(expect));
  }
 +
 +static int for_each_file_in_obj_subdir(int subdir_nr,
 +                                     struct strbuf *path,
 +                                     each_loose_object_fn obj_cb,
 +                                     each_loose_cruft_fn cruft_cb,
 +                                     each_loose_subdir_fn subdir_cb,
 +                                     void *data)
 +{
 +      size_t baselen = path->len;
 +      DIR *dir = opendir(path->buf);
 +      struct dirent *de;
 +      int r = 0;
 +
 +      if (!dir) {
 +              if (errno == ENOENT)
 +                      return 0;
 +              return error("unable to open %s: %s", path->buf, strerror(errno));
 +      }
 +
 +      while ((de = readdir(dir))) {
 +              if (is_dot_or_dotdot(de->d_name))
 +                      continue;
 +
 +              strbuf_setlen(path, baselen);
 +              strbuf_addf(path, "/%s", de->d_name);
 +
 +              if (strlen(de->d_name) == 38)  {
 +                      char hex[41];
 +                      unsigned char sha1[20];
 +
 +                      snprintf(hex, sizeof(hex), "%02x%s",
 +                               subdir_nr, de->d_name);
 +                      if (!get_sha1_hex(hex, sha1)) {
 +                              if (obj_cb) {
 +                                      r = obj_cb(sha1, path->buf, data);
 +                                      if (r)
 +                                              break;
 +                              }
 +                              continue;
 +                      }
 +              }
 +
 +              if (cruft_cb) {
 +                      r = cruft_cb(de->d_name, path->buf, data);
 +                      if (r)
 +                              break;
 +              }
 +      }
 +      strbuf_setlen(path, baselen);
 +
 +      if (!r && subdir_cb)
 +              r = subdir_cb(subdir_nr, path->buf, data);
 +
 +      closedir(dir);
 +      return r;
 +}
 +
 +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)
 +{
 +      size_t baselen = path->len;
 +      int r = 0;
 +      int i;
 +
 +      for (i = 0; i < 256; i++) {
 +              strbuf_addf(path, "/%02x", i);
 +              r = for_each_file_in_obj_subdir(i, path, obj_cb, cruft_cb,
 +                                              subdir_cb, data);
 +              strbuf_setlen(path, baselen);
 +              if (r)
 +                      break;
 +      }
 +
 +      return r;
 +}
 +
 +int for_each_loose_file_in_objdir(const char *path,
 +                                each_loose_object_fn obj_cb,
 +                                each_loose_cruft_fn cruft_cb,
 +                                each_loose_subdir_fn subdir_cb,
 +                                void *data)
 +{
 +      struct strbuf buf = STRBUF_INIT;
 +      int r;
 +
 +      strbuf_addstr(&buf, path);
 +      r = for_each_loose_file_in_objdir_buf(&buf, obj_cb, cruft_cb,
 +                                            subdir_cb, data);
 +      strbuf_release(&buf);
 +
 +      return r;
 +}
 +
 +struct loose_alt_odb_data {
 +      each_loose_object_fn *cb;
 +      void *data;
 +};
 +
 +static int loose_from_alt_odb(struct alternate_object_database *alt,
 +                            void *vdata)
 +{
 +      struct loose_alt_odb_data *data = vdata;
 +      struct strbuf buf = STRBUF_INIT;
 +      int r;
 +
 +      /* copy base not including trailing '/' */
 +      strbuf_add(&buf, alt->base, alt->name - alt->base - 1);
 +      r = for_each_loose_file_in_objdir_buf(&buf,
 +                                            data->cb, NULL, NULL,
 +                                            data->data);
 +      strbuf_release(&buf);
 +      return r;
 +}
 +
 +int for_each_loose_object(each_loose_object_fn cb, void *data, unsigned flags)
 +{
 +      struct loose_alt_odb_data alt;
 +      int r;
 +
 +      r = for_each_loose_file_in_objdir(get_object_directory(),
 +                                        cb, NULL, NULL, data);
 +      if (r)
 +              return r;
 +
 +      if (flags & FOR_EACH_OBJECT_LOCAL_ONLY)
 +              return 0;
 +
 +      alt.cb = cb;
 +      alt.data = data;
 +      return foreach_alt_odb(loose_from_alt_odb, &alt);
 +}
 +
 +static int for_each_object_in_pack(struct packed_git *p, each_packed_object_fn cb, void *data)
 +{
 +      uint32_t i;
 +      int r = 0;
 +
 +      for (i = 0; i < p->num_objects; i++) {
 +              const unsigned char *sha1 = nth_packed_object_sha1(p, i);
 +
 +              if (!sha1)
 +                      return error("unable to get sha1 of object %u in %s",
 +                                   i, p->pack_name);
 +
 +              r = cb(sha1, p, i, data);
 +              if (r)
 +                      break;
 +      }
 +      return r;
 +}
 +
 +int for_each_packed_object(each_packed_object_fn cb, void *data, unsigned flags)
 +{
 +      struct packed_git *p;
 +      int r = 0;
 +
 +      prepare_packed_git();
 +      for (p = packed_git; p; p = p->next) {
 +              if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
 +                      continue;
 +              r = for_each_object_in_pack(p, cb, data);
 +              if (r)
 +                      break;
 +      }
 +      return r;
 +}