Extend index to save more flags
[gitweb.git] / read-cache.c
index 276b09e66f603fa3816640a0f692775c5e15ba32..ea262fc37e2eb38da4bfbe507989867f9e68393a 100644 (file)
@@ -608,8 +608,10 @@ struct cache_entry *make_cache_entry(unsigned int mode,
        int size, len;
        struct cache_entry *ce;
 
-       if (!verify_path(path))
+       if (!verify_path(path)) {
+               error("Invalid path '%s'", path);
                return NULL;
+       }
 
        len = strlen(path);
        size = cache_entry_size(len);
@@ -893,7 +895,7 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
        if (!ok_to_add)
                return -1;
        if (!verify_path(ce->name))
-               return -1;
+               return error("Invalid path '%s'", ce->name);
 
        if (!skip_df_check &&
            check_file_directory_conflict(istate, ce, pos, ok_to_replace)) {
@@ -1091,16 +1093,16 @@ struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
 
 static int verify_hdr(struct cache_header *hdr, unsigned long size)
 {
-       SHA_CTX c;
+       git_SHA_CTX c;
        unsigned char sha1[20];
 
        if (hdr->hdr_signature != htonl(CACHE_SIGNATURE))
                return error("bad signature");
-       if (hdr->hdr_version != htonl(2))
+       if (hdr->hdr_version != htonl(2) && hdr->hdr_version != htonl(3))
                return error("bad index version");
-       SHA1_Init(&c);
-       SHA1_Update(&c, hdr, size - 20);
-       SHA1_Final(sha1, &c);
+       git_SHA1_Init(&c);
+       git_SHA1_Update(&c, hdr, size - 20);
+       git_SHA1_Final(sha1, &c);
        if (hashcmp(sha1, (unsigned char *)hdr + size - 20))
                return error("bad index file sha1 signature");
        return 0;
@@ -1131,6 +1133,7 @@ int read_index(struct index_state *istate)
 static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_entry *ce)
 {
        size_t len;
+       const char *name;
 
        ce->ce_ctime = ntohl(ondisk->ctime.sec);
        ce->ce_mtime = ntohl(ondisk->mtime.sec);
@@ -1143,19 +1146,31 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en
        /* On-disk flags are just 16 bits */
        ce->ce_flags = ntohs(ondisk->flags);
 
-       /* For future extension: we do not understand this entry yet */
-       if (ce->ce_flags & CE_EXTENDED)
-               die("Unknown index entry format");
        hashcpy(ce->sha1, ondisk->sha1);
 
        len = ce->ce_flags & CE_NAMEMASK;
+
+       if (ce->ce_flags & CE_EXTENDED) {
+               struct ondisk_cache_entry_extended *ondisk2;
+               int extended_flags;
+               ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
+               extended_flags = ntohs(ondisk2->flags2) << 16;
+               /* We do not yet understand any bit out of CE_EXTENDED_FLAGS */
+               if (extended_flags & ~CE_EXTENDED_FLAGS)
+                       die("Unknown index entry format %08x", extended_flags);
+               ce->ce_flags |= extended_flags;
+               name = ondisk2->name;
+       }
+       else
+               name = ondisk->name;
+
        if (len == CE_NAMEMASK)
-               len = strlen(ondisk->name);
+               len = strlen(name);
        /*
         * NEEDSWORK: If the original index is crafted, this copy could
         * go unchecked.
         */
-       memcpy(ce->name, ondisk->name, len + 1);
+       memcpy(ce->name, name, len + 1);
 }
 
 static inline size_t estimate_cache_size(size_t ondisk_size, unsigned int entries)
@@ -1272,6 +1287,7 @@ int discard_index(struct index_state *istate)
        istate->cache_nr = 0;
        istate->cache_changed = 0;
        istate->timestamp = 0;
+       istate->name_hash_initialized = 0;
        free_hash(&istate->name_hash);
        cache_tree_free(&(istate->cache_tree));
        free(istate->alloc);
@@ -1296,11 +1312,11 @@ int unmerged_index(const struct index_state *istate)
 static unsigned char write_buffer[WRITE_BUFFER_SIZE];
 static unsigned long write_buffer_len;
 
-static int ce_write_flush(SHA_CTX *context, int fd)
+static int ce_write_flush(git_SHA_CTX *context, int fd)
 {
        unsigned int buffered = write_buffer_len;
        if (buffered) {
-               SHA1_Update(context, write_buffer, buffered);
+               git_SHA1_Update(context, write_buffer, buffered);
                if (write_in_full(fd, write_buffer, buffered) != buffered)
                        return -1;
                write_buffer_len = 0;
@@ -1308,7 +1324,7 @@ static int ce_write_flush(SHA_CTX *context, int fd)
        return 0;
 }
 
-static int ce_write(SHA_CTX *context, int fd, void *data, unsigned int len)
+static int ce_write(git_SHA_CTX *context, int fd, void *data, unsigned int len)
 {
        while (len) {
                unsigned int buffered = write_buffer_len;
@@ -1330,7 +1346,7 @@ static int ce_write(SHA_CTX *context, int fd, void *data, unsigned int len)
        return 0;
 }
 
-static int write_index_ext_header(SHA_CTX *context, int fd,
+static int write_index_ext_header(git_SHA_CTX *context, int fd,
                                  unsigned int ext, unsigned int sz)
 {
        ext = htonl(ext);
@@ -1339,13 +1355,13 @@ static int write_index_ext_header(SHA_CTX *context, int fd,
                (ce_write(context, fd, &sz, 4) < 0)) ? -1 : 0;
 }
 
-static int ce_flush(SHA_CTX *context, int fd)
+static int ce_flush(git_SHA_CTX *context, int fd)
 {
        unsigned int left = write_buffer_len;
 
        if (left) {
                write_buffer_len = 0;
-               SHA1_Update(context, write_buffer, left);
+               git_SHA1_Update(context, write_buffer, left);
        }
 
        /* Flush first if not enough space for SHA1 signature */
@@ -1356,7 +1372,7 @@ static int ce_flush(SHA_CTX *context, int fd)
        }
 
        /* Append the SHA1 signature at the end */
-       SHA1_Final(write_buffer + left, context);
+       git_SHA1_Final(write_buffer + left, context);
        left += 20;
        return (write_in_full(fd, write_buffer, left) != left) ? -1 : 0;
 }
@@ -1410,10 +1426,11 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
        }
 }
 
-static int ce_write_entry(SHA_CTX *c, int fd, struct cache_entry *ce)
+static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce)
 {
        int size = ondisk_ce_size(ce);
        struct ondisk_cache_entry *ondisk = xcalloc(1, size);
+       char *name;
 
        ondisk->ctime.sec = htonl(ce->ce_ctime);
        ondisk->ctime.nsec = 0;
@@ -1427,28 +1444,45 @@ static int ce_write_entry(SHA_CTX *c, int fd, struct cache_entry *ce)
        ondisk->size = htonl(ce->ce_size);
        hashcpy(ondisk->sha1, ce->sha1);
        ondisk->flags = htons(ce->ce_flags);
-       memcpy(ondisk->name, ce->name, ce_namelen(ce));
+       if (ce->ce_flags & CE_EXTENDED) {
+               struct ondisk_cache_entry_extended *ondisk2;
+               ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
+               ondisk2->flags2 = htons((ce->ce_flags & CE_EXTENDED_FLAGS) >> 16);
+               name = ondisk2->name;
+       }
+       else
+               name = ondisk->name;
+       memcpy(name, ce->name, ce_namelen(ce));
 
        return ce_write(c, fd, ondisk, size);
 }
 
 int write_index(const struct index_state *istate, int newfd)
 {
-       SHA_CTX c;
+       git_SHA_CTX c;
        struct cache_header hdr;
-       int i, err, removed;
+       int i, err, removed, extended;
        struct cache_entry **cache = istate->cache;
        int entries = istate->cache_nr;
 
-       for (i = removed = 0; i < entries; i++)
+       for (i = removed = extended = 0; i < entries; i++) {
                if (cache[i]->ce_flags & CE_REMOVE)
                        removed++;
 
+               /* reduce extended entries if possible */
+               cache[i]->ce_flags &= ~CE_EXTENDED;
+               if (cache[i]->ce_flags & CE_EXTENDED_FLAGS) {
+                       extended++;
+                       cache[i]->ce_flags |= CE_EXTENDED;
+               }
+       }
+
        hdr.hdr_signature = htonl(CACHE_SIGNATURE);
-       hdr.hdr_version = htonl(2);
+       /* for extended format, increase version so older git won't try to read it */
+       hdr.hdr_version = htonl(extended ? 3 : 2);
        hdr.hdr_entries = htonl(entries - removed);
 
-       SHA1_Init(&c);
+       git_SHA1_Init(&c);
        if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
                return -1;
 
@@ -1464,9 +1498,8 @@ int write_index(const struct index_state *istate, int newfd)
 
        /* Write extension data here */
        if (istate->cache_tree) {
-               struct strbuf sb;
+               struct strbuf sb = STRBUF_INIT;
 
-               strbuf_init(&sb, 0);
                cache_tree_write(&sb, istate->cache_tree);
                err = write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sb.len) < 0
                        || ce_write(&c, newfd, sb.buf, sb.len) < 0;