t9107-git-svn-migrate.sh: use the $( ... ) construct for command substitution
[gitweb.git] / builtin / fsck.c
index b9a74f0cf6e169073994e466110fd1bde9febba7..55eac756f7c83e496daae7cb8874552caaa58ff5 100644 (file)
@@ -40,14 +40,6 @@ static int show_dangling = 1;
 #define ERROR_PACK 04
 #define ERROR_REFS 010
 
-#ifdef NO_D_INO_IN_DIRENT
-#define SORT_DIRENT 0
-#define DIRENT_SORT_HINT(de) 0
-#else
-#define SORT_DIRENT 1
-#define DIRENT_SORT_HINT(de) ((de)->d_ino)
-#endif
-
 static int fsck_config(const char *var, const char *value, void *cb)
 {
        if (strcmp(var, "fsck.skiplist") == 0) {
@@ -75,7 +67,7 @@ static void objreport(struct object *obj, const char *msg_type,
                        const char *err)
 {
        fprintf(stderr, "%s in %s %s: %s\n",
-               msg_type, typename(obj->type), sha1_to_hex(obj->sha1), err);
+               msg_type, typename(obj->type), oid_to_hex(&obj->oid), err);
 }
 
 static int objerror(struct object *obj, const char *err)
@@ -105,7 +97,7 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
        if (!obj) {
                /* ... these references to parent->fld are safe here */
                printf("broken link from %7s %s\n",
-                          typename(parent->type), sha1_to_hex(parent->sha1));
+                          typename(parent->type), oid_to_hex(&parent->oid));
                printf("broken link from %7s %s\n",
                           (type == OBJ_ANY ? "unknown" : typename(type)), "unknown");
                errors_found |= ERROR_REACHABLE;
@@ -120,11 +112,11 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
                return 0;
        obj->flags |= REACHABLE;
        if (!(obj->flags & HAS_OBJ)) {
-               if (parent && !has_sha1_file(obj->sha1)) {
+               if (parent && !has_object_file(&obj->oid)) {
                        printf("broken link from %7s %s\n",
-                                typename(parent->type), sha1_to_hex(parent->sha1));
+                                typename(parent->type), oid_to_hex(&parent->oid));
                        printf("              to %7s %s\n",
-                                typename(obj->type), sha1_to_hex(obj->sha1));
+                                typename(obj->type), oid_to_hex(&obj->oid));
                        errors_found |= ERROR_REACHABLE;
                }
                return 1;
@@ -194,11 +186,11 @@ static void check_reachable_object(struct object *obj)
         * do a full fsck
         */
        if (!(obj->flags & HAS_OBJ)) {
-               if (has_sha1_pack(obj->sha1))
+               if (has_sha1_pack(obj->oid.hash))
                        return; /* it is in pack - forget about it */
-               if (connectivity_only && has_sha1_file(obj->sha1))
+               if (connectivity_only && has_object_file(&obj->oid))
                        return;
-               printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
+               printf("missing %s %s\n", typename(obj->type), oid_to_hex(&obj->oid));
                errors_found |= ERROR_REACHABLE;
                return;
        }
@@ -223,7 +215,7 @@ static void check_unreachable_object(struct object *obj)
         * since this is something that is prunable.
         */
        if (show_unreachable) {
-               printf("unreachable %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
+               printf("unreachable %s %s\n", typename(obj->type), oid_to_hex(&obj->oid));
                return;
        }
 
@@ -242,11 +234,11 @@ static void check_unreachable_object(struct object *obj)
        if (!obj->used) {
                if (show_dangling)
                        printf("dangling %s %s\n", typename(obj->type),
-                              sha1_to_hex(obj->sha1));
+                              oid_to_hex(&obj->oid));
                if (write_lost_and_found) {
                        char *filename = git_pathdup("lost-found/%s/%s",
                                obj->type == OBJ_COMMIT ? "commit" : "other",
-                               sha1_to_hex(obj->sha1));
+                               oid_to_hex(&obj->oid));
                        FILE *f;
 
                        if (safe_create_leading_directories_const(filename)) {
@@ -257,10 +249,10 @@ static void check_unreachable_object(struct object *obj)
                        if (!(f = fopen(filename, "w")))
                                die_errno("Could not open '%s'", filename);
                        if (obj->type == OBJ_BLOB) {
-                               if (stream_blob_to_fd(fileno(f), obj->sha1, NULL, 1))
+                               if (stream_blob_to_fd(fileno(f), obj->oid.hash, NULL, 1))
                                        die_errno("Could not write '%s'", filename);
                        } else
-                               fprintf(f, "%s\n", sha1_to_hex(obj->sha1));
+                               fprintf(f, "%s\n", oid_to_hex(&obj->oid));
                        if (fclose(f))
                                die_errno("Could not finish '%s'",
                                          filename);
@@ -279,7 +271,7 @@ static void check_unreachable_object(struct object *obj)
 static void check_object(struct object *obj)
 {
        if (verbose)
-               fprintf(stderr, "Checking %s\n", sha1_to_hex(obj->sha1));
+               fprintf(stderr, "Checking %s\n", oid_to_hex(&obj->oid));
 
        if (obj->flags & REACHABLE)
                check_reachable_object(obj);
@@ -315,7 +307,7 @@ static int fsck_obj(struct object *obj)
 
        if (verbose)
                fprintf(stderr, "Checking %s %s\n",
-                       typename(obj->type), sha1_to_hex(obj->sha1));
+                       typename(obj->type), oid_to_hex(&obj->oid));
 
        if (fsck_walk(obj, NULL, &fsck_obj_options))
                objerror(obj, "broken links");
@@ -334,15 +326,15 @@ static int fsck_obj(struct object *obj)
                free_commit_buffer(commit);
 
                if (!commit->parents && show_root)
-                       printf("root %s\n", sha1_to_hex(commit->object.sha1));
+                       printf("root %s\n", oid_to_hex(&commit->object.oid));
        }
 
        if (obj->type == OBJ_TAG) {
                struct tag *tag = (struct tag *) obj;
 
                if (show_tags && tag->tagged) {
-                       printf("tagged %s %s", typename(tag->tagged->type), sha1_to_hex(tag->tagged->sha1));
-                       printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1));
+                       printf("tagged %s %s", typename(tag->tagged->type), oid_to_hex(&tag->tagged->oid));
+                       printf(" (%s) in %s\n", tag->tag, oid_to_hex(&tag->object.oid));
                }
        }
 
@@ -374,102 +366,6 @@ static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,
        return fsck_obj(obj);
 }
 
-/*
- * This is the sorting chunk size: make it reasonably
- * big so that we can sort well..
- */
-#define MAX_SHA1_ENTRIES (1024)
-
-struct sha1_entry {
-       unsigned long ino;
-       unsigned char sha1[20];
-};
-
-static struct {
-       unsigned long nr;
-       struct sha1_entry *entry[MAX_SHA1_ENTRIES];
-} sha1_list;
-
-static int ino_compare(const void *_a, const void *_b)
-{
-       const struct sha1_entry *a = _a, *b = _b;
-       unsigned long ino1 = a->ino, ino2 = b->ino;
-       return ino1 < ino2 ? -1 : ino1 > ino2 ? 1 : 0;
-}
-
-static void fsck_sha1_list(void)
-{
-       int i, nr = sha1_list.nr;
-
-       if (SORT_DIRENT)
-               qsort(sha1_list.entry, nr,
-                     sizeof(struct sha1_entry *), ino_compare);
-       for (i = 0; i < nr; i++) {
-               struct sha1_entry *entry = sha1_list.entry[i];
-               unsigned char *sha1 = entry->sha1;
-
-               sha1_list.entry[i] = NULL;
-               if (fsck_sha1(sha1))
-                       errors_found |= ERROR_OBJECT;
-               free(entry);
-       }
-       sha1_list.nr = 0;
-}
-
-static void add_sha1_list(unsigned char *sha1, unsigned long ino)
-{
-       struct sha1_entry *entry = xmalloc(sizeof(*entry));
-       int nr;
-
-       entry->ino = ino;
-       hashcpy(entry->sha1, sha1);
-       nr = sha1_list.nr;
-       if (nr == MAX_SHA1_ENTRIES) {
-               fsck_sha1_list();
-               nr = 0;
-       }
-       sha1_list.entry[nr] = entry;
-       sha1_list.nr = ++nr;
-}
-
-static inline int is_loose_object_file(struct dirent *de,
-                                      char *name, unsigned char *sha1)
-{
-       if (strlen(de->d_name) != 38)
-               return 0;
-       memcpy(name + 2, de->d_name, 39);
-       return !get_sha1_hex(name, sha1);
-}
-
-static void fsck_dir(int i, char *path)
-{
-       DIR *dir = opendir(path);
-       struct dirent *de;
-       char name[100];
-
-       if (!dir)
-               return;
-
-       if (verbose)
-               fprintf(stderr, "Checking directory %s\n", path);
-
-       sprintf(name, "%02x", i);
-       while ((de = readdir(dir)) != NULL) {
-               unsigned char sha1[20];
-
-               if (is_dot_or_dotdot(de->d_name))
-                       continue;
-               if (is_loose_object_file(de, name, sha1)) {
-                       add_sha1_list(sha1, DIRENT_SORT_HINT(de));
-                       continue;
-               }
-               if (starts_with(de->d_name, "tmp_obj_"))
-                       continue;
-               fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
-       }
-       closedir(dir);
-}
-
 static int default_refs;
 
 static void fsck_handle_reflog_sha1(const char *refname, unsigned char *sha1)
@@ -559,9 +455,28 @@ static void get_default_heads(void)
        }
 }
 
+static int fsck_loose(const unsigned char *sha1, const char *path, void *data)
+{
+       if (fsck_sha1(sha1))
+               errors_found |= ERROR_OBJECT;
+       return 0;
+}
+
+static int fsck_cruft(const char *basename, const char *path, void *data)
+{
+       if (!starts_with(basename, "tmp_obj_"))
+               fprintf(stderr, "bad sha1 file: %s\n", path);
+       return 0;
+}
+
+static int fsck_subdir(int nr, const char *path, void *progress)
+{
+       display_progress(progress, nr + 1);
+       return 0;
+}
+
 static void fsck_object_dir(const char *path)
 {
-       int i;
        struct progress *progress = NULL;
 
        if (verbose)
@@ -569,14 +484,11 @@ static void fsck_object_dir(const char *path)
 
        if (show_progress)
                progress = start_progress(_("Checking object directories"), 256);
-       for (i = 0; i < 256; i++) {
-               static char dir[4096];
-               sprintf(dir, "%s/%02x", path, i);
-               fsck_dir(i, dir);
-               display_progress(progress, i+1);
-       }
+
+       for_each_loose_file_in_objdir(path, fsck_loose, fsck_cruft, fsck_subdir,
+                                     progress);
+       display_progress(progress, 256);
        stop_progress(&progress);
-       fsck_sha1_list();
 }
 
 static int fsck_head_link(void)
@@ -688,16 +600,18 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
        git_config(fsck_config, NULL);
 
        fsck_head_link();
-       if (!connectivity_only)
+       if (!connectivity_only) {
                fsck_object_dir(get_object_directory());
 
-       prepare_alt_odb();
-       for (alt = alt_odb_list; alt; alt = alt->next) {
-               char namebuf[PATH_MAX];
-               int namelen = alt->name - alt->base;
-               memcpy(namebuf, alt->base, namelen);
-               namebuf[namelen - 1] = 0;
-               fsck_object_dir(namebuf);
+               prepare_alt_odb();
+               for (alt = alt_odb_list; alt; alt = alt->next) {
+                       /* directory name, minus trailing slash */
+                       size_t namelen = alt->name - alt->base - 1;
+                       struct strbuf name = STRBUF_INIT;
+                       strbuf_add(&name, alt->base, namelen);
+                       fsck_object_dir(name.buf);
+                       strbuf_release(&name);
+               }
        }
 
        if (check_full) {