Commit 89217d8f by Ramsay Jones Committed by Andreas Ericsson

Add functions to open a '*.pack' file and perform some basic validation

Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
parent 3cc60635
......@@ -71,6 +71,9 @@ struct git_pack {
/** Number of objects in this pack. */
uint32_t obj_cnt;
/** File descriptor for the .pack file. */
git_file pack_fd;
/** The size of the .pack file. */
off_t pack_size;
......@@ -121,6 +124,12 @@ typedef struct { /* object header data */
size_t size; /* object size */
} obj_hdr;
typedef struct { /* '.pack' file header */
uint32_t sig; /* PACK_SIG */
uint32_t ver; /* pack version */
uint32_t cnt; /* object count */
} pack_hdr;
static struct {
const char *str; /* type name string */
int loose; /* valid loose object type flag */
......@@ -1085,6 +1094,91 @@ static void pack_decidx(git_pack *p)
gitlck_unlock(&p->lock);
}
static int read_pack_hdr(pack_hdr *out, git_file fd)
{
pack_hdr hdr;
if (gitfo_read(fd, &hdr, sizeof(hdr)))
return GIT_ERROR;
out->sig = decode32(&hdr.sig);
out->ver = decode32(&hdr.ver);
out->cnt = decode32(&hdr.cnt);
return GIT_SUCCESS;
}
static int check_pack_hdr(git_pack *p)
{
pack_hdr hdr;
if (read_pack_hdr(&hdr, p->pack_fd))
return GIT_ERROR;
if (hdr.sig != PACK_SIG
|| (hdr.ver != 2 && hdr.ver != 3)
|| hdr.cnt != p->obj_cnt)
return GIT_ERROR;
return GIT_SUCCESS;
}
static int check_pack_sha1(git_pack *p)
{
unsigned char *data = p->idx_map.data;
off_t pack_sha1_off = p->pack_size - GIT_OID_RAWSZ;
size_t idx_pack_sha1_off = p->idx_map.len - 2 * GIT_OID_RAWSZ;
git_oid pack_id, idx_pack_id;
if (gitfo_lseek(p->pack_fd, pack_sha1_off, SEEK_SET) == -1)
return GIT_ERROR;
if (gitfo_read(p->pack_fd, pack_id.id, sizeof(pack_id.id)))
return GIT_ERROR;
git_oid_mkraw(&idx_pack_id, data + idx_pack_sha1_off);
if (git_oid_cmp(&pack_id, &idx_pack_id))
return GIT_ERROR;
return GIT_SUCCESS;
}
static int open_pack(git_pack *p)
{
char pb[GIT_PATH_MAX];
struct stat sb;
if (p->pack_fd != -1)
return GIT_SUCCESS;
if (git__fmt(pb, sizeof(pb), "%s/pack/%s.pack",
p->db->objects_dir,
p->pack_name) < 0)
return GIT_ERROR;
if (pack_openidx(p))
return GIT_ERROR;
if ((p->pack_fd = gitfo_open(pb, O_RDONLY)) < 0) {
p->pack_fd = -1;
pack_decidx(p);
return GIT_ERROR;
}
if (gitfo_fstat(p->pack_fd, &sb)
|| !S_ISREG(sb.st_mode) || p->pack_size != sb.st_size
|| check_pack_hdr(p) || check_pack_sha1(p)) {
gitfo_close(p->pack_fd);
p->pack_fd = -1;
pack_decidx(p);
return GIT_ERROR;
}
pack_decidx(p);
return GIT_SUCCESS;
}
static void pack_dec(git_pack *p)
{
int need_free;
......@@ -1100,6 +1194,8 @@ static void pack_dec(git_pack *p)
free(p->im_fanout);
free(p->im_off_idx);
free(p->im_off_next);
if (p->pack_fd != -1)
gitfo_close(p->pack_fd);
}
gitlck_free(&p->lock);
......@@ -1134,6 +1230,7 @@ static git_pack *alloc_pack(const char *pack_name)
gitlck_init(&p->lock);
strcpy(p->pack_name, pack_name);
p->refcnt = 1;
p->pack_fd = -1;
return p;
}
......@@ -1378,9 +1475,22 @@ int git_odb__read_loose(git_obj *out, git_odb *db, const git_oid *id)
return GIT_SUCCESS;
}
static int unpack_object(git_obj *out, git_pack *p, index_entry *e)
{
assert(out && p && e);
if (open_pack(p))
return GIT_ERROR;
/* TODO - actually unpack the data! */
return GIT_SUCCESS;
}
static int read_packed(git_obj *out, git_pack *p, const git_oid *id)
{
uint32_t n;
index_entry e;
int res;
assert(out && p && id);
......@@ -1388,11 +1498,13 @@ static int read_packed(git_obj *out, git_pack *p, const git_oid *id)
if (pack_openidx(p))
return GIT_ERROR;
res = p->idx_search(&n, p, id);
if (!res)
res = p->idx_get(&e, p, n);
pack_decidx(p);
if (!res) {
/* TODO unpack object */
res = GIT_ERROR;
res = unpack_object(out, p, &e);
}
return res;
......
......@@ -16,4 +16,7 @@
*/
#define PACK_TOC 0xff744f63 /* -1tOc */
/** First 4 bytes of a pack-*.pack file header. */
#define PACK_SIG 0x5041434b /* PACK */
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment