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