Commit e24fbba9 by Vicent Martí

Merge pull request #595 from arrbee/new-errors-odb

Update odb code to new error handling
parents dda708e7 deafee7b
......@@ -103,7 +103,7 @@ typedef enum {
GIT_EOBJCORRUPTED = -28,
/** The given short oid is ambiguous */
GIT_EAMBIGUOUSOIDPREFIX = -29,
GIT_EAMBIGUOUS = -29,
/** Skip and passthrough the given ODB backend */
GIT_EPASSTHROUGH = -30,
......@@ -128,11 +128,13 @@ typedef enum {
GITERR_REPOSITORY,
GITERR_CONFIG,
GITERR_REGEX,
GITERR_ODB
} git_error_class;
/**
* Return a detailed error string with the latest error
* that occurred in the library.
* @deprecated This will be replaced in the new error handling
* @return a string explaining the error
*/
GIT_EXTERN(const char *) git_lasterror(void);
......@@ -144,6 +146,7 @@ GIT_EXTERN(const char *) git_lasterror(void);
* NOTE: This method will be eventually deprecated in favor
* of the new `git_lasterror`.
*
* @deprecated This will be replaced in the new error handling
* @param num The error code to explain
* @return a string explaining the error code
*/
......@@ -151,9 +154,23 @@ GIT_EXTERN(const char *) git_strerror(int num);
/**
* Clear the latest library error
* @deprecated This will be replaced in the new error handling
*/
GIT_EXTERN(void) git_clearerror(void);
/**
* Return the last `git_error` object that was generated for the
* current thread or NULL if no error has occurred.
*
* @return A git_error object.
*/
GIT_EXTERN(const git_error *) git_error_last(void);
/**
* Clear the last library error that occurred for this thread.
*/
GIT_EXTERN(void) git_error_clear(void);
/** @} */
GIT_END_DECL
#endif
......@@ -317,13 +317,12 @@ static int collect_attr_files(
const char *workdir = git_repository_workdir(repo);
attr_walk_up_info info;
if ((error = git_attr_cache__init(repo)) < GIT_SUCCESS)
goto cleanup;
if ((error = git_vector_init(files, 4, NULL)) < GIT_SUCCESS)
goto cleanup;
if (git_attr_cache__init(repo) < 0 ||
git_vector_init(files, 4, NULL) < 0)
return -1;
if ((error = git_path_find_dir(&dir, path, workdir)) < GIT_SUCCESS)
error = git_path_find_dir(&dir, path, workdir);
if (error < 0)
goto cleanup;
/* in precendence order highest to lowest:
......@@ -334,13 +333,13 @@ static int collect_attr_files(
*/
error = push_attrs(repo, files, repo->path_repository, GIT_ATTR_FILE_INREPO);
if (error < GIT_SUCCESS)
if (error < 0)
goto cleanup;
info.repo = repo;
info.files = files;
error = git_path_walk_up(&dir, workdir, push_one_attr, &info);
if (error < GIT_SUCCESS)
if (error < 0)
goto cleanup;
if ((error = git_repository_config(&cfg, repo)) == GIT_SUCCESS) {
......@@ -352,19 +351,17 @@ static int collect_attr_files(
git_config_free(cfg);
}
if (error == GIT_SUCCESS) {
if (!error) {
error = git_futils_find_system_file(&dir, GIT_ATTR_FILE_SYSTEM);
if (error == GIT_SUCCESS)
if (!error)
error = push_attrs(repo, files, NULL, dir.ptr);
else if (error == GIT_ENOTFOUND)
error = GIT_SUCCESS;
error = 0;
}
cleanup:
if (error < GIT_SUCCESS) {
git__rethrow(error, "Could not get attributes for '%s'", path);
if (error < 0)
git_vector_free(files);
}
git_buf_free(&dir);
return error;
......@@ -373,32 +370,29 @@ static int collect_attr_files(
int git_attr_cache__init(git_repository *repo)
{
int error = GIT_SUCCESS;
git_attr_cache *cache = &repo->attrcache;
if (cache->initialized)
return GIT_SUCCESS;
return 0;
if (cache->files == NULL) {
cache->files = git_hashtable_alloc(
8, git_hash__strhash_cb, git_hash__strcmp_cb);
if (!cache->files)
return git__throw(GIT_ENOMEM, "Could not initialize attribute cache");
return -1;
}
if (cache->macros == NULL) {
cache->macros = git_hashtable_alloc(
8, git_hash__strhash_cb, git_hash__strcmp_cb);
if (!cache->macros)
return git__throw(GIT_ENOMEM, "Could not initialize attribute cache");
return -1;
}
cache->initialized = 1;
/* insert default macros */
error = git_attr_add_macro(repo, "binary", "-diff -crlf");
return error;
return git_attr_add_macro(repo, "binary", "-diff -crlf");
}
void git_attr_cache_flush(
......@@ -432,8 +426,9 @@ void git_attr_cache_flush(
int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro)
{
/* TODO: generate warning log if (macro->assigns.length == 0) */
if (macro->assigns.length == 0)
return git__throw(GIT_EMISSINGOBJDATA, "git attribute macro with no values");
return 0;
return git_hashtable_insert(
repo->attrcache.macros, macro->match.pattern, macro);
......
......@@ -180,37 +180,37 @@ int git_attr_file__lookup_one(
}
}
return GIT_SUCCESS;
return 0;
}
int git_attr_fnmatch__match(
bool git_attr_fnmatch__match(
git_attr_fnmatch *match,
const git_attr_path *path)
{
int matched = FNM_NOMATCH;
int fnm;
if (match->flags & GIT_ATTR_FNMATCH_DIRECTORY && !path->is_dir)
return matched;
return false;
if (match->flags & GIT_ATTR_FNMATCH_FULLPATH)
matched = p_fnmatch(match->pattern, path->path, FNM_PATHNAME);
fnm = p_fnmatch(match->pattern, path->path, FNM_PATHNAME);
else if (path->is_dir)
matched = p_fnmatch(match->pattern, path->basename, FNM_LEADING_DIR);
fnm = p_fnmatch(match->pattern, path->basename, FNM_LEADING_DIR);
else
matched = p_fnmatch(match->pattern, path->basename, 0);
fnm = p_fnmatch(match->pattern, path->basename, 0);
return matched;
return (fnm == FNM_NOMATCH) ? false : true;
}
int git_attr_rule__match(
bool git_attr_rule__match(
git_attr_rule *rule,
const git_attr_path *path)
{
int matched = git_attr_fnmatch__match(&rule->match, path);
bool matched = git_attr_fnmatch__match(&rule->match, path);
if (rule->match.flags & GIT_ATTR_FNMATCH_NEGATIVE)
matched = (matched == GIT_SUCCESS) ? FNM_NOMATCH : GIT_SUCCESS;
matched = !matched;
return matched;
}
......
......@@ -82,7 +82,7 @@ extern int git_attr_file__lookup_one(
/* loop over rules in file from bottom to top */
#define git_attr_file__foreach_matching_rule(file, path, iter, rule) \
git_vector_rforeach(&(file)->rules, (iter), (rule)) \
if (git_attr_rule__match((rule), (path)) == GIT_SUCCESS)
if (git_attr_rule__match((rule), (path)))
extern unsigned long git_attr_file__name_hash(const char *name);
......@@ -96,13 +96,13 @@ extern int git_attr_fnmatch__parse(
const char *source,
const char **base);
extern int git_attr_fnmatch__match(
extern bool git_attr_fnmatch__match(
git_attr_fnmatch *rule,
const git_attr_path *path);
extern void git_attr_rule__free(git_attr_rule *rule);
extern int git_attr_rule__match(
extern bool git_attr_rule__match(
git_attr_rule *rule,
const git_attr_path *path);
......
......@@ -42,7 +42,7 @@ int git_blob__parse(git_blob *blob, git_odb_object *odb_obj)
assert(blob);
git_cached_obj_incref((git_cached_obj *)odb_obj);
blob->odb_object = odb_obj;
return GIT_SUCCESS;
return 0;
}
int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *buffer, size_t len)
......@@ -51,58 +51,50 @@ int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *b
git_odb *odb;
git_odb_stream *stream;
error = git_repository_odb__weakptr(&odb, repo);
if (error < GIT_SUCCESS)
if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 ||
(error = git_odb_open_wstream(&stream, odb, len, GIT_OBJ_BLOB)) < 0)
return error;
if ((error = git_odb_open_wstream(&stream, odb, len, GIT_OBJ_BLOB)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to create blob");
if ((error = stream->write(stream, buffer, len)) == 0)
error = stream->finalize_write(oid, stream);
if ((error = stream->write(stream, buffer, len)) < GIT_SUCCESS) {
stream->free(stream);
return error;
}
error = stream->finalize_write(oid, stream);
stream->free(stream);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to create blob");
return GIT_SUCCESS;
return error;
}
static int write_file_stream(git_oid *oid, git_odb *odb, const char *path, git_off_t file_size)
static int write_file_stream(
git_oid *oid, git_odb *odb, const char *path, git_off_t file_size)
{
int fd, error;
char buffer[4096];
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)) < 0)
return error;
if ((fd = p_open(path, O_RDONLY)) < 0) {
error = git__throw(GIT_ENOTFOUND, "Failed to create blob. Could not open '%s'", path);
goto cleanup;
if ((fd = git_futils_open_ro(path)) < 0) {
stream->free(stream);
return -1;
}
while (file_size > 0) {
while (!error && file_size > 0) {
ssize_t read_len = p_read(fd, buffer, sizeof(buffer));
if (read_len < 0) {
error = git__throw(GIT_EOSERR, "Failed to create blob. Can't read full file");
p_close(fd);
goto cleanup;
giterr_set(
GITERR_OS, "Failed to create blob. Can't read whole file");
error = -1;
}
stream->write(stream, buffer, read_len);
file_size -= read_len;
else if (!(error = stream->write(stream, buffer, read_len)))
file_size -= read_len;
}
p_close(fd);
error = stream->finalize_write(oid, stream);
cleanup:
if (!error)
error = stream->finalize_write(oid, stream);
stream->free(stream);
return error;
}
......@@ -117,8 +109,7 @@ static int write_file_filtered(
git_buf source = GIT_BUF_INIT;
git_buf dest = GIT_BUF_INIT;
error = git_futils_readbuffer(&source, full_path);
if (error < GIT_SUCCESS)
if ((error = git_futils_readbuffer(&source, full_path)) < 0)
return error;
error = git_filters_apply(&dest, &source, filters);
......@@ -127,30 +118,29 @@ static int write_file_filtered(
* and we don't want to ODB write to choke */
git_buf_free(&source);
if (error == GIT_SUCCESS) {
/* Write the file to disk if it was properly filtered */
/* Write the file to disk if it was properly filtered */
if (!error)
error = git_odb_write(oid, odb, dest.ptr, dest.size, GIT_OBJ_BLOB);
}
git_buf_free(&dest);
return GIT_SUCCESS;
return error;
}
static int write_symlink(git_oid *oid, git_odb *odb, const char *path, size_t link_size)
static int write_symlink(
git_oid *oid, git_odb *odb, const char *path, size_t link_size)
{
char *link_data;
ssize_t read_len;
int error;
link_data = git__malloc(link_size);
if (!link_data)
return GIT_ENOMEM;
GITERR_CHECK_ALLOC(link_data);
read_len = p_readlink(path, link_data, link_size);
if (read_len != (ssize_t)link_size) {
giterr_set(GITERR_OS, "Failed to create blob. Can't read symlink '%s'", path);
free(link_data);
return git__throw(GIT_EOSERR, "Failed to create blob. Can't read symlink");
return -1;
}
error = git_odb_write(oid, odb, (void *)link_data, link_size, GIT_OBJ_BLOB);
......@@ -168,25 +158,18 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
git_odb *odb = NULL;
workdir = git_repository_workdir(repo);
if (workdir == NULL)
return git__throw(GIT_ENOTFOUND, "Failed to create blob. (No working directory found)");
assert(workdir); /* error to call this on bare repo */
error = git_buf_joinpath(&full_path, workdir, path);
if (error < GIT_SUCCESS)
if ((error = git_buf_joinpath(&full_path, workdir, path)) < 0 ||
(error = git_path_lstat(full_path.ptr, &st)) < 0 ||
(error = git_repository_odb__weakptr(&odb, repo)) < 0)
{
git_buf_free(&full_path);
return error;
error = p_lstat(full_path.ptr, &st);
if (error < 0) {
error = git__throw(GIT_EOSERR, "Failed to stat blob. %s", strerror(errno));
goto cleanup;
}
size = st.st_size;
error = git_repository_odb__weakptr(&odb, repo);
if (error < GIT_SUCCESS)
goto cleanup;
if (S_ISLNK(st.st_mode)) {
error = write_symlink(oid, odb, full_path.ptr, (size_t)size);
} else {
......@@ -194,12 +177,12 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
int filter_count;
/* Load the filters for writing this file to the ODB */
filter_count = git_filters_load(&write_filters, repo, path, GIT_FILTER_TO_ODB);
filter_count = git_filters_load(
&write_filters, repo, path, GIT_FILTER_TO_ODB);
if (filter_count < 0) {
/* Negative value means there was a critical error */
error = filter_count;
goto cleanup;
} else if (filter_count == 0) {
/* No filters need to be applied to the document: we can stream
* directly from disk */
......@@ -212,19 +195,20 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
git_filters_free(&write_filters);
/*
* TODO: eventually support streaming filtered files, for files which are bigger
* than a given threshold. This is not a priority because applying a filter in
* streaming mode changes the final size of the blob, and without knowing its
* final size, the blob cannot be written in stream mode to the ODB.
* TODO: eventually support streaming filtered files, for files
* which are bigger than a given threshold. This is not a priority
* because applying a filter in streaming mode changes the final
* size of the blob, and without knowing its final size, the blob
* cannot be written in stream mode to the ODB.
*
* The plan is to do streaming writes to a tempfile on disk and then opening
* streaming that file to the ODB, using `write_file_stream`.
* The plan is to do streaming writes to a tempfile on disk and then
* opening streaming that file to the ODB, using
* `write_file_stream`.
*
* CAREFULLY DESIGNED APIS YO
*/
}
cleanup:
git_buf_free(&full_path);
return error;
}
......
......@@ -215,8 +215,8 @@ void git_buf_truncate(git_buf *buf, size_t len)
void git_buf_rtruncate_at_char(git_buf *buf, char separator)
{
int idx = git_buf_rfind_next(buf, separator);
git_buf_truncate(buf, idx < 0 ? 0 : idx);
ssize_t idx = git_buf_rfind_next(buf, separator);
git_buf_truncate(buf, idx < 0 ? 0 : (size_t)idx);
}
void git_buf_swap(git_buf *buf_a, git_buf *buf_b)
......
......@@ -102,9 +102,9 @@ void git_buf_copy_cstr(char *data, size_t datasize, const git_buf *buf);
#define git_buf_PUTS(buf, str) git_buf_put(buf, str, sizeof(str) - 1)
GIT_INLINE(int) git_buf_rfind_next(git_buf *buf, char ch)
GIT_INLINE(ssize_t) git_buf_rfind_next(git_buf *buf, char ch)
{
int idx = buf->size - 1;
ssize_t idx = (ssize_t)buf->size - 1;
while (idx >= 0 && buf->ptr[idx] == ch) idx--;
while (idx >= 0 && buf->ptr[idx] != ch) idx--;
return idx;
......
......@@ -40,7 +40,7 @@ static struct {
{GIT_EEXISTS, "A reference with this name already exists"},
{GIT_EOVERFLOW, "The given integer literal is too large to be parsed"},
{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)
......@@ -123,15 +123,43 @@ void giterr_set(int error_class, const char *string, ...)
char error_str[1024];
va_list arglist;
/* Grab errno before calling vsnprintf() so it won't be overwritten */
const char *os_error_msg =
(error_class == GITERR_OS && errno != 0) ? strerror(errno) : NULL;
#ifdef GIT_WIN32
DWORD dwLastError = GetLastError();
#endif
va_start(arglist, string);
p_vsnprintf(error_str, sizeof(error_str), string, arglist);
va_end(arglist);
/* automatically suffix strerror(errno) for GITERR_OS errors */
if (error_class == GITERR_OS) {
strncat(error_str, ": ", sizeof(error_str));
strncat(error_str, strerror(errno), sizeof(error_str));
errno = 0;
if (os_error_msg != NULL) {
strncat(error_str, ": ", sizeof(error_str));
strncat(error_str, os_error_msg, sizeof(error_str));
errno = 0; /* reset so same error won't be reported twice */
}
#ifdef GIT_WIN32
else if (dwLastError != 0) {
LPVOID lpMsgBuf = NULL;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dwLastError, 0, (LPTSTR) &lpMsgBuf, 0, NULL);
if (lpMsgBuf) {
strncat(error_str, ": ", sizeof(error_str));
strncat(error_str, (const char *)lpMsgBuf, sizeof(error_str));
LocalFree(lpMsgBuf);
}
SetLastError(0);
}
#endif
}
giterr_set_str(error_class, error_str);
......@@ -165,3 +193,14 @@ void giterr_clear(void)
{
GIT_GLOBAL->last_error = NULL;
}
const git_error *git_error_last(void)
{
return GIT_GLOBAL->last_error;
}
void git_error_clear(void)
{
giterr_clear();
}
......@@ -67,6 +67,8 @@ static int lock_file(git_filebuf *file, int flags)
if (file->fd < 0)
return -1;
file->fd_is_open = true;
if ((flags & GIT_FILEBUF_APPEND) && git_path_exists(file->path_original) == true) {
git_file source;
char buffer[2048];
......@@ -94,10 +96,10 @@ static int lock_file(git_filebuf *file, int flags)
void git_filebuf_cleanup(git_filebuf *file)
{
if (file->fd >= 0)
if (file->fd_is_open && file->fd >= 0)
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);
if (file->digest)
......@@ -239,6 +241,7 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags)
git_buf_free(&tmp_path);
goto cleanup;
}
file->fd_is_open = true;
/* No original path */
file->path_original = NULL;
......@@ -308,6 +311,7 @@ int git_filebuf_commit(git_filebuf *file, mode_t mode)
p_close(file->fd);
file->fd = -1;
file->fd_is_open = false;
if (p_chmod(file->path_lock, mode)) {
giterr_set(GITERR_OS, "Failed to set attributes for file at '%s'", file->path_lock);
......
......@@ -40,6 +40,7 @@ struct git_filebuf {
size_t buf_size, buf_pos;
git_file fd;
bool fd_is_open;
int last_error;
};
......
......@@ -79,11 +79,25 @@ int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, con
return git_futils_creat_locked(path, mode);
}
int git_futils_open_ro(const char *path)
{
int fd = p_open(path, O_RDONLY);
if (fd < 0) {
if (errno == ENOENT)
fd = GIT_ENOTFOUND;
giterr_set(GITERR_OS, "Failed to open '%s'", path);
}
return fd;
}
git_off_t git_futils_filesize(git_file fd)
{
struct stat sb;
if (p_fstat(fd, &sb))
return GIT_ERROR;
if (p_fstat(fd, &sb)) {
giterr_set(GITERR_OS, "Failed to stat file descriptor");
return -1;
}
return sb.st_size;
}
......@@ -117,7 +131,7 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime,
return fd;
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);
return -1;
}
......@@ -127,7 +141,7 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime,
* has been modified.
*/
if (mtime != NULL && *mtime >= st.st_mtime) {
close(fd);
p_close(fd);
return 0;
}
......@@ -139,8 +153,8 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime,
git_buf_clear(buf);
if (git_buf_grow(buf, len + 1) < 0) {
close(fd);
return GIT_ENOMEM;
p_close(fd);
return -1;
}
buf->ptr[len] = '\0';
......@@ -149,7 +163,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);
if (read_size < 0) {
close(fd);
p_close(fd);
giterr_set(GITERR_OS, "Failed to read descriptor for '%s'", path);
return -1;
}
......@@ -176,10 +190,15 @@ int git_futils_readbuffer(git_buf *buf, const char *path)
int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode)
{
if (git_futils_mkpath2file(to, dirmode) < GIT_SUCCESS)
return GIT_EOSERR; /* The callee already takes care of setting the correct error message. */
if (git_futils_mkpath2file(to, dirmode) < 0)
return -1;
if (p_rename(from, to) < 0) {
giterr_set(GITERR_OS, "Failed to rename '%s' to '%s'", from, to);
return -1;
}
return p_rename(from, to); /* The callee already takes care of setting the correct error message. */
return 0;
}
int git_futils_mmap_ro(git_map *out, git_file fd, git_off_t begin, size_t len)
......@@ -192,8 +211,10 @@ int git_futils_mmap_ro_file(git_map *out, const char *path)
git_file fd = p_open(path, O_RDONLY /* | O_NOATIME */);
git_off_t len = git_futils_filesize(fd);
int result;
if (!git__is_sizet(len))
return git__throw(GIT_ERROR, "File `%s` too large to mmap", path);
if (!git__is_sizet(len)) {
giterr_set(GITERR_OS, "File `%s` too large to mmap", path);
return -1;
}
result = git_futils_mmap_ro(out, fd, 0, (size_t)len);
p_close(fd);
return result;
......@@ -260,20 +281,31 @@ int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode)
static int _rmdir_recurs_foreach(void *opaque, git_buf *path)
{
int error = GIT_SUCCESS;
int force = *(int *)opaque;
if (git_path_isdir(path->ptr) == true) {
error = git_path_direach(path, _rmdir_recurs_foreach, opaque);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to remove directory `%s`", path->ptr);
return p_rmdir(path->ptr);
if (git_path_direach(path, _rmdir_recurs_foreach, opaque) < 0)
return -1;
if (p_rmdir(path->ptr) < 0) {
giterr_set(GITERR_OS, "Could not remove directory '%s'", path->ptr);
return -1;
}
} else if (force) {
return p_unlink(path->ptr);
return 0;
}
return git__rethrow(error, "Failed to remove directory. `%s` is not empty", path->ptr);
if (force) {
if (p_unlink(path->ptr) < 0) {
giterr_set(GITERR_OS, "Could not remove directory. File '%s' cannot be removed", path->ptr);
return -1;
}
return 0;
}
giterr_set(GITERR_OS, "Could not remove directory. File '%s' still present", path->ptr);
return -1;
}
int git_futils_rmdir_r(const char *path, int force)
......@@ -282,7 +314,7 @@ int git_futils_rmdir_r(const char *path, int force)
git_buf p = GIT_BUF_INIT;
error = git_buf_sets(&p, path);
if (error == GIT_SUCCESS)
if (!error)
error = _rmdir_recurs_foreach(&force, &p);
git_buf_free(&p);
return error;
......@@ -328,9 +360,8 @@ static const win32_path *win32_system_root(void)
const wchar_t *root_tmpl = L"%PROGRAMFILES%\\Git\\etc\\";
s_root.len = ExpandEnvironmentStringsW(root_tmpl, NULL, 0);
if (s_root.len <= 0) {
git__throw(GIT_EOSERR, "Failed to expand environment strings");
giterr_set(GITERR_OS, "Failed to expand environment strings");
return NULL;
}
......@@ -339,7 +370,7 @@ static const win32_path *win32_system_root(void)
return NULL;
if (ExpandEnvironmentStringsW(root_tmpl, s_root.path, s_root.len) != s_root.len) {
git__throw(GIT_EOSERR, "Failed to expand environment strings");
giterr_set(GITERR_OS, "Failed to expand environment strings");
git__free(s_root.path);
s_root.path = NULL;
return NULL;
......@@ -351,7 +382,7 @@ static const win32_path *win32_system_root(void)
static int win32_find_system_file(git_buf *path, const char *filename)
{
int error = GIT_SUCCESS;
int error = 0;
const win32_path *root = win32_system_root();
size_t len;
wchar_t *file_utf16 = NULL, *scan;
......@@ -362,8 +393,7 @@ static int win32_find_system_file(git_buf *path, const char *filename)
/* allocate space for wchar_t path to file */
file_utf16 = git__calloc(root->len + len + 2, sizeof(wchar_t));
if (!file_utf16)
return GIT_ENOMEM;
GITERR_CHECK_ALLOC(file_utf16);
/* append root + '\\' + filename as wchar_t */
memcpy(file_utf16, root->path, root->len * sizeof(wchar_t));
......@@ -373,7 +403,7 @@ static int win32_find_system_file(git_buf *path, const char *filename)
if (gitwin_append_utf16(file_utf16 + root->len - 1, filename, len + 1) !=
(int)len + 1) {
error = git__throw(GIT_EOSERR, "Failed to build file path");
error = -1;
goto cleanup;
}
......@@ -389,9 +419,8 @@ static int win32_find_system_file(git_buf *path, const char *filename)
/* convert to utf8 */
if ((file_utf8 = gitwin_from_utf16(file_utf16)) == NULL)
error = GIT_ENOMEM;
if (file_utf8) {
error = -1;
else {
git_path_mkposix(file_utf8);
git_buf_attach(path, file_utf8, 0);
}
......@@ -409,7 +438,7 @@ int git_futils_find_system_file(git_buf *path, const char *filename)
return -1;
if (git_path_exists(path->ptr) == true)
return GIT_SUCCESS;
return 0;
git_buf_clear(path);
......
......@@ -77,18 +77,9 @@ extern int git_futils_mktmp(git_buf *path_out, const char *filename);
extern int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode);
/**
* Open a file readonly and set error if needed
*/
GIT_INLINE(int) git_futils_open_ro(const char *path)
{
int fd = p_open(path, O_RDONLY);
if (fd < 0) {
if (errno == ENOENT)
fd = GIT_ENOTFOUND;
giterr_set(GITERR_OS, "Failed to open '%s'", path);
}
return fd;
}
* Open a file readonly and set error if needed.
*/
extern int git_futils_open_ro(const char *path);
/**
* Get the filesize in bytes of a file
......
......@@ -31,9 +31,7 @@ static int resize_to(git_hashtable *self, size_t new_size)
self->size_mask = new_size - 1;
self->key_count = 0;
self->nodes = git__calloc(1, sizeof(git_hashtable_node) * self->size);
if (self->nodes == NULL)
return GIT_ENOMEM;
GITERR_CHECK_ALLOC(self->nodes);
if (insert_nodes(self, old_nodes, old_size) == 0)
self->is_resizing = 0;
......@@ -44,22 +42,22 @@ static int resize_to(git_hashtable *self, size_t new_size)
} while(self->is_resizing);
git__free(old_nodes);
return GIT_SUCCESS;
return 0;
}
static int set_size(git_hashtable *self, size_t new_size)
{
self->nodes = git__realloc(self->nodes, new_size * sizeof(git_hashtable_node));
if (self->nodes == NULL)
return GIT_ENOMEM;
GITERR_CHECK_ALLOC(self->nodes);
if (new_size > self->size) {
memset(&self->nodes[self->size], 0x0, (new_size - self->size) * sizeof(git_hashtable_node));
memset(&self->nodes[self->size], 0x0,
(new_size - self->size) * sizeof(git_hashtable_node));
}
self->size = new_size;
self->size_mask = new_size - 1;
return GIT_SUCCESS;
return 0;
}
static git_hashtable_node *node_with_hash(git_hashtable *self, const void *key, int hash_id)
......@@ -84,43 +82,47 @@ static int node_insert(git_hashtable *self, git_hashtable_node *new_node)
git_hashtable_node *node;
node = node_with_hash(self, new_node->key, hash_id);
node_swap_with(new_node, node);
if(new_node->key == 0x0){
if (new_node->key == 0x0){
self->key_count++;
return GIT_SUCCESS;
return 0;
}
}
}
if (self->is_resizing)
return git__throw(GIT_EBUSY, "Failed to insert node. Hashtable is currently resizing");
/* Failed to insert node. Hashtable is currently resizing */
assert(!self->is_resizing);
if (resize_to(self, self->size * 2) < 0)
return -1;
resize_to(self, self->size * 2);
git_hashtable_insert(self, new_node->key, new_node->value);
return GIT_SUCCESS;
return git_hashtable_insert(self, new_node->key, new_node->value);
}
static int insert_nodes(git_hashtable *self, git_hashtable_node *old_nodes, size_t old_size)
static int insert_nodes(
git_hashtable *self, git_hashtable_node *old_nodes, size_t old_size)
{
size_t i;
for (i = 0; i < old_size; ++i) {
git_hashtable_node *node = git_hashtable_node_at(old_nodes, i);
if (node->key && git_hashtable_insert(self, node->key, node->value) < GIT_SUCCESS)
return GIT_ENOMEM;
if (node->key &&
git_hashtable_insert(self, node->key, node->value) < 0)
return -1;
}
return GIT_SUCCESS;
return 0;
}
git_hashtable *git_hashtable_alloc(size_t min_size,
git_hash_ptr hash,
git_hash_keyeq_ptr key_eq)
git_hashtable *git_hashtable_alloc(
size_t min_size,
git_hash_ptr hash,
git_hash_keyeq_ptr key_eq)
{
git_hashtable *table;
assert(hash && key_eq);
if ((table = git__malloc(sizeof(git_hashtable))) == NULL)
if ((table = git__malloc(sizeof(*table))) == NULL)
return NULL;
memset(table, 0x0, sizeof(git_hashtable));
......@@ -161,7 +163,8 @@ void git_hashtable_free(git_hashtable *self)
}
int git_hashtable_insert2(git_hashtable *self, const void *key, void *value, void **old_value)
int git_hashtable_insert2(
git_hashtable *self, const void *key, void *value, void **old_value)
{
int hash_id;
git_hashtable_node *node;
......@@ -177,14 +180,14 @@ int git_hashtable_insert2(git_hashtable *self, const void *key, void *value, voi
node->key = key;
node->value = value;
self->key_count++;
return GIT_SUCCESS;
return 0;
}
if (key == node->key || self->key_equal(key, node->key) == 0) {
*old_value = node->value;
node->key = key;
node->value = value;
return GIT_SUCCESS;
return 0;
}
}
......@@ -213,7 +216,8 @@ void *git_hashtable_lookup(git_hashtable *self, const void *key)
return NULL;
}
int git_hashtable_remove2(git_hashtable *self, const void *key, void **old_value)
int git_hashtable_remove2(
git_hashtable *self, const void *key, void **old_value)
{
int hash_id;
git_hashtable_node *node;
......@@ -236,8 +240,8 @@ int git_hashtable_remove2(git_hashtable *self, const void *key, void **old_value
int git_hashtable_merge(git_hashtable *self, git_hashtable *other)
{
if (resize_to(self, (self->size + other->size) * 2) < GIT_SUCCESS)
return GIT_ENOMEM;
if (resize_to(self, (self->size + other->size) * 2) < 0)
return -1;
return insert_nodes(self, other->nodes, other->key_count);
}
......@@ -254,5 +258,10 @@ uint32_t git_hash__strhash_cb(const void *key, int hash_id)
0x7daaab3c
};
return git__hash(key, strlen((const char *)key), hash_seeds[hash_id]);
size_t key_len = strlen((const char *)key);
/* won't take hash of strings longer than 2^31 right now */
assert(key_len == (size_t)((int)key_len));
return git__hash(key, (int)key_len, hash_seeds[hash_id]);
}
......@@ -66,7 +66,7 @@ GIT_INLINE(int) git_hashtable_insert(git_hashtable *h, const void *key, void *va
#define git_hashtable_node_at(nodes, pos) ((git_hashtable_node *)(&nodes[pos]))
#define GIT_HASHTABLE__FOREACH(self,block) { \
unsigned int _c; \
size_t _c; \
git_hashtable_node *_n = (self)->nodes; \
for (_c = (self)->size; _c > 0; _c--, _n++) { \
if (!_n->key) continue; block } }
......
......@@ -168,9 +168,9 @@ static int ignore_lookup_in_rules(
git_attr_fnmatch *match;
git_vector_rforeach(rules, j, match) {
if (git_attr_fnmatch__match(match, path) == GIT_SUCCESS) {
if (git_attr_fnmatch__match(match, path)) {
*ignored = ((match->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0);
return GIT_SUCCESS;
return 0;
}
}
......
......@@ -319,8 +319,7 @@ static int index_entry_init(git_index_entry **entry_out, git_index *index, const
if (error < GIT_SUCCESS)
return error;
if (p_lstat(full_path.ptr, &st) < 0) {
error = git__throw(GIT_ENOTFOUND, "Failed to initialize entry. '%s' cannot be opened. %s", full_path.ptr, strerror(errno));
if ((error = git_path_lstat(full_path.ptr, &st)) < 0) {
git_buf_free(&full_path);
return error;
}
......
......@@ -133,12 +133,15 @@ int git_indexer_new(git_indexer **out, const char *packname)
idx->nr_objects = ntohl(idx->hdr.hdr_entries);
error = git_vector_init(&idx->pack->cache, idx->nr_objects, cache_cmp);
/* for now, limit to 2^32 objects */
assert(idx->nr_objects == (size_t)((unsigned int)idx->nr_objects));
error = git_vector_init(&idx->pack->cache, (unsigned int)idx->nr_objects, cache_cmp);
if (error < GIT_SUCCESS)
goto cleanup;
idx->pack->has_cache = 1;
error = git_vector_init(&idx->objects, idx->nr_objects, objects_cmp);
error = git_vector_init(&idx->objects, (unsigned int)idx->nr_objects, objects_cmp);
if (error < GIT_SUCCESS)
goto cleanup;
......@@ -307,7 +310,7 @@ cleanup:
int git_indexer_run(git_indexer *idx, git_indexer_stats *stats)
{
git_mwindow_file *mwf;
off_t off = sizeof(struct git_pack_header);
git_off_t off = sizeof(struct git_pack_header);
int error;
struct entry *entry;
unsigned int left, processed;
......@@ -319,7 +322,7 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats)
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to register mwindow file");
stats->total = idx->nr_objects;
stats->total = (unsigned int)idx->nr_objects;
stats->processed = processed = 0;
while (processed < idx->nr_objects) {
......@@ -328,18 +331,18 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats)
struct git_pack_entry *pentry;
git_mwindow *w = NULL;
int i;
off_t entry_start = off;
git_off_t entry_start = off;
void *packed;
size_t entry_size;
entry = git__malloc(sizeof(struct entry));
memset(entry, 0x0, sizeof(struct entry));
entry = git__calloc(1, sizeof(*entry));
GITERR_CHECK_ALLOC(entry);
if (off > UINT31_MAX) {
entry->offset = UINT32_MAX;
entry->offset_long = off;
} else {
entry->offset = off;
entry->offset = (uint32_t)off;
}
error = git_packfile_unpack(&obj, idx->pack, &off);
......@@ -369,13 +372,13 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats)
git_oid_cpy(&entry->oid, &oid);
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);
if (packed == NULL) {
error = git__rethrow(error, "Failed to open window to read packed data");
goto cleanup;
}
entry->crc = htonl(crc32(entry->crc, packed, entry_size));
entry->crc = htonl(crc32(entry->crc, packed, (uInt)entry_size));
git_mwindow_close(&w);
/* Add the object to the list */
......
......@@ -309,7 +309,7 @@ static int workdir_iterator__expand_dir(workdir_iterator *wi)
/* only push new ignores if this is not top level directory */
if (wi->stack->next != NULL) {
int slash_pos = git_buf_rfind_next(&wi->path, '/');
ssize_t slash_pos = git_buf_rfind_next(&wi->path, '/');
(void)git_ignore__push_dir(&wi->ignores, &wi->path.ptr[slash_pos + 1]);
}
......
......@@ -31,6 +31,11 @@ typedef struct { /* memory mapped buffer */
#endif
} git_map;
#define GIT_MMAP_VALIDATE(out, len, prot, flags) do { \
assert(out != NULL && len > 0); \
assert((prot & GIT_PROT_WRITE) || (prot & GIT_PROT_READ)); \
assert((flags & GIT_MAP_FIXED) == 0); } while (0)
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);
......
......@@ -178,8 +178,10 @@ static git_mwindow *new_window(
* window.
*/
if (git_futils_mmap_ro(&w->window_map, fd, w->offset, (size_t)len) < GIT_SUCCESS)
goto cleanup;
if (git_futils_mmap_ro(&w->window_map, fd, w->offset, (size_t)len) < 0) {
git__free(w);
return NULL;
}
ctl->mmap_calls++;
ctl->open_windows++;
......@@ -191,10 +193,6 @@ static git_mwindow *new_window(
ctl->peak_open_windows = ctl->open_windows;
return w;
cleanup:
git__free(w);
return NULL;
}
/*
......@@ -205,7 +203,7 @@ unsigned char *git_mwindow_open(
git_mwindow_file *mwf,
git_mwindow **cursor,
git_off_t offset,
int extra,
size_t extra,
unsigned int *left)
{
git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
......@@ -253,11 +251,10 @@ unsigned char *git_mwindow_open(
int git_mwindow_file_register(git_mwindow_file *mwf)
{
git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
int error;
if (ctl->windowfiles.length == 0 &&
(error = git_vector_init(&ctl->windowfiles, 8, NULL)) < GIT_SUCCESS)
return error;
git_vector_init(&ctl->windowfiles, 8, NULL) < 0)
return -1;
return git_vector_insert(&ctl->windowfiles, mwf);
}
......
......@@ -15,8 +15,8 @@ typedef struct git_mwindow {
struct git_mwindow *next;
git_map window_map;
git_off_t offset;
unsigned int last_used;
unsigned int inuse_cnt;
size_t last_used;
size_t inuse_cnt;
} git_mwindow;
typedef struct git_mwindow_file {
......@@ -37,7 +37,7 @@ typedef struct git_mwindow_ctl {
int git_mwindow_contains(git_mwindow *win, git_off_t offset);
void git_mwindow_free_all(git_mwindow_file *mwf);
unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor, git_off_t offset, int extra, unsigned int *left);
unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor, git_off_t offset, size_t extra, unsigned int *left);
void git_mwindow_scan_lru(git_mwindow_file *mwf, git_mwindow **lru_w, git_mwindow **lru_l);
int git_mwindow_file_register(git_mwindow_file *mwf);
void git_mwindow_close(git_mwindow **w_cursor);
......
......@@ -92,7 +92,7 @@ int git_object_lookup_prefix(
assert(repo && object_out && id);
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);
error = git_repository_odb__weakptr(&odb, repo);
......
......@@ -145,10 +145,8 @@ int git_odb__hashlink(git_oid *out, const char *path)
git_off_t size;
int result;
if (p_lstat(path, &st) < 0) {
giterr_set(GITERR_OS, "Failed to stat object '%s'", path);
if (git_path_lstat(path, &st) < 0)
return -1;
}
size = st.st_size;
......@@ -188,7 +186,7 @@ int git_odb_hashfile(git_oid *out, const char *path, git_otype type)
git_off_t size;
int result, fd = git_futils_open_ro(path);
if (fd < 0)
return -1;
return fd;
if ((size = git_futils_filesize(fd)) < 0 || !git__is_sizet(size)) {
giterr_set(GITERR_OS, "File size overflow for 32-bit systems");
......@@ -507,23 +505,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);
}
if (error == GIT_EPASSTHROUGH)
if (!error || error == GIT_EPASSTHROUGH)
return 0;
/*
* no backend could read only the header.
* try reading the whole object and freeing the contents
*/
if (error < 0) {
if ((error = git_odb_read(&object, db, id)) < GIT_SUCCESS)
return error; /* error already set - pass through */
*len_p = object->raw.len;
*type_p = object->raw.type;
git_odb_object_free(object);
}
if ((error = git_odb_read(&object, db, id)) < 0)
return error; /* error already set - pass along */
return GIT_SUCCESS;
*len_p = object->raw.len;
*type_p = object->raw.type;
git_odb_object_free(object);
return 0;
}
int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
......@@ -536,7 +531,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
*out = git_cache_get(&db->cache, id);
if (*out != NULL)
return GIT_SUCCESS;
return 0;
for (i = 0; i < db->backends.length && error < 0; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i);
......@@ -546,15 +541,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);
}
if (error == GIT_EPASSTHROUGH || error == GIT_SUCCESS) {
*out = git_cache_try_store(&db->cache, new_odb_object(id, &raw));
return GIT_SUCCESS;
}
if (error && error != GIT_EPASSTHROUGH)
return error;
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;
int error = GIT_ENOTFOUND;
......@@ -565,7 +560,7 @@ int git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_
assert(out && db);
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)
len = GIT_OID_HEXSZ;
......@@ -573,7 +568,7 @@ int git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_
if (len == GIT_OID_HEXSZ) {
*out = git_cache_get(&db->cache, short_id);
if (*out != NULL)
return GIT_SUCCESS;
return 0;
}
for (i = 0; i < db->backends.length && found < 2; ++i) {
......@@ -582,33 +577,24 @@ int git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_
if (b->read != NULL) {
error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, short_id, len);
switch (error) {
case GIT_SUCCESS:
if (!error)
found++;
break;
case GIT_ENOTFOUND:
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");
}
else if (error != GIT_ENOTFOUND && error != GIT_EPASSTHROUGH)
return error;
}
}
if (found == 1) {
*out = git_cache_try_store(&db->cache, new_odb_object(&full_oid, &raw));
} else if (found > 1) {
return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to read object. Ambiguous sha1 prefix");
} else {
return git__throw(GIT_ENOTFOUND, "Failed to read object. Object not found");
}
if (found == 0)
return git_odb__error_notfound("no match for prefix");
if (found > 1)
return git_odb__error_ambiguous("multiple matches for prefix");
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;
int error = GIT_ERROR;
......@@ -628,24 +614,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);
}
if (error == GIT_EPASSTHROUGH || error == GIT_SUCCESS)
return GIT_SUCCESS;
if (!error || error == GIT_EPASSTHROUGH)
return 0;
/* 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
* push */
if ((error = git_odb_open_wstream(&stream, db, len, type)) == GIT_SUCCESS) {
stream->write(stream, data, len);
error = stream->finalize_write(oid, stream);
stream->free(stream);
return GIT_SUCCESS;
}
if ((error = git_odb_open_wstream(&stream, db, len, type)) != 0)
return error;
return git__rethrow(error, "Failed to write object");
stream->write(stream, data, len);
error = stream->finalize_write(oid, stream);
stream->free(stream);
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;
int error = GIT_ERROR;
......@@ -666,10 +653,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);
}
if (error == GIT_EPASSTHROUGH || error == GIT_SUCCESS)
return GIT_SUCCESS;
if (error == GIT_EPASSTHROUGH)
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)
......@@ -687,9 +674,21 @@ int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oi
error = b->readstream(stream, b, oid);
}
if (error == GIT_EPASSTHROUGH || error == GIT_SUCCESS)
return GIT_SUCCESS;
if (error == GIT_EPASSTHROUGH)
error = 0;
return git__rethrow(error, "Failed to open read stream");
return error;
}
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);
*/
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
......@@ -61,8 +61,8 @@ static int object_file_name(git_buf *name, const char *dir, const git_oid *id)
git_buf_sets(name, dir);
/* expand length for 40 hex sha1 chars + 2 * '/' + '\0' */
if (git_buf_grow(name, name->size + GIT_OID_HEXSZ + 3) < GIT_SUCCESS)
return GIT_ENOMEM;
if (git_buf_grow(name, name->size + GIT_OID_HEXSZ + 3) < 0)
return -1;
git_path_to_dir(name);
......@@ -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->ptr[name->size] = '\0';
return GIT_SUCCESS;
return 0;
}
......@@ -199,10 +199,12 @@ static int finish_inflate(z_stream *s)
inflateEnd(s);
if ((status != Z_STREAM_END) || (s->avail_in != 0))
return git__throw(GIT_ERROR, "Failed to finish inflation. Stream aborted prematurely");
if ((status != Z_STREAM_END) || (s->avail_in != 0)) {
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)
......@@ -226,21 +228,24 @@ static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
zs.next_in = in;
zs.avail_in = (uInt)inlen;
if (inflateInit(&zs) < Z_OK)
return git__throw(GIT_ERROR, "Failed to inflate buffer");
if (inflateInit(&zs) < Z_OK) {
giterr_set(GITERR_ZLIB, "Failed to inflate buffer");
return -1;
}
while (status == Z_OK)
status = inflate(&zs, Z_FINISH);
inflateEnd(&zs);
if ((status != Z_STREAM_END) /*|| (zs.avail_in != 0) */)
return git__throw(GIT_ERROR, "Failed to inflate buffer. Stream aborted prematurely");
if (zs.total_out != outlen)
return git__throw(GIT_ERROR, "Failed to inflate buffer. Stream aborted prematurely");
if (status != Z_STREAM_END /* || zs.avail_in != 0 */ ||
zs.total_out != outlen)
{
giterr_set(GITERR_ZLIB, "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)
......@@ -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)
* binary encoding of the object type and size.
*/
if ((used = get_binary_object_header(&hdr, obj)) == 0)
return git__throw(GIT_ERROR, "Failed to inflate loose object. Object has no header");
if (!git_object_typeisloose(hdr.type))
return git__throw(GIT_ERROR, "Failed to inflate loose object. Wrong object type");
if ((used = get_binary_object_header(&hdr, obj)) == 0 ||
!git_object_typeisloose(hdr.type)) {
giterr_set(GITERR_ODB, "Failed to inflate loose object.");
return -1;
}
/*
* allocate a buffer and inflate the data into it
*/
buf = git__malloc(hdr.size + 1);
if (!buf)
return GIT_ENOMEM;
GITERR_CHECK_ALLOC(buf);
in = ((unsigned char *)obj->ptr) + 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);
return git__throw(GIT_ERROR, "Failed to inflate loose object. Could not inflate buffer");
return -1;
}
buf[hdr.size] = '\0';
......@@ -322,7 +326,7 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_buf *obj)
out->len = hdr.size;
out->type = hdr.type;
return GIT_SUCCESS;
return 0;
}
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
* to parse the object header (type and size).
*/
if (start_inflate(&zs, obj, head, sizeof(head)) < Z_OK)
return git__throw(GIT_ERROR, "Failed to inflate disk object. Could not inflate buffer");
if ((used = get_object_header(&hdr, head)) == 0)
return git__throw(GIT_ERROR, "Failed to inflate disk object. Object has no header");
if (!git_object_typeisloose(hdr.type))
return git__throw(GIT_ERROR, "Failed to inflate disk object. Wrong object type");
if (start_inflate(&zs, obj, head, sizeof(head)) < Z_OK ||
(used = get_object_header(&hdr, head)) == 0 ||
!git_object_typeisloose(hdr.type))
{
giterr_set(GITERR_ODB, "Failed to inflate disk object.");
return -1;
}
/*
* allocate a buffer and inflate the object data into it
* (including the initial sequence in the head buffer).
*/
if ((buf = inflate_tail(&zs, head, used, &hdr)) == NULL)
return GIT_ENOMEM;
return -1;
buf[hdr.size] = '\0';
out->data = buf;
out->len = hdr.size;
out->type = hdr.type;
return GIT_SUCCESS;
return 0;
}
......@@ -388,24 +391,23 @@ static int read_loose(git_rawobj *out, git_buf *loc)
assert(out && loc);
if (git_buf_oom(loc))
return GIT_ENOMEM;
return -1;
out->data = NULL;
out->len = 0;
out->type = GIT_OBJ_BAD;
if (git_futils_readbuffer(&obj, loc->ptr) < 0)
return git__throw(GIT_ENOTFOUND, "Failed to read loose object. File not found");
if (!(error = git_futils_readbuffer(&obj, loc->ptr)))
error = inflate_disk_obj(out, &obj);
error = inflate_disk_obj(out, &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)
{
int error = GIT_SUCCESS, z_return = Z_ERRNO, read_bytes;
int error = 0, z_return = Z_ERRNO, read_bytes;
git_file fd;
z_stream zs;
obj_hdr header_obj;
......@@ -414,48 +416,40 @@ static int read_header_loose(git_rawobj *out, git_buf *loc)
assert(out && loc);
if (git_buf_oom(loc))
return GIT_ENOMEM;
return -1;
out->data = NULL;
if ((fd = p_open(loc->ptr, O_RDONLY)) < 0)
return git__throw(GIT_ENOTFOUND, "Failed to read loose object header. File not found");
if ((fd = git_futils_open_ro(loc->ptr)) < 0)
return fd;
init_stream(&zs, inflated_buffer, sizeof(inflated_buffer));
if (inflateInit(&zs) < Z_OK) {
error = GIT_EZLIB;
goto cleanup;
}
z_return = inflateInit(&zs);
do {
if ((read_bytes = read(fd, raw_buffer, sizeof(raw_buffer))) > 0) {
while (z_return == Z_OK) {
if ((read_bytes = p_read(fd, raw_buffer, sizeof(raw_buffer))) > 0) {
set_stream_input(&zs, raw_buffer, read_bytes);
z_return = inflate(&zs, 0);
} else {
} else
z_return = Z_STREAM_END;
break;
}
} while (z_return == Z_OK);
}
if ((z_return != Z_STREAM_END && z_return != Z_BUF_ERROR)
|| get_object_header(&header_obj, inflated_buffer) == 0
|| git_object_typeisloose(header_obj.type) == 0) {
error = GIT_EOBJCORRUPTED;
goto cleanup;
|| git_object_typeisloose(header_obj.type) == 0)
{
giterr_set(GITERR_ZLIB, "Failed to read loose object header");
error = -1;
} else {
out->len = header_obj.size;
out->type = header_obj.type;
}
out->len = header_obj.size;
out->type = header_obj.type;
cleanup:
finish_inflate(&zs);
p_close(fd);
if (error < GIT_SUCCESS)
return git__throw(error, "Failed to read loose object header. Header is corrupted");
return GIT_SUCCESS;
return error;
}
static int locate_object(
......@@ -465,8 +459,8 @@ static int locate_object(
{
int error = object_file_name(object_location, backend->objects_dir, oid);
if (error == GIT_SUCCESS)
error = git_path_exists(git_buf_cstr(object_location)) ? GIT_SUCCESS : GIT_ENOTFOUND;
if (!error && !git_path_exists(object_location->ptr))
return GIT_ENOTFOUND;
return error;
}
......@@ -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) {
/* Entry cannot be an object. Continue to next entry */
return GIT_SUCCESS;
return 0;
}
if (git_path_isdir(pathbuf->ptr) == false) {
......@@ -495,10 +489,11 @@ static int fn_locate_object_short_oid(void *state, git_buf *pathbuf) {
sstate->found++;
}
}
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 */
......@@ -515,8 +510,8 @@ static int locate_object_short_oid(
int error;
/* prealloc memory for OBJ_DIR/xx/ */
if ((error = git_buf_grow(object_location, dir_len + 5)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to locate object from short oid");
if (git_buf_grow(object_location, dir_len + 5) < 0)
return -1;
git_buf_sets(object_location, objects_dir);
git_path_to_dir(object_location);
......@@ -528,46 +523,43 @@ static int locate_object_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 */
error = git_buf_printf(object_location, "%.2s/", state.short_oid);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to locate object from short oid");
if (git_buf_printf(object_location, "%.2s/", state.short_oid) < 0)
return -1;
/* Check that directory exists */
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.short_oid_len = len;
state.found = 0;
/* 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)
return git__rethrow(error, "Failed to locate object from short oid");
return error;
if (!state.found) {
return git__throw(GIT_ENOTFOUND, "Failed to locate object from short oid. Object not found");
}
if (!state.found)
return git_odb__error_notfound("failed to locate from short oid");
/* Convert obtained hex formatted oid to raw */
error = git_oid_fromstr(res_oid, (char *)state.res_oid);
if (error) {
return git__rethrow(error, "Failed to locate object from short oid");
}
if (error)
return error;
/* Update the location according to the oid obtained */
git_buf_truncate(object_location, dir_len);
error = git_buf_grow(object_location, dir_len + GIT_OID_HEXSZ + 2);
if (error)
return git__rethrow(error, "Failed to locate object from short oid");
if (git_buf_grow(object_location, dir_len + GIT_OID_HEXSZ + 2) < 0)
return -1;
git_oid_pathfmt(object_location->ptr + dir_len, res_oid);
object_location->size += GIT_OID_HEXSZ + 1;
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_
raw.type = GIT_OBJ_BAD;
if (locate_object(&object_path, (loose_backend *)backend, oid) < 0)
error = git__throw(GIT_ENOTFOUND, "Failed to read loose backend header. Object not found");
else if ((error = read_header_loose(&raw, &object_path)) == GIT_SUCCESS) {
error = git_odb__error_notfound("in loose backend");
else if ((error = read_header_loose(&raw, &object_path)) == 0) {
*len_p = raw.len;
*type_p = raw.type;
}
......@@ -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_rawobj raw;
int error = GIT_SUCCESS;
int error = 0;
assert(backend && oid);
if (locate_object(&object_path, (loose_backend *)backend, oid) < 0)
error = git__throw(GIT_ENOTFOUND, "Failed to read loose backend. Object not found");
else if ((error = read_loose(&raw, &object_path)) == GIT_SUCCESS) {
error = git_odb__error_notfound("in loose backend");
else if ((error = read_loose(&raw, &object_path)) == 0) {
*buffer_p = raw.data;
*len_p = raw.len;
*type_p = raw.type;
}
else {
git__rethrow(error, "Failed to read loose backend");
}
git_buf_free(&object_path);
......@@ -642,16 +631,15 @@ static int loose_backend__read_prefix(
const git_oid *short_oid,
unsigned int len)
{
int error = GIT_SUCCESS;
int error = 0;
if (len < GIT_OID_MINPREFIXLEN)
return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to read loose "
"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 */
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);
} else {
git_buf object_path = GIT_BUF_INIT;
......@@ -660,11 +648,9 @@ static int loose_backend__read_prefix(
assert(backend && short_oid);
if ((error = locate_object_short_oid(&object_path, out_oid,
(loose_backend *)backend, short_oid, len)) < 0)
git__rethrow(error, "Failed to read loose backend");
else if ((error = read_loose(&raw, &object_path)) < GIT_SUCCESS)
git__rethrow(error, "Failed to read loose backend");
else {
(loose_backend *)backend, short_oid, len)) == 0 &&
(error = read_loose(&raw, &object_path)) == 0)
{
*buffer_p = raw.data;
*len_p = raw.len;
*type_p = raw.type;
......@@ -687,47 +673,33 @@ static int loose_backend__exists(git_odb_backend *backend, const git_oid *oid)
git_buf_free(&object_path);
return (error == GIT_SUCCESS);
return !error;
}
static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream)
{
loose_writestream *stream = (loose_writestream *)_stream;
loose_backend *backend = (loose_backend *)_stream->backend;
int error;
git_buf final_path = GIT_BUF_INIT;
int error = 0;
if ((error = git_filebuf_hash(oid, &stream->fbuf)) < GIT_SUCCESS)
goto cleanup;
if ((error = object_file_name(&final_path, backend->objects_dir, oid)) < GIT_SUCCESS)
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;
if (git_filebuf_hash(oid, &stream->fbuf) < 0 ||
object_file_name(&final_path, backend->objects_dir, oid) < 0 ||
git_futils_mkpath2file(final_path.ptr, GIT_OBJECT_DIR_MODE) < 0)
error = -1;
/*
* Don't try to add an existing object to the repository. This
* is what git does and allows us to sidestep the fact that
* 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);
goto cleanup;
}
error = git_filebuf_commit_at(&stream->fbuf, final_path.ptr, GIT_OBJECT_FILE_MODE);
else
error = git_filebuf_commit_at(
&stream->fbuf, final_path.ptr, GIT_OBJECT_FILE_MODE);
cleanup:
git_buf_free(&final_path);
if (error < GIT_SUCCESS)
git__rethrow(error, "Failed to write loose backend");
return error;
}
......@@ -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);
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;
}
static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_backend, size_t length, git_otype type)
{
loose_backend *backend;
loose_writestream *stream;
loose_writestream *stream = NULL;
char hdr[64];
git_buf tmp_path = GIT_BUF_INIT;
int hdrlen;
int error;
assert(_backend);
......@@ -774,12 +742,9 @@ static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_
*stream_out = NULL;
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));
if (stream == NULL)
return GIT_ENOMEM;
GITERR_CHECK_ALLOC(stream);
stream->stream.backend = _backend;
stream->stream.read = NULL; /* read only */
......@@ -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.mode = GIT_STREAM_WRONLY;
error = git_buf_joinpath(&tmp_path, backend->objects_dir, "tmp_object");
if (error < GIT_SUCCESS)
goto cleanup;
error = git_filebuf_open(&stream->fbuf, tmp_path.ptr,
GIT_FILEBUF_HASH_CONTENTS |
GIT_FILEBUF_TEMPORARY |
(backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT));
if (error < GIT_SUCCESS)
goto cleanup;
error = stream->stream.write((git_odb_stream *)stream, hdr, hdrlen);
if (error < GIT_SUCCESS)
goto cleanup;
if (git_buf_joinpath(&tmp_path, backend->objects_dir, "tmp_object") < 0 ||
git_filebuf_open(&stream->fbuf, tmp_path.ptr,
GIT_FILEBUF_HASH_CONTENTS |
GIT_FILEBUF_TEMPORARY |
(backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT)) < 0 ||
stream->stream.write((git_odb_stream *)stream, hdr, hdrlen) < 0)
{
git_filebuf_cleanup(&stream->fbuf);
git__free(stream);
stream = NULL;
}
git_buf_free(&tmp_path);
*stream_out = (git_odb_stream *)stream;
return GIT_SUCCESS;
cleanup:
git_buf_free(&tmp_path);
git_filebuf_cleanup(&stream->fbuf);
git__free(stream);
return git__rethrow(error, "Failed to create loose backend stream");
return !stream ? -1 : 0;
}
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
backend = (loose_backend *)_backend;
/* prepare the header for the file */
{
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;
header_len = format_object_header(header, sizeof(header), len, type);
error = git_filebuf_open(&fbuf, final_path.ptr,
GIT_FILEBUF_HASH_CONTENTS |
GIT_FILEBUF_TEMPORARY |
(backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT));
if (error < GIT_SUCCESS)
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_TEMPORARY |
(backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT)) < 0)
{
error = -1;
goto cleanup;
}
git_filebuf_write(&fbuf, header, header_len);
git_filebuf_write(&fbuf, data, len);
git_filebuf_hash(oid, &fbuf);
error = object_file_name(&final_path, backend->objects_dir, oid);
if (error < GIT_SUCCESS)
goto cleanup;
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);
if (object_file_name(&final_path, backend->objects_dir, oid) < 0 ||
git_futils_mkpath2file(final_path.ptr, GIT_OBJECT_DIR_MODE) < 0 ||
git_filebuf_commit_at(&fbuf, final_path.ptr, GIT_OBJECT_FILE_MODE) < 0)
error = -1;
cleanup:
if (error < GIT_SUCCESS)
......@@ -883,14 +828,10 @@ int git_odb_backend_loose(
loose_backend *backend;
backend = git__calloc(1, sizeof(loose_backend));
if (backend == NULL)
return GIT_ENOMEM;
GITERR_CHECK_ALLOC(backend);
backend->objects_dir = git__strdup(objects_dir);
if (backend->objects_dir == NULL) {
git__free(backend);
return GIT_ENOMEM;
}
GITERR_CHECK_ALLOC(backend->objects_dir);
if (compression_level < 0)
compression_level = Z_BEST_SPEED;
......@@ -907,5 +848,5 @@ int git_odb_backend_loose(
backend->parent.free = &loose_backend__free;
*backend_out = (git_odb_backend *)backend;
return GIT_SUCCESS;
return 0;
}
......@@ -137,19 +137,19 @@ static int packfile_load__cb(void *_data, git_buf *path);
static int packfile_refresh_all(struct pack_backend *backend);
static int pack_entry_find(struct git_pack_entry *e,
struct pack_backend *backend, const git_oid *oid);
struct pack_backend *backend, const git_oid *oid);
/* Can find the offset of an object given
* a prefix of an identifier.
* Throws GIT_EAMBIGUOUSOIDPREFIX if short oid
* is ambiguous.
* Sets GIT_EAMBIGUOUS if short oid is ambiguous.
* This method assumes that len is between
* GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ.
*/
static int pack_entry_find_prefix(struct git_pack_entry *e,
struct pack_backend *backend,
const git_oid *short_oid,
unsigned int len);
static int pack_entry_find_prefix(
struct git_pack_entry *e,
struct pack_backend *backend,
const git_oid *short_oid,
unsigned int len);
......@@ -215,27 +215,22 @@ static int packfile_load__cb(void *_data, git_buf *path)
size_t i;
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) {
struct git_pack_file *p = git_vector_get(&backend->packs, i);
if (memcmp(p->pack_name, path->ptr, path->size - strlen(".idx")) == 0)
return GIT_SUCCESS;
return 0;
}
error = git_packfile_check(&pack, path->ptr);
if (error == GIT_ENOTFOUND) {
if (error == GIT_ENOTFOUND)
/* ignore missing .pack file as git does */
return GIT_SUCCESS;
} else if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to load packfile");
if (git_vector_insert(&backend->packs, pack) < GIT_SUCCESS) {
git__free(pack);
return GIT_ENOMEM;
}
else if (error < 0)
return error;
return GIT_SUCCESS;
return git_vector_insert(&backend->packs, pack);
}
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;
if (backend->pack_folder == NULL)
return GIT_SUCCESS;
return 0;
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) {
git_buf path = GIT_BUF_INIT;
......@@ -257,14 +252,15 @@ static int packfile_refresh_all(struct pack_backend *backend)
error = git_path_direach(&path, packfile_load__cb, (void *)backend);
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);
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)
......@@ -272,12 +268,12 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen
int error;
size_t i;
if ((error = packfile_refresh_all(backend)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to find pack entry");
if ((error = packfile_refresh_all(backend)) < 0)
return error;
if (backend->last_found &&
git_pack_entry_find(e, backend->last_found, oid, GIT_OID_HEXSZ) == GIT_SUCCESS)
return GIT_SUCCESS;
git_pack_entry_find(e, backend->last_found, oid, GIT_OID_HEXSZ) == 0)
return 0;
for (i = 0; i < backend->packs.length; ++i) {
struct git_pack_file *p;
......@@ -286,13 +282,13 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen
if (p == backend->last_found)
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;
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(
......@@ -305,16 +301,15 @@ static int pack_entry_find_prefix(
size_t i;
unsigned found = 0;
if ((error = packfile_refresh_all(backend)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to find pack entry");
if ((error = packfile_refresh_all(backend)) < 0)
return error;
if (backend->last_found) {
error = git_pack_entry_find(e, backend->last_found, short_oid, len);
if (error == GIT_EAMBIGUOUSOIDPREFIX) {
return git__rethrow(error, "Failed to find pack entry. Ambiguous sha1 prefix");
} else if (error == GIT_SUCCESS) {
if (error == GIT_EAMBIGUOUS)
return error;
if (!error)
found = 1;
}
}
for (i = 0; i < backend->packs.length; ++i) {
......@@ -325,24 +320,21 @@ static int pack_entry_find_prefix(
continue;
error = git_pack_entry_find(e, p, short_oid, len);
if (error == GIT_EAMBIGUOUSOIDPREFIX) {
return git__rethrow(error, "Failed to find pack entry. Ambiguous sha1 prefix");
} else if (error == GIT_SUCCESS) {
found++;
if (found > 1)
if (error == GIT_EAMBIGUOUS)
return error;
if (!error) {
if (++found > 1)
break;
backend->last_found = p;
}
}
if (!found) {
return git__rethrow(GIT_ENOTFOUND, "Failed to find pack entry");
} else if (found > 1) {
return git__rethrow(GIT_EAMBIGUOUSOIDPREFIX, "Failed to find pack entry. Ambiguous sha1 prefix");
} else {
return GIT_SUCCESS;
}
if (!found)
return git_odb__error_notfound("failed to find pack entry");
else if (found > 1)
return git_odb__error_ambiguous("found multiple pack entries");
else
return 0;
}
......@@ -374,17 +366,15 @@ static int pack_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p,
git_rawobj raw;
int error;
if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < 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(&e, (struct pack_backend *)backend, oid)) < 0 ||
(error = git_packfile_unpack(&raw, e.p, &e.offset)) < 0)
return error;
*buffer_p = raw.data;
*len_p = raw.len;
*type_p = raw.type;
return GIT_SUCCESS;
return 0;
}
static int pack_backend__read_prefix(
......@@ -396,40 +386,38 @@ static int pack_backend__read_prefix(
const git_oid *short_oid,
unsigned int len)
{
int error = 0;
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 */
int error = pack_backend__read(buffer_p, len_p, type_p, backend, short_oid);
if (error == GIT_SUCCESS)
error = pack_backend__read(buffer_p, len_p, type_p, backend, short_oid);
if (!error)
git_oid_cpy(out_oid, short_oid);
return error;
} else {
struct git_pack_entry e;
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");
*buffer_p = raw.data;
*len_p = raw.len;
*type_p = raw.type;
git_oid_cpy(out_oid, &e.sha1);
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;
*len_p = raw.len;
*type_p = raw.type;
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)
{
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)
......@@ -455,19 +443,16 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
{
struct pack_backend *backend = NULL;
git_buf path = GIT_BUF_INIT;
int error = GIT_SUCCESS;
backend = git__calloc(1, sizeof(struct pack_backend));
if (backend == NULL)
return GIT_ENOMEM;
error = git_vector_init(&backend->packs, 8, packfile_sort__cb);
if (error < GIT_SUCCESS)
goto cleanup;
GITERR_CHECK_ALLOC(backend);
error = git_buf_joinpath(&path, objects_dir, "pack");
if (error < GIT_SUCCESS)
goto cleanup;
if (git_vector_init(&backend->packs, 8, packfile_sort__cb) < 0 ||
git_buf_joinpath(&path, objects_dir, "pack") < 0)
{
git__free(backend);
return -1;
}
if (git_path_isdir(git_buf_cstr(&path)) == true) {
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)
*backend_out = (git_odb_backend *)backend;
cleanup:
if (error < GIT_SUCCESS)
git__free(backend);
git_buf_free(&path);
return error;
return 0;
}
......@@ -17,12 +17,12 @@
#include <zlib.h>
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(
git_rawobj *obj,
struct git_pack_file *p,
git_mwindow **w_curs,
off_t *curpos,
git_off_t *curpos,
size_t size,
git_otype type);
......@@ -34,12 +34,18 @@ int packfile_unpack_compressed(
* GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ.
*/
static int pack_entry_find_offset(
off_t *offset_out,
git_off_t *offset_out,
git_oid *found_oid,
struct git_pack_file *p,
const git_oid *short_oid,
unsigned int len);
static int packfile_error(const char *message)
{
giterr_set(GITERR_ODB, "Invalid pack file - %s", message);
return -1;
}
/***********************************************************
*
* PACK INDEX METHODS
......@@ -58,40 +64,31 @@ static int pack_index_check(const char *path, struct git_pack_file *p)
{
struct git_pack_idx_header *hdr;
uint32_t version, nr, i, *index;
void *idx_map;
size_t idx_size;
struct stat st;
/* TODO: properly open the file without access time */
git_file fd = p_open(path, O_RDONLY /*| O_NOATIME */);
int error;
/* TODO: properly open the file without access time using O_NOATIME */
git_file fd = git_futils_open_ro(path);
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) {
if (p_fstat(fd, &st) < 0 ||
!S_ISREG(st.st_mode) ||
!git__is_sizet(st.st_size) ||
(idx_size = (size_t)st.st_size) < 4 * 256 + 20 + 20)
{
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 (idx_size < 4 * 256 + 20 + 20) {
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);
p_close(fd);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to check index");
if (error < 0)
return error;
hdr = idx_map = p->index_map.data;
......@@ -100,7 +97,7 @@ static int pack_index_check(const char *path, struct git_pack_file *p)
if (version < 2 || version > 2) {
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
......@@ -116,7 +113,7 @@ static int pack_index_check(const char *path, struct git_pack_file *p)
uint32_t n = ntohl(index[i]);
if (n < nr) {
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;
}
......@@ -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) {
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) {
/*
......@@ -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) {
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->num_objects = nr;
return GIT_SUCCESS;
return 0;
}
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;
if (p->index_map.data)
return GIT_SUCCESS;
return 0;
idx_name = git__strdup(p->pack_name);
GITERR_CHECK_ALLOC(idx_name);
strcpy(idx_name + strlen(idx_name) - strlen(".pack"), ".idx");
error = pack_index_check(idx_name, p);
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(
struct git_pack_file *p,
git_mwindow **w_cursor,
off_t offset,
git_off_t offset,
unsigned int *left)
{
if (p->mwf.fd == -1 && packfile_open(p) < GIT_SUCCESS)
if (p->mwf.fd == -1 && packfile_open(p) < 0)
return NULL;
/* Since packfiles end in a hash of their content and it's
......@@ -233,7 +232,7 @@ int git_packfile_unpack_header(
git_otype *type_p,
git_mwindow_file *mwf,
git_mwindow **w_curs,
off_t *curpos)
git_off_t *curpos)
{
unsigned char *base;
unsigned int left;
......@@ -248,35 +247,34 @@ int git_packfile_unpack_header(
// base = pack_window_open(p, w_curs, *curpos, &left);
base = git_mwindow_open(mwf, w_curs, *curpos, 20, &left);
if (base == NULL)
return GIT_ENOMEM;
return -1;
used = packfile_unpack_header1(size_p, type_p, base, left);
if (used == 0)
return git__throw(GIT_EOBJCORRUPTED, "Header length is zero");
return packfile_error("header length is zero");
*curpos += used;
return GIT_SUCCESS;
return 0;
}
static int packfile_unpack_delta(
git_rawobj *obj,
struct git_pack_file *p,
git_mwindow **w_curs,
off_t *curpos,
git_off_t *curpos,
size_t delta_size,
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;
int error;
base_offset = get_delta_base(p, w_curs, curpos, delta_type, obj_offset);
if (base_offset == 0)
return git__throw(GIT_EOBJCORRUPTED, "Delta offset is zero");
if (base_offset < 0)
return git__rethrow(base_offset, "Failed to get delta base");
return packfile_error("delta offset is zero");
if (base_offset < 0) /* must actually be an error code */
return (int)base_offset;
git_mwindow_close(w_curs);
error = git_packfile_unpack(&base, p, &base_offset);
......@@ -287,35 +285,34 @@ static int packfile_unpack_delta(
*
* We'll need to do this in order to support thin packs.
*/
if (error < GIT_SUCCESS)
return git__rethrow(error, "Corrupted delta");
if (error < 0)
return error;
error = packfile_unpack_compressed(&delta, p, w_curs, curpos, delta_size, delta_type);
if (error < GIT_SUCCESS) {
if (error < 0) {
git__free(base.data);
return git__rethrow(error, "Corrupted delta");
return error;
}
obj->type = base.type;
error = git__delta_apply(obj,
base.data, base.len,
delta.data, delta.len);
error = git__delta_apply(obj, base.data, base.len, delta.data, delta.len);
git__free(base.data);
git__free(delta.data);
/* TODO: we might want to cache this shit. eventually */
//add_delta_base_cache(p, base_offset, base, base_size, *type);
return error; /* error set by git__delta_apply */
}
int git_packfile_unpack(
git_rawobj *obj,
struct git_pack_file *p,
off_t *obj_offset)
git_rawobj *obj,
struct git_pack_file *p,
git_off_t *obj_offset)
{
git_mwindow *w_curs = NULL;
off_t curpos = *obj_offset;
git_off_t curpos = *obj_offset;
int error;
size_t size = 0;
......@@ -330,8 +327,8 @@ int git_packfile_unpack(
obj->type = GIT_OBJ_BAD;
error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to unpack packfile");
if (error < 0)
return error;
switch (type) {
case GIT_OBJ_OFS_DELTA:
......@@ -351,33 +348,30 @@ int git_packfile_unpack(
break;
default:
error = GIT_EOBJCORRUPTED;
error = packfile_error("invalid packfile type in header");;
break;
}
git_mwindow_close(&w_curs);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to unpack object");
*obj_offset = curpos;
return GIT_SUCCESS;
return error;
}
int packfile_unpack_compressed(
git_rawobj *obj,
struct git_pack_file *p,
git_mwindow **w_curs,
off_t *curpos,
size_t size,
git_otype type)
git_rawobj *obj,
struct git_pack_file *p,
git_mwindow **w_curs,
git_off_t *curpos,
size_t size,
git_otype type)
{
int st;
z_stream stream;
unsigned char *buffer, *in;
buffer = git__malloc(size + 1);
memset(buffer, 0x0, size + 1);
buffer = git__calloc(1, size + 1);
GITERR_CHECK_ALLOC(buffer);
memset(&stream, 0, sizeof(stream));
stream.next_out = buffer;
......@@ -386,7 +380,8 @@ int packfile_unpack_compressed(
st = inflateInit(&stream);
if (st != Z_OK) {
git__free(buffer);
return git__throw(GIT_EZLIB, "Error in zlib");
giterr_set(GITERR_ZLIB, "Failed to inflate packfile");
return -1;
}
do {
......@@ -404,28 +399,29 @@ int packfile_unpack_compressed(
if ((st != Z_STREAM_END) || stream.total_out != size) {
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->len = size;
obj->data = buffer;
return GIT_SUCCESS;
return 0;
}
/*
* curpos is where the data starts, delta_obj_offset is the where the
* header starts
*/
off_t get_delta_base(
struct git_pack_file *p,
git_mwindow **w_curs,
off_t *curpos,
git_otype type,
off_t delta_obj_offset)
git_off_t get_delta_base(
struct git_pack_file *p,
git_mwindow **w_curs,
git_off_t *curpos,
git_otype type,
git_off_t delta_obj_offset)
{
unsigned char *base_info = pack_window_open(p, w_curs, *curpos, NULL);
off_t base_offset;
git_off_t base_offset;
git_oid unused;
/* pack_window_open() assured us we have [base_info, base_info + 20)
......@@ -463,8 +459,8 @@ off_t get_delta_base(
}
}
/* 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)
return git__rethrow(GIT_EPACKCORRUPTED, "Base entry delta is not in the same pack");
if (pack_entry_find_offset(&base_offset, &unused, p, (git_oid *)base_info, GIT_OID_HEXSZ) < 0)
return packfile_error("base entry delta is not in the same pack");
*curpos += 20;
} else
return 0;
......@@ -480,9 +476,9 @@ off_t get_delta_base(
static struct git_pack_file *packfile_alloc(int extra)
{
struct git_pack_file *p = git__malloc(sizeof(*p) + extra);
memset(p, 0, sizeof(*p));
p->mwf.fd = -1;
struct git_pack_file *p = git__calloc(1, sizeof(*p) + extra);
if (p != NULL)
p->mwf.fd = -1;
return p;
}
......@@ -510,24 +506,25 @@ static int packfile_open(struct git_pack_file *p)
git_oid sha1;
unsigned char *idx_sha1;
assert(p->index_map.data);
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 */
p->mwf.fd = p_open(p->pack_name, O_RDONLY);
if (p->mwf.fd < 0 || p_fstat(p->mwf.fd, &st) < GIT_SUCCESS)
return git__throw(GIT_EOSERR, "Failed to open packfile. File appears to be corrupted");
p->mwf.fd = git_futils_open_ro(p->pack_name);
if (p->mwf.fd < 0)
return p->mwf.fd;
if (git_mwindow_file_register(&p->mwf) < GIT_SUCCESS) {
p_close(p->mwf.fd);
return git__throw(GIT_ERROR, "Failed to register packfile windows");
}
if (p_fstat(p->mwf.fd, &st) < 0 ||
git_mwindow_file_register(&p->mwf) < 0)
goto cleanup;
/* If we created the struct before we had the pack we lack size. */
if (!p->mwf.size) {
if (!S_ISREG(st.st_mode))
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)
goto cleanup;
......@@ -537,44 +534,35 @@ static int packfile_open(struct git_pack_file *p)
*/
fd_flag = fcntl(p->mwf.fd, F_GETFD, 0);
if (fd_flag < 0)
return error("cannot determine file descriptor flags");
goto cleanup;
fd_flag |= FD_CLOEXEC;
if (fcntl(p->pack_fd, F_SETFD, fd_flag) == -1)
return GIT_EOSERR;
goto cleanup;
#endif
/* Verify we recognize this pack file format. */
if (p_read(p->mwf.fd, &hdr, sizeof(hdr)) < GIT_SUCCESS)
goto cleanup;
if (hdr.hdr_signature != htonl(PACK_SIGNATURE))
goto cleanup;
if (!pack_version_ok(hdr.hdr_version))
if (p_read(p->mwf.fd, &hdr, sizeof(hdr)) < 0 ||
hdr.hdr_signature != htonl(PACK_SIGNATURE) ||
!pack_version_ok(hdr.hdr_version))
goto cleanup;
/* Verify the pack matches its index. */
if (p->num_objects != ntohl(hdr.hdr_entries))
goto cleanup;
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)
if (p->num_objects != ntohl(hdr.hdr_entries) ||
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)
goto cleanup;
idx_sha1 = ((unsigned char *)p->index_map.data) + p->index_map.len - 40;
if (git_oid_cmp(&sha1, (git_oid *)idx_sha1) != 0)
goto cleanup;
return GIT_SUCCESS;
if (git_oid_cmp(&sha1, (git_oid *)idx_sha1) == 0)
return 0;
cleanup:
giterr_set(GITERR_OS, "Invalid packfile '%s'", p->pack_name);
p_close(p->mwf.fd);
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)
......@@ -586,6 +574,7 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path)
*pack_out = NULL;
path_len = strlen(path);
p = packfile_alloc(path_len + 2);
GITERR_CHECK_ALLOC(p);
/*
* 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)
path_len -= strlen(".idx");
if (path_len < 1) {
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);
......@@ -604,9 +593,9 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path)
p->pack_keep = 1;
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);
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
......@@ -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 */
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);
*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)
*
***********************************************************/
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;
index += 4 * 256;
......@@ -650,11 +640,11 @@ static off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n)
}
static int pack_entry_find_offset(
off_t *offset_out,
git_oid *found_oid,
struct git_pack_file *p,
const git_oid *short_oid,
unsigned int len)
git_off_t *offset_out,
git_oid *found_oid,
struct git_pack_file *p,
const git_oid *short_oid,
unsigned int len)
{
const uint32_t *level1_ofs = p->index_map.data;
const unsigned char *index = p->index_map.data;
......@@ -667,8 +657,8 @@ static int pack_entry_find_offset(
if (index == NULL) {
int error;
if ((error = pack_index_open(p)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to find offset for pack entry");
if ((error = pack_index_open(p)) < 0)
return error;
assert(p->index_map.data);
......@@ -726,22 +716,22 @@ static int pack_entry_find_offset(
}
}
if (!found) {
return git__throw(GIT_ENOTFOUND, "Failed to find offset for pack entry. Entry not found");
} else if (found > 1) {
return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to find offset for pack entry. Ambiguous sha1 prefix within pack");
} else {
*offset_out = nth_packed_object_offset(p, pos);
git_oid_fromraw(found_oid, current);
if (!found)
return git_odb__error_notfound("failed to find offset for pack entry");
if (found > 1)
return git_odb__error_ambiguous("found multiple offsets for pack entry");
*offset_out = nth_packed_object_offset(p, pos);
git_oid_fromraw(found_oid, current);
#ifdef INDEX_DEBUG_LOOKUP
{
unsigned char hex_sha1[GIT_OID_HEXSZ + 1];
git_oid_fmt(hex_sha1, found_oid);
hex_sha1[GIT_OID_HEXSZ] = '\0';
printf("found lo=%d %s\n", lo, hex_sha1);
#endif
return GIT_SUCCESS;
}
#endif
return 0;
}
int git_pack_entry_find(
......@@ -750,7 +740,7 @@ int git_pack_entry_find(
const git_oid *short_oid,
unsigned int len)
{
off_t offset;
git_off_t offset;
git_oid found_oid;
int error;
......@@ -760,22 +750,22 @@ int git_pack_entry_find(
unsigned i;
for (i = 0; i < p->num_bad_objects; i++)
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);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to find pack entry. Couldn't find offset");
if (error < 0)
return error;
/* we found a unique entry in the index;
* make sure the packfile backing the index
* still exists on disk */
if (p->mwf.fd == -1 && packfile_open(p) < GIT_SUCCESS)
return git__throw(GIT_EOSERR, "Failed to find pack entry. Packfile doesn't exist on disk");
if (p->mwf.fd == -1 && (error = packfile_open(p)) < 0)
return error;
e->offset = offset;
e->p = p;
git_oid_cpy(&e->sha1, &found_oid);
return GIT_SUCCESS;
return 0;
}
......@@ -70,7 +70,7 @@ struct git_pack_file {
};
struct git_pack_entry {
off_t offset;
git_off_t offset;
git_oid sha1;
struct git_pack_file *p;
};
......@@ -80,13 +80,13 @@ int git_packfile_unpack_header(
git_otype *type_p,
git_mwindow_file *mwf,
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,
off_t *curpos, git_otype type,
off_t delta_obj_offset);
git_off_t get_delta_base(struct git_pack_file *p, git_mwindow **w_curs,
git_off_t *curpos, git_otype type,
git_off_t delta_obj_offset);
void packfile_free(struct git_pack_file *p);
int git_packfile_check(struct git_pack_file **pack_out, const char *path);
......
......@@ -49,16 +49,14 @@ int git_path_basename_r(git_buf *buffer, const char *path)
while (startp > path && *(startp - 1) != '/')
startp--;
len = endp - startp +1;
/* Cast is safe because max path < max int */
len = (int)(endp - startp + 1);
Exit:
result = len;
if (buffer != NULL) {
if (git_buf_set(buffer, startp, len) < GIT_SUCCESS)
return git__rethrow(GIT_ENOMEM,
"Could not get basename of '%s'", path);
}
if (buffer != NULL && git_buf_set(buffer, startp, len) < 0)
return -1;
return result;
}
......@@ -99,7 +97,8 @@ int git_path_dirname_r(git_buf *buffer, const char *path)
endp--;
} while (endp > path && *endp == '/');
len = endp - path +1;
/* Cast is safe because max path < max int */
len = (int)(endp - path + 1);
#ifdef GIT_WIN32
/* Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return
......@@ -114,11 +113,8 @@ int git_path_dirname_r(git_buf *buffer, const char *path)
Exit:
result = len;
if (buffer != NULL) {
if (git_buf_set(buffer, path, len) < GIT_SUCCESS)
return git__rethrow(GIT_ENOMEM,
"Could not get dirname of '%s'", path);
}
if (buffer != NULL && git_buf_set(buffer, path, len) < 0)
return -1;
return result;
}
......@@ -152,7 +148,7 @@ char *git_path_basename(const char *path)
const char *git_path_topdir(const char *path)
{
size_t len;
int i;
ssize_t i;
assert(path);
len = strlen(path);
......@@ -160,7 +156,7 @@ const char *git_path_topdir(const char *path)
if (!len || path[len - 1] != '/')
return NULL;
for (i = len - 2; i >= 0; --i)
for (i = (ssize_t)len - 2; i >= 0; --i)
if (path[i] == '/')
break;
......@@ -199,7 +195,8 @@ int git_path_prettify(git_buf *path_out, const char *path, const char *base)
}
if (p_realpath(path, buf) == NULL) {
giterr_set(GITERR_OS, "Failed to resolve path '%s': %s", path, strerror(errno));
giterr_set(GITERR_OS, "Failed to resolve path '%s': %s",
path, strerror(errno));
return (errno == ENOENT) ? GIT_ENOTFOUND : -1;
}
......@@ -211,10 +208,8 @@ int git_path_prettify(git_buf *path_out, const char *path, const char *base)
int git_path_prettify_dir(git_buf *path_out, const char *path, const char *base)
{
if (git_path_prettify(path_out, path, base) < 0)
return -1;
return git_path_to_dir(path_out);
int error = git_path_prettify(path_out, path, base);
return (error < 0) ? error : git_path_to_dir(path_out);
}
int git_path_to_dir(git_buf *path)
......@@ -224,10 +219,7 @@ int git_path_to_dir(git_buf *path)
path->ptr[path->size - 1] != '/')
git_buf_putc(path, '/');
if (git_buf_oom(path))
return -1;
return 0;
return git_buf_oom(path) ? -1 : 0;
}
void git_path_string_to_dir(char* path, size_t size)
......@@ -242,10 +234,10 @@ void git_path_string_to_dir(char* path, size_t size)
int git__percent_decode(git_buf *decoded_out, const char *input)
{
int len, hi, lo, i, error = GIT_SUCCESS;
int len, hi, lo, i;
assert(decoded_out && input);
len = strlen(input);
len = (int)strlen(input);
git_buf_clear(decoded_out);
for(i = 0; i < len; i++)
......@@ -268,39 +260,40 @@ int git__percent_decode(git_buf *decoded_out, const char *input)
i += 2;
append:
error = git_buf_putc(decoded_out, c);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to percent decode '%s'.", input);
if (git_buf_putc(decoded_out, c) < 0)
return -1;
}
return error;
return 0;
}
static int error_invalid_local_file_uri(const char *uri)
{
giterr_set(GITERR_CONFIG, "'%s' is not a valid local file URI", uri);
return -1;
}
int git_path_fromurl(git_buf *local_path_out, const char *file_url)
{
int error = GIT_SUCCESS, offset = 0, len;
int offset = 0, len;
assert(local_path_out && file_url);
if (git__prefixcmp(file_url, "file://") != 0)
return git__throw(GIT_EINVALIDPATH,
"Parsing of '%s' failed. A file Uri is expected (ie. with 'file://' scheme).",
file_url);
return error_invalid_local_file_uri(file_url);
offset += 7;
len = strlen(file_url);
len = (int)strlen(file_url);
if (offset < len && file_url[offset] == '/')
offset++;
else if (offset < len && git__prefixcmp(file_url + offset, "localhost/") == 0)
offset += 10;
else
return git__throw(GIT_EINVALIDPATH,
"Parsing of '%s' failed. A local file Uri is expected.", file_url);
return error_invalid_local_file_uri(file_url);
if (offset >= len || file_url[offset] == '/')
return git__throw(GIT_EINVALIDPATH,
"Parsing of '%s' failed. Invalid file Uri format.", file_url);
return error_invalid_local_file_uri(file_url);
#ifndef _MSC_VER
offset--; /* A *nix absolute path starts with a forward slash */
......@@ -308,11 +301,7 @@ int git_path_fromurl(git_buf *local_path_out, const char *file_url)
git_buf_clear(local_path_out);
error = git__percent_decode(local_path_out, file_url + offset);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Parsing of '%s' failed.", file_url);
return error;
return git__percent_decode(local_path_out, file_url + offset);
}
int git_path_walk_up(
......@@ -321,7 +310,7 @@ int git_path_walk_up(
int (*cb)(void *data, git_buf *),
void *data)
{
int error = GIT_SUCCESS;
int error = 0;
git_buf iter;
ssize_t stop = 0, scan;
char oldc = '\0';
......@@ -341,7 +330,7 @@ int git_path_walk_up(
iter.asize = path->asize;
while (scan >= stop) {
if ((error = cb(data, &iter)) < GIT_SUCCESS)
if ((error = cb(data, &iter)) < 0)
break;
iter.ptr[scan] = oldc;
scan = git_buf_rfind_next(&iter, '/');
......@@ -394,6 +383,18 @@ bool git_path_isfile(const char *path)
return S_ISREG(st.st_mode) != 0;
}
int git_path_lstat(const char *path, struct stat *st)
{
int err = 0;
if (p_lstat(path, st) < 0) {
err = (errno == ENOENT) ? GIT_ENOTFOUND : -1;
giterr_set(GITERR_OS, "Failed to stat file '%s'", path);
}
return err;
}
static bool _check_dir_contents(
git_buf *dir,
const char *sub,
......@@ -434,25 +435,24 @@ bool git_path_contains_file(git_buf *base, const char *file)
int git_path_find_dir(git_buf *dir, const char *path, const char *base)
{
int error = GIT_SUCCESS;
int error;
if (base != NULL && git_path_root(path) < 0)
error = git_buf_joinpath(dir, base, path);
else
error = git_buf_sets(dir, path);
if (error == GIT_SUCCESS) {
if (!error) {
char buf[GIT_PATH_MAX];
if (p_realpath(dir->ptr, buf) != NULL)
error = git_buf_sets(dir, buf);
}
/* call dirname if this is not a directory */
if (error == GIT_SUCCESS && git_path_isdir(dir->ptr) == false)
if (git_path_dirname_r(dir, dir->ptr) < GIT_SUCCESS)
error = GIT_ENOMEM;
if (!error && git_path_isdir(dir->ptr) == false)
error = git_path_dirname_r(dir, dir->ptr);
if (error == GIT_SUCCESS)
if (!error)
error = git_path_to_dir(dir);
return error;
......@@ -497,9 +497,9 @@ int git_path_direach(
return -1;
wd_len = path->size;
dir = opendir(path->ptr);
if (!dir) {
giterr_set(GITERR_OS, "Failed to 'opendir' %s", path->ptr);
if ((dir = opendir(path->ptr)) == NULL) {
giterr_set(GITERR_OS, "Failed to open directory '%s'", path->ptr);
return -1;
}
......@@ -541,9 +541,10 @@ int git_path_dirload(
path_len = strlen(path);
assert(path_len > 0 && path_len >= prefix_len);
if ((dir = opendir(path)) == NULL)
return git__throw(GIT_EOSERR, "Failed to process `%s` tree structure."
" An error occured while opening the directory", path);
if ((dir = opendir(path)) == NULL) {
giterr_set(GITERR_OS, "Failed to open directory '%s'", path);
return -1;
}
path += prefix_len;
path_len -= prefix_len;
......@@ -560,8 +561,7 @@ int git_path_dirload(
entry_path = git__malloc(
path_len + need_slash + entry_len + 1 + alloc_extra);
if (entry_path == NULL)
return GIT_ENOMEM;
GITERR_CHECK_ALLOC(entry_path);
if (path_len)
memcpy(entry_path, path, path_len);
......@@ -570,19 +570,16 @@ int git_path_dirload(
memcpy(&entry_path[path_len + need_slash], de->d_name, entry_len);
entry_path[path_len + need_slash + entry_len] = '\0';
if ((error = git_vector_insert(contents, entry_path)) < GIT_SUCCESS) {
git__free(entry_path);
return error;
}
if (git_vector_insert(contents, entry_path) < 0)
return -1;
}
closedir(dir);
if (error != GIT_SUCCESS)
return git__throw(
GIT_EOSERR, "Failed to process directory entry in `%s`", path);
if (error != 0)
giterr_set(GITERR_OS, "Failed to process directory entry in '%s'", path);
return GIT_SUCCESS;
return error;
}
int git_path_with_stat_cmp(const void *a, const void *b)
......@@ -601,11 +598,12 @@ int git_path_dirload_with_stat(
git_path_with_stat *ps;
git_buf full = GIT_BUF_INIT;
if ((error = git_buf_set(&full, path, prefix_len)) != GIT_SUCCESS)
return error;
if (git_buf_set(&full, path, prefix_len) < 0)
return -1;
if ((error = git_path_dirload(path, prefix_len,
sizeof(git_path_with_stat) + 1, contents)) != GIT_SUCCESS) {
error = git_path_dirload(
path, prefix_len, sizeof(git_path_with_stat) + 1, contents);
if (error < 0) {
git_buf_free(&full);
return error;
}
......@@ -616,8 +614,10 @@ int git_path_dirload_with_stat(
memmove(ps->path, ps, path_len + 1);
ps->path_len = path_len;
git_buf_joinpath(&full, full.ptr, ps->path);
p_lstat(full.ptr, &ps->st);
if ((error = git_buf_joinpath(&full, full.ptr, ps->path)) < 0 ||
(error = git_path_lstat(full.ptr, &ps->st)) < 0)
break;
git_buf_truncate(&full, prefix_len);
if (S_ISDIR(ps->st.st_mode)) {
......
......@@ -130,6 +130,11 @@ extern bool git_path_isdir(const char *path);
extern bool git_path_isfile(const char *path);
/**
* Stat a file and/or link and set error if needed.
*/
extern int git_path_lstat(const char *path, struct stat *st);
/**
* Check if the parent directory contains the item.
*
* @param dir Directory to check.
......
......@@ -34,9 +34,9 @@ int p_getcwd(char *buffer_out, size_t size)
return -1;
git_path_mkposix(buffer_out);
git_path_string_to_dir(buffer_out, size); //Ensure the path ends with a trailing slash
git_path_string_to_dir(buffer_out, size); /* append trailing slash */
return GIT_SUCCESS;
return 0;
}
int p_rename(const char *from, const char *to)
......
......@@ -842,7 +842,7 @@ static int reference_path_available(
if (!data.available) {
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;
}
......@@ -902,7 +902,7 @@ static int reference_can_write(
* the rename; the existing one would be overwritten */
if (exists) {
giterr_set(GITERR_REFERENCE,
"A reference with that name (%s) already exists");
"A reference with that name (%s) already exists", refname);
return GIT_EEXISTS;
}
}
......
......@@ -377,17 +377,15 @@ void git_repository_set_index(git_repository *repo, git_index *index)
static int retrieve_device(dev_t *device_out, const char *path)
{
int error;
struct stat path_info;
assert(device_out);
if (p_lstat(path, &path_info)) {
giterr_set(GITERR_OS, "Failed to retrieve file information: %s", strerror(errno));
return -1;
}
if ((error = git_path_lstat(path, &path_info)) == 0)
*device_out = path_info.st_dev;
*device_out = path_info.st_dev;
return 0;
return error;
}
/*
......
......@@ -17,12 +17,7 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs
int mprot = 0;
int mflag = 0;
assert((out != NULL) && (len > 0));
if ((out == NULL) || (len == 0)) {
errno = EINVAL;
return git__throw(GIT_ERROR, "Failed to mmap. No map or zero length");
}
GIT_MMAP_VALIDATE(out, len, prot, flags);
out->data = NULL;
out->len = 0;
......@@ -31,39 +26,28 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs
mprot = PROT_WRITE;
else if (prot & GIT_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)
mflag = MAP_SHARED;
else if ((flags & GIT_MAP_TYPE) == GIT_MAP_PRIVATE)
mflag = MAP_PRIVATE;
if (flags & GIT_MAP_FIXED) {
errno = EINVAL;
return git__throw(GIT_ERROR, "Failed to mmap. FIXED not set");
out->data = mmap(NULL, len, mprot, mflag, fd, offset);
if (!out->data || out->data == MAP_FAILED) {
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;
return GIT_SUCCESS;
return 0;
}
int p_munmap(git_map *map)
{
assert(map != NULL);
if (!map)
return git__throw(GIT_ERROR, "Failed to munmap. Map does not exist");
munmap(map->data, map->len);
return GIT_SUCCESS;
return 0;
}
#endif
......
......@@ -27,8 +27,8 @@ static int init_filter(char *filter, size_t n, const char *dir)
git__DIR *git__opendir(const char *dir)
{
char filter[4096];
wchar_t* filter_w;
git__DIR *new;
wchar_t* filter_w = NULL;
git__DIR *new = NULL;
if (!dir || !init_filter(filter, sizeof(filter), dir))
return NULL;
......@@ -37,25 +37,29 @@ git__DIR *git__opendir(const char *dir)
if (!new)
return NULL;
new->dir = git__malloc(strlen(dir)+1);
if (!new->dir) {
git__free(new);
return NULL;
}
strcpy(new->dir, dir);
new->dir = git__strdup(dir);
if (!new->dir)
goto fail;
filter_w = gitwin_to_utf16(filter);
if (!filter_w)
goto fail;
new->h = FindFirstFileW(filter_w, &new->f);
git__free(filter_w);
if (new->h == INVALID_HANDLE_VALUE) {
git__free(new->dir);
git__free(new);
return NULL;
giterr_set(GITERR_OS, "Could not open directory '%s'", dir);
goto fail;
}
new->first = 1;
new->first = 1;
return new;
fail:
git__free(new->dir);
git__free(new);
return NULL;
}
int git__readdir_ext(
......@@ -67,22 +71,32 @@ int git__readdir_ext(
if (!d || !entry || !result || d->h == INVALID_HANDLE_VALUE)
return -1;
*result = NULL;
if (d->first)
d->first = 0;
else if (!FindNextFileW(d->h, &d->f)) {
*result = NULL;
return 0;
if (GetLastError() == ERROR_NO_MORE_FILES)
return 0;
giterr_set(GITERR_OS, "Could not read from directory '%s'", d->dir);
return -1;
}
if (wcslen(d->f.cFileName) >= sizeof(entry->d_name))
return -1;
entry->d_ino = 0;
WideCharToMultiByte(
if (WideCharToMultiByte(
gitwin_get_codepage(), 0, d->f.cFileName, -1,
entry->d_name, GIT_PATH_MAX, NULL, NULL);
entry->d_name, GIT_PATH_MAX, NULL, NULL) == 0)
{
giterr_set(GITERR_OS, "Could not convert filename to UTF-8");
return -1;
}
*result = entry;
if (is_dir != NULL)
*is_dir = ((d->f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
......@@ -102,32 +116,40 @@ void git__rewinddir(git__DIR *d)
char filter[4096];
wchar_t* filter_w;
if (d) {
if (d->h != INVALID_HANDLE_VALUE)
FindClose(d->h);
if (!d)
return;
if (d->h != INVALID_HANDLE_VALUE) {
FindClose(d->h);
d->h = INVALID_HANDLE_VALUE;
d->first = 0;
}
if (init_filter(filter, sizeof(filter), d->dir)) {
filter_w = gitwin_to_utf16(filter);
d->h = FindFirstFileW(filter_w, &d->f);
git__free(filter_w);
if (!init_filter(filter, sizeof(filter), d->dir) ||
(filter_w = gitwin_to_utf16(filter)) == NULL)
return;
if (d->h != INVALID_HANDLE_VALUE)
d->first = 1;
}
}
d->h = FindFirstFileW(filter_w, &d->f);
git__free(filter_w);
if (d->h == INVALID_HANDLE_VALUE)
giterr_set(GITERR_OS, "Could not open directory '%s'", d->dir);
else
d->first = 1;
}
int git__closedir(git__DIR *d)
{
if (d) {
if (d->h != INVALID_HANDLE_VALUE)
FindClose(d->h);
if (d->dir)
git__free(d->dir);
git__free(d);
if (!d)
return 0;
if (d->h != INVALID_HANDLE_VALUE) {
FindClose(d->h);
d->h = INVALID_HANDLE_VALUE;
}
git__free(d->dir);
d->dir = NULL;
git__free(d);
return 0;
}
......@@ -33,12 +33,7 @@ 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_offset;
assert((out != NULL) && (len > 0));
if ((out == NULL) || (len == 0)) {
errno = EINVAL;
return git__throw(GIT_ERROR, "Failed to mmap. No map or zero length");
}
GIT_MMAP_VALIDATE(out, len, prot, flags);
out->data = NULL;
out->len = 0;
......@@ -46,86 +41,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) {
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)
fmap_prot |= PAGE_READWRITE;
else if (prot & GIT_PROT_READ)
fmap_prot |= PAGE_READONLY;
else {
errno = EINVAL;
return git__throw(GIT_ERROR, "Failed to mmap. Invalid protection parameters");
}
if (prot & GIT_PROT_WRITE)
view_prot |= FILE_MAP_WRITE;
if (prot & GIT_PROT_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_offset = offset - page_start;
if (page_offset != 0) { /* offset must be multiple of page size */
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);
if (!out->fmh || out->fmh == INVALID_HANDLE_VALUE) {
/* errno = ? */
giterr_set(GITERR_OS, "Failed to mmap. Invalid handle value");
out->fmh = NULL;
return git__throw(GIT_ERROR, "Failed to mmap. Invalid handle value");
return -1;
}
assert(sizeof(git_off_t) == 8);
off_low = (DWORD)(page_start);
off_hi = (DWORD)(page_start >> 32);
out->data = MapViewOfFile(out->fmh, view_prot, off_hi, off_low, len);
if (!out->data) {
/* errno = ? */
giterr_set(GITERR_OS, "Failed to mmap. No data written");
CloseHandle(out->fmh);
out->fmh = NULL;
return git__throw(GIT_ERROR, "Failed to mmap. No data written");
return -1;
}
out->len = len;
return GIT_SUCCESS;
return 0;
}
int p_munmap(git_map *map)
{
assert(map != NULL);
int error = 0;
if (!map)
return git__throw(GIT_ERROR, "Failed to munmap. Map does not exist");
assert(map != NULL);
if (map->data) {
if (!UnmapViewOfFile(map->data)) {
/* errno = ? */
CloseHandle(map->fmh);
map->data = NULL;
map->fmh = NULL;
return git__throw(GIT_ERROR, "Failed to munmap. Could not unmap view of file");
giterr_set(GITERR_OS, "Failed to munmap. Could not unmap view of file");
error = -1;
}
map->data = NULL;
}
if (map->fmh) {
if (!CloseHandle(map->fmh)) {
/* errno = ? */
map->fmh = NULL;
return git__throw(GIT_ERROR, "Failed to munmap. Could not close handle");
giterr_set(GITERR_OS, "Failed to munmap. Could not close handle");
error = -1;
}
map->fmh = NULL;
}
return GIT_SUCCESS;
return error;
}
/ < 0)
/*
* Copyright (C) 2009-2012 the libgit2 contributors
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
......@@ -17,10 +17,11 @@ int p_unlink(const char *path)
int ret = 0;
wchar_t* buf;
buf = gitwin_to_utf16(path);
_wchmod(buf, 0666);
ret = _wunlink(buf);
git__free(buf);
if ((buf = gitwin_to_utf16(path)) != NULL) {
_wchmod(buf, 0666);
ret = _wunlink(buf);
git__free(buf);
}
return ret;
}
......@@ -60,6 +61,8 @@ static int do_lstat(const char *file_name, struct stat *buf)
{
WIN32_FILE_ATTRIBUTE_DATA fdata;
wchar_t* fbuf = gitwin_to_utf16(file_name);
if (!fbuf)
return -1;
if (GetFileAttributesExW(fbuf, GetFileExInfoStandard, &fdata)) {
int fMode = S_IREAD;
......@@ -87,54 +90,43 @@ static int do_lstat(const char *file_name, struct stat *buf)
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
git__free(fbuf);
return GIT_SUCCESS;
return 0;
}
git__free(fbuf);
switch (GetLastError()) {
case ERROR_ACCESS_DENIED:
case ERROR_SHARING_VIOLATION:
case ERROR_LOCK_VIOLATION:
case ERROR_SHARING_BUFFER_EXCEEDED:
return GIT_EOSERR;
case ERROR_BUFFER_OVERFLOW:
case ERROR_NOT_ENOUGH_MEMORY:
return GIT_ENOMEM;
default:
return GIT_EINVALIDPATH;
}
return -1;
}
int p_lstat(const char *file_name, struct stat *buf)
{
int namelen, error;
char alt_name[GIT_PATH_MAX];
int error;
size_t namelen;
char *alt_name;
if ((error = do_lstat(file_name, buf)) == GIT_SUCCESS)
return GIT_SUCCESS;
if (do_lstat(file_name, buf) == 0)
return 0;
/* if file_name ended in a '/', Windows returned ENOENT;
* try again without trailing slashes
*/
if (error != GIT_EINVALIDPATH)
return git__throw(GIT_EOSERR, "Failed to lstat file");
namelen = strlen(file_name);
if (namelen && file_name[namelen-1] != '/')
return git__throw(GIT_EOSERR, "Failed to lstat file");
return -1;
while (namelen && file_name[namelen-1] == '/')
--namelen;
if (!namelen || namelen >= GIT_PATH_MAX)
return git__throw(GIT_ENOMEM, "Failed to lstat file");
if (!namelen)
return -1;
alt_name = git__strndup(file_name, namelen);
if (!alt_name)
return -1;
error = do_lstat(alt_name, buf);
memcpy(alt_name, file_name, namelen);
alt_name[namelen] = 0;
return do_lstat(alt_name, buf);
git__free(alt_name);
return error;
}
int p_readlink(const char *link, char *target, size_t target_len)
......@@ -145,6 +137,9 @@ int p_readlink(const char *link, char *target, size_t target_len)
DWORD dwRet;
wchar_t* link_w;
wchar_t* target_w;
int error = 0;
assert(link && target && target_len > 0);
/*
* Try to load the pointer to pGetFinalPath dynamically, because
......@@ -156,12 +151,15 @@ int p_readlink(const char *link, char *target, size_t target_len)
if (library != NULL)
pGetFinalPath = (fpath_func)GetProcAddress(library, "GetFinalPathNameByHandleW");
if (pGetFinalPath == NULL)
return git__throw(GIT_EOSERR,
if (pGetFinalPath == NULL) {
giterr_set(GITERR_OS,
"'GetFinalPathNameByHandleW' is not available in this platform");
return -1;
}
}
link_w = gitwin_to_utf16(link);
GITERR_CHECK_ALLOC(link_w);
hFile = CreateFileW(link_w, // file to open
GENERIC_READ, // open for reading
......@@ -173,50 +171,49 @@ int p_readlink(const char *link, char *target, size_t target_len)
git__free(link_w);
if (hFile == INVALID_HANDLE_VALUE)
return GIT_EOSERR;
if (target_len <= 0) {
return GIT_EINVALIDARGS;
if (hFile == INVALID_HANDLE_VALUE) {
giterr_set(GITERR_OS, "Cannot open '%s' for reading", link);
return -1;
}
target_w = (wchar_t*)git__malloc(target_len * sizeof(wchar_t));
GITERR_CHECK_ALLOC(target_w);
dwRet = pGetFinalPath(hFile, target_w, target_len, 0x0);
if (dwRet >= target_len) {
git__free(target_w);
CloseHandle(hFile);
return GIT_ENOMEM;
}
if (!WideCharToMultiByte(CP_UTF8, 0, target_w, -1, target, target_len * sizeof(char), NULL, NULL)) {
git__free(target_w);
return GIT_EOSERR;
}
if (dwRet == 0 ||
dwRet >= target_len ||
!WideCharToMultiByte(CP_UTF8, 0, target_w, -1, target,
target_len * sizeof(char), NULL, NULL))
error = -1;
git__free(target_w);
CloseHandle(hFile);
if (dwRet > 4) {
/* Skip first 4 characters if they are "\\?\" */
if (target[0] == '\\' && target[1] == '\\' && target[2] == '?' && target[3] == '\\') {
char tmp[GIT_PATH_MAX];
unsigned int offset = 4;
dwRet -= 4;
/* \??\UNC\ */
if (dwRet > 7 && target[4] == 'U' && target[5] == 'N' && target[6] == 'C') {
offset += 2;
dwRet -= 2;
target[offset] = '\\';
}
memcpy(tmp, target + offset, dwRet);
memcpy(target, tmp, dwRet);
if (error)
return error;
/* Skip first 4 characters if they are "\\?\" */
if (dwRet > 4 &&
target[0] == '\\' && target[1] == '\\' &&
target[2] == '?' && target[3] == '\\')
{
unsigned int offset = 4;
dwRet -= 4;
/* \??\UNC\ */
if (dwRet > 7 &&
target[4] == 'U' && target[5] == 'N' && target[6] == 'C')
{
offset += 2;
dwRet -= 2;
target[offset] = '\\';
}
memmove(target, target + offset, dwRet);
}
target[dwRet] = '\0';
return dwRet;
}
......@@ -224,8 +221,9 @@ int p_open(const char *path, int flags)
{
int fd;
wchar_t* buf = gitwin_to_utf16(path);
if (!buf)
return -1;
fd = _wopen(buf, flags | _O_BINARY);
git__free(buf);
return fd;
}
......@@ -234,8 +232,9 @@ int p_creat(const char *path, mode_t mode)
{
int fd;
wchar_t* buf = gitwin_to_utf16(path);
if (!buf)
return -1;
fd = _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode);
git__free(buf);
return fd;
}
......@@ -243,15 +242,15 @@ int p_creat(const char *path, mode_t mode)
int p_getcwd(char *buffer_out, size_t size)
{
wchar_t* buf = (wchar_t*)git__malloc(sizeof(wchar_t) * (int)size);
int ret;
_wgetcwd(buf, (int)size);
if (!WideCharToMultiByte(CP_UTF8, 0, buf, -1, buffer_out, size, NULL, NULL)) {
git__free(buf);
return GIT_EOSERR;
}
ret = WideCharToMultiByte(
CP_UTF8, 0, buf, -1, buffer_out, size, NULL, NULL);
git__free(buf);
return GIT_SUCCESS;
return !ret ? -1 : 0;
}
int p_stat(const char* path, struct stat* buf)
......@@ -262,8 +261,10 @@ int p_stat(const char* path, struct stat* buf)
int p_chdir(const char* path)
{
wchar_t* buf = gitwin_to_utf16(path);
int ret = _wchdir(buf);
int ret;
if (!buf)
return -1;
ret = _wchdir(buf);
git__free(buf);
return ret;
}
......@@ -271,8 +272,10 @@ int p_chdir(const char* path)
int p_chmod(const char* path, mode_t mode)
{
wchar_t* buf = gitwin_to_utf16(path);
int ret = _wchmod(buf, mode);
int ret;
if (!buf)
return -1;
ret = _wchmod(buf, mode);
git__free(buf);
return ret;
}
......@@ -280,8 +283,10 @@ int p_chmod(const char* path, mode_t mode)
int p_rmdir(const char* path)
{
wchar_t* buf = gitwin_to_utf16(path);
int ret = _wrmdir(buf);
int ret;
if (!buf)
return -1;
ret = _wrmdir(buf);
git__free(buf);
return ret;
}
......@@ -290,11 +295,13 @@ int p_hide_directory__w32(const char *path)
{
int res;
wchar_t* buf = gitwin_to_utf16(path);
if (!buf)
return -1;
res = SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN);
git__free(buf);
return (res != 0) ? GIT_SUCCESS : GIT_ERROR; /* MSDN states a "non zero" value indicates a success */
return (res != 0) ? 0 : -1; /* MSDN states a "non zero" value indicates a success */
}
char *p_realpath(const char *orig_path, char *buffer)
......@@ -303,6 +310,9 @@ char *p_realpath(const char *orig_path, char *buffer)
wchar_t* orig_path_w = gitwin_to_utf16(orig_path);
wchar_t* buffer_w = (wchar_t*)git__malloc(GIT_PATH_MAX * sizeof(wchar_t));
if (!orig_path_w || !buffer_w)
return NULL;
ret = GetFullPathNameW(orig_path_w, GIT_PATH_MAX, buffer_w, NULL);
git__free(orig_path_w);
......@@ -339,7 +349,7 @@ int p_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr)
int len;
if (count == 0 || (len = _vsnprintf(buffer, count, format, argptr)) < 0)
return p_vscprintf(format, argptr);
return _vscprintf(format, argptr);
return len;
#else /* MinGW */
......@@ -365,10 +375,10 @@ int p_mkstemp(char *tmp_path)
{
#if defined(_MSC_VER)
if (_mktemp_s(tmp_path, strlen(tmp_path) + 1) != 0)
return GIT_EOSERR;
return -1;
#else
if (_mktemp(tmp_path) == NULL)
return GIT_EOSERR;
return -1;
#endif
return p_creat(tmp_path, 0744);
......@@ -377,15 +387,17 @@ int p_mkstemp(char *tmp_path)
int p_setenv(const char* name, const char* value, int overwrite)
{
if (overwrite != 1)
return EINVAL;
return -1;
return (SetEnvironmentVariableA(name, value) == 0 ? GIT_EOSERR : GIT_SUCCESS);
return (SetEnvironmentVariableA(name, value) == 0 ? -1 : 0);
}
int p_access(const char* path, mode_t mode)
{
wchar_t *buf = gitwin_to_utf16(path);
int ret;
if (!buf)
return -1;
ret = _waccess(buf, mode);
git__free(buf);
......@@ -393,13 +405,16 @@ int p_access(const char* path, mode_t mode)
return ret;
}
extern int p_rename(const char *from, const char *to)
int p_rename(const char *from, const char *to)
{
wchar_t *wfrom = gitwin_to_utf16(from);
wchar_t *wto = gitwin_to_utf16(to);
int ret;
ret = MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? GIT_SUCCESS : GIT_EOSERR;
if (!wfrom || !wto)
return -1;
ret = MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? 0 : -1;
git__free(wfrom);
git__free(wto);
......
......@@ -7,13 +7,16 @@
#include "pthread.h"
int pthread_create(pthread_t *GIT_RESTRICT thread,
const pthread_attr_t *GIT_RESTRICT attr,
void *(*start_routine)(void*), void *GIT_RESTRICT arg)
int pthread_create(
pthread_t *GIT_RESTRICT thread,
const pthread_attr_t *GIT_RESTRICT attr,
void *(*start_routine)(void*),
void *GIT_RESTRICT arg)
{
GIT_UNUSED(attr);
*thread = (pthread_t) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, arg, 0, NULL);
return *thread ? GIT_SUCCESS : git__throw(GIT_EOSERR, "Failed to create pthread");
*thread = (pthread_t) CreateThread(
NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, arg, 0, NULL);
return *thread ? 0 : -1;
}
int pthread_join(pthread_t thread, void **value_ptr)
......
......@@ -33,14 +33,14 @@ wchar_t* gitwin_to_utf16(const char* str)
wchar_t* ret;
int cb;
if (!str) {
if (!str)
return NULL;
}
cb = strlen(str) * sizeof(wchar_t);
if (cb == 0) {
ret = (wchar_t*)git__malloc(sizeof(wchar_t));
ret[0] = 0;
if (ret)
ret[0] = 0;
return ret;
}
......@@ -48,8 +48,11 @@ wchar_t* gitwin_to_utf16(const char* str)
cb += sizeof(wchar_t);
ret = (wchar_t*)git__malloc(cb);
if (!ret)
return NULL;
if (MultiByteToWideChar(_active_codepage, 0, str, -1, ret, cb) == 0) {
giterr_set(GITERR_OS, "Could not convert string to UTF-16");
git__free(ret);
ret = NULL;
}
......@@ -59,7 +62,10 @@ wchar_t* gitwin_to_utf16(const char* str)
int gitwin_append_utf16(wchar_t *buffer, const char *str, size_t len)
{
return MultiByteToWideChar(_active_codepage, 0, str, -1, buffer, len);
int result = MultiByteToWideChar(_active_codepage, 0, str, -1, buffer, len);
if (result == 0)
giterr_set(GITERR_OS, "Could not convert string to UTF-16");
return result;
}
char* gitwin_from_utf16(const wchar_t* str)
......@@ -74,7 +80,8 @@ char* gitwin_from_utf16(const wchar_t* str)
cb = wcslen(str) * sizeof(char);
if (cb == 0) {
ret = (char*)git__malloc(sizeof(char));
ret[0] = 0;
if (ret)
ret[0] = 0;
return ret;
}
......@@ -82,8 +89,11 @@ char* gitwin_from_utf16(const wchar_t* str)
cb += sizeof(char);
ret = (char*)git__malloc(cb);
if (!ret)
return NULL;
if (WideCharToMultiByte(_active_codepage, 0, str, -1, ret, cb, NULL, NULL) == 0) {
giterr_set(GITERR_OS, "Could not convert string to UTF-8");
git__free(ret);
ret = NULL;
}
......
......@@ -15,7 +15,7 @@ struct attr_expected {
const char *expected_str;
};
static inline void attr_check_expected(
GIT_INLINE(void) attr_check_expected(
enum attr_expect_t expected,
const char *expected_str,
const char *value)
......
#include "clar_libgit2.h"
#include "common.h"
#include "util.h"
#include "posix.h"
#ifdef git__throw
void test_core_errors__old_school(void)
{
git_clearerror();
cl_assert(git_lasterror() == NULL);
cl_assert(git_strerror(GIT_ENOTFOUND) != NULL);
git__throw(GIT_ENOTFOUND, "My Message");
cl_assert(git_lasterror() != NULL);
cl_assert(git__prefixcmp(git_lasterror(), "My Message") == 0);
git_clearerror();
}
#endif
#ifdef GITERR_CHECK_ALLOC
void test_core_errors__new_school(void)
{
char *str_in_error;
git_error_clear();
cl_assert(git_error_last() == NULL);
giterr_set_oom(); /* internal fn */
cl_assert(git_error_last() != NULL);
cl_assert(git_error_last()->klass == GITERR_NOMEMORY);
str_in_error = strstr(git_error_last()->message, "memory");
cl_assert(str_in_error != NULL);
git_error_clear();
giterr_set(GITERR_REPOSITORY, "This is a test"); /* internal fn */
cl_assert(git_error_last() != NULL);
str_in_error = strstr(git_error_last()->message, "This is a test");
cl_assert(str_in_error != NULL);
git_error_clear();
{
struct stat st;
assert(p_lstat("this_file_does_not_exist", &st) < 0);
}
giterr_set(GITERR_OS, "stat failed"); /* internal fn */
cl_assert(git_error_last() != NULL);
str_in_error = strstr(git_error_last()->message, "stat failed");
cl_assert(str_in_error != NULL);
cl_assert(git__prefixcmp(str_in_error, "stat failed: ") == 0);
cl_assert(strlen(str_in_error) > strlen("stat failed: "));
#ifdef GIT_WIN32
git_error_clear();
/* The MSDN docs use this to generate a sample error */
cl_assert(GetProcessId(NULL) == 0);
giterr_set(GITERR_OS, "GetProcessId failed"); /* internal fn */
cl_assert(git_error_last() != NULL);
str_in_error = strstr(git_error_last()->message, "GetProcessId failed");
cl_assert(str_in_error != NULL);
cl_assert(git__prefixcmp(str_in_error, "GetProcessId failed: ") == 0);
cl_assert(strlen(str_in_error) > strlen("GetProcessId failed: "));
#endif
git_error_clear();
}
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment