2005-04-08 22:02:42 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
|
2005-04-30 16:59:31 +00:00
|
|
|
#include "cache.h"
|
2005-04-18 18:39:48 +00:00
|
|
|
#include "commit.h"
|
|
|
|
#include "tree.h"
|
|
|
|
#include "blob.h"
|
2005-04-28 14:46:33 +00:00
|
|
|
#include "tag.h"
|
2005-07-03 17:01:38 +00:00
|
|
|
#include "refs.h"
|
2005-06-29 09:51:27 +00:00
|
|
|
#include "pack.h"
|
2006-04-25 23:37:08 +00:00
|
|
|
#include "cache-tree.h"
|
2006-05-29 19:19:02 +00:00
|
|
|
#include "tree-walk.h"
|
2005-04-18 18:39:48 +00:00
|
|
|
|
|
|
|
#define REACHABLE 0x0001
|
2006-05-29 19:18:33 +00:00
|
|
|
#define SEEN 0x0002
|
2005-04-13 16:57:30 +00:00
|
|
|
|
2005-04-25 23:34:13 +00:00
|
|
|
static int show_root = 0;
|
2005-04-25 23:31:13 +00:00
|
|
|
static int show_tags = 0;
|
2005-04-13 16:57:30 +00:00
|
|
|
static int show_unreachable = 0;
|
2005-06-28 21:58:33 +00:00
|
|
|
static int check_full = 0;
|
2005-07-27 22:16:03 +00:00
|
|
|
static int check_strict = 0;
|
2006-03-09 09:44:19 +00:00
|
|
|
static int keep_cache_objects = 0;
|
2005-04-13 16:57:30 +00:00
|
|
|
static unsigned char head_sha1[20];
|
|
|
|
|
2006-02-26 15:13:46 +00:00
|
|
|
#ifdef NO_D_INO_IN_DIRENT
|
2006-01-20 01:13:51 +00:00
|
|
|
#define SORT_DIRENT 0
|
|
|
|
#define DIRENT_SORT_HINT(de) 0
|
|
|
|
#else
|
|
|
|
#define SORT_DIRENT 1
|
|
|
|
#define DIRENT_SORT_HINT(de) ((de)->d_ino)
|
|
|
|
#endif
|
2005-09-20 18:56:05 +00:00
|
|
|
|
|
|
|
static void objreport(struct object *obj, const char *severity,
|
|
|
|
const char *err, va_list params)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "%s in %s %s: ",
|
Shrink "struct object" a bit
This shrinks "struct object" by a small amount, by getting rid of the
"struct type *" pointer and replacing it with a 3-bit bitfield instead.
In addition, we merge the bitfields and the "flags" field, which
incidentally should also remove a useless 4-byte padding from the object
when in 64-bit mode.
Now, our "struct object" is still too damn large, but it's now less
obviously bloated, and of the remaining fields, only the "util" (which is
not used by most things) is clearly something that should be eventually
discarded.
This shrinks the "git-rev-list --all" memory use by about 2.5% on the
kernel archive (and, perhaps more importantly, on the larger mozilla
archive). That may not sound like much, but I suspect it's more on a
64-bit platform.
There are other remaining inefficiencies (the parent lists, for example,
probably have horrible malloc overhead), but this was pretty obvious.
Most of the patch is just changing the comparison of the "type" pointer
from one of the constant string pointers to the appropriate new TYPE_xxx
small integer constant.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-14 23:45:13 +00:00
|
|
|
severity, typename(obj->type), sha1_to_hex(obj->sha1));
|
2005-09-20 18:56:05 +00:00
|
|
|
vfprintf(stderr, err, params);
|
|
|
|
fputs("\n", stderr);
|
|
|
|
}
|
|
|
|
|
2005-09-28 12:04:54 +00:00
|
|
|
static int objerror(struct object *obj, const char *err, ...)
|
2005-09-20 18:56:05 +00:00
|
|
|
{
|
|
|
|
va_list params;
|
|
|
|
va_start(params, err);
|
|
|
|
objreport(obj, "error", err, params);
|
|
|
|
va_end(params);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-09-28 12:04:54 +00:00
|
|
|
static int objwarning(struct object *obj, const char *err, ...)
|
2005-09-20 18:56:05 +00:00
|
|
|
{
|
|
|
|
va_list params;
|
|
|
|
va_start(params, err);
|
|
|
|
objreport(obj, "warning", err, params);
|
|
|
|
va_end(params);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-04-11 06:13:09 +00:00
|
|
|
static void check_connectivity(void)
|
|
|
|
{
|
2006-06-30 04:38:55 +00:00
|
|
|
int i, max;
|
2005-04-11 06:13:09 +00:00
|
|
|
|
|
|
|
/* Look up all the requirements, warn about missing objects.. */
|
2006-06-30 04:38:55 +00:00
|
|
|
max = get_max_object_index();
|
|
|
|
for (i = 0; i < max; i++) {
|
2006-06-18 18:45:02 +00:00
|
|
|
const struct object_refs *refs;
|
2006-06-30 04:38:55 +00:00
|
|
|
struct object *obj = get_indexed_object(i);
|
2005-04-11 06:13:09 +00:00
|
|
|
|
2006-02-12 01:57:57 +00:00
|
|
|
if (!obj)
|
|
|
|
continue;
|
|
|
|
|
2005-04-30 18:22:26 +00:00
|
|
|
if (!obj->parsed) {
|
2006-03-09 09:44:19 +00:00
|
|
|
if (has_sha1_file(obj->sha1))
|
2005-06-28 21:58:33 +00:00
|
|
|
; /* it is in pack */
|
|
|
|
else
|
|
|
|
printf("missing %s %s\n",
|
Shrink "struct object" a bit
This shrinks "struct object" by a small amount, by getting rid of the
"struct type *" pointer and replacing it with a 3-bit bitfield instead.
In addition, we merge the bitfields and the "flags" field, which
incidentally should also remove a useless 4-byte padding from the object
when in 64-bit mode.
Now, our "struct object" is still too damn large, but it's now less
obviously bloated, and of the remaining fields, only the "util" (which is
not used by most things) is clearly something that should be eventually
discarded.
This shrinks the "git-rev-list --all" memory use by about 2.5% on the
kernel archive (and, perhaps more importantly, on the larger mozilla
archive). That may not sound like much, but I suspect it's more on a
64-bit platform.
There are other remaining inefficiencies (the parent lists, for example,
probably have horrible malloc overhead), but this was pretty obvious.
Most of the patch is just changing the comparison of the "type" pointer
from one of the constant string pointers to the appropriate new TYPE_xxx
small integer constant.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-14 23:45:13 +00:00
|
|
|
typename(obj->type), sha1_to_hex(obj->sha1));
|
2005-04-30 18:22:26 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2006-06-18 18:45:02 +00:00
|
|
|
refs = lookup_object_refs(obj);
|
|
|
|
if (refs) {
|
2005-11-15 16:08:08 +00:00
|
|
|
unsigned j;
|
|
|
|
for (j = 0; j < refs->count; j++) {
|
|
|
|
struct object *ref = refs->ref[j];
|
|
|
|
if (ref->parsed ||
|
2006-03-09 09:44:19 +00:00
|
|
|
(has_sha1_file(ref->sha1)))
|
2005-11-15 16:08:08 +00:00
|
|
|
continue;
|
|
|
|
printf("broken link from %7s %s\n",
|
Shrink "struct object" a bit
This shrinks "struct object" by a small amount, by getting rid of the
"struct type *" pointer and replacing it with a 3-bit bitfield instead.
In addition, we merge the bitfields and the "flags" field, which
incidentally should also remove a useless 4-byte padding from the object
when in 64-bit mode.
Now, our "struct object" is still too damn large, but it's now less
obviously bloated, and of the remaining fields, only the "util" (which is
not used by most things) is clearly something that should be eventually
discarded.
This shrinks the "git-rev-list --all" memory use by about 2.5% on the
kernel archive (and, perhaps more importantly, on the larger mozilla
archive). That may not sound like much, but I suspect it's more on a
64-bit platform.
There are other remaining inefficiencies (the parent lists, for example,
probably have horrible malloc overhead), but this was pretty obvious.
Most of the patch is just changing the comparison of the "type" pointer
from one of the constant string pointers to the appropriate new TYPE_xxx
small integer constant.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-14 23:45:13 +00:00
|
|
|
typename(obj->type), sha1_to_hex(obj->sha1));
|
2005-11-15 16:08:08 +00:00
|
|
|
printf(" to %7s %s\n",
|
Shrink "struct object" a bit
This shrinks "struct object" by a small amount, by getting rid of the
"struct type *" pointer and replacing it with a 3-bit bitfield instead.
In addition, we merge the bitfields and the "flags" field, which
incidentally should also remove a useless 4-byte padding from the object
when in 64-bit mode.
Now, our "struct object" is still too damn large, but it's now less
obviously bloated, and of the remaining fields, only the "util" (which is
not used by most things) is clearly something that should be eventually
discarded.
This shrinks the "git-rev-list --all" memory use by about 2.5% on the
kernel archive (and, perhaps more importantly, on the larger mozilla
archive). That may not sound like much, but I suspect it's more on a
64-bit platform.
There are other remaining inefficiencies (the parent lists, for example,
probably have horrible malloc overhead), but this was pretty obvious.
Most of the patch is just changing the comparison of the "type" pointer
from one of the constant string pointers to the appropriate new TYPE_xxx
small integer constant.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-14 23:45:13 +00:00
|
|
|
typename(ref->type), sha1_to_hex(ref->sha1));
|
2005-11-15 16:08:08 +00:00
|
|
|
}
|
2005-04-30 18:22:26 +00:00
|
|
|
}
|
|
|
|
|
2005-04-18 18:39:48 +00:00
|
|
|
if (show_unreachable && !(obj->flags & REACHABLE)) {
|
2005-06-27 10:33:33 +00:00
|
|
|
printf("unreachable %s %s\n",
|
Shrink "struct object" a bit
This shrinks "struct object" by a small amount, by getting rid of the
"struct type *" pointer and replacing it with a 3-bit bitfield instead.
In addition, we merge the bitfields and the "flags" field, which
incidentally should also remove a useless 4-byte padding from the object
when in 64-bit mode.
Now, our "struct object" is still too damn large, but it's now less
obviously bloated, and of the remaining fields, only the "util" (which is
not used by most things) is clearly something that should be eventually
discarded.
This shrinks the "git-rev-list --all" memory use by about 2.5% on the
kernel archive (and, perhaps more importantly, on the larger mozilla
archive). That may not sound like much, but I suspect it's more on a
64-bit platform.
There are other remaining inefficiencies (the parent lists, for example,
probably have horrible malloc overhead), but this was pretty obvious.
Most of the patch is just changing the comparison of the "type" pointer
from one of the constant string pointers to the appropriate new TYPE_xxx
small integer constant.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-14 23:45:13 +00:00
|
|
|
typename(obj->type), sha1_to_hex(obj->sha1));
|
2005-04-11 06:13:09 +00:00
|
|
|
continue;
|
2005-04-13 16:57:30 +00:00
|
|
|
}
|
2005-04-11 06:13:09 +00:00
|
|
|
|
2005-04-18 18:39:48 +00:00
|
|
|
if (!obj->used) {
|
Shrink "struct object" a bit
This shrinks "struct object" by a small amount, by getting rid of the
"struct type *" pointer and replacing it with a 3-bit bitfield instead.
In addition, we merge the bitfields and the "flags" field, which
incidentally should also remove a useless 4-byte padding from the object
when in 64-bit mode.
Now, our "struct object" is still too damn large, but it's now less
obviously bloated, and of the remaining fields, only the "util" (which is
not used by most things) is clearly something that should be eventually
discarded.
This shrinks the "git-rev-list --all" memory use by about 2.5% on the
kernel archive (and, perhaps more importantly, on the larger mozilla
archive). That may not sound like much, but I suspect it's more on a
64-bit platform.
There are other remaining inefficiencies (the parent lists, for example,
probably have horrible malloc overhead), but this was pretty obvious.
Most of the patch is just changing the comparison of the "type" pointer
from one of the constant string pointers to the appropriate new TYPE_xxx
small integer constant.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-14 23:45:13 +00:00
|
|
|
printf("dangling %s %s\n", typename(obj->type),
|
2005-04-18 18:39:48 +00:00
|
|
|
sha1_to_hex(obj->sha1));
|
2005-04-13 16:57:30 +00:00
|
|
|
}
|
2005-04-11 06:13:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-05-02 23:13:18 +00:00
|
|
|
/*
|
|
|
|
* 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".
|
|
|
|
*/
|
2005-05-07 21:43:32 +00:00
|
|
|
#define TREE_UNORDERED (-1)
|
|
|
|
#define TREE_HAS_DUPS (-2)
|
|
|
|
|
2006-05-29 19:19:02 +00:00
|
|
|
static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2)
|
2005-05-02 23:13:18 +00:00
|
|
|
{
|
2006-05-29 19:19:02 +00:00
|
|
|
int len1 = strlen(name1);
|
|
|
|
int len2 = strlen(name2);
|
2005-05-02 23:13:18 +00:00
|
|
|
int len = len1 < len2 ? len1 : len2;
|
|
|
|
unsigned char c1, c2;
|
|
|
|
int cmp;
|
|
|
|
|
2006-05-29 19:19:02 +00:00
|
|
|
cmp = memcmp(name1, name2, len);
|
2005-05-02 23:13:18 +00:00
|
|
|
if (cmp < 0)
|
|
|
|
return 0;
|
|
|
|
if (cmp > 0)
|
2005-05-07 21:43:32 +00:00
|
|
|
return TREE_UNORDERED;
|
2005-05-02 23:13:18 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2006-05-29 19:19:02 +00:00
|
|
|
c1 = name1[len];
|
|
|
|
c2 = name2[len];
|
2005-05-07 21:43:32 +00:00
|
|
|
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;
|
2006-05-29 19:19:02 +00:00
|
|
|
if (!c1 && S_ISDIR(mode1))
|
2005-05-02 23:13:18 +00:00
|
|
|
c1 = '/';
|
2006-05-29 19:19:02 +00:00
|
|
|
if (!c2 && S_ISDIR(mode2))
|
2005-05-02 23:13:18 +00:00
|
|
|
c2 = '/';
|
2005-05-07 21:43:32 +00:00
|
|
|
return c1 < c2 ? 0 : TREE_UNORDERED;
|
2005-05-02 23:13:18 +00:00
|
|
|
}
|
|
|
|
|
2005-04-28 14:46:33 +00:00
|
|
|
static int fsck_tree(struct tree *item)
|
2005-04-08 22:02:42 +00:00
|
|
|
{
|
2005-07-27 23:08:43 +00:00
|
|
|
int retval;
|
2005-05-02 23:13:18 +00:00
|
|
|
int has_full_path = 0;
|
2005-07-27 23:08:43 +00:00
|
|
|
int has_zero_pad = 0;
|
|
|
|
int has_bad_modes = 0;
|
|
|
|
int has_dup_entries = 0;
|
|
|
|
int not_properly_sorted = 0;
|
2006-05-29 19:19:02 +00:00
|
|
|
struct tree_desc desc;
|
|
|
|
unsigned o_mode;
|
|
|
|
const char *o_name;
|
|
|
|
const unsigned char *o_sha1;
|
2005-05-02 23:13:18 +00:00
|
|
|
|
2006-05-29 19:19:02 +00:00
|
|
|
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, '/'))
|
2005-05-02 23:13:18 +00:00
|
|
|
has_full_path = 1;
|
2006-05-29 19:19:02 +00:00
|
|
|
has_zero_pad |= *(char *)desc.buf == '0';
|
|
|
|
update_tree_entry(&desc);
|
2005-05-02 23:13:18 +00:00
|
|
|
|
2006-05-29 19:19:02 +00:00
|
|
|
switch (mode) {
|
2005-05-05 23:18:48 +00:00
|
|
|
/*
|
2006-05-29 19:19:02 +00:00
|
|
|
* Standard modes..
|
2005-05-05 23:18:48 +00:00
|
|
|
*/
|
|
|
|
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:
|
2005-07-27 22:16:03 +00:00
|
|
|
if (!check_strict)
|
|
|
|
break;
|
2005-05-05 23:18:48 +00:00
|
|
|
default:
|
2005-07-27 23:08:43 +00:00
|
|
|
has_bad_modes = 1;
|
2005-05-05 23:18:48 +00:00
|
|
|
}
|
|
|
|
|
2006-05-29 19:19:02 +00:00
|
|
|
if (o_name) {
|
|
|
|
switch (verify_ordered(o_mode, o_name, mode, name)) {
|
2005-05-07 21:43:32 +00:00
|
|
|
case TREE_UNORDERED:
|
2005-07-27 23:08:43 +00:00
|
|
|
not_properly_sorted = 1;
|
|
|
|
break;
|
2005-05-07 21:43:32 +00:00
|
|
|
case TREE_HAS_DUPS:
|
2005-07-27 23:08:43 +00:00
|
|
|
has_dup_entries = 1;
|
|
|
|
break;
|
2005-05-07 21:43:32 +00:00
|
|
|
default:
|
|
|
|
break;
|
2005-05-02 23:13:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-29 19:19:02 +00:00
|
|
|
o_mode = mode;
|
|
|
|
o_name = name;
|
|
|
|
o_sha1 = sha1;
|
2005-05-02 23:13:18 +00:00
|
|
|
}
|
2006-05-29 19:16:12 +00:00
|
|
|
free(item->buffer);
|
|
|
|
item->buffer = NULL;
|
2005-05-02 23:13:18 +00:00
|
|
|
|
2005-07-27 23:08:43 +00:00
|
|
|
retval = 0;
|
2005-05-02 23:13:18 +00:00
|
|
|
if (has_full_path) {
|
2005-09-20 18:56:05 +00:00
|
|
|
objwarning(&item->object, "contains full pathnames");
|
2005-04-09 00:11:14 +00:00
|
|
|
}
|
2005-07-27 23:08:43 +00:00
|
|
|
if (has_zero_pad) {
|
2005-09-20 18:56:05 +00:00
|
|
|
objwarning(&item->object, "contains zero-padded file modes");
|
2005-07-27 23:08:43 +00:00
|
|
|
}
|
|
|
|
if (has_bad_modes) {
|
2005-09-20 18:56:05 +00:00
|
|
|
objwarning(&item->object, "contains bad file modes");
|
2005-07-27 23:08:43 +00:00
|
|
|
}
|
|
|
|
if (has_dup_entries) {
|
2005-09-20 18:56:05 +00:00
|
|
|
retval = objerror(&item->object, "contains duplicate file entries");
|
2005-07-27 23:08:43 +00:00
|
|
|
}
|
|
|
|
if (not_properly_sorted) {
|
2005-09-20 18:56:05 +00:00
|
|
|
retval = objerror(&item->object, "not properly sorted");
|
2005-07-27 23:08:43 +00:00
|
|
|
}
|
|
|
|
return retval;
|
2005-04-09 00:11:14 +00:00
|
|
|
}
|
|
|
|
|
2005-04-28 14:46:33 +00:00
|
|
|
static int fsck_commit(struct commit *commit)
|
2005-04-09 00:11:14 +00:00
|
|
|
{
|
2005-07-27 22:16:03 +00:00
|
|
|
char *buffer = commit->buffer;
|
2005-09-20 18:56:05 +00:00
|
|
|
unsigned char tree_sha1[20], sha1[20];
|
2005-07-27 22:16:03 +00:00
|
|
|
|
|
|
|
if (memcmp(buffer, "tree ", 5))
|
2005-09-20 18:56:05 +00:00
|
|
|
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");
|
2005-07-27 22:16:03 +00:00
|
|
|
buffer += 46;
|
|
|
|
while (!memcmp(buffer, "parent ", 7)) {
|
|
|
|
if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n')
|
2005-09-20 18:56:05 +00:00
|
|
|
return objerror(&commit->object, "invalid 'parent' line format - bad sha1");
|
2005-07-27 22:16:03 +00:00
|
|
|
buffer += 48;
|
|
|
|
}
|
|
|
|
if (memcmp(buffer, "author ", 7))
|
2005-09-20 18:56:05 +00:00
|
|
|
return objerror(&commit->object, "invalid format - expected 'author' line");
|
2005-05-26 02:26:28 +00:00
|
|
|
free(commit->buffer);
|
|
|
|
commit->buffer = NULL;
|
2005-04-18 18:39:48 +00:00
|
|
|
if (!commit->tree)
|
2005-09-20 18:56:05 +00:00
|
|
|
return objerror(&commit->object, "could not load commit's tree %s", tree_sha1);
|
2005-04-25 23:34:13 +00:00
|
|
|
if (!commit->parents && show_root)
|
2005-04-28 14:46:33 +00:00
|
|
|
printf("root %s\n", sha1_to_hex(commit->object.sha1));
|
2005-04-24 23:20:53 +00:00
|
|
|
if (!commit->date)
|
2005-04-28 14:46:33 +00:00
|
|
|
printf("bad commit date in %s\n",
|
|
|
|
sha1_to_hex(commit->object.sha1));
|
2005-04-24 21:10:55 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-28 14:46:33 +00:00
|
|
|
static int fsck_tag(struct tag *tag)
|
2005-04-25 19:07:44 +00:00
|
|
|
{
|
2005-05-03 14:57:56 +00:00
|
|
|
struct object *tagged = tag->tagged;
|
|
|
|
|
|
|
|
if (!tagged) {
|
2005-09-20 18:56:05 +00:00
|
|
|
return objerror(&tag->object, "could not load tagged object");
|
2005-05-03 14:57:56 +00:00
|
|
|
}
|
2005-04-25 23:31:13 +00:00
|
|
|
if (!show_tags)
|
|
|
|
return 0;
|
|
|
|
|
Shrink "struct object" a bit
This shrinks "struct object" by a small amount, by getting rid of the
"struct type *" pointer and replacing it with a 3-bit bitfield instead.
In addition, we merge the bitfields and the "flags" field, which
incidentally should also remove a useless 4-byte padding from the object
when in 64-bit mode.
Now, our "struct object" is still too damn large, but it's now less
obviously bloated, and of the remaining fields, only the "util" (which is
not used by most things) is clearly something that should be eventually
discarded.
This shrinks the "git-rev-list --all" memory use by about 2.5% on the
kernel archive (and, perhaps more importantly, on the larger mozilla
archive). That may not sound like much, but I suspect it's more on a
64-bit platform.
There are other remaining inefficiencies (the parent lists, for example,
probably have horrible malloc overhead), but this was pretty obvious.
Most of the patch is just changing the comparison of the "type" pointer
from one of the constant string pointers to the appropriate new TYPE_xxx
small integer constant.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-14 23:45:13 +00:00
|
|
|
printf("tagged %s %s", typename(tagged->type), sha1_to_hex(tagged->sha1));
|
2005-05-03 14:57:56 +00:00
|
|
|
printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1));
|
2005-04-18 18:39:48 +00:00
|
|
|
return 0;
|
2005-04-08 22:02:42 +00:00
|
|
|
}
|
|
|
|
|
2005-05-02 16:06:33 +00:00
|
|
|
static int fsck_sha1(unsigned char *sha1)
|
2005-04-08 22:02:42 +00:00
|
|
|
{
|
2005-05-02 16:06:33 +00:00
|
|
|
struct object *obj = parse_object(sha1);
|
|
|
|
if (!obj)
|
2005-09-20 18:56:05 +00:00
|
|
|
return error("%s: object not found", sha1_to_hex(sha1));
|
2006-05-29 19:18:33 +00:00
|
|
|
if (obj->flags & SEEN)
|
|
|
|
return 0;
|
|
|
|
obj->flags |= SEEN;
|
2006-07-12 03:45:31 +00:00
|
|
|
if (obj->type == OBJ_BLOB)
|
2005-05-02 16:06:33 +00:00
|
|
|
return 0;
|
2006-07-12 03:45:31 +00:00
|
|
|
if (obj->type == OBJ_TREE)
|
2005-05-02 16:06:33 +00:00
|
|
|
return fsck_tree((struct tree *) obj);
|
2006-07-12 03:45:31 +00:00
|
|
|
if (obj->type == OBJ_COMMIT)
|
2005-05-02 16:06:33 +00:00
|
|
|
return fsck_commit((struct commit *) obj);
|
2006-07-12 03:45:31 +00:00
|
|
|
if (obj->type == OBJ_TAG)
|
2005-05-02 16:06:33 +00:00
|
|
|
return fsck_tag((struct tag *) obj);
|
2005-09-20 18:56:05 +00:00
|
|
|
/* By now, parse_object() would've returned NULL instead. */
|
Shrink "struct object" a bit
This shrinks "struct object" by a small amount, by getting rid of the
"struct type *" pointer and replacing it with a 3-bit bitfield instead.
In addition, we merge the bitfields and the "flags" field, which
incidentally should also remove a useless 4-byte padding from the object
when in 64-bit mode.
Now, our "struct object" is still too damn large, but it's now less
obviously bloated, and of the remaining fields, only the "util" (which is
not used by most things) is clearly something that should be eventually
discarded.
This shrinks the "git-rev-list --all" memory use by about 2.5% on the
kernel archive (and, perhaps more importantly, on the larger mozilla
archive). That may not sound like much, but I suspect it's more on a
64-bit platform.
There are other remaining inefficiencies (the parent lists, for example,
probably have horrible malloc overhead), but this was pretty obvious.
Most of the patch is just changing the comparison of the "type" pointer
from one of the constant string pointers to the appropriate new TYPE_xxx
small integer constant.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-14 23:45:13 +00:00
|
|
|
return objerror(obj, "unknown type '%d' (internal fsck error)", obj->type);
|
2005-05-02 16:06:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
2005-04-08 22:02:42 +00:00
|
|
|
unsigned char sha1[20];
|
2005-05-02 16:06:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2006-01-20 01:13:51 +00:00
|
|
|
if (SORT_DIRENT)
|
|
|
|
qsort(sha1_list.entry, nr,
|
|
|
|
sizeof(struct sha1_entry *), ino_compare);
|
2005-05-02 16:06:33 +00:00
|
|
|
for (i = 0; i < nr; i++) {
|
|
|
|
struct sha1_entry *entry = sha1_list.entry[i];
|
|
|
|
unsigned char *sha1 = entry->sha1;
|
|
|
|
|
|
|
|
sha1_list.entry[i] = NULL;
|
2005-09-20 18:56:05 +00:00
|
|
|
fsck_sha1(sha1);
|
2005-05-02 16:06:33 +00:00
|
|
|
free(entry);
|
2005-04-08 22:02:42 +00:00
|
|
|
}
|
2005-05-02 16:06:33 +00:00
|
|
|
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;
|
|
|
|
memcpy(entry->sha1, sha1, 20);
|
|
|
|
nr = sha1_list.nr;
|
|
|
|
if (nr == MAX_SHA1_ENTRIES) {
|
|
|
|
fsck_sha1_list();
|
|
|
|
nr = 0;
|
|
|
|
}
|
|
|
|
sha1_list.entry[nr] = entry;
|
|
|
|
sha1_list.nr = ++nr;
|
2005-04-08 22:02:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int fsck_dir(int i, char *path)
|
|
|
|
{
|
|
|
|
DIR *dir = opendir(path);
|
|
|
|
struct dirent *de;
|
|
|
|
|
Create object subdirectories on demand
This makes it possible to have a "sparse" git object subdirectory
structure, something that has become much more attractive now that people
use pack-files all the time.
As a result of pack-files, a git object directory doesn't necessarily have
any individual objects lying around, and in that case it's just wasting
space to keep the empty first-level object directories around: on many
filesystems the 256 empty directories will be aboue 1MB of diskspace.
Even more importantly, after you re-pack a project that _used_ to be
unpacked, you could be left with huge directories that no longer contain
anything, but that waste space and take time to look through.
With this change, "git prune-packed" can just do an rmdir() on the
directories, and they'll get removed if empty, and re-created on demand.
This patch also tries to fix up "write_sha1_from_fd()" to use the new
common infrastructure for creating the object files, closing a hole where
we might otherwise leave half-written objects in the object database.
[jc: I unoptimized the part that really removes the fan-out directories
to ease transition. init-db still wastes 1MB of diskspace to hold 256
empty fan-outs, and prune-packed rmdir()'s the grown but empty directories,
but runs mkdir() immediately after that -- reducing the saving from 150KB
to 146KB. These parts will be re-introduced when everybody has the
on-demand capability.]
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-10-08 22:54:01 +00:00
|
|
|
if (!dir)
|
|
|
|
return 0;
|
2005-04-08 22:02:42 +00:00
|
|
|
|
|
|
|
while ((de = readdir(dir)) != NULL) {
|
|
|
|
char name[100];
|
2005-05-02 16:06:33 +00:00
|
|
|
unsigned char sha1[20];
|
2005-04-08 22:02:42 +00:00
|
|
|
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);
|
2005-05-02 16:06:33 +00:00
|
|
|
if (get_sha1_hex(name, sha1) < 0)
|
|
|
|
break;
|
2006-01-20 01:13:51 +00:00
|
|
|
add_sha1_list(sha1, DIRENT_SORT_HINT(de));
|
2005-05-02 16:06:33 +00:00
|
|
|
continue;
|
2005-04-08 22:02:42 +00:00
|
|
|
}
|
|
|
|
fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
|
|
|
|
}
|
|
|
|
closedir(dir);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-07-03 17:01:38 +00:00
|
|
|
static int default_refs = 0;
|
|
|
|
|
|
|
|
static int fsck_handle_ref(const char *refname, const unsigned char *sha1)
|
2005-05-18 17:16:14 +00:00
|
|
|
{
|
|
|
|
struct object *obj;
|
|
|
|
|
|
|
|
obj = lookup_object(sha1);
|
2005-06-28 21:58:33 +00:00
|
|
|
if (!obj) {
|
2006-03-09 09:44:19 +00:00
|
|
|
if (has_sha1_file(sha1)) {
|
2005-07-08 00:05:41 +00:00
|
|
|
default_refs++;
|
2005-07-03 17:01:38 +00:00
|
|
|
return 0; /* it is in a pack */
|
2005-07-08 00:05:41 +00:00
|
|
|
}
|
2005-07-03 17:01:38 +00:00
|
|
|
error("%s: invalid sha1 pointer %s", refname, sha1_to_hex(sha1));
|
|
|
|
/* We'll continue with the rest despite the error.. */
|
|
|
|
return 0;
|
2005-06-28 21:58:33 +00:00
|
|
|
}
|
2005-07-03 17:01:38 +00:00
|
|
|
default_refs++;
|
2005-05-18 17:16:14 +00:00
|
|
|
obj->used = 1;
|
|
|
|
mark_reachable(obj, REACHABLE);
|
2005-05-20 14:49:17 +00:00
|
|
|
return 0;
|
2005-05-18 17:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void get_default_heads(void)
|
|
|
|
{
|
2005-07-03 17:01:38 +00:00
|
|
|
for_each_ref(fsck_handle_ref);
|
|
|
|
if (!default_refs)
|
2005-06-05 16:55:27 +00:00
|
|
|
die("No default references");
|
2005-05-18 17:16:14 +00:00
|
|
|
}
|
|
|
|
|
2005-06-28 21:58:33 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2005-07-03 17:40:38 +00:00
|
|
|
static int fsck_head_link(void)
|
|
|
|
{
|
|
|
|
unsigned char sha1[20];
|
2005-09-30 21:26:57 +00:00
|
|
|
const char *git_HEAD = strdup(git_path("HEAD"));
|
|
|
|
const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1, 1);
|
|
|
|
int pfxlen = strlen(git_HEAD) - 4; /* strip .../.git/ part */
|
|
|
|
|
|
|
|
if (!git_refs_heads_master)
|
|
|
|
return error("HEAD is not a symbolic ref");
|
|
|
|
if (strncmp(git_refs_heads_master + pfxlen, "refs/heads/", 11))
|
|
|
|
return error("HEAD points to something strange (%s)",
|
|
|
|
git_refs_heads_master + pfxlen);
|
|
|
|
if (!memcmp(null_sha1, sha1, 20))
|
2005-07-03 17:40:38 +00:00
|
|
|
return error("HEAD: not a valid git pointer");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-04-25 23:37:08 +00:00
|
|
|
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);
|
2006-05-04 04:17:45 +00:00
|
|
|
if (!obj) {
|
|
|
|
error("%s: invalid sha1 pointer in cache-tree",
|
|
|
|
sha1_to_hex(it->sha1));
|
|
|
|
return 1;
|
|
|
|
}
|
2006-05-02 05:15:54 +00:00
|
|
|
mark_reachable(obj, REACHABLE);
|
|
|
|
obj->used = 1;
|
2006-07-12 03:45:31 +00:00
|
|
|
if (obj->type != OBJ_TREE)
|
2006-04-25 23:37:08 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2005-04-08 22:02:42 +00:00
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
2005-04-13 23:42:09 +00:00
|
|
|
int i, heads;
|
2005-04-08 22:02:42 +00:00
|
|
|
|
2006-05-29 19:16:46 +00:00
|
|
|
track_object_refs = 1;
|
2005-11-26 07:52:04 +00:00
|
|
|
setup_git_directory();
|
|
|
|
|
2005-04-25 23:31:13 +00:00
|
|
|
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;
|
|
|
|
}
|
2005-04-25 23:34:13 +00:00
|
|
|
if (!strcmp(arg, "--root")) {
|
|
|
|
show_root = 1;
|
|
|
|
continue;
|
|
|
|
}
|
2005-05-04 08:33:33 +00:00
|
|
|
if (!strcmp(arg, "--cache")) {
|
|
|
|
keep_cache_objects = 1;
|
|
|
|
continue;
|
|
|
|
}
|
2005-06-28 21:58:33 +00:00
|
|
|
if (!strcmp(arg, "--full")) {
|
|
|
|
check_full = 1;
|
|
|
|
continue;
|
|
|
|
}
|
2005-07-27 22:16:03 +00:00
|
|
|
if (!strcmp(arg, "--strict")) {
|
|
|
|
check_strict = 1;
|
|
|
|
continue;
|
|
|
|
}
|
2005-04-25 23:31:13 +00:00
|
|
|
if (*arg == '-')
|
2006-03-09 09:44:19 +00:00
|
|
|
usage("git-fsck-objects [--tags] [--root] [[--unreachable] [--cache] [--full] [--strict] <head-sha1>*]");
|
2005-04-25 23:31:13 +00:00
|
|
|
}
|
|
|
|
|
2005-07-03 17:40:38 +00:00
|
|
|
fsck_head_link();
|
2005-06-28 21:58:33 +00:00
|
|
|
fsck_object_dir(get_object_directory());
|
|
|
|
if (check_full) {
|
2005-08-15 00:25:57 +00:00
|
|
|
struct alternate_object_database *alt;
|
2005-06-28 21:58:33 +00:00
|
|
|
struct packed_git *p;
|
|
|
|
prepare_alt_odb();
|
2005-08-15 00:25:57 +00:00
|
|
|
for (alt = alt_odb_list; alt; alt = alt->next) {
|
2005-07-10 22:40:43 +00:00
|
|
|
char namebuf[PATH_MAX];
|
2005-08-15 00:25:57 +00:00
|
|
|
int namelen = alt->name - alt->base;
|
|
|
|
memcpy(namebuf, alt->base, namelen);
|
2005-07-10 22:40:43 +00:00
|
|
|
namebuf[namelen - 1] = 0;
|
|
|
|
fsck_object_dir(namebuf);
|
2005-06-28 21:58:33 +00:00
|
|
|
}
|
|
|
|
prepare_packed_git();
|
2005-06-29 09:51:27 +00:00
|
|
|
for (p = packed_git; p; p = p->next)
|
|
|
|
/* verify gives error messages itself */
|
2005-07-01 00:15:39 +00:00
|
|
|
verify_pack(p, 0);
|
2005-06-29 09:51:27 +00:00
|
|
|
|
2005-06-28 21:58:33 +00:00
|
|
|
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);
|
2005-09-20 18:56:05 +00:00
|
|
|
fsck_sha1(sha1);
|
2005-06-28 21:58:33 +00:00
|
|
|
}
|
|
|
|
}
|
2005-04-13 23:42:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
heads = 0;
|
2005-04-13 16:57:30 +00:00
|
|
|
for (i = 1; i < argc; i++) {
|
2005-04-25 23:31:13 +00:00
|
|
|
const char *arg = argv[i];
|
|
|
|
|
|
|
|
if (*arg == '-')
|
2005-04-13 16:57:30 +00:00
|
|
|
continue;
|
2005-04-25 23:31:13 +00:00
|
|
|
|
2005-05-01 23:36:56 +00:00
|
|
|
if (!get_sha1(arg, head_sha1)) {
|
2005-05-05 00:03:09 +00:00
|
|
|
struct object *obj = lookup_object(head_sha1);
|
2005-04-30 03:00:40 +00:00
|
|
|
|
2005-05-05 00:03:09 +00:00
|
|
|
/* Error is printed by lookup_object(). */
|
|
|
|
if (!obj)
|
2005-04-30 03:00:40 +00:00
|
|
|
continue;
|
|
|
|
|
2005-04-18 18:39:48 +00:00
|
|
|
obj->used = 1;
|
|
|
|
mark_reachable(obj, REACHABLE);
|
2005-04-13 23:42:09 +00:00
|
|
|
heads++;
|
2005-04-13 16:57:30 +00:00
|
|
|
continue;
|
|
|
|
}
|
2005-09-20 18:56:05 +00:00
|
|
|
error("invalid parameter: expected sha1, got '%s'", arg);
|
2005-04-13 16:57:30 +00:00
|
|
|
}
|
|
|
|
|
2005-05-18 17:16:14 +00:00
|
|
|
/*
|
2005-05-20 20:59:17 +00:00
|
|
|
* If we've not been given any explicit head information, do the
|
2005-05-18 17:19:59 +00:00
|
|
|
* default ones from .git/refs. We also consider the index file
|
|
|
|
* in this case (ie this implies --cache).
|
2005-05-18 17:16:14 +00:00
|
|
|
*/
|
2005-05-18 17:19:59 +00:00
|
|
|
if (!heads) {
|
2005-05-18 17:16:14 +00:00
|
|
|
get_default_heads();
|
|
|
|
keep_cache_objects = 1;
|
|
|
|
}
|
|
|
|
|
2005-05-04 08:33:33 +00:00
|
|
|
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);
|
|
|
|
}
|
2006-04-25 23:37:08 +00:00
|
|
|
if (active_cache_tree)
|
|
|
|
fsck_cache_tree(active_cache_tree);
|
2005-05-04 08:33:33 +00:00
|
|
|
}
|
|
|
|
|
2005-04-11 06:13:09 +00:00
|
|
|
check_connectivity();
|
2005-04-08 22:02:42 +00:00
|
|
|
return 0;
|
|
|
|
}
|