Merge branch 'jm/api-strbuf-doc' into maint
[gitweb.git] / builtin / index-pack.c
index 79dfe47320e244c3110ce65d5b19fa87ebca3cb5..9ca0203922ba41139ad8daa9672acd22602bc1b5 100644 (file)
@@ -40,17 +40,13 @@ struct base_data {
        int ofs_first, ofs_last;
 };
 
-#if !defined(NO_PTHREADS) && defined(NO_THREAD_SAFE_PREAD)
-/* pread() emulation is not thread-safe. Disable threading. */
-#define NO_PTHREADS
-#endif
-
 struct thread_local {
 #ifndef NO_PTHREADS
        pthread_t thread;
 #endif
        struct base_data *base_cache;
        size_t base_cache_used;
+       int pack_fd;
 };
 
 /*
@@ -77,8 +73,10 @@ static int nr_threads;
 
 static int from_stdin;
 static int strict;
+static int do_fsck_object;
 static int verbose;
 static int show_stat;
+static int check_self_contained_and_connected;
 
 static struct progress *progress;
 
@@ -89,7 +87,8 @@ static off_t consumed_bytes;
 static unsigned deepest_delta;
 static git_SHA_CTX input_ctx;
 static uint32_t input_crc32;
-static int input_fd, output_fd, pack_fd;
+static int input_fd, output_fd;
+static const char *curr_pack;
 
 #ifndef NO_PTHREADS
 
@@ -132,6 +131,7 @@ static inline void unlock_mutex(pthread_mutex_t *mutex)
  */
 static void init_thread(void)
 {
+       int i;
        init_recursive_mutex(&read_mutex);
        pthread_mutex_init(&counter_mutex, NULL);
        pthread_mutex_init(&work_mutex, NULL);
@@ -139,11 +139,18 @@ static void init_thread(void)
                pthread_mutex_init(&deepest_delta_mutex, NULL);
        pthread_key_create(&key, NULL);
        thread_data = xcalloc(nr_threads, sizeof(*thread_data));
+       for (i = 0; i < nr_threads; i++) {
+               thread_data[i].pack_fd = open(curr_pack, O_RDONLY);
+               if (thread_data[i].pack_fd == -1)
+                       die_errno(_("unable to open %s"), curr_pack);
+       }
+
        threads_active = 1;
 }
 
 static void cleanup_thread(void)
 {
+       int i;
        if (!threads_active)
                return;
        threads_active = 0;
@@ -152,6 +159,8 @@ static void cleanup_thread(void)
        pthread_mutex_destroy(&work_mutex);
        if (show_stat)
                pthread_mutex_destroy(&deepest_delta_mutex);
+       for (i = 0; i < nr_threads; i++)
+               close(thread_data[i].pack_fd);
        pthread_key_delete(key);
        free(thread_data);
 }
@@ -187,31 +196,39 @@ static int mark_link(struct object *obj, int type, void *data)
 
 /* The content of each linked object must have been checked
    or it must be already present in the object database */
-static void check_object(struct object *obj)
+static unsigned check_object(struct object *obj)
 {
        if (!obj)
-               return;
+               return 0;
 
        if (!(obj->flags & FLAG_LINK))
-               return;
+               return 0;
 
        if (!(obj->flags & FLAG_CHECKED)) {
                unsigned long size;
                int type = sha1_object_info(obj->sha1, &size);
-               if (type != obj->type || type <= 0)
-                       die(_("object of unexpected type"));
+               if (type <= 0)
+                       die(_("did not receive expected object %s"),
+                             sha1_to_hex(obj->sha1));
+               if (type != obj->type)
+                       die(_("object %s: expected type %s, found %s"),
+                           sha1_to_hex(obj->sha1),
+                           typename(obj->type), typename(type));
                obj->flags |= FLAG_CHECKED;
-               return;
+               return 1;
        }
+
+       return 0;
 }
 
-static void check_objects(void)
+static unsigned check_objects(void)
 {
-       unsigned i, max;
+       unsigned i, max, foreign_nr = 0;
 
        max = get_max_object_index();
        for (i = 0; i < max; i++)
-               check_object(get_indexed_object(i));
+               foreign_nr += check_object(get_indexed_object(i));
+       return foreign_nr;
 }
 
 
@@ -283,13 +300,13 @@ static const char *open_pack_file(const char *pack_name)
                        output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600);
                if (output_fd < 0)
                        die_errno(_("unable to create '%s'"), pack_name);
-               pack_fd = output_fd;
+               nothread_data.pack_fd = output_fd;
        } else {
                input_fd = open(pack_name, O_RDONLY);
                if (input_fd < 0)
                        die_errno(_("cannot open packfile '%s'"), pack_name);
                output_fd = -1;
-               pack_fd = input_fd;
+               nothread_data.pack_fd = input_fd;
        }
        git_SHA1_Init(&input_ctx);
        return pack_name;
@@ -345,8 +362,7 @@ static void set_thread_data(struct thread_local *data)
 
 static struct base_data *alloc_base_data(void)
 {
-       struct base_data *base = xmalloc(sizeof(struct base_data));
-       memset(base, 0, sizeof(*base));
+       struct base_data *base = xcalloc(1, sizeof(struct base_data));
        base->ref_last = -1;
        base->ofs_last = -1;
        return base;
@@ -537,7 +553,7 @@ static void *unpack_data(struct object_entry *obj,
 
        do {
                ssize_t n = (len < 64*1024) ? len : 64*1024;
-               n = pread(pack_fd, inbuf, n, from);
+               n = xpread(get_thread_data()->pack_fd, inbuf, n, from);
                if (n < 0)
                        die_errno(_("cannot pread pack file"));
                if (!n)
@@ -747,8 +763,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
                        int eaten;
                        void *buf = (void *) data;
 
-                       if (!buf)
-                               buf = new_data = get_data_from_pack(obj_entry);
+                       assert(data && "data can only be NULL for large _blobs_");
 
                        /*
                         * we do not need to free the memory here, as the
@@ -757,7 +772,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
                        obj = parse_object_buffer(sha1, type, size, buf, &eaten);
                        if (!obj)
                                die(_("invalid %s"), typename(type));
-                       if (fsck_object(obj, 1, fsck_error_function))
+                       if (do_fsck_object &&
+                           fsck_object(obj, 1, fsck_error_function))
                                die(_("Error in object"));
                        if (fsck_walk(obj, mark_link, NULL))
                                die(_("Not all child objects of %s are reachable"), sha1_to_hex(obj->sha1));
@@ -765,10 +781,12 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
                        if (obj->type == OBJ_TREE) {
                                struct tree *item = (struct tree *) obj;
                                item->buffer = NULL;
+                               obj->parsed = 0;
                        }
                        if (obj->type == OBJ_COMMIT) {
                                struct commit *commit = (struct commit *) obj;
-                               commit->buffer = NULL;
+                               if (detach_commit_buffer(commit, NULL) != data)
+                                       die("BUG: parse_object_buffer transmogrified our buffer");
                        }
                        obj->flags |= FLAG_CHECKED;
                }
@@ -1285,7 +1303,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                if (keep_fd < 0) {
                        if (errno != EEXIST)
                                die_errno(_("cannot write keep file '%s'"),
-                                         keep_name);
+                                         keep_name ? keep_name : name);
                } else {
                        if (keep_msg_len > 0) {
                                write_or_die(keep_fd, keep_msg, keep_msg_len);
@@ -1293,7 +1311,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                        }
                        if (close(keep_fd) != 0)
                                die_errno(_("cannot close written keep file '%s'"),
-                                   keep_name);
+                                         keep_name ? keep_name : name);
                        report = "keep";
                }
        }
@@ -1484,18 +1502,19 @@ static void show_pack_info(int stat_only)
 int cmd_index_pack(int argc, const char **argv, const char *prefix)
 {
        int i, fix_thin_pack = 0, verify = 0, stat_only = 0;
-       const char *curr_pack, *curr_index;
+       const char *curr_index;
        const char *index_name = NULL, *pack_name = NULL;
        const char *keep_name = NULL, *keep_msg = NULL;
        char *index_name_buf = NULL, *keep_name_buf = NULL;
        struct pack_idx_entry **idx_objects;
        struct pack_idx_option opts;
        unsigned char pack_sha1[20];
+       unsigned foreign_nr = 1;        /* zero is a "good" value, assume bad */
 
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage(index_pack_usage);
 
-       read_replace_refs = 0;
+       check_replace_refs = 0;
 
        reset_pack_idx_option(&opts);
        git_config(git_index_pack_config, &opts);
@@ -1512,6 +1531,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
                                fix_thin_pack = 1;
                        } else if (!strcmp(arg, "--strict")) {
                                strict = 1;
+                               do_fsck_object = 1;
+                       } else if (!strcmp(arg, "--check-self-contained-and-connected")) {
+                               strict = 1;
+                               check_self_contained_and_connected = 1;
                        } else if (!strcmp(arg, "--verify")) {
                                verify = 1;
                        } else if (!strcmp(arg, "--verify-stat")) {
@@ -1523,9 +1546,9 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
                                stat_only = 1;
                        } else if (!strcmp(arg, "--keep")) {
                                keep_msg = "";
-                       } else if (!prefixcmp(arg, "--keep=")) {
+                       } else if (starts_with(arg, "--keep=")) {
                                keep_msg = arg + 7;
-                       } else if (!prefixcmp(arg, "--threads=")) {
+                       } else if (starts_with(arg, "--threads=")) {
                                char *end;
                                nr_threads = strtoul(arg+10, &end, 0);
                                if (!arg[10] || *end || nr_threads < 0)
@@ -1536,7 +1559,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
                                                  "ignoring %s"), arg);
                                nr_threads = 1;
 #endif
-                       } else if (!prefixcmp(arg, "--pack_header=")) {
+                       } else if (starts_with(arg, "--pack_header=")) {
                                struct pack_header *hdr;
                                char *c;
 
@@ -1555,7 +1578,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
                                if (index_name || (i+1) >= argc)
                                        usage(index_pack_usage);
                                index_name = argv[++i];
-                       } else if (!prefixcmp(arg, "--index-version=")) {
+                       } else if (starts_with(arg, "--index-version=")) {
                                char *c;
                                opts.version = strtoul(arg + 16, &c, 10);
                                if (opts.version > 2)
@@ -1625,7 +1648,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        conclude_pack(fix_thin_pack, curr_pack, pack_sha1);
        free(deltas);
        if (strict)
-               check_objects();
+               foreign_nr = check_objects();
 
        if (show_stat)
                show_pack_info(stat_only);
@@ -1651,5 +1674,11 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        if (index_name == NULL)
                free((void *) curr_index);
 
+       /*
+        * Let the caller know this pack is not self contained
+        */
+       if (check_self_contained_and_connected && foreign_nr)
+               return 1;
+
        return 0;
 }