builtin / unpack-objects.con commit Merge branch 'jc/max-io-size-and-ssize-max' (81a535d)
   1#include "builtin.h"
   2#include "cache.h"
   3#include "object.h"
   4#include "delta.h"
   5#include "pack.h"
   6#include "blob.h"
   7#include "commit.h"
   8#include "tag.h"
   9#include "tree.h"
  10#include "tree-walk.h"
  11#include "progress.h"
  12#include "decorate.h"
  13#include "fsck.h"
  14
  15static int dry_run, quiet, recover, has_errors, strict;
  16static const char unpack_usage[] = "git unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
  17
  18/* We always read in 4kB chunks. */
  19static unsigned char buffer[4096];
  20static unsigned int offset, len;
  21static off_t consumed_bytes;
  22static git_SHA_CTX ctx;
  23
  24/*
  25 * When running under --strict mode, objects whose reachability are
  26 * suspect are kept in core without getting written in the object
  27 * store.
  28 */
  29struct obj_buffer {
  30        char *buffer;
  31        unsigned long size;
  32};
  33
  34static struct decoration obj_decorate;
  35
  36static struct obj_buffer *lookup_object_buffer(struct object *base)
  37{
  38        return lookup_decoration(&obj_decorate, base);
  39}
  40
  41static void add_object_buffer(struct object *object, char *buffer, unsigned long size)
  42{
  43        struct obj_buffer *obj;
  44        obj = xcalloc(1, sizeof(struct obj_buffer));
  45        obj->buffer = buffer;
  46        obj->size = size;
  47        if (add_decoration(&obj_decorate, object, obj))
  48                die("object %s tried to add buffer twice!", sha1_to_hex(object->sha1));
  49}
  50
  51/*
  52 * Make sure at least "min" bytes are available in the buffer, and
  53 * return the pointer to the buffer.
  54 */
  55static void *fill(int min)
  56{
  57        if (min <= len)
  58                return buffer + offset;
  59        if (min > sizeof(buffer))
  60                die("cannot fill %d bytes", min);
  61        if (offset) {
  62                git_SHA1_Update(&ctx, buffer, offset);
  63                memmove(buffer, buffer + offset, len);
  64                offset = 0;
  65        }
  66        do {
  67                ssize_t ret = xread(0, buffer + len, sizeof(buffer) - len);
  68                if (ret <= 0) {
  69                        if (!ret)
  70                                die("early EOF");
  71                        die_errno("read error on input");
  72                }
  73                len += ret;
  74        } while (len < min);
  75        return buffer;
  76}
  77
  78static void use(int bytes)
  79{
  80        if (bytes > len)
  81                die("used more bytes than were available");
  82        len -= bytes;
  83        offset += bytes;
  84
  85        /* make sure off_t is sufficiently large not to wrap */
  86        if (signed_add_overflows(consumed_bytes, bytes))
  87                die("pack too large for current definition of off_t");
  88        consumed_bytes += bytes;
  89}
  90
  91static void *get_data(unsigned long size)
  92{
  93        git_zstream stream;
  94        void *buf = xmallocz(size);
  95
  96        memset(&stream, 0, sizeof(stream));
  97
  98        stream.next_out = buf;
  99        stream.avail_out = size;
 100        stream.next_in = fill(1);
 101        stream.avail_in = len;
 102        git_inflate_init(&stream);
 103
 104        for (;;) {
 105                int ret = git_inflate(&stream, 0);
 106                use(len - stream.avail_in);
 107                if (stream.total_out == size && ret == Z_STREAM_END)
 108                        break;
 109                if (ret != Z_OK) {
 110                        error("inflate returned %d", ret);
 111                        free(buf);
 112                        buf = NULL;
 113                        if (!recover)
 114                                exit(1);
 115                        has_errors = 1;
 116                        break;
 117                }
 118                stream.next_in = fill(1);
 119                stream.avail_in = len;
 120        }
 121        git_inflate_end(&stream);
 122        return buf;
 123}
 124
 125struct delta_info {
 126        unsigned char base_sha1[20];
 127        unsigned nr;
 128        off_t base_offset;
 129        unsigned long size;
 130        void *delta;
 131        struct delta_info *next;
 132};
 133
 134static struct delta_info *delta_list;
 135
 136static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1,
 137                              off_t base_offset,
 138                              void *delta, unsigned long size)
 139{
 140        struct delta_info *info = xmalloc(sizeof(*info));
 141
 142        hashcpy(info->base_sha1, base_sha1);
 143        info->base_offset = base_offset;
 144        info->size = size;
 145        info->delta = delta;
 146        info->nr = nr;
 147        info->next = delta_list;
 148        delta_list = info;
 149}
 150
 151struct obj_info {
 152        off_t offset;
 153        unsigned char sha1[20];
 154        struct object *obj;
 155};
 156
 157#define FLAG_OPEN (1u<<20)
 158#define FLAG_WRITTEN (1u<<21)
 159
 160static struct obj_info *obj_list;
 161static unsigned nr_objects;
 162
 163/*
 164 * Called only from check_object() after it verified this object
 165 * is Ok.
 166 */
 167static void write_cached_object(struct object *obj, struct obj_buffer *obj_buf)
 168{
 169        unsigned char sha1[20];
 170
 171        if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), sha1) < 0)
 172                die("failed to write object %s", sha1_to_hex(obj->sha1));
 173        obj->flags |= FLAG_WRITTEN;
 174}
 175
 176/*
 177 * At the very end of the processing, write_rest() scans the objects
 178 * that have reachability requirements and calls this function.
 179 * Verify its reachability and validity recursively and write it out.
 180 */
 181static int check_object(struct object *obj, int type, void *data)
 182{
 183        struct obj_buffer *obj_buf;
 184
 185        if (!obj)
 186                return 1;
 187
 188        if (obj->flags & FLAG_WRITTEN)
 189                return 0;
 190
 191        if (type != OBJ_ANY && obj->type != type)
 192                die("object type mismatch");
 193
 194        if (!(obj->flags & FLAG_OPEN)) {
 195                unsigned long size;
 196                int type = sha1_object_info(obj->sha1, &size);
 197                if (type != obj->type || type <= 0)
 198                        die("object of unexpected type");
 199                obj->flags |= FLAG_WRITTEN;
 200                return 0;
 201        }
 202
 203        obj_buf = lookup_object_buffer(obj);
 204        if (!obj_buf)
 205                die("Whoops! Cannot find object '%s'", sha1_to_hex(obj->sha1));
 206        if (fsck_object(obj, obj_buf->buffer, obj_buf->size, 1,
 207                        fsck_error_function))
 208                die("Error in object");
 209        if (fsck_walk(obj, check_object, NULL))
 210                die("Error on reachable objects of %s", sha1_to_hex(obj->sha1));
 211        write_cached_object(obj, obj_buf);
 212        return 0;
 213}
 214
 215static void write_rest(void)
 216{
 217        unsigned i;
 218        for (i = 0; i < nr_objects; i++) {
 219                if (obj_list[i].obj)
 220                        check_object(obj_list[i].obj, OBJ_ANY, NULL);
 221        }
 222}
 223
 224static void added_object(unsigned nr, enum object_type type,
 225                         void *data, unsigned long size);
 226
 227/*
 228 * Write out nr-th object from the list, now we know the contents
 229 * of it.  Under --strict, this buffers structured objects in-core,
 230 * to be checked at the end.
 231 */
 232static void write_object(unsigned nr, enum object_type type,
 233                         void *buf, unsigned long size)
 234{
 235        if (!strict) {
 236                if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
 237                        die("failed to write object");
 238                added_object(nr, type, buf, size);
 239                free(buf);
 240                obj_list[nr].obj = NULL;
 241        } else if (type == OBJ_BLOB) {
 242                struct blob *blob;
 243                if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
 244                        die("failed to write object");
 245                added_object(nr, type, buf, size);
 246                free(buf);
 247
 248                blob = lookup_blob(obj_list[nr].sha1);
 249                if (blob)
 250                        blob->object.flags |= FLAG_WRITTEN;
 251                else
 252                        die("invalid blob object");
 253                obj_list[nr].obj = NULL;
 254        } else {
 255                struct object *obj;
 256                int eaten;
 257                hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1);
 258                added_object(nr, type, buf, size);
 259                obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten);
 260                if (!obj)
 261                        die("invalid %s", typename(type));
 262                add_object_buffer(obj, buf, size);
 263                obj->flags |= FLAG_OPEN;
 264                obj_list[nr].obj = obj;
 265        }
 266}
 267
 268static void resolve_delta(unsigned nr, enum object_type type,
 269                          void *base, unsigned long base_size,
 270                          void *delta, unsigned long delta_size)
 271{
 272        void *result;
 273        unsigned long result_size;
 274
 275        result = patch_delta(base, base_size,
 276                             delta, delta_size,
 277                             &result_size);
 278        if (!result)
 279                die("failed to apply delta");
 280        free(delta);
 281        write_object(nr, type, result, result_size);
 282}
 283
 284/*
 285 * We now know the contents of an object (which is nr-th in the pack);
 286 * resolve all the deltified objects that are based on it.
 287 */
 288static void added_object(unsigned nr, enum object_type type,
 289                         void *data, unsigned long size)
 290{
 291        struct delta_info **p = &delta_list;
 292        struct delta_info *info;
 293
 294        while ((info = *p) != NULL) {
 295                if (!hashcmp(info->base_sha1, obj_list[nr].sha1) ||
 296                    info->base_offset == obj_list[nr].offset) {
 297                        *p = info->next;
 298                        p = &delta_list;
 299                        resolve_delta(info->nr, type, data, size,
 300                                      info->delta, info->size);
 301                        free(info);
 302                        continue;
 303                }
 304                p = &info->next;
 305        }
 306}
 307
 308static void unpack_non_delta_entry(enum object_type type, unsigned long size,
 309                                   unsigned nr)
 310{
 311        void *buf = get_data(size);
 312
 313        if (!dry_run && buf)
 314                write_object(nr, type, buf, size);
 315        else
 316                free(buf);
 317}
 318
 319static int resolve_against_held(unsigned nr, const unsigned char *base,
 320                                void *delta_data, unsigned long delta_size)
 321{
 322        struct object *obj;
 323        struct obj_buffer *obj_buffer;
 324        obj = lookup_object(base);
 325        if (!obj)
 326                return 0;
 327        obj_buffer = lookup_object_buffer(obj);
 328        if (!obj_buffer)
 329                return 0;
 330        resolve_delta(nr, obj->type, obj_buffer->buffer,
 331                      obj_buffer->size, delta_data, delta_size);
 332        return 1;
 333}
 334
 335static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
 336                               unsigned nr)
 337{
 338        void *delta_data, *base;
 339        unsigned long base_size;
 340        unsigned char base_sha1[20];
 341
 342        if (type == OBJ_REF_DELTA) {
 343                hashcpy(base_sha1, fill(20));
 344                use(20);
 345                delta_data = get_data(delta_size);
 346                if (dry_run || !delta_data) {
 347                        free(delta_data);
 348                        return;
 349                }
 350                if (has_sha1_file(base_sha1))
 351                        ; /* Ok we have this one */
 352                else if (resolve_against_held(nr, base_sha1,
 353                                              delta_data, delta_size))
 354                        return; /* we are done */
 355                else {
 356                        /* cannot resolve yet --- queue it */
 357                        hashcpy(obj_list[nr].sha1, null_sha1);
 358                        add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size);
 359                        return;
 360                }
 361        } else {
 362                unsigned base_found = 0;
 363                unsigned char *pack, c;
 364                off_t base_offset;
 365                unsigned lo, mid, hi;
 366
 367                pack = fill(1);
 368                c = *pack;
 369                use(1);
 370                base_offset = c & 127;
 371                while (c & 128) {
 372                        base_offset += 1;
 373                        if (!base_offset || MSB(base_offset, 7))
 374                                die("offset value overflow for delta base object");
 375                        pack = fill(1);
 376                        c = *pack;
 377                        use(1);
 378                        base_offset = (base_offset << 7) + (c & 127);
 379                }
 380                base_offset = obj_list[nr].offset - base_offset;
 381                if (base_offset <= 0 || base_offset >= obj_list[nr].offset)
 382                        die("offset value out of bound for delta base object");
 383
 384                delta_data = get_data(delta_size);
 385                if (dry_run || !delta_data) {
 386                        free(delta_data);
 387                        return;
 388                }
 389                lo = 0;
 390                hi = nr;
 391                while (lo < hi) {
 392                        mid = (lo + hi)/2;
 393                        if (base_offset < obj_list[mid].offset) {
 394                                hi = mid;
 395                        } else if (base_offset > obj_list[mid].offset) {
 396                                lo = mid + 1;
 397                        } else {
 398                                hashcpy(base_sha1, obj_list[mid].sha1);
 399                                base_found = !is_null_sha1(base_sha1);
 400                                break;
 401                        }
 402                }
 403                if (!base_found) {
 404                        /*
 405                         * The delta base object is itself a delta that
 406                         * has not been resolved yet.
 407                         */
 408                        hashcpy(obj_list[nr].sha1, null_sha1);
 409                        add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size);
 410                        return;
 411                }
 412        }
 413
 414        if (resolve_against_held(nr, base_sha1, delta_data, delta_size))
 415                return;
 416
 417        base = read_sha1_file(base_sha1, &type, &base_size);
 418        if (!base) {
 419                error("failed to read delta-pack base object %s",
 420                      sha1_to_hex(base_sha1));
 421                if (!recover)
 422                        exit(1);
 423                has_errors = 1;
 424                return;
 425        }
 426        resolve_delta(nr, type, base, base_size, delta_data, delta_size);
 427        free(base);
 428}
 429
 430static void unpack_one(unsigned nr)
 431{
 432        unsigned shift;
 433        unsigned char *pack;
 434        unsigned long size, c;
 435        enum object_type type;
 436
 437        obj_list[nr].offset = consumed_bytes;
 438
 439        pack = fill(1);
 440        c = *pack;
 441        use(1);
 442        type = (c >> 4) & 7;
 443        size = (c & 15);
 444        shift = 4;
 445        while (c & 0x80) {
 446                pack = fill(1);
 447                c = *pack;
 448                use(1);
 449                size += (c & 0x7f) << shift;
 450                shift += 7;
 451        }
 452
 453        switch (type) {
 454        case OBJ_COMMIT:
 455        case OBJ_TREE:
 456        case OBJ_BLOB:
 457        case OBJ_TAG:
 458                unpack_non_delta_entry(type, size, nr);
 459                return;
 460        case OBJ_REF_DELTA:
 461        case OBJ_OFS_DELTA:
 462                unpack_delta_entry(type, size, nr);
 463                return;
 464        default:
 465                error("bad object type %d", type);
 466                has_errors = 1;
 467                if (recover)
 468                        return;
 469                exit(1);
 470        }
 471}
 472
 473static void unpack_all(void)
 474{
 475        int i;
 476        struct progress *progress = NULL;
 477        struct pack_header *hdr = fill(sizeof(struct pack_header));
 478
 479        nr_objects = ntohl(hdr->hdr_entries);
 480
 481        if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE)
 482                die("bad pack file");
 483        if (!pack_version_ok(hdr->hdr_version))
 484                die("unknown pack file version %"PRIu32,
 485                        ntohl(hdr->hdr_version));
 486        use(sizeof(struct pack_header));
 487
 488        if (!quiet)
 489                progress = start_progress(_("Unpacking objects"), nr_objects);
 490        obj_list = xcalloc(nr_objects, sizeof(*obj_list));
 491        for (i = 0; i < nr_objects; i++) {
 492                unpack_one(i);
 493                display_progress(progress, i + 1);
 494        }
 495        stop_progress(&progress);
 496
 497        if (delta_list)
 498                die("unresolved deltas left after unpacking");
 499}
 500
 501int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
 502{
 503        int i;
 504        unsigned char sha1[20];
 505
 506        check_replace_refs = 0;
 507
 508        git_config(git_default_config, NULL);
 509
 510        quiet = !isatty(2);
 511
 512        for (i = 1 ; i < argc; i++) {
 513                const char *arg = argv[i];
 514
 515                if (*arg == '-') {
 516                        if (!strcmp(arg, "-n")) {
 517                                dry_run = 1;
 518                                continue;
 519                        }
 520                        if (!strcmp(arg, "-q")) {
 521                                quiet = 1;
 522                                continue;
 523                        }
 524                        if (!strcmp(arg, "-r")) {
 525                                recover = 1;
 526                                continue;
 527                        }
 528                        if (!strcmp(arg, "--strict")) {
 529                                strict = 1;
 530                                continue;
 531                        }
 532                        if (starts_with(arg, "--pack_header=")) {
 533                                struct pack_header *hdr;
 534                                char *c;
 535
 536                                hdr = (struct pack_header *)buffer;
 537                                hdr->hdr_signature = htonl(PACK_SIGNATURE);
 538                                hdr->hdr_version = htonl(strtoul(arg + 14, &c, 10));
 539                                if (*c != ',')
 540                                        die("bad %s", arg);
 541                                hdr->hdr_entries = htonl(strtoul(c + 1, &c, 10));
 542                                if (*c)
 543                                        die("bad %s", arg);
 544                                len = sizeof(*hdr);
 545                                continue;
 546                        }
 547                        usage(unpack_usage);
 548                }
 549
 550                /* We don't take any non-flag arguments now.. Maybe some day */
 551                usage(unpack_usage);
 552        }
 553        git_SHA1_Init(&ctx);
 554        unpack_all();
 555        git_SHA1_Update(&ctx, buffer, offset);
 556        git_SHA1_Final(sha1, &ctx);
 557        if (strict)
 558                write_rest();
 559        if (hashcmp(fill(20), sha1))
 560                die("final sha1 did not match");
 561        use(20);
 562
 563        /* Write the last part of the buffer to stdout */
 564        while (len) {
 565                int ret = xwrite(1, buffer + offset, len);
 566                if (ret <= 0)
 567                        break;
 568                len -= ret;
 569                offset += ret;
 570        }
 571
 572        /* All done */
 573        return has_errors;
 574}