git-fsck-objects is now synonym to git-fsck
authorJunio C Hamano <junkio@cox.net>
Mon, 29 Jan 2007 00:33:58 +0000 (16:33 -0800)
committerJunio C Hamano <junkio@cox.net>
Mon, 29 Jan 2007 00:33:58 +0000 (16:33 -0800)
Signed-off-by: Junio C Hamano <junkio@cox.net>
16 files changed:
.gitignore
Documentation/cmd-list.perl
Documentation/core-intro.txt
Documentation/everyday.txt
Documentation/git-fsck-objects.txt
Documentation/git-fsck.txt [new file with mode: 0644]
Documentation/git-pack-redundant.txt
Documentation/git-prune.txt
Makefile
fsck-objects.c [deleted file]
fsck.c [new file with mode: 0644]
git-lost-found.sh
http-fetch.c
t/t1410-reflog.sh
t/t5500-fetch-pack.sh
t/t5710-info-alternate.sh
index b4dccd7b816e958273ec84b77e8ff4d1602461de..a43444fb92e3475eaadbc7792e0defb9153910fb 100644 (file)
@@ -42,6 +42,7 @@ git-findtags
 git-fmt-merge-msg
 git-for-each-ref
 git-format-patch
 git-fmt-merge-msg
 git-for-each-ref
 git-format-patch
+git-fsck
 git-fsck-objects
 git-gc
 git-get-tar-commit-id
 git-fsck-objects
 git-gc
 git-get-tar-commit-id
index 824462551f4663fcce2d97b0dccbcba0851a5bdf..6dba8d8fe05769efa69ccc97ebdcbb2af0ca56e2 100755 (executable)
@@ -97,7 +97,7 @@ sub format_one {
 git-fmt-merge-msg                       purehelpers
 git-for-each-ref                        plumbinginterrogators
 git-format-patch                        mainporcelain
 git-fmt-merge-msg                       purehelpers
 git-for-each-ref                        plumbinginterrogators
 git-format-patch                        mainporcelain
-git-fsck-objects                        ancillaryinterrogators
+git-fsck                               ancillaryinterrogators
 git-gc                                  mainporcelain
 git-get-tar-commit-id                   ancillaryinterrogators
 git-grep                                mainporcelain
 git-gc                                  mainporcelain
 git-get-tar-commit-id                   ancillaryinterrogators
 git-grep                                mainporcelain
index 0458dc3d0263d40854e07d1a8ac53d1ec88379e7..abafefc71c37d8a3015f0227d24da0f07096fe4c 100644 (file)
@@ -82,7 +82,7 @@ size> + <byte\0> + <binary object data>.
 
 The structured objects can further have their structure and
 connectivity to other objects verified. This is generally done with
 
 The structured objects can further have their structure and
 connectivity to other objects verified. This is generally done with
-the `git-fsck-objects` program, which generates a full dependency graph
+the `git-fsck` program, which generates a full dependency graph
 of all objects, and verifies their internal consistency (in addition
 to just verifying their superficial consistency through the hash).
 
 of all objects, and verifies their internal consistency (in addition
 to just verifying their superficial consistency through the hash).
 
index fbbbc92b811f32581e20f96c3c664368ce4e801b..08c61b1f1ac6ca880c6c3a4f311f65486aabd23e 100644 (file)
@@ -28,7 +28,7 @@ Everybody uses these commands to maintain git repositories.
   * gitlink:git-init[1] or gitlink:git-clone[1] to create a
     new repository.
 
   * gitlink:git-init[1] or gitlink:git-clone[1] to create a
     new repository.
 
-  * gitlink:git-fsck-objects[1] to check the repository for errors.
+  * gitlink:git-fsck[1] to check the repository for errors.
 
   * gitlink:git-prune[1] to remove unused objects in the repository.
 
 
   * gitlink:git-prune[1] to remove unused objects in the repository.
 
@@ -43,7 +43,7 @@ Examples
 Check health and remove cruft.::
 +
 ------------
 Check health and remove cruft.::
 +
 ------------
-$ git fsck-objects <1>
+$ git fsck <1>
 $ git count-objects <2>
 $ git repack <3>
 $ git gc <4>
 $ git count-objects <2>
 $ git repack <3>
 $ git gc <4>
index d0af99d3512d3794f9907612cef1d30616120064..f21061ecfe56a438238cc84761174f836bd0035e 100644 (file)
@@ -8,132 +8,10 @@ git-fsck-objects - Verifies the connectivity and validity of the objects in the
 
 SYNOPSIS
 --------
 
 SYNOPSIS
 --------
-[verse]
-'git-fsck-objects' [--tags] [--root] [--unreachable] [--cache]
-                [--full] [--strict] [<object>*]
+'git-fsck-objects' ...
 
 DESCRIPTION
 -----------
 
 DESCRIPTION
 -----------
-Verifies the connectivity and validity of the objects in the database.
-
-OPTIONS
--------
-<object>::
-       An object to treat as the head of an unreachability trace.
-+
-If no objects are given, git-fsck-objects defaults to using the
-index file and all SHA1 references in .git/refs/* as heads.
-
---unreachable::
-       Print out objects that exist but that aren't readable from any
-       of the reference nodes.
-
---root::
-       Report root nodes.
-
---tags::
-       Report tags.
-
---cache::
-       Consider any object recorded in the index also as a head node for
-       an unreachability trace.
-
---full::
-       Check not just objects in GIT_OBJECT_DIRECTORY
-       ($GIT_DIR/objects), but also the ones found in alternate
-       object pools listed in GIT_ALTERNATE_OBJECT_DIRECTORIES
-       or $GIT_DIR/objects/info/alternates,
-       and in packed git archives found in $GIT_DIR/objects/pack
-       and corresponding pack subdirectories in alternate
-       object pools.
-
---strict::
-       Enable more strict checking, namely to catch a file mode
-       recorded with g+w bit set, which was created by older
-       versions of git.  Existing repositories, including the
-       Linux kernel, git itself, and sparse repository have old
-       objects that triggers this check, but it is recommended
-       to check new projects with this flag.
-
-It tests SHA1 and general object sanity, and it does full tracking of
-the resulting reachability and everything else. It prints out any
-corruption it finds (missing or bad objects), and if you use the
-'--unreachable' flag it will also print out objects that exist but
-that aren't readable from any of the specified head nodes.
-
-So for example
-
-       git-fsck-objects --unreachable HEAD $(cat .git/refs/heads/*)
-
-will do quite a _lot_ of verification on the tree. There are a few
-extra validity tests to be added (make sure that tree objects are
-sorted properly etc), but on the whole if "git-fsck-objects" is happy, you
-do have a valid tree.
-
-Any corrupt objects you will have to find in backups or other archives
-(i.e., you can just remove them and do an "rsync" with some other site in
-the hopes that somebody else has the object you have corrupted).
-
-Of course, "valid tree" doesn't mean that it wasn't generated by some
-evil person, and the end result might be crap. git is a revision
-tracking system, not a quality assurance system ;)
-
-Extracted Diagnostics
----------------------
-
-expect dangling commits - potential heads - due to lack of head information::
-       You haven't specified any nodes as heads so it won't be
-       possible to differentiate between un-parented commits and
-       root nodes.
-
-missing sha1 directory '<dir>'::
-       The directory holding the sha1 objects is missing.
-
-unreachable <type> <object>::
-       The <type> object <object>, isn't actually referred to directly
-       or indirectly in any of the trees or commits seen. This can
-       mean that there's another root node that you're not specifying
-       or that the tree is corrupt. If you haven't missed a root node
-       then you might as well delete unreachable nodes since they
-       can't be used.
-
-missing <type> <object>::
-       The <type> object <object>, is referred to but isn't present in
-       the database.
-
-dangling <type> <object>::
-       The <type> object <object>, is present in the database but never
-       'directly' used. A dangling commit could be a root node.
-
-warning: git-fsck-objects: tree <tree> has full pathnames in it::
-       And it shouldn't...
-
-sha1 mismatch <object>::
-       The database has an object who's sha1 doesn't match the
-       database value.
-       This indicates a serious data integrity problem.
-
-Environment Variables
----------------------
-
-GIT_OBJECT_DIRECTORY::
-       used to specify the object database root (usually $GIT_DIR/objects)
-
-GIT_INDEX_FILE::
-       used to specify the index file of the index
-
-GIT_ALTERNATE_OBJECT_DIRECTORIES::
-       used to specify additional object database roots (usually unset)
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the gitlink:git[7] suite
 
 
+This is a synonym for gitlink:git-fsck[1].  Please refer to the
+documentation of that command.
diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.txt
new file mode 100644 (file)
index 0000000..058009d
--- /dev/null
@@ -0,0 +1,139 @@
+git-fsck(1)
+===========
+
+NAME
+----
+git-fsck - Verifies the connectivity and validity of the objects in the database
+
+
+SYNOPSIS
+--------
+[verse]
+'git-fsck' [--tags] [--root] [--unreachable] [--cache]
+                [--full] [--strict] [<object>*]
+
+DESCRIPTION
+-----------
+Verifies the connectivity and validity of the objects in the database.
+
+OPTIONS
+-------
+<object>::
+       An object to treat as the head of an unreachability trace.
++
+If no objects are given, git-fsck defaults to using the
+index file and all SHA1 references in .git/refs/* as heads.
+
+--unreachable::
+       Print out objects that exist but that aren't readable from any
+       of the reference nodes.
+
+--root::
+       Report root nodes.
+
+--tags::
+       Report tags.
+
+--cache::
+       Consider any object recorded in the index also as a head node for
+       an unreachability trace.
+
+--full::
+       Check not just objects in GIT_OBJECT_DIRECTORY
+       ($GIT_DIR/objects), but also the ones found in alternate
+       object pools listed in GIT_ALTERNATE_OBJECT_DIRECTORIES
+       or $GIT_DIR/objects/info/alternates,
+       and in packed git archives found in $GIT_DIR/objects/pack
+       and corresponding pack subdirectories in alternate
+       object pools.
+
+--strict::
+       Enable more strict checking, namely to catch a file mode
+       recorded with g+w bit set, which was created by older
+       versions of git.  Existing repositories, including the
+       Linux kernel, git itself, and sparse repository have old
+       objects that triggers this check, but it is recommended
+       to check new projects with this flag.
+
+It tests SHA1 and general object sanity, and it does full tracking of
+the resulting reachability and everything else. It prints out any
+corruption it finds (missing or bad objects), and if you use the
+'--unreachable' flag it will also print out objects that exist but
+that aren't readable from any of the specified head nodes.
+
+So for example
+
+       git-fsck --unreachable HEAD $(cat .git/refs/heads/*)
+
+will do quite a _lot_ of verification on the tree. There are a few
+extra validity tests to be added (make sure that tree objects are
+sorted properly etc), but on the whole if "git-fsck" is happy, you
+do have a valid tree.
+
+Any corrupt objects you will have to find in backups or other archives
+(i.e., you can just remove them and do an "rsync" with some other site in
+the hopes that somebody else has the object you have corrupted).
+
+Of course, "valid tree" doesn't mean that it wasn't generated by some
+evil person, and the end result might be crap. git is a revision
+tracking system, not a quality assurance system ;)
+
+Extracted Diagnostics
+---------------------
+
+expect dangling commits - potential heads - due to lack of head information::
+       You haven't specified any nodes as heads so it won't be
+       possible to differentiate between un-parented commits and
+       root nodes.
+
+missing sha1 directory '<dir>'::
+       The directory holding the sha1 objects is missing.
+
+unreachable <type> <object>::
+       The <type> object <object>, isn't actually referred to directly
+       or indirectly in any of the trees or commits seen. This can
+       mean that there's another root node that you're not specifying
+       or that the tree is corrupt. If you haven't missed a root node
+       then you might as well delete unreachable nodes since they
+       can't be used.
+
+missing <type> <object>::
+       The <type> object <object>, is referred to but isn't present in
+       the database.
+
+dangling <type> <object>::
+       The <type> object <object>, is present in the database but never
+       'directly' used. A dangling commit could be a root node.
+
+warning: git-fsck: tree <tree> has full pathnames in it::
+       And it shouldn't...
+
+sha1 mismatch <object>::
+       The database has an object who's sha1 doesn't match the
+       database value.
+       This indicates a serious data integrity problem.
+
+Environment Variables
+---------------------
+
+GIT_OBJECT_DIRECTORY::
+       used to specify the object database root (usually $GIT_DIR/objects)
+
+GIT_INDEX_FILE::
+       used to specify the index file of the index
+
+GIT_ALTERNATE_OBJECT_DIRECTORIES::
+       used to specify additional object database roots (usually unset)
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>
+
+Documentation
+--------------
+Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
+
index be2c64eb57cdbc10c12c9784134911f91d791f8c..94bbea0db2caf32635cfa8fc199e8150b1cd05f2 100644 (file)
@@ -21,7 +21,7 @@ given will be ignored when checking which packs are required. This makes the
 following command useful when wanting to remove packs which contain unreachable
 objects.
 
 following command useful when wanting to remove packs which contain unreachable
 objects.
 
-git-fsck-objects --full --unreachable | cut -d ' ' -f3 | \
+git-fsck --full --unreachable | cut -d ' ' -f3 | \
 git-pack-redundant --all | xargs rm
 
 OPTIONS
 git-pack-redundant --all | xargs rm
 
 OPTIONS
index a11e3030943ab3ffd10afa017640826795809d05..0b44f3015d1ce8c600eb274a0f74c53868949658 100644 (file)
@@ -13,7 +13,7 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
 DESCRIPTION
 -----------
 
-This runs `git-fsck-objects --unreachable` using all the refs
+This runs `git-fsck --unreachable` using all the refs
 available in `$GIT_DIR/refs`, optionally with additional set of
 objects specified on the command line, and prunes all
 objects unreachable from any of these head objects from the object database.
 available in `$GIT_DIR/refs`, optionally with additional set of
 objects specified on the command line, and prunes all
 objects unreachable from any of these head objects from the object database.
index fd8a522efa110d9d2b178201dd9b66bffda7a46f..1552b2a5308f0a7c73b22f3416d5268e75a23deb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -192,7 +192,7 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
 
 # ... and all the rest that could be moved out of bindir to gitexecdir
 PROGRAMS = \
 
 # ... and all the rest that could be moved out of bindir to gitexecdir
 PROGRAMS = \
-       git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \
+       git-convert-objects$X git-fetch-pack$X git-fsck$X \
        git-hash-object$X git-index-pack$X git-local-fetch$X \
        git-merge-base$X \
        git-daemon$X \
        git-hash-object$X git-index-pack$X git-local-fetch$X \
        git-merge-base$X \
        git-daemon$X \
@@ -214,6 +214,7 @@ EXTRA_PROGRAMS =
 BUILT_INS = \
        git-format-patch$X git-show$X git-whatchanged$X git-cherry$X \
        git-get-tar-commit-id$X git-init$X git-repo-config$X \
 BUILT_INS = \
        git-format-patch$X git-show$X git-whatchanged$X git-cherry$X \
        git-get-tar-commit-id$X git-init$X git-repo-config$X \
+       git-fsck-objects$X \
        $(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
 
 # what 'all' will build and 'install' will install, in gitexecdir
        $(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
 
 # what 'all' will build and 'install' will install, in gitexecdir
diff --git a/fsck-objects.c b/fsck-objects.c
deleted file mode 100644 (file)
index ecfb014..0000000
+++ /dev/null
@@ -1,690 +0,0 @@
-#include "cache.h"
-#include "commit.h"
-#include "tree.h"
-#include "blob.h"
-#include "tag.h"
-#include "refs.h"
-#include "pack.h"
-#include "cache-tree.h"
-#include "tree-walk.h"
-
-#define REACHABLE 0x0001
-#define SEEN      0x0002
-
-static int show_root;
-static int show_tags;
-static int show_unreachable;
-static int check_full;
-static int check_strict;
-static int keep_cache_objects;
-static unsigned char head_sha1[20];
-
-#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 void objreport(struct object *obj, const char *severity,
-                      const char *err, va_list params)
-{
-       fprintf(stderr, "%s in %s %s: ",
-               severity, typename(obj->type), sha1_to_hex(obj->sha1));
-       vfprintf(stderr, err, params);
-       fputs("\n", stderr);
-}
-
-static int objerror(struct object *obj, const char *err, ...)
-{
-       va_list params;
-       va_start(params, err);
-       objreport(obj, "error", err, params);
-       va_end(params);
-       return -1;
-}
-
-static int objwarning(struct object *obj, const char *err, ...)
-{
-       va_list params;
-       va_start(params, err);
-       objreport(obj, "warning", err, params);
-       va_end(params);
-       return -1;
-}
-
-/*
- * Check a single reachable object
- */
-static void check_reachable_object(struct object *obj)
-{
-       const struct object_refs *refs;
-
-       /*
-        * We obviously want the object to be parsed,
-        * except if it was in a pack-file and we didn't
-        * do a full fsck
-        */
-       if (!obj->parsed) {
-               if (has_sha1_file(obj->sha1))
-                       return; /* it is in pack - forget about it */
-               printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
-               return;
-       }
-
-       /*
-        * Check that everything that we try to reference is also good.
-        */
-       refs = lookup_object_refs(obj);
-       if (refs) {
-               unsigned j;
-               for (j = 0; j < refs->count; j++) {
-                       struct object *ref = refs->ref[j];
-                       if (ref->parsed ||
-                           (has_sha1_file(ref->sha1)))
-                               continue;
-                       printf("broken link from %7s %s\n",
-                              typename(obj->type), sha1_to_hex(obj->sha1));
-                       printf("              to %7s %s\n",
-                              typename(ref->type), sha1_to_hex(ref->sha1));
-               }
-       }
-}
-
-/*
- * Check a single unreachable object
- */
-static void check_unreachable_object(struct object *obj)
-{
-       /*
-        * Missing unreachable object? Ignore it. It's not like
-        * we miss it (since it can't be reached), nor do we want
-        * to complain about it being unreachable (since it does
-        * not exist).
-        */
-       if (!obj->parsed)
-               return;
-
-       /*
-        * Unreachable object that exists? Show it if asked to,
-        * since this is something that is prunable.
-        */
-       if (show_unreachable) {
-               printf("unreachable %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
-               return;
-       }
-
-       /*
-        * "!used" means that nothing at all points to it, including
-        * other unreacahble objects. In other words, it's the "tip"
-        * of some set of unreachable objects, usually a commit that
-        * got dropped.
-        *
-        * Such starting points are more interesting than some random
-        * set of unreachable objects, so we show them even if the user
-        * hasn't asked for _all_ unreachable objects. If you have
-        * deleted a branch by mistake, this is a prime candidate to
-        * start looking at, for example.
-        */
-       if (!obj->used) {
-               printf("dangling %s %s\n", typename(obj->type),
-                      sha1_to_hex(obj->sha1));
-               return;
-       }
-
-       /*
-        * Otherwise? It's there, it's unreachable, and some other unreachable
-        * object points to it. Ignore it - it's not interesting, and we showed
-        * all the interesting cases above.
-        */
-}
-
-static void check_object(struct object *obj)
-{
-       if (obj->flags & REACHABLE)
-               check_reachable_object(obj);
-       else
-               check_unreachable_object(obj);
-}
-
-static void check_connectivity(void)
-{
-       int i, max;
-
-       /* Look up all the requirements, warn about missing objects.. */
-       max = get_max_object_index();
-       for (i = 0; i < max; i++) {
-               struct object *obj = get_indexed_object(i);
-
-               if (obj)
-                       check_object(obj);
-       }
-}
-
-/*
- * The entries in a tree are ordered in the _path_ order,
- * which means that a directory entry is ordered by adding
- * a slash to the end of it.
- *
- * So a directory called "a" is ordered _after_ a file
- * called "a.c", because "a/" sorts after "a.c".
- */
-#define TREE_UNORDERED (-1)
-#define TREE_HAS_DUPS  (-2)
-
-static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2)
-{
-       int len1 = strlen(name1);
-       int len2 = strlen(name2);
-       int len = len1 < len2 ? len1 : len2;
-       unsigned char c1, c2;
-       int cmp;
-
-       cmp = memcmp(name1, name2, len);
-       if (cmp < 0)
-               return 0;
-       if (cmp > 0)
-               return TREE_UNORDERED;
-
-       /*
-        * Ok, the first <len> characters are the same.
-        * Now we need to order the next one, but turn
-        * a '\0' into a '/' for a directory entry.
-        */
-       c1 = name1[len];
-       c2 = name2[len];
-       if (!c1 && !c2)
-               /*
-                * git-write-tree used to write out a nonsense tree that has
-                * entries with the same name, one blob and one tree.  Make
-                * sure we do not have duplicate entries.
-                */
-               return TREE_HAS_DUPS;
-       if (!c1 && S_ISDIR(mode1))
-               c1 = '/';
-       if (!c2 && S_ISDIR(mode2))
-               c2 = '/';
-       return c1 < c2 ? 0 : TREE_UNORDERED;
-}
-
-static int fsck_tree(struct tree *item)
-{
-       int retval;
-       int has_full_path = 0;
-       int has_zero_pad = 0;
-       int has_bad_modes = 0;
-       int has_dup_entries = 0;
-       int not_properly_sorted = 0;
-       struct tree_desc desc;
-       unsigned o_mode;
-       const char *o_name;
-       const unsigned char *o_sha1;
-
-       desc.buf = item->buffer;
-       desc.size = item->size;
-
-       o_mode = 0;
-       o_name = NULL;
-       o_sha1 = NULL;
-       while (desc.size) {
-               unsigned mode;
-               const char *name;
-               const unsigned char *sha1;
-
-               sha1 = tree_entry_extract(&desc, &name, &mode);
-
-               if (strchr(name, '/'))
-                       has_full_path = 1;
-               has_zero_pad |= *(char *)desc.buf == '0';
-               update_tree_entry(&desc);
-
-               switch (mode) {
-               /*
-                * Standard modes..
-                */
-               case S_IFREG | 0755:
-               case S_IFREG | 0644:
-               case S_IFLNK:
-               case S_IFDIR:
-                       break;
-               /*
-                * This is nonstandard, but we had a few of these
-                * early on when we honored the full set of mode
-                * bits..
-                */
-               case S_IFREG | 0664:
-                       if (!check_strict)
-                               break;
-               default:
-                       has_bad_modes = 1;
-               }
-
-               if (o_name) {
-                       switch (verify_ordered(o_mode, o_name, mode, name)) {
-                       case TREE_UNORDERED:
-                               not_properly_sorted = 1;
-                               break;
-                       case TREE_HAS_DUPS:
-                               has_dup_entries = 1;
-                               break;
-                       default:
-                               break;
-                       }
-               }
-
-               o_mode = mode;
-               o_name = name;
-               o_sha1 = sha1;
-       }
-       free(item->buffer);
-       item->buffer = NULL;
-
-       retval = 0;
-       if (has_full_path) {
-               objwarning(&item->object, "contains full pathnames");
-       }
-       if (has_zero_pad) {
-               objwarning(&item->object, "contains zero-padded file modes");
-       }
-       if (has_bad_modes) {
-               objwarning(&item->object, "contains bad file modes");
-       }
-       if (has_dup_entries) {
-               retval = objerror(&item->object, "contains duplicate file entries");
-       }
-       if (not_properly_sorted) {
-               retval = objerror(&item->object, "not properly sorted");
-       }
-       return retval;
-}
-
-static int fsck_commit(struct commit *commit)
-{
-       char *buffer = commit->buffer;
-       unsigned char tree_sha1[20], sha1[20];
-
-       if (memcmp(buffer, "tree ", 5))
-               return objerror(&commit->object, "invalid format - expected 'tree' line");
-       if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n')
-               return objerror(&commit->object, "invalid 'tree' line format - bad sha1");
-       buffer += 46;
-       while (!memcmp(buffer, "parent ", 7)) {
-               if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n')
-                       return objerror(&commit->object, "invalid 'parent' line format - bad sha1");
-               buffer += 48;
-       }
-       if (memcmp(buffer, "author ", 7))
-               return objerror(&commit->object, "invalid format - expected 'author' line");
-       free(commit->buffer);
-       commit->buffer = NULL;
-       if (!commit->tree)
-               return objerror(&commit->object, "could not load commit's tree %s", tree_sha1);
-       if (!commit->parents && show_root)
-               printf("root %s\n", sha1_to_hex(commit->object.sha1));
-       if (!commit->date)
-               printf("bad commit date in %s\n", 
-                      sha1_to_hex(commit->object.sha1));
-       return 0;
-}
-
-static int fsck_tag(struct tag *tag)
-{
-       struct object *tagged = tag->tagged;
-
-       if (!tagged) {
-               return objerror(&tag->object, "could not load tagged object");
-       }
-       if (!show_tags)
-               return 0;
-
-       printf("tagged %s %s", typename(tagged->type), sha1_to_hex(tagged->sha1));
-       printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1));
-       return 0;
-}
-
-static int fsck_sha1(unsigned char *sha1)
-{
-       struct object *obj = parse_object(sha1);
-       if (!obj)
-               return error("%s: object corrupt or missing", sha1_to_hex(sha1));
-       if (obj->flags & SEEN)
-               return 0;
-       obj->flags |= SEEN;
-       if (obj->type == OBJ_BLOB)
-               return 0;
-       if (obj->type == OBJ_TREE)
-               return fsck_tree((struct tree *) obj);
-       if (obj->type == OBJ_COMMIT)
-               return fsck_commit((struct commit *) obj);
-       if (obj->type == OBJ_TAG)
-               return fsck_tag((struct tag *) obj);
-       /* By now, parse_object() would've returned NULL instead. */
-       return objerror(obj, "unknown type '%d' (internal fsck error)", obj->type);
-}
-
-/*
- * 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;
-               fsck_sha1(sha1);
-               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 void fsck_dir(int i, char *path)
-{
-       DIR *dir = opendir(path);
-       struct dirent *de;
-
-       if (!dir)
-               return;
-
-       while ((de = readdir(dir)) != NULL) {
-               char name[100];
-               unsigned char sha1[20];
-               int len = strlen(de->d_name);
-
-               switch (len) {
-               case 2:
-                       if (de->d_name[1] != '.')
-                               break;
-               case 1:
-                       if (de->d_name[0] != '.')
-                               break;
-                       continue;
-               case 38:
-                       sprintf(name, "%02x", i);
-                       memcpy(name+2, de->d_name, len+1);
-                       if (get_sha1_hex(name, sha1) < 0)
-                               break;
-                       add_sha1_list(sha1, DIRENT_SORT_HINT(de));
-                       continue;
-               }
-               fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
-       }
-       closedir(dir);
-}
-
-static int default_refs;
-
-static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
-               const char *email, unsigned long timestamp, int tz,
-               const char *message, void *cb_data)
-{
-       struct object *obj;
-
-       if (!is_null_sha1(osha1)) {
-               obj = lookup_object(osha1);
-               if (obj) {
-                       obj->used = 1;
-                       mark_reachable(obj, REACHABLE);
-               }
-       }
-       obj = lookup_object(nsha1);
-       if (obj) {
-               obj->used = 1;
-               mark_reachable(obj, REACHABLE);
-       }
-       return 0;
-}
-
-static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
-{
-       struct object *obj;
-
-       obj = lookup_object(sha1);
-       if (!obj) {
-               if (has_sha1_file(sha1)) {
-                       default_refs++;
-                       return 0; /* it is in a pack */
-               }
-               error("%s: invalid sha1 pointer %s", refname, sha1_to_hex(sha1));
-               /* We'll continue with the rest despite the error.. */
-               return 0;
-       }
-       default_refs++;
-       obj->used = 1;
-       mark_reachable(obj, REACHABLE);
-
-       for_each_reflog_ent(refname, fsck_handle_reflog_ent, NULL);
-
-       return 0;
-}
-
-static void get_default_heads(void)
-{
-       for_each_ref(fsck_handle_ref, NULL);
-
-       /*
-        * Not having any default heads isn't really fatal, but
-        * it does mean that "--unreachable" no longer makes any
-        * sense (since in this case everything will obviously
-        * be unreachable by definition.
-        *
-        * Showing dangling objects is valid, though (as those
-        * dangling objects are likely lost heads).
-        *
-        * So we just print a warning about it, and clear the
-        * "show_unreachable" flag.
-        */
-       if (!default_refs) {
-               error("No default references");
-               show_unreachable = 0;
-       }
-}
-
-static void fsck_object_dir(const char *path)
-{
-       int i;
-       for (i = 0; i < 256; i++) {
-               static char dir[4096];
-               sprintf(dir, "%s/%02x", path, i);
-               fsck_dir(i, dir);
-       }
-       fsck_sha1_list();
-}
-
-static int fsck_head_link(void)
-{
-       unsigned char sha1[20];
-       int flag;
-       const char *head_points_at = resolve_ref("HEAD", sha1, 1, &flag);
-
-       if (!head_points_at || !(flag & REF_ISSYMREF))
-               return error("HEAD is not a symbolic ref");
-       if (strncmp(head_points_at, "refs/heads/", 11))
-               return error("HEAD points to something strange (%s)",
-                            head_points_at);
-       if (is_null_sha1(sha1))
-               return error("HEAD: not a valid git pointer");
-       return 0;
-}
-
-static int fsck_cache_tree(struct cache_tree *it)
-{
-       int i;
-       int err = 0;
-
-       if (0 <= it->entry_count) {
-               struct object *obj = parse_object(it->sha1);
-               if (!obj) {
-                       error("%s: invalid sha1 pointer in cache-tree",
-                             sha1_to_hex(it->sha1));
-                       return 1;
-               }
-               mark_reachable(obj, REACHABLE);
-               obj->used = 1;
-               if (obj->type != OBJ_TREE)
-                       err |= objerror(obj, "non-tree in cache-tree");
-       }
-       for (i = 0; i < it->subtree_nr; i++)
-               err |= fsck_cache_tree(it->down[i]->cache_tree);
-       return err;
-}
-
-int main(int argc, char **argv)
-{
-       int i, heads;
-
-       track_object_refs = 1;
-       setup_git_directory();
-
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
-
-               if (!strcmp(arg, "--unreachable")) {
-                       show_unreachable = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "--tags")) {
-                       show_tags = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "--root")) {
-                       show_root = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "--cache")) {
-                       keep_cache_objects = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "--full")) {
-                       check_full = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "--strict")) {
-                       check_strict = 1;
-                       continue;
-               }
-               if (*arg == '-')
-                       usage("git-fsck-objects [--tags] [--root] [[--unreachable] [--cache] [--full] [--strict] <head-sha1>*]");
-       }
-
-       fsck_head_link();
-       fsck_object_dir(get_object_directory());
-       if (check_full) {
-               struct alternate_object_database *alt;
-               struct packed_git *p;
-               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_packed_git();
-               for (p = packed_git; p; p = p->next)
-                       /* verify gives error messages itself */
-                       verify_pack(p, 0);
-
-               for (p = packed_git; p; p = p->next) {
-                       int num = num_packed_objects(p);
-                       for (i = 0; i < num; i++) {
-                               unsigned char sha1[20];
-                               nth_packed_object_sha1(p, i, sha1);
-                               fsck_sha1(sha1);
-                       }
-               }
-       }
-
-       heads = 0;
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i]; 
-
-               if (*arg == '-')
-                       continue;
-
-               if (!get_sha1(arg, head_sha1)) {
-                       struct object *obj = lookup_object(head_sha1);
-
-                       /* Error is printed by lookup_object(). */
-                       if (!obj)
-                               continue;
-
-                       obj->used = 1;
-                       mark_reachable(obj, REACHABLE);
-                       heads++;
-                       continue;
-               }
-               error("invalid parameter: expected sha1, got '%s'", arg);
-       }
-
-       /*
-        * If we've not been given any explicit head information, do the
-        * default ones from .git/refs. We also consider the index file
-        * in this case (ie this implies --cache).
-        */
-       if (!heads) {
-               get_default_heads();
-               keep_cache_objects = 1;
-       }
-
-       if (keep_cache_objects) {
-               int i;
-               read_cache();
-               for (i = 0; i < active_nr; i++) {
-                       struct blob *blob = lookup_blob(active_cache[i]->sha1);
-                       struct object *obj;
-                       if (!blob)
-                               continue;
-                       obj = &blob->object;
-                       obj->used = 1;
-                       mark_reachable(obj, REACHABLE);
-               }
-               if (active_cache_tree)
-                       fsck_cache_tree(active_cache_tree);
-       }
-
-       check_connectivity();
-       return 0;
-}
diff --git a/fsck.c b/fsck.c
new file mode 100644 (file)
index 0000000..558f0a6
--- /dev/null
+++ b/fsck.c
@@ -0,0 +1,690 @@
+#include "cache.h"
+#include "commit.h"
+#include "tree.h"
+#include "blob.h"
+#include "tag.h"
+#include "refs.h"
+#include "pack.h"
+#include "cache-tree.h"
+#include "tree-walk.h"
+
+#define REACHABLE 0x0001
+#define SEEN      0x0002
+
+static int show_root;
+static int show_tags;
+static int show_unreachable;
+static int check_full;
+static int check_strict;
+static int keep_cache_objects;
+static unsigned char head_sha1[20];
+
+#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 void objreport(struct object *obj, const char *severity,
+                      const char *err, va_list params)
+{
+       fprintf(stderr, "%s in %s %s: ",
+               severity, typename(obj->type), sha1_to_hex(obj->sha1));
+       vfprintf(stderr, err, params);
+       fputs("\n", stderr);
+}
+
+static int objerror(struct object *obj, const char *err, ...)
+{
+       va_list params;
+       va_start(params, err);
+       objreport(obj, "error", err, params);
+       va_end(params);
+       return -1;
+}
+
+static int objwarning(struct object *obj, const char *err, ...)
+{
+       va_list params;
+       va_start(params, err);
+       objreport(obj, "warning", err, params);
+       va_end(params);
+       return -1;
+}
+
+/*
+ * Check a single reachable object
+ */
+static void check_reachable_object(struct object *obj)
+{
+       const struct object_refs *refs;
+
+       /*
+        * We obviously want the object to be parsed,
+        * except if it was in a pack-file and we didn't
+        * do a full fsck
+        */
+       if (!obj->parsed) {
+               if (has_sha1_file(obj->sha1))
+                       return; /* it is in pack - forget about it */
+               printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
+               return;
+       }
+
+       /*
+        * Check that everything that we try to reference is also good.
+        */
+       refs = lookup_object_refs(obj);
+       if (refs) {
+               unsigned j;
+               for (j = 0; j < refs->count; j++) {
+                       struct object *ref = refs->ref[j];
+                       if (ref->parsed ||
+                           (has_sha1_file(ref->sha1)))
+                               continue;
+                       printf("broken link from %7s %s\n",
+                              typename(obj->type), sha1_to_hex(obj->sha1));
+                       printf("              to %7s %s\n",
+                              typename(ref->type), sha1_to_hex(ref->sha1));
+               }
+       }
+}
+
+/*
+ * Check a single unreachable object
+ */
+static void check_unreachable_object(struct object *obj)
+{
+       /*
+        * Missing unreachable object? Ignore it. It's not like
+        * we miss it (since it can't be reached), nor do we want
+        * to complain about it being unreachable (since it does
+        * not exist).
+        */
+       if (!obj->parsed)
+               return;
+
+       /*
+        * Unreachable object that exists? Show it if asked to,
+        * since this is something that is prunable.
+        */
+       if (show_unreachable) {
+               printf("unreachable %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
+               return;
+       }
+
+       /*
+        * "!used" means that nothing at all points to it, including
+        * other unreacahble objects. In other words, it's the "tip"
+        * of some set of unreachable objects, usually a commit that
+        * got dropped.
+        *
+        * Such starting points are more interesting than some random
+        * set of unreachable objects, so we show them even if the user
+        * hasn't asked for _all_ unreachable objects. If you have
+        * deleted a branch by mistake, this is a prime candidate to
+        * start looking at, for example.
+        */
+       if (!obj->used) {
+               printf("dangling %s %s\n", typename(obj->type),
+                      sha1_to_hex(obj->sha1));
+               return;
+       }
+
+       /*
+        * Otherwise? It's there, it's unreachable, and some other unreachable
+        * object points to it. Ignore it - it's not interesting, and we showed
+        * all the interesting cases above.
+        */
+}
+
+static void check_object(struct object *obj)
+{
+       if (obj->flags & REACHABLE)
+               check_reachable_object(obj);
+       else
+               check_unreachable_object(obj);
+}
+
+static void check_connectivity(void)
+{
+       int i, max;
+
+       /* Look up all the requirements, warn about missing objects.. */
+       max = get_max_object_index();
+       for (i = 0; i < max; i++) {
+               struct object *obj = get_indexed_object(i);
+
+               if (obj)
+                       check_object(obj);
+       }
+}
+
+/*
+ * The entries in a tree are ordered in the _path_ order,
+ * which means that a directory entry is ordered by adding
+ * a slash to the end of it.
+ *
+ * So a directory called "a" is ordered _after_ a file
+ * called "a.c", because "a/" sorts after "a.c".
+ */
+#define TREE_UNORDERED (-1)
+#define TREE_HAS_DUPS  (-2)
+
+static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2)
+{
+       int len1 = strlen(name1);
+       int len2 = strlen(name2);
+       int len = len1 < len2 ? len1 : len2;
+       unsigned char c1, c2;
+       int cmp;
+
+       cmp = memcmp(name1, name2, len);
+       if (cmp < 0)
+               return 0;
+       if (cmp > 0)
+               return TREE_UNORDERED;
+
+       /*
+        * Ok, the first <len> characters are the same.
+        * Now we need to order the next one, but turn
+        * a '\0' into a '/' for a directory entry.
+        */
+       c1 = name1[len];
+       c2 = name2[len];
+       if (!c1 && !c2)
+               /*
+                * git-write-tree used to write out a nonsense tree that has
+                * entries with the same name, one blob and one tree.  Make
+                * sure we do not have duplicate entries.
+                */
+               return TREE_HAS_DUPS;
+       if (!c1 && S_ISDIR(mode1))
+               c1 = '/';
+       if (!c2 && S_ISDIR(mode2))
+               c2 = '/';
+       return c1 < c2 ? 0 : TREE_UNORDERED;
+}
+
+static int fsck_tree(struct tree *item)
+{
+       int retval;
+       int has_full_path = 0;
+       int has_zero_pad = 0;
+       int has_bad_modes = 0;
+       int has_dup_entries = 0;
+       int not_properly_sorted = 0;
+       struct tree_desc desc;
+       unsigned o_mode;
+       const char *o_name;
+       const unsigned char *o_sha1;
+
+       desc.buf = item->buffer;
+       desc.size = item->size;
+
+       o_mode = 0;
+       o_name = NULL;
+       o_sha1 = NULL;
+       while (desc.size) {
+               unsigned mode;
+               const char *name;
+               const unsigned char *sha1;
+
+               sha1 = tree_entry_extract(&desc, &name, &mode);
+
+               if (strchr(name, '/'))
+                       has_full_path = 1;
+               has_zero_pad |= *(char *)desc.buf == '0';
+               update_tree_entry(&desc);
+
+               switch (mode) {
+               /*
+                * Standard modes..
+                */
+               case S_IFREG | 0755:
+               case S_IFREG | 0644:
+               case S_IFLNK:
+               case S_IFDIR:
+                       break;
+               /*
+                * This is nonstandard, but we had a few of these
+                * early on when we honored the full set of mode
+                * bits..
+                */
+               case S_IFREG | 0664:
+                       if (!check_strict)
+                               break;
+               default:
+                       has_bad_modes = 1;
+               }
+
+               if (o_name) {
+                       switch (verify_ordered(o_mode, o_name, mode, name)) {
+                       case TREE_UNORDERED:
+                               not_properly_sorted = 1;
+                               break;
+                       case TREE_HAS_DUPS:
+                               has_dup_entries = 1;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
+               o_mode = mode;
+               o_name = name;
+               o_sha1 = sha1;
+       }
+       free(item->buffer);
+       item->buffer = NULL;
+
+       retval = 0;
+       if (has_full_path) {
+               objwarning(&item->object, "contains full pathnames");
+       }
+       if (has_zero_pad) {
+               objwarning(&item->object, "contains zero-padded file modes");
+       }
+       if (has_bad_modes) {
+               objwarning(&item->object, "contains bad file modes");
+       }
+       if (has_dup_entries) {
+               retval = objerror(&item->object, "contains duplicate file entries");
+       }
+       if (not_properly_sorted) {
+               retval = objerror(&item->object, "not properly sorted");
+       }
+       return retval;
+}
+
+static int fsck_commit(struct commit *commit)
+{
+       char *buffer = commit->buffer;
+       unsigned char tree_sha1[20], sha1[20];
+
+       if (memcmp(buffer, "tree ", 5))
+               return objerror(&commit->object, "invalid format - expected 'tree' line");
+       if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n')
+               return objerror(&commit->object, "invalid 'tree' line format - bad sha1");
+       buffer += 46;
+       while (!memcmp(buffer, "parent ", 7)) {
+               if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n')
+                       return objerror(&commit->object, "invalid 'parent' line format - bad sha1");
+               buffer += 48;
+       }
+       if (memcmp(buffer, "author ", 7))
+               return objerror(&commit->object, "invalid format - expected 'author' line");
+       free(commit->buffer);
+       commit->buffer = NULL;
+       if (!commit->tree)
+               return objerror(&commit->object, "could not load commit's tree %s", tree_sha1);
+       if (!commit->parents && show_root)
+               printf("root %s\n", sha1_to_hex(commit->object.sha1));
+       if (!commit->date)
+               printf("bad commit date in %s\n", 
+                      sha1_to_hex(commit->object.sha1));
+       return 0;
+}
+
+static int fsck_tag(struct tag *tag)
+{
+       struct object *tagged = tag->tagged;
+
+       if (!tagged) {
+               return objerror(&tag->object, "could not load tagged object");
+       }
+       if (!show_tags)
+               return 0;
+
+       printf("tagged %s %s", typename(tagged->type), sha1_to_hex(tagged->sha1));
+       printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1));
+       return 0;
+}
+
+static int fsck_sha1(unsigned char *sha1)
+{
+       struct object *obj = parse_object(sha1);
+       if (!obj)
+               return error("%s: object corrupt or missing", sha1_to_hex(sha1));
+       if (obj->flags & SEEN)
+               return 0;
+       obj->flags |= SEEN;
+       if (obj->type == OBJ_BLOB)
+               return 0;
+       if (obj->type == OBJ_TREE)
+               return fsck_tree((struct tree *) obj);
+       if (obj->type == OBJ_COMMIT)
+               return fsck_commit((struct commit *) obj);
+       if (obj->type == OBJ_TAG)
+               return fsck_tag((struct tag *) obj);
+       /* By now, parse_object() would've returned NULL instead. */
+       return objerror(obj, "unknown type '%d' (internal fsck error)", obj->type);
+}
+
+/*
+ * 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;
+               fsck_sha1(sha1);
+               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 void fsck_dir(int i, char *path)
+{
+       DIR *dir = opendir(path);
+       struct dirent *de;
+
+       if (!dir)
+               return;
+
+       while ((de = readdir(dir)) != NULL) {
+               char name[100];
+               unsigned char sha1[20];
+               int len = strlen(de->d_name);
+
+               switch (len) {
+               case 2:
+                       if (de->d_name[1] != '.')
+                               break;
+               case 1:
+                       if (de->d_name[0] != '.')
+                               break;
+                       continue;
+               case 38:
+                       sprintf(name, "%02x", i);
+                       memcpy(name+2, de->d_name, len+1);
+                       if (get_sha1_hex(name, sha1) < 0)
+                               break;
+                       add_sha1_list(sha1, DIRENT_SORT_HINT(de));
+                       continue;
+               }
+               fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
+       }
+       closedir(dir);
+}
+
+static int default_refs;
+
+static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
+               const char *email, unsigned long timestamp, int tz,
+               const char *message, void *cb_data)
+{
+       struct object *obj;
+
+       if (!is_null_sha1(osha1)) {
+               obj = lookup_object(osha1);
+               if (obj) {
+                       obj->used = 1;
+                       mark_reachable(obj, REACHABLE);
+               }
+       }
+       obj = lookup_object(nsha1);
+       if (obj) {
+               obj->used = 1;
+               mark_reachable(obj, REACHABLE);
+       }
+       return 0;
+}
+
+static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
+{
+       struct object *obj;
+
+       obj = lookup_object(sha1);
+       if (!obj) {
+               if (has_sha1_file(sha1)) {
+                       default_refs++;
+                       return 0; /* it is in a pack */
+               }
+               error("%s: invalid sha1 pointer %s", refname, sha1_to_hex(sha1));
+               /* We'll continue with the rest despite the error.. */
+               return 0;
+       }
+       default_refs++;
+       obj->used = 1;
+       mark_reachable(obj, REACHABLE);
+
+       for_each_reflog_ent(refname, fsck_handle_reflog_ent, NULL);
+
+       return 0;
+}
+
+static void get_default_heads(void)
+{
+       for_each_ref(fsck_handle_ref, NULL);
+
+       /*
+        * Not having any default heads isn't really fatal, but
+        * it does mean that "--unreachable" no longer makes any
+        * sense (since in this case everything will obviously
+        * be unreachable by definition.
+        *
+        * Showing dangling objects is valid, though (as those
+        * dangling objects are likely lost heads).
+        *
+        * So we just print a warning about it, and clear the
+        * "show_unreachable" flag.
+        */
+       if (!default_refs) {
+               error("No default references");
+               show_unreachable = 0;
+       }
+}
+
+static void fsck_object_dir(const char *path)
+{
+       int i;
+       for (i = 0; i < 256; i++) {
+               static char dir[4096];
+               sprintf(dir, "%s/%02x", path, i);
+               fsck_dir(i, dir);
+       }
+       fsck_sha1_list();
+}
+
+static int fsck_head_link(void)
+{
+       unsigned char sha1[20];
+       int flag;
+       const char *head_points_at = resolve_ref("HEAD", sha1, 1, &flag);
+
+       if (!head_points_at || !(flag & REF_ISSYMREF))
+               return error("HEAD is not a symbolic ref");
+       if (strncmp(head_points_at, "refs/heads/", 11))
+               return error("HEAD points to something strange (%s)",
+                            head_points_at);
+       if (is_null_sha1(sha1))
+               return error("HEAD: not a valid git pointer");
+       return 0;
+}
+
+static int fsck_cache_tree(struct cache_tree *it)
+{
+       int i;
+       int err = 0;
+
+       if (0 <= it->entry_count) {
+               struct object *obj = parse_object(it->sha1);
+               if (!obj) {
+                       error("%s: invalid sha1 pointer in cache-tree",
+                             sha1_to_hex(it->sha1));
+                       return 1;
+               }
+               mark_reachable(obj, REACHABLE);
+               obj->used = 1;
+               if (obj->type != OBJ_TREE)
+                       err |= objerror(obj, "non-tree in cache-tree");
+       }
+       for (i = 0; i < it->subtree_nr; i++)
+               err |= fsck_cache_tree(it->down[i]->cache_tree);
+       return err;
+}
+
+int main(int argc, char **argv)
+{
+       int i, heads;
+
+       track_object_refs = 1;
+       setup_git_directory();
+
+       for (i = 1; i < argc; i++) {
+               const char *arg = argv[i];
+
+               if (!strcmp(arg, "--unreachable")) {
+                       show_unreachable = 1;
+                       continue;
+               }
+               if (!strcmp(arg, "--tags")) {
+                       show_tags = 1;
+                       continue;
+               }
+               if (!strcmp(arg, "--root")) {
+                       show_root = 1;
+                       continue;
+               }
+               if (!strcmp(arg, "--cache")) {
+                       keep_cache_objects = 1;
+                       continue;
+               }
+               if (!strcmp(arg, "--full")) {
+                       check_full = 1;
+                       continue;
+               }
+               if (!strcmp(arg, "--strict")) {
+                       check_strict = 1;
+                       continue;
+               }
+               if (*arg == '-')
+                       usage("git-fsck [--tags] [--root] [[--unreachable] [--cache] [--full] [--strict] <head-sha1>*]");
+       }
+
+       fsck_head_link();
+       fsck_object_dir(get_object_directory());
+       if (check_full) {
+               struct alternate_object_database *alt;
+               struct packed_git *p;
+               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_packed_git();
+               for (p = packed_git; p; p = p->next)
+                       /* verify gives error messages itself */
+                       verify_pack(p, 0);
+
+               for (p = packed_git; p; p = p->next) {
+                       int num = num_packed_objects(p);
+                       for (i = 0; i < num; i++) {
+                               unsigned char sha1[20];
+                               nth_packed_object_sha1(p, i, sha1);
+                               fsck_sha1(sha1);
+                       }
+               }
+       }
+
+       heads = 0;
+       for (i = 1; i < argc; i++) {
+               const char *arg = argv[i]; 
+
+               if (*arg == '-')
+                       continue;
+
+               if (!get_sha1(arg, head_sha1)) {
+                       struct object *obj = lookup_object(head_sha1);
+
+                       /* Error is printed by lookup_object(). */
+                       if (!obj)
+                               continue;
+
+                       obj->used = 1;
+                       mark_reachable(obj, REACHABLE);
+                       heads++;
+                       continue;
+               }
+               error("invalid parameter: expected sha1, got '%s'", arg);
+       }
+
+       /*
+        * If we've not been given any explicit head information, do the
+        * default ones from .git/refs. We also consider the index file
+        * in this case (ie this implies --cache).
+        */
+       if (!heads) {
+               get_default_heads();
+               keep_cache_objects = 1;
+       }
+
+       if (keep_cache_objects) {
+               int i;
+               read_cache();
+               for (i = 0; i < active_nr; i++) {
+                       struct blob *blob = lookup_blob(active_cache[i]->sha1);
+                       struct object *obj;
+                       if (!blob)
+                               continue;
+                       obj = &blob->object;
+                       obj->used = 1;
+                       mark_reachable(obj, REACHABLE);
+               }
+               if (active_cache_tree)
+                       fsck_cache_tree(active_cache_tree);
+       }
+
+       check_connectivity();
+       return 0;
+}
index b928f2ca52c1991ee50838fc47580ed83c58fb64..9360804711d6b81983e53df67c86ddc8082e2ab4 100755 (executable)
@@ -12,7 +12,7 @@ fi
 laf="$GIT_DIR/lost-found"
 rm -fr "$laf" && mkdir -p "$laf/commit" "$laf/other" || exit
 
 laf="$GIT_DIR/lost-found"
 rm -fr "$laf" && mkdir -p "$laf/commit" "$laf/other" || exit
 
-git fsck-objects --full |
+git fsck --full |
 while read dangling type sha1
 do
        case "$dangling" in
 while read dangling type sha1
 do
        case "$dangling" in
index efd494a47fb961f4f8425d52bd10e37e5ffdab51..9f790a08e5d2760524ab7a34e98071062b3ed42f 100644 (file)
@@ -1069,7 +1069,7 @@ int main(int argc, const char **argv)
                fprintf(stderr,
 "Some loose object were found to be corrupt, but they might be just\n"
 "a false '404 Not Found' error message sent with incorrect HTTP\n"
                fprintf(stderr,
 "Some loose object were found to be corrupt, but they might be just\n"
 "a false '404 Not Found' error message sent with incorrect HTTP\n"
-"status code.  Suggest running git fsck-objects.\n");
+"status code.  Suggest running git-fsck.\n");
        }
        return rc;
 }
        }
        return rc;
 }
index 47d124732cd04481d6a21e927aa6104f63e21fbf..e5bbc384f7f4e56b13a13bf2bedad1427e257652 100755 (executable)
@@ -20,7 +20,7 @@ check_have () {
 }
 
 check_fsck () {
 }
 
 check_fsck () {
-       output=$(git fsck-objects --full)
+       output=$(git fsck --full)
        case "$1" in
        '')
                test -z "$output" ;;
        case "$1" in
        '')
                test -z "$output" ;;
index e35d60fa3ab9d7694f89f4451caf741003feeb13..48e3d1705f5e4bc7f206692276b4e3e1fe1ddf66 100755 (executable)
@@ -63,13 +63,13 @@ pull_to_client () {
        case "$heads" in *B*) echo $BTIP > .git/refs/heads/B;; esac
        git-symbolic-ref HEAD refs/heads/`echo $heads | sed -e 's/^\(.\).*$/\1/'`
 
        case "$heads" in *B*) echo $BTIP > .git/refs/heads/B;; esac
        git-symbolic-ref HEAD refs/heads/`echo $heads | sed -e 's/^\(.\).*$/\1/'`
 
-       test_expect_success "fsck" 'git-fsck-objects --full > fsck.txt 2>&1'
+       test_expect_success "fsck" 'git-fsck --full > fsck.txt 2>&1'
 
        test_expect_success 'check downloaded results' \
        'mv .git/objects/pack/pack-* . &&
         p=`ls -1 pack-*.pack` &&
         git-unpack-objects <$p &&
 
        test_expect_success 'check downloaded results' \
        'mv .git/objects/pack/pack-* . &&
         p=`ls -1 pack-*.pack` &&
         git-unpack-objects <$p &&
-        git-fsck-objects --full'
+        git-fsck --full'
 
        test_expect_success "new object count after $number pull" \
        'idx=`echo pack-*.idx` &&
 
        test_expect_success "new object count after $number pull" \
        'idx=`echo pack-*.idx` &&
@@ -145,7 +145,7 @@ test_expect_success "clone shallow object count (part 2)" '
 '
 
 test_expect_success "fsck in shallow repo" \
 '
 
 test_expect_success "fsck in shallow repo" \
-       "(cd shallow; git-fsck-objects --full)"
+       "(cd shallow; git-fsck --full)"
 
 #test_done; exit
 
 
 #test_done; exit
 
index b9f6d9636313c29cb9d9553ca908e623fdefd179..2f8e97cb7ea4b8bdf56d5795d512534d504d25c0 100755 (executable)
@@ -17,7 +17,7 @@ reachable_via() {
 }
 
 test_valid_repo() {
 }
 
 test_valid_repo() {
-       git fsck-objects --full > fsck.log &&
+       git fsck --full > fsck.log &&
        test `wc -l < fsck.log` = 0
 }
 
        test `wc -l < fsck.log` = 0
 }