Commit e24fbba9 by Vicent Martí

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

Update odb code to new error handling
parents dda708e7 deafee7b
...@@ -103,7 +103,7 @@ typedef enum { ...@@ -103,7 +103,7 @@ typedef enum {
GIT_EOBJCORRUPTED = -28, GIT_EOBJCORRUPTED = -28,
/** The given short oid is ambiguous */ /** The given short oid is ambiguous */
GIT_EAMBIGUOUSOIDPREFIX = -29, GIT_EAMBIGUOUS = -29,
/** Skip and passthrough the given ODB backend */ /** Skip and passthrough the given ODB backend */
GIT_EPASSTHROUGH = -30, GIT_EPASSTHROUGH = -30,
...@@ -128,11 +128,13 @@ typedef enum { ...@@ -128,11 +128,13 @@ typedef enum {
GITERR_REPOSITORY, GITERR_REPOSITORY,
GITERR_CONFIG, GITERR_CONFIG,
GITERR_REGEX, GITERR_REGEX,
GITERR_ODB
} git_error_class; } git_error_class;
/** /**
* Return a detailed error string with the latest error * Return a detailed error string with the latest error
* that occurred in the library. * that occurred in the library.
* @deprecated This will be replaced in the new error handling
* @return a string explaining the error * @return a string explaining the error
*/ */
GIT_EXTERN(const char *) git_lasterror(void); GIT_EXTERN(const char *) git_lasterror(void);
...@@ -144,6 +146,7 @@ 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 * NOTE: This method will be eventually deprecated in favor
* of the new `git_lasterror`. * of the new `git_lasterror`.
* *
* @deprecated This will be replaced in the new error handling
* @param num The error code to explain * @param num The error code to explain
* @return a string explaining the error code * @return a string explaining the error code
*/ */
...@@ -151,9 +154,23 @@ GIT_EXTERN(const char *) git_strerror(int num); ...@@ -151,9 +154,23 @@ GIT_EXTERN(const char *) git_strerror(int num);
/** /**
* Clear the latest library error * Clear the latest library error
* @deprecated This will be replaced in the new error handling
*/ */
GIT_EXTERN(void) git_clearerror(void); 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 GIT_END_DECL
#endif #endif
...@@ -317,13 +317,12 @@ static int collect_attr_files( ...@@ -317,13 +317,12 @@ static int collect_attr_files(
const char *workdir = git_repository_workdir(repo); const char *workdir = git_repository_workdir(repo);
attr_walk_up_info info; attr_walk_up_info info;
if ((error = git_attr_cache__init(repo)) < GIT_SUCCESS) if (git_attr_cache__init(repo) < 0 ||
goto cleanup; 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; goto cleanup;
/* in precendence order highest to lowest: /* in precendence order highest to lowest:
...@@ -334,13 +333,13 @@ static int collect_attr_files( ...@@ -334,13 +333,13 @@ static int collect_attr_files(
*/ */
error = push_attrs(repo, files, repo->path_repository, GIT_ATTR_FILE_INREPO); error = push_attrs(repo, files, repo->path_repository, GIT_ATTR_FILE_INREPO);
if (error < GIT_SUCCESS) if (error < 0)
goto cleanup; goto cleanup;
info.repo = repo; info.repo = repo;
info.files = files; info.files = files;
error = git_path_walk_up(&dir, workdir, push_one_attr, &info); error = git_path_walk_up(&dir, workdir, push_one_attr, &info);
if (error < GIT_SUCCESS) if (error < 0)
goto cleanup; goto cleanup;
if ((error = git_repository_config(&cfg, repo)) == GIT_SUCCESS) { if ((error = git_repository_config(&cfg, repo)) == GIT_SUCCESS) {
...@@ -352,19 +351,17 @@ static int collect_attr_files( ...@@ -352,19 +351,17 @@ static int collect_attr_files(
git_config_free(cfg); git_config_free(cfg);
} }
if (error == GIT_SUCCESS) { if (!error) {
error = git_futils_find_system_file(&dir, GIT_ATTR_FILE_SYSTEM); 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); error = push_attrs(repo, files, NULL, dir.ptr);
else if (error == GIT_ENOTFOUND) else if (error == GIT_ENOTFOUND)
error = GIT_SUCCESS; error = 0;
} }
cleanup: cleanup:
if (error < GIT_SUCCESS) { if (error < 0)
git__rethrow(error, "Could not get attributes for '%s'", path);
git_vector_free(files); git_vector_free(files);
}
git_buf_free(&dir); git_buf_free(&dir);
return error; return error;
...@@ -373,32 +370,29 @@ static int collect_attr_files( ...@@ -373,32 +370,29 @@ static int collect_attr_files(
int git_attr_cache__init(git_repository *repo) int git_attr_cache__init(git_repository *repo)
{ {
int error = GIT_SUCCESS;
git_attr_cache *cache = &repo->attrcache; git_attr_cache *cache = &repo->attrcache;
if (cache->initialized) if (cache->initialized)
return GIT_SUCCESS; return 0;
if (cache->files == NULL) { if (cache->files == NULL) {
cache->files = git_hashtable_alloc( cache->files = git_hashtable_alloc(
8, git_hash__strhash_cb, git_hash__strcmp_cb); 8, git_hash__strhash_cb, git_hash__strcmp_cb);
if (!cache->files) if (!cache->files)
return git__throw(GIT_ENOMEM, "Could not initialize attribute cache"); return -1;
} }
if (cache->macros == NULL) { if (cache->macros == NULL) {
cache->macros = git_hashtable_alloc( cache->macros = git_hashtable_alloc(
8, git_hash__strhash_cb, git_hash__strcmp_cb); 8, git_hash__strhash_cb, git_hash__strcmp_cb);
if (!cache->macros) if (!cache->macros)
return git__throw(GIT_ENOMEM, "Could not initialize attribute cache"); return -1;
} }
cache->initialized = 1; cache->initialized = 1;
/* insert default macros */ /* insert default macros */
error = git_attr_add_macro(repo, "binary", "-diff -crlf"); return git_attr_add_macro(repo, "binary", "-diff -crlf");
return error;
} }
void git_attr_cache_flush( void git_attr_cache_flush(
...@@ -432,8 +426,9 @@ 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) 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) if (macro->assigns.length == 0)
return git__throw(GIT_EMISSINGOBJDATA, "git attribute macro with no values"); return 0;
return git_hashtable_insert( return git_hashtable_insert(
repo->attrcache.macros, macro->match.pattern, macro); repo->attrcache.macros, macro->match.pattern, macro);
......
...@@ -180,37 +180,37 @@ int git_attr_file__lookup_one( ...@@ -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, git_attr_fnmatch *match,
const git_attr_path *path) const git_attr_path *path)
{ {
int matched = FNM_NOMATCH; int fnm;
if (match->flags & GIT_ATTR_FNMATCH_DIRECTORY && !path->is_dir) if (match->flags & GIT_ATTR_FNMATCH_DIRECTORY && !path->is_dir)
return matched; return false;
if (match->flags & GIT_ATTR_FNMATCH_FULLPATH) 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) 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 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, git_attr_rule *rule,
const git_attr_path *path) 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) if (rule->match.flags & GIT_ATTR_FNMATCH_NEGATIVE)
matched = (matched == GIT_SUCCESS) ? FNM_NOMATCH : GIT_SUCCESS; matched = !matched;
return matched; return matched;
} }
......
...@@ -82,7 +82,7 @@ extern int git_attr_file__lookup_one( ...@@ -82,7 +82,7 @@ extern int git_attr_file__lookup_one(
/* loop over rules in file from bottom to top */ /* loop over rules in file from bottom to top */
#define git_attr_file__foreach_matching_rule(file, path, iter, rule) \ #define git_attr_file__foreach_matching_rule(file, path, iter, rule) \
git_vector_rforeach(&(file)->rules, (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); extern unsigned long git_attr_file__name_hash(const char *name);
...@@ -96,13 +96,13 @@ extern int git_attr_fnmatch__parse( ...@@ -96,13 +96,13 @@ extern int git_attr_fnmatch__parse(
const char *source, const char *source,
const char **base); const char **base);
extern int git_attr_fnmatch__match( extern bool git_attr_fnmatch__match(
git_attr_fnmatch *rule, git_attr_fnmatch *rule,
const git_attr_path *path); const git_attr_path *path);
extern void git_attr_rule__free(git_attr_rule *rule); 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, git_attr_rule *rule,
const git_attr_path *path); const git_attr_path *path);
......
...@@ -42,7 +42,7 @@ int git_blob__parse(git_blob *blob, git_odb_object *odb_obj) ...@@ -42,7 +42,7 @@ int git_blob__parse(git_blob *blob, git_odb_object *odb_obj)
assert(blob); assert(blob);
git_cached_obj_incref((git_cached_obj *)odb_obj); git_cached_obj_incref((git_cached_obj *)odb_obj);
blob->odb_object = 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) 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 ...@@ -51,58 +51,50 @@ int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *b
git_odb *odb; git_odb *odb;
git_odb_stream *stream; git_odb_stream *stream;
error = git_repository_odb__weakptr(&odb, repo); if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 ||
if (error < GIT_SUCCESS) (error = git_odb_open_wstream(&stream, odb, len, GIT_OBJ_BLOB)) < 0)
return error; return error;
if ((error = git_odb_open_wstream(&stream, odb, len, GIT_OBJ_BLOB)) < GIT_SUCCESS) if ((error = stream->write(stream, buffer, len)) == 0)
return git__rethrow(error, "Failed to create blob"); 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); stream->free(stream);
return error;
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to create blob");
return GIT_SUCCESS;
} }
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; int fd, error;
char buffer[4096]; char buffer[4096];
git_odb_stream *stream = NULL; git_odb_stream *stream = NULL;
if ((error = git_odb_open_wstream(&stream, odb, file_size, GIT_OBJ_BLOB)) < GIT_SUCCESS) if ((error = git_odb_open_wstream(
&stream, odb, (size_t)file_size, GIT_OBJ_BLOB)) < 0)
return error; return error;
if ((fd = p_open(path, O_RDONLY)) < 0) { if ((fd = git_futils_open_ro(path)) < 0) {
error = git__throw(GIT_ENOTFOUND, "Failed to create blob. Could not open '%s'", path); stream->free(stream);
goto cleanup; return -1;
} }
while (file_size > 0) { while (!error && file_size > 0) {
ssize_t read_len = p_read(fd, buffer, sizeof(buffer)); ssize_t read_len = p_read(fd, buffer, sizeof(buffer));
if (read_len < 0) { if (read_len < 0) {
error = git__throw(GIT_EOSERR, "Failed to create blob. Can't read full file"); giterr_set(
p_close(fd); GITERR_OS, "Failed to create blob. Can't read whole file");
goto cleanup; error = -1;
} }
else if (!(error = stream->write(stream, buffer, read_len)))
stream->write(stream, buffer, read_len); file_size -= read_len;
file_size -= read_len;
} }
p_close(fd); p_close(fd);
error = stream->finalize_write(oid, stream);
cleanup: if (!error)
error = stream->finalize_write(oid, stream);
stream->free(stream); stream->free(stream);
return error; return error;
} }
...@@ -117,8 +109,7 @@ static int write_file_filtered( ...@@ -117,8 +109,7 @@ static int write_file_filtered(
git_buf source = GIT_BUF_INIT; git_buf source = GIT_BUF_INIT;
git_buf dest = GIT_BUF_INIT; git_buf dest = GIT_BUF_INIT;
error = git_futils_readbuffer(&source, full_path); if ((error = git_futils_readbuffer(&source, full_path)) < 0)
if (error < GIT_SUCCESS)
return error; return error;
error = git_filters_apply(&dest, &source, filters); error = git_filters_apply(&dest, &source, filters);
...@@ -127,30 +118,29 @@ static int write_file_filtered( ...@@ -127,30 +118,29 @@ static int write_file_filtered(
* and we don't want to ODB write to choke */ * and we don't want to ODB write to choke */
git_buf_free(&source); 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); error = git_odb_write(oid, odb, dest.ptr, dest.size, GIT_OBJ_BLOB);
}
git_buf_free(&dest); 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; char *link_data;
ssize_t read_len; ssize_t read_len;
int error; int error;
link_data = git__malloc(link_size); link_data = git__malloc(link_size);
if (!link_data) GITERR_CHECK_ALLOC(link_data);
return GIT_ENOMEM;
read_len = p_readlink(path, link_data, link_size); read_len = p_readlink(path, link_data, link_size);
if (read_len != (ssize_t)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); 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); 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 ...@@ -168,25 +158,18 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
git_odb *odb = NULL; git_odb *odb = NULL;
workdir = git_repository_workdir(repo); workdir = git_repository_workdir(repo);
if (workdir == NULL) assert(workdir); /* error to call this on bare repo */
return git__throw(GIT_ENOTFOUND, "Failed to create blob. (No working directory found)");
error = git_buf_joinpath(&full_path, workdir, path); if ((error = git_buf_joinpath(&full_path, workdir, path)) < 0 ||
if (error < GIT_SUCCESS) (error = git_path_lstat(full_path.ptr, &st)) < 0 ||
(error = git_repository_odb__weakptr(&odb, repo)) < 0)
{
git_buf_free(&full_path);
return error; 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; size = st.st_size;
error = git_repository_odb__weakptr(&odb, repo);
if (error < GIT_SUCCESS)
goto cleanup;
if (S_ISLNK(st.st_mode)) { if (S_ISLNK(st.st_mode)) {
error = write_symlink(oid, odb, full_path.ptr, (size_t)size); error = write_symlink(oid, odb, full_path.ptr, (size_t)size);
} else { } else {
...@@ -194,12 +177,12 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat ...@@ -194,12 +177,12 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
int filter_count; int filter_count;
/* Load the filters for writing this file to the ODB */ /* 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) { if (filter_count < 0) {
/* Negative value means there was a critical error */ /* Negative value means there was a critical error */
error = filter_count; error = filter_count;
goto cleanup;
} else if (filter_count == 0) { } else if (filter_count == 0) {
/* No filters need to be applied to the document: we can stream /* No filters need to be applied to the document: we can stream
* directly from disk */ * directly from disk */
...@@ -212,19 +195,20 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat ...@@ -212,19 +195,20 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
git_filters_free(&write_filters); git_filters_free(&write_filters);
/* /*
* TODO: eventually support streaming filtered files, for files which are bigger * TODO: eventually support streaming filtered files, for files
* than a given threshold. This is not a priority because applying a filter in * which are bigger than a given threshold. This is not a priority
* streaming mode changes the final size of the blob, and without knowing its * because applying a filter in streaming mode changes the final
* final size, the blob cannot be written in stream mode to the ODB. * 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 * The plan is to do streaming writes to a tempfile on disk and then
* streaming that file to the ODB, using `write_file_stream`. * opening streaming that file to the ODB, using
* `write_file_stream`.
* *
* CAREFULLY DESIGNED APIS YO * CAREFULLY DESIGNED APIS YO
*/ */
} }
cleanup:
git_buf_free(&full_path); git_buf_free(&full_path);
return error; return error;
} }
......
...@@ -215,8 +215,8 @@ void git_buf_truncate(git_buf *buf, size_t len) ...@@ -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) void git_buf_rtruncate_at_char(git_buf *buf, char separator)
{ {
int idx = git_buf_rfind_next(buf, separator); ssize_t idx = git_buf_rfind_next(buf, separator);
git_buf_truncate(buf, idx < 0 ? 0 : idx); git_buf_truncate(buf, idx < 0 ? 0 : (size_t)idx);
} }
void git_buf_swap(git_buf *buf_a, git_buf *buf_b) void git_buf_swap(git_buf *buf_a, git_buf *buf_b)
......
...@@ -102,9 +102,9 @@ void git_buf_copy_cstr(char *data, size_t datasize, const git_buf *buf); ...@@ -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) #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--;
while (idx >= 0 && buf->ptr[idx] != ch) idx--; while (idx >= 0 && buf->ptr[idx] != ch) idx--;
return idx; return idx;
......
...@@ -40,7 +40,7 @@ static struct { ...@@ -40,7 +40,7 @@ static struct {
{GIT_EEXISTS, "A reference with this name already exists"}, {GIT_EEXISTS, "A reference with this name already exists"},
{GIT_EOVERFLOW, "The given integer literal is too large to be parsed"}, {GIT_EOVERFLOW, "The given integer literal is too large to be parsed"},
{GIT_ENOTNUM, "The given literal is not a valid number"}, {GIT_ENOTNUM, "The given literal is not a valid number"},
{GIT_EAMBIGUOUSOIDPREFIX, "The given oid prefix is ambiguous"}, {GIT_EAMBIGUOUS, "The given oid prefix is ambiguous"},
}; };
const char *git_strerror(int num) const char *git_strerror(int num)
...@@ -123,15 +123,43 @@ void giterr_set(int error_class, const char *string, ...) ...@@ -123,15 +123,43 @@ void giterr_set(int error_class, const char *string, ...)
char error_str[1024]; char error_str[1024];
va_list arglist; 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); va_start(arglist, string);
p_vsnprintf(error_str, sizeof(error_str), string, arglist); p_vsnprintf(error_str, sizeof(error_str), string, arglist);
va_end(arglist); va_end(arglist);
/* automatically suffix strerror(errno) for GITERR_OS errors */ /* automatically suffix strerror(errno) for GITERR_OS errors */
if (error_class == GITERR_OS) { if (error_class == GITERR_OS) {
strncat(error_str, ": ", sizeof(error_str)); if (os_error_msg != NULL) {
strncat(error_str, strerror(errno), sizeof(error_str)); strncat(error_str, ": ", sizeof(error_str));
errno = 0; 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); giterr_set_str(error_class, error_str);
...@@ -165,3 +193,14 @@ void giterr_clear(void) ...@@ -165,3 +193,14 @@ void giterr_clear(void)
{ {
GIT_GLOBAL->last_error = NULL; GIT_GLOBAL->last_error = NULL;
} }
const git_error *git_error_last(void)
{
return GIT_GLOBAL->last_error;
}
void git_error_clear(void)
{
giterr_clear();
}
...@@ -67,6 +67,8 @@ static int lock_file(git_filebuf *file, int flags) ...@@ -67,6 +67,8 @@ static int lock_file(git_filebuf *file, int flags)
if (file->fd < 0) if (file->fd < 0)
return -1; return -1;
file->fd_is_open = true;
if ((flags & GIT_FILEBUF_APPEND) && git_path_exists(file->path_original) == true) { if ((flags & GIT_FILEBUF_APPEND) && git_path_exists(file->path_original) == true) {
git_file source; git_file source;
char buffer[2048]; char buffer[2048];
...@@ -94,10 +96,10 @@ static int lock_file(git_filebuf *file, int flags) ...@@ -94,10 +96,10 @@ static int lock_file(git_filebuf *file, int flags)
void git_filebuf_cleanup(git_filebuf *file) void git_filebuf_cleanup(git_filebuf *file)
{ {
if (file->fd >= 0) if (file->fd_is_open && file->fd >= 0)
p_close(file->fd); p_close(file->fd);
if (file->fd >= 0 && file->path_lock && git_path_exists(file->path_lock) == true) if (file->fd_is_open && file->path_lock && git_path_exists(file->path_lock))
p_unlink(file->path_lock); p_unlink(file->path_lock);
if (file->digest) if (file->digest)
...@@ -239,6 +241,7 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags) ...@@ -239,6 +241,7 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags)
git_buf_free(&tmp_path); git_buf_free(&tmp_path);
goto cleanup; goto cleanup;
} }
file->fd_is_open = true;
/* No original path */ /* No original path */
file->path_original = NULL; file->path_original = NULL;
...@@ -308,6 +311,7 @@ int git_filebuf_commit(git_filebuf *file, mode_t mode) ...@@ -308,6 +311,7 @@ int git_filebuf_commit(git_filebuf *file, mode_t mode)
p_close(file->fd); p_close(file->fd);
file->fd = -1; file->fd = -1;
file->fd_is_open = false;
if (p_chmod(file->path_lock, mode)) { if (p_chmod(file->path_lock, mode)) {
giterr_set(GITERR_OS, "Failed to set attributes for file at '%s'", file->path_lock); giterr_set(GITERR_OS, "Failed to set attributes for file at '%s'", file->path_lock);
......
...@@ -40,6 +40,7 @@ struct git_filebuf { ...@@ -40,6 +40,7 @@ struct git_filebuf {
size_t buf_size, buf_pos; size_t buf_size, buf_pos;
git_file fd; git_file fd;
bool fd_is_open;
int last_error; int last_error;
}; };
......
...@@ -79,11 +79,25 @@ int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, con ...@@ -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); 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) git_off_t git_futils_filesize(git_file fd)
{ {
struct stat sb; 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; return sb.st_size;
} }
...@@ -117,7 +131,7 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime, ...@@ -117,7 +131,7 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime,
return fd; return fd;
if (p_fstat(fd, &st) < 0 || S_ISDIR(st.st_mode) || !git__is_sizet(st.st_size+1)) { if (p_fstat(fd, &st) < 0 || S_ISDIR(st.st_mode) || !git__is_sizet(st.st_size+1)) {
close(fd); p_close(fd);
giterr_set(GITERR_OS, "Invalid regular file stat for '%s'", path); giterr_set(GITERR_OS, "Invalid regular file stat for '%s'", path);
return -1; return -1;
} }
...@@ -127,7 +141,7 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime, ...@@ -127,7 +141,7 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime,
* has been modified. * has been modified.
*/ */
if (mtime != NULL && *mtime >= st.st_mtime) { if (mtime != NULL && *mtime >= st.st_mtime) {
close(fd); p_close(fd);
return 0; return 0;
} }
...@@ -139,8 +153,8 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime, ...@@ -139,8 +153,8 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime,
git_buf_clear(buf); git_buf_clear(buf);
if (git_buf_grow(buf, len + 1) < 0) { if (git_buf_grow(buf, len + 1) < 0) {
close(fd); p_close(fd);
return GIT_ENOMEM; return -1;
} }
buf->ptr[len] = '\0'; buf->ptr[len] = '\0';
...@@ -149,7 +163,7 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime, ...@@ -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); ssize_t read_size = p_read(fd, buf->ptr, len);
if (read_size < 0) { if (read_size < 0) {
close(fd); p_close(fd);
giterr_set(GITERR_OS, "Failed to read descriptor for '%s'", path); giterr_set(GITERR_OS, "Failed to read descriptor for '%s'", path);
return -1; return -1;
} }
...@@ -176,10 +190,15 @@ int git_futils_readbuffer(git_buf *buf, const char *path) ...@@ -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) int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode)
{ {
if (git_futils_mkpath2file(to, dirmode) < GIT_SUCCESS) if (git_futils_mkpath2file(to, dirmode) < 0)
return GIT_EOSERR; /* The callee already takes care of setting the correct error message. */ return -1;
if (p_rename(from, to) < 0) {
giterr_set(GITERR_OS, "Failed to rename '%s' to '%s'", from, to);
return -1;
}
return p_rename(from, to); /* The callee already takes care of setting the correct error message. */ return 0;
} }
int git_futils_mmap_ro(git_map *out, git_file fd, git_off_t begin, size_t len) 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) ...@@ -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_file fd = p_open(path, O_RDONLY /* | O_NOATIME */);
git_off_t len = git_futils_filesize(fd); git_off_t len = git_futils_filesize(fd);
int result; int result;
if (!git__is_sizet(len)) if (!git__is_sizet(len)) {
return git__throw(GIT_ERROR, "File `%s` too large to mmap", path); giterr_set(GITERR_OS, "File `%s` too large to mmap", path);
return -1;
}
result = git_futils_mmap_ro(out, fd, 0, (size_t)len); result = git_futils_mmap_ro(out, fd, 0, (size_t)len);
p_close(fd); p_close(fd);
return result; return result;
...@@ -260,20 +281,31 @@ int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode) ...@@ -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) static int _rmdir_recurs_foreach(void *opaque, git_buf *path)
{ {
int error = GIT_SUCCESS;
int force = *(int *)opaque; int force = *(int *)opaque;
if (git_path_isdir(path->ptr) == true) { if (git_path_isdir(path->ptr) == true) {
error = git_path_direach(path, _rmdir_recurs_foreach, opaque); if (git_path_direach(path, _rmdir_recurs_foreach, opaque) < 0)
if (error < GIT_SUCCESS) return -1;
return git__rethrow(error, "Failed to remove directory `%s`", path->ptr);
return p_rmdir(path->ptr); if (p_rmdir(path->ptr) < 0) {
giterr_set(GITERR_OS, "Could not remove directory '%s'", path->ptr);
return -1;
}
} else if (force) { return 0;
return p_unlink(path->ptr);
} }
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) int git_futils_rmdir_r(const char *path, int force)
...@@ -282,7 +314,7 @@ 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; git_buf p = GIT_BUF_INIT;
error = git_buf_sets(&p, path); error = git_buf_sets(&p, path);
if (error == GIT_SUCCESS) if (!error)
error = _rmdir_recurs_foreach(&force, &p); error = _rmdir_recurs_foreach(&force, &p);
git_buf_free(&p); git_buf_free(&p);
return error; return error;
...@@ -328,9 +360,8 @@ static const win32_path *win32_system_root(void) ...@@ -328,9 +360,8 @@ static const win32_path *win32_system_root(void)
const wchar_t *root_tmpl = L"%PROGRAMFILES%\\Git\\etc\\"; const wchar_t *root_tmpl = L"%PROGRAMFILES%\\Git\\etc\\";
s_root.len = ExpandEnvironmentStringsW(root_tmpl, NULL, 0); s_root.len = ExpandEnvironmentStringsW(root_tmpl, NULL, 0);
if (s_root.len <= 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; return NULL;
} }
...@@ -339,7 +370,7 @@ static const win32_path *win32_system_root(void) ...@@ -339,7 +370,7 @@ static const win32_path *win32_system_root(void)
return NULL; return NULL;
if (ExpandEnvironmentStringsW(root_tmpl, s_root.path, s_root.len) != s_root.len) { 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); git__free(s_root.path);
s_root.path = NULL; s_root.path = NULL;
return NULL; return NULL;
...@@ -351,7 +382,7 @@ static const win32_path *win32_system_root(void) ...@@ -351,7 +382,7 @@ static const win32_path *win32_system_root(void)
static int win32_find_system_file(git_buf *path, const char *filename) 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(); const win32_path *root = win32_system_root();
size_t len; size_t len;
wchar_t *file_utf16 = NULL, *scan; wchar_t *file_utf16 = NULL, *scan;
...@@ -362,8 +393,7 @@ static int win32_find_system_file(git_buf *path, const char *filename) ...@@ -362,8 +393,7 @@ static int win32_find_system_file(git_buf *path, const char *filename)
/* allocate space for wchar_t path to file */ /* allocate space for wchar_t path to file */
file_utf16 = git__calloc(root->len + len + 2, sizeof(wchar_t)); file_utf16 = git__calloc(root->len + len + 2, sizeof(wchar_t));
if (!file_utf16) GITERR_CHECK_ALLOC(file_utf16);
return GIT_ENOMEM;
/* append root + '\\' + filename as wchar_t */ /* append root + '\\' + filename as wchar_t */
memcpy(file_utf16, root->path, root->len * sizeof(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) ...@@ -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) != if (gitwin_append_utf16(file_utf16 + root->len - 1, filename, len + 1) !=
(int)len + 1) { (int)len + 1) {
error = git__throw(GIT_EOSERR, "Failed to build file path"); error = -1;
goto cleanup; goto cleanup;
} }
...@@ -389,9 +419,8 @@ static int win32_find_system_file(git_buf *path, const char *filename) ...@@ -389,9 +419,8 @@ static int win32_find_system_file(git_buf *path, const char *filename)
/* convert to utf8 */ /* convert to utf8 */
if ((file_utf8 = gitwin_from_utf16(file_utf16)) == NULL) if ((file_utf8 = gitwin_from_utf16(file_utf16)) == NULL)
error = GIT_ENOMEM; error = -1;
else {
if (file_utf8) {
git_path_mkposix(file_utf8); git_path_mkposix(file_utf8);
git_buf_attach(path, file_utf8, 0); git_buf_attach(path, file_utf8, 0);
} }
...@@ -409,7 +438,7 @@ int git_futils_find_system_file(git_buf *path, const char *filename) ...@@ -409,7 +438,7 @@ int git_futils_find_system_file(git_buf *path, const char *filename)
return -1; return -1;
if (git_path_exists(path->ptr) == true) if (git_path_exists(path->ptr) == true)
return GIT_SUCCESS; return 0;
git_buf_clear(path); git_buf_clear(path);
......
...@@ -77,18 +77,9 @@ extern int git_futils_mktmp(git_buf *path_out, const char *filename); ...@@ -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); 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) extern 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;
}
/** /**
* Get the filesize in bytes of a file * Get the filesize in bytes of a file
......
...@@ -31,9 +31,7 @@ static int resize_to(git_hashtable *self, size_t new_size) ...@@ -31,9 +31,7 @@ static int resize_to(git_hashtable *self, size_t new_size)
self->size_mask = new_size - 1; self->size_mask = new_size - 1;
self->key_count = 0; self->key_count = 0;
self->nodes = git__calloc(1, sizeof(git_hashtable_node) * self->size); self->nodes = git__calloc(1, sizeof(git_hashtable_node) * self->size);
GITERR_CHECK_ALLOC(self->nodes);
if (self->nodes == NULL)
return GIT_ENOMEM;
if (insert_nodes(self, old_nodes, old_size) == 0) if (insert_nodes(self, old_nodes, old_size) == 0)
self->is_resizing = 0; self->is_resizing = 0;
...@@ -44,22 +42,22 @@ static int resize_to(git_hashtable *self, size_t new_size) ...@@ -44,22 +42,22 @@ static int resize_to(git_hashtable *self, size_t new_size)
} while(self->is_resizing); } while(self->is_resizing);
git__free(old_nodes); git__free(old_nodes);
return GIT_SUCCESS; return 0;
} }
static int set_size(git_hashtable *self, size_t new_size) static int set_size(git_hashtable *self, size_t new_size)
{ {
self->nodes = git__realloc(self->nodes, new_size * sizeof(git_hashtable_node)); self->nodes = git__realloc(self->nodes, new_size * sizeof(git_hashtable_node));
if (self->nodes == NULL) GITERR_CHECK_ALLOC(self->nodes);
return GIT_ENOMEM;
if (new_size > self->size) { 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 = new_size;
self->size_mask = new_size - 1; 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) 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) ...@@ -84,43 +82,47 @@ static int node_insert(git_hashtable *self, git_hashtable_node *new_node)
git_hashtable_node *node; git_hashtable_node *node;
node = node_with_hash(self, new_node->key, hash_id); node = node_with_hash(self, new_node->key, hash_id);
node_swap_with(new_node, node); node_swap_with(new_node, node);
if(new_node->key == 0x0){ if (new_node->key == 0x0){
self->key_count++; self->key_count++;
return GIT_SUCCESS; return 0;
} }
} }
} }
if (self->is_resizing) /* Failed to insert node. Hashtable is currently resizing */
return git__throw(GIT_EBUSY, "Failed to insert node. Hashtable is currently resizing"); assert(!self->is_resizing);
if (resize_to(self, self->size * 2) < 0)
return -1;
resize_to(self, self->size * 2); return git_hashtable_insert(self, new_node->key, new_node->value);
git_hashtable_insert(self, new_node->key, new_node->value);
return GIT_SUCCESS;
} }
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; size_t i;
for (i = 0; i < old_size; ++i) { for (i = 0; i < old_size; ++i) {
git_hashtable_node *node = git_hashtable_node_at(old_nodes, 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) if (node->key &&
return GIT_ENOMEM; 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_hashtable *git_hashtable_alloc(
git_hash_ptr hash, size_t min_size,
git_hash_keyeq_ptr key_eq) git_hash_ptr hash,
git_hash_keyeq_ptr key_eq)
{ {
git_hashtable *table; git_hashtable *table;
assert(hash && key_eq); assert(hash && key_eq);
if ((table = git__malloc(sizeof(git_hashtable))) == NULL) if ((table = git__malloc(sizeof(*table))) == NULL)
return NULL; return NULL;
memset(table, 0x0, sizeof(git_hashtable)); memset(table, 0x0, sizeof(git_hashtable));
...@@ -161,7 +163,8 @@ void git_hashtable_free(git_hashtable *self) ...@@ -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; int hash_id;
git_hashtable_node *node; git_hashtable_node *node;
...@@ -177,14 +180,14 @@ int git_hashtable_insert2(git_hashtable *self, const void *key, void *value, voi ...@@ -177,14 +180,14 @@ int git_hashtable_insert2(git_hashtable *self, const void *key, void *value, voi
node->key = key; node->key = key;
node->value = value; node->value = value;
self->key_count++; self->key_count++;
return GIT_SUCCESS; return 0;
} }
if (key == node->key || self->key_equal(key, node->key) == 0) { if (key == node->key || self->key_equal(key, node->key) == 0) {
*old_value = node->value; *old_value = node->value;
node->key = key; node->key = key;
node->value = value; node->value = value;
return GIT_SUCCESS; return 0;
} }
} }
...@@ -213,7 +216,8 @@ void *git_hashtable_lookup(git_hashtable *self, const void *key) ...@@ -213,7 +216,8 @@ void *git_hashtable_lookup(git_hashtable *self, const void *key)
return NULL; 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; int hash_id;
git_hashtable_node *node; git_hashtable_node *node;
...@@ -236,8 +240,8 @@ int git_hashtable_remove2(git_hashtable *self, const void *key, void **old_value ...@@ -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) int git_hashtable_merge(git_hashtable *self, git_hashtable *other)
{ {
if (resize_to(self, (self->size + other->size) * 2) < GIT_SUCCESS) if (resize_to(self, (self->size + other->size) * 2) < 0)
return GIT_ENOMEM; return -1;
return insert_nodes(self, other->nodes, other->key_count); 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) ...@@ -254,5 +258,10 @@ uint32_t git_hash__strhash_cb(const void *key, int hash_id)
0x7daaab3c 0x7daaab3c
}; };
return git__hash(key, strlen((const char *)key), hash_seeds[hash_id]); size_t key_len = strlen((const char *)key);
/* won't take hash of strings longer than 2^31 right now */
assert(key_len == (size_t)((int)key_len));
return git__hash(key, (int)key_len, hash_seeds[hash_id]);
} }
...@@ -66,7 +66,7 @@ GIT_INLINE(int) git_hashtable_insert(git_hashtable *h, const void *key, void *va ...@@ -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_node_at(nodes, pos) ((git_hashtable_node *)(&nodes[pos]))
#define GIT_HASHTABLE__FOREACH(self,block) { \ #define GIT_HASHTABLE__FOREACH(self,block) { \
unsigned int _c; \ size_t _c; \
git_hashtable_node *_n = (self)->nodes; \ git_hashtable_node *_n = (self)->nodes; \
for (_c = (self)->size; _c > 0; _c--, _n++) { \ for (_c = (self)->size; _c > 0; _c--, _n++) { \
if (!_n->key) continue; block } } if (!_n->key) continue; block } }
......
...@@ -168,9 +168,9 @@ static int ignore_lookup_in_rules( ...@@ -168,9 +168,9 @@ static int ignore_lookup_in_rules(
git_attr_fnmatch *match; git_attr_fnmatch *match;
git_vector_rforeach(rules, j, 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); *ignored = ((match->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0);
return GIT_SUCCESS; return 0;
} }
} }
......
...@@ -319,8 +319,7 @@ static int index_entry_init(git_index_entry **entry_out, git_index *index, const ...@@ -319,8 +319,7 @@ static int index_entry_init(git_index_entry **entry_out, git_index *index, const
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; return error;
if (p_lstat(full_path.ptr, &st) < 0) { if ((error = git_path_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));
git_buf_free(&full_path); git_buf_free(&full_path);
return error; return error;
} }
......
...@@ -133,12 +133,15 @@ int git_indexer_new(git_indexer **out, const char *packname) ...@@ -133,12 +133,15 @@ int git_indexer_new(git_indexer **out, const char *packname)
idx->nr_objects = ntohl(idx->hdr.hdr_entries); 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) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
idx->pack->has_cache = 1; 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) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
...@@ -307,7 +310,7 @@ cleanup: ...@@ -307,7 +310,7 @@ cleanup:
int git_indexer_run(git_indexer *idx, git_indexer_stats *stats) int git_indexer_run(git_indexer *idx, git_indexer_stats *stats)
{ {
git_mwindow_file *mwf; git_mwindow_file *mwf;
off_t off = sizeof(struct git_pack_header); git_off_t off = sizeof(struct git_pack_header);
int error; int error;
struct entry *entry; struct entry *entry;
unsigned int left, processed; unsigned int left, processed;
...@@ -319,7 +322,7 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats) ...@@ -319,7 +322,7 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats)
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to register mwindow file"); 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; stats->processed = processed = 0;
while (processed < idx->nr_objects) { while (processed < idx->nr_objects) {
...@@ -328,18 +331,18 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats) ...@@ -328,18 +331,18 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats)
struct git_pack_entry *pentry; struct git_pack_entry *pentry;
git_mwindow *w = NULL; git_mwindow *w = NULL;
int i; int i;
off_t entry_start = off; git_off_t entry_start = off;
void *packed; void *packed;
size_t entry_size; size_t entry_size;
entry = git__malloc(sizeof(struct entry)); entry = git__calloc(1, sizeof(*entry));
memset(entry, 0x0, sizeof(struct entry)); GITERR_CHECK_ALLOC(entry);
if (off > UINT31_MAX) { if (off > UINT31_MAX) {
entry->offset = UINT32_MAX; entry->offset = UINT32_MAX;
entry->offset_long = off; entry->offset_long = off;
} else { } else {
entry->offset = off; entry->offset = (uint32_t)off;
} }
error = git_packfile_unpack(&obj, idx->pack, &off); error = git_packfile_unpack(&obj, idx->pack, &off);
...@@ -369,13 +372,13 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats) ...@@ -369,13 +372,13 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats)
git_oid_cpy(&entry->oid, &oid); git_oid_cpy(&entry->oid, &oid);
entry->crc = crc32(0L, Z_NULL, 0); entry->crc = crc32(0L, Z_NULL, 0);
entry_size = off - entry_start; entry_size = (size_t)(off - entry_start);
packed = git_mwindow_open(mwf, &w, entry_start, entry_size, &left); packed = git_mwindow_open(mwf, &w, entry_start, entry_size, &left);
if (packed == NULL) { if (packed == NULL) {
error = git__rethrow(error, "Failed to open window to read packed data"); error = git__rethrow(error, "Failed to open window to read packed data");
goto cleanup; 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); git_mwindow_close(&w);
/* Add the object to the list */ /* Add the object to the list */
......
...@@ -309,7 +309,7 @@ static int workdir_iterator__expand_dir(workdir_iterator *wi) ...@@ -309,7 +309,7 @@ static int workdir_iterator__expand_dir(workdir_iterator *wi)
/* only push new ignores if this is not top level directory */ /* only push new ignores if this is not top level directory */
if (wi->stack->next != NULL) { 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]); (void)git_ignore__push_dir(&wi->ignores, &wi->path.ptr[slash_pos + 1]);
} }
......
...@@ -31,6 +31,11 @@ typedef struct { /* memory mapped buffer */ ...@@ -31,6 +31,11 @@ typedef struct { /* memory mapped buffer */
#endif #endif
} git_map; } 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_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset);
extern int p_munmap(git_map *map); extern int p_munmap(git_map *map);
......
...@@ -178,8 +178,10 @@ static git_mwindow *new_window( ...@@ -178,8 +178,10 @@ static git_mwindow *new_window(
* window. * window.
*/ */
if (git_futils_mmap_ro(&w->window_map, fd, w->offset, (size_t)len) < GIT_SUCCESS) if (git_futils_mmap_ro(&w->window_map, fd, w->offset, (size_t)len) < 0) {
goto cleanup; git__free(w);
return NULL;
}
ctl->mmap_calls++; ctl->mmap_calls++;
ctl->open_windows++; ctl->open_windows++;
...@@ -191,10 +193,6 @@ static git_mwindow *new_window( ...@@ -191,10 +193,6 @@ static git_mwindow *new_window(
ctl->peak_open_windows = ctl->open_windows; ctl->peak_open_windows = ctl->open_windows;
return w; return w;
cleanup:
git__free(w);
return NULL;
} }
/* /*
...@@ -205,7 +203,7 @@ unsigned char *git_mwindow_open( ...@@ -205,7 +203,7 @@ unsigned char *git_mwindow_open(
git_mwindow_file *mwf, git_mwindow_file *mwf,
git_mwindow **cursor, git_mwindow **cursor,
git_off_t offset, git_off_t offset,
int extra, size_t extra,
unsigned int *left) unsigned int *left)
{ {
git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl; git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
...@@ -253,11 +251,10 @@ unsigned char *git_mwindow_open( ...@@ -253,11 +251,10 @@ unsigned char *git_mwindow_open(
int git_mwindow_file_register(git_mwindow_file *mwf) int git_mwindow_file_register(git_mwindow_file *mwf)
{ {
git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl; git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
int error;
if (ctl->windowfiles.length == 0 && if (ctl->windowfiles.length == 0 &&
(error = git_vector_init(&ctl->windowfiles, 8, NULL)) < GIT_SUCCESS) git_vector_init(&ctl->windowfiles, 8, NULL) < 0)
return error; return -1;
return git_vector_insert(&ctl->windowfiles, mwf); return git_vector_insert(&ctl->windowfiles, mwf);
} }
......
...@@ -15,8 +15,8 @@ typedef struct git_mwindow { ...@@ -15,8 +15,8 @@ typedef struct git_mwindow {
struct git_mwindow *next; struct git_mwindow *next;
git_map window_map; git_map window_map;
git_off_t offset; git_off_t offset;
unsigned int last_used; size_t last_used;
unsigned int inuse_cnt; size_t inuse_cnt;
} git_mwindow; } git_mwindow;
typedef struct git_mwindow_file { typedef struct git_mwindow_file {
...@@ -37,7 +37,7 @@ typedef struct git_mwindow_ctl { ...@@ -37,7 +37,7 @@ typedef struct git_mwindow_ctl {
int git_mwindow_contains(git_mwindow *win, git_off_t offset); int git_mwindow_contains(git_mwindow *win, git_off_t offset);
void git_mwindow_free_all(git_mwindow_file *mwf); 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); 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); int git_mwindow_file_register(git_mwindow_file *mwf);
void git_mwindow_close(git_mwindow **w_cursor); void git_mwindow_close(git_mwindow **w_cursor);
......
...@@ -92,7 +92,7 @@ int git_object_lookup_prefix( ...@@ -92,7 +92,7 @@ int git_object_lookup_prefix(
assert(repo && object_out && id); assert(repo && object_out && id);
if (len < GIT_OID_MINPREFIXLEN) if (len < GIT_OID_MINPREFIXLEN)
return git__throw(GIT_EAMBIGUOUSOIDPREFIX, return git__throw(GIT_EAMBIGUOUS,
"Failed to lookup object. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN); "Failed to lookup object. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN);
error = git_repository_odb__weakptr(&odb, repo); error = git_repository_odb__weakptr(&odb, repo);
......
...@@ -145,10 +145,8 @@ int git_odb__hashlink(git_oid *out, const char *path) ...@@ -145,10 +145,8 @@ int git_odb__hashlink(git_oid *out, const char *path)
git_off_t size; git_off_t size;
int result; int result;
if (p_lstat(path, &st) < 0) { if (git_path_lstat(path, &st) < 0)
giterr_set(GITERR_OS, "Failed to stat object '%s'", path);
return -1; return -1;
}
size = st.st_size; size = st.st_size;
...@@ -188,7 +186,7 @@ int git_odb_hashfile(git_oid *out, const char *path, git_otype type) ...@@ -188,7 +186,7 @@ int git_odb_hashfile(git_oid *out, const char *path, git_otype type)
git_off_t size; git_off_t size;
int result, fd = git_futils_open_ro(path); int result, fd = git_futils_open_ro(path);
if (fd < 0) if (fd < 0)
return -1; return fd;
if ((size = git_futils_filesize(fd)) < 0 || !git__is_sizet(size)) { if ((size = git_futils_filesize(fd)) < 0 || !git__is_sizet(size)) {
giterr_set(GITERR_OS, "File size overflow for 32-bit systems"); giterr_set(GITERR_OS, "File size overflow for 32-bit systems");
...@@ -507,23 +505,20 @@ int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git ...@@ -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); error = b->read_header(len_p, type_p, b, id);
} }
if (error == GIT_EPASSTHROUGH) if (!error || error == GIT_EPASSTHROUGH)
return 0; return 0;
/* /*
* no backend could read only the header. * no backend could read only the header.
* try reading the whole object and freeing the contents * try reading the whole object and freeing the contents
*/ */
if (error < 0) { if ((error = git_odb_read(&object, db, id)) < 0)
if ((error = git_odb_read(&object, db, id)) < GIT_SUCCESS) return error; /* error already set - pass along */
return error; /* error already set - pass through */
*len_p = object->raw.len;
*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) 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) ...@@ -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); *out = git_cache_get(&db->cache, id);
if (*out != NULL) if (*out != NULL)
return GIT_SUCCESS; return 0;
for (i = 0; i < db->backends.length && error < 0; ++i) { for (i = 0; i < db->backends.length && error < 0; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i); backend_internal *internal = git_vector_get(&db->backends, i);
...@@ -546,15 +541,15 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) ...@@ -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); error = b->read(&raw.data, &raw.len, &raw.type, b, id);
} }
if (error == GIT_EPASSTHROUGH || error == GIT_SUCCESS) { if (error && error != GIT_EPASSTHROUGH)
*out = git_cache_try_store(&db->cache, new_odb_object(id, &raw)); return error;
return GIT_SUCCESS;
}
return git__rethrow(error, "Failed to read object"); *out = git_cache_try_store(&db->cache, new_odb_object(id, &raw));
return 0;
} }
int git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_id, unsigned int len) int git_odb_read_prefix(
git_odb_object **out, git_odb *db, const git_oid *short_id, unsigned int len)
{ {
unsigned int i; unsigned int i;
int error = GIT_ENOTFOUND; int error = GIT_ENOTFOUND;
...@@ -565,7 +560,7 @@ int git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_ ...@@ -565,7 +560,7 @@ int git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_
assert(out && db); assert(out && db);
if (len < GIT_OID_MINPREFIXLEN) if (len < GIT_OID_MINPREFIXLEN)
return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to lookup object. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN); return git_odb__error_ambiguous("prefix length too short");
if (len > GIT_OID_HEXSZ) if (len > GIT_OID_HEXSZ)
len = GIT_OID_HEXSZ; len = GIT_OID_HEXSZ;
...@@ -573,7 +568,7 @@ int git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_ ...@@ -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) { if (len == GIT_OID_HEXSZ) {
*out = git_cache_get(&db->cache, short_id); *out = git_cache_get(&db->cache, short_id);
if (*out != NULL) if (*out != NULL)
return GIT_SUCCESS; return 0;
} }
for (i = 0; i < db->backends.length && found < 2; ++i) { for (i = 0; i < db->backends.length && found < 2; ++i) {
...@@ -582,33 +577,24 @@ int git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_ ...@@ -582,33 +577,24 @@ int git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_
if (b->read != NULL) { if (b->read != NULL) {
error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, short_id, len); error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, short_id, len);
switch (error) { if (!error)
case GIT_SUCCESS:
found++; found++;
break; else if (error != GIT_ENOTFOUND && error != GIT_EPASSTHROUGH)
case GIT_ENOTFOUND: return error;
case GIT_EPASSTHROUGH:
break;
case GIT_EAMBIGUOUSOIDPREFIX:
return git__rethrow(error, "Failed to read object. Ambiguous sha1 prefix");
default:
return git__rethrow(error, "Failed to read object");
}
} }
} }
if (found == 1) { if (found == 0)
*out = git_cache_try_store(&db->cache, new_odb_object(&full_oid, &raw)); return git_odb__error_notfound("no match for prefix");
} else if (found > 1) { if (found > 1)
return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to read object. Ambiguous sha1 prefix"); return git_odb__error_ambiguous("multiple matches for prefix");
} else {
return git__throw(GIT_ENOTFOUND, "Failed to read object. Object not found");
}
return GIT_SUCCESS; *out = git_cache_try_store(&db->cache, new_odb_object(&full_oid, &raw));
return 0;
} }
int git_odb_write(git_oid *oid, git_odb *db, const void *data, size_t len, git_otype type) int git_odb_write(
git_oid *oid, git_odb *db, const void *data, size_t len, git_otype type)
{ {
unsigned int i; unsigned int i;
int error = GIT_ERROR; int error = GIT_ERROR;
...@@ -628,24 +614,25 @@ int git_odb_write(git_oid *oid, git_odb *db, const void *data, size_t len, git_o ...@@ -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); error = b->write(oid, b, data, len, type);
} }
if (error == GIT_EPASSTHROUGH || error == GIT_SUCCESS) if (!error || error == GIT_EPASSTHROUGH)
return GIT_SUCCESS; return 0;
/* if no backends were able to write the object directly, we try a streaming /* if no backends were able to write the object directly, we try a streaming
* write to the backends; just write the whole object into the stream in one * write to the backends; just write the whole object into the stream in one
* push */ * push */
if ((error = git_odb_open_wstream(&stream, db, len, type)) == GIT_SUCCESS) { if ((error = git_odb_open_wstream(&stream, db, len, type)) != 0)
stream->write(stream, data, len); return error;
error = stream->finalize_write(oid, stream);
stream->free(stream);
return GIT_SUCCESS;
}
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; unsigned int i;
int error = GIT_ERROR; int error = GIT_ERROR;
...@@ -666,10 +653,10 @@ int git_odb_open_wstream(git_odb_stream **stream, git_odb *db, size_t size, git_ ...@@ -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); error = init_fake_wstream(stream, b, size, type);
} }
if (error == GIT_EPASSTHROUGH || error == GIT_SUCCESS) if (error == GIT_EPASSTHROUGH)
return GIT_SUCCESS; error = 0;
return git__rethrow(error, "Failed to open write stream"); return error;
} }
int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oid) int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oid)
...@@ -687,9 +674,21 @@ int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oi ...@@ -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); error = b->readstream(stream, b, oid);
} }
if (error == GIT_EPASSTHROUGH || error == GIT_SUCCESS) if (error == GIT_EPASSTHROUGH)
return GIT_SUCCESS; error = 0;
return git__rethrow(error, "Failed to open read stream"); return error;
}
int git_odb__error_notfound(const char *message)
{
giterr_set(GITERR_ODB, "Object not found - %s", message);
return GIT_ENOTFOUND;
}
int git_odb__error_ambiguous(const char *message)
{
giterr_set(GITERR_ODB, "Ambiguous SHA1 prefix - %s", message);
return GIT_EAMBIGUOUS;
} }
...@@ -67,4 +67,14 @@ int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type); ...@@ -67,4 +67,14 @@ int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type);
*/ */
int git_odb__hashlink(git_oid *out, const char *path); int git_odb__hashlink(git_oid *out, const char *path);
/*
* Generate a GIT_ENOTFOUND error for the ODB.
*/
int git_odb__error_notfound(const char *message);
/*
* Generate a GIT_EAMBIGUOUS error for the ODB.
*/
int git_odb__error_ambiguous(const char *message);
#endif #endif
...@@ -137,19 +137,19 @@ static int packfile_load__cb(void *_data, git_buf *path); ...@@ -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 packfile_refresh_all(struct pack_backend *backend);
static int pack_entry_find(struct git_pack_entry *e, 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 /* Can find the offset of an object given
* a prefix of an identifier. * a prefix of an identifier.
* Throws GIT_EAMBIGUOUSOIDPREFIX if short oid * Sets GIT_EAMBIGUOUS if short oid is ambiguous.
* is ambiguous.
* This method assumes that len is between * This method assumes that len is between
* GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ. * GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ.
*/ */
static int pack_entry_find_prefix(struct git_pack_entry *e, static int pack_entry_find_prefix(
struct pack_backend *backend, struct git_pack_entry *e,
const git_oid *short_oid, struct pack_backend *backend,
unsigned int len); const git_oid *short_oid,
unsigned int len);
...@@ -215,27 +215,22 @@ static int packfile_load__cb(void *_data, git_buf *path) ...@@ -215,27 +215,22 @@ static int packfile_load__cb(void *_data, git_buf *path)
size_t i; size_t i;
if (git__suffixcmp(path->ptr, ".idx") != 0) if (git__suffixcmp(path->ptr, ".idx") != 0)
return GIT_SUCCESS; /* not an index */ return 0; /* not an index */
for (i = 0; i < backend->packs.length; ++i) { for (i = 0; i < backend->packs.length; ++i) {
struct git_pack_file *p = git_vector_get(&backend->packs, i); struct git_pack_file *p = git_vector_get(&backend->packs, i);
if (memcmp(p->pack_name, path->ptr, path->size - strlen(".idx")) == 0) if (memcmp(p->pack_name, path->ptr, path->size - strlen(".idx")) == 0)
return GIT_SUCCESS; return 0;
} }
error = git_packfile_check(&pack, path->ptr); error = git_packfile_check(&pack, path->ptr);
if (error == GIT_ENOTFOUND) { if (error == GIT_ENOTFOUND)
/* ignore missing .pack file as git does */ /* ignore missing .pack file as git does */
return GIT_SUCCESS; return GIT_SUCCESS;
} else if (error < GIT_SUCCESS) else if (error < 0)
return git__rethrow(error, "Failed to load packfile"); return error;
if (git_vector_insert(&backend->packs, pack) < GIT_SUCCESS) {
git__free(pack);
return GIT_ENOMEM;
}
return GIT_SUCCESS; return git_vector_insert(&backend->packs, pack);
} }
static int packfile_refresh_all(struct pack_backend *backend) static int packfile_refresh_all(struct pack_backend *backend)
...@@ -244,10 +239,10 @@ static int packfile_refresh_all(struct pack_backend *backend) ...@@ -244,10 +239,10 @@ static int packfile_refresh_all(struct pack_backend *backend)
struct stat st; struct stat st;
if (backend->pack_folder == NULL) if (backend->pack_folder == NULL)
return GIT_SUCCESS; return 0;
if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode)) if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode))
return git__throw(GIT_ENOTFOUND, "Failed to refresh packfiles. Backend not found"); return git_odb__error_notfound("failed to refresh packfiles");
if (st.st_mtime != backend->pack_folder_mtime) { if (st.st_mtime != backend->pack_folder_mtime) {
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
...@@ -257,14 +252,15 @@ static int packfile_refresh_all(struct pack_backend *backend) ...@@ -257,14 +252,15 @@ static int packfile_refresh_all(struct pack_backend *backend)
error = git_path_direach(&path, packfile_load__cb, (void *)backend); error = git_path_direach(&path, packfile_load__cb, (void *)backend);
git_buf_free(&path); git_buf_free(&path);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to refresh packfiles"); if (error < 0)
return error;
git_vector_sort(&backend->packs); git_vector_sort(&backend->packs);
backend->pack_folder_mtime = st.st_mtime; backend->pack_folder_mtime = st.st_mtime;
} }
return GIT_SUCCESS; return 0;
} }
static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backend, const git_oid *oid) static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backend, const git_oid *oid)
...@@ -272,12 +268,12 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen ...@@ -272,12 +268,12 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen
int error; int error;
size_t i; size_t i;
if ((error = packfile_refresh_all(backend)) < GIT_SUCCESS) if ((error = packfile_refresh_all(backend)) < 0)
return git__rethrow(error, "Failed to find pack entry"); return error;
if (backend->last_found && if (backend->last_found &&
git_pack_entry_find(e, backend->last_found, oid, GIT_OID_HEXSZ) == GIT_SUCCESS) git_pack_entry_find(e, backend->last_found, oid, GIT_OID_HEXSZ) == 0)
return GIT_SUCCESS; return 0;
for (i = 0; i < backend->packs.length; ++i) { for (i = 0; i < backend->packs.length; ++i) {
struct git_pack_file *p; struct git_pack_file *p;
...@@ -286,13 +282,13 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen ...@@ -286,13 +282,13 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen
if (p == backend->last_found) if (p == backend->last_found)
continue; continue;
if (git_pack_entry_find(e, p, oid, GIT_OID_HEXSZ) == GIT_SUCCESS) { if (git_pack_entry_find(e, p, oid, GIT_OID_HEXSZ) == 0) {
backend->last_found = p; backend->last_found = p;
return GIT_SUCCESS; return 0;
} }
} }
return git__throw(GIT_ENOTFOUND, "Failed to find pack entry"); return git_odb__error_notfound("failed to find pack entry");
} }
static int pack_entry_find_prefix( static int pack_entry_find_prefix(
...@@ -305,16 +301,15 @@ static int pack_entry_find_prefix( ...@@ -305,16 +301,15 @@ static int pack_entry_find_prefix(
size_t i; size_t i;
unsigned found = 0; unsigned found = 0;
if ((error = packfile_refresh_all(backend)) < GIT_SUCCESS) if ((error = packfile_refresh_all(backend)) < 0)
return git__rethrow(error, "Failed to find pack entry"); return error;
if (backend->last_found) { if (backend->last_found) {
error = git_pack_entry_find(e, backend->last_found, short_oid, len); error = git_pack_entry_find(e, backend->last_found, short_oid, len);
if (error == GIT_EAMBIGUOUSOIDPREFIX) { if (error == GIT_EAMBIGUOUS)
return git__rethrow(error, "Failed to find pack entry. Ambiguous sha1 prefix"); return error;
} else if (error == GIT_SUCCESS) { if (!error)
found = 1; found = 1;
}
} }
for (i = 0; i < backend->packs.length; ++i) { for (i = 0; i < backend->packs.length; ++i) {
...@@ -325,24 +320,21 @@ static int pack_entry_find_prefix( ...@@ -325,24 +320,21 @@ static int pack_entry_find_prefix(
continue; continue;
error = git_pack_entry_find(e, p, short_oid, len); error = git_pack_entry_find(e, p, short_oid, len);
if (error == GIT_EAMBIGUOUSOIDPREFIX) { if (error == GIT_EAMBIGUOUS)
return git__rethrow(error, "Failed to find pack entry. Ambiguous sha1 prefix"); return error;
} else if (error == GIT_SUCCESS) { if (!error) {
found++; if (++found > 1)
if (found > 1)
break; break;
backend->last_found = p; backend->last_found = p;
} }
} }
if (!found) { if (!found)
return git__rethrow(GIT_ENOTFOUND, "Failed to find pack entry"); return git_odb__error_notfound("failed to find pack entry");
} else if (found > 1) { else if (found > 1)
return git__rethrow(GIT_EAMBIGUOUSOIDPREFIX, "Failed to find pack entry. Ambiguous sha1 prefix"); return git_odb__error_ambiguous("found multiple pack entries");
} else { else
return GIT_SUCCESS; return 0;
}
} }
...@@ -374,17 +366,15 @@ static int pack_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, ...@@ -374,17 +366,15 @@ static int pack_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p,
git_rawobj raw; git_rawobj raw;
int error; int error;
if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < GIT_SUCCESS) if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < 0 ||
return git__rethrow(error, "Failed to read pack backend"); (error = git_packfile_unpack(&raw, e.p, &e.offset)) < 0)
return error;
if ((error = git_packfile_unpack(&raw, e.p, &e.offset)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to read pack backend");
*buffer_p = raw.data; *buffer_p = raw.data;
*len_p = raw.len; *len_p = raw.len;
*type_p = raw.type; *type_p = raw.type;
return GIT_SUCCESS; return 0;
} }
static int pack_backend__read_prefix( static int pack_backend__read_prefix(
...@@ -396,40 +386,38 @@ static int pack_backend__read_prefix( ...@@ -396,40 +386,38 @@ static int pack_backend__read_prefix(
const git_oid *short_oid, const git_oid *short_oid,
unsigned int len) unsigned int len)
{ {
int error = 0;
if (len < GIT_OID_MINPREFIXLEN) if (len < GIT_OID_MINPREFIXLEN)
return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to read pack backend. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN); error = git_odb__error_ambiguous("prefix length too short");
if (len >= GIT_OID_HEXSZ) { else if (len >= GIT_OID_HEXSZ) {
/* We can fall back to regular read method */ /* We can fall back to regular read method */
int error = pack_backend__read(buffer_p, len_p, type_p, backend, short_oid); error = pack_backend__read(buffer_p, len_p, type_p, backend, short_oid);
if (error == GIT_SUCCESS) if (!error)
git_oid_cpy(out_oid, short_oid); git_oid_cpy(out_oid, short_oid);
return error;
} else { } else {
struct git_pack_entry e; struct git_pack_entry e;
git_rawobj raw; git_rawobj raw;
int error;
if ((error = pack_entry_find_prefix(&e, (struct pack_backend *)backend, short_oid, len)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to read pack backend");
if ((error = git_packfile_unpack(&raw, e.p, &e.offset)) < GIT_SUCCESS) if ((error = pack_entry_find_prefix(
return git__rethrow(error, "Failed to read pack backend"); &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; *buffer_p = raw.data;
*type_p = raw.type; *len_p = raw.len;
git_oid_cpy(out_oid, &e.sha1); *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) static int pack_backend__exists(git_odb_backend *backend, const git_oid *oid)
{ {
struct git_pack_entry e; struct git_pack_entry e;
return pack_entry_find(&e, (struct pack_backend *)backend, oid) == GIT_SUCCESS; return pack_entry_find(&e, (struct pack_backend *)backend, oid) == 0;
} }
static void pack_backend__free(git_odb_backend *_backend) static void pack_backend__free(git_odb_backend *_backend)
...@@ -455,19 +443,16 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) ...@@ -455,19 +443,16 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
{ {
struct pack_backend *backend = NULL; struct pack_backend *backend = NULL;
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
int error = GIT_SUCCESS;
backend = git__calloc(1, sizeof(struct pack_backend)); backend = git__calloc(1, sizeof(struct pack_backend));
if (backend == NULL) GITERR_CHECK_ALLOC(backend);
return GIT_ENOMEM;
error = git_vector_init(&backend->packs, 8, packfile_sort__cb);
if (error < GIT_SUCCESS)
goto cleanup;
error = git_buf_joinpath(&path, objects_dir, "pack"); if (git_vector_init(&backend->packs, 8, packfile_sort__cb) < 0 ||
if (error < GIT_SUCCESS) git_buf_joinpath(&path, objects_dir, "pack") < 0)
goto cleanup; {
git__free(backend);
return -1;
}
if (git_path_isdir(git_buf_cstr(&path)) == true) { if (git_path_isdir(git_buf_cstr(&path)) == true) {
backend->pack_folder = git_buf_detach(&path); backend->pack_folder = git_buf_detach(&path);
...@@ -482,10 +467,7 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) ...@@ -482,10 +467,7 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
*backend_out = (git_odb_backend *)backend; *backend_out = (git_odb_backend *)backend;
cleanup:
if (error < GIT_SUCCESS)
git__free(backend);
git_buf_free(&path); git_buf_free(&path);
return error; return 0;
} }
...@@ -70,7 +70,7 @@ struct git_pack_file { ...@@ -70,7 +70,7 @@ struct git_pack_file {
}; };
struct git_pack_entry { struct git_pack_entry {
off_t offset; git_off_t offset;
git_oid sha1; git_oid sha1;
struct git_pack_file *p; struct git_pack_file *p;
}; };
...@@ -80,13 +80,13 @@ int git_packfile_unpack_header( ...@@ -80,13 +80,13 @@ int git_packfile_unpack_header(
git_otype *type_p, git_otype *type_p,
git_mwindow_file *mwf, git_mwindow_file *mwf,
git_mwindow **w_curs, git_mwindow **w_curs,
off_t *curpos); git_off_t *curpos);
int git_packfile_unpack(git_rawobj *obj, struct git_pack_file *p, off_t *obj_offset); int git_packfile_unpack(git_rawobj *obj, struct git_pack_file *p, git_off_t *obj_offset);
off_t get_delta_base(struct git_pack_file *p, git_mwindow **w_curs, git_off_t get_delta_base(struct git_pack_file *p, git_mwindow **w_curs,
off_t *curpos, git_otype type, git_off_t *curpos, git_otype type,
off_t delta_obj_offset); git_off_t delta_obj_offset);
void packfile_free(struct git_pack_file *p); void packfile_free(struct git_pack_file *p);
int git_packfile_check(struct git_pack_file **pack_out, const char *path); int git_packfile_check(struct git_pack_file **pack_out, const char *path);
......
...@@ -49,16 +49,14 @@ int git_path_basename_r(git_buf *buffer, const char *path) ...@@ -49,16 +49,14 @@ int git_path_basename_r(git_buf *buffer, const char *path)
while (startp > path && *(startp - 1) != '/') while (startp > path && *(startp - 1) != '/')
startp--; startp--;
len = endp - startp +1; /* Cast is safe because max path < max int */
len = (int)(endp - startp + 1);
Exit: Exit:
result = len; result = len;
if (buffer != NULL) { if (buffer != NULL && git_buf_set(buffer, startp, len) < 0)
if (git_buf_set(buffer, startp, len) < GIT_SUCCESS) return -1;
return git__rethrow(GIT_ENOMEM,
"Could not get basename of '%s'", path);
}
return result; return result;
} }
...@@ -99,7 +97,8 @@ int git_path_dirname_r(git_buf *buffer, const char *path) ...@@ -99,7 +97,8 @@ int git_path_dirname_r(git_buf *buffer, const char *path)
endp--; endp--;
} while (endp > 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 #ifdef GIT_WIN32
/* Mimic unix behavior where '/.git' returns '/': 'C:/.git' will return /* 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) ...@@ -114,11 +113,8 @@ int git_path_dirname_r(git_buf *buffer, const char *path)
Exit: Exit:
result = len; result = len;
if (buffer != NULL) { if (buffer != NULL && git_buf_set(buffer, path, len) < 0)
if (git_buf_set(buffer, path, len) < GIT_SUCCESS) return -1;
return git__rethrow(GIT_ENOMEM,
"Could not get dirname of '%s'", path);
}
return result; return result;
} }
...@@ -152,7 +148,7 @@ char *git_path_basename(const char *path) ...@@ -152,7 +148,7 @@ char *git_path_basename(const char *path)
const char *git_path_topdir(const char *path) const char *git_path_topdir(const char *path)
{ {
size_t len; size_t len;
int i; ssize_t i;
assert(path); assert(path);
len = strlen(path); len = strlen(path);
...@@ -160,7 +156,7 @@ const char *git_path_topdir(const char *path) ...@@ -160,7 +156,7 @@ const char *git_path_topdir(const char *path)
if (!len || path[len - 1] != '/') if (!len || path[len - 1] != '/')
return NULL; return NULL;
for (i = len - 2; i >= 0; --i) for (i = (ssize_t)len - 2; i >= 0; --i)
if (path[i] == '/') if (path[i] == '/')
break; break;
...@@ -199,7 +195,8 @@ int git_path_prettify(git_buf *path_out, const char *path, const char *base) ...@@ -199,7 +195,8 @@ int git_path_prettify(git_buf *path_out, const char *path, const char *base)
} }
if (p_realpath(path, buf) == NULL) { 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; return (errno == ENOENT) ? GIT_ENOTFOUND : -1;
} }
...@@ -211,10 +208,8 @@ int git_path_prettify(git_buf *path_out, const char *path, const char *base) ...@@ -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) int git_path_prettify_dir(git_buf *path_out, const char *path, const char *base)
{ {
if (git_path_prettify(path_out, path, base) < 0) int error = git_path_prettify(path_out, path, base);
return -1; return (error < 0) ? error : git_path_to_dir(path_out);
return git_path_to_dir(path_out);
} }
int git_path_to_dir(git_buf *path) int git_path_to_dir(git_buf *path)
...@@ -224,10 +219,7 @@ 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] != '/') path->ptr[path->size - 1] != '/')
git_buf_putc(path, '/'); git_buf_putc(path, '/');
if (git_buf_oom(path)) return git_buf_oom(path) ? -1 : 0;
return -1;
return 0;
} }
void git_path_string_to_dir(char* path, size_t size) 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) ...@@ -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 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); assert(decoded_out && input);
len = strlen(input); len = (int)strlen(input);
git_buf_clear(decoded_out); git_buf_clear(decoded_out);
for(i = 0; i < len; i++) for(i = 0; i < len; i++)
...@@ -268,39 +260,40 @@ int git__percent_decode(git_buf *decoded_out, const char *input) ...@@ -268,39 +260,40 @@ int git__percent_decode(git_buf *decoded_out, const char *input)
i += 2; i += 2;
append: append:
error = git_buf_putc(decoded_out, c); if (git_buf_putc(decoded_out, c) < 0)
if (error < GIT_SUCCESS) return -1;
return git__rethrow(error, "Failed to percent decode '%s'.", input);
} }
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 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); assert(local_path_out && file_url);
if (git__prefixcmp(file_url, "file://") != 0) if (git__prefixcmp(file_url, "file://") != 0)
return git__throw(GIT_EINVALIDPATH, return error_invalid_local_file_uri(file_url);
"Parsing of '%s' failed. A file Uri is expected (ie. with 'file://' scheme).",
file_url);
offset += 7; offset += 7;
len = strlen(file_url); len = (int)strlen(file_url);
if (offset < len && file_url[offset] == '/') if (offset < len && file_url[offset] == '/')
offset++; offset++;
else if (offset < len && git__prefixcmp(file_url + offset, "localhost/") == 0) else if (offset < len && git__prefixcmp(file_url + offset, "localhost/") == 0)
offset += 10; offset += 10;
else else
return git__throw(GIT_EINVALIDPATH, return error_invalid_local_file_uri(file_url);
"Parsing of '%s' failed. A local file Uri is expected.", file_url);
if (offset >= len || file_url[offset] == '/') if (offset >= len || file_url[offset] == '/')
return git__throw(GIT_EINVALIDPATH, return error_invalid_local_file_uri(file_url);
"Parsing of '%s' failed. Invalid file Uri format.", file_url);
#ifndef _MSC_VER #ifndef _MSC_VER
offset--; /* A *nix absolute path starts with a forward slash */ 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) ...@@ -308,11 +301,7 @@ int git_path_fromurl(git_buf *local_path_out, const char *file_url)
git_buf_clear(local_path_out); git_buf_clear(local_path_out);
error = git__percent_decode(local_path_out, file_url + offset); return 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;
} }
int git_path_walk_up( int git_path_walk_up(
...@@ -321,7 +310,7 @@ int git_path_walk_up( ...@@ -321,7 +310,7 @@ int git_path_walk_up(
int (*cb)(void *data, git_buf *), int (*cb)(void *data, git_buf *),
void *data) void *data)
{ {
int error = GIT_SUCCESS; int error = 0;
git_buf iter; git_buf iter;
ssize_t stop = 0, scan; ssize_t stop = 0, scan;
char oldc = '\0'; char oldc = '\0';
...@@ -341,7 +330,7 @@ int git_path_walk_up( ...@@ -341,7 +330,7 @@ int git_path_walk_up(
iter.asize = path->asize; iter.asize = path->asize;
while (scan >= stop) { while (scan >= stop) {
if ((error = cb(data, &iter)) < GIT_SUCCESS) if ((error = cb(data, &iter)) < 0)
break; break;
iter.ptr[scan] = oldc; iter.ptr[scan] = oldc;
scan = git_buf_rfind_next(&iter, '/'); scan = git_buf_rfind_next(&iter, '/');
...@@ -394,6 +383,18 @@ bool git_path_isfile(const char *path) ...@@ -394,6 +383,18 @@ bool git_path_isfile(const char *path)
return S_ISREG(st.st_mode) != 0; 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( static bool _check_dir_contents(
git_buf *dir, git_buf *dir,
const char *sub, const char *sub,
...@@ -434,25 +435,24 @@ bool git_path_contains_file(git_buf *base, const char *file) ...@@ -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 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) if (base != NULL && git_path_root(path) < 0)
error = git_buf_joinpath(dir, base, path); error = git_buf_joinpath(dir, base, path);
else else
error = git_buf_sets(dir, path); error = git_buf_sets(dir, path);
if (error == GIT_SUCCESS) { if (!error) {
char buf[GIT_PATH_MAX]; char buf[GIT_PATH_MAX];
if (p_realpath(dir->ptr, buf) != NULL) if (p_realpath(dir->ptr, buf) != NULL)
error = git_buf_sets(dir, buf); error = git_buf_sets(dir, buf);
} }
/* call dirname if this is not a directory */ /* call dirname if this is not a directory */
if (error == GIT_SUCCESS && git_path_isdir(dir->ptr) == false) if (!error && git_path_isdir(dir->ptr) == false)
if (git_path_dirname_r(dir, dir->ptr) < GIT_SUCCESS) error = git_path_dirname_r(dir, dir->ptr);
error = GIT_ENOMEM;
if (error == GIT_SUCCESS) if (!error)
error = git_path_to_dir(dir); error = git_path_to_dir(dir);
return error; return error;
...@@ -497,9 +497,9 @@ int git_path_direach( ...@@ -497,9 +497,9 @@ int git_path_direach(
return -1; return -1;
wd_len = path->size; wd_len = path->size;
dir = opendir(path->ptr);
if (!dir) { if ((dir = opendir(path->ptr)) == NULL) {
giterr_set(GITERR_OS, "Failed to 'opendir' %s", path->ptr); giterr_set(GITERR_OS, "Failed to open directory '%s'", path->ptr);
return -1; return -1;
} }
...@@ -541,9 +541,10 @@ int git_path_dirload( ...@@ -541,9 +541,10 @@ int git_path_dirload(
path_len = strlen(path); path_len = strlen(path);
assert(path_len > 0 && path_len >= prefix_len); assert(path_len > 0 && path_len >= prefix_len);
if ((dir = opendir(path)) == NULL) if ((dir = opendir(path)) == NULL) {
return git__throw(GIT_EOSERR, "Failed to process `%s` tree structure." giterr_set(GITERR_OS, "Failed to open directory '%s'", path);
" An error occured while opening the directory", path); return -1;
}
path += prefix_len; path += prefix_len;
path_len -= prefix_len; path_len -= prefix_len;
...@@ -560,8 +561,7 @@ int git_path_dirload( ...@@ -560,8 +561,7 @@ int git_path_dirload(
entry_path = git__malloc( entry_path = git__malloc(
path_len + need_slash + entry_len + 1 + alloc_extra); path_len + need_slash + entry_len + 1 + alloc_extra);
if (entry_path == NULL) GITERR_CHECK_ALLOC(entry_path);
return GIT_ENOMEM;
if (path_len) if (path_len)
memcpy(entry_path, path, path_len); memcpy(entry_path, path, path_len);
...@@ -570,19 +570,16 @@ int git_path_dirload( ...@@ -570,19 +570,16 @@ int git_path_dirload(
memcpy(&entry_path[path_len + need_slash], de->d_name, entry_len); memcpy(&entry_path[path_len + need_slash], de->d_name, entry_len);
entry_path[path_len + need_slash + entry_len] = '\0'; entry_path[path_len + need_slash + entry_len] = '\0';
if ((error = git_vector_insert(contents, entry_path)) < GIT_SUCCESS) { if (git_vector_insert(contents, entry_path) < 0)
git__free(entry_path); return -1;
return error;
}
} }
closedir(dir); closedir(dir);
if (error != GIT_SUCCESS) if (error != 0)
return git__throw( giterr_set(GITERR_OS, "Failed to process directory entry in '%s'", path);
GIT_EOSERR, "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) int git_path_with_stat_cmp(const void *a, const void *b)
...@@ -601,11 +598,12 @@ int git_path_dirload_with_stat( ...@@ -601,11 +598,12 @@ int git_path_dirload_with_stat(
git_path_with_stat *ps; git_path_with_stat *ps;
git_buf full = GIT_BUF_INIT; git_buf full = GIT_BUF_INIT;
if ((error = git_buf_set(&full, path, prefix_len)) != GIT_SUCCESS) if (git_buf_set(&full, path, prefix_len) < 0)
return error; return -1;
if ((error = git_path_dirload(path, prefix_len, error = git_path_dirload(
sizeof(git_path_with_stat) + 1, contents)) != GIT_SUCCESS) { path, prefix_len, sizeof(git_path_with_stat) + 1, contents);
if (error < 0) {
git_buf_free(&full); git_buf_free(&full);
return error; return error;
} }
...@@ -616,8 +614,10 @@ int git_path_dirload_with_stat( ...@@ -616,8 +614,10 @@ int git_path_dirload_with_stat(
memmove(ps->path, ps, path_len + 1); memmove(ps->path, ps, path_len + 1);
ps->path_len = path_len; ps->path_len = path_len;
git_buf_joinpath(&full, full.ptr, ps->path); if ((error = git_buf_joinpath(&full, full.ptr, ps->path)) < 0 ||
p_lstat(full.ptr, &ps->st); (error = git_path_lstat(full.ptr, &ps->st)) < 0)
break;
git_buf_truncate(&full, prefix_len); git_buf_truncate(&full, prefix_len);
if (S_ISDIR(ps->st.st_mode)) { if (S_ISDIR(ps->st.st_mode)) {
......
...@@ -130,6 +130,11 @@ extern bool git_path_isdir(const char *path); ...@@ -130,6 +130,11 @@ extern bool git_path_isdir(const char *path);
extern bool git_path_isfile(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. * Check if the parent directory contains the item.
* *
* @param dir Directory to check. * @param dir Directory to check.
......
...@@ -34,9 +34,9 @@ int p_getcwd(char *buffer_out, size_t size) ...@@ -34,9 +34,9 @@ int p_getcwd(char *buffer_out, size_t size)
return -1; return -1;
git_path_mkposix(buffer_out); 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) int p_rename(const char *from, const char *to)
......
...@@ -842,7 +842,7 @@ static int reference_path_available( ...@@ -842,7 +842,7 @@ static int reference_path_available(
if (!data.available) { if (!data.available) {
giterr_set(GITERR_REFERENCE, giterr_set(GITERR_REFERENCE,
"The path to reference '%s' collides with an existing one"); "The path to reference '%s' collides with an existing one", ref);
return -1; return -1;
} }
...@@ -902,7 +902,7 @@ static int reference_can_write( ...@@ -902,7 +902,7 @@ static int reference_can_write(
* the rename; the existing one would be overwritten */ * the rename; the existing one would be overwritten */
if (exists) { if (exists) {
giterr_set(GITERR_REFERENCE, giterr_set(GITERR_REFERENCE,
"A reference with that name (%s) already exists"); "A reference with that name (%s) already exists", refname);
return GIT_EEXISTS; return GIT_EEXISTS;
} }
} }
......
...@@ -377,17 +377,15 @@ void git_repository_set_index(git_repository *repo, git_index *index) ...@@ -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) static int retrieve_device(dev_t *device_out, const char *path)
{ {
int error;
struct stat path_info; struct stat path_info;
assert(device_out); assert(device_out);
if (p_lstat(path, &path_info)) { if ((error = git_path_lstat(path, &path_info)) == 0)
giterr_set(GITERR_OS, "Failed to retrieve file information: %s", strerror(errno)); *device_out = path_info.st_dev;
return -1;
}
*device_out = path_info.st_dev; return error;
return 0;
} }
/* /*
......
...@@ -17,12 +17,7 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs ...@@ -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 mprot = 0;
int mflag = 0; int mflag = 0;
assert((out != NULL) && (len > 0)); GIT_MMAP_VALIDATE(out, len, prot, flags);
if ((out == NULL) || (len == 0)) {
errno = EINVAL;
return git__throw(GIT_ERROR, "Failed to mmap. No map or zero length");
}
out->data = NULL; out->data = NULL;
out->len = 0; out->len = 0;
...@@ -31,39 +26,28 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs ...@@ -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; mprot = PROT_WRITE;
else if (prot & GIT_PROT_READ) else if (prot & GIT_PROT_READ)
mprot = PROT_READ; mprot = PROT_READ;
else {
errno = EINVAL;
return git__throw(GIT_ERROR, "Failed to mmap. Invalid protection parameters");
}
if ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED) if ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)
mflag = MAP_SHARED; mflag = MAP_SHARED;
else if ((flags & GIT_MAP_TYPE) == GIT_MAP_PRIVATE) else if ((flags & GIT_MAP_TYPE) == GIT_MAP_PRIVATE)
mflag = MAP_PRIVATE; mflag = MAP_PRIVATE;
if (flags & GIT_MAP_FIXED) { out->data = mmap(NULL, len, mprot, mflag, fd, offset);
errno = EINVAL; if (!out->data || out->data == MAP_FAILED) {
return git__throw(GIT_ERROR, "Failed to mmap. FIXED not set"); giterr_set(GITERR_OS, "Failed to mmap. Could not write data");
return -1;
} }
out->data = mmap(NULL, len, mprot, mflag, fd, offset);
if (!out->data || out->data == MAP_FAILED)
return git__throw(GIT_EOSERR, "Failed to mmap. Could not write data");
out->len = len; out->len = len;
return GIT_SUCCESS; return 0;
} }
int p_munmap(git_map *map) int p_munmap(git_map *map)
{ {
assert(map != NULL); assert(map != NULL);
if (!map)
return git__throw(GIT_ERROR, "Failed to munmap. Map does not exist");
munmap(map->data, map->len); munmap(map->data, map->len);
return 0;
return GIT_SUCCESS;
} }
#endif #endif
......
...@@ -27,8 +27,8 @@ static int init_filter(char *filter, size_t n, const char *dir) ...@@ -27,8 +27,8 @@ static int init_filter(char *filter, size_t n, const char *dir)
git__DIR *git__opendir(const char *dir) git__DIR *git__opendir(const char *dir)
{ {
char filter[4096]; char filter[4096];
wchar_t* filter_w; wchar_t* filter_w = NULL;
git__DIR *new; git__DIR *new = NULL;
if (!dir || !init_filter(filter, sizeof(filter), dir)) if (!dir || !init_filter(filter, sizeof(filter), dir))
return NULL; return NULL;
...@@ -37,25 +37,29 @@ git__DIR *git__opendir(const char *dir) ...@@ -37,25 +37,29 @@ git__DIR *git__opendir(const char *dir)
if (!new) if (!new)
return NULL; return NULL;
new->dir = git__malloc(strlen(dir)+1); new->dir = git__strdup(dir);
if (!new->dir) { if (!new->dir)
git__free(new); goto fail;
return NULL;
}
strcpy(new->dir, dir);
filter_w = gitwin_to_utf16(filter); filter_w = gitwin_to_utf16(filter);
if (!filter_w)
goto fail;
new->h = FindFirstFileW(filter_w, &new->f); new->h = FindFirstFileW(filter_w, &new->f);
git__free(filter_w); git__free(filter_w);
if (new->h == INVALID_HANDLE_VALUE) { if (new->h == INVALID_HANDLE_VALUE) {
git__free(new->dir); giterr_set(GITERR_OS, "Could not open directory '%s'", dir);
git__free(new); goto fail;
return NULL;
} }
new->first = 1;
new->first = 1;
return new; return new;
fail:
git__free(new->dir);
git__free(new);
return NULL;
} }
int git__readdir_ext( int git__readdir_ext(
...@@ -67,22 +71,32 @@ int git__readdir_ext( ...@@ -67,22 +71,32 @@ int git__readdir_ext(
if (!d || !entry || !result || d->h == INVALID_HANDLE_VALUE) if (!d || !entry || !result || d->h == INVALID_HANDLE_VALUE)
return -1; return -1;
*result = NULL;
if (d->first) if (d->first)
d->first = 0; d->first = 0;
else if (!FindNextFileW(d->h, &d->f)) { else if (!FindNextFileW(d->h, &d->f)) {
*result = NULL; if (GetLastError() == ERROR_NO_MORE_FILES)
return 0; 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)) if (wcslen(d->f.cFileName) >= sizeof(entry->d_name))
return -1; return -1;
entry->d_ino = 0; entry->d_ino = 0;
WideCharToMultiByte(
if (WideCharToMultiByte(
gitwin_get_codepage(), 0, d->f.cFileName, -1, 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; *result = entry;
if (is_dir != NULL) if (is_dir != NULL)
*is_dir = ((d->f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0); *is_dir = ((d->f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
...@@ -102,32 +116,40 @@ void git__rewinddir(git__DIR *d) ...@@ -102,32 +116,40 @@ void git__rewinddir(git__DIR *d)
char filter[4096]; char filter[4096];
wchar_t* filter_w; wchar_t* filter_w;
if (d) { if (!d)
if (d->h != INVALID_HANDLE_VALUE) return;
FindClose(d->h);
if (d->h != INVALID_HANDLE_VALUE) {
FindClose(d->h);
d->h = INVALID_HANDLE_VALUE; d->h = INVALID_HANDLE_VALUE;
d->first = 0; d->first = 0;
}
if (init_filter(filter, sizeof(filter), d->dir)) { if (!init_filter(filter, sizeof(filter), d->dir) ||
filter_w = gitwin_to_utf16(filter); (filter_w = gitwin_to_utf16(filter)) == NULL)
d->h = FindFirstFileW(filter_w, &d->f); return;
git__free(filter_w);
if (d->h != INVALID_HANDLE_VALUE) d->h = FindFirstFileW(filter_w, &d->f);
d->first = 1; 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) int git__closedir(git__DIR *d)
{ {
if (d) { if (!d)
if (d->h != INVALID_HANDLE_VALUE) return 0;
FindClose(d->h);
if (d->dir) if (d->h != INVALID_HANDLE_VALUE) {
git__free(d->dir); FindClose(d->h);
git__free(d); d->h = INVALID_HANDLE_VALUE;
} }
git__free(d->dir);
d->dir = NULL;
git__free(d);
return 0; return 0;
} }
...@@ -33,12 +33,7 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs ...@@ -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_start;
git_off_t page_offset; git_off_t page_offset;
assert((out != NULL) && (len > 0)); GIT_MMAP_VALIDATE(out, len, prot, flags);
if ((out == NULL) || (len == 0)) {
errno = EINVAL;
return git__throw(GIT_ERROR, "Failed to mmap. No map or zero length");
}
out->data = NULL; out->data = NULL;
out->len = 0; out->len = 0;
...@@ -46,86 +41,75 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs ...@@ -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) { if (fh == INVALID_HANDLE_VALUE) {
errno = EBADF; errno = EBADF;
return git__throw(GIT_ERROR, "Failed to mmap. Invalid handle value"); giterr_set(GITERR_OS, "Failed to mmap. Invalid handle value");
return -1;
} }
if (prot & GIT_PROT_WRITE) if (prot & GIT_PROT_WRITE)
fmap_prot |= PAGE_READWRITE; fmap_prot |= PAGE_READWRITE;
else if (prot & GIT_PROT_READ) else if (prot & GIT_PROT_READ)
fmap_prot |= PAGE_READONLY; fmap_prot |= PAGE_READONLY;
else {
errno = EINVAL;
return git__throw(GIT_ERROR, "Failed to mmap. Invalid protection parameters");
}
if (prot & GIT_PROT_WRITE) if (prot & GIT_PROT_WRITE)
view_prot |= FILE_MAP_WRITE; view_prot |= FILE_MAP_WRITE;
if (prot & GIT_PROT_READ) if (prot & GIT_PROT_READ)
view_prot |= FILE_MAP_READ; view_prot |= FILE_MAP_READ;
if (flags & GIT_MAP_FIXED) {
errno = EINVAL;
return git__throw(GIT_ERROR, "Failed to mmap. FIXED not set");
}
page_start = (offset / page_size) * page_size; page_start = (offset / page_size) * page_size;
page_offset = offset - page_start; page_offset = offset - page_start;
if (page_offset != 0) { /* offset must be multiple of page size */ if (page_offset != 0) { /* offset must be multiple of page size */
errno = EINVAL; errno = EINVAL;
return git__throw(GIT_ERROR, "Failed to mmap. Offset must be multiple of page size"); giterr_set(GITERR_OS, "Failed to mmap. Offset must be multiple of page size");
return -1;
} }
out->fmh = CreateFileMapping(fh, NULL, fmap_prot, 0, 0, NULL); out->fmh = CreateFileMapping(fh, NULL, fmap_prot, 0, 0, NULL);
if (!out->fmh || out->fmh == INVALID_HANDLE_VALUE) { if (!out->fmh || out->fmh == INVALID_HANDLE_VALUE) {
/* errno = ? */ giterr_set(GITERR_OS, "Failed to mmap. Invalid handle value");
out->fmh = NULL; out->fmh = NULL;
return git__throw(GIT_ERROR, "Failed to mmap. Invalid handle value"); return -1;
} }
assert(sizeof(git_off_t) == 8); assert(sizeof(git_off_t) == 8);
off_low = (DWORD)(page_start); off_low = (DWORD)(page_start);
off_hi = (DWORD)(page_start >> 32); off_hi = (DWORD)(page_start >> 32);
out->data = MapViewOfFile(out->fmh, view_prot, off_hi, off_low, len); out->data = MapViewOfFile(out->fmh, view_prot, off_hi, off_low, len);
if (!out->data) { if (!out->data) {
/* errno = ? */ giterr_set(GITERR_OS, "Failed to mmap. No data written");
CloseHandle(out->fmh); CloseHandle(out->fmh);
out->fmh = NULL; out->fmh = NULL;
return git__throw(GIT_ERROR, "Failed to mmap. No data written"); return -1;
} }
out->len = len; out->len = len;
return GIT_SUCCESS; return 0;
} }
int p_munmap(git_map *map) int p_munmap(git_map *map)
{ {
assert(map != NULL); int error = 0;
if (!map) assert(map != NULL);
return git__throw(GIT_ERROR, "Failed to munmap. Map does not exist");
if (map->data) { if (map->data) {
if (!UnmapViewOfFile(map->data)) { if (!UnmapViewOfFile(map->data)) {
/* errno = ? */ giterr_set(GITERR_OS, "Failed to munmap. Could not unmap view of file");
CloseHandle(map->fmh); error = -1;
map->data = NULL;
map->fmh = NULL;
return git__throw(GIT_ERROR, "Failed to munmap. Could not unmap view of file");
} }
map->data = NULL; map->data = NULL;
} }
if (map->fmh) { if (map->fmh) {
if (!CloseHandle(map->fmh)) { if (!CloseHandle(map->fmh)) {
/* errno = ? */ giterr_set(GITERR_OS, "Failed to munmap. Could not close handle");
map->fmh = NULL; error = -1;
return git__throw(GIT_ERROR, "Failed to munmap. Could not close handle");
} }
map->fmh = NULL; map->fmh = NULL;
} }
return GIT_SUCCESS; return error;
} }
/ < 0) /*
* Copyright (C) 2009-2012 the libgit2 contributors * Copyright (C) 2009-2012 the libgit2 contributors
* *
* This file is part of libgit2, distributed under the GNU GPL v2 with * This file is part of libgit2, distributed under the GNU GPL v2 with
...@@ -17,10 +17,11 @@ int p_unlink(const char *path) ...@@ -17,10 +17,11 @@ int p_unlink(const char *path)
int ret = 0; int ret = 0;
wchar_t* buf; wchar_t* buf;
buf = gitwin_to_utf16(path); if ((buf = gitwin_to_utf16(path)) != NULL) {
_wchmod(buf, 0666); _wchmod(buf, 0666);
ret = _wunlink(buf); ret = _wunlink(buf);
git__free(buf); git__free(buf);
}
return ret; return ret;
} }
...@@ -60,6 +61,8 @@ static int do_lstat(const char *file_name, struct stat *buf) ...@@ -60,6 +61,8 @@ static int do_lstat(const char *file_name, struct stat *buf)
{ {
WIN32_FILE_ATTRIBUTE_DATA fdata; WIN32_FILE_ATTRIBUTE_DATA fdata;
wchar_t* fbuf = gitwin_to_utf16(file_name); wchar_t* fbuf = gitwin_to_utf16(file_name);
if (!fbuf)
return -1;
if (GetFileAttributesExW(fbuf, GetFileExInfoStandard, &fdata)) { if (GetFileAttributesExW(fbuf, GetFileExInfoStandard, &fdata)) {
int fMode = S_IREAD; int fMode = S_IREAD;
...@@ -87,54 +90,43 @@ static int do_lstat(const char *file_name, struct stat *buf) ...@@ -87,54 +90,43 @@ static int do_lstat(const char *file_name, struct stat *buf)
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
git__free(fbuf); git__free(fbuf);
return GIT_SUCCESS; return 0;
} }
git__free(fbuf); git__free(fbuf);
return -1;
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;
}
} }
int p_lstat(const char *file_name, struct stat *buf) int p_lstat(const char *file_name, struct stat *buf)
{ {
int namelen, error; int error;
char alt_name[GIT_PATH_MAX]; size_t namelen;
char *alt_name;
if ((error = do_lstat(file_name, buf)) == GIT_SUCCESS) if (do_lstat(file_name, buf) == 0)
return GIT_SUCCESS; return 0;
/* if file_name ended in a '/', Windows returned ENOENT; /* if file_name ended in a '/', Windows returned ENOENT;
* try again without trailing slashes * try again without trailing slashes
*/ */
if (error != GIT_EINVALIDPATH)
return git__throw(GIT_EOSERR, "Failed to lstat file");
namelen = strlen(file_name); namelen = strlen(file_name);
if (namelen && file_name[namelen-1] != '/') if (namelen && file_name[namelen-1] != '/')
return git__throw(GIT_EOSERR, "Failed to lstat file"); return -1;
while (namelen && file_name[namelen-1] == '/') while (namelen && file_name[namelen-1] == '/')
--namelen; --namelen;
if (!namelen || namelen >= GIT_PATH_MAX) if (!namelen)
return git__throw(GIT_ENOMEM, "Failed to lstat file"); return -1;
alt_name = git__strndup(file_name, namelen);
if (!alt_name)
return -1;
error = do_lstat(alt_name, buf);
memcpy(alt_name, file_name, namelen); git__free(alt_name);
alt_name[namelen] = 0; return error;
return do_lstat(alt_name, buf);
} }
int p_readlink(const char *link, char *target, size_t target_len) 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) ...@@ -145,6 +137,9 @@ int p_readlink(const char *link, char *target, size_t target_len)
DWORD dwRet; DWORD dwRet;
wchar_t* link_w; wchar_t* link_w;
wchar_t* target_w; wchar_t* target_w;
int error = 0;
assert(link && target && target_len > 0);
/* /*
* Try to load the pointer to pGetFinalPath dynamically, because * 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) ...@@ -156,12 +151,15 @@ int p_readlink(const char *link, char *target, size_t target_len)
if (library != NULL) if (library != NULL)
pGetFinalPath = (fpath_func)GetProcAddress(library, "GetFinalPathNameByHandleW"); pGetFinalPath = (fpath_func)GetProcAddress(library, "GetFinalPathNameByHandleW");
if (pGetFinalPath == NULL) if (pGetFinalPath == NULL) {
return git__throw(GIT_EOSERR, giterr_set(GITERR_OS,
"'GetFinalPathNameByHandleW' is not available in this platform"); "'GetFinalPathNameByHandleW' is not available in this platform");
return -1;
}
} }
link_w = gitwin_to_utf16(link); link_w = gitwin_to_utf16(link);
GITERR_CHECK_ALLOC(link_w);
hFile = CreateFileW(link_w, // file to open hFile = CreateFileW(link_w, // file to open
GENERIC_READ, // open for reading GENERIC_READ, // open for reading
...@@ -173,50 +171,49 @@ int p_readlink(const char *link, char *target, size_t target_len) ...@@ -173,50 +171,49 @@ int p_readlink(const char *link, char *target, size_t target_len)
git__free(link_w); git__free(link_w);
if (hFile == INVALID_HANDLE_VALUE) if (hFile == INVALID_HANDLE_VALUE) {
return GIT_EOSERR; giterr_set(GITERR_OS, "Cannot open '%s' for reading", link);
return -1;
if (target_len <= 0) {
return GIT_EINVALIDARGS;
} }
target_w = (wchar_t*)git__malloc(target_len * sizeof(wchar_t)); target_w = (wchar_t*)git__malloc(target_len * sizeof(wchar_t));
GITERR_CHECK_ALLOC(target_w);
dwRet = pGetFinalPath(hFile, target_w, target_len, 0x0); dwRet = pGetFinalPath(hFile, target_w, target_len, 0x0);
if (dwRet >= target_len) { if (dwRet == 0 ||
git__free(target_w); dwRet >= target_len ||
CloseHandle(hFile); !WideCharToMultiByte(CP_UTF8, 0, target_w, -1, target,
return GIT_ENOMEM; target_len * sizeof(char), NULL, NULL))
} error = -1;
if (!WideCharToMultiByte(CP_UTF8, 0, target_w, -1, target, target_len * sizeof(char), NULL, NULL)) {
git__free(target_w);
return GIT_EOSERR;
}
git__free(target_w); git__free(target_w);
CloseHandle(hFile); CloseHandle(hFile);
if (dwRet > 4) { if (error)
/* Skip first 4 characters if they are "\\?\" */ return error;
if (target[0] == '\\' && target[1] == '\\' && target[2] == '?' && target[3] == '\\') {
char tmp[GIT_PATH_MAX]; /* Skip first 4 characters if they are "\\?\" */
unsigned int offset = 4; if (dwRet > 4 &&
dwRet -= 4; target[0] == '\\' && target[1] == '\\' &&
target[2] == '?' && target[3] == '\\')
/* \??\UNC\ */ {
if (dwRet > 7 && target[4] == 'U' && target[5] == 'N' && target[6] == 'C') { unsigned int offset = 4;
offset += 2; dwRet -= 4;
dwRet -= 2;
target[offset] = '\\'; /* \??\UNC\ */
} if (dwRet > 7 &&
target[4] == 'U' && target[5] == 'N' && target[6] == 'C')
memcpy(tmp, target + offset, dwRet); {
memcpy(target, tmp, dwRet); offset += 2;
dwRet -= 2;
target[offset] = '\\';
} }
memmove(target, target + offset, dwRet);
} }
target[dwRet] = '\0'; target[dwRet] = '\0';
return dwRet; return dwRet;
} }
...@@ -224,8 +221,9 @@ int p_open(const char *path, int flags) ...@@ -224,8 +221,9 @@ int p_open(const char *path, int flags)
{ {
int fd; int fd;
wchar_t* buf = gitwin_to_utf16(path); wchar_t* buf = gitwin_to_utf16(path);
if (!buf)
return -1;
fd = _wopen(buf, flags | _O_BINARY); fd = _wopen(buf, flags | _O_BINARY);
git__free(buf); git__free(buf);
return fd; return fd;
} }
...@@ -234,8 +232,9 @@ int p_creat(const char *path, mode_t mode) ...@@ -234,8 +232,9 @@ int p_creat(const char *path, mode_t mode)
{ {
int fd; int fd;
wchar_t* buf = gitwin_to_utf16(path); wchar_t* buf = gitwin_to_utf16(path);
if (!buf)
return -1;
fd = _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode); fd = _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode);
git__free(buf); git__free(buf);
return fd; return fd;
} }
...@@ -243,15 +242,15 @@ int p_creat(const char *path, mode_t mode) ...@@ -243,15 +242,15 @@ int p_creat(const char *path, mode_t mode)
int p_getcwd(char *buffer_out, size_t size) int p_getcwd(char *buffer_out, size_t size)
{ {
wchar_t* buf = (wchar_t*)git__malloc(sizeof(wchar_t) * (int)size); wchar_t* buf = (wchar_t*)git__malloc(sizeof(wchar_t) * (int)size);
int ret;
_wgetcwd(buf, (int)size); _wgetcwd(buf, (int)size);
if (!WideCharToMultiByte(CP_UTF8, 0, buf, -1, buffer_out, size, NULL, NULL)) { ret = WideCharToMultiByte(
git__free(buf); CP_UTF8, 0, buf, -1, buffer_out, size, NULL, NULL);
return GIT_EOSERR;
}
git__free(buf); git__free(buf);
return GIT_SUCCESS; return !ret ? -1 : 0;
} }
int p_stat(const char* path, struct stat* buf) int p_stat(const char* path, struct stat* buf)
...@@ -262,8 +261,10 @@ 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) int p_chdir(const char* path)
{ {
wchar_t* buf = gitwin_to_utf16(path); wchar_t* buf = gitwin_to_utf16(path);
int ret = _wchdir(buf); int ret;
if (!buf)
return -1;
ret = _wchdir(buf);
git__free(buf); git__free(buf);
return ret; return ret;
} }
...@@ -271,8 +272,10 @@ int p_chdir(const char* path) ...@@ -271,8 +272,10 @@ int p_chdir(const char* path)
int p_chmod(const char* path, mode_t mode) int p_chmod(const char* path, mode_t mode)
{ {
wchar_t* buf = gitwin_to_utf16(path); 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); git__free(buf);
return ret; return ret;
} }
...@@ -280,8 +283,10 @@ int p_chmod(const char* path, mode_t mode) ...@@ -280,8 +283,10 @@ int p_chmod(const char* path, mode_t mode)
int p_rmdir(const char* path) int p_rmdir(const char* path)
{ {
wchar_t* buf = gitwin_to_utf16(path); wchar_t* buf = gitwin_to_utf16(path);
int ret = _wrmdir(buf); int ret;
if (!buf)
return -1;
ret = _wrmdir(buf);
git__free(buf); git__free(buf);
return ret; return ret;
} }
...@@ -290,11 +295,13 @@ int p_hide_directory__w32(const char *path) ...@@ -290,11 +295,13 @@ int p_hide_directory__w32(const char *path)
{ {
int res; int res;
wchar_t* buf = gitwin_to_utf16(path); wchar_t* buf = gitwin_to_utf16(path);
if (!buf)
return -1;
res = SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN); res = SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN);
git__free(buf); 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) char *p_realpath(const char *orig_path, char *buffer)
...@@ -303,6 +310,9 @@ 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* orig_path_w = gitwin_to_utf16(orig_path);
wchar_t* buffer_w = (wchar_t*)git__malloc(GIT_PATH_MAX * sizeof(wchar_t)); 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); ret = GetFullPathNameW(orig_path_w, GIT_PATH_MAX, buffer_w, NULL);
git__free(orig_path_w); git__free(orig_path_w);
...@@ -339,7 +349,7 @@ int p_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr) ...@@ -339,7 +349,7 @@ int p_vsnprintf(char *buffer, size_t count, const char *format, va_list argptr)
int len; int len;
if (count == 0 || (len = _vsnprintf(buffer, count, format, argptr)) < 0) if (count == 0 || (len = _vsnprintf(buffer, count, format, argptr)) < 0)
return p_vscprintf(format, argptr); return _vscprintf(format, argptr);
return len; return len;
#else /* MinGW */ #else /* MinGW */
...@@ -365,10 +375,10 @@ int p_mkstemp(char *tmp_path) ...@@ -365,10 +375,10 @@ int p_mkstemp(char *tmp_path)
{ {
#if defined(_MSC_VER) #if defined(_MSC_VER)
if (_mktemp_s(tmp_path, strlen(tmp_path) + 1) != 0) if (_mktemp_s(tmp_path, strlen(tmp_path) + 1) != 0)
return GIT_EOSERR; return -1;
#else #else
if (_mktemp(tmp_path) == NULL) if (_mktemp(tmp_path) == NULL)
return GIT_EOSERR; return -1;
#endif #endif
return p_creat(tmp_path, 0744); return p_creat(tmp_path, 0744);
...@@ -377,15 +387,17 @@ int p_mkstemp(char *tmp_path) ...@@ -377,15 +387,17 @@ int p_mkstemp(char *tmp_path)
int p_setenv(const char* name, const char* value, int overwrite) int p_setenv(const char* name, const char* value, int overwrite)
{ {
if (overwrite != 1) 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) int p_access(const char* path, mode_t mode)
{ {
wchar_t *buf = gitwin_to_utf16(path); wchar_t *buf = gitwin_to_utf16(path);
int ret; int ret;
if (!buf)
return -1;
ret = _waccess(buf, mode); ret = _waccess(buf, mode);
git__free(buf); git__free(buf);
...@@ -393,13 +405,16 @@ int p_access(const char* path, mode_t mode) ...@@ -393,13 +405,16 @@ int p_access(const char* path, mode_t mode)
return ret; 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 *wfrom = gitwin_to_utf16(from);
wchar_t *wto = gitwin_to_utf16(to); wchar_t *wto = gitwin_to_utf16(to);
int ret; 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(wfrom);
git__free(wto); git__free(wto);
......
...@@ -7,13 +7,16 @@ ...@@ -7,13 +7,16 @@
#include "pthread.h" #include "pthread.h"
int pthread_create(pthread_t *GIT_RESTRICT thread, int pthread_create(
const pthread_attr_t *GIT_RESTRICT attr, pthread_t *GIT_RESTRICT thread,
void *(*start_routine)(void*), void *GIT_RESTRICT arg) const pthread_attr_t *GIT_RESTRICT attr,
void *(*start_routine)(void*),
void *GIT_RESTRICT arg)
{ {
GIT_UNUSED(attr); GIT_UNUSED(attr);
*thread = (pthread_t) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, arg, 0, NULL); *thread = (pthread_t) CreateThread(
return *thread ? GIT_SUCCESS : git__throw(GIT_EOSERR, "Failed to create pthread"); NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, arg, 0, NULL);
return *thread ? 0 : -1;
} }
int pthread_join(pthread_t thread, void **value_ptr) int pthread_join(pthread_t thread, void **value_ptr)
......
...@@ -33,14 +33,14 @@ wchar_t* gitwin_to_utf16(const char* str) ...@@ -33,14 +33,14 @@ wchar_t* gitwin_to_utf16(const char* str)
wchar_t* ret; wchar_t* ret;
int cb; int cb;
if (!str) { if (!str)
return NULL; return NULL;
}
cb = strlen(str) * sizeof(wchar_t); cb = strlen(str) * sizeof(wchar_t);
if (cb == 0) { if (cb == 0) {
ret = (wchar_t*)git__malloc(sizeof(wchar_t)); ret = (wchar_t*)git__malloc(sizeof(wchar_t));
ret[0] = 0; if (ret)
ret[0] = 0;
return ret; return ret;
} }
...@@ -48,8 +48,11 @@ wchar_t* gitwin_to_utf16(const char* str) ...@@ -48,8 +48,11 @@ wchar_t* gitwin_to_utf16(const char* str)
cb += sizeof(wchar_t); cb += sizeof(wchar_t);
ret = (wchar_t*)git__malloc(cb); ret = (wchar_t*)git__malloc(cb);
if (!ret)
return NULL;
if (MultiByteToWideChar(_active_codepage, 0, str, -1, ret, cb) == 0) { if (MultiByteToWideChar(_active_codepage, 0, str, -1, ret, cb) == 0) {
giterr_set(GITERR_OS, "Could not convert string to UTF-16");
git__free(ret); git__free(ret);
ret = NULL; ret = NULL;
} }
...@@ -59,7 +62,10 @@ wchar_t* gitwin_to_utf16(const char* str) ...@@ -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) 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) char* gitwin_from_utf16(const wchar_t* str)
...@@ -74,7 +80,8 @@ 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); cb = wcslen(str) * sizeof(char);
if (cb == 0) { if (cb == 0) {
ret = (char*)git__malloc(sizeof(char)); ret = (char*)git__malloc(sizeof(char));
ret[0] = 0; if (ret)
ret[0] = 0;
return ret; return ret;
} }
...@@ -82,8 +89,11 @@ char* gitwin_from_utf16(const wchar_t* str) ...@@ -82,8 +89,11 @@ char* gitwin_from_utf16(const wchar_t* str)
cb += sizeof(char); cb += sizeof(char);
ret = (char*)git__malloc(cb); ret = (char*)git__malloc(cb);
if (!ret)
return NULL;
if (WideCharToMultiByte(_active_codepage, 0, str, -1, ret, cb, NULL, NULL) == 0) { 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); git__free(ret);
ret = NULL; ret = NULL;
} }
......
...@@ -15,7 +15,7 @@ struct attr_expected { ...@@ -15,7 +15,7 @@ struct attr_expected {
const char *expected_str; const char *expected_str;
}; };
static inline void attr_check_expected( GIT_INLINE(void) attr_check_expected(
enum attr_expect_t expected, enum attr_expect_t expected,
const char *expected_str, const char *expected_str,
const char *value) const char *value)
......
#include "clar_libgit2.h"
#include "common.h"
#include "util.h"
#include "posix.h"
#ifdef git__throw
void test_core_errors__old_school(void)
{
git_clearerror();
cl_assert(git_lasterror() == NULL);
cl_assert(git_strerror(GIT_ENOTFOUND) != NULL);
git__throw(GIT_ENOTFOUND, "My Message");
cl_assert(git_lasterror() != NULL);
cl_assert(git__prefixcmp(git_lasterror(), "My Message") == 0);
git_clearerror();
}
#endif
#ifdef GITERR_CHECK_ALLOC
void test_core_errors__new_school(void)
{
char *str_in_error;
git_error_clear();
cl_assert(git_error_last() == NULL);
giterr_set_oom(); /* internal fn */
cl_assert(git_error_last() != NULL);
cl_assert(git_error_last()->klass == GITERR_NOMEMORY);
str_in_error = strstr(git_error_last()->message, "memory");
cl_assert(str_in_error != NULL);
git_error_clear();
giterr_set(GITERR_REPOSITORY, "This is a test"); /* internal fn */
cl_assert(git_error_last() != NULL);
str_in_error = strstr(git_error_last()->message, "This is a test");
cl_assert(str_in_error != NULL);
git_error_clear();
{
struct stat st;
assert(p_lstat("this_file_does_not_exist", &st) < 0);
}
giterr_set(GITERR_OS, "stat failed"); /* internal fn */
cl_assert(git_error_last() != NULL);
str_in_error = strstr(git_error_last()->message, "stat failed");
cl_assert(str_in_error != NULL);
cl_assert(git__prefixcmp(str_in_error, "stat failed: ") == 0);
cl_assert(strlen(str_in_error) > strlen("stat failed: "));
#ifdef GIT_WIN32
git_error_clear();
/* The MSDN docs use this to generate a sample error */
cl_assert(GetProcessId(NULL) == 0);
giterr_set(GITERR_OS, "GetProcessId failed"); /* internal fn */
cl_assert(git_error_last() != NULL);
str_in_error = strstr(git_error_last()->message, "GetProcessId failed");
cl_assert(str_in_error != NULL);
cl_assert(git__prefixcmp(str_in_error, "GetProcessId failed: ") == 0);
cl_assert(strlen(str_in_error) > strlen("GetProcessId failed: "));
#endif
git_error_clear();
}
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment