]> git.ipfire.org Git - thirdparty/git.git/blobdiff - read-cache.c
The 20th batch
[thirdparty/git.git] / read-cache.c
index 080bd39713bc1782434b7212954e6bc590fa4d6d..764fdfec46582a44eaf2d95558346c05275558cf 100644 (file)
@@ -3,6 +3,9 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "bulk-checkin.h"
 #include "config.h"
@@ -20,7 +23,6 @@
 #include "oid-array.h"
 #include "tree.h"
 #include "commit.h"
-#include "blob.h"
 #include "environment.h"
 #include "gettext.h"
 #include "mem-pool.h"
@@ -29,9 +31,9 @@
 #include "path.h"
 #include "preload-index.h"
 #include "read-cache.h"
+#include "repository.h"
 #include "resolve-undo.h"
 #include "revision.h"
-#include "run-command.h"
 #include "strbuf.h"
 #include "trace2.h"
 #include "varint.h"
@@ -197,6 +199,33 @@ void fill_stat_cache_info(struct index_state *istate, struct cache_entry *ce, st
        }
 }
 
+static unsigned int st_mode_from_ce(const struct cache_entry *ce)
+{
+       extern int trust_executable_bit, has_symlinks;
+
+       switch (ce->ce_mode & S_IFMT) {
+       case S_IFLNK:
+               return has_symlinks ? S_IFLNK : (S_IFREG | 0644);
+       case S_IFREG:
+               return (ce->ce_mode & (trust_executable_bit ? 0755 : 0644)) | S_IFREG;
+       case S_IFGITLINK:
+               return S_IFDIR | 0755;
+       case S_IFDIR:
+               return ce->ce_mode;
+       default:
+               BUG("unsupported ce_mode: %o", ce->ce_mode);
+       }
+}
+
+int fake_lstat(const struct cache_entry *ce, struct stat *st)
+{
+       fake_lstat_data(&ce->ce_stat_data, st);
+       st->st_mode = st_mode_from_ce(ce);
+
+       /* always succeed as lstat() replacement */
+       return 0;
+}
+
 static int ce_compare_data(struct index_state *istate,
                           const struct cache_entry *ce,
                           struct stat *st)
@@ -246,7 +275,8 @@ static int ce_compare_gitlink(const struct cache_entry *ce)
         *
         * If so, we consider it always to match.
         */
-       if (resolve_gitlink_ref(ce->name, "HEAD", &oid) < 0)
+       if (repo_resolve_gitlink_ref(the_repository, ce->name,
+                                    "HEAD", &oid) < 0)
                return 0;
        return !oideq(&oid, &ce->oid);
 }
@@ -311,7 +341,7 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
 
        /* Racily smudged entry? */
        if (!ce->ce_stat_data.sd_size) {
-               if (!is_empty_blob_sha1(ce->oid.hash))
+               if (!is_empty_blob_oid(&ce->oid, the_repository->hash_algo))
                        changed |= DATA_CHANGED;
        }
 
@@ -686,7 +716,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
 
        namelen = strlen(path);
        if (S_ISDIR(st_mode)) {
-               if (resolve_gitlink_ref(path, "HEAD", &oid) < 0)
+               if (repo_resolve_gitlink_ref(the_repository, path, "HEAD", &oid) < 0)
                        return error(_("'%s' does not have a commit checked out"), path);
                while (namelen && path[namelen-1] == '/')
                        namelen--;
@@ -1091,19 +1121,32 @@ static int has_dir_name(struct index_state *istate,
                        istate->cache[istate->cache_nr - 1]->name,
                        &len_eq_last);
                if (cmp_last > 0) {
-                       if (len_eq_last == 0) {
+                       if (name[len_eq_last] != '/') {
                                /*
                                 * The entry sorts AFTER the last one in the
-                                * index and their paths have no common prefix,
-                                * so there cannot be a F/D conflict.
+                                * index.
+                                *
+                                * If there were a conflict with "file", then our
+                                * name would start with "file/" and the last index
+                                * entry would start with "file" but not "file/".
+                                *
+                                * The next character after common prefix is
+                                * not '/', so there can be no conflict.
                                 */
                                return retval;
                        } else {
                                /*
                                 * The entry sorts AFTER the last one in the
-                                * index, but has a common prefix.  Fall through
-                                * to the loop below to disect the entry's path
-                                * and see where the difference is.
+                                * index, and the next character after common
+                                * prefix is '/'.
+                                *
+                                * Either the last index entry is a file in
+                                * conflict with this entry, or it has a name
+                                * which sorts between this entry and the
+                                * potential conflicting file.
+                                *
+                                * In both cases, we fall through to the loop
+                                * below and let the regular search code handle it.
                                 */
                        }
                } else if (cmp_last == 0) {
@@ -1127,53 +1170,6 @@ static int has_dir_name(struct index_state *istate,
                }
                len = slash - name;
 
-               if (cmp_last > 0) {
-                       /*
-                        * (len + 1) is a directory boundary (including
-                        * the trailing slash).  And since the loop is
-                        * decrementing "slash", the first iteration is
-                        * the longest directory prefix; subsequent
-                        * iterations consider parent directories.
-                        */
-
-                       if (len + 1 <= len_eq_last) {
-                               /*
-                                * The directory prefix (including the trailing
-                                * slash) also appears as a prefix in the last
-                                * entry, so the remainder cannot collide (because
-                                * strcmp said the whole path was greater).
-                                *
-                                * EQ: last: xxx/A
-                                *     this: xxx/B
-                                *
-                                * LT: last: xxx/file_A
-                                *     this: xxx/file_B
-                                */
-                               return retval;
-                       }
-
-                       if (len > len_eq_last) {
-                               /*
-                                * This part of the directory prefix (excluding
-                                * the trailing slash) is longer than the known
-                                * equal portions, so this sub-directory cannot
-                                * collide with a file.
-                                *
-                                * GT: last: xxxA
-                                *     this: xxxB/file
-                                */
-                               return retval;
-                       }
-
-                       /*
-                        * This is a possible collision. Fall through and
-                        * let the regular search code handle it.
-                        *
-                        * last: xxx
-                        * this: xxx/file
-                        */
-               }
-
                pos = index_name_stage_pos(istate, name, len, stage, EXPAND_SPARSE);
                if (pos >= 0) {
                        /*
@@ -1736,14 +1732,14 @@ static int verify_hdr(const struct cache_header *hdr, unsigned long size)
 
        end = (unsigned char *)hdr + size;
        start = end - the_hash_algo->rawsz;
-       oidread(&oid, start);
+       oidread(&oid, start, the_repository->hash_algo);
        if (oideq(&oid, null_oid()))
                return 0;
 
        the_hash_algo->init_fn(&c);
        the_hash_algo->update_fn(&c, hdr, size - the_hash_algo->rawsz);
        the_hash_algo->final_fn(hash, &c);
-       if (!hasheq(hash, start))
+       if (!hasheq(hash, start, the_repository->hash_algo))
                return error(_("bad index file sha1 signature"));
        return 0;
 }
@@ -1884,7 +1880,8 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
        ce->ce_flags = flags & ~CE_NAMEMASK;
        ce->ce_namelen = len;
        ce->index = 0;
-       oidread(&ce->oid, (const unsigned char *)ondisk + offsetof(struct ondisk_cache_entry, data));
+       oidread(&ce->oid, (const unsigned char *)ondisk + offsetof(struct ondisk_cache_entry, data),
+               the_repository->hash_algo);
 
        if (expand_name_field) {
                if (copy_len)
@@ -1949,7 +1946,7 @@ static void tweak_untracked_cache(struct index_state *istate)
 
 static void tweak_split_index(struct index_state *istate)
 {
-       switch (git_config_get_split_index()) {
+       switch (repo_config_get_split_index(the_repository)) {
        case -1: /* unset: do nothing */
                break;
        case 0: /* false */
@@ -2257,7 +2254,8 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
        if (verify_hdr(hdr, mmap_size) < 0)
                goto unmap;
 
-       oidread(&istate->oid, (const unsigned char *)hdr + mmap_size - the_hash_algo->rawsz);
+       oidread(&istate->oid, (const unsigned char *)hdr + mmap_size - the_hash_algo->rawsz,
+               the_repository->hash_algo);
        istate->version = ntohl(hdr->hdr_version);
        istate->cache_nr = ntohl(hdr->hdr_entries);
        istate->cache_alloc = alloc_nr(istate->cache_nr);
@@ -2270,7 +2268,7 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
 
        src_offset = sizeof(*hdr);
 
-       if (git_config_get_index_threads(&nr_threads))
+       if (repo_config_get_index_threads(the_repository, &nr_threads))
                nr_threads = 1;
 
        /* TODO: does creating more threads than cores help? */
@@ -2649,7 +2647,7 @@ static void copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
        ondisk->uid  = htonl(ce->ce_stat_data.sd_uid);
        ondisk->gid  = htonl(ce->ce_stat_data.sd_gid);
        ondisk->size = htonl(ce->ce_stat_data.sd_size);
-       hashcpy(ondisk->data, ce->oid.hash);
+       hashcpy(ondisk->data, ce->oid.hash, the_repository->hash_algo);
 
        flags = ce->ce_flags & ~CE_NAMEMASK;
        flags |= (ce_namelen(ce) >= CE_NAMEMASK ? CE_NAMEMASK : ce_namelen(ce));
@@ -2738,7 +2736,7 @@ static int verify_index_from(const struct index_state *istate, const char *path)
        if (n != the_hash_algo->rawsz)
                goto out;
 
-       if (!hasheq(istate->oid.hash, hash))
+       if (!hasheq(istate->oid.hash, hash, the_repository->hash_algo))
                goto out;
 
        close(fd);
@@ -2790,7 +2788,7 @@ static int record_eoie(void)
         * used for threading is written by default if the user
         * explicitly requested threaded index reads.
         */
-       return !git_config_get_index_threads(&val) && val != 1;
+       return !repo_config_get_index_threads(the_repository, &val) && val != 1;
 }
 
 static int record_ieot(void)
@@ -2805,7 +2803,7 @@ static int record_ieot(void)
         * written by default if the user explicitly requested
         * threaded index reads.
         */
-       return !git_config_get_index_threads(&val) && val != 1;
+       return !repo_config_get_index_threads(the_repository, &val) && val != 1;
 }
 
 enum write_extensions {
@@ -2843,8 +2841,9 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
        int csum_fsync_flag;
        int ieot_entries = 1;
        struct index_entry_offset_table *ieot = NULL;
-       int nr, nr_threads;
        struct repository *r = istate->repo;
+       struct strbuf sb = STRBUF_INIT;
+       int nr, nr_threads, ret;
 
        f = hashfd(tempfile->fd, tempfile->filename.buf);
 
@@ -2878,7 +2877,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
 
        hashwrite(f, &hdr, sizeof(hdr));
 
-       if (!HAVE_THREADS || git_config_get_index_threads(&nr_threads))
+       if (!HAVE_THREADS || repo_config_get_index_threads(the_repository, &nr_threads))
                nr_threads = 1;
 
        if (nr_threads != 1 && record_ieot()) {
@@ -2965,8 +2964,8 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
        strbuf_release(&previous_name_buf);
 
        if (err) {
-               free(ieot);
-               return err;
+               ret = err;
+               goto out;
        }
 
        offset = hashfile_total(f);
@@ -2988,20 +2987,20 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
         * index.
         */
        if (ieot) {
-               struct strbuf sb = STRBUF_INIT;
+               strbuf_reset(&sb);
 
                write_ieot_extension(&sb, ieot);
                err = write_index_ext_header(f, eoie_c, CACHE_EXT_INDEXENTRYOFFSETTABLE, sb.len) < 0;
                hashwrite(f, sb.buf, sb.len);
-               strbuf_release(&sb);
-               free(ieot);
-               if (err)
-                       return -1;
+               if (err) {
+                       ret = -1;
+                       goto out;
+               }
        }
 
        if (write_extensions & WRITE_SPLIT_INDEX_EXTENSION &&
            istate->split_index) {
-               struct strbuf sb = STRBUF_INIT;
+               strbuf_reset(&sb);
 
                if (istate->sparse_index)
                        die(_("cannot write split index for a sparse index"));
@@ -3010,59 +3009,66 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
                        write_index_ext_header(f, eoie_c, CACHE_EXT_LINK,
                                               sb.len) < 0;
                hashwrite(f, sb.buf, sb.len);
-               strbuf_release(&sb);
-               if (err)
-                       return -1;
+               if (err) {
+                       ret = -1;
+                       goto out;
+               }
        }
        if (write_extensions & WRITE_CACHE_TREE_EXTENSION &&
            !drop_cache_tree && istate->cache_tree) {
-               struct strbuf sb = STRBUF_INIT;
+               strbuf_reset(&sb);
 
                cache_tree_write(&sb, istate->cache_tree);
                err = write_index_ext_header(f, eoie_c, CACHE_EXT_TREE, sb.len) < 0;
                hashwrite(f, sb.buf, sb.len);
-               strbuf_release(&sb);
-               if (err)
-                       return -1;
+               if (err) {
+                       ret = -1;
+                       goto out;
+               }
        }
        if (write_extensions & WRITE_RESOLVE_UNDO_EXTENSION &&
            istate->resolve_undo) {
-               struct strbuf sb = STRBUF_INIT;
+               strbuf_reset(&sb);
 
                resolve_undo_write(&sb, istate->resolve_undo);
                err = write_index_ext_header(f, eoie_c, CACHE_EXT_RESOLVE_UNDO,
                                             sb.len) < 0;
                hashwrite(f, sb.buf, sb.len);
-               strbuf_release(&sb);
-               if (err)
-                       return -1;
+               if (err) {
+                       ret = -1;
+                       goto out;
+               }
        }
        if (write_extensions & WRITE_UNTRACKED_CACHE_EXTENSION &&
            istate->untracked) {
-               struct strbuf sb = STRBUF_INIT;
+               strbuf_reset(&sb);
 
                write_untracked_extension(&sb, istate->untracked);
                err = write_index_ext_header(f, eoie_c, CACHE_EXT_UNTRACKED,
                                             sb.len) < 0;
                hashwrite(f, sb.buf, sb.len);
-               strbuf_release(&sb);
-               if (err)
-                       return -1;
+               if (err) {
+                       ret = -1;
+                       goto out;
+               }
        }
        if (write_extensions & WRITE_FSMONITOR_EXTENSION &&
            istate->fsmonitor_last_update) {
-               struct strbuf sb = STRBUF_INIT;
+               strbuf_reset(&sb);
 
                write_fsmonitor_extension(&sb, istate);
                err = write_index_ext_header(f, eoie_c, CACHE_EXT_FSMONITOR, sb.len) < 0;
                hashwrite(f, sb.buf, sb.len);
-               strbuf_release(&sb);
-               if (err)
-                       return -1;
+               if (err) {
+                       ret = -1;
+                       goto out;
+               }
        }
        if (istate->sparse_index) {
-               if (write_index_ext_header(f, eoie_c, CACHE_EXT_SPARSE_DIRECTORIES, 0) < 0)
-                       return -1;
+               if (write_index_ext_header(f, eoie_c, CACHE_EXT_SPARSE_DIRECTORIES, 0) < 0) {
+                       ret = -1;
+                       goto out;
+               }
        }
 
        /*
@@ -3072,14 +3078,15 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
         * when loading the shared index.
         */
        if (eoie_c) {
-               struct strbuf sb = STRBUF_INIT;
+               strbuf_reset(&sb);
 
                write_eoie_extension(&sb, eoie_c, offset);
                err = write_index_ext_header(f, NULL, CACHE_EXT_ENDOFINDEXENTRIES, sb.len) < 0;
                hashwrite(f, sb.buf, sb.len);
-               strbuf_release(&sb);
-               if (err)
-                       return -1;
+               if (err) {
+                       ret = -1;
+                       goto out;
+               }
        }
 
        csum_fsync_flag = 0;
@@ -3088,13 +3095,16 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
 
        finalize_hashfile(f, istate->oid.hash, FSYNC_COMPONENT_INDEX,
                          CSUM_HASH_IN_STREAM | csum_fsync_flag);
+       f = NULL;
 
        if (close_tempfile_gently(tempfile)) {
-               error(_("could not close '%s'"), get_tempfile_path(tempfile));
-               return -1;
+               ret = error(_("could not close '%s'"), get_tempfile_path(tempfile));
+               goto out;
+       }
+       if (stat(get_tempfile_path(tempfile), &st)) {
+               ret = -1;
+               goto out;
        }
-       if (stat(get_tempfile_path(tempfile), &st))
-               return -1;
        istate->timestamp.sec = (unsigned int)st.st_mtime;
        istate->timestamp.nsec = ST_MTIME_NSEC(st);
        trace_performance_since(start, "write index, changed mask = %x", istate->cache_changed);
@@ -3108,7 +3118,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
        trace2_data_intmax("index", the_repository, "write/cache_nr",
                           istate->cache_nr);
 
-       return 0;
+       ret = 0;
+
+out:
+       if (f)
+               free_hashfile(f);
+       strbuf_release(&sb);
+       free(ieot);
+       return ret;
 }
 
 void set_alternate_index_output(const char *name)
@@ -3159,9 +3176,9 @@ static int do_write_locked_index(struct index_state *istate,
        else
                ret = close_lock_file_gently(lock);
 
-       run_hooks_l("post-index-change",
-                       istate->updated_workdir ? "1" : "0",
-                       istate->updated_skipworktree ? "1" : "0", NULL);
+       run_hooks_l(the_repository, "post-index-change",
+                   istate->updated_workdir ? "1" : "0",
+                   istate->updated_skipworktree ? "1" : "0", NULL);
        istate->updated_workdir = 0;
        istate->updated_skipworktree = 0;
 
@@ -3179,18 +3196,24 @@ static int write_split_index(struct index_state *istate,
        return ret;
 }
 
-static const char *shared_index_expire = "2.weeks.ago";
-
 static unsigned long get_shared_index_expire_date(void)
 {
        static unsigned long shared_index_expire_date;
        static int shared_index_expire_date_prepared;
 
        if (!shared_index_expire_date_prepared) {
-               git_config_get_expiry("splitindex.sharedindexexpire",
-                                     &shared_index_expire);
+               const char *shared_index_expire = "2.weeks.ago";
+               char *value = NULL;
+
+               repo_config_get_expiry(the_repository, "splitindex.sharedindexexpire",
+                                      &value);
+               if (value)
+                       shared_index_expire = value;
+
                shared_index_expire_date = approxidate(shared_index_expire);
                shared_index_expire_date_prepared = 1;
+
+               free(value);
        }
 
        return shared_index_expire_date;
@@ -3216,10 +3239,11 @@ static int should_delete_shared_index(const char *shared_index_path)
 static int clean_shared_index_files(const char *current_hex)
 {
        struct dirent *de;
-       DIR *dir = opendir(get_git_dir());
+       DIR *dir = opendir(repo_get_git_dir(the_repository));
 
        if (!dir)
-               return error_errno(_("unable to open git dir: %s"), get_git_dir());
+               return error_errno(_("unable to open git dir: %s"),
+                                  repo_get_git_dir(the_repository));
 
        while ((de = readdir(dir)) != NULL) {
                const char *sha1_hex;
@@ -3278,7 +3302,7 @@ static const int default_max_percent_split_change = 20;
 static int too_many_not_shared_entries(struct index_state *istate)
 {
        int i, not_shared = 0;
-       int max_split = git_config_get_max_percent_split_change();
+       int max_split = repo_config_get_max_percent_split_change(the_repository);
 
        switch (max_split) {
        case -1:
@@ -3611,7 +3635,7 @@ static size_t read_eoie_extension(const char *mmap, size_t mmap_size)
                src_offset += extsize;
        }
        the_hash_algo->final_fn(hash, &c);
-       if (!hasheq(hash, (const unsigned char *)index))
+       if (!hasheq(hash, (const unsigned char *)index, the_repository->hash_algo))
                return 0;
 
        /* Validate that the extension offsets returned us back to the eoie extension. */
@@ -3933,8 +3957,8 @@ static void update_callback(struct diff_queue_struct *q,
 }
 
 int add_files_to_cache(struct repository *repo, const char *prefix,
-                      const struct pathspec *pathspec, int include_sparse,
-                      int flags)
+                      const struct pathspec *pathspec, char *ps_matched,
+                      int include_sparse, int flags)
 {
        struct update_callback_data data;
        struct rev_info rev;
@@ -3946,8 +3970,10 @@ int add_files_to_cache(struct repository *repo, const char *prefix,
 
        repo_init_revisions(repo, &rev, prefix);
        setup_revisions(0, NULL, &rev, NULL);
-       if (pathspec)
+       if (pathspec) {
                copy_pathspec(&rev.prune_data, pathspec);
+               rev.ps_matched = ps_matched;
+       }
        rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
        rev.diffopt.format_callback = update_callback;
        rev.diffopt.format_callback_data = &data;