Merge branch 'tr/valgrind'
[gitweb.git] / sha1_file.c
index 964c4d44ab0bca796d8366b52867555965d58b62..0ed23981b363a07c6f4c5b930b1a5991d5c8a622 100644 (file)
@@ -7,6 +7,7 @@
  * creation etc.
  */
 #include "cache.h"
+#include "string-list.h"
 #include "delta.h"
 #include "pack.h"
 #include "blob.h"
@@ -20,6 +21,7 @@
 #include "sha1-lookup.h"
 #include "bulk-checkin.h"
 #include "streaming.h"
+#include "dir.h"
 
 #ifndef O_NOATIME
 #if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
@@ -251,7 +253,7 @@ static int git_open_noatime(const char *name);
  * SHA1, an extra slash for the first level indirection, and the
  * terminating NUL.
  */
-static int link_alt_odb_entry(const char * entry, int len, const char * relative_base, int depth)
+static int link_alt_odb_entry(const char *entry, const char *relative_base, int depth)
 {
        const char *objdir = get_object_directory();
        struct alternate_object_database *ent;
@@ -263,7 +265,7 @@ static int link_alt_odb_entry(const char * entry, int len, const char * relative
                strbuf_addstr(&pathbuf, real_path(relative_base));
                strbuf_addch(&pathbuf, '/');
        }
-       strbuf_add(&pathbuf, entry, len);
+       strbuf_addstr(&pathbuf, entry);
 
        normalize_path_copy(pathbuf.buf, pathbuf.buf);
 
@@ -321,10 +323,12 @@ static int link_alt_odb_entry(const char * entry, int len, const char * relative
        return 0;
 }
 
-static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
+static void link_alt_odb_entries(const char *alt, int len, int sep,
                                 const char *relative_base, int depth)
 {
-       const char *cp, *last;
+       struct string_list entries = STRING_LIST_INIT_NODUP;
+       char *alt_copy;
+       int i;
 
        if (depth > 5) {
                error("%s: ignoring alternate object stores, nesting too deep.",
@@ -332,30 +336,21 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
                return;
        }
 
-       last = alt;
-       while (last < ep) {
-               cp = last;
-               if (cp < ep && *cp == '#') {
-                       while (cp < ep && *cp != sep)
-                               cp++;
-                       last = cp + 1;
+       alt_copy = xmemdupz(alt, len);
+       string_list_split_in_place(&entries, alt_copy, sep, -1);
+       for (i = 0; i < entries.nr; i++) {
+               const char *entry = entries.items[i].string;
+               if (entry[0] == '\0' || entry[0] == '#')
                        continue;
+               if (!is_absolute_path(entry) && depth) {
+                       error("%s: ignoring relative alternate object store %s",
+                                       relative_base, entry);
+               } else {
+                       link_alt_odb_entry(entry, relative_base, depth);
                }
-               while (cp < ep && *cp != sep)
-                       cp++;
-               if (last != cp) {
-                       if (!is_absolute_path(last) && depth) {
-                               error("%s: ignoring relative alternate object store %s",
-                                               relative_base, last);
-                       } else {
-                               link_alt_odb_entry(last, cp - last,
-                                               relative_base, depth);
-                       }
-               }
-               while (cp < ep && *cp == sep)
-                       cp++;
-               last = cp;
        }
+       string_list_clear(&entries, 0);
+       free(alt_copy);
 }
 
 void read_info_alternates(const char * relative_base, int depth)
@@ -382,7 +377,7 @@ void read_info_alternates(const char * relative_base, int depth)
        map = xmmap(NULL, mapsz, PROT_READ, MAP_PRIVATE, fd, 0);
        close(fd);
 
-       link_alt_odb_entries(map, map + mapsz, '\n', relative_base, depth);
+       link_alt_odb_entries(map, mapsz, '\n', relative_base, depth);
 
        munmap(map, mapsz);
 }
@@ -396,7 +391,7 @@ void add_to_alternates_file(const char *reference)
        if (commit_lock_file(lock))
                die("could not close alternates file");
        if (alt_odb_tail)
-               link_alt_odb_entries(alt, alt + strlen(alt), '\n', NULL, 0);
+               link_alt_odb_entries(alt, strlen(alt), '\n', NULL, 0);
 }
 
 void foreach_alt_odb(alt_odb_fn fn, void *cb)
@@ -420,7 +415,7 @@ void prepare_alt_odb(void)
        if (!alt) alt = "";
 
        alt_odb_tail = &alt_odb_list;
-       link_alt_odb_entries(alt, alt + strlen(alt), PATH_SEP, NULL, 0);
+       link_alt_odb_entries(alt, strlen(alt), PATH_SEP, NULL, 0);
 
        read_info_alternates(get_object_directory(), 0);
 }
@@ -1011,6 +1006,63 @@ void install_packed_git(struct packed_git *pack)
        packed_git = pack;
 }
 
+void (*report_garbage)(const char *desc, const char *path);
+
+static void report_helper(const struct string_list *list,
+                         int seen_bits, int first, int last)
+{
+       const char *msg;
+       switch (seen_bits) {
+       case 0:
+               msg = "no corresponding .idx nor .pack";
+               break;
+       case 1:
+               msg = "no corresponding .idx";
+               break;
+       case 2:
+               msg = "no corresponding .pack";
+               break;
+       default:
+               return;
+       }
+       for (; first < last; first++)
+               report_garbage(msg, list->items[first].string);
+}
+
+static void report_pack_garbage(struct string_list *list)
+{
+       int i, baselen = -1, first = 0, seen_bits = 0;
+
+       if (!report_garbage)
+               return;
+
+       sort_string_list(list);
+
+       for (i = 0; i < list->nr; i++) {
+               const char *path = list->items[i].string;
+               if (baselen != -1 &&
+                   strncmp(path, list->items[first].string, baselen)) {
+                       report_helper(list, seen_bits, first, i);
+                       baselen = -1;
+                       seen_bits = 0;
+               }
+               if (baselen == -1) {
+                       const char *dot = strrchr(path, '.');
+                       if (!dot) {
+                               report_garbage("garbage found", path);
+                               continue;
+                       }
+                       baselen = dot - path + 1;
+                       first = i;
+               }
+               if (!strcmp(path + baselen, "pack"))
+                       seen_bits |= 1;
+               else if (!strcmp(path + baselen, "idx"))
+                       seen_bits |= 2;
+       }
+       report_helper(list, seen_bits, first, list->nr);
+}
+
 static void prepare_packed_git_one(char *objdir, int local)
 {
        /* Ensure that this buffer is large enough so that we can
@@ -1020,6 +1072,7 @@ static void prepare_packed_git_one(char *objdir, int local)
        int len;
        DIR *dir;
        struct dirent *de;
+       struct string_list garbage = STRING_LIST_INIT_DUP;
 
        sprintf(path, "%s/pack", objdir);
        len = strlen(path);
@@ -1035,29 +1088,49 @@ static void prepare_packed_git_one(char *objdir, int local)
                int namelen = strlen(de->d_name);
                struct packed_git *p;
 
-               if (!has_extension(de->d_name, ".idx"))
+               if (len + namelen + 1 > sizeof(path)) {
+                       if (report_garbage) {
+                               struct strbuf sb = STRBUF_INIT;
+                               strbuf_addf(&sb, "%.*s/%s", len - 1, path, de->d_name);
+                               report_garbage("path too long", sb.buf);
+                               strbuf_release(&sb);
+                       }
                        continue;
+               }
 
-               if (len + namelen + 1 > sizeof(path))
+               if (is_dot_or_dotdot(de->d_name))
                        continue;
 
-               /* Don't reopen a pack we already have. */
                strcpy(path + len, de->d_name);
-               for (p = packed_git; p; p = p->next) {
-                       if (!memcmp(path, p->pack_name, len + namelen - 4))
-                               break;
+
+               if (has_extension(de->d_name, ".idx")) {
+                       /* Don't reopen a pack we already have. */
+                       for (p = packed_git; p; p = p->next) {
+                               if (!memcmp(path, p->pack_name, len + namelen - 4))
+                                       break;
+                       }
+                       if (p == NULL &&
+                           /*
+                            * See if it really is a valid .idx file with
+                            * corresponding .pack file that we can map.
+                            */
+                           (p = add_packed_git(path, len + namelen, local)) != NULL)
+                               install_packed_git(p);
                }
-               if (p)
-                       continue;
-               /* See if it really is a valid .idx file with corresponding
-                * .pack file that we can map.
-                */
-               p = add_packed_git(path, len + namelen, local);
-               if (!p)
+
+               if (!report_garbage)
                        continue;
-               install_packed_git(p);
+
+               if (has_extension(de->d_name, ".idx") ||
+                   has_extension(de->d_name, ".pack") ||
+                   has_extension(de->d_name, ".keep"))
+                       string_list_append(&garbage, path);
+               else
+                       report_garbage("garbage found", path);
        }
        closedir(dir);
+       report_pack_garbage(&garbage);
+       string_list_clear(&garbage, 0);
 }
 
 static int sort_pack(const void *a_, const void *b_)
@@ -1198,6 +1271,10 @@ int check_sha1_signature(const unsigned char *sha1, void *map,
                char buf[1024 * 16];
                ssize_t readlen = read_istream(st, buf, sizeof(buf));
 
+               if (readlen < 0) {
+                       close_istream(st);
+                       return -1;
+               }
                if (!readlen)
                        break;
                git_SHA1_Update(&c, buf, readlen);