Add copyright notice of Rene Scharfe to tar-tree.c
[git.git] / read-cache.c
index bfa2de7..a6fbf08 100644 (file)
@@ -7,12 +7,25 @@
 #include "cache.h"
 
 struct cache_entry **active_cache = NULL;
-unsigned int active_nr = 0, active_alloc = 0;
+unsigned int active_nr = 0, active_alloc = 0, active_cache_changed = 0;
 
 int cache_match_stat(struct cache_entry *ce, struct stat *st)
 {
        unsigned int changed = 0;
 
+       switch (ntohl(ce->ce_mode) & S_IFMT) {
+       case S_IFREG:
+               changed |= !S_ISREG(st->st_mode) ? TYPE_CHANGED : 0;
+               /* We consider only the owner x bit to be relevant for "mode changes" */
+               if (0100 & (ntohl(ce->ce_mode) ^ st->st_mode))
+                       changed |= MODE_CHANGED;
+               break;
+       case S_IFLNK:
+               changed |= !S_ISLNK(st->st_mode) ? TYPE_CHANGED : 0;
+               break;
+       default:
+               die("internal error: ce_mode is %o", ntohl(ce->ce_mode));
+       }
        if (ce->ce_mtime.sec != htonl(st->st_mtime))
                changed |= MTIME_CHANGED;
        if (ce->ce_ctime.sec != htonl(st->st_ctime))
@@ -24,18 +37,15 @@ int cache_match_stat(struct cache_entry *ce, struct stat *st)
         * as long as it is in the inode cache you get right nsec
         * but after it gets flushed, you get zero nsec.
         */
-       if (ce->ce_mtime.nsec != htonl(st->st_mtim.tv_nsec)
+       if (ce->ce_mtime.nsec != htonl(st->st_mtim.tv_nsec))
                changed |= MTIME_CHANGED;
-       if (ce->ce_ctime.nsec != htonl(st->st_ctim.tv_nsec)
+       if (ce->ce_ctime.nsec != htonl(st->st_ctim.tv_nsec))
                changed |= CTIME_CHANGED;
 #endif 
 
        if (ce->ce_uid != htonl(st->st_uid) ||
            ce->ce_gid != htonl(st->st_gid))
                changed |= OWNER_CHANGED;
-       /* We consider only the owner x bit to be relevant for "mode changes" */
-       if (0100 & (ntohl(ce->ce_mode) ^ st->st_mode))
-               changed |= MODE_CHANGED;
        if (ce->ce_dev != htonl(st->st_dev) ||
            ce->ce_ino != htonl(st->st_ino))
                changed |= INODE_CHANGED;
@@ -87,8 +97,9 @@ int cache_name_pos(const char *name, int namelen)
 }
 
 /* Remove entry, return true if there are more entries to go.. */
-static int remove_entry_at(int pos)
+int remove_entry_at(int pos)
 {
+       active_cache_changed = 1;
        active_nr--;
        if (pos >= active_nr)
                return 0;
@@ -106,7 +117,7 @@ int remove_file_from_cache(char *path)
        return 0;
 }
 
-static int same_name(struct cache_entry *a, struct cache_entry *b)
+int same_name(struct cache_entry *a, struct cache_entry *b)
 {
        int len = ce_namelen(a);
        return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
@@ -120,6 +131,7 @@ int add_cache_entry(struct cache_entry *ce, int ok_to_add)
 
        /* existing match? Just replace it */
        if (pos >= 0) {
+               active_cache_changed = 1;
                active_cache[pos] = ce;
                return 0;
        }
@@ -143,7 +155,7 @@ int add_cache_entry(struct cache_entry *ce, int ok_to_add)
        /* Make sure the array is big enough .. */
        if (active_nr == active_alloc) {
                active_alloc = alloc_nr(active_alloc);
-               active_cache = realloc(active_cache, active_alloc * sizeof(struct cache_entry *));
+               active_cache = xrealloc(active_cache, active_alloc * sizeof(struct cache_entry *));
        }
 
        /* Add it in.. */
@@ -151,6 +163,7 @@ int add_cache_entry(struct cache_entry *ce, int ok_to_add)
        if (active_nr > pos)
                memmove(active_cache + pos + 1, active_cache + pos, (active_nr - pos - 1) * sizeof(ce));
        active_cache[pos] = ce;
+       active_cache_changed = 1;
        return 0;
 }
 
@@ -161,14 +174,13 @@ static int verify_hdr(struct cache_header *hdr, unsigned long size)
 
        if (hdr->hdr_signature != htonl(CACHE_SIGNATURE))
                return error("bad signature");
-       if (hdr->hdr_version != htonl(1))
-               return error("bad version");
+       if (hdr->hdr_version != htonl(2))
+               return error("bad index version");
        SHA1_Init(&c);
-       SHA1_Update(&c, hdr, offsetof(struct cache_header, sha1));
-       SHA1_Update(&c, hdr+1, size - sizeof(*hdr));
+       SHA1_Update(&c, hdr, size - 20);
        SHA1_Final(sha1, &c);
-       if (memcmp(sha1, hdr->sha1, 20))
-               return error("bad header sha1");
+       if (memcmp(sha1, (void *)hdr + size - 20, 20))
+               return error("bad index file sha1 signature");
        return 0;
 }
 
@@ -184,12 +196,7 @@ int read_cache(void)
        if (active_cache)
                return error("more than one cachefile");
        errno = ENOENT;
-       sha1_file_directory = getenv(DB_ENVIRONMENT);
-       if (!sha1_file_directory)
-               sha1_file_directory = DEFAULT_DB_ENVIRONMENT;
-       if (access(sha1_file_directory, X_OK) < 0)
-               return error("no access to SHA1 file directory");
-       fd = open(".git/index", O_RDONLY);
+       fd = open(get_index_file(), O_RDONLY);
        if (fd < 0)
                return (errno == ENOENT) ? 0 : error("open failed");
 
@@ -198,8 +205,8 @@ int read_cache(void)
        if (!fstat(fd, &st)) {
                size = st.st_size;
                errno = EINVAL;
-               if (size >= sizeof(struct cache_header))
-                       map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+               if (size >= sizeof(struct cache_header) + 20)
+                       map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
        }
        close(fd);
        if (-1 == (int)(long)map)
@@ -227,6 +234,49 @@ unmap:
        return error("verify header failed");
 }
 
+#define WRITE_BUFFER_SIZE 8192
+static char write_buffer[WRITE_BUFFER_SIZE];
+static unsigned long write_buffer_len;
+
+static int ce_write(SHA_CTX *context, int fd, void *data, unsigned int len)
+{
+       while (len) {
+               unsigned int buffered = write_buffer_len;
+               unsigned int partial = WRITE_BUFFER_SIZE - buffered;
+               if (partial > len)
+                       partial = len;
+               memcpy(write_buffer + buffered, data, partial);
+               buffered += partial;
+               if (buffered == WRITE_BUFFER_SIZE) {
+                       SHA1_Update(context, write_buffer, WRITE_BUFFER_SIZE);
+                       if (write(fd, write_buffer, WRITE_BUFFER_SIZE) != WRITE_BUFFER_SIZE)
+                               return -1;
+                       buffered = 0;
+               }
+               write_buffer_len = buffered;
+               len -= partial;
+               data += partial;
+       }
+       return 0;
+}
+
+static int ce_flush(SHA_CTX *context, int fd)
+{
+       unsigned int left = write_buffer_len;
+
+       if (left) {
+               write_buffer_len = 0;
+               SHA1_Update(context, write_buffer, left);
+       }
+
+       /* Append the SHA1 signature at the end */
+       SHA1_Final(write_buffer + left, context);
+       left += 20;
+       if (write(fd, write_buffer, left) != left)
+               return -1;
+       return 0;
+}
+
 int write_cache(int newfd, struct cache_entry **cache, int entries)
 {
        SHA_CTX c;
@@ -234,26 +284,17 @@ int write_cache(int newfd, struct cache_entry **cache, int entries)
        int i;
 
        hdr.hdr_signature = htonl(CACHE_SIGNATURE);
-       hdr.hdr_version = htonl(1);
+       hdr.hdr_version = htonl(2);
        hdr.hdr_entries = htonl(entries);
 
        SHA1_Init(&c);
-       SHA1_Update(&c, &hdr, offsetof(struct cache_header, sha1));
-       for (i = 0; i < entries; i++) {
-               struct cache_entry *ce = cache[i];
-               int size = ce_size(ce);
-               SHA1_Update(&c, ce, size);
-       }
-       SHA1_Final(hdr.sha1, &c);
-
-       if (write(newfd, &hdr, sizeof(hdr)) != sizeof(hdr))
+       if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
                return -1;
 
        for (i = 0; i < entries; i++) {
                struct cache_entry *ce = cache[i];
-               int size = ce_size(ce);
-               if (write(newfd, ce, size) != size)
+               if (ce_write(&c, newfd, ce, ce_size(ce)) < 0)
                        return -1;
        }
-       return 0;
+       return ce_flush(&c, newfd);
 }