gitweb: Secure against commit-ish/tree-ish with the same name as path
[gitweb.git] / read-cache.c
index 3228ffb3001fa360dbd4f5a0907fd0b204382423..97c38670b45d852b2f07f3d3addb2aaf6dbd8697 100644 (file)
@@ -5,7 +5,6 @@
  */
 #include "cache.h"
 #include "cache-tree.h"
-#include <time.h>
 
 /* Index extensions.
  *
@@ -61,7 +60,7 @@ static int ce_compare_data(struct cache_entry *ce, struct stat *st)
        if (fd >= 0) {
                unsigned char sha1[20];
                if (!index_fd(sha1, fd, st, 0, NULL))
-                       match = memcmp(sha1, ce->sha1, 20);
+                       match = hashcmp(sha1, ce->sha1);
                /* index_fd() closed the file descriptor already */
        }
        return match;
@@ -170,9 +169,11 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
        return changed;
 }
 
-int ce_match_stat(struct cache_entry *ce, struct stat *st, int ignore_valid)
+int ce_match_stat(struct cache_entry *ce, struct stat *st, int options)
 {
        unsigned int changed;
+       int ignore_valid = options & 01;
+       int assume_racy_is_modified = options & 02;
 
        /*
         * If it's marked as always valid in the index, it's
@@ -201,8 +202,12 @@ int ce_match_stat(struct cache_entry *ce, struct stat *st, int ignore_valid)
         */
        if (!changed &&
            index_file_timestamp &&
-           index_file_timestamp <= ntohl(ce->ce_mtime.sec))
-               changed |= ce_modified_check_fs(ce, st);
+           index_file_timestamp <= ntohl(ce->ce_mtime.sec)) {
+               if (assume_racy_is_modified)
+                       changed |= DATA_CHANGED;
+               else
+                       changed |= ce_modified_check_fs(ce, st);
+       }
 
        return changed;
 }
@@ -342,11 +347,13 @@ int add_file_to_index(const char *path, int verbose)
        ce->ce_mode = create_ce_mode(st.st_mode);
        if (!trust_executable_bit) {
                /* If there is an existing entry, pick the mode bits
-                * from it.
+                * from it, otherwise force to 644.
                 */
                int pos = cache_name_pos(path, namelen);
                if (pos >= 0)
                        ce->ce_mode = active_cache[pos]->ce_mode;
+               else
+                       ce->ce_mode = create_ce_mode(S_IFREG | 0644);
        }
 
        if (index_path(ce->sha1, path, &st, 1))
@@ -739,7 +746,7 @@ static int verify_hdr(struct cache_header *hdr, unsigned long size)
        SHA1_Init(&c);
        SHA1_Update(&c, hdr, size - 20);
        SHA1_Final(sha1, &c);
-       if (memcmp(sha1, (char *) hdr + size - 20, 20))
+       if (hashcmp(sha1, (unsigned char *)hdr + size - 20))
                return error("bad index file sha1 signature");
        return 0;
 }
@@ -837,6 +844,23 @@ int read_cache_from(const char *path)
        die("index file corrupt");
 }
 
+int discard_cache()
+{
+       int ret;
+
+       active_nr = active_cache_changed = 0;
+       index_file_timestamp = 0;
+       cache_tree_free(&active_cache_tree);
+       if (cache_mmap == NULL)
+               return 0;
+       ret = munmap(cache_mmap, cache_mmap_size);
+       cache_mmap = NULL;
+       cache_mmap_size = 0;
+
+       /* no need to throw away allocated active_cache */
+       return ret;
+}
+
 #define WRITE_BUFFER_SIZE 8192
 static unsigned char write_buffer[WRITE_BUFFER_SIZE];
 static unsigned long write_buffer_len;
@@ -954,9 +978,7 @@ int write_cache(int newfd, struct cache_entry **cache, int entries)
 {
        SHA_CTX c;
        struct cache_header hdr;
-       int i, removed, recent;
-       struct stat st;
-       time_t now;
+       int i, removed;
 
        for (i = removed = 0; i < entries; i++)
                if (!cache[i]->ce_mode)
@@ -994,57 +1016,5 @@ int write_cache(int newfd, struct cache_entry **cache, int entries)
                        return -1;
                }
        }
-
-       /*
-        * To prevent later ce_match_stat() from always falling into
-        * check_fs(), if we have too many entries that can trigger
-        * racily clean check, we are better off delaying the return.
-        * We arbitrarily say if more than 20 paths or 25% of total
-        * paths are very new, we delay the return until the index
-        * file gets a new timestamp.
-        *
-        * NOTE! NOTE! NOTE!
-        *
-        * This assumes that nobody is touching the working tree while
-        * we are updating the index.
-        */
-
-       /* Make sure that the new index file has st_mtime
-        * that is current enough -- ce_write() batches the data
-        * so it might not have written anything yet.
-        */
-       ce_write_flush(&c, newfd);
-
-       now = fstat(newfd, &st) ? 0 : st.st_mtime;
-       if (now) {
-               recent = 0;
-               for (i = 0; i < entries; i++) {
-                       struct cache_entry *ce = cache[i];
-                       time_t entry_time = (time_t) ntohl(ce->ce_mtime.sec);
-                       if (!ce->ce_mode)
-                               continue;
-                       if (now && now <= entry_time)
-                               recent++;
-               }
-               if (20 < recent && entries <= recent * 4) {
-#if 0
-                       fprintf(stderr, "entries    %d\n", entries);
-                       fprintf(stderr, "recent     %d\n", recent);
-                       fprintf(stderr, "now        %lu\n", now);
-#endif
-                       while (!fstat(newfd, &st) && st.st_mtime <= now) {
-                               struct timespec rq, rm;
-                               off_t where = lseek(newfd, 0, SEEK_CUR);
-                               rq.tv_sec = 0;
-                               rq.tv_nsec = 250000000;
-                               nanosleep(&rq, &rm);
-                               if ((where == (off_t) -1) ||
-                                   (write(newfd, "", 1) != 1) ||
-                                   (lseek(newfd, -1, SEEK_CUR) != where) ||
-                                   ftruncate(newfd, where))
-                                       break;
-                       }
-               }
-       }
        return ce_flush(&c, newfd);
 }