pack-write.con commit Merge branch 'maint' of git://linux-nfs.org/~bfields/git into maint (f3caeb9)
   1#include "cache.h"
   2#include "pack.h"
   3#include "csum-file.h"
   4
   5uint32_t pack_idx_default_version = 1;
   6uint32_t pack_idx_off32_limit = 0x7fffffff;
   7
   8static int sha1_compare(const void *_a, const void *_b)
   9{
  10        struct pack_idx_entry *a = *(struct pack_idx_entry **)_a;
  11        struct pack_idx_entry *b = *(struct pack_idx_entry **)_b;
  12        return hashcmp(a->sha1, b->sha1);
  13}
  14
  15/*
  16 * On entry *sha1 contains the pack content SHA1 hash, on exit it is
  17 * the SHA1 hash of sorted object names. The objects array passed in
  18 * will be sorted by SHA1 on exit.
  19 */
  20const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1)
  21{
  22        struct sha1file *f;
  23        struct pack_idx_entry **sorted_by_sha, **list, **last;
  24        off_t last_obj_offset = 0;
  25        uint32_t array[256];
  26        int i, fd;
  27        SHA_CTX ctx;
  28        uint32_t index_version;
  29
  30        if (nr_objects) {
  31                sorted_by_sha = objects;
  32                list = sorted_by_sha;
  33                last = sorted_by_sha + nr_objects;
  34                for (i = 0; i < nr_objects; ++i) {
  35                        if (objects[i]->offset > last_obj_offset)
  36                                last_obj_offset = objects[i]->offset;
  37                }
  38                qsort(sorted_by_sha, nr_objects, sizeof(sorted_by_sha[0]),
  39                      sha1_compare);
  40        }
  41        else
  42                sorted_by_sha = list = last = NULL;
  43
  44        if (!index_name) {
  45                static char tmpfile[PATH_MAX];
  46                snprintf(tmpfile, sizeof(tmpfile),
  47                         "%s/tmp_idx_XXXXXX", get_object_directory());
  48                fd = xmkstemp(tmpfile);
  49                index_name = xstrdup(tmpfile);
  50        } else {
  51                unlink(index_name);
  52                fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
  53        }
  54        if (fd < 0)
  55                die("unable to create %s: %s", index_name, strerror(errno));
  56        f = sha1fd(fd, index_name);
  57
  58        /* if last object's offset is >= 2^31 we should use index V2 */
  59        index_version = (last_obj_offset >> 31) ? 2 : pack_idx_default_version;
  60
  61        /* index versions 2 and above need a header */
  62        if (index_version >= 2) {
  63                struct pack_idx_header hdr;
  64                hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
  65                hdr.idx_version = htonl(index_version);
  66                sha1write(f, &hdr, sizeof(hdr));
  67        }
  68
  69        /*
  70         * Write the first-level table (the list is sorted,
  71         * but we use a 256-entry lookup to be able to avoid
  72         * having to do eight extra binary search iterations).
  73         */
  74        for (i = 0; i < 256; i++) {
  75                struct pack_idx_entry **next = list;
  76                while (next < last) {
  77                        struct pack_idx_entry *obj = *next;
  78                        if (obj->sha1[0] != i)
  79                                break;
  80                        next++;
  81                }
  82                array[i] = htonl(next - sorted_by_sha);
  83                list = next;
  84        }
  85        sha1write(f, array, 256 * 4);
  86
  87        /* compute the SHA1 hash of sorted object names. */
  88        SHA1_Init(&ctx);
  89
  90        /*
  91         * Write the actual SHA1 entries..
  92         */
  93        list = sorted_by_sha;
  94        for (i = 0; i < nr_objects; i++) {
  95                struct pack_idx_entry *obj = *list++;
  96                if (index_version < 2) {
  97                        uint32_t offset = htonl(obj->offset);
  98                        sha1write(f, &offset, 4);
  99                }
 100                sha1write(f, obj->sha1, 20);
 101                SHA1_Update(&ctx, obj->sha1, 20);
 102        }
 103
 104        if (index_version >= 2) {
 105                unsigned int nr_large_offset = 0;
 106
 107                /* write the crc32 table */
 108                list = sorted_by_sha;
 109                for (i = 0; i < nr_objects; i++) {
 110                        struct pack_idx_entry *obj = *list++;
 111                        uint32_t crc32_val = htonl(obj->crc32);
 112                        sha1write(f, &crc32_val, 4);
 113                }
 114
 115                /* write the 32-bit offset table */
 116                list = sorted_by_sha;
 117                for (i = 0; i < nr_objects; i++) {
 118                        struct pack_idx_entry *obj = *list++;
 119                        uint32_t offset = (obj->offset <= pack_idx_off32_limit) ?
 120                                obj->offset : (0x80000000 | nr_large_offset++);
 121                        offset = htonl(offset);
 122                        sha1write(f, &offset, 4);
 123                }
 124
 125                /* write the large offset table */
 126                list = sorted_by_sha;
 127                while (nr_large_offset) {
 128                        struct pack_idx_entry *obj = *list++;
 129                        uint64_t offset = obj->offset;
 130                        if (offset > pack_idx_off32_limit) {
 131                                uint32_t split[2];
 132                                split[0] = htonl(offset >> 32);
 133                                split[1] = htonl(offset & 0xffffffff);
 134                                sha1write(f, split, 8);
 135                                nr_large_offset--;
 136                        }
 137                }
 138        }
 139
 140        sha1write(f, sha1, 20);
 141        sha1close(f, NULL, 1);
 142        SHA1_Final(sha1, &ctx);
 143        return index_name;
 144}
 145
 146void fixup_pack_header_footer(int pack_fd,
 147                         unsigned char *pack_file_sha1,
 148                         const char *pack_name,
 149                         uint32_t object_count)
 150{
 151        static const int buf_sz = 128 * 1024;
 152        SHA_CTX c;
 153        struct pack_header hdr;
 154        char *buf;
 155
 156        if (lseek(pack_fd, 0, SEEK_SET) != 0)
 157                die("Failed seeking to start: %s", strerror(errno));
 158        if (read_in_full(pack_fd, &hdr, sizeof(hdr)) != sizeof(hdr))
 159                die("Unable to reread header of %s: %s", pack_name, strerror(errno));
 160        if (lseek(pack_fd, 0, SEEK_SET) != 0)
 161                die("Failed seeking to start: %s", strerror(errno));
 162        hdr.hdr_entries = htonl(object_count);
 163        write_or_die(pack_fd, &hdr, sizeof(hdr));
 164
 165        SHA1_Init(&c);
 166        SHA1_Update(&c, &hdr, sizeof(hdr));
 167
 168        buf = xmalloc(buf_sz);
 169        for (;;) {
 170                ssize_t n = xread(pack_fd, buf, buf_sz);
 171                if (!n)
 172                        break;
 173                if (n < 0)
 174                        die("Failed to checksum %s: %s", pack_name, strerror(errno));
 175                SHA1_Update(&c, buf, n);
 176        }
 177        free(buf);
 178
 179        SHA1_Final(pack_file_sha1, &c);
 180        write_or_die(pack_fd, pack_file_sha1, 20);
 181}