Commit e1de726c by Russell Belfer

Migrate ODB files to new error handling

This migrates odb.c, odb_loose.c, odb_pack.c and pack.c to
the new style of error handling.  Also got the unix and win32
versions of map.c.  There are some minor changes to other
files but no others were completely converted.

This also contains an update to filebuf so that a zeroed out
filebuf will not think that the fd (== 0) is actually open
(and inadvertently call close() on fd 0 if cleaned up).

Lastly, this was built and tested on win32 and contains a
bunch of fixes for the win32 build which was pretty broken.
parent dda708e7
...@@ -103,7 +103,7 @@ typedef enum { ...@@ -103,7 +103,7 @@ typedef enum {
GIT_EOBJCORRUPTED = -28, GIT_EOBJCORRUPTED = -28,
/** The given short oid is ambiguous */ /** The given short oid is ambiguous */
GIT_EAMBIGUOUSOIDPREFIX = -29, GIT_EAMBIGUOUS = -29,
/** Skip and passthrough the given ODB backend */ /** Skip and passthrough the given ODB backend */
GIT_EPASSTHROUGH = -30, GIT_EPASSTHROUGH = -30,
...@@ -128,6 +128,7 @@ typedef enum { ...@@ -128,6 +128,7 @@ typedef enum {
GITERR_REPOSITORY, GITERR_REPOSITORY,
GITERR_CONFIG, GITERR_CONFIG,
GITERR_REGEX, GITERR_REGEX,
GITERR_ODB
} git_error_class; } git_error_class;
/** /**
......
...@@ -78,7 +78,7 @@ static int write_file_stream(git_oid *oid, git_odb *odb, const char *path, git_o ...@@ -78,7 +78,7 @@ static int write_file_stream(git_oid *oid, git_odb *odb, const char *path, git_o
char buffer[4096]; char buffer[4096];
git_odb_stream *stream = NULL; git_odb_stream *stream = NULL;
if ((error = git_odb_open_wstream(&stream, odb, file_size, GIT_OBJ_BLOB)) < GIT_SUCCESS) if ((error = git_odb_open_wstream(&stream, odb, (size_t)file_size, GIT_OBJ_BLOB)) < GIT_SUCCESS)
return error; return error;
if ((fd = p_open(path, O_RDONLY)) < 0) { if ((fd = p_open(path, O_RDONLY)) < 0) {
......
...@@ -40,7 +40,7 @@ static struct { ...@@ -40,7 +40,7 @@ static struct {
{GIT_EEXISTS, "A reference with this name already exists"}, {GIT_EEXISTS, "A reference with this name already exists"},
{GIT_EOVERFLOW, "The given integer literal is too large to be parsed"}, {GIT_EOVERFLOW, "The given integer literal is too large to be parsed"},
{GIT_ENOTNUM, "The given literal is not a valid number"}, {GIT_ENOTNUM, "The given literal is not a valid number"},
{GIT_EAMBIGUOUSOIDPREFIX, "The given oid prefix is ambiguous"}, {GIT_EAMBIGUOUS, "The given oid prefix is ambiguous"},
}; };
const char *git_strerror(int num) const char *git_strerror(int num)
...@@ -129,10 +129,30 @@ void giterr_set(int error_class, const char *string, ...) ...@@ -129,10 +129,30 @@ void giterr_set(int error_class, const char *string, ...)
/* automatically suffix strerror(errno) for GITERR_OS errors */ /* automatically suffix strerror(errno) for GITERR_OS errors */
if (error_class == GITERR_OS) { if (error_class == GITERR_OS) {
if (errno != 0) {
strncat(error_str, ": ", sizeof(error_str)); strncat(error_str, ": ", sizeof(error_str));
strncat(error_str, strerror(errno), sizeof(error_str)); strncat(error_str, strerror(errno), sizeof(error_str));
errno = 0; errno = 0;
} }
#ifdef GIT_WIN32
else {
LPVOID lpMsgBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dw, 0, (LPTSTR) &lpMsgBuf, 0, NULL);
if (lpMsgBuf) {
strncat(error_str, ": ", sizeof(error_str));
strncat(error_str, (const char *)lpMsgBuf, sizeof(error_str));
LocalFree(lpMsgBuf);
}
}
#endif
}
giterr_set_str(error_class, error_str); giterr_set_str(error_class, error_str);
} }
......
...@@ -67,6 +67,8 @@ static int lock_file(git_filebuf *file, int flags) ...@@ -67,6 +67,8 @@ static int lock_file(git_filebuf *file, int flags)
if (file->fd < 0) if (file->fd < 0)
return -1; return -1;
file->fd_is_open = true;
if ((flags & GIT_FILEBUF_APPEND) && git_path_exists(file->path_original) == true) { if ((flags & GIT_FILEBUF_APPEND) && git_path_exists(file->path_original) == true) {
git_file source; git_file source;
char buffer[2048]; char buffer[2048];
...@@ -94,10 +96,10 @@ static int lock_file(git_filebuf *file, int flags) ...@@ -94,10 +96,10 @@ static int lock_file(git_filebuf *file, int flags)
void git_filebuf_cleanup(git_filebuf *file) void git_filebuf_cleanup(git_filebuf *file)
{ {
if (file->fd >= 0) if (file->fd_is_open && file->fd >= 0)
p_close(file->fd); p_close(file->fd);
if (file->fd >= 0 && file->path_lock && git_path_exists(file->path_lock) == true) if (file->fd_is_open && file->path_lock && git_path_exists(file->path_lock))
p_unlink(file->path_lock); p_unlink(file->path_lock);
if (file->digest) if (file->digest)
...@@ -239,6 +241,7 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags) ...@@ -239,6 +241,7 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags)
git_buf_free(&tmp_path); git_buf_free(&tmp_path);
goto cleanup; goto cleanup;
} }
file->fd_is_open = true;
/* No original path */ /* No original path */
file->path_original = NULL; file->path_original = NULL;
...@@ -308,6 +311,7 @@ int git_filebuf_commit(git_filebuf *file, mode_t mode) ...@@ -308,6 +311,7 @@ int git_filebuf_commit(git_filebuf *file, mode_t mode)
p_close(file->fd); p_close(file->fd);
file->fd = -1; file->fd = -1;
file->fd_is_open = false;
if (p_chmod(file->path_lock, mode)) { if (p_chmod(file->path_lock, mode)) {
giterr_set(GITERR_OS, "Failed to set attributes for file at '%s'", file->path_lock); giterr_set(GITERR_OS, "Failed to set attributes for file at '%s'", file->path_lock);
......
...@@ -40,6 +40,7 @@ struct git_filebuf { ...@@ -40,6 +40,7 @@ struct git_filebuf {
size_t buf_size, buf_pos; size_t buf_size, buf_pos;
git_file fd; git_file fd;
bool fd_is_open;
int last_error; int last_error;
}; };
......
...@@ -117,7 +117,7 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime, ...@@ -117,7 +117,7 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime,
return fd; return fd;
if (p_fstat(fd, &st) < 0 || S_ISDIR(st.st_mode) || !git__is_sizet(st.st_size+1)) { if (p_fstat(fd, &st) < 0 || S_ISDIR(st.st_mode) || !git__is_sizet(st.st_size+1)) {
close(fd); p_close(fd);
giterr_set(GITERR_OS, "Invalid regular file stat for '%s'", path); giterr_set(GITERR_OS, "Invalid regular file stat for '%s'", path);
return -1; return -1;
} }
...@@ -127,7 +127,7 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime, ...@@ -127,7 +127,7 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime,
* has been modified. * has been modified.
*/ */
if (mtime != NULL && *mtime >= st.st_mtime) { if (mtime != NULL && *mtime >= st.st_mtime) {
close(fd); p_close(fd);
return 0; return 0;
} }
...@@ -139,8 +139,8 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime, ...@@ -139,8 +139,8 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime,
git_buf_clear(buf); git_buf_clear(buf);
if (git_buf_grow(buf, len + 1) < 0) { if (git_buf_grow(buf, len + 1) < 0) {
close(fd); p_close(fd);
return GIT_ENOMEM; return -1;
} }
buf->ptr[len] = '\0'; buf->ptr[len] = '\0';
...@@ -149,7 +149,7 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime, ...@@ -149,7 +149,7 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime,
ssize_t read_size = p_read(fd, buf->ptr, len); ssize_t read_size = p_read(fd, buf->ptr, len);
if (read_size < 0) { if (read_size < 0) {
close(fd); p_close(fd);
giterr_set(GITERR_OS, "Failed to read descriptor for '%s'", path); giterr_set(GITERR_OS, "Failed to read descriptor for '%s'", path);
return -1; return -1;
} }
......
...@@ -307,7 +307,7 @@ cleanup: ...@@ -307,7 +307,7 @@ cleanup:
int git_indexer_run(git_indexer *idx, git_indexer_stats *stats) int git_indexer_run(git_indexer *idx, git_indexer_stats *stats)
{ {
git_mwindow_file *mwf; git_mwindow_file *mwf;
off_t off = sizeof(struct git_pack_header); git_off_t off = sizeof(struct git_pack_header);
int error; int error;
struct entry *entry; struct entry *entry;
unsigned int left, processed; unsigned int left, processed;
...@@ -328,18 +328,18 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats) ...@@ -328,18 +328,18 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats)
struct git_pack_entry *pentry; struct git_pack_entry *pentry;
git_mwindow *w = NULL; git_mwindow *w = NULL;
int i; int i;
off_t entry_start = off; git_off_t entry_start = off;
void *packed; void *packed;
size_t entry_size; size_t entry_size;
entry = git__malloc(sizeof(struct entry)); entry = git__calloc(1, sizeof(*entry));
memset(entry, 0x0, sizeof(struct entry)); GITERR_CHECK_ALLOC(entry);
if (off > UINT31_MAX) { if (off > UINT31_MAX) {
entry->offset = UINT32_MAX; entry->offset = UINT32_MAX;
entry->offset_long = off; entry->offset_long = off;
} else { } else {
entry->offset = off; entry->offset = (uint32_t)off;
} }
error = git_packfile_unpack(&obj, idx->pack, &off); error = git_packfile_unpack(&obj, idx->pack, &off);
...@@ -369,7 +369,7 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats) ...@@ -369,7 +369,7 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats)
git_oid_cpy(&entry->oid, &oid); git_oid_cpy(&entry->oid, &oid);
entry->crc = crc32(0L, Z_NULL, 0); entry->crc = crc32(0L, Z_NULL, 0);
entry_size = off - entry_start; entry_size = (size_t)(off - entry_start);
packed = git_mwindow_open(mwf, &w, entry_start, entry_size, &left); packed = git_mwindow_open(mwf, &w, entry_start, entry_size, &left);
if (packed == NULL) { if (packed == NULL) {
error = git__rethrow(error, "Failed to open window to read packed data"); error = git__rethrow(error, "Failed to open window to read packed data");
......
...@@ -31,6 +31,8 @@ typedef struct { /* memory mapped buffer */ ...@@ -31,6 +31,8 @@ typedef struct { /* memory mapped buffer */
#endif #endif
} git_map; } git_map;
extern int validate_map_args(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset);
extern int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset); extern int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset);
extern int p_munmap(git_map *map); extern int p_munmap(git_map *map);
......
...@@ -178,8 +178,10 @@ static git_mwindow *new_window( ...@@ -178,8 +178,10 @@ static git_mwindow *new_window(
* window. * window.
*/ */
if (git_futils_mmap_ro(&w->window_map, fd, w->offset, (size_t)len) < GIT_SUCCESS) if (git_futils_mmap_ro(&w->window_map, fd, w->offset, (size_t)len) < 0) {
goto cleanup; git__free(w);
return NULL;
}
ctl->mmap_calls++; ctl->mmap_calls++;
ctl->open_windows++; ctl->open_windows++;
...@@ -191,10 +193,6 @@ static git_mwindow *new_window( ...@@ -191,10 +193,6 @@ static git_mwindow *new_window(
ctl->peak_open_windows = ctl->open_windows; ctl->peak_open_windows = ctl->open_windows;
return w; return w;
cleanup:
git__free(w);
return NULL;
} }
/* /*
...@@ -253,11 +251,10 @@ unsigned char *git_mwindow_open( ...@@ -253,11 +251,10 @@ unsigned char *git_mwindow_open(
int git_mwindow_file_register(git_mwindow_file *mwf) int git_mwindow_file_register(git_mwindow_file *mwf)
{ {
git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl; git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
int error;
if (ctl->windowfiles.length == 0 && if (ctl->windowfiles.length == 0 &&
(error = git_vector_init(&ctl->windowfiles, 8, NULL)) < GIT_SUCCESS) git_vector_init(&ctl->windowfiles, 8, NULL) < 0)
return error; return -1;
return git_vector_insert(&ctl->windowfiles, mwf); return git_vector_insert(&ctl->windowfiles, mwf);
} }
......
...@@ -92,7 +92,7 @@ int git_object_lookup_prefix( ...@@ -92,7 +92,7 @@ int git_object_lookup_prefix(
assert(repo && object_out && id); assert(repo && object_out && id);
if (len < GIT_OID_MINPREFIXLEN) if (len < GIT_OID_MINPREFIXLEN)
return git__throw(GIT_EAMBIGUOUSOIDPREFIX, return git__throw(GIT_EAMBIGUOUS,
"Failed to lookup object. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN); "Failed to lookup object. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN);
error = git_repository_odb__weakptr(&odb, repo); error = git_repository_odb__weakptr(&odb, repo);
......
...@@ -188,7 +188,7 @@ int git_odb_hashfile(git_oid *out, const char *path, git_otype type) ...@@ -188,7 +188,7 @@ int git_odb_hashfile(git_oid *out, const char *path, git_otype type)
git_off_t size; git_off_t size;
int result, fd = git_futils_open_ro(path); int result, fd = git_futils_open_ro(path);
if (fd < 0) if (fd < 0)
return -1; return fd;
if ((size = git_futils_filesize(fd)) < 0 || !git__is_sizet(size)) { if ((size = git_futils_filesize(fd)) < 0 || !git__is_sizet(size)) {
giterr_set(GITERR_OS, "File size overflow for 32-bit systems"); giterr_set(GITERR_OS, "File size overflow for 32-bit systems");
...@@ -507,23 +507,20 @@ int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git ...@@ -507,23 +507,20 @@ int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git
error = b->read_header(len_p, type_p, b, id); error = b->read_header(len_p, type_p, b, id);
} }
if (error == GIT_EPASSTHROUGH) if (!error || error == GIT_EPASSTHROUGH)
return 0; return 0;
/* /*
* no backend could read only the header. * no backend could read only the header.
* try reading the whole object and freeing the contents * try reading the whole object and freeing the contents
*/ */
if (error < 0) { if ((error = git_odb_read(&object, db, id)) < 0)
if ((error = git_odb_read(&object, db, id)) < GIT_SUCCESS) return error; /* error already set - pass along */
return error; /* error already set - pass through */
*len_p = object->raw.len; *len_p = object->raw.len;
*type_p = object->raw.type; *type_p = object->raw.type;
git_odb_object_free(object); git_odb_object_free(object);
} return 0;
return GIT_SUCCESS;
} }
int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
...@@ -536,7 +533,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) ...@@ -536,7 +533,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
*out = git_cache_get(&db->cache, id); *out = git_cache_get(&db->cache, id);
if (*out != NULL) if (*out != NULL)
return GIT_SUCCESS; return 0;
for (i = 0; i < db->backends.length && error < 0; ++i) { for (i = 0; i < db->backends.length && error < 0; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i); backend_internal *internal = git_vector_get(&db->backends, i);
...@@ -546,15 +543,15 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) ...@@ -546,15 +543,15 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
error = b->read(&raw.data, &raw.len, &raw.type, b, id); error = b->read(&raw.data, &raw.len, &raw.type, b, id);
} }
if (error == GIT_EPASSTHROUGH || error == GIT_SUCCESS) { if (error && error != GIT_EPASSTHROUGH)
*out = git_cache_try_store(&db->cache, new_odb_object(id, &raw)); return error;
return GIT_SUCCESS;
}
return git__rethrow(error, "Failed to read object"); *out = git_cache_try_store(&db->cache, new_odb_object(id, &raw));
return 0;
} }
int git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_id, unsigned int len) int git_odb_read_prefix(
git_odb_object **out, git_odb *db, const git_oid *short_id, unsigned int len)
{ {
unsigned int i; unsigned int i;
int error = GIT_ENOTFOUND; int error = GIT_ENOTFOUND;
...@@ -565,7 +562,7 @@ int git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_ ...@@ -565,7 +562,7 @@ int git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_
assert(out && db); assert(out && db);
if (len < GIT_OID_MINPREFIXLEN) if (len < GIT_OID_MINPREFIXLEN)
return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to lookup object. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN); return git_odb__error_ambiguous("prefix length too short");
if (len > GIT_OID_HEXSZ) if (len > GIT_OID_HEXSZ)
len = GIT_OID_HEXSZ; len = GIT_OID_HEXSZ;
...@@ -573,7 +570,7 @@ int git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_ ...@@ -573,7 +570,7 @@ int git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_
if (len == GIT_OID_HEXSZ) { if (len == GIT_OID_HEXSZ) {
*out = git_cache_get(&db->cache, short_id); *out = git_cache_get(&db->cache, short_id);
if (*out != NULL) if (*out != NULL)
return GIT_SUCCESS; return 0;
} }
for (i = 0; i < db->backends.length && found < 2; ++i) { for (i = 0; i < db->backends.length && found < 2; ++i) {
...@@ -582,33 +579,24 @@ int git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_ ...@@ -582,33 +579,24 @@ int git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_
if (b->read != NULL) { if (b->read != NULL) {
error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, short_id, len); error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, short_id, len);
switch (error) { if (!error)
case GIT_SUCCESS:
found++; found++;
break; else if (error != GIT_ENOTFOUND && error != GIT_EPASSTHROUGH)
case GIT_ENOTFOUND: return error;
case GIT_EPASSTHROUGH:
break;
case GIT_EAMBIGUOUSOIDPREFIX:
return git__rethrow(error, "Failed to read object. Ambiguous sha1 prefix");
default:
return git__rethrow(error, "Failed to read object");
}
} }
} }
if (found == 1) { if (found == 0)
*out = git_cache_try_store(&db->cache, new_odb_object(&full_oid, &raw)); return git_odb__error_notfound("no match for prefix");
} else if (found > 1) { if (found > 1)
return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to read object. Ambiguous sha1 prefix"); return git_odb__error_ambiguous("multiple matches for prefix");
} else {
return git__throw(GIT_ENOTFOUND, "Failed to read object. Object not found");
}
return GIT_SUCCESS; *out = git_cache_try_store(&db->cache, new_odb_object(&full_oid, &raw));
return 0;
} }
int git_odb_write(git_oid *oid, git_odb *db, const void *data, size_t len, git_otype type) int git_odb_write(
git_oid *oid, git_odb *db, const void *data, size_t len, git_otype type)
{ {
unsigned int i; unsigned int i;
int error = GIT_ERROR; int error = GIT_ERROR;
...@@ -628,24 +616,25 @@ int git_odb_write(git_oid *oid, git_odb *db, const void *data, size_t len, git_o ...@@ -628,24 +616,25 @@ int git_odb_write(git_oid *oid, git_odb *db, const void *data, size_t len, git_o
error = b->write(oid, b, data, len, type); error = b->write(oid, b, data, len, type);
} }
if (error == GIT_EPASSTHROUGH || error == GIT_SUCCESS) if (!error || error == GIT_EPASSTHROUGH)
return GIT_SUCCESS; return 0;
/* if no backends were able to write the object directly, we try a streaming /* if no backends were able to write the object directly, we try a streaming
* write to the backends; just write the whole object into the stream in one * write to the backends; just write the whole object into the stream in one
* push */ * push */
if ((error = git_odb_open_wstream(&stream, db, len, type)) == GIT_SUCCESS) { if ((error = git_odb_open_wstream(&stream, db, len, type)) != 0)
return error;
stream->write(stream, data, len); stream->write(stream, data, len);
error = stream->finalize_write(oid, stream); error = stream->finalize_write(oid, stream);
stream->free(stream); stream->free(stream);
return GIT_SUCCESS;
}
return git__rethrow(error, "Failed to write object"); return error;
} }
int git_odb_open_wstream(git_odb_stream **stream, git_odb *db, size_t size, git_otype type) int git_odb_open_wstream(
git_odb_stream **stream, git_odb *db, size_t size, git_otype type)
{ {
unsigned int i; unsigned int i;
int error = GIT_ERROR; int error = GIT_ERROR;
...@@ -666,10 +655,10 @@ int git_odb_open_wstream(git_odb_stream **stream, git_odb *db, size_t size, git_ ...@@ -666,10 +655,10 @@ int git_odb_open_wstream(git_odb_stream **stream, git_odb *db, size_t size, git_
error = init_fake_wstream(stream, b, size, type); error = init_fake_wstream(stream, b, size, type);
} }
if (error == GIT_EPASSTHROUGH || error == GIT_SUCCESS) if (error == GIT_EPASSTHROUGH)
return GIT_SUCCESS; error = 0;
return git__rethrow(error, "Failed to open write stream"); return error;
} }
int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oid) int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oid)
...@@ -687,9 +676,21 @@ int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oi ...@@ -687,9 +676,21 @@ int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oi
error = b->readstream(stream, b, oid); error = b->readstream(stream, b, oid);
} }
if (error == GIT_EPASSTHROUGH || error == GIT_SUCCESS) if (error == GIT_EPASSTHROUGH)
return GIT_SUCCESS; error = 0;
return error;
}
return git__rethrow(error, "Failed to open read stream"); int git_odb__error_notfound(const char *message)
{
giterr_set(GITERR_ODB, "Object not found - %s", message);
return GIT_ENOTFOUND;
}
int git_odb__error_ambiguous(const char *message)
{
giterr_set(GITERR_ODB, "Ambiguous SHA1 prefix - %s", message);
return GIT_EAMBIGUOUS;
} }
...@@ -67,4 +67,14 @@ int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type); ...@@ -67,4 +67,14 @@ int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type);
*/ */
int git_odb__hashlink(git_oid *out, const char *path); int git_odb__hashlink(git_oid *out, const char *path);
/*
* Generate a GIT_ENOTFOUND error for the ODB.
*/
int git_odb__error_notfound(const char *message);
/*
* Generate a GIT_EAMBIGUOUS error for the ODB.
*/
int git_odb__error_ambiguous(const char *message);
#endif #endif
...@@ -61,8 +61,8 @@ static int object_file_name(git_buf *name, const char *dir, const git_oid *id) ...@@ -61,8 +61,8 @@ static int object_file_name(git_buf *name, const char *dir, const git_oid *id)
git_buf_sets(name, dir); git_buf_sets(name, dir);
/* expand length for 40 hex sha1 chars + 2 * '/' + '\0' */ /* expand length for 40 hex sha1 chars + 2 * '/' + '\0' */
if (git_buf_grow(name, name->size + GIT_OID_HEXSZ + 3) < GIT_SUCCESS) if (git_buf_grow(name, name->size + GIT_OID_HEXSZ + 3) < 0)
return GIT_ENOMEM; return -1;
git_path_to_dir(name); git_path_to_dir(name);
...@@ -71,7 +71,7 @@ static int object_file_name(git_buf *name, const char *dir, const git_oid *id) ...@@ -71,7 +71,7 @@ static int object_file_name(git_buf *name, const char *dir, const git_oid *id)
name->size += GIT_OID_HEXSZ + 1; name->size += GIT_OID_HEXSZ + 1;
name->ptr[name->size] = '\0'; name->ptr[name->size] = '\0';
return GIT_SUCCESS; return 0;
} }
...@@ -199,10 +199,12 @@ static int finish_inflate(z_stream *s) ...@@ -199,10 +199,12 @@ static int finish_inflate(z_stream *s)
inflateEnd(s); inflateEnd(s);
if ((status != Z_STREAM_END) || (s->avail_in != 0)) if ((status != Z_STREAM_END) || (s->avail_in != 0)) {
return git__throw(GIT_ERROR, "Failed to finish inflation. Stream aborted prematurely"); giterr_set(GITERR_ZLIB, "Failed to finish ZLib inflation. Stream aborted prematurely");
return -1;
}
return GIT_SUCCESS; return 0;
} }
static int is_zlib_compressed_data(unsigned char *data) static int is_zlib_compressed_data(unsigned char *data)
...@@ -226,21 +228,24 @@ static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen) ...@@ -226,21 +228,24 @@ static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
zs.next_in = in; zs.next_in = in;
zs.avail_in = (uInt)inlen; zs.avail_in = (uInt)inlen;
if (inflateInit(&zs) < Z_OK) if (inflateInit(&zs) < Z_OK) {
return git__throw(GIT_ERROR, "Failed to inflate buffer"); giterr_set(GITERR_ZLIB, "Failed to inflate buffer");
return -1;
}
while (status == Z_OK) while (status == Z_OK)
status = inflate(&zs, Z_FINISH); status = inflate(&zs, Z_FINISH);
inflateEnd(&zs); inflateEnd(&zs);
if ((status != Z_STREAM_END) /*|| (zs.avail_in != 0) */) if (status != Z_STREAM_END /* || zs.avail_in != 0 */ ||
return git__throw(GIT_ERROR, "Failed to inflate buffer. Stream aborted prematurely"); zs.total_out != outlen)
{
if (zs.total_out != outlen) giterr_set(GITERR_ZLIB, "Failed to inflate buffer. Stream aborted prematurely");
return git__throw(GIT_ERROR, "Failed to inflate buffer. Stream aborted prematurely"); return -1;
}
return GIT_SUCCESS; return 0;
} }
static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr) static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr)
...@@ -297,24 +302,23 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_buf *obj) ...@@ -297,24 +302,23 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_buf *obj)
* read the object header, which is an (uncompressed) * read the object header, which is an (uncompressed)
* binary encoding of the object type and size. * binary encoding of the object type and size.
*/ */
if ((used = get_binary_object_header(&hdr, obj)) == 0) if ((used = get_binary_object_header(&hdr, obj)) == 0 ||
return git__throw(GIT_ERROR, "Failed to inflate loose object. Object has no header"); !git_object_typeisloose(hdr.type)) {
giterr_set(GITERR_ODB, "Failed to inflate loose object.");
if (!git_object_typeisloose(hdr.type)) return -1;
return git__throw(GIT_ERROR, "Failed to inflate loose object. Wrong object type"); }
/* /*
* allocate a buffer and inflate the data into it * allocate a buffer and inflate the data into it
*/ */
buf = git__malloc(hdr.size + 1); buf = git__malloc(hdr.size + 1);
if (!buf) GITERR_CHECK_ALLOC(buf);
return GIT_ENOMEM;
in = ((unsigned char *)obj->ptr) + used; in = ((unsigned char *)obj->ptr) + used;
len = obj->size - used; len = obj->size - used;
if (inflate_buffer(in, len, buf, hdr.size)) { if (inflate_buffer(in, len, buf, hdr.size) < 0) {
git__free(buf); git__free(buf);
return git__throw(GIT_ERROR, "Failed to inflate loose object. Could not inflate buffer"); return -1;
} }
buf[hdr.size] = '\0'; buf[hdr.size] = '\0';
...@@ -322,7 +326,7 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_buf *obj) ...@@ -322,7 +326,7 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_buf *obj)
out->len = hdr.size; out->len = hdr.size;
out->type = hdr.type; out->type = hdr.type;
return GIT_SUCCESS; return 0;
} }
static int inflate_disk_obj(git_rawobj *out, git_buf *obj) static int inflate_disk_obj(git_rawobj *out, git_buf *obj)
...@@ -342,28 +346,27 @@ static int inflate_disk_obj(git_rawobj *out, git_buf *obj) ...@@ -342,28 +346,27 @@ static int inflate_disk_obj(git_rawobj *out, git_buf *obj)
* inflate the initial part of the io buffer in order * inflate the initial part of the io buffer in order
* to parse the object header (type and size). * to parse the object header (type and size).
*/ */
if (start_inflate(&zs, obj, head, sizeof(head)) < Z_OK) if (start_inflate(&zs, obj, head, sizeof(head)) < Z_OK ||
return git__throw(GIT_ERROR, "Failed to inflate disk object. Could not inflate buffer"); (used = get_object_header(&hdr, head)) == 0 ||
!git_object_typeisloose(hdr.type))
if ((used = get_object_header(&hdr, head)) == 0) {
return git__throw(GIT_ERROR, "Failed to inflate disk object. Object has no header"); giterr_set(GITERR_ODB, "Failed to inflate disk object.");
return -1;
if (!git_object_typeisloose(hdr.type)) }
return git__throw(GIT_ERROR, "Failed to inflate disk object. Wrong object type");
/* /*
* allocate a buffer and inflate the object data into it * allocate a buffer and inflate the object data into it
* (including the initial sequence in the head buffer). * (including the initial sequence in the head buffer).
*/ */
if ((buf = inflate_tail(&zs, head, used, &hdr)) == NULL) if ((buf = inflate_tail(&zs, head, used, &hdr)) == NULL)
return GIT_ENOMEM; return -1;
buf[hdr.size] = '\0'; buf[hdr.size] = '\0';
out->data = buf; out->data = buf;
out->len = hdr.size; out->len = hdr.size;
out->type = hdr.type; out->type = hdr.type;
return GIT_SUCCESS; return 0;
} }
...@@ -388,24 +391,23 @@ static int read_loose(git_rawobj *out, git_buf *loc) ...@@ -388,24 +391,23 @@ static int read_loose(git_rawobj *out, git_buf *loc)
assert(out && loc); assert(out && loc);
if (git_buf_oom(loc)) if (git_buf_oom(loc))
return GIT_ENOMEM; return -1;
out->data = NULL; out->data = NULL;
out->len = 0; out->len = 0;
out->type = GIT_OBJ_BAD; out->type = GIT_OBJ_BAD;
if (git_futils_readbuffer(&obj, loc->ptr) < 0) if (!(error = git_futils_readbuffer(&obj, loc->ptr)))
return git__throw(GIT_ENOTFOUND, "Failed to read loose object. File not found");
error = inflate_disk_obj(out, &obj); error = inflate_disk_obj(out, &obj);
git_buf_free(&obj); git_buf_free(&obj);
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to read loose object"); return error;
} }
static int read_header_loose(git_rawobj *out, git_buf *loc) static int read_header_loose(git_rawobj *out, git_buf *loc)
{ {
int error = GIT_SUCCESS, z_return = Z_ERRNO, read_bytes; int error = 0, z_return = Z_ERRNO, read_bytes;
git_file fd; git_file fd;
z_stream zs; z_stream zs;
obj_hdr header_obj; obj_hdr header_obj;
...@@ -414,48 +416,40 @@ static int read_header_loose(git_rawobj *out, git_buf *loc) ...@@ -414,48 +416,40 @@ static int read_header_loose(git_rawobj *out, git_buf *loc)
assert(out && loc); assert(out && loc);
if (git_buf_oom(loc)) if (git_buf_oom(loc))
return GIT_ENOMEM; return -1;
out->data = NULL; out->data = NULL;
if ((fd = p_open(loc->ptr, O_RDONLY)) < 0) if ((fd = git_futils_open_ro(loc->ptr)) < 0)
return git__throw(GIT_ENOTFOUND, "Failed to read loose object header. File not found"); return fd;
init_stream(&zs, inflated_buffer, sizeof(inflated_buffer)); init_stream(&zs, inflated_buffer, sizeof(inflated_buffer));
if (inflateInit(&zs) < Z_OK) { z_return = inflateInit(&zs);
error = GIT_EZLIB;
goto cleanup;
}
do { while (z_return == Z_OK) {
if ((read_bytes = read(fd, raw_buffer, sizeof(raw_buffer))) > 0) { if ((read_bytes = p_read(fd, raw_buffer, sizeof(raw_buffer))) > 0) {
set_stream_input(&zs, raw_buffer, read_bytes); set_stream_input(&zs, raw_buffer, read_bytes);
z_return = inflate(&zs, 0); z_return = inflate(&zs, 0);
} else { } else
z_return = Z_STREAM_END; z_return = Z_STREAM_END;
break;
} }
} while (z_return == Z_OK);
if ((z_return != Z_STREAM_END && z_return != Z_BUF_ERROR) if ((z_return != Z_STREAM_END && z_return != Z_BUF_ERROR)
|| get_object_header(&header_obj, inflated_buffer) == 0 || get_object_header(&header_obj, inflated_buffer) == 0
|| git_object_typeisloose(header_obj.type) == 0) { || git_object_typeisloose(header_obj.type) == 0)
error = GIT_EOBJCORRUPTED; {
goto cleanup; giterr_set(GITERR_ZLIB, "Failed to read loose object header");
} error = -1;
} else {
out->len = header_obj.size; out->len = header_obj.size;
out->type = header_obj.type; out->type = header_obj.type;
}
cleanup:
finish_inflate(&zs); finish_inflate(&zs);
p_close(fd); p_close(fd);
if (error < GIT_SUCCESS) return error;
return git__throw(error, "Failed to read loose object header. Header is corrupted");
return GIT_SUCCESS;
} }
static int locate_object( static int locate_object(
...@@ -465,8 +459,8 @@ static int locate_object( ...@@ -465,8 +459,8 @@ static int locate_object(
{ {
int error = object_file_name(object_location, backend->objects_dir, oid); int error = object_file_name(object_location, backend->objects_dir, oid);
if (error == GIT_SUCCESS) if (!error && !git_path_exists(object_location->ptr))
error = git_path_exists(git_buf_cstr(object_location)) ? GIT_SUCCESS : GIT_ENOTFOUND; return GIT_ENOTFOUND;
return error; return error;
} }
...@@ -477,7 +471,7 @@ static int fn_locate_object_short_oid(void *state, git_buf *pathbuf) { ...@@ -477,7 +471,7 @@ static int fn_locate_object_short_oid(void *state, git_buf *pathbuf) {
if (pathbuf->size - sstate->dir_len != GIT_OID_HEXSZ - 2) { if (pathbuf->size - sstate->dir_len != GIT_OID_HEXSZ - 2) {
/* Entry cannot be an object. Continue to next entry */ /* Entry cannot be an object. Continue to next entry */
return GIT_SUCCESS; return 0;
} }
if (git_path_isdir(pathbuf->ptr) == false) { if (git_path_isdir(pathbuf->ptr) == false) {
...@@ -495,10 +489,11 @@ static int fn_locate_object_short_oid(void *state, git_buf *pathbuf) { ...@@ -495,10 +489,11 @@ static int fn_locate_object_short_oid(void *state, git_buf *pathbuf) {
sstate->found++; sstate->found++;
} }
} }
if (sstate->found > 1) if (sstate->found > 1)
return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Ambiguous sha1 prefix within loose objects"); return git_odb__error_ambiguous("multiple matches in loose objects");
return GIT_SUCCESS; return 0;
} }
/* Locate an object matching a given short oid */ /* Locate an object matching a given short oid */
...@@ -515,8 +510,8 @@ static int locate_object_short_oid( ...@@ -515,8 +510,8 @@ static int locate_object_short_oid(
int error; int error;
/* prealloc memory for OBJ_DIR/xx/ */ /* prealloc memory for OBJ_DIR/xx/ */
if ((error = git_buf_grow(object_location, dir_len + 5)) < GIT_SUCCESS) if (git_buf_grow(object_location, dir_len + 5) < 0)
return git__rethrow(error, "Failed to locate object from short oid"); return -1;
git_buf_sets(object_location, objects_dir); git_buf_sets(object_location, objects_dir);
git_path_to_dir(object_location); git_path_to_dir(object_location);
...@@ -528,46 +523,43 @@ static int locate_object_short_oid( ...@@ -528,46 +523,43 @@ static int locate_object_short_oid(
git_oid_fmt((char *)state.short_oid, short_oid); git_oid_fmt((char *)state.short_oid, short_oid);
/* Explore OBJ_DIR/xx/ where xx is the beginning of hex formatted short oid */ /* Explore OBJ_DIR/xx/ where xx is the beginning of hex formatted short oid */
error = git_buf_printf(object_location, "%.2s/", state.short_oid); if (git_buf_printf(object_location, "%.2s/", state.short_oid) < 0)
if (error < GIT_SUCCESS) return -1;
return git__rethrow(error, "Failed to locate object from short oid");
/* Check that directory exists */ /* Check that directory exists */
if (git_path_isdir(object_location->ptr) == false) if (git_path_isdir(object_location->ptr) == false)
return git__throw(GIT_ENOTFOUND, "Failed to locate object from short oid. Object not found"); return git_odb__error_notfound("failed to locate from short oid");
state.dir_len = object_location->size; state.dir_len = object_location->size;
state.short_oid_len = len; state.short_oid_len = len;
state.found = 0; state.found = 0;
/* Explore directory to find a unique object matching short_oid */ /* Explore directory to find a unique object matching short_oid */
error = git_path_direach(object_location, fn_locate_object_short_oid, &state); error = git_path_direach(
object_location, fn_locate_object_short_oid, &state);
if (error) if (error)
return git__rethrow(error, "Failed to locate object from short oid"); return error;
if (!state.found) { if (!state.found)
return git__throw(GIT_ENOTFOUND, "Failed to locate object from short oid. Object not found"); return git_odb__error_notfound("failed to locate from short oid");
}
/* Convert obtained hex formatted oid to raw */ /* Convert obtained hex formatted oid to raw */
error = git_oid_fromstr(res_oid, (char *)state.res_oid); error = git_oid_fromstr(res_oid, (char *)state.res_oid);
if (error) { if (error)
return git__rethrow(error, "Failed to locate object from short oid"); return error;
}
/* Update the location according to the oid obtained */ /* Update the location according to the oid obtained */
git_buf_truncate(object_location, dir_len); git_buf_truncate(object_location, dir_len);
error = git_buf_grow(object_location, dir_len + GIT_OID_HEXSZ + 2); if (git_buf_grow(object_location, dir_len + GIT_OID_HEXSZ + 2) < 0)
if (error) return -1;
return git__rethrow(error, "Failed to locate object from short oid");
git_oid_pathfmt(object_location->ptr + dir_len, res_oid); git_oid_pathfmt(object_location->ptr + dir_len, res_oid);
object_location->size += GIT_OID_HEXSZ + 1; object_location->size += GIT_OID_HEXSZ + 1;
object_location->ptr[object_location->size] = '\0'; object_location->ptr[object_location->size] = '\0';
return GIT_SUCCESS; return 0;
} }
...@@ -598,8 +590,8 @@ static int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_ ...@@ -598,8 +590,8 @@ static int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_
raw.type = GIT_OBJ_BAD; raw.type = GIT_OBJ_BAD;
if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) if (locate_object(&object_path, (loose_backend *)backend, oid) < 0)
error = git__throw(GIT_ENOTFOUND, "Failed to read loose backend header. Object not found"); error = git_odb__error_notfound("in loose backend");
else if ((error = read_header_loose(&raw, &object_path)) == GIT_SUCCESS) { else if ((error = read_header_loose(&raw, &object_path)) == 0) {
*len_p = raw.len; *len_p = raw.len;
*type_p = raw.type; *type_p = raw.type;
} }
...@@ -613,20 +605,17 @@ static int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p ...@@ -613,20 +605,17 @@ static int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p
{ {
git_buf object_path = GIT_BUF_INIT; git_buf object_path = GIT_BUF_INIT;
git_rawobj raw; git_rawobj raw;
int error = GIT_SUCCESS; int error = 0;
assert(backend && oid); assert(backend && oid);
if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) if (locate_object(&object_path, (loose_backend *)backend, oid) < 0)
error = git__throw(GIT_ENOTFOUND, "Failed to read loose backend. Object not found"); error = git_odb__error_notfound("in loose backend");
else if ((error = read_loose(&raw, &object_path)) == GIT_SUCCESS) { else if ((error = read_loose(&raw, &object_path)) == 0) {
*buffer_p = raw.data; *buffer_p = raw.data;
*len_p = raw.len; *len_p = raw.len;
*type_p = raw.type; *type_p = raw.type;
} }
else {
git__rethrow(error, "Failed to read loose backend");
}
git_buf_free(&object_path); git_buf_free(&object_path);
...@@ -642,16 +631,15 @@ static int loose_backend__read_prefix( ...@@ -642,16 +631,15 @@ static int loose_backend__read_prefix(
const git_oid *short_oid, const git_oid *short_oid,
unsigned int len) unsigned int len)
{ {
int error = GIT_SUCCESS; int error = 0;
if (len < GIT_OID_MINPREFIXLEN) if (len < GIT_OID_MINPREFIXLEN)
return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to read loose " error = git_odb__error_ambiguous("prefix length too short");
"backend. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN);
if (len >= GIT_OID_HEXSZ) { else if (len >= GIT_OID_HEXSZ) {
/* We can fall back to regular read method */ /* We can fall back to regular read method */
error = loose_backend__read(buffer_p, len_p, type_p, backend, short_oid); error = loose_backend__read(buffer_p, len_p, type_p, backend, short_oid);
if (error == GIT_SUCCESS) if (!error)
git_oid_cpy(out_oid, short_oid); git_oid_cpy(out_oid, short_oid);
} else { } else {
git_buf object_path = GIT_BUF_INIT; git_buf object_path = GIT_BUF_INIT;
...@@ -660,11 +648,9 @@ static int loose_backend__read_prefix( ...@@ -660,11 +648,9 @@ static int loose_backend__read_prefix(
assert(backend && short_oid); assert(backend && short_oid);
if ((error = locate_object_short_oid(&object_path, out_oid, if ((error = locate_object_short_oid(&object_path, out_oid,
(loose_backend *)backend, short_oid, len)) < 0) (loose_backend *)backend, short_oid, len)) == 0 &&
git__rethrow(error, "Failed to read loose backend"); (error = read_loose(&raw, &object_path)) == 0)
else if ((error = read_loose(&raw, &object_path)) < GIT_SUCCESS) {
git__rethrow(error, "Failed to read loose backend");
else {
*buffer_p = raw.data; *buffer_p = raw.data;
*len_p = raw.len; *len_p = raw.len;
*type_p = raw.type; *type_p = raw.type;
...@@ -687,47 +673,33 @@ static int loose_backend__exists(git_odb_backend *backend, const git_oid *oid) ...@@ -687,47 +673,33 @@ static int loose_backend__exists(git_odb_backend *backend, const git_oid *oid)
git_buf_free(&object_path); git_buf_free(&object_path);
return (error == GIT_SUCCESS); return !error;
} }
static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream) static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream)
{ {
loose_writestream *stream = (loose_writestream *)_stream; loose_writestream *stream = (loose_writestream *)_stream;
loose_backend *backend = (loose_backend *)_stream->backend; loose_backend *backend = (loose_backend *)_stream->backend;
int error;
git_buf final_path = GIT_BUF_INIT; git_buf final_path = GIT_BUF_INIT;
int error = 0;
if ((error = git_filebuf_hash(oid, &stream->fbuf)) < GIT_SUCCESS) if (git_filebuf_hash(oid, &stream->fbuf) < 0 ||
goto cleanup; object_file_name(&final_path, backend->objects_dir, oid) < 0 ||
git_futils_mkpath2file(final_path.ptr, GIT_OBJECT_DIR_MODE) < 0)
if ((error = object_file_name(&final_path, backend->objects_dir, oid)) < GIT_SUCCESS) error = -1;
goto cleanup;
if (git_buf_oom(&final_path))
return GIT_ENOMEM;
if ((error = git_futils_mkpath2file(final_path.ptr, GIT_OBJECT_DIR_MODE)) < GIT_SUCCESS)
goto cleanup;
/* /*
* Don't try to add an existing object to the repository. This * Don't try to add an existing object to the repository. This
* is what git does and allows us to sidestep the fact that * is what git does and allows us to sidestep the fact that
* we're not allowed to overwrite a read-only file on Windows. * we're not allowed to overwrite a read-only file on Windows.
*/ */
if (git_path_exists(final_path.ptr) == true) { else if (git_path_exists(final_path.ptr) == true)
git_filebuf_cleanup(&stream->fbuf); git_filebuf_cleanup(&stream->fbuf);
goto cleanup; else
} error = git_filebuf_commit_at(
&stream->fbuf, final_path.ptr, GIT_OBJECT_FILE_MODE);
error = git_filebuf_commit_at(&stream->fbuf, final_path.ptr, GIT_OBJECT_FILE_MODE);
cleanup:
git_buf_free(&final_path); git_buf_free(&final_path);
if (error < GIT_SUCCESS)
git__rethrow(error, "Failed to write loose backend");
return error; return error;
} }
...@@ -751,22 +723,18 @@ static int format_object_header(char *hdr, size_t n, size_t obj_len, git_otype o ...@@ -751,22 +723,18 @@ static int format_object_header(char *hdr, size_t n, size_t obj_len, git_otype o
int len = snprintf(hdr, n, "%s %"PRIuZ, type_str, obj_len); int len = snprintf(hdr, n, "%s %"PRIuZ, type_str, obj_len);
assert(len > 0); /* otherwise snprintf() is broken */ assert(len > 0); /* otherwise snprintf() is broken */
assert(((size_t) len) < n); /* otherwise the caller is broken! */ assert(((size_t)len) < n); /* otherwise the caller is broken! */
if (len < 0 || ((size_t) len) >= n)
return git__throw(GIT_ERROR, "Failed to format object header. Length is out of bounds");
return len+1; return len+1;
} }
static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_backend, size_t length, git_otype type) static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_backend, size_t length, git_otype type)
{ {
loose_backend *backend; loose_backend *backend;
loose_writestream *stream; loose_writestream *stream = NULL;
char hdr[64]; char hdr[64];
git_buf tmp_path = GIT_BUF_INIT; git_buf tmp_path = GIT_BUF_INIT;
int hdrlen; int hdrlen;
int error;
assert(_backend); assert(_backend);
...@@ -774,12 +742,9 @@ static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_ ...@@ -774,12 +742,9 @@ static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_
*stream_out = NULL; *stream_out = NULL;
hdrlen = format_object_header(hdr, sizeof(hdr), length, type); hdrlen = format_object_header(hdr, sizeof(hdr), length, type);
if (hdrlen < GIT_SUCCESS)
return git__throw(GIT_EOBJCORRUPTED, "Failed to create loose backend stream. Object is corrupted");
stream = git__calloc(1, sizeof(loose_writestream)); stream = git__calloc(1, sizeof(loose_writestream));
if (stream == NULL) GITERR_CHECK_ALLOC(stream);
return GIT_ENOMEM;
stream->stream.backend = _backend; stream->stream.backend = _backend;
stream->stream.read = NULL; /* read only */ stream->stream.read = NULL; /* read only */
...@@ -788,31 +753,21 @@ static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_ ...@@ -788,31 +753,21 @@ static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_
stream->stream.free = &loose_backend__stream_free; stream->stream.free = &loose_backend__stream_free;
stream->stream.mode = GIT_STREAM_WRONLY; stream->stream.mode = GIT_STREAM_WRONLY;
error = git_buf_joinpath(&tmp_path, backend->objects_dir, "tmp_object"); if (git_buf_joinpath(&tmp_path, backend->objects_dir, "tmp_object") < 0 ||
if (error < GIT_SUCCESS) git_filebuf_open(&stream->fbuf, tmp_path.ptr,
goto cleanup;
error = git_filebuf_open(&stream->fbuf, tmp_path.ptr,
GIT_FILEBUF_HASH_CONTENTS | GIT_FILEBUF_HASH_CONTENTS |
GIT_FILEBUF_TEMPORARY | GIT_FILEBUF_TEMPORARY |
(backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT)); (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT)) < 0 ||
if (error < GIT_SUCCESS) stream->stream.write((git_odb_stream *)stream, hdr, hdrlen) < 0)
goto cleanup; {
git_filebuf_cleanup(&stream->fbuf);
error = stream->stream.write((git_odb_stream *)stream, hdr, hdrlen); git__free(stream);
if (error < GIT_SUCCESS) stream = NULL;
goto cleanup; }
git_buf_free(&tmp_path); git_buf_free(&tmp_path);
*stream_out = (git_odb_stream *)stream; *stream_out = (git_odb_stream *)stream;
return GIT_SUCCESS;
cleanup: return !stream ? -1 : 0;
git_buf_free(&tmp_path);
git_filebuf_cleanup(&stream->fbuf);
git__free(stream);
return git__rethrow(error, "Failed to create loose backend stream");
} }
static int loose_backend__write(git_oid *oid, git_odb_backend *_backend, const void *data, size_t len, git_otype type) static int loose_backend__write(git_oid *oid, git_odb_backend *_backend, const void *data, size_t len, git_otype type)
...@@ -826,36 +781,26 @@ static int loose_backend__write(git_oid *oid, git_odb_backend *_backend, const v ...@@ -826,36 +781,26 @@ static int loose_backend__write(git_oid *oid, git_odb_backend *_backend, const v
backend = (loose_backend *)_backend; backend = (loose_backend *)_backend;
/* prepare the header for the file */ /* prepare the header for the file */
{
header_len = format_object_header(header, sizeof(header), len, type); header_len = format_object_header(header, sizeof(header), len, type);
if (header_len < GIT_SUCCESS)
return GIT_EOBJCORRUPTED;
}
error = git_buf_joinpath(&final_path, backend->objects_dir, "tmp_object");
if (error < GIT_SUCCESS)
goto cleanup;
error = git_filebuf_open(&fbuf, final_path.ptr, if (git_buf_joinpath(&final_path, backend->objects_dir, "tmp_object") < 0 ||
git_filebuf_open(&fbuf, final_path.ptr,
GIT_FILEBUF_HASH_CONTENTS | GIT_FILEBUF_HASH_CONTENTS |
GIT_FILEBUF_TEMPORARY | GIT_FILEBUF_TEMPORARY |
(backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT)); (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT)) < 0)
if (error < GIT_SUCCESS) {
error = -1;
goto cleanup; goto cleanup;
}
git_filebuf_write(&fbuf, header, header_len); git_filebuf_write(&fbuf, header, header_len);
git_filebuf_write(&fbuf, data, len); git_filebuf_write(&fbuf, data, len);
git_filebuf_hash(oid, &fbuf); git_filebuf_hash(oid, &fbuf);
error = object_file_name(&final_path, backend->objects_dir, oid); if (object_file_name(&final_path, backend->objects_dir, oid) < 0 ||
if (error < GIT_SUCCESS) git_futils_mkpath2file(final_path.ptr, GIT_OBJECT_DIR_MODE) < 0 ||
goto cleanup; git_filebuf_commit_at(&fbuf, final_path.ptr, GIT_OBJECT_FILE_MODE) < 0)
error = -1;
error = git_futils_mkpath2file(final_path.ptr, GIT_OBJECT_DIR_MODE);
if (error < GIT_SUCCESS)
goto cleanup;
error = git_filebuf_commit_at(&fbuf, final_path.ptr, GIT_OBJECT_FILE_MODE);
cleanup: cleanup:
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
...@@ -883,14 +828,10 @@ int git_odb_backend_loose( ...@@ -883,14 +828,10 @@ int git_odb_backend_loose(
loose_backend *backend; loose_backend *backend;
backend = git__calloc(1, sizeof(loose_backend)); backend = git__calloc(1, sizeof(loose_backend));
if (backend == NULL) GITERR_CHECK_ALLOC(backend);
return GIT_ENOMEM;
backend->objects_dir = git__strdup(objects_dir); backend->objects_dir = git__strdup(objects_dir);
if (backend->objects_dir == NULL) { GITERR_CHECK_ALLOC(backend->objects_dir);
git__free(backend);
return GIT_ENOMEM;
}
if (compression_level < 0) if (compression_level < 0)
compression_level = Z_BEST_SPEED; compression_level = Z_BEST_SPEED;
...@@ -907,5 +848,5 @@ int git_odb_backend_loose( ...@@ -907,5 +848,5 @@ int git_odb_backend_loose(
backend->parent.free = &loose_backend__free; backend->parent.free = &loose_backend__free;
*backend_out = (git_odb_backend *)backend; *backend_out = (git_odb_backend *)backend;
return GIT_SUCCESS; return 0;
} }
...@@ -141,12 +141,12 @@ static int pack_entry_find(struct git_pack_entry *e, ...@@ -141,12 +141,12 @@ static int pack_entry_find(struct git_pack_entry *e,
/* Can find the offset of an object given /* Can find the offset of an object given
* a prefix of an identifier. * a prefix of an identifier.
* Throws GIT_EAMBIGUOUSOIDPREFIX if short oid * Sets GIT_EAMBIGUOUS if short oid is ambiguous.
* is ambiguous.
* This method assumes that len is between * This method assumes that len is between
* GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ. * GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ.
*/ */
static int pack_entry_find_prefix(struct git_pack_entry *e, static int pack_entry_find_prefix(
struct git_pack_entry *e,
struct pack_backend *backend, struct pack_backend *backend,
const git_oid *short_oid, const git_oid *short_oid,
unsigned int len); unsigned int len);
...@@ -215,27 +215,22 @@ static int packfile_load__cb(void *_data, git_buf *path) ...@@ -215,27 +215,22 @@ static int packfile_load__cb(void *_data, git_buf *path)
size_t i; size_t i;
if (git__suffixcmp(path->ptr, ".idx") != 0) if (git__suffixcmp(path->ptr, ".idx") != 0)
return GIT_SUCCESS; /* not an index */ return 0; /* not an index */
for (i = 0; i < backend->packs.length; ++i) { for (i = 0; i < backend->packs.length; ++i) {
struct git_pack_file *p = git_vector_get(&backend->packs, i); struct git_pack_file *p = git_vector_get(&backend->packs, i);
if (memcmp(p->pack_name, path->ptr, path->size - strlen(".idx")) == 0) if (memcmp(p->pack_name, path->ptr, path->size - strlen(".idx")) == 0)
return GIT_SUCCESS; return 0;
} }
error = git_packfile_check(&pack, path->ptr); error = git_packfile_check(&pack, path->ptr);
if (error == GIT_ENOTFOUND) { if (error == GIT_ENOTFOUND)
/* ignore missing .pack file as git does */ /* ignore missing .pack file as git does */
return GIT_SUCCESS; return GIT_SUCCESS;
} else if (error < GIT_SUCCESS) else if (error < 0)
return git__rethrow(error, "Failed to load packfile"); return error;
if (git_vector_insert(&backend->packs, pack) < GIT_SUCCESS) {
git__free(pack);
return GIT_ENOMEM;
}
return GIT_SUCCESS; return git_vector_insert(&backend->packs, pack);
} }
static int packfile_refresh_all(struct pack_backend *backend) static int packfile_refresh_all(struct pack_backend *backend)
...@@ -244,10 +239,10 @@ static int packfile_refresh_all(struct pack_backend *backend) ...@@ -244,10 +239,10 @@ static int packfile_refresh_all(struct pack_backend *backend)
struct stat st; struct stat st;
if (backend->pack_folder == NULL) if (backend->pack_folder == NULL)
return GIT_SUCCESS; return 0;
if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode)) if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode))
return git__throw(GIT_ENOTFOUND, "Failed to refresh packfiles. Backend not found"); return git_odb__error_notfound("failed to refresh packfiles");
if (st.st_mtime != backend->pack_folder_mtime) { if (st.st_mtime != backend->pack_folder_mtime) {
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
...@@ -257,14 +252,15 @@ static int packfile_refresh_all(struct pack_backend *backend) ...@@ -257,14 +252,15 @@ static int packfile_refresh_all(struct pack_backend *backend)
error = git_path_direach(&path, packfile_load__cb, (void *)backend); error = git_path_direach(&path, packfile_load__cb, (void *)backend);
git_buf_free(&path); git_buf_free(&path);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to refresh packfiles"); if (error < 0)
return error;
git_vector_sort(&backend->packs); git_vector_sort(&backend->packs);
backend->pack_folder_mtime = st.st_mtime; backend->pack_folder_mtime = st.st_mtime;
} }
return GIT_SUCCESS; return 0;
} }
static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backend, const git_oid *oid) static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backend, const git_oid *oid)
...@@ -272,12 +268,12 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen ...@@ -272,12 +268,12 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen
int error; int error;
size_t i; size_t i;
if ((error = packfile_refresh_all(backend)) < GIT_SUCCESS) if ((error = packfile_refresh_all(backend)) < 0)
return git__rethrow(error, "Failed to find pack entry"); return error;
if (backend->last_found && if (backend->last_found &&
git_pack_entry_find(e, backend->last_found, oid, GIT_OID_HEXSZ) == GIT_SUCCESS) git_pack_entry_find(e, backend->last_found, oid, GIT_OID_HEXSZ) == 0)
return GIT_SUCCESS; return 0;
for (i = 0; i < backend->packs.length; ++i) { for (i = 0; i < backend->packs.length; ++i) {
struct git_pack_file *p; struct git_pack_file *p;
...@@ -286,13 +282,13 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen ...@@ -286,13 +282,13 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen
if (p == backend->last_found) if (p == backend->last_found)
continue; continue;
if (git_pack_entry_find(e, p, oid, GIT_OID_HEXSZ) == GIT_SUCCESS) { if (git_pack_entry_find(e, p, oid, GIT_OID_HEXSZ) == 0) {
backend->last_found = p; backend->last_found = p;
return GIT_SUCCESS; return 0;
} }
} }
return git__throw(GIT_ENOTFOUND, "Failed to find pack entry"); return git_odb__error_notfound("failed to find pack entry");
} }
static int pack_entry_find_prefix( static int pack_entry_find_prefix(
...@@ -305,17 +301,16 @@ static int pack_entry_find_prefix( ...@@ -305,17 +301,16 @@ static int pack_entry_find_prefix(
size_t i; size_t i;
unsigned found = 0; unsigned found = 0;
if ((error = packfile_refresh_all(backend)) < GIT_SUCCESS) if ((error = packfile_refresh_all(backend)) < 0)
return git__rethrow(error, "Failed to find pack entry"); return error;
if (backend->last_found) { if (backend->last_found) {
error = git_pack_entry_find(e, backend->last_found, short_oid, len); error = git_pack_entry_find(e, backend->last_found, short_oid, len);
if (error == GIT_EAMBIGUOUSOIDPREFIX) { if (error == GIT_EAMBIGUOUS)
return git__rethrow(error, "Failed to find pack entry. Ambiguous sha1 prefix"); return error;
} else if (error == GIT_SUCCESS) { if (!error)
found = 1; found = 1;
} }
}
for (i = 0; i < backend->packs.length; ++i) { for (i = 0; i < backend->packs.length; ++i) {
struct git_pack_file *p; struct git_pack_file *p;
...@@ -325,24 +320,21 @@ static int pack_entry_find_prefix( ...@@ -325,24 +320,21 @@ static int pack_entry_find_prefix(
continue; continue;
error = git_pack_entry_find(e, p, short_oid, len); error = git_pack_entry_find(e, p, short_oid, len);
if (error == GIT_EAMBIGUOUSOIDPREFIX) { if (error == GIT_EAMBIGUOUS)
return git__rethrow(error, "Failed to find pack entry. Ambiguous sha1 prefix"); return error;
} else if (error == GIT_SUCCESS) { if (!error) {
found++; if (++found > 1)
if (found > 1)
break; break;
backend->last_found = p; backend->last_found = p;
} }
} }
if (!found) { if (!found)
return git__rethrow(GIT_ENOTFOUND, "Failed to find pack entry"); return git_odb__error_notfound("failed to find pack entry");
} else if (found > 1) { else if (found > 1)
return git__rethrow(GIT_EAMBIGUOUSOIDPREFIX, "Failed to find pack entry. Ambiguous sha1 prefix"); return git_odb__error_ambiguous("found multiple pack entries");
} else { else
return GIT_SUCCESS; return 0;
}
} }
...@@ -374,17 +366,15 @@ static int pack_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, ...@@ -374,17 +366,15 @@ static int pack_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p,
git_rawobj raw; git_rawobj raw;
int error; int error;
if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < GIT_SUCCESS) if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < 0 ||
return git__rethrow(error, "Failed to read pack backend"); (error = git_packfile_unpack(&raw, e.p, &e.offset)) < 0)
return error;
if ((error = git_packfile_unpack(&raw, e.p, &e.offset)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to read pack backend");
*buffer_p = raw.data; *buffer_p = raw.data;
*len_p = raw.len; *len_p = raw.len;
*type_p = raw.type; *type_p = raw.type;
return GIT_SUCCESS; return 0;
} }
static int pack_backend__read_prefix( static int pack_backend__read_prefix(
...@@ -396,40 +386,38 @@ static int pack_backend__read_prefix( ...@@ -396,40 +386,38 @@ static int pack_backend__read_prefix(
const git_oid *short_oid, const git_oid *short_oid,
unsigned int len) unsigned int len)
{ {
int error = 0;
if (len < GIT_OID_MINPREFIXLEN) if (len < GIT_OID_MINPREFIXLEN)
return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to read pack backend. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN); error = git_odb__error_ambiguous("prefix length too short");
if (len >= GIT_OID_HEXSZ) { else if (len >= GIT_OID_HEXSZ) {
/* We can fall back to regular read method */ /* We can fall back to regular read method */
int error = pack_backend__read(buffer_p, len_p, type_p, backend, short_oid); error = pack_backend__read(buffer_p, len_p, type_p, backend, short_oid);
if (error == GIT_SUCCESS) if (!error)
git_oid_cpy(out_oid, short_oid); git_oid_cpy(out_oid, short_oid);
return error;
} else { } else {
struct git_pack_entry e; struct git_pack_entry e;
git_rawobj raw; git_rawobj raw;
int error;
if ((error = pack_entry_find_prefix(&e, (struct pack_backend *)backend, short_oid, len)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to read pack backend");
if ((error = git_packfile_unpack(&raw, e.p, &e.offset)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to read pack backend");
if ((error = pack_entry_find_prefix(
&e, (struct pack_backend *)backend, short_oid, len)) == 0 &&
(error = git_packfile_unpack(&raw, e.p, &e.offset)) == 0)
{
*buffer_p = raw.data; *buffer_p = raw.data;
*len_p = raw.len; *len_p = raw.len;
*type_p = raw.type; *type_p = raw.type;
git_oid_cpy(out_oid, &e.sha1); git_oid_cpy(out_oid, &e.sha1);
} }
}
return GIT_SUCCESS; return error;
} }
static int pack_backend__exists(git_odb_backend *backend, const git_oid *oid) static int pack_backend__exists(git_odb_backend *backend, const git_oid *oid)
{ {
struct git_pack_entry e; struct git_pack_entry e;
return pack_entry_find(&e, (struct pack_backend *)backend, oid) == GIT_SUCCESS; return pack_entry_find(&e, (struct pack_backend *)backend, oid) == 0;
} }
static void pack_backend__free(git_odb_backend *_backend) static void pack_backend__free(git_odb_backend *_backend)
...@@ -455,19 +443,16 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) ...@@ -455,19 +443,16 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
{ {
struct pack_backend *backend = NULL; struct pack_backend *backend = NULL;
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
int error = GIT_SUCCESS;
backend = git__calloc(1, sizeof(struct pack_backend)); backend = git__calloc(1, sizeof(struct pack_backend));
if (backend == NULL) GITERR_CHECK_ALLOC(backend);
return GIT_ENOMEM;
error = git_vector_init(&backend->packs, 8, packfile_sort__cb);
if (error < GIT_SUCCESS)
goto cleanup;
error = git_buf_joinpath(&path, objects_dir, "pack"); if (git_vector_init(&backend->packs, 8, packfile_sort__cb) < 0 ||
if (error < GIT_SUCCESS) git_buf_joinpath(&path, objects_dir, "pack") < 0)
goto cleanup; {
git__free(backend);
return -1;
}
if (git_path_isdir(git_buf_cstr(&path)) == true) { if (git_path_isdir(git_buf_cstr(&path)) == true) {
backend->pack_folder = git_buf_detach(&path); backend->pack_folder = git_buf_detach(&path);
...@@ -482,10 +467,7 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) ...@@ -482,10 +467,7 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
*backend_out = (git_odb_backend *)backend; *backend_out = (git_odb_backend *)backend;
cleanup:
if (error < GIT_SUCCESS)
git__free(backend);
git_buf_free(&path); git_buf_free(&path);
return error; return 0;
} }
...@@ -17,12 +17,12 @@ ...@@ -17,12 +17,12 @@
#include <zlib.h> #include <zlib.h>
static int packfile_open(struct git_pack_file *p); static int packfile_open(struct git_pack_file *p);
static off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n); static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n);
int packfile_unpack_compressed( int packfile_unpack_compressed(
git_rawobj *obj, git_rawobj *obj,
struct git_pack_file *p, struct git_pack_file *p,
git_mwindow **w_curs, git_mwindow **w_curs,
off_t *curpos, git_off_t *curpos,
size_t size, size_t size,
git_otype type); git_otype type);
...@@ -34,12 +34,18 @@ int packfile_unpack_compressed( ...@@ -34,12 +34,18 @@ int packfile_unpack_compressed(
* GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ. * GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ.
*/ */
static int pack_entry_find_offset( static int pack_entry_find_offset(
off_t *offset_out, git_off_t *offset_out,
git_oid *found_oid, git_oid *found_oid,
struct git_pack_file *p, struct git_pack_file *p,
const git_oid *short_oid, const git_oid *short_oid,
unsigned int len); unsigned int len);
static int packfile_error(const char *message)
{
giterr_set(GITERR_ODB, "Invalid pack file - %s", message);
return -1;
}
/*********************************************************** /***********************************************************
* *
* PACK INDEX METHODS * PACK INDEX METHODS
...@@ -58,40 +64,31 @@ static int pack_index_check(const char *path, struct git_pack_file *p) ...@@ -58,40 +64,31 @@ static int pack_index_check(const char *path, struct git_pack_file *p)
{ {
struct git_pack_idx_header *hdr; struct git_pack_idx_header *hdr;
uint32_t version, nr, i, *index; uint32_t version, nr, i, *index;
void *idx_map; void *idx_map;
size_t idx_size; size_t idx_size;
struct stat st; struct stat st;
/* TODO: properly open the file without access time */
git_file fd = p_open(path, O_RDONLY /*| O_NOATIME */);
int error; int error;
/* TODO: properly open the file without access time using O_NOATIME */
git_file fd = git_futils_open_ro(path);
if (fd < 0) if (fd < 0)
return git__throw(GIT_EOSERR, "Failed to check index. File missing or corrupted"); return fd;
if (p_fstat(fd, &st) < GIT_SUCCESS) {
p_close(fd);
return git__throw(GIT_EOSERR, "Failed to check index. File appears to be corrupted");
}
if (!git__is_sizet(st.st_size))
return GIT_ENOMEM;
idx_size = (size_t)st.st_size; if (p_fstat(fd, &st) < 0 ||
!S_ISREG(st.st_mode) ||
if (idx_size < 4 * 256 + 20 + 20) { !git__is_sizet(st.st_size) ||
(idx_size = (size_t)st.st_size) < 4 * 256 + 20 + 20)
{
p_close(fd); p_close(fd);
return git__throw(GIT_EOBJCORRUPTED, "Failed to check index. Object is corrupted"); giterr_set(GITERR_OS, "Failed to check pack index.");
return -1;
} }
error = git_futils_mmap_ro(&p->index_map, fd, 0, idx_size); error = git_futils_mmap_ro(&p->index_map, fd, 0, idx_size);
p_close(fd); p_close(fd);
if (error < GIT_SUCCESS) if (error < 0)
return git__rethrow(error, "Failed to check index"); return error;
hdr = idx_map = p->index_map.data; hdr = idx_map = p->index_map.data;
...@@ -100,7 +97,7 @@ static int pack_index_check(const char *path, struct git_pack_file *p) ...@@ -100,7 +97,7 @@ static int pack_index_check(const char *path, struct git_pack_file *p)
if (version < 2 || version > 2) { if (version < 2 || version > 2) {
git_futils_mmap_free(&p->index_map); git_futils_mmap_free(&p->index_map);
return git__throw(GIT_EOBJCORRUPTED, "Failed to check index. Unsupported index version"); return packfile_error("unsupported index version");
} }
} else } else
...@@ -116,7 +113,7 @@ static int pack_index_check(const char *path, struct git_pack_file *p) ...@@ -116,7 +113,7 @@ static int pack_index_check(const char *path, struct git_pack_file *p)
uint32_t n = ntohl(index[i]); uint32_t n = ntohl(index[i]);
if (n < nr) { if (n < nr) {
git_futils_mmap_free(&p->index_map); git_futils_mmap_free(&p->index_map);
return git__throw(GIT_EOBJCORRUPTED, "Failed to check index. Index is non-monotonic"); return packfile_error("index is non-monotonic");
} }
nr = n; nr = n;
} }
...@@ -131,7 +128,7 @@ static int pack_index_check(const char *path, struct git_pack_file *p) ...@@ -131,7 +128,7 @@ static int pack_index_check(const char *path, struct git_pack_file *p)
*/ */
if (idx_size != 4*256 + nr * 24 + 20 + 20) { if (idx_size != 4*256 + nr * 24 + 20 + 20) {
git_futils_mmap_free(&p->index_map); git_futils_mmap_free(&p->index_map);
return git__throw(GIT_EOBJCORRUPTED, "Failed to check index. Object is corrupted"); return packfile_error("index is corrupted");
} }
} else if (version == 2) { } else if (version == 2) {
/* /*
...@@ -155,13 +152,13 @@ static int pack_index_check(const char *path, struct git_pack_file *p) ...@@ -155,13 +152,13 @@ static int pack_index_check(const char *path, struct git_pack_file *p)
if (idx_size < min_size || idx_size > max_size) { if (idx_size < min_size || idx_size > max_size) {
git_futils_mmap_free(&p->index_map); git_futils_mmap_free(&p->index_map);
return git__throw(GIT_EOBJCORRUPTED, "Failed to check index. Wrong index size"); return packfile_error("wrong index size");
} }
} }
p->index_version = version; p->index_version = version;
p->num_objects = nr; p->num_objects = nr;
return GIT_SUCCESS; return 0;
} }
static int pack_index_open(struct git_pack_file *p) static int pack_index_open(struct git_pack_file *p)
...@@ -170,24 +167,26 @@ static int pack_index_open(struct git_pack_file *p) ...@@ -170,24 +167,26 @@ static int pack_index_open(struct git_pack_file *p)
int error; int error;
if (p->index_map.data) if (p->index_map.data)
return GIT_SUCCESS; return 0;
idx_name = git__strdup(p->pack_name); idx_name = git__strdup(p->pack_name);
GITERR_CHECK_ALLOC(idx_name);
strcpy(idx_name + strlen(idx_name) - strlen(".pack"), ".idx"); strcpy(idx_name + strlen(idx_name) - strlen(".pack"), ".idx");
error = pack_index_check(idx_name, p); error = pack_index_check(idx_name, p);
git__free(idx_name); git__free(idx_name);
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to open index"); return error;
} }
static unsigned char *pack_window_open( static unsigned char *pack_window_open(
struct git_pack_file *p, struct git_pack_file *p,
git_mwindow **w_cursor, git_mwindow **w_cursor,
off_t offset, git_off_t offset,
unsigned int *left) unsigned int *left)
{ {
if (p->mwf.fd == -1 && packfile_open(p) < GIT_SUCCESS) if (p->mwf.fd == -1 && packfile_open(p) < 0)
return NULL; return NULL;
/* Since packfiles end in a hash of their content and it's /* Since packfiles end in a hash of their content and it's
...@@ -233,7 +232,7 @@ int git_packfile_unpack_header( ...@@ -233,7 +232,7 @@ int git_packfile_unpack_header(
git_otype *type_p, git_otype *type_p,
git_mwindow_file *mwf, git_mwindow_file *mwf,
git_mwindow **w_curs, git_mwindow **w_curs,
off_t *curpos) git_off_t *curpos)
{ {
unsigned char *base; unsigned char *base;
unsigned int left; unsigned int left;
...@@ -248,35 +247,34 @@ int git_packfile_unpack_header( ...@@ -248,35 +247,34 @@ int git_packfile_unpack_header(
// base = pack_window_open(p, w_curs, *curpos, &left); // base = pack_window_open(p, w_curs, *curpos, &left);
base = git_mwindow_open(mwf, w_curs, *curpos, 20, &left); base = git_mwindow_open(mwf, w_curs, *curpos, 20, &left);
if (base == NULL) if (base == NULL)
return GIT_ENOMEM; return -1;
used = packfile_unpack_header1(size_p, type_p, base, left); used = packfile_unpack_header1(size_p, type_p, base, left);
if (used == 0) if (used == 0)
return git__throw(GIT_EOBJCORRUPTED, "Header length is zero"); return packfile_error("header length is zero");
*curpos += used; *curpos += used;
return GIT_SUCCESS; return 0;
} }
static int packfile_unpack_delta( static int packfile_unpack_delta(
git_rawobj *obj, git_rawobj *obj,
struct git_pack_file *p, struct git_pack_file *p,
git_mwindow **w_curs, git_mwindow **w_curs,
off_t *curpos, git_off_t *curpos,
size_t delta_size, size_t delta_size,
git_otype delta_type, git_otype delta_type,
off_t obj_offset) git_off_t obj_offset)
{ {
off_t base_offset; git_off_t base_offset;
git_rawobj base, delta; git_rawobj base, delta;
int error; int error;
base_offset = get_delta_base(p, w_curs, curpos, delta_type, obj_offset); base_offset = get_delta_base(p, w_curs, curpos, delta_type, obj_offset);
if (base_offset == 0) if (base_offset == 0)
return git__throw(GIT_EOBJCORRUPTED, "Delta offset is zero"); return packfile_error("delta offset is zero");
if (base_offset < 0) if (base_offset < 0) /* must actually be an error code */
return git__rethrow(base_offset, "Failed to get delta base"); return (int)base_offset;
git_mwindow_close(w_curs); git_mwindow_close(w_curs);
error = git_packfile_unpack(&base, p, &base_offset); error = git_packfile_unpack(&base, p, &base_offset);
...@@ -287,35 +285,34 @@ static int packfile_unpack_delta( ...@@ -287,35 +285,34 @@ static int packfile_unpack_delta(
* *
* We'll need to do this in order to support thin packs. * We'll need to do this in order to support thin packs.
*/ */
if (error < GIT_SUCCESS) if (error < 0)
return git__rethrow(error, "Corrupted delta"); return error;
error = packfile_unpack_compressed(&delta, p, w_curs, curpos, delta_size, delta_type); error = packfile_unpack_compressed(&delta, p, w_curs, curpos, delta_size, delta_type);
if (error < GIT_SUCCESS) { if (error < 0) {
git__free(base.data); git__free(base.data);
return git__rethrow(error, "Corrupted delta"); return error;
} }
obj->type = base.type; obj->type = base.type;
error = git__delta_apply(obj, error = git__delta_apply(obj, base.data, base.len, delta.data, delta.len);
base.data, base.len,
delta.data, delta.len);
git__free(base.data); git__free(base.data);
git__free(delta.data); git__free(delta.data);
/* TODO: we might want to cache this shit. eventually */ /* TODO: we might want to cache this shit. eventually */
//add_delta_base_cache(p, base_offset, base, base_size, *type); //add_delta_base_cache(p, base_offset, base, base_size, *type);
return error; /* error set by git__delta_apply */ return error; /* error set by git__delta_apply */
} }
int git_packfile_unpack( int git_packfile_unpack(
git_rawobj *obj, git_rawobj *obj,
struct git_pack_file *p, struct git_pack_file *p,
off_t *obj_offset) git_off_t *obj_offset)
{ {
git_mwindow *w_curs = NULL; git_mwindow *w_curs = NULL;
off_t curpos = *obj_offset; git_off_t curpos = *obj_offset;
int error; int error;
size_t size = 0; size_t size = 0;
...@@ -330,8 +327,8 @@ int git_packfile_unpack( ...@@ -330,8 +327,8 @@ int git_packfile_unpack(
obj->type = GIT_OBJ_BAD; obj->type = GIT_OBJ_BAD;
error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos); error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos);
if (error < GIT_SUCCESS) if (error < 0)
return git__rethrow(error, "Failed to unpack packfile"); return error;
switch (type) { switch (type) {
case GIT_OBJ_OFS_DELTA: case GIT_OBJ_OFS_DELTA:
...@@ -351,24 +348,21 @@ int git_packfile_unpack( ...@@ -351,24 +348,21 @@ int git_packfile_unpack(
break; break;
default: default:
error = GIT_EOBJCORRUPTED; error = packfile_error("invalid packfile type in header");;
break; break;
} }
git_mwindow_close(&w_curs); git_mwindow_close(&w_curs);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to unpack object");
*obj_offset = curpos; *obj_offset = curpos;
return GIT_SUCCESS; return error;
} }
int packfile_unpack_compressed( int packfile_unpack_compressed(
git_rawobj *obj, git_rawobj *obj,
struct git_pack_file *p, struct git_pack_file *p,
git_mwindow **w_curs, git_mwindow **w_curs,
off_t *curpos, git_off_t *curpos,
size_t size, size_t size,
git_otype type) git_otype type)
{ {
...@@ -376,8 +370,8 @@ int packfile_unpack_compressed( ...@@ -376,8 +370,8 @@ int packfile_unpack_compressed(
z_stream stream; z_stream stream;
unsigned char *buffer, *in; unsigned char *buffer, *in;
buffer = git__malloc(size + 1); buffer = git__calloc(1, size + 1);
memset(buffer, 0x0, size + 1); GITERR_CHECK_ALLOC(buffer);
memset(&stream, 0, sizeof(stream)); memset(&stream, 0, sizeof(stream));
stream.next_out = buffer; stream.next_out = buffer;
...@@ -386,7 +380,8 @@ int packfile_unpack_compressed( ...@@ -386,7 +380,8 @@ int packfile_unpack_compressed(
st = inflateInit(&stream); st = inflateInit(&stream);
if (st != Z_OK) { if (st != Z_OK) {
git__free(buffer); git__free(buffer);
return git__throw(GIT_EZLIB, "Error in zlib"); giterr_set(GITERR_ZLIB, "Failed to inflate packfile");
return -1;
} }
do { do {
...@@ -404,28 +399,29 @@ int packfile_unpack_compressed( ...@@ -404,28 +399,29 @@ int packfile_unpack_compressed(
if ((st != Z_STREAM_END) || stream.total_out != size) { if ((st != Z_STREAM_END) || stream.total_out != size) {
git__free(buffer); git__free(buffer);
return git__throw(GIT_EZLIB, "Error in zlib"); giterr_set(GITERR_ZLIB, "Failed to inflate packfile");
return -1;
} }
obj->type = type; obj->type = type;
obj->len = size; obj->len = size;
obj->data = buffer; obj->data = buffer;
return GIT_SUCCESS; return 0;
} }
/* /*
* curpos is where the data starts, delta_obj_offset is the where the * curpos is where the data starts, delta_obj_offset is the where the
* header starts * header starts
*/ */
off_t get_delta_base( git_off_t get_delta_base(
struct git_pack_file *p, struct git_pack_file *p,
git_mwindow **w_curs, git_mwindow **w_curs,
off_t *curpos, git_off_t *curpos,
git_otype type, git_otype type,
off_t delta_obj_offset) git_off_t delta_obj_offset)
{ {
unsigned char *base_info = pack_window_open(p, w_curs, *curpos, NULL); unsigned char *base_info = pack_window_open(p, w_curs, *curpos, NULL);
off_t base_offset; git_off_t base_offset;
git_oid unused; git_oid unused;
/* pack_window_open() assured us we have [base_info, base_info + 20) /* pack_window_open() assured us we have [base_info, base_info + 20)
...@@ -463,8 +459,8 @@ off_t get_delta_base( ...@@ -463,8 +459,8 @@ off_t get_delta_base(
} }
} }
/* The base entry _must_ be in the same pack */ /* The base entry _must_ be in the same pack */
if (pack_entry_find_offset(&base_offset, &unused, p, (git_oid *)base_info, GIT_OID_HEXSZ) < GIT_SUCCESS) if (pack_entry_find_offset(&base_offset, &unused, p, (git_oid *)base_info, GIT_OID_HEXSZ) < 0)
return git__rethrow(GIT_EPACKCORRUPTED, "Base entry delta is not in the same pack"); return packfile_error("base entry delta is not in the same pack");
*curpos += 20; *curpos += 20;
} else } else
return 0; return 0;
...@@ -480,8 +476,8 @@ off_t get_delta_base( ...@@ -480,8 +476,8 @@ off_t get_delta_base(
static struct git_pack_file *packfile_alloc(int extra) static struct git_pack_file *packfile_alloc(int extra)
{ {
struct git_pack_file *p = git__malloc(sizeof(*p) + extra); struct git_pack_file *p = git__calloc(1, sizeof(*p) + extra);
memset(p, 0, sizeof(*p)); if (p != NULL)
p->mwf.fd = -1; p->mwf.fd = -1;
return p; return p;
} }
...@@ -510,24 +506,25 @@ static int packfile_open(struct git_pack_file *p) ...@@ -510,24 +506,25 @@ static int packfile_open(struct git_pack_file *p)
git_oid sha1; git_oid sha1;
unsigned char *idx_sha1; unsigned char *idx_sha1;
assert(p->index_map.data);
if (!p->index_map.data && pack_index_open(p) < GIT_SUCCESS) if (!p->index_map.data && pack_index_open(p) < GIT_SUCCESS)
return git__throw(GIT_ENOTFOUND, "Failed to open packfile. File not found"); return git_odb__error_notfound("failed to open packfile");
/* TODO: open with noatime */ /* TODO: open with noatime */
p->mwf.fd = p_open(p->pack_name, O_RDONLY); p->mwf.fd = git_futils_open_ro(p->pack_name);
if (p->mwf.fd < 0 || p_fstat(p->mwf.fd, &st) < GIT_SUCCESS) if (p->mwf.fd < 0)
return git__throw(GIT_EOSERR, "Failed to open packfile. File appears to be corrupted"); return p->mwf.fd;
if (git_mwindow_file_register(&p->mwf) < GIT_SUCCESS) { if (p_fstat(p->mwf.fd, &st) < 0 ||
p_close(p->mwf.fd); git_mwindow_file_register(&p->mwf) < 0)
return git__throw(GIT_ERROR, "Failed to register packfile windows"); goto cleanup;
}
/* If we created the struct before we had the pack we lack size. */ /* If we created the struct before we had the pack we lack size. */
if (!p->mwf.size) { if (!p->mwf.size) {
if (!S_ISREG(st.st_mode)) if (!S_ISREG(st.st_mode))
goto cleanup; goto cleanup;
p->mwf.size = (off_t)st.st_size; p->mwf.size = (git_off_t)st.st_size;
} else if (p->mwf.size != st.st_size) } else if (p->mwf.size != st.st_size)
goto cleanup; goto cleanup;
...@@ -537,44 +534,35 @@ static int packfile_open(struct git_pack_file *p) ...@@ -537,44 +534,35 @@ static int packfile_open(struct git_pack_file *p)
*/ */
fd_flag = fcntl(p->mwf.fd, F_GETFD, 0); fd_flag = fcntl(p->mwf.fd, F_GETFD, 0);
if (fd_flag < 0) if (fd_flag < 0)
return error("cannot determine file descriptor flags"); goto cleanup;
fd_flag |= FD_CLOEXEC; fd_flag |= FD_CLOEXEC;
if (fcntl(p->pack_fd, F_SETFD, fd_flag) == -1) if (fcntl(p->pack_fd, F_SETFD, fd_flag) == -1)
return GIT_EOSERR; goto cleanup;
#endif #endif
/* Verify we recognize this pack file format. */ /* Verify we recognize this pack file format. */
if (p_read(p->mwf.fd, &hdr, sizeof(hdr)) < GIT_SUCCESS) if (p_read(p->mwf.fd, &hdr, sizeof(hdr)) < 0 ||
goto cleanup; hdr.hdr_signature != htonl(PACK_SIGNATURE) ||
!pack_version_ok(hdr.hdr_version))
if (hdr.hdr_signature != htonl(PACK_SIGNATURE))
goto cleanup;
if (!pack_version_ok(hdr.hdr_version))
goto cleanup; goto cleanup;
/* Verify the pack matches its index. */ /* Verify the pack matches its index. */
if (p->num_objects != ntohl(hdr.hdr_entries)) if (p->num_objects != ntohl(hdr.hdr_entries) ||
goto cleanup; p_lseek(p->mwf.fd, p->mwf.size - GIT_OID_RAWSZ, SEEK_SET) == -1 ||
p_read(p->mwf.fd, sha1.id, GIT_OID_RAWSZ) < 0)
if (p_lseek(p->mwf.fd, p->mwf.size - GIT_OID_RAWSZ, SEEK_SET) == -1)
goto cleanup;
if (p_read(p->mwf.fd, sha1.id, GIT_OID_RAWSZ) < GIT_SUCCESS)
goto cleanup; goto cleanup;
idx_sha1 = ((unsigned char *)p->index_map.data) + p->index_map.len - 40; idx_sha1 = ((unsigned char *)p->index_map.data) + p->index_map.len - 40;
if (git_oid_cmp(&sha1, (git_oid *)idx_sha1) != 0) if (git_oid_cmp(&sha1, (git_oid *)idx_sha1) == 0)
goto cleanup; return 0;
return GIT_SUCCESS;
cleanup: cleanup:
giterr_set(GITERR_OS, "Invalid packfile '%s'", p->pack_name);
p_close(p->mwf.fd); p_close(p->mwf.fd);
p->mwf.fd = -1; p->mwf.fd = -1;
return git__throw(GIT_EPACKCORRUPTED, "Failed to open packfile. Pack is corrupted"); return -1;
} }
int git_packfile_check(struct git_pack_file **pack_out, const char *path) int git_packfile_check(struct git_pack_file **pack_out, const char *path)
...@@ -586,6 +574,7 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path) ...@@ -586,6 +574,7 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path)
*pack_out = NULL; *pack_out = NULL;
path_len = strlen(path); path_len = strlen(path);
p = packfile_alloc(path_len + 2); p = packfile_alloc(path_len + 2);
GITERR_CHECK_ALLOC(p);
/* /*
* Make sure a corresponding .pack file exists and that * Make sure a corresponding .pack file exists and that
...@@ -594,7 +583,7 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path) ...@@ -594,7 +583,7 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path)
path_len -= strlen(".idx"); path_len -= strlen(".idx");
if (path_len < 1) { if (path_len < 1) {
git__free(p); git__free(p);
return git__throw(GIT_ENOTFOUND, "Failed to check packfile. Wrong path name"); return git_odb__error_notfound("invalid packfile path");
} }
memcpy(p->pack_name, path, path_len); memcpy(p->pack_name, path, path_len);
...@@ -604,9 +593,9 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path) ...@@ -604,9 +593,9 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path)
p->pack_keep = 1; p->pack_keep = 1;
strcpy(p->pack_name + path_len, ".pack"); strcpy(p->pack_name + path_len, ".pack");
if (p_stat(p->pack_name, &st) < GIT_SUCCESS || !S_ISREG(st.st_mode)) { if (p_stat(p->pack_name, &st) < 0 || !S_ISREG(st.st_mode)) {
git__free(p); git__free(p);
return git__throw(GIT_ENOTFOUND, "Failed to check packfile. File not found"); return git_odb__error_notfound("packfile not found");
} }
/* ok, it looks sane as far as we can check without /* ok, it looks sane as far as we can check without
...@@ -618,11 +607,12 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path) ...@@ -618,11 +607,12 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path)
/* see if we can parse the sha1 oid in the packfile name */ /* see if we can parse the sha1 oid in the packfile name */
if (path_len < 40 || if (path_len < 40 ||
git_oid_fromstr(&p->sha1, path + path_len - GIT_OID_HEXSZ) < GIT_SUCCESS) git_oid_fromstr(&p->sha1, path + path_len - GIT_OID_HEXSZ) < 0)
memset(&p->sha1, 0x0, GIT_OID_RAWSZ); memset(&p->sha1, 0x0, GIT_OID_RAWSZ);
*pack_out = p; *pack_out = p;
return GIT_SUCCESS;
return 0;
} }
/*********************************************************** /***********************************************************
...@@ -631,7 +621,7 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path) ...@@ -631,7 +621,7 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path)
* *
***********************************************************/ ***********************************************************/
static off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n) static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n)
{ {
const unsigned char *index = p->index_map.data; const unsigned char *index = p->index_map.data;
index += 4 * 256; index += 4 * 256;
...@@ -650,7 +640,7 @@ static off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n) ...@@ -650,7 +640,7 @@ static off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n)
} }
static int pack_entry_find_offset( static int pack_entry_find_offset(
off_t *offset_out, git_off_t *offset_out,
git_oid *found_oid, git_oid *found_oid,
struct git_pack_file *p, struct git_pack_file *p,
const git_oid *short_oid, const git_oid *short_oid,
...@@ -667,8 +657,8 @@ static int pack_entry_find_offset( ...@@ -667,8 +657,8 @@ static int pack_entry_find_offset(
if (index == NULL) { if (index == NULL) {
int error; int error;
if ((error = pack_index_open(p)) < GIT_SUCCESS) if ((error = pack_index_open(p)) < 0)
return git__rethrow(error, "Failed to find offset for pack entry"); return error;
assert(p->index_map.data); assert(p->index_map.data);
...@@ -726,22 +716,22 @@ static int pack_entry_find_offset( ...@@ -726,22 +716,22 @@ static int pack_entry_find_offset(
} }
} }
if (!found) { if (!found)
return git__throw(GIT_ENOTFOUND, "Failed to find offset for pack entry. Entry not found"); return git_odb__error_notfound("failed to find offset for pack entry");
} else if (found > 1) { if (found > 1)
return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to find offset for pack entry. Ambiguous sha1 prefix within pack"); return git_odb__error_ambiguous("found multiple offsets for pack entry");
} else {
*offset_out = nth_packed_object_offset(p, pos); *offset_out = nth_packed_object_offset(p, pos);
git_oid_fromraw(found_oid, current); git_oid_fromraw(found_oid, current);
#ifdef INDEX_DEBUG_LOOKUP #ifdef INDEX_DEBUG_LOOKUP
{
unsigned char hex_sha1[GIT_OID_HEXSZ + 1]; unsigned char hex_sha1[GIT_OID_HEXSZ + 1];
git_oid_fmt(hex_sha1, found_oid); git_oid_fmt(hex_sha1, found_oid);
hex_sha1[GIT_OID_HEXSZ] = '\0'; hex_sha1[GIT_OID_HEXSZ] = '\0';
printf("found lo=%d %s\n", lo, hex_sha1); printf("found lo=%d %s\n", lo, hex_sha1);
#endif
return GIT_SUCCESS;
} }
#endif
return 0;
} }
int git_pack_entry_find( int git_pack_entry_find(
...@@ -750,7 +740,7 @@ int git_pack_entry_find( ...@@ -750,7 +740,7 @@ int git_pack_entry_find(
const git_oid *short_oid, const git_oid *short_oid,
unsigned int len) unsigned int len)
{ {
off_t offset; git_off_t offset;
git_oid found_oid; git_oid found_oid;
int error; int error;
...@@ -760,22 +750,22 @@ int git_pack_entry_find( ...@@ -760,22 +750,22 @@ int git_pack_entry_find(
unsigned i; unsigned i;
for (i = 0; i < p->num_bad_objects; i++) for (i = 0; i < p->num_bad_objects; i++)
if (git_oid_cmp(short_oid, &p->bad_object_sha1[i]) == 0) if (git_oid_cmp(short_oid, &p->bad_object_sha1[i]) == 0)
return git__throw(GIT_ERROR, "Failed to find pack entry. Bad object found"); return packfile_error("bad object found in packfile");
} }
error = pack_entry_find_offset(&offset, &found_oid, p, short_oid, len); error = pack_entry_find_offset(&offset, &found_oid, p, short_oid, len);
if (error < GIT_SUCCESS) if (error < 0)
return git__rethrow(error, "Failed to find pack entry. Couldn't find offset"); return error;
/* we found a unique entry in the index; /* we found a unique entry in the index;
* make sure the packfile backing the index * make sure the packfile backing the index
* still exists on disk */ * still exists on disk */
if (p->mwf.fd == -1 && packfile_open(p) < GIT_SUCCESS) if (p->mwf.fd == -1 && (error = packfile_open(p)) < 0)
return git__throw(GIT_EOSERR, "Failed to find pack entry. Packfile doesn't exist on disk"); return error;
e->offset = offset; e->offset = offset;
e->p = p; e->p = p;
git_oid_cpy(&e->sha1, &found_oid); git_oid_cpy(&e->sha1, &found_oid);
return GIT_SUCCESS; return 0;
} }
...@@ -70,7 +70,7 @@ struct git_pack_file { ...@@ -70,7 +70,7 @@ struct git_pack_file {
}; };
struct git_pack_entry { struct git_pack_entry {
off_t offset; git_off_t offset;
git_oid sha1; git_oid sha1;
struct git_pack_file *p; struct git_pack_file *p;
}; };
...@@ -80,13 +80,13 @@ int git_packfile_unpack_header( ...@@ -80,13 +80,13 @@ int git_packfile_unpack_header(
git_otype *type_p, git_otype *type_p,
git_mwindow_file *mwf, git_mwindow_file *mwf,
git_mwindow **w_curs, git_mwindow **w_curs,
off_t *curpos); git_off_t *curpos);
int git_packfile_unpack(git_rawobj *obj, struct git_pack_file *p, off_t *obj_offset); int git_packfile_unpack(git_rawobj *obj, struct git_pack_file *p, git_off_t *obj_offset);
off_t get_delta_base(struct git_pack_file *p, git_mwindow **w_curs, git_off_t get_delta_base(struct git_pack_file *p, git_mwindow **w_curs,
off_t *curpos, git_otype type, git_off_t *curpos, git_otype type,
off_t delta_obj_offset); git_off_t delta_obj_offset);
void packfile_free(struct git_pack_file *p); void packfile_free(struct git_pack_file *p);
int git_packfile_check(struct git_pack_file **pack_out, const char *path); int git_packfile_check(struct git_pack_file **pack_out, const char *path);
......
...@@ -842,7 +842,7 @@ static int reference_path_available( ...@@ -842,7 +842,7 @@ static int reference_path_available(
if (!data.available) { if (!data.available) {
giterr_set(GITERR_REFERENCE, giterr_set(GITERR_REFERENCE,
"The path to reference '%s' collides with an existing one"); "The path to reference '%s' collides with an existing one", ref);
return -1; return -1;
} }
...@@ -902,7 +902,7 @@ static int reference_can_write( ...@@ -902,7 +902,7 @@ static int reference_can_write(
* the rename; the existing one would be overwritten */ * the rename; the existing one would be overwritten */
if (exists) { if (exists) {
giterr_set(GITERR_REFERENCE, giterr_set(GITERR_REFERENCE,
"A reference with that name (%s) already exists"); "A reference with that name (%s) already exists", refname);
return GIT_EEXISTS; return GIT_EEXISTS;
} }
} }
......
...@@ -17,12 +17,8 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs ...@@ -17,12 +17,8 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs
int mprot = 0; int mprot = 0;
int mflag = 0; int mflag = 0;
assert((out != NULL) && (len > 0)); if (validate_map_args(out, len, prot, flags, fd, offset) < 0)
return -1;
if ((out == NULL) || (len == 0)) {
errno = EINVAL;
return git__throw(GIT_ERROR, "Failed to mmap. No map or zero length");
}
out->data = NULL; out->data = NULL;
out->len = 0; out->len = 0;
...@@ -31,39 +27,28 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs ...@@ -31,39 +27,28 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs
mprot = PROT_WRITE; mprot = PROT_WRITE;
else if (prot & GIT_PROT_READ) else if (prot & GIT_PROT_READ)
mprot = PROT_READ; mprot = PROT_READ;
else {
errno = EINVAL;
return git__throw(GIT_ERROR, "Failed to mmap. Invalid protection parameters");
}
if ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED) if ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)
mflag = MAP_SHARED; mflag = MAP_SHARED;
else if ((flags & GIT_MAP_TYPE) == GIT_MAP_PRIVATE) else if ((flags & GIT_MAP_TYPE) == GIT_MAP_PRIVATE)
mflag = MAP_PRIVATE; mflag = MAP_PRIVATE;
if (flags & GIT_MAP_FIXED) { out->data = mmap(NULL, len, mprot, mflag, fd, offset);
errno = EINVAL; if (!out->data || out->data == MAP_FAILED) {
return git__throw(GIT_ERROR, "Failed to mmap. FIXED not set"); giterr_set(GITERR_OS, "Failed to mmap. Could not write data");
return -1;
} }
out->data = mmap(NULL, len, mprot, mflag, fd, offset);
if (!out->data || out->data == MAP_FAILED)
return git__throw(GIT_EOSERR, "Failed to mmap. Could not write data");
out->len = len; out->len = len;
return GIT_SUCCESS; return 0;
} }
int p_munmap(git_map *map) int p_munmap(git_map *map)
{ {
assert(map != NULL); assert(map != NULL);
if (!map)
return git__throw(GIT_ERROR, "Failed to munmap. Map does not exist");
munmap(map->data, map->len); munmap(map->data, map->len);
return 0;
return GIT_SUCCESS;
} }
#endif #endif
......
...@@ -33,12 +33,8 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs ...@@ -33,12 +33,8 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs
git_off_t page_start; git_off_t page_start;
git_off_t page_offset; git_off_t page_offset;
assert((out != NULL) && (len > 0)); if (validate_map_args(out, len, prot, flags, fd, offset) < 0)
return -1;
if ((out == NULL) || (len == 0)) {
errno = EINVAL;
return git__throw(GIT_ERROR, "Failed to mmap. No map or zero length");
}
out->data = NULL; out->data = NULL;
out->len = 0; out->len = 0;
...@@ -46,86 +42,75 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs ...@@ -46,86 +42,75 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs
if (fh == INVALID_HANDLE_VALUE) { if (fh == INVALID_HANDLE_VALUE) {
errno = EBADF; errno = EBADF;
return git__throw(GIT_ERROR, "Failed to mmap. Invalid handle value"); giterr_set(GITERR_OS, "Failed to mmap. Invalid handle value");
return -1;
} }
if (prot & GIT_PROT_WRITE) if (prot & GIT_PROT_WRITE)
fmap_prot |= PAGE_READWRITE; fmap_prot |= PAGE_READWRITE;
else if (prot & GIT_PROT_READ) else if (prot & GIT_PROT_READ)
fmap_prot |= PAGE_READONLY; fmap_prot |= PAGE_READONLY;
else {
errno = EINVAL;
return git__throw(GIT_ERROR, "Failed to mmap. Invalid protection parameters");
}
if (prot & GIT_PROT_WRITE) if (prot & GIT_PROT_WRITE)
view_prot |= FILE_MAP_WRITE; view_prot |= FILE_MAP_WRITE;
if (prot & GIT_PROT_READ) if (prot & GIT_PROT_READ)
view_prot |= FILE_MAP_READ; view_prot |= FILE_MAP_READ;
if (flags & GIT_MAP_FIXED) {
errno = EINVAL;
return git__throw(GIT_ERROR, "Failed to mmap. FIXED not set");
}
page_start = (offset / page_size) * page_size; page_start = (offset / page_size) * page_size;
page_offset = offset - page_start; page_offset = offset - page_start;
if (page_offset != 0) { /* offset must be multiple of page size */ if (page_offset != 0) { /* offset must be multiple of page size */
errno = EINVAL; errno = EINVAL;
return git__throw(GIT_ERROR, "Failed to mmap. Offset must be multiple of page size"); giterr_set(GITERR_OS, "Failed to mmap. Offset must be multiple of page size");
return -1;
} }
out->fmh = CreateFileMapping(fh, NULL, fmap_prot, 0, 0, NULL); out->fmh = CreateFileMapping(fh, NULL, fmap_prot, 0, 0, NULL);
if (!out->fmh || out->fmh == INVALID_HANDLE_VALUE) { if (!out->fmh || out->fmh == INVALID_HANDLE_VALUE) {
/* errno = ? */ giterr_set(GITERR_OS, "Failed to mmap. Invalid handle value");
out->fmh = NULL; out->fmh = NULL;
return git__throw(GIT_ERROR, "Failed to mmap. Invalid handle value"); return -1;
} }
assert(sizeof(git_off_t) == 8); assert(sizeof(git_off_t) == 8);
off_low = (DWORD)(page_start); off_low = (DWORD)(page_start);
off_hi = (DWORD)(page_start >> 32); off_hi = (DWORD)(page_start >> 32);
out->data = MapViewOfFile(out->fmh, view_prot, off_hi, off_low, len); out->data = MapViewOfFile(out->fmh, view_prot, off_hi, off_low, len);
if (!out->data) { if (!out->data) {
/* errno = ? */ giterr_set(GITERR_OS, "Failed to mmap. No data written");
CloseHandle(out->fmh); CloseHandle(out->fmh);
out->fmh = NULL; out->fmh = NULL;
return git__throw(GIT_ERROR, "Failed to mmap. No data written"); return -1;
} }
out->len = len; out->len = len;
return GIT_SUCCESS; return 0;
} }
int p_munmap(git_map *map) int p_munmap(git_map *map)
{ {
assert(map != NULL); int error = 0;
if (!map) assert(map != NULL);
return git__throw(GIT_ERROR, "Failed to munmap. Map does not exist");
if (map->data) { if (map->data) {
if (!UnmapViewOfFile(map->data)) { if (!UnmapViewOfFile(map->data)) {
/* errno = ? */ giterr_set(GITERR_OS, "Failed to munmap. Could not unmap view of file");
CloseHandle(map->fmh); error = -1;
map->data = NULL;
map->fmh = NULL;
return git__throw(GIT_ERROR, "Failed to munmap. Could not unmap view of file");
} }
map->data = NULL; map->data = NULL;
} }
if (map->fmh) { if (map->fmh) {
if (!CloseHandle(map->fmh)) { if (!CloseHandle(map->fmh)) {
/* errno = ? */ giterr_set(GITERR_OS, "Failed to munmap. Could not close handle");
map->fmh = NULL; error = -1;
return git__throw(GIT_ERROR, "Failed to munmap. Could not close handle");
} }
map->fmh = NULL; map->fmh = NULL;
} }
return GIT_SUCCESS; return error;
} }
/ < 0) /*
* Copyright (C) 2009-2012 the libgit2 contributors * Copyright (C) 2009-2012 the libgit2 contributors
* *
* This file is part of libgit2, distributed under the GNU GPL v2 with * This file is part of libgit2, distributed under the GNU GPL v2 with
...@@ -339,7 +339,7 @@ int p_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr) ...@@ -339,7 +339,7 @@ int p_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr)
int len; int len;
if (count == 0 || (len = _vsnprintf(buffer, count, format, argptr)) < 0) if (count == 0 || (len = _vsnprintf(buffer, count, format, argptr)) < 0)
return p_vscprintf(format, argptr); return _vscprintf(format, argptr);
return len; return len;
#else /* MinGW */ #else /* MinGW */
......
...@@ -15,7 +15,7 @@ struct attr_expected { ...@@ -15,7 +15,7 @@ struct attr_expected {
const char *expected_str; const char *expected_str;
}; };
static inline void attr_check_expected( GIT_INLINE(void) attr_check_expected(
enum attr_expect_t expected, enum attr_expect_t expected,
const char *expected_str, const char *expected_str,
const char *value) const char *value)
......
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