diff --git a/include/git2/errors.h b/include/git2/errors.h index 085dd52f0..5a4e540e1 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -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 diff --git a/src/attr.c b/src/attr.c index 0aa1e325b..a0d6f2954 100644 --- a/src/attr.c +++ b/src/attr.c @@ -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 (git_attr_cache__init(repo) < 0 || + git_vector_init(files, 4, NULL) < 0) + return -1; - if ((error = git_vector_init(files, 4, NULL)) < GIT_SUCCESS) - goto cleanup; - - 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); diff --git a/src/attr_file.c b/src/attr_file.c index 029934317..35679ef22 100644 --- a/src/attr_file.c +++ b/src/attr_file.c @@ -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; } diff --git a/src/attr_file.h b/src/attr_file.h index 1ba18f9e4..6284c5386 100644 --- a/src/attr_file.h +++ b/src/attr_file.h @@ -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); diff --git a/src/blob.c b/src/blob.c index b67f8afa5..20dcece74 100644 --- a/src/blob.c +++ b/src/blob.c @@ -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; } diff --git a/src/buffer.c b/src/buffer.c index dd245e243..b0e329908 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -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) diff --git a/src/buffer.h b/src/buffer.h index 6f59dce62..d90db4d4a 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -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; diff --git a/src/errors.c b/src/errors.c index 6fb7777f0..70aa641c4 100644 --- a/src/errors.c +++ b/src/errors.c @@ -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(); +} + diff --git a/src/filebuf.c b/src/filebuf.c index 5e206c5d8..09b1e0e59 100644 --- a/src/filebuf.c +++ b/src/filebuf.c @@ -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); diff --git a/src/filebuf.h b/src/filebuf.h index 5f9d4ad9d..19e17975b 100644 --- a/src/filebuf.h +++ b/src/filebuf.h @@ -40,6 +40,7 @@ struct git_filebuf { size_t buf_size, buf_pos; git_file fd; + bool fd_is_open; int last_error; }; diff --git a/src/fileops.c b/src/fileops.c index c9fd2c5bc..aa52b09d7 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -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; - return p_rename(from, to); /* The callee already takes care of setting the correct error message. */ + if (p_rename(from, to) < 0) { + giterr_set(GITERR_OS, "Failed to rename '%s' to '%s'", from, to); + return -1; + } + + 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; - } else if (force) { - return p_unlink(path->ptr); + if (p_rmdir(path->ptr) < 0) { + giterr_set(GITERR_OS, "Could not remove directory '%s'", path->ptr); + return -1; + } + + 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); diff --git a/src/fileops.h b/src/fileops.h index c2ba8ffc8..6df565321 100644 --- a/src/fileops.h +++ b/src/fileops.h @@ -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 + * 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; -} +extern int git_futils_open_ro(const char *path); /** * Get the filesize in bytes of a file diff --git a/src/hashtable.c b/src/hashtable.c index c081fc9a7..8e057d4b1 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -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); - resize_to(self, self->size * 2); - git_hashtable_insert(self, new_node->key, new_node->value); - return GIT_SUCCESS; + if (resize_to(self, self->size * 2) < 0) + return -1; + + 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]); } diff --git a/src/hashtable.h b/src/hashtable.h index e09965965..0bab84543 100644 --- a/src/hashtable.h +++ b/src/hashtable.h @@ -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 } } diff --git a/src/ignore.c b/src/ignore.c index a3bf0a282..4cbc55d4b 100644 --- a/src/ignore.c +++ b/src/ignore.c @@ -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; } } diff --git a/src/index.c b/src/index.c index d5410a3a7..7f5909ae0 100644 --- a/src/index.c +++ b/src/index.c @@ -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; } diff --git a/src/indexer.c b/src/indexer.c index dd7c71962..6f8bd329f 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -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 */ diff --git a/src/iterator.c b/src/iterator.c index 0ce89df9e..c10b9ffc2 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -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]); } diff --git a/src/map.h b/src/map.h index 0b070fa15..96d879547 100644 --- a/src/map.h +++ b/src/map.h @@ -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); diff --git a/src/mwindow.c b/src/mwindow.c index 39f6aeacc..cde24d1b1 100644 --- a/src/mwindow.c +++ b/src/mwindow.c @@ -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); } diff --git a/src/mwindow.h b/src/mwindow.h index 94bfb5d61..058027251 100644 --- a/src/mwindow.h +++ b/src/mwindow.h @@ -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); diff --git a/src/object.c b/src/object.c index 043001599..bb27f71c1 100644 --- a/src/object.c +++ b/src/object.c @@ -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); diff --git a/src/odb.c b/src/odb.c index edb9c72a0..f68d13509 100644 --- a/src/odb.c +++ b/src/odb.c @@ -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 */ + if ((error = git_odb_read(&object, db, id)) < 0) + return error; /* error already set - pass along */ - *len_p = object->raw.len; - *type_p = object->raw.type; - git_odb_object_free(object); - } - - 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; } diff --git a/src/odb.h b/src/odb.h index 2f84ebea4..4c425c007 100644 --- a/src/odb.h +++ b/src/odb.h @@ -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 diff --git a/src/odb_loose.c b/src/odb_loose.c index 17fede4a3..c493cc60b 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -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 (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; + } - if (zs.total_out != outlen) - return git__throw(GIT_ERROR, "Failed to inflate buffer. Stream aborted prematurely"); - - 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_SUCCESS; + if (sstate->found > 1) + return git_odb__error_ambiguous("multiple matches in loose objects"); + + 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; - } + else + error = git_filebuf_commit_at( + &stream->fbuf, final_path.ptr, GIT_OBJECT_FILE_MODE); - error = git_filebuf_commit_at(&stream->fbuf, final_path.ptr, GIT_OBJECT_FILE_MODE); - -cleanup: git_buf_free(&final_path); - 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 (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) { - header_len = format_object_header(header, sizeof(header), len, type); - if (header_len < GIT_SUCCESS) - return GIT_EOBJCORRUPTED; + error = -1; + goto cleanup; } - error = git_buf_joinpath(&final_path, backend->objects_dir, "tmp_object"); - if (error < GIT_SUCCESS) - goto cleanup; - - error = git_filebuf_open(&fbuf, final_path.ptr, - GIT_FILEBUF_HASH_CONTENTS | - GIT_FILEBUF_TEMPORARY | - (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT)); - if (error < GIT_SUCCESS) - 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; } diff --git a/src/odb_pack.c b/src/odb_pack.c index 159c88685..7add3718a 100644 --- a/src/odb_pack.c +++ b/src/odb_pack.c @@ -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"); + else if (error < 0) + return error; - if (git_vector_insert(&backend->packs, pack) < GIT_SUCCESS) { - git__free(pack); - return GIT_ENOMEM; - } - - return GIT_SUCCESS; + return git_vector_insert(&backend->packs, pack); } static int packfile_refresh_all(struct pack_backend *backend) @@ -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; + GITERR_CHECK_ALLOC(backend); - error = git_vector_init(&backend->packs, 8, packfile_sort__cb); - if (error < GIT_SUCCESS) - goto cleanup; - - error = git_buf_joinpath(&path, objects_dir, "pack"); - if (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; } diff --git a/src/pack.c b/src/pack.c index acab8734b..40b3ca77c 100644 --- a/src/pack.c +++ b/src/pack.c @@ -17,12 +17,12 @@ #include 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; } diff --git a/src/pack.h b/src/pack.h index 590297847..7cf41c183 100644 --- a/src/pack.h +++ b/src/pack.h @@ -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); diff --git a/src/path.c b/src/path.c index 1ff257a98..0f45d7130 100644 --- a/src/path.c +++ b/src/path.c @@ -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)) { diff --git a/src/path.h b/src/path.h index e885d875e..3cf73940e 100644 --- a/src/path.h +++ b/src/path.h @@ -129,6 +129,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. * diff --git a/src/posix.c b/src/posix.c index 9d96d3013..977880999 100644 --- a/src/posix.c +++ b/src/posix.c @@ -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) diff --git a/src/refs.c b/src/refs.c index e90cf5de1..b4c4b1ec1 100644 --- a/src/refs.c +++ b/src/refs.c @@ -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; } } diff --git a/src/repository.c b/src/repository.c index 7d7b3c4e0..99eee52ea 100644 --- a/src/repository.c +++ b/src/repository.c @@ -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; } /* diff --git a/src/unix/map.c b/src/unix/map.c index 67a73e43c..772f4e247 100644 --- a/src/unix/map.c +++ b/src/unix/map.c @@ -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 diff --git a/src/win32/dir.c b/src/win32/dir.c index 035e2b685..bc3d40fa5 100644 --- a/src/win32/dir.c +++ b/src/win32/dir.c @@ -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 (d->h != INVALID_HANDLE_VALUE) - d->first = 1; - } } + + if (!init_filter(filter, sizeof(filter), d->dir) || + (filter_w = gitwin_to_utf16(filter)) == NULL) + return; + + 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; } diff --git a/src/win32/map.c b/src/win32/map.c index 60adf0f94..f730120cc 100644 --- a/src/win32/map.c +++ b/src/win32/map.c @@ -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; } diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index 2d7c2e3c9..c6b36a847 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -1,4 +1,4 @@ -/ < 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; - memcpy(alt_name, file_name, namelen); - alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + alt_name = git__strndup(file_name, namelen); + if (!alt_name) + return -1; + + error = 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; + if (error) + return error; - /* \??\UNC\ */ - if (dwRet > 7 && target[4] == 'U' && target[5] == 'N' && target[6] == 'C') { - offset += 2; - dwRet -= 2; - target[offset] = '\\'; - } + /* Skip first 4 characters if they are "\\?\" */ + if (dwRet > 4 && + target[0] == '\\' && target[1] == '\\' && + target[2] == '?' && target[3] == '\\') + { + unsigned int offset = 4; + dwRet -= 4; - memcpy(tmp, target + offset, dwRet); - memcpy(target, tmp, dwRet); + /* \??\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); diff --git a/src/win32/pthread.c b/src/win32/pthread.c index 3db536848..3a186c8d9 100644 --- a/src/win32/pthread.c +++ b/src/win32/pthread.c @@ -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) diff --git a/src/win32/utf-conv.c b/src/win32/utf-conv.c index 3c8be81d1..f00f5be92 100644 --- a/src/win32/utf-conv.c +++ b/src/win32/utf-conv.c @@ -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; } diff --git a/tests-clar/attr/attr_expect.h b/tests-clar/attr/attr_expect.h index bea562457..b064eac65 100644 --- a/tests-clar/attr/attr_expect.h +++ b/tests-clar/attr/attr_expect.h @@ -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) diff --git a/tests-clar/core/errors.c b/tests-clar/core/errors.c new file mode 100644 index 000000000..52b2652c8 --- /dev/null +++ b/tests-clar/core/errors.c @@ -0,0 +1,74 @@ +#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