Commit fb799dfe by Andreas Ericsson

Merge remote branch 'ramsay/dev'

* ramsay/dev:
  Add a pack index 'virtual function' to fetch an index entry
  Add a pack index 'virtual function' to search by file offset
  Change the interface of the pack index search function
  Add an 64-bit offset table index bounds check for v2 pack index
  Add a minimum size check when opening an v2 pack index file
  win32: Add separate MinGW and MSVC compatability header files
  Makefile: Add support for custom build options in config.mak file
  Fix some coding style issues
parents 10074651 2cdc4544
/apidocs /apidocs
/trash-*.exe /trash-*.exe
/libgit2.pc /libgit2.pc
/config.mak
*.o *.o
*.a *.a
*.exe *.exe
......
...@@ -52,6 +52,8 @@ ifneq (,$(findstring MINGW,$(uname_S))) ...@@ -52,6 +52,8 @@ ifneq (,$(findstring MINGW,$(uname_S)))
SPARSE_FLAGS=-Wno-one-bit-signed-bitfield SPARSE_FLAGS=-Wno-one-bit-signed-bitfield
endif endif
-include config.mak
SRC_C = $(wildcard src/*.c) SRC_C = $(wildcard src/*.c)
OS_SRC = $(wildcard src/$(OS)/*.c) OS_SRC = $(wildcard src/$(OS)/*.c)
SRC_C += $(OS_SRC) SRC_C += $(OS_SRC)
......
...@@ -9,7 +9,7 @@ struct git_commit { ...@@ -9,7 +9,7 @@ struct git_commit {
git_oid id; git_oid id;
time_t commit_time; time_t commit_time;
unsigned parsed:1, unsigned parsed:1,
flags:26; flags:26;
}; };
#endif #endif
...@@ -32,43 +32,13 @@ ...@@ -32,43 +32,13 @@
# include <io.h> # include <io.h>
# include <direct.h> # include <direct.h>
# include <windows.h> # include <windows.h>
# include "msvc-compat.h"
# include "mingw-compat.h"
# define snprintf _snprintf # define snprintf _snprintf
# if defined(__DMC__)
# if defined(_M_AMD64)
# define SSIZE_T long long
# else
# define SSIZE_T int
# endif
# endif
typedef SSIZE_T ssize_t; typedef SSIZE_T ssize_t;
# if defined(_MSC_VER)
/* access() mode parameter #defines */
# define F_OK 0 /* existence check */
# define W_OK 2 /* write mode check */
# define R_OK 4 /* read mode check */
# endif
#if defined(__MINGW32__)
# define off_t off64_t
# define lseek _lseeki64
# define stat _stati64
# define fstat _fstati64
#elif defined(_MSC_VER)
typedef __int64 off64_t;
# define off_t off64_t
# define lseek _lseeki64
# define stat _stat64
# define fstat _fstat64
#endif
#else #else
# include <unistd.h> # include <unistd.h>
...@@ -84,13 +54,4 @@ typedef __int64 off64_t; ...@@ -84,13 +54,4 @@ typedef __int64 off64_t;
#define GIT_PATH_MAX 4096 #define GIT_PATH_MAX 4096
#ifndef GIT_HAVE_INTTYPES_H
/* add some missing <stdint.h> typedef's */
typedef long int32_t;
typedef unsigned long uint32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
#endif
#endif /* INCLUDE_common_h__ */ #endif /* INCLUDE_common_h__ */
...@@ -34,7 +34,7 @@ extern int git__fsync(int fd); ...@@ -34,7 +34,7 @@ extern int git__fsync(int fd);
# ifndef GIT__WIN32_NO_HIDE_FILEOPS # ifndef GIT__WIN32_NO_HIDE_FILEOPS
# define unlink(p) git__unlink(p) # define unlink(p) git__unlink(p)
# define mkstemp(t) git__mkstemp(t) # define mkstemp(t) git__mkstemp(t)
# define mkdir(p,m) git__mkdir(p,m) # define mkdir(p,m) git__mkdir(p, m)
# define fsync(fd) git__fsync(fd) # define fsync(fd) git__fsync(fd)
# endif # endif
#endif /* GIT_WIN32 */ #endif /* GIT_WIN32 */
......
...@@ -25,14 +25,14 @@ typedef struct git_commit git_commit; ...@@ -25,14 +25,14 @@ typedef struct git_commit git_commit;
* pool's git_odb, or if the commit is present but is * pool's git_odb, or if the commit is present but is
* too malformed to be parsed successfully. * too malformed to be parsed successfully.
*/ */
GIT_EXTERN(git_commit*) git_commit_parse(git_revpool *pool, const git_oid *id); GIT_EXTERN(git_commit *) git_commit_parse(git_revpool *pool, const git_oid *id);
/** /**
* Get the id of a commit. * Get the id of a commit.
* @param commit a previously parsed commit. * @param commit a previously parsed commit.
* @return object identity for the commit. * @return object identity for the commit.
*/ */
GIT_EXTERN(const git_oid*) git_commit_id(git_commit *commit); GIT_EXTERN(const git_oid *) git_commit_id(git_commit *commit);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
......
...@@ -16,8 +16,8 @@ ...@@ -16,8 +16,8 @@
/** Declare a public function exported for application use. */ /** Declare a public function exported for application use. */
#ifdef __GNUC__ #ifdef __GNUC__
# define GIT_EXTERN(type) extern \ # define GIT_EXTERN(type) extern \
__attribute__((visibility("default"))) \ __attribute__((visibility("default"))) \
type type
#else #else
# define GIT_EXTERN(type) extern type # define GIT_EXTERN(type) extern type
#endif #endif
...@@ -25,9 +25,9 @@ ...@@ -25,9 +25,9 @@
/** Declare a public TLS symbol exported for application use. */ /** Declare a public TLS symbol exported for application use. */
#ifdef __GNUC__ #ifdef __GNUC__
# define GIT_EXTERN_TLS(type) extern \ # define GIT_EXTERN_TLS(type) extern \
__attribute__((visibility("default"))) \ __attribute__((visibility("default"))) \
GIT_TLS \ GIT_TLS \
type type
#else #else
# define GIT_EXTERN_TLS(type) extern GIT_TLS type # define GIT_EXTERN_TLS(type) extern GIT_TLS type
#endif #endif
......
...@@ -20,8 +20,7 @@ GIT_BEGIN_DECL ...@@ -20,8 +20,7 @@ GIT_BEGIN_DECL
#define GIT_OID_HEXSZ (GIT_OID_RAWSZ * 2) #define GIT_OID_HEXSZ (GIT_OID_RAWSZ * 2)
/** Unique identity of any object (commit, tree, blob, tag). */ /** Unique identity of any object (commit, tree, blob, tag). */
typedef struct typedef struct {
{
/** raw binary formatted id */ /** raw binary formatted id */
unsigned char id[GIT_OID_RAWSZ]; unsigned char id[GIT_OID_RAWSZ];
} git_oid; } git_oid;
......
...@@ -25,7 +25,7 @@ GIT_BEGIN_DECL ...@@ -25,7 +25,7 @@ GIT_BEGIN_DECL
* @param db the database objects are read from. * @param db the database objects are read from.
* @return the new traversal handle; NULL if memory is exhausted. * @return the new traversal handle; NULL if memory is exhausted.
*/ */
GIT_EXTERN(git_revpool*) gitrp_alloc(git_odb *db); GIT_EXTERN(git_revpool *) gitrp_alloc(git_odb *db);
/** /**
* Reset the traversal machinary for reuse. * Reset the traversal machinary for reuse.
...@@ -52,7 +52,7 @@ GIT_EXTERN(void) gitrp_hide(git_revpool *pool, git_commit *commit); ...@@ -52,7 +52,7 @@ GIT_EXTERN(void) gitrp_hide(git_revpool *pool, git_commit *commit);
* @param pool the pool to pop the commit from. * @param pool the pool to pop the commit from.
* @return next commit; NULL if there is no more output. * @return next commit; NULL if there is no more output.
*/ */
GIT_EXTERN(git_commit*) gitrp_next(git_revpool *pool); GIT_EXTERN(git_commit *) gitrp_next(git_revpool *pool);
/** /**
* Free a revwalk previously allocated. * Free a revwalk previously allocated.
......
#ifndef INCLUDE_mingw_compat__
#define INCLUDE_mingw_compat__
#if defined(__MINGW32__)
/* use a 64-bit file offset type */
# define off_t off64_t
# define lseek _lseeki64
# define stat _stati64
# define fstat _fstati64
#endif
#endif /* INCLUDE_mingw_compat__ */
#ifndef INCLUDE_msvc_compat__
#define INCLUDE_msvc_compat__
#if defined(_MSC_VER)
/* access() mode parameter #defines */
# define F_OK 0 /* existence check */
# define W_OK 2 /* write mode check */
# define R_OK 4 /* read mode check */
/* use a 64-bit file offset type */
typedef __int64 off64_t;
# define off_t off64_t
# define lseek _lseeki64
# define stat _stat64
# define fstat _fstat64
/* stat: file mode type testing macros */
# define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
# define S_ISFIFO(m) (((m) & _S_IFMT) == _S_IFIFO)
/* add some missing <stdint.h> typedef's */
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef long int32_t;
typedef unsigned long uint32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
typedef long long intmax_t;
typedef unsigned long long uintmax_t;
#endif
#endif /* INCLUDE_msvc_compat__ */
...@@ -31,15 +31,31 @@ ...@@ -31,15 +31,31 @@
#include "odb.h" #include "odb.h"
#define GIT_PACK_NAME_MAX (5 + 40 + 1) #define GIT_PACK_NAME_MAX (5 + 40 + 1)
typedef struct {
uint32_t n;
unsigned char *oid;
off_t offset;
off_t size;
} index_entry;
struct git_pack { struct git_pack {
git_odb *db; git_odb *db;
git_lck lock; git_lck lock;
/** Functions to access idx_map. */ /** Functions to access idx_map. */
int (*idx_search)( int (*idx_search)(
off_t *, uint32_t *,
struct git_pack *, struct git_pack *,
const git_oid *); const git_oid *);
int (*idx_search_offset)(
uint32_t *,
struct git_pack *,
off_t);
int (*idx_get)(
index_entry *,
struct git_pack *,
uint32_t n);
/** The .idx file, mapped into memory. */ /** The .idx file, mapped into memory. */
git_file idx_fd; git_file idx_fd;
...@@ -49,10 +65,18 @@ struct git_pack { ...@@ -49,10 +65,18 @@ struct git_pack {
uint32_t *im_crc; uint32_t *im_crc;
uint32_t *im_offset32; uint32_t *im_offset32;
uint32_t *im_offset64; uint32_t *im_offset64;
uint32_t *im_off_idx;
uint32_t *im_off_next;
/** Number of objects in this pack. */ /** Number of objects in this pack. */
uint32_t obj_cnt; uint32_t obj_cnt;
/** The size of the .pack file. */
off_t pack_size;
/** The mtime of the .pack file. */
time_t pack_mtime;
/** Number of git_packlist we appear in. */ /** Number of git_packlist we appear in. */
unsigned int refcnt; unsigned int refcnt;
...@@ -100,7 +124,7 @@ typedef struct { /* object header data */ ...@@ -100,7 +124,7 @@ typedef struct { /* object header data */
static struct { static struct {
const char *str; /* type name string */ const char *str; /* type name string */
int loose; /* valid loose object type flag */ int loose; /* valid loose object type flag */
} obj_type_table [] = { } obj_type_table[] = {
{ "", 0 }, /* 0 = GIT_OBJ__EXT1 */ { "", 0 }, /* 0 = GIT_OBJ__EXT1 */
{ "commit", 1 }, /* 1 = GIT_OBJ_COMMIT */ { "commit", 1 }, /* 1 = GIT_OBJ_COMMIT */
{ "tree", 1 }, /* 2 = GIT_OBJ_TREE */ { "tree", 1 }, /* 2 = GIT_OBJ_TREE */
...@@ -113,7 +137,7 @@ static struct { ...@@ -113,7 +137,7 @@ static struct {
GIT_INLINE(uint32_t) decode32(void *b) GIT_INLINE(uint32_t) decode32(void *b)
{ {
return ntohl(*((uint32_t*)b)); return ntohl(*((uint32_t *)b));
} }
GIT_INLINE(uint64_t) decode64(void *b) GIT_INLINE(uint64_t) decode64(void *b)
...@@ -226,7 +250,7 @@ static int is_zlib_compressed_data(unsigned char *data) ...@@ -226,7 +250,7 @@ static int is_zlib_compressed_data(unsigned char *data)
unsigned int w; unsigned int w;
w = ((unsigned int)(data[0]) << 8) + data[1]; w = ((unsigned int)(data[0]) << 8) + data[1];
return data[0] == 0x78 && !(w %31); return data[0] == 0x78 && !(w % 31);
} }
static size_t get_binary_object_header(obj_hdr *hdr, gitfo_buf *obj) static size_t get_binary_object_header(obj_hdr *hdr, gitfo_buf *obj)
...@@ -663,20 +687,65 @@ static int pack_openidx_map(git_pack *p) ...@@ -663,20 +687,65 @@ static int pack_openidx_map(git_pack *p)
return GIT_SUCCESS; return GIT_SUCCESS;
} }
static int idxv1_search(off_t *out, git_pack *p, const git_oid *id) typedef struct {
off_t offset;
uint32_t n;
} offset_idx_info;
static int cmp_offset_idx_info(const void *lhs, const void *rhs)
{
const offset_idx_info *a = lhs;
const offset_idx_info *b = rhs;
return (a->offset < b->offset) ? -1 : (a->offset > b->offset) ? 1 : 0;
}
static int make_offset_index(git_pack *p, offset_idx_info *data)
{
off_t min_off = 3 * 4, max_off = p->pack_size - GIT_OID_RAWSZ;
uint32_t *idx, *next;
uint32_t j;
qsort(data, p->obj_cnt, sizeof(*data), cmp_offset_idx_info);
if (data[0].offset < min_off || data[p->obj_cnt].offset > max_off)
return GIT_ERROR;
if ((idx = git__malloc(sizeof(*idx) * (p->obj_cnt+1))) == NULL)
return GIT_ERROR;
if ((next = git__malloc(sizeof(*next) * p->obj_cnt)) == NULL) {
free(idx);
return GIT_ERROR;
}
for (j = 0; j < p->obj_cnt+1; j++)
idx[j] = data[j].n;
for (j = 0; j < p->obj_cnt; j++) {
assert(idx[j] < p->obj_cnt);
assert(idx[j+1] < p->obj_cnt+1);
next[idx[j]] = idx[j+1];
}
p->im_off_idx = idx;
p->im_off_next = next;
return GIT_SUCCESS;
}
static int idxv1_search(uint32_t *out, git_pack *p, const git_oid *id)
{ {
unsigned char *data = p->im_oid; unsigned char *data = p->im_oid;
size_t lo = id->id[0] ? p->im_fanout[id->id[0] - 1] : 0; uint32_t lo = id->id[0] ? p->im_fanout[id->id[0] - 1] : 0;
size_t hi = p->im_fanout[id->id[0]]; uint32_t hi = p->im_fanout[id->id[0]];
do { do {
size_t mid = (lo + hi) >> 1; uint32_t mid = (lo + hi) >> 1;
size_t pos = 24 * mid; uint32_t pos = 24 * mid;
int cmp = memcmp(id->id, data + pos + 4, 20); int cmp = memcmp(id->id, data + pos + 4, 20);
if (cmp < 0) if (cmp < 0)
hi = mid; hi = mid;
else if (!cmp) { else if (!cmp) {
*out = decode32(data + pos); *out = mid;
return GIT_SUCCESS; return GIT_SUCCESS;
} else } else
lo = mid + 1; lo = mid + 1;
...@@ -684,12 +753,58 @@ static int idxv1_search(off_t *out, git_pack *p, const git_oid *id) ...@@ -684,12 +753,58 @@ static int idxv1_search(off_t *out, git_pack *p, const git_oid *id)
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
} }
static int idxv1_search_offset(uint32_t *out, git_pack *p, off_t offset)
{
if (offset > 0 && offset < (p->pack_size - GIT_OID_RAWSZ)) {
uint32_t lo = 0, hi = p->obj_cnt+1;
unsigned char *data = p->im_oid;
uint32_t *idx = p->im_off_idx;
do {
uint32_t mid = (lo + hi) >> 1;
uint32_t n = idx[mid];
uint32_t pos = n * (GIT_OID_RAWSZ + 4);
off_t here = decode32(data + pos);
if (offset < here)
hi = mid;
else if (offset == here) {
*out = n;
return GIT_SUCCESS;
} else
lo = mid + 1;
} while (lo < hi);
}
return GIT_ENOTFOUND;
}
static int idxv1_get(index_entry *e, git_pack *p, uint32_t n)
{
unsigned char *data = p->im_oid;
uint32_t *next = p->im_off_next;
if (n < p->obj_cnt) {
uint32_t pos = n * (GIT_OID_RAWSZ + 4);
off_t next_off = p->pack_size - GIT_OID_RAWSZ;
e->n = n;
e->oid = data + pos + 4;
e->offset = decode32(data + pos);
if (next[n] < p->obj_cnt) {
pos = next[n] * (GIT_OID_RAWSZ + 4);
next_off = decode32(data + pos);
}
e->size = next_off - e->offset;
return GIT_SUCCESS;
}
return GIT_ENOTFOUND;
}
static int pack_openidx_v1(git_pack *p) static int pack_openidx_v1(git_pack *p)
{ {
uint32_t *src_fanout = p->idx_map.data; uint32_t *src_fanout = p->idx_map.data;
uint32_t *im_fanout; uint32_t *im_fanout;
offset_idx_info *info;
size_t expsz; size_t expsz;
int j; uint32_t j;
if ((im_fanout = git__malloc(sizeof(*im_fanout) * 256)) == NULL) if ((im_fanout = git__malloc(sizeof(*im_fanout) * 256)) == NULL)
return GIT_ERROR; return GIT_ERROR;
...@@ -711,29 +826,48 @@ static int pack_openidx_v1(git_pack *p) ...@@ -711,29 +826,48 @@ static int pack_openidx_v1(git_pack *p)
} }
p->idx_search = idxv1_search; p->idx_search = idxv1_search;
p->idx_search_offset = idxv1_search_offset;
p->idx_get = idxv1_get;
p->im_fanout = im_fanout; p->im_fanout = im_fanout;
p->im_oid = (unsigned char*)(src_fanout + 256); p->im_oid = (unsigned char *)(src_fanout + 256);
if ((info = git__malloc(sizeof(*info) * (p->obj_cnt+1))) == NULL) {
free(im_fanout);
return GIT_ERROR;
}
for (j = 0; j < p->obj_cnt; j++) {
uint32_t pos = j * (GIT_OID_RAWSZ + 4);
info[j].offset = decode32(p->im_oid + pos);
info[j].n = j;
}
info[p->obj_cnt].offset = p->pack_size - GIT_OID_RAWSZ;
info[p->obj_cnt].n = p->obj_cnt;
if (make_offset_index(p, info)) {
free(im_fanout);
free(info);
return GIT_ERROR;
}
free(info);
return GIT_SUCCESS; return GIT_SUCCESS;
} }
static int idxv2_search(off_t *out, git_pack *p, const git_oid *id) static int idxv2_search(uint32_t *out, git_pack *p, const git_oid *id)
{ {
unsigned char *data = p->im_oid; unsigned char *data = p->im_oid;
size_t lo = id->id[0] ? p->im_fanout[id->id[0] - 1] : 0; uint32_t lo = id->id[0] ? p->im_fanout[id->id[0] - 1] : 0;
size_t hi = p->im_fanout[id->id[0]]; uint32_t hi = p->im_fanout[id->id[0]];
do { do {
size_t mid = (lo + hi) >> 1; uint32_t mid = (lo + hi) >> 1;
size_t pos = 20 * mid; uint32_t pos = 20 * mid;
int cmp = memcmp(id->id, data + pos, 20); int cmp = memcmp(id->id, data + pos, 20);
if (cmp < 0) if (cmp < 0)
hi = mid; hi = mid;
else if (!cmp) { else if (!cmp) {
uint32_t o32 = decode32(p->im_offset32 + mid); *out = mid;
if (o32 & 0x80000000)
*out = decode64(p->im_offset64 + 2*(o32 & ~0x80000000));
else
*out = o32;
return GIT_SUCCESS; return GIT_SUCCESS;
} else } else
lo = mid + 1; lo = mid + 1;
...@@ -741,12 +875,71 @@ static int idxv2_search(off_t *out, git_pack *p, const git_oid *id) ...@@ -741,12 +875,71 @@ static int idxv2_search(off_t *out, git_pack *p, const git_oid *id)
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
} }
static int idxv2_search_offset(uint32_t *out, git_pack *p, off_t offset)
{
if (offset > 0 && offset < (p->pack_size - GIT_OID_RAWSZ)) {
uint32_t lo = 0, hi = p->obj_cnt+1;
uint32_t *idx = p->im_off_idx;
do {
uint32_t mid = (lo + hi) >> 1;
uint32_t n = idx[mid];
uint32_t o32 = decode32(p->im_offset32 + n);
off_t here = o32;
if (o32 & 0x80000000) {
uint32_t o64_idx = (o32 & ~0x80000000);
here = decode64(p->im_offset64 + 2*o64_idx);
}
if (offset < here)
hi = mid;
else if (offset == here) {
*out = n;
return GIT_SUCCESS;
} else
lo = mid + 1;
} while (lo < hi);
}
return GIT_ENOTFOUND;
}
static int idxv2_get(index_entry *e, git_pack *p, uint32_t n)
{
unsigned char *data = p->im_oid;
uint32_t *next = p->im_off_next;
if (n < p->obj_cnt) {
uint32_t o32 = decode32(p->im_offset32 + n);
off_t next_off = p->pack_size - GIT_OID_RAWSZ;
e->n = n;
e->oid = data + n * GIT_OID_RAWSZ;
e->offset = o32;
if (o32 & 0x80000000) {
uint32_t o64_idx = (o32 & ~0x80000000);
e->offset = decode64(p->im_offset64 + 2*o64_idx);
}
if (next[n] < p->obj_cnt) {
o32 = decode32(p->im_offset32 + next[n]);
next_off = o32;
if (o32 & 0x80000000) {
uint32_t o64_idx = (o32 & ~0x80000000);
next_off = decode64(p->im_offset64 + 2*o64_idx);
}
}
e->size = next_off - e->offset;
return GIT_SUCCESS;
}
return GIT_ENOTFOUND;
}
static int pack_openidx_v2(git_pack *p) static int pack_openidx_v2(git_pack *p)
{ {
unsigned char *data = p->idx_map.data; unsigned char *data = p->idx_map.data;
uint32_t *src_fanout = (uint32_t*)(data + 8); uint32_t *src_fanout = (uint32_t *)(data + 8);
uint32_t *im_fanout; uint32_t *im_fanout;
int j; offset_idx_info *info;
size_t sz, o64_sz, o64_len;
uint32_t j;
if ((im_fanout = git__malloc(sizeof(*im_fanout) * 256)) == NULL) if ((im_fanout = git__malloc(sizeof(*im_fanout) * 256)) == NULL)
return GIT_ERROR; return GIT_ERROR;
...@@ -761,52 +954,128 @@ static int pack_openidx_v2(git_pack *p) ...@@ -761,52 +954,128 @@ static int pack_openidx_v2(git_pack *p)
} }
p->obj_cnt = im_fanout[255]; p->obj_cnt = im_fanout[255];
/* minimum size of .idx file (with empty 64-bit offsets table): */
sz = 4 + 4 + 256 * 4 + p->obj_cnt * (20 + 4 + 4) + 2 * 20;
if (p->idx_map.len < sz) {
free(im_fanout);
return GIT_ERROR;
}
p->idx_search = idxv2_search; p->idx_search = idxv2_search;
p->idx_search_offset = idxv2_search_offset;
p->idx_get = idxv2_get;
p->im_fanout = im_fanout; p->im_fanout = im_fanout;
p->im_oid = (unsigned char*)(src_fanout + 256); p->im_oid = (unsigned char *)(src_fanout + 256);
p->im_crc = (uint32_t*)(p->im_oid + 20 * p->obj_cnt); p->im_crc = (uint32_t *)(p->im_oid + 20 * p->obj_cnt);
p->im_offset32 = p->im_crc + p->obj_cnt; p->im_offset32 = p->im_crc + p->obj_cnt;
p->im_offset64 = p->im_offset32 + p->obj_cnt; p->im_offset64 = p->im_offset32 + p->obj_cnt;
if ((info = git__malloc(sizeof(*info) * (p->obj_cnt+1))) == NULL) {
free(im_fanout);
return GIT_ERROR;
}
/* check 64-bit offset table index values are within bounds */
o64_sz = p->idx_map.len - sz;
o64_len = o64_sz / 8;
for (j = 0; j < p->obj_cnt; j++) {
uint32_t o32 = decode32(p->im_offset32 + j);
off_t offset = o32;
if (o32 & 0x80000000) {
uint32_t o64_idx = (o32 & ~0x80000000);
if (o64_idx >= o64_len) {
free(im_fanout);
free(info);
return GIT_ERROR;
}
offset = decode64(p->im_offset64 + 2*o64_idx);
}
info[j].offset = offset;
info[j].n = j;
}
info[p->obj_cnt].offset = p->pack_size - GIT_OID_RAWSZ;
info[p->obj_cnt].n = p->obj_cnt;
if (make_offset_index(p, info)) {
free(im_fanout);
free(info);
return GIT_ERROR;
}
free(info);
return GIT_SUCCESS;
}
static int pack_stat(git_pack *p)
{
char pb[GIT_PATH_MAX];
struct stat sb;
if (git__fmt(pb, sizeof(pb), "%s/pack/%s.pack",
p->db->objects_dir,
p->pack_name) < 0)
return GIT_ERROR;
if (stat(pb, &sb) || !S_ISREG(sb.st_mode))
return GIT_ERROR;
if (sb.st_size < (3 * 4 + GIT_OID_RAWSZ))
return GIT_ERROR;
p->pack_size = sb.st_size;
p->pack_mtime = sb.st_mtime;
return GIT_SUCCESS; return GIT_SUCCESS;
} }
static int pack_openidx(git_pack *p) static int pack_openidx(git_pack *p)
{ {
gitlck_lock(&p->lock); gitlck_lock(&p->lock);
if (p->invalid)
goto unlock_fail; if (p->invalid) {
gitlck_unlock(&p->lock);
return GIT_ERROR;
}
if (++p->idxcnt == 1 && !p->idx_search) { if (++p->idxcnt == 1 && !p->idx_search) {
int status, version;
uint32_t *data; uint32_t *data;
if (pack_openidx_map(p)) if (pack_stat(p) || pack_openidx_map(p)) {
goto invalid_fail; p->invalid = 1;
p->idxcnt--;
gitlck_unlock(&p->lock);
return GIT_ERROR;
}
data = p->idx_map.data; data = p->idx_map.data;
status = GIT_SUCCESS;
version = 1;
if (decode32(&data[0]) == PACK_TOC) { if (decode32(&data[0]) == PACK_TOC)
switch (decode32(&data[1])) { version = decode32(&data[1]);
case 2:
if (pack_openidx_v2(p))
goto unmap_fail;
break;
default:
goto unmap_fail;
}
} else if (pack_openidx_v1(p))
goto unmap_fail;
}
gitlck_unlock(&p->lock);
return GIT_SUCCESS;
unmap_fail: switch (version) {
gitfo_free_map(&p->idx_map); case 1:
status = pack_openidx_v1(p);
break;
case 2:
status = pack_openidx_v2(p);
break;
default:
status = GIT_ERROR;
}
invalid_fail: if (status != GIT_SUCCESS) {
p->invalid = 1; gitfo_free_map(&p->idx_map);
p->idxcnt--; p->invalid = 1;
p->idxcnt--;
gitlck_unlock(&p->lock);
return status;
}
}
unlock_fail:
gitlck_unlock(&p->lock); gitlck_unlock(&p->lock);
return GIT_ERROR; return GIT_SUCCESS;
} }
static void pack_decidx(git_pack *p) static void pack_decidx(git_pack *p)
...@@ -900,7 +1169,7 @@ static int scan_one_pack(void *state, char *name) ...@@ -900,7 +1169,7 @@ static int scan_one_pack(void *state, char *name)
return 0; return 0;
} }
static git_packlist* scan_packs(git_odb *db) static git_packlist *scan_packs(git_odb *db)
{ {
char pb[GIT_PATH_MAX]; char pb[GIT_PATH_MAX];
struct scanned_pack *state = NULL, *c; struct scanned_pack *state = NULL, *c;
...@@ -954,7 +1223,7 @@ static git_packlist *packlist_get(git_odb *db) ...@@ -954,7 +1223,7 @@ static git_packlist *packlist_get(git_odb *db)
return pl; return pl;
} }
static int search_packs(git_pack **p, off_t *offset, git_odb *db, const git_oid *id) static int search_packs(git_pack **p, uint32_t *n, git_odb *db, const git_oid *id)
{ {
git_packlist *pl = packlist_get(db); git_packlist *pl = packlist_get(db);
size_t j; size_t j;
...@@ -965,7 +1234,7 @@ static int search_packs(git_pack **p, off_t *offset, git_odb *db, const git_oid ...@@ -965,7 +1234,7 @@ static int search_packs(git_pack **p, off_t *offset, git_odb *db, const git_oid
for (j = 0; j < pl->n_packs; j++) { for (j = 0; j < pl->n_packs; j++) {
git_pack *pack = pl->packs[j]; git_pack *pack = pl->packs[j];
off_t pos; uint32_t pos;
int res; int res;
if (pack_openidx(pack)) if (pack_openidx(pack))
...@@ -974,17 +1243,17 @@ static int search_packs(git_pack **p, off_t *offset, git_odb *db, const git_oid ...@@ -974,17 +1243,17 @@ static int search_packs(git_pack **p, off_t *offset, git_odb *db, const git_oid
pack_decidx(pack); pack_decidx(pack);
if (!res) { if (!res) {
packlist_dec(db,pl); packlist_dec(db, pl);
if (p) if (p)
*p = pack; *p = pack;
if (offset) if (n)
*offset = pos; *n = pos;
return GIT_SUCCESS; return GIT_SUCCESS;
} }
} }
packlist_dec(db,pl); packlist_dec(db, pl);
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
} }
...@@ -1109,18 +1378,18 @@ int git_odb__read_loose(git_obj *out, git_odb *db, const git_oid *id) ...@@ -1109,18 +1378,18 @@ int git_odb__read_loose(git_obj *out, git_odb *db, const git_oid *id)
static int read_packed(git_obj *out, git_pack *p, const git_oid *id) static int read_packed(git_obj *out, git_pack *p, const git_oid *id)
{ {
off_t pos; uint32_t n;
int res; int res;
assert(out && p && id); assert(out && p && id);
if (pack_openidx(p)) if (pack_openidx(p))
return GIT_ERROR; return GIT_ERROR;
res = p->idx_search(&pos, p, id); res = p->idx_search(&n, p, id);
pack_decidx(p); pack_decidx(p);
if (!res) { if (!res) {
/* TODO unpack object at pos */ /* TODO unpack object */
res = GIT_ERROR; res = GIT_ERROR;
} }
......
...@@ -58,6 +58,6 @@ GIT_INLINE(int) git__is_sizet(off_t p) ...@@ -58,6 +58,6 @@ GIT_INLINE(int) git__is_sizet(off_t p)
alloc = alloc_nr(alloc); \ alloc = alloc_nr(alloc); \
x = xrealloc((x), alloc * sizeof(*(x))); \ x = xrealloc((x), alloc * sizeof(*(x))); \
} \ } \
} while(0) } while (0)
#endif /* INCLUDE_util_h__ */ #endif /* INCLUDE_util_h__ */
...@@ -41,6 +41,8 @@ ifneq (,$(findstring MINGW,$(uname_S))) ...@@ -41,6 +41,8 @@ ifneq (,$(findstring MINGW,$(uname_S)))
EXTRA_LIBS += -lwsock32 -lpthread EXTRA_LIBS += -lwsock32 -lpthread
endif endif
-include ../config.mak
GIT_LIB = ../libgit2.a GIT_LIB = ../libgit2.a
HDRS = $(wildcard ../src/*.h) HDRS = $(wildcard ../src/*.h)
......
...@@ -123,9 +123,9 @@ BEGIN_TEST(dot) ...@@ -123,9 +123,9 @@ BEGIN_TEST(dot)
must_pass(setup(&dot)); must_pass(setup(&dot));
must_pass(gitfo_dirent(path_buffer, must_pass(gitfo_dirent(path_buffer,
sizeof(path_buffer), sizeof(path_buffer),
one_entry, one_entry,
&dot)); &dot));
must_pass(check_counts(&dot)); must_pass(check_counts(&dot));
...@@ -148,9 +148,9 @@ BEGIN_TEST(sub) ...@@ -148,9 +148,9 @@ BEGIN_TEST(sub)
must_pass(setup(&sub)); must_pass(setup(&sub));
must_pass(gitfo_dirent(path_buffer, must_pass(gitfo_dirent(path_buffer,
sizeof(path_buffer), sizeof(path_buffer),
one_entry, one_entry,
&sub)); &sub));
must_pass(check_counts(&sub)); must_pass(check_counts(&sub));
...@@ -167,9 +167,9 @@ BEGIN_TEST(sub_slash) ...@@ -167,9 +167,9 @@ BEGIN_TEST(sub_slash)
must_pass(setup(&sub_slash)); must_pass(setup(&sub_slash));
must_pass(gitfo_dirent(path_buffer, must_pass(gitfo_dirent(path_buffer,
sizeof(path_buffer), sizeof(path_buffer),
one_entry, one_entry,
&sub_slash)); &sub_slash));
must_pass(check_counts(&sub_slash)); must_pass(check_counts(&sub_slash));
...@@ -196,17 +196,17 @@ BEGIN_TEST(empty) ...@@ -196,17 +196,17 @@ BEGIN_TEST(empty)
must_pass(setup(&empty)); must_pass(setup(&empty));
must_pass(gitfo_dirent(path_buffer, must_pass(gitfo_dirent(path_buffer,
sizeof(path_buffer), sizeof(path_buffer),
one_entry, one_entry,
&empty)); &empty));
must_pass(check_counts(&empty)); must_pass(check_counts(&empty));
/* make sure callback not called */ /* make sure callback not called */
must_pass(gitfo_dirent(path_buffer, must_pass(gitfo_dirent(path_buffer,
sizeof(path_buffer), sizeof(path_buffer),
dont_call_me, dont_call_me,
&empty)); &empty));
must_pass(knockdown(&empty)); must_pass(knockdown(&empty));
END_TEST END_TEST
...@@ -229,9 +229,9 @@ BEGIN_TEST(odd) ...@@ -229,9 +229,9 @@ BEGIN_TEST(odd)
must_pass(setup(&odd)); must_pass(setup(&odd));
must_pass(gitfo_dirent(path_buffer, must_pass(gitfo_dirent(path_buffer,
sizeof(path_buffer), sizeof(path_buffer),
one_entry, one_entry,
&odd)); &odd));
must_pass(check_counts(&odd)); must_pass(check_counts(&odd));
......
...@@ -50,7 +50,7 @@ BEGIN_TEST(invalid_string_all_chars) ...@@ -50,7 +50,7 @@ BEGIN_TEST(invalid_string_all_chars)
test_die("line %d: must accept '%s'", __LINE__, in); test_die("line %d: must accept '%s'", __LINE__, in);
if (memcmp(out.id, exp, sizeof(out.id))) if (memcmp(out.id, exp, sizeof(out.id)))
test_die("line %d: bad parse of '%s', %x != %x", test_die("line %d: bad parse of '%s', %x != %x",
__LINE__, in, exp[19], out.id[19]); __LINE__, in, exp[19], out.id[19]);
} else if (!git_oid_mkstr(&out, in)) } else if (!git_oid_mkstr(&out, in))
test_die("line %d: must not accept '%s'", __LINE__, in); test_die("line %d: must not accept '%s'", __LINE__, in);
} }
......
...@@ -3,19 +3,19 @@ ...@@ -3,19 +3,19 @@
#include <git/odb.h> #include <git/odb.h>
BEGIN_TEST(type_to_string) BEGIN_TEST(type_to_string)
must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ_BAD),"")); must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ_BAD), ""));
must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ__EXT1),"")); must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ__EXT1), ""));
must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ_COMMIT),"commit")); must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ_COMMIT), "commit"));
must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ_TREE),"tree")); must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ_TREE), "tree"));
must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ_BLOB),"blob")); must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ_BLOB), "blob"));
must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ_TAG),"tag")); must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ_TAG), "tag"));
must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ__EXT2),"")); must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ__EXT2), ""));
must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ_OFS_DELTA),"OFS_DELTA")); must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ_OFS_DELTA), "OFS_DELTA"));
must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ_REF_DELTA),"REF_DELTA")); must_be_true(!strcmp(git_obj_type_to_string(GIT_OBJ_REF_DELTA), "REF_DELTA"));
must_be_true(!strcmp(git_obj_type_to_string(-2),"")); must_be_true(!strcmp(git_obj_type_to_string(-2), ""));
must_be_true(!strcmp(git_obj_type_to_string(8),"")); must_be_true(!strcmp(git_obj_type_to_string(8), ""));
must_be_true(!strcmp(git_obj_type_to_string(1234),"")); must_be_true(!strcmp(git_obj_type_to_string(1234), ""));
END_TEST END_TEST
BEGIN_TEST(string_to_type) BEGIN_TEST(string_to_type)
......
...@@ -37,8 +37,8 @@ BEGIN_TEST(exists_loose_one) ...@@ -37,8 +37,8 @@ BEGIN_TEST(exists_loose_one)
must_be_true(git_odb_exists(db, &id)); must_be_true(git_odb_exists(db, &id));
/* Test for a non-existant object */ /* Test for a non-existant object */
must_pass(git_oid_mkstr(&id2,"8b137891791fe96927ad78e64b0aad7bded08baa")); must_pass(git_oid_mkstr(&id2, "8b137891791fe96927ad78e64b0aad7bded08baa"));
must_be_true(0 == git_odb_exists(db, &id2)); must_be_true(0 == git_odb_exists(db, &id2));
git_odb_close(db); git_odb_close(db);
must_pass(remove_object_files(odb_dir, &one)); must_pass(remove_object_files(odb_dir, &one));
......
...@@ -351,55 +351,54 @@ static git_obj some_obj = { ...@@ -351,55 +351,54 @@ static git_obj some_obj = {
static int make_odb_dir(void) static int make_odb_dir(void)
{ {
if (gitfo_mkdir(odb_dir, 0755) < 0) { if (gitfo_mkdir(odb_dir, 0755) < 0) {
if (errno == EEXIST) { int err = errno;
fprintf(stderr, "odb directory \"%s\" already exists!\n", odb_dir); fprintf(stderr, "can't make directory \"%s\"", odb_dir);
return -1; if (err == EEXIST)
} fprintf(stderr, " (already exists)");
fprintf(stderr, "can't make odb directory \"%s\"\n", odb_dir); fprintf(stderr, "\n");
return -1; return -1;
} }
return 0;
return 0;
} }
static int remove_object_files(object_data *d) static int remove_object_files(object_data *d)
{ {
if (gitfo_unlink(d->file) < 0) { if (gitfo_unlink(d->file) < 0) {
fprintf(stderr, "can't delete object file \"%s\"\n", d->file); fprintf(stderr, "can't delete object file \"%s\"\n", d->file);
return -1; return -1;
} }
if ((gitfo_rmdir(d->dir) < 0) && (errno != ENOTEMPTY)) { if ((gitfo_rmdir(d->dir) < 0) && (errno != ENOTEMPTY)) {
fprintf(stderr, "can't remove object directory \"%s\"\n", d->dir); fprintf(stderr, "can't remove directory \"%s\"\n", d->dir);
return -1; return -1;
} }
if (gitfo_rmdir(odb_dir) < 0) { if (gitfo_rmdir(odb_dir) < 0) {
fprintf(stderr, "can't remove odb directory \"%s\"\n", odb_dir); fprintf(stderr, "can't remove directory \"%s\"\n", odb_dir);
return -1; return -1;
} }
return 0; return 0;
} }
static int check_object_files(object_data *d) static int check_object_files(object_data *d)
{ {
if (gitfo_exists(d->dir) < 0) if (gitfo_exists(d->dir) < 0)
return -1; return -1;
if (gitfo_exists(d->file) < 0) if (gitfo_exists(d->file) < 0)
return -1; return -1;
return 0; return 0;
} }
static int cmp_objects(git_obj *o1, git_obj *o2) static int cmp_objects(git_obj *o1, git_obj *o2)
{ {
if (o1->type != o2->type) if (o1->type != o2->type)
return -1; return -1;
if (o1->len != o2->len) if (o1->len != o2->len)
return -1; return -1;
if ((o1->len > 0) && (memcmp(o1->data, o2->data, o1->len) != 0)) if ((o1->len > 0) && (memcmp(o1->data, o2->data, o1->len) != 0))
return -1; return -1;
return 0; return 0;
} }
BEGIN_TEST(write_commit) BEGIN_TEST(write_commit)
......
...@@ -29,66 +29,66 @@ ...@@ -29,66 +29,66 @@
int write_object_data(char *file, void *data, size_t len) int write_object_data(char *file, void *data, size_t len)
{ {
git_file fd; git_file fd;
int ret; int ret;
if ((fd = gitfo_creat(file, S_IREAD | S_IWRITE)) < 0) if ((fd = gitfo_creat(file, S_IREAD | S_IWRITE)) < 0)
return -1; return -1;
ret = gitfo_write(fd, data, len); ret = gitfo_write(fd, data, len);
gitfo_close(fd); gitfo_close(fd);
return ret; return ret;
} }
int write_object_files(const char *odb_dir, object_data *d) int write_object_files(const char *odb_dir, object_data *d)
{ {
if (gitfo_mkdir(odb_dir, 0755) < 0) { if (gitfo_mkdir(odb_dir, 0755) < 0) {
if (errno == EEXIST) { int err = errno;
fprintf(stderr, "odb directory \"%s\" already exists!\n", odb_dir); fprintf(stderr, "can't make directory \"%s\"", odb_dir);
return -1; if (err == EEXIST)
} fprintf(stderr, " (already exists)");
fprintf(stderr, "can't make odb directory \"%s\"\n", odb_dir); fprintf(stderr, "\n");
return -1; return -1;
} }
if ((gitfo_mkdir(d->dir, 0755) < 0) && (errno != EEXIST)) { if ((gitfo_mkdir(d->dir, 0755) < 0) && (errno != EEXIST)) {
fprintf(stderr, "can't make object directory \"%s\"\n", d->dir); fprintf(stderr, "can't make object directory \"%s\"\n", d->dir);
return -1; return -1;
} }
if (write_object_data(d->file, d->bytes, d->blen) < 0) { if (write_object_data(d->file, d->bytes, d->blen) < 0) {
fprintf(stderr, "can't write object file \"%s\"\n", d->file); fprintf(stderr, "can't write object file \"%s\"\n", d->file);
return -1; return -1;
} }
return 0; return 0;
} }
int remove_object_files(const char *odb_dir, object_data *d) int remove_object_files(const char *odb_dir, object_data *d)
{ {
if (gitfo_unlink(d->file) < 0) { if (gitfo_unlink(d->file) < 0) {
fprintf(stderr, "can't delete object file \"%s\"\n", d->file); fprintf(stderr, "can't delete object file \"%s\"\n", d->file);
return -1; return -1;
} }
if ((gitfo_rmdir(d->dir) < 0) && (errno != ENOTEMPTY)) { if ((gitfo_rmdir(d->dir) < 0) && (errno != ENOTEMPTY)) {
fprintf(stderr, "can't remove object directory \"%s\"\n", d->dir); fprintf(stderr, "can't remove object directory \"%s\"\n", d->dir);
return -1; return -1;
} }
if (gitfo_rmdir(odb_dir) < 0) { if (gitfo_rmdir(odb_dir) < 0) {
fprintf(stderr, "can't remove odb directory \"%s\"\n", odb_dir); fprintf(stderr, "can't remove directory \"%s\"\n", odb_dir);
return -1; return -1;
} }
return 0; return 0;
} }
int cmp_objects(git_obj *o, object_data *d) int cmp_objects(git_obj *o, object_data *d)
{ {
if (o->type != git_obj_string_to_type(d->type)) if (o->type != git_obj_string_to_type(d->type))
return -1; return -1;
if (o->len != d->dlen) if (o->len != d->dlen)
return -1; return -1;
if ((o->len > 0) && (memcmp(o->data, d->data, o->len) != 0)) if ((o->len > 0) && (memcmp(o->data, d->data, o->len) != 0))
return -1; return -1;
return 0; return 0;
} }
...@@ -26,8 +26,7 @@ ...@@ -26,8 +26,7 @@
#define GIT__NO_HIDE_MALLOC #define GIT__NO_HIDE_MALLOC
#include "test_lib.h" #include "test_lib.h"
struct test_info struct test_info {
{
struct test_info *next; struct test_info *next;
const char *test_name; const char *test_name;
const char *file_name; const char *file_name;
...@@ -40,9 +39,9 @@ static struct test_info *current_test; ...@@ -40,9 +39,9 @@ static struct test_info *current_test;
static void show_test_result(const char *status) static void show_test_result(const char *status)
{ {
fprintf(stderr, "* %-6s %5d: %s\n", fprintf(stderr, "* %-6s %5d: %s\n",
status, status,
current_test->line_no, current_test->line_no,
current_test->test_name); current_test->test_name);
} }
void test_die(const char *fmt, ...) void test_die(const char *fmt, ...)
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
* @param name C symbol to assign to this test's function. * @param name C symbol to assign to this test's function.
*/ */
#define BEGIN_TEST(name) \ #define BEGIN_TEST(name) \
void testfunc__##name (void) \ void testfunc__##name(void) \
{ \ { \
test_begin(#name, __FILE__, __LINE__); \ test_begin(#name, __FILE__, __LINE__); \
{ {
......
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