Move index-related variables into a structure.
[gitweb.git] / read-cache.c
index 823c2c3b08e559a5b0a29dc30c00772301b8cb79..9b4385ea5cfd23ac07b460557cf296650983794d 100644 (file)
@@ -5,6 +5,7 @@
  */
 #include "cache.h"
 #include "cache-tree.h"
+#include "refs.h"
 
 /* Index extensions.
  *
 #define CACHE_EXT(s) ( (s[0]<<24)|(s[1]<<16)|(s[2]<<8)|(s[3]) )
 #define CACHE_EXT_TREE 0x54524545      /* "TREE" */
 
-struct cache_entry **active_cache;
-static time_t index_file_timestamp;
-unsigned int active_nr, active_alloc, active_cache_changed;
-
-struct cache_tree *active_cache_tree;
-
-int cache_errno;
-
-static void *cache_mmap;
-static size_t cache_mmap_size;
+struct index_state the_index;
+#define index_file_timestamp (the_index.timestamp)
+#define cache_mmap (the_index.mmap)
+#define cache_mmap_size (the_index.mmap_size)
 
 /*
  * This only updates the "non-critical" parts of the directory
@@ -93,6 +88,23 @@ static int ce_compare_link(struct cache_entry *ce, size_t expected_size)
        return match;
 }
 
+static int ce_compare_gitlink(struct cache_entry *ce)
+{
+       unsigned char sha1[20];
+
+       /*
+        * We don't actually require that the .git directory
+        * under DIRLNK directory be a valid git directory. It
+        * might even be missing (in case nobody populated that
+        * sub-project).
+        *
+        * If so, we consider it always to match.
+        */
+       if (resolve_gitlink_ref(ce->name, "HEAD", sha1) < 0)
+               return 0;
+       return hashcmp(sha1, ce->sha1);
+}
+
 static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st)
 {
        switch (st->st_mode & S_IFMT) {
@@ -104,6 +116,9 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st)
                if (ce_compare_link(ce, xsize_t(st->st_size)))
                        return DATA_CHANGED;
                break;
+       case S_IFDIR:
+               if (S_ISDIRLNK(ntohl(ce->ce_mode)))
+                       return 0;
        default:
                return TYPE_CHANGED;
        }
@@ -129,6 +144,12 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
                    (has_symlinks || !S_ISREG(st->st_mode)))
                        changed |= TYPE_CHANGED;
                break;
+       case S_IFDIRLNK:
+               if (!S_ISDIR(st->st_mode))
+                       changed |= TYPE_CHANGED;
+               else if (ce_compare_gitlink(ce))
+                       changed |= DATA_CHANGED;
+               return changed;
        default:
                die("internal error: ce_mode is %o", ntohl(ce->ce_mode));
        }
@@ -327,7 +348,7 @@ int remove_file_from_cache(const char *path)
        return 0;
 }
 
-int add_file_to_index(const char *path, int verbose)
+int add_file_to_cache(const char *path, int verbose)
 {
        int size, namelen;
        struct stat st;
@@ -336,10 +357,14 @@ int add_file_to_index(const char *path, int verbose)
        if (lstat(path, &st))
                die("%s: unable to stat (%s)", path, strerror(errno));
 
-       if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
-               die("%s: can only add regular files or symbolic links", path);
+       if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
+               die("%s: can only add regular files, symbolic links or git-directories", path);
 
        namelen = strlen(path);
+       if (S_ISDIR(st.st_mode)) {
+               while (namelen && path[namelen-1] == '/')
+                       namelen--;
+       }
        size = cache_entry_size(namelen);
        ce = xcalloc(1, size);
        memcpy(ce->name, path, namelen);
@@ -665,14 +690,15 @@ int add_cache_entry(struct cache_entry *ce, int option)
  * For example, you'd want to do this after doing a "git-read-tree",
  * to link up the stat cache details with the proper files.
  */
-struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
+static struct cache_entry *refresh_cache_ent(struct cache_entry *ce, int really, int *err)
 {
        struct stat st;
        struct cache_entry *updated;
        int changed, size;
 
        if (lstat(ce->name, &st) < 0) {
-               cache_errno = errno;
+               if (err)
+                       *err = errno;
                return NULL;
        }
 
@@ -686,7 +712,8 @@ struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
        }
 
        if (ce_modified(ce, &st, really)) {
-               cache_errno = EINVAL;
+               if (err)
+                       *err = EINVAL;
                return NULL;
        }
 
@@ -718,6 +745,8 @@ int refresh_cache(unsigned int flags)
 
        for (i = 0; i < active_nr; i++) {
                struct cache_entry *ce, *new;
+               int cache_errno = 0;
+
                ce = active_cache[i];
                if (ce_stage(ce)) {
                        while ((i < active_nr) &&
@@ -731,7 +760,7 @@ int refresh_cache(unsigned int flags)
                        continue;
                }
 
-               new = refresh_cache_entry(ce, really);
+               new = refresh_cache_ent(ce, really, &cache_errno);
                if (new == ce)
                        continue;
                if (!new) {
@@ -759,6 +788,11 @@ int refresh_cache(unsigned int flags)
        return has_errors;
 }
 
+struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
+{
+       return refresh_cache_ent(ce, really, NULL);
+}
+
 static int verify_hdr(struct cache_header *hdr, unsigned long size)
 {
        SHA_CTX c;