summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--unpack-objects.c105
2 files changed, 107 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 37fdbb0..89f6f93 100644
--- a/Makefile
+++ b/Makefile
@@ -36,7 +36,7 @@ PROG= git-update-cache git-diff-files git-init-db git-write-tree \
git-diff-helper git-tar-tree git-local-pull git-write-blob \
git-get-tar-commit-id git-mkdelta git-apply git-stripspace \
git-cvs2git git-diff-stages git-rev-parse git-patch-id \
- git-pack-objects
+ git-pack-objects git-unpack-objects
all: $(PROG)
@@ -124,6 +124,7 @@ git-diff-stages: diff-stages.c
git-rev-parse: rev-parse.c
git-patch-id: patch-id.c
git-pack-objects: pack-objects.c
+git-unpack-objects: unpack-objects.c
git-http-pull: LIBS += -lcurl
git-rev-list: LIBS += -lssl
diff --git a/unpack-objects.c b/unpack-objects.c
new file mode 100644
index 0000000..73d0c2d
--- /dev/null
+++ b/unpack-objects.c
@@ -0,0 +1,105 @@
+#include "cache.h"
+
+static int nr_entries;
+static const char *base_name;
+static const char unpack_usage[] = "git-unpack-objects basename";
+
+struct pack_entry {
+ unsigned int offset;
+ unsigned char sha1[20];
+};
+
+static struct pack_entry **pack_list;
+
+static void *map_file(const char *suffix, unsigned long *sizep)
+{
+ static char pathname[PATH_MAX];
+ unsigned long len;
+ int fd;
+ struct stat st;
+ void *map;
+
+ len = snprintf(pathname, PATH_MAX, "%s.%s", base_name, suffix);
+ if (len >= PATH_MAX)
+ die("bad pack base-name");
+ fd = open(pathname, O_RDONLY);
+ if (fd < 0 || fstat(fd, &st))
+ die("unable to open '%s'", pathname);
+ len = st.st_size;
+ if (!len)
+ die("bad pack file '%s'", pathname);
+ map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (-1 == (int)(long)map)
+ die("unable to mmap '%s'", pathname);
+ close(fd);
+ *sizep = len;
+ return map;
+}
+
+static int sort_by_offset(const void *_a, const void *_b)
+{
+ struct pack_entry *a = *(struct pack_entry **)_a;
+ struct pack_entry *b = *(struct pack_entry **)_b;
+ unsigned int o1, o2;
+
+ o1 = ntohl(a->offset);
+ o2 = ntohl(b->offset);
+ return o1 < o2 ? -1 : 1;
+}
+
+static int check_index(void *index, unsigned long idx_size)
+{
+ unsigned int *array = index;
+ unsigned int nr;
+ int i;
+
+ if (idx_size < 4*256)
+ return error("index file too small");
+ nr = 0;
+ for (i = 0; i < 256; i++) {
+ unsigned int n = ntohl(array[i]);
+ if (n < nr)
+ return error("non-monotonic index");
+ nr = n;
+ }
+ if (idx_size != 4*256 + nr * 24) {
+ printf("idx_size=%d, expected %d (%d)\n", idx_size, 4*256 + nr * 24, nr);
+ return error("wrong index file size");
+ }
+
+ nr_entries = nr;
+ pack_list = xmalloc(nr * sizeof(struct pack_entry *));
+ for (i = 0; i < nr; i++)
+ pack_list[i] = index + 4*256 + i*24;
+
+ qsort(pack_list, nr, sizeof(*pack_list), sort_by_offset);
+
+ printf("%d entries\n", nr);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+ unsigned long idx_size, pack_size;
+ void *index, *pack;
+
+ for (i = 1 ; i < argc; i++) {
+ const char *arg = argv[i];
+
+ if (*arg == '-') {
+ /* Maybe we'll have some flags here some day.. */
+ usage(unpack_usage);
+ }
+ if (base_name)
+ usage(unpack_usage);
+ base_name = arg;
+ }
+ if (!base_name)
+ usage(unpack_usage);
+ index = map_file("idx", &idx_size);
+ pack = map_file("pack", &pack_size);
+ if (check_index(index, idx_size) < 0)
+ die("bad index file");
+ return 0;
+}