#endif
#endif
-const unsigned char null_sha1[20] = { 0, };
+const unsigned char null_sha1[20];
static unsigned int sha1_file_open_flag = O_NOATIME;
/*
* NOTE! This returns a statically allocated buffer, so you have to be
- * careful about using it. Do a "strdup()" if you need to save the
+ * careful about using it. Do a "xstrdup()" if you need to save the
* filename.
*
* Also note that this returns the location for creating. Reading
int fd;
struct stat st;
void *map;
+ struct pack_header *hdr;
pack_mapped += p->pack_size;
while (PACK_MAX_SZ < pack_mapped && unuse_one_packed_git())
die("packfile %s cannot be mapped.", p->pack_name);
p->pack_base = map;
+ /* Check if we understand this pack file. If we don't we're
+ * likely too old to handle it.
+ */
+ hdr = map;
+ if (hdr->hdr_signature != htonl(PACK_SIGNATURE))
+ die("packfile %s isn't actually a pack.", p->pack_name);
+ if (!pack_version_ok(hdr->hdr_version))
+ die("packfile %s is version %i and not supported"
+ " (try upgrading GIT to a newer version)",
+ p->pack_name, ntohl(hdr->hdr_version));
+
/* Check if the pack file matches with the index file.
* this is cheap.
*/
- if (memcmp((char*)(p->index_base) + p->index_size - 40,
- (char *) p->pack_base + p->pack_size - 20,
- 20)) {
-
+ if (hashcmp((unsigned char *)(p->index_base) +
+ p->index_size - 40,
+ (unsigned char *)p->pack_base +
+ p->pack_size - 20)) {
die("packfile %s does not match index.", p->pack_name);
}
}
p->pack_use_cnt = 0;
p->pack_local = local;
if ((path_len > 44) && !get_sha1_hex(path + path_len - 44, sha1))
- memcpy(p->sha1, sha1, 20);
+ hashcpy(p->sha1, sha1);
return p;
}
p->pack_base = NULL;
p->pack_last_used = 0;
p->pack_use_cnt = 0;
- memcpy(p->sha1, sha1, 20);
+ hashcpy(p->sha1, sha1);
return p;
}
int namelen = strlen(de->d_name);
struct packed_git *p;
- if (strcmp(de->d_name + namelen - 4, ".idx"))
+ if (!has_extension(de->d_name, ".idx"))
continue;
/* we have .idx. Is it a file we can map? */
SHA1_Update(&c, header, 1+sprintf(header, "%s %lu", type, size));
SHA1_Update(&c, map, size);
SHA1_Final(real_sha1, &c);
- return memcmp(sha1, real_sha1, 20) ? -1 : 0;
+ return hashcmp(sha1, real_sha1) ? -1 : 0;
}
void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
return 0;
}
-static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz)
+unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep)
{
+ unsigned shift;
unsigned char c;
- unsigned int bits;
unsigned long size;
- static const char *typename[8] = {
- NULL, /* OBJ_EXT */
- "commit", "tree", "blob", "tag",
- NULL, NULL, NULL
+ unsigned long used = 0;
+
+ c = buf[used++];
+ *type = (c >> 4) & 7;
+ size = c & 15;
+ shift = 4;
+ while (c & 0x80) {
+ if (len <= used)
+ return 0;
+ if (sizeof(long) * 8 <= shift)
+ return 0;
+ c = buf[used++];
+ size += (c & 0x7f) << shift;
+ shift += 7;
+ }
+ *sizep = size;
+ return used;
+}
+
+static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz)
+{
+ unsigned long size, used;
+ static const char valid_loose_object_type[8] = {
+ 0, /* OBJ_EXT */
+ 1, 1, 1, 1, /* "commit", "tree", "blob", "tag" */
+ 0, /* "delta" and others are invalid in a loose object */
};
- const char *type;
+ enum object_type type;
/* Get the data stream */
memset(stream, 0, sizeof(*stream));
return inflate(stream, 0);
}
- c = *map++;
- mapsize--;
- type = typename[(c >> 4) & 7];
- if (!type)
+ used = unpack_object_header_gently(map, mapsize, &type, &size);
+ if (!used || !valid_loose_object_type[type])
return -1;
-
- bits = 4;
- size = c & 0xf;
- while ((c & 0x80)) {
- if (bits >= 8*sizeof(long))
- return -1;
- c = *map++;
- size += (c & 0x7f) << bits;
- bits += 7;
- mapsize--;
- }
+ map += used;
+ mapsize -= used;
/* Set up the stream for the rest.. */
stream->next_in = map;
inflateInit(stream);
/* And generate the fake traditional header */
- stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu", type, size);
+ stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu",
+ type_names[type], size);
return 0;
}
static unsigned long unpack_object_header(struct packed_git *p, unsigned long offset,
enum object_type *type, unsigned long *sizep)
{
- unsigned shift;
- unsigned char *pack, c;
- unsigned long size;
+ unsigned long used;
- if (offset >= p->pack_size)
+ if (p->pack_size <= offset)
die("object offset outside of pack file");
- pack = (unsigned char *) p->pack_base + offset;
- c = *pack++;
- offset++;
- *type = (c >> 4) & 7;
- size = c & 15;
- shift = 4;
- while (c & 0x80) {
- if (offset >= p->pack_size)
- die("object offset outside of pack file");
- c = *pack++;
- offset++;
- size += (c & 0x7f) << shift;
- shift += 7;
- }
- *sizep = size;
- return offset;
+ used = unpack_object_header_gently((unsigned char *)p->pack_base +
+ offset,
+ p->pack_size - offset, type, sizep);
+ if (!used)
+ die("object offset outside of pack file");
+
+ return offset + used;
}
int check_reuse_pack_delta(struct packed_git *p, unsigned long offset,
ptr = unpack_object_header(p, ptr, kindp, sizep);
if (*kindp != OBJ_DELTA)
goto done;
- memcpy(base, (char *) p->pack_base + ptr, 20);
+ hashcpy(base, (unsigned char *) p->pack_base + ptr);
status = 0;
done:
unuse_packed_git(p);
if (p->pack_size <= offset + 20)
die("pack file %s records an incomplete delta base",
p->pack_name);
- memcpy(base_sha1, pack, 20);
+ hashcpy(base_sha1, pack);
do {
struct pack_entry base_ent;
unsigned long junk;
}
switch (kind) {
case OBJ_COMMIT:
- strcpy(type, commit_type);
- break;
case OBJ_TREE:
- strcpy(type, tree_type);
- break;
case OBJ_BLOB:
- strcpy(type, blob_type);
- break;
case OBJ_TAG:
- strcpy(type, tag_type);
+ strcpy(type, type_names[kind]);
break;
default:
die("corrupted pack file %s containing object of kind %d",
unuse_packed_git(p);
return retval;
case OBJ_COMMIT:
- strcpy(type, commit_type);
- break;
case OBJ_TREE:
- strcpy(type, tree_type);
- break;
case OBJ_BLOB:
- strcpy(type, blob_type);
- break;
case OBJ_TAG:
- strcpy(type, tag_type);
+ strcpy(type, type_names[kind]);
break;
default:
die("corrupted pack file %s containing object of kind %d",
return 0;
}
-/* forward declaration for a mutually recursive function */
-static void *unpack_entry(struct pack_entry *, char *, unsigned long *);
+static void *unpack_compressed_entry(struct packed_git *p,
+ unsigned long offset,
+ unsigned long size)
+{
+ int st;
+ z_stream stream;
+ unsigned char *buffer;
+
+ buffer = xmalloc(size + 1);
+ buffer[size] = 0;
+ memset(&stream, 0, sizeof(stream));
+ stream.next_in = (unsigned char*)p->pack_base + offset;
+ stream.avail_in = p->pack_size - offset;
+ stream.next_out = buffer;
+ stream.avail_out = size;
+
+ inflateInit(&stream);
+ st = inflate(&stream, Z_FINISH);
+ inflateEnd(&stream);
+ if ((st != Z_STREAM_END) || stream.total_out != size) {
+ free(buffer);
+ return NULL;
+ }
+
+ return buffer;
+}
-static void *unpack_delta_entry(unsigned char *base_sha1,
+static void *unpack_delta_entry(struct packed_git *p,
+ unsigned long offset,
unsigned long delta_size,
- unsigned long left,
char *type,
- unsigned long *sizep,
- struct packed_git *p)
+ unsigned long *sizep)
{
struct pack_entry base_ent;
- void *data, *delta_data, *result, *base;
- unsigned long data_size, result_size, base_size;
- z_stream stream;
- int st;
+ void *delta_data, *result, *base;
+ unsigned long result_size, base_size;
+ unsigned char* base_sha1;
- if (left < 20)
+ if ((offset + 20) >= p->pack_size)
die("truncated pack file");
/* The base entry _must_ be in the same pack */
+ base_sha1 = (unsigned char*)p->pack_base + offset;
if (!find_pack_entry_one(base_sha1, &base_ent, p))
die("failed to find delta-pack base object %s",
sha1_to_hex(base_sha1));
die("failed to read delta-pack base object %s",
sha1_to_hex(base_sha1));
- data = base_sha1 + 20;
- data_size = left - 20;
- delta_data = xmalloc(delta_size);
-
- memset(&stream, 0, sizeof(stream));
-
- stream.next_in = data;
- stream.avail_in = data_size;
- stream.next_out = delta_data;
- stream.avail_out = delta_size;
-
- inflateInit(&stream);
- st = inflate(&stream, Z_FINISH);
- inflateEnd(&stream);
- if ((st != Z_STREAM_END) || stream.total_out != delta_size)
- die("delta data unpack failed");
-
+ delta_data = unpack_compressed_entry(p, offset + 20, delta_size);
result = patch_delta(base, base_size,
delta_data, delta_size,
&result_size);
return result;
}
-static void *unpack_non_delta_entry(unsigned char *data,
- unsigned long size,
- unsigned long left)
-{
- int st;
- z_stream stream;
- unsigned char *buffer;
-
- buffer = xmalloc(size + 1);
- buffer[size] = 0;
- memset(&stream, 0, sizeof(stream));
- stream.next_in = data;
- stream.avail_in = left;
- stream.next_out = buffer;
- stream.avail_out = size;
-
- inflateInit(&stream);
- st = inflate(&stream, Z_FINISH);
- inflateEnd(&stream);
- if ((st != Z_STREAM_END) || stream.total_out != size) {
- free(buffer);
- return NULL;
- }
-
- return buffer;
-}
-
static void *unpack_entry(struct pack_entry *entry,
char *type, unsigned long *sizep)
{
char *type, unsigned long *sizep)
{
struct packed_git *p = entry->p;
- unsigned long offset, size, left;
- unsigned char *pack;
+ unsigned long offset, size;
enum object_type kind;
- void *retval;
offset = unpack_object_header(p, entry->offset, &kind, &size);
- pack = (unsigned char *) p->pack_base + offset;
- left = p->pack_size - offset;
switch (kind) {
case OBJ_DELTA:
- retval = unpack_delta_entry(pack, size, left, type, sizep, p);
- return retval;
+ return unpack_delta_entry(p, offset, size, type, sizep);
case OBJ_COMMIT:
- strcpy(type, commit_type);
- break;
case OBJ_TREE:
- strcpy(type, tree_type);
- break;
case OBJ_BLOB:
- strcpy(type, blob_type);
- break;
case OBJ_TAG:
- strcpy(type, tag_type);
- break;
+ strcpy(type, type_names[kind]);
+ *sizep = size;
+ return unpack_compressed_entry(p, offset, size);
default:
return NULL;
}
- *sizep = size;
- retval = unpack_non_delta_entry(pack, size, left);
- return retval;
}
int num_packed_objects(const struct packed_git *p)
void *index = p->index_base + 256;
if (n < 0 || num_packed_objects(p) <= n)
return -1;
- memcpy(sha1, (char *) index + (24 * n) + 4, 20);
+ hashcpy(sha1, (unsigned char *) index + (24 * n) + 4);
return 0;
}
do {
int mi = (lo + hi) / 2;
- int cmp = memcmp((char *) index + (24 * mi) + 4, sha1, 20);
+ int cmp = hashcmp((unsigned char *)index + (24 * mi) + 4, sha1);
if (!cmp) {
e->offset = ntohl(*((unsigned int *) ((char *) index + (24 * mi))));
- memcpy(e->sha1, sha1, 20);
+ hashcpy(e->sha1, sha1);
e->p = p;
return 1;
}
unsigned long isize;
unsigned char actual_sha1[20];
- memcpy(actual_sha1, sha1, 20);
+ hashcpy(actual_sha1, sha1);
while (1) {
int ref_length = -1;
const char *ref_type = NULL;
if (!strcmp(type, required_type)) {
*size = isize;
if (actual_sha1_return)
- memcpy(actual_sha1_return, actual_sha1, 20);
+ hashcpy(actual_sha1_return, actual_sha1);
return buffer;
}
/* Handle references */
*
* Returns the errno on failure, 0 on success.
*/
-static int link_temp_to_file(const char *tmpfile, char *filename)
+static int link_temp_to_file(const char *tmpfile, const char *filename)
{
int ret;
char *dir;
/*
* Move the just written object into its final resting place
*/
-int move_temp_to_file(const char *tmpfile, char *filename)
+int move_temp_to_file(const char *tmpfile, const char *filename)
{
int ret = link_temp_to_file(tmpfile, filename);
*/
filename = write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
if (returnsha1)
- memcpy(returnsha1, sha1, 20);
+ hashcpy(returnsha1, sha1);
if (has_sha1_file(sha1))
return 0;
fd = open(filename, O_RDONLY);
unlink(tmpfile);
return error("File %s corrupted", sha1_to_hex(sha1));
}
- if (memcmp(sha1, real_sha1, 20)) {
+ if (hashcmp(sha1, real_sha1)) {
unlink(tmpfile);
return error("File %s has bad hash", sha1_to_hex(sha1));
}
off += iret;
if (off == size) {
size *= 2;
- buf = realloc(buf, size);
+ buf = xrealloc(buf, size);
}
}
} while (iret > 0);
int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object)
{
unsigned long size = 4096;
- char *buf = malloc(size);
+ char *buf = xmalloc(size);
int ret;
unsigned char hdr[50];
int hdrlen;