Commit 97769280 by Russell Belfer

Use git_buf for path storage instead of stack-based buffers

This converts virtually all of the places that allocate GIT_PATH_MAX
buffers on the stack for manipulating paths to use git_buf objects
instead.  The patch is pretty careful not to touch the public API
for libgit2, so there are a few places that still use GIT_PATH_MAX.

This extends and changes some details of the git_buf implementation
to add a couple of extra functions and to make error handling easier.

This includes serious alterations to all the path.c functions, and
several of the fileops.c ones, too.  Also, there are a number of new
functions that parallel existing ones except that use a git_buf
instead of a stack-based buffer (such as git_config_find_global_r
that exists alongsize git_config_find_global).

This also modifies the win32 version of p_realpath to allocate whatever
buffer size is needed to accommodate the realpath instead of hardcoding
a GIT_PATH_MAX limit, but that change needs to be tested still.
parent a22b14d3
...@@ -67,12 +67,13 @@ int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *b ...@@ -67,12 +67,13 @@ int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *b
int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path) int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path)
{ {
int error, islnk; int error = GIT_SUCCESS;
int islnk = 0;
int fd = 0; int fd = 0;
char full_path[GIT_PATH_MAX]; git_buf full_path = GIT_BUF_INIT;
char buffer[2048]; char buffer[2048];
git_off_t size; git_off_t size;
git_odb_stream *stream; git_odb_stream *stream = NULL;
struct stat st; struct stat st;
const char *workdir; const char *workdir;
git_odb *odb; git_odb *odb;
...@@ -81,11 +82,14 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat ...@@ -81,11 +82,14 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
if (workdir == NULL) if (workdir == NULL)
return git__throw(GIT_ENOTFOUND, "Failed to create blob. (No working directory found)"); return git__throw(GIT_ENOTFOUND, "Failed to create blob. (No working directory found)");
git_path_join(full_path, workdir, path); error = git_buf_joinpath(&full_path, workdir, path);
if (error < GIT_SUCCESS)
return error;
error = p_lstat(full_path, &st); error = p_lstat(full_path.ptr, &st);
if (error < 0) { if (error < 0) {
return git__throw(GIT_EOSERR, "Failed to stat blob. %s", strerror(errno)); error = git__throw(GIT_EOSERR, "Failed to stat blob. %s", strerror(errno));
goto cleanup;
} }
islnk = S_ISLNK(st.st_mode); islnk = S_ISLNK(st.st_mode);
...@@ -93,18 +97,18 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat ...@@ -93,18 +97,18 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
error = git_repository_odb__weakptr(&odb, repo); error = git_repository_odb__weakptr(&odb, repo);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; goto cleanup;
if (!islnk) { if (!islnk) {
if ((fd = p_open(full_path, O_RDONLY)) < 0) if ((fd = p_open(full_path.ptr, O_RDONLY)) < 0) {
return git__throw(GIT_ENOTFOUND, "Failed to create blob. Could not open '%s'", full_path); error = git__throw(GIT_ENOTFOUND, "Failed to create blob. Could not open '%s'", full_path.ptr
);
goto cleanup;
}
} }
if ((error = git_odb_open_wstream(&stream, odb, (size_t)size, GIT_OBJ_BLOB)) < GIT_SUCCESS) { if ((error = git_odb_open_wstream(&stream, odb, (size_t)size, GIT_OBJ_BLOB)) < GIT_SUCCESS)
if (!islnk) goto cleanup;
p_close(fd);
return git__rethrow(error, "Failed to create blob");
}
while (size > 0) { while (size > 0) {
ssize_t read_len; ssize_t read_len;
...@@ -112,13 +116,11 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat ...@@ -112,13 +116,11 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
if (!islnk) if (!islnk)
read_len = p_read(fd, buffer, sizeof(buffer)); read_len = p_read(fd, buffer, sizeof(buffer));
else else
read_len = p_readlink(full_path, buffer, sizeof(buffer)); read_len = p_readlink(full_path.ptr, buffer, sizeof(buffer));
if (read_len < 0) { if (read_len < 0) {
if (!islnk) error = git__throw(GIT_EOSERR, "Failed to create blob. Can't read full file");
p_close(fd); goto cleanup;
stream->free(stream);
return git__throw(GIT_EOSERR, "Failed to create blob. Can't read full file");
} }
stream->write(stream, buffer, read_len); stream->write(stream, buffer, read_len);
...@@ -126,10 +128,15 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat ...@@ -126,10 +128,15 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
} }
error = stream->finalize_write(oid, stream); error = stream->finalize_write(oid, stream);
stream->free(stream);
if (!islnk) cleanup:
if (stream)
stream->free(stream);
if (!islnk && fd)
p_close(fd); p_close(fd);
git_buf_free(&full_path);
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create blob"); return error == GIT_SUCCESS ? GIT_SUCCESS :
git__rethrow(error, "Failed to create blob");
} }
...@@ -15,7 +15,8 @@ char git_buf_initbuf[1]; ...@@ -15,7 +15,8 @@ char git_buf_initbuf[1];
#define ENSURE_SIZE(b, d) \ #define ENSURE_SIZE(b, d) \
if ((ssize_t)(d) > buf->asize && git_buf_grow(b, (d)) < GIT_SUCCESS)\ if ((ssize_t)(d) > buf->asize && git_buf_grow(b, (d)) < GIT_SUCCESS)\
return; return GIT_ENOMEM;
void git_buf_init(git_buf *buf, size_t initial_size) void git_buf_init(git_buf *buf, size_t initial_size)
{ {
...@@ -29,6 +30,14 @@ void git_buf_init(git_buf *buf, size_t initial_size) ...@@ -29,6 +30,14 @@ void git_buf_init(git_buf *buf, size_t initial_size)
int git_buf_grow(git_buf *buf, size_t target_size) int git_buf_grow(git_buf *buf, size_t target_size)
{ {
int error = git_buf_try_grow(buf, target_size);
if (error != GIT_SUCCESS)
buf->asize = -1;
return error;
}
int git_buf_try_grow(git_buf *buf, size_t target_size)
{
char *new_ptr; char *new_ptr;
size_t new_size; size_t new_size;
...@@ -55,10 +64,9 @@ int git_buf_grow(git_buf *buf, size_t target_size) ...@@ -55,10 +64,9 @@ int git_buf_grow(git_buf *buf, size_t target_size)
new_size = (new_size + 7) & ~7; new_size = (new_size + 7) & ~7;
new_ptr = git__realloc(new_ptr, new_size); new_ptr = git__realloc(new_ptr, new_size);
if (!new_ptr) { /* if realloc fails, return without modifying the git_buf */
buf->asize = -1; if (!new_ptr)
return GIT_ENOMEM; return GIT_ENOMEM;
}
buf->asize = new_size; buf->asize = new_size;
buf->ptr = new_ptr; buf->ptr = new_ptr;
...@@ -93,7 +101,12 @@ int git_buf_oom(const git_buf *buf) ...@@ -93,7 +101,12 @@ int git_buf_oom(const git_buf *buf)
return (buf->asize < 0); return (buf->asize < 0);
} }
void git_buf_set(git_buf *buf, const char *data, size_t len) int git_buf_lasterror(const git_buf *buf)
{
return (buf->asize < 0) ? GIT_ENOMEM : GIT_SUCCESS;
}
int git_buf_set(git_buf *buf, const char *data, size_t len)
{ {
if (len == 0 || data == NULL) { if (len == 0 || data == NULL) {
git_buf_clear(buf); git_buf_clear(buf);
...@@ -103,35 +116,38 @@ void git_buf_set(git_buf *buf, const char *data, size_t len) ...@@ -103,35 +116,38 @@ void git_buf_set(git_buf *buf, const char *data, size_t len)
buf->size = len; buf->size = len;
buf->ptr[buf->size] = '\0'; buf->ptr[buf->size] = '\0';
} }
return GIT_SUCCESS;
} }
void git_buf_sets(git_buf *buf, const char *string) int git_buf_sets(git_buf *buf, const char *string)
{ {
git_buf_set(buf, string, string ? strlen(string) : 0); return git_buf_set(buf, string, string ? strlen(string) : 0);
} }
void git_buf_putc(git_buf *buf, char c) int git_buf_putc(git_buf *buf, char c)
{ {
ENSURE_SIZE(buf, buf->size + 2); ENSURE_SIZE(buf, buf->size + 2);
buf->ptr[buf->size++] = c; buf->ptr[buf->size++] = c;
buf->ptr[buf->size] = '\0'; buf->ptr[buf->size] = '\0';
return GIT_SUCCESS;
} }
void git_buf_put(git_buf *buf, const char *data, size_t len) int git_buf_put(git_buf *buf, const char *data, size_t len)
{ {
ENSURE_SIZE(buf, buf->size + len + 1); ENSURE_SIZE(buf, buf->size + len + 1);
memmove(buf->ptr + buf->size, data, len); memmove(buf->ptr + buf->size, data, len);
buf->size += len; buf->size += len;
buf->ptr[buf->size] = '\0'; buf->ptr[buf->size] = '\0';
return GIT_SUCCESS;
} }
void git_buf_puts(git_buf *buf, const char *string) int git_buf_puts(git_buf *buf, const char *string)
{ {
assert(string); assert(string);
git_buf_put(buf, string, strlen(string)); return git_buf_put(buf, string, strlen(string));
} }
void git_buf_printf(git_buf *buf, const char *format, ...) int git_buf_printf(git_buf *buf, const char *format, ...)
{ {
int len; int len;
va_list arglist; va_list arglist;
...@@ -145,16 +161,18 @@ void git_buf_printf(git_buf *buf, const char *format, ...) ...@@ -145,16 +161,18 @@ void git_buf_printf(git_buf *buf, const char *format, ...)
if (len < 0) { if (len < 0) {
buf->asize = -1; buf->asize = -1;
return; return GIT_ENOMEM;
} }
if (len + 1 <= buf->asize - buf->size) { if (len + 1 <= buf->asize - buf->size) {
buf->size += len; buf->size += len;
return; break;
} }
ENSURE_SIZE(buf, buf->size + len + 1); ENSURE_SIZE(buf, buf->size + len + 1);
} }
return GIT_SUCCESS;
} }
const char *git_buf_cstr(git_buf *buf) const char *git_buf_cstr(git_buf *buf)
...@@ -162,7 +180,7 @@ const char *git_buf_cstr(git_buf *buf) ...@@ -162,7 +180,7 @@ const char *git_buf_cstr(git_buf *buf)
return buf->ptr; return buf->ptr;
} }
void git_buf_copy_cstr(char *data, size_t datasize, git_buf *buf) void git_buf_copy_cstr(char *data, size_t datasize, const git_buf *buf)
{ {
size_t copylen; size_t copylen;
...@@ -190,6 +208,14 @@ void git_buf_consume(git_buf *buf, const char *end) ...@@ -190,6 +208,14 @@ void git_buf_consume(git_buf *buf, const char *end)
} }
} }
void git_buf_truncate(git_buf *buf, ssize_t len)
{
if (len < buf->size) {
buf->size = len;
buf->ptr[buf->size] = '\0';
}
}
void git_buf_swap(git_buf *buf_a, git_buf *buf_b) void git_buf_swap(git_buf *buf_a, git_buf *buf_b)
{ {
git_buf t = *buf_a; git_buf t = *buf_a;
...@@ -197,7 +223,7 @@ void git_buf_swap(git_buf *buf_a, git_buf *buf_b) ...@@ -197,7 +223,7 @@ void git_buf_swap(git_buf *buf_a, git_buf *buf_b)
*buf_b = t; *buf_b = t;
} }
char *git_buf_take_cstr(git_buf *buf) char *git_buf_detach(git_buf *buf)
{ {
char *data = buf->ptr; char *data = buf->ptr;
...@@ -209,18 +235,34 @@ char *git_buf_take_cstr(git_buf *buf) ...@@ -209,18 +235,34 @@ char *git_buf_take_cstr(git_buf *buf)
return data; return data;
} }
void git_buf_join_n(git_buf *buf, char separator, int nbuf, ...) void git_buf_attach(git_buf *buf, char *ptr, ssize_t asize)
{ {
/* Make two passes to avoid multiple reallocation */ git_buf_free(buf);
if (ptr) {
buf->ptr = ptr;
buf->size = strlen(ptr);
if (asize)
buf->asize = (asize < buf->size) ? buf->size + 1 : asize;
else /* pass 0 to fall back on strlen + 1 */
buf->asize = buf->size + 1;
} else {
git_buf_grow(buf, asize);
}
}
int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...)
{
va_list ap; va_list ap;
int i; int i, error = GIT_SUCCESS;
size_t total_size = 0; size_t total_size = 0;
char *out; char *out;
if (buf->size > 0 && buf->ptr[buf->size - 1] != separator) if (buf->size > 0 && buf->ptr[buf->size - 1] != separator)
++total_size; /* space for initial separator */ ++total_size; /* space for initial separator */
/* Make two passes to avoid multiple reallocation */
va_start(ap, nbuf); va_start(ap, nbuf);
for (i = 0; i < nbuf; ++i) { for (i = 0; i < nbuf; ++i) {
const char* segment; const char* segment;
...@@ -237,7 +279,10 @@ void git_buf_join_n(git_buf *buf, char separator, int nbuf, ...) ...@@ -237,7 +279,10 @@ void git_buf_join_n(git_buf *buf, char separator, int nbuf, ...)
} }
va_end(ap); va_end(ap);
ENSURE_SIZE(buf, buf->size + total_size + 1); /* expand buffer if needed */
if (total_size > 0 &&
(error = git_buf_grow(buf, buf->size + total_size + 1)) < GIT_SUCCESS)
return error;
out = buf->ptr + buf->size; out = buf->ptr + buf->size;
...@@ -274,14 +319,17 @@ void git_buf_join_n(git_buf *buf, char separator, int nbuf, ...) ...@@ -274,14 +319,17 @@ void git_buf_join_n(git_buf *buf, char separator, int nbuf, ...)
/* set size based on num characters actually written */ /* set size based on num characters actually written */
buf->size = out - buf->ptr; buf->size = out - buf->ptr;
buf->ptr[buf->size] = '\0'; buf->ptr[buf->size] = '\0';
return error;
} }
void git_buf_join( int git_buf_join(
git_buf *buf, git_buf *buf,
char separator, char separator,
const char *str_a, const char *str_a,
const char *str_b) const char *str_b)
{ {
int error = GIT_SUCCESS;
size_t strlen_a = strlen(str_a); size_t strlen_a = strlen(str_a);
size_t strlen_b = strlen(str_b); size_t strlen_b = strlen(str_b);
int need_sep = 0; int need_sep = 0;
...@@ -293,7 +341,9 @@ void git_buf_join( ...@@ -293,7 +341,9 @@ void git_buf_join(
need_sep = 1; need_sep = 1;
} }
ENSURE_SIZE(buf, strlen_a + strlen_b + need_sep + 1); error = git_buf_grow(buf, strlen_a + strlen_b + need_sep + 1);
if (error < GIT_SUCCESS)
return error;
memmove(buf->ptr, str_a, strlen_a); memmove(buf->ptr, str_a, strlen_a);
if (need_sep) if (need_sep)
...@@ -302,4 +352,6 @@ void git_buf_join( ...@@ -302,4 +352,6 @@ void git_buf_join(
buf->size = strlen_a + strlen_b + need_sep; buf->size = strlen_a + strlen_b + need_sep;
buf->ptr[buf->size] = '\0'; buf->ptr[buf->size] = '\0';
return error;
} }
...@@ -18,34 +18,87 @@ extern char git_buf_initbuf[]; ...@@ -18,34 +18,87 @@ extern char git_buf_initbuf[];
#define GIT_BUF_INIT { git_buf_initbuf, 0, 0 } #define GIT_BUF_INIT { git_buf_initbuf, 0, 0 }
/**
* Initialize a git_buf structure.
*
* For the cases where GIT_BUF_INIT cannot be used to do static
* initialization.
*/
void git_buf_init(git_buf *buf, size_t initial_size); void git_buf_init(git_buf *buf, size_t initial_size);
/**
* Grow the buffer to hold at least `target_size` bytes.
*
* If the allocation fails, this will return an error and the buffer
* will be marked as invalid for future operations. The existing
* contents of the buffer will be preserved however.
* @return GIT_SUCCESS or GIT_ENOMEM on failure
*/
int git_buf_grow(git_buf *buf, size_t target_size); int git_buf_grow(git_buf *buf, size_t target_size);
/**
* Attempt to grow the buffer to hold at least `target_size` bytes.
*
* This is just like `git_buf_grow` except that even if the allocation
* fails, the git_buf will still be left in a valid state.
*/
int git_buf_try_grow(git_buf *buf, size_t target_size);
void git_buf_free(git_buf *buf); void git_buf_free(git_buf *buf);
void git_buf_swap(git_buf *buf_a, git_buf *buf_b); void git_buf_swap(git_buf *buf_a, git_buf *buf_b);
char *git_buf_detach(git_buf *buf);
void git_buf_attach(git_buf *buf, char *ptr, ssize_t asize);
/** /**
* Test if there have been any reallocation failures with this git_buf.
*
* Any function that writes to a git_buf can fail due to memory allocation * Any function that writes to a git_buf can fail due to memory allocation
* issues. If one fails, the git_buf will be marked with an OOM error and * issues. If one fails, the git_buf will be marked with an OOM error and
* further calls to modify the buffer will fail. You just check * further calls to modify the buffer will fail. Check git_buf_oom() at the
* git_buf_oom() at the end of your sequence and it will be true if you ran * end of your sequence and it will be true if you ran out of memory at any
* out of memory at any point with that buffer. * point with that buffer.
* @return 0 if no error, 1 if allocation error.
*/ */
int git_buf_oom(const git_buf *buf); int git_buf_oom(const git_buf *buf);
void git_buf_set(git_buf *buf, const char *data, size_t len); /**
void git_buf_sets(git_buf *buf, const char *string); * Just like git_buf_oom, except returns appropriate error code.
void git_buf_putc(git_buf *buf, char c); * @return GIT_ENOMEM if allocation error, GIT_SUCCESS if not.
void git_buf_put(git_buf *buf, const char *data, size_t len); */
void git_buf_puts(git_buf *buf, const char *string); int git_buf_lasterror(const git_buf *buf);
void git_buf_printf(git_buf *buf, const char *format, ...) GIT_FORMAT_PRINTF(2, 3);
/*
* The functions below that return int values, will return GIT_ENOMEM
* if they fail to expand the git_buf when they are called, otherwise
* GIT_SUCCESS. Passing a git_buf that has failed an allocation will
* automatically return GIT_ENOMEM for all further calls. As a result,
* you can ignore the return code of these functions and call them in a
* series then just call git_buf_lasterror at the end.
*/
int git_buf_set(git_buf *buf, const char *data, size_t len);
int git_buf_sets(git_buf *buf, const char *string);
int git_buf_putc(git_buf *buf, char c);
int git_buf_put(git_buf *buf, const char *data, size_t len);
int git_buf_puts(git_buf *buf, const char *string);
int git_buf_printf(git_buf *buf, const char *format, ...) GIT_FORMAT_PRINTF(2, 3);
void git_buf_clear(git_buf *buf); void git_buf_clear(git_buf *buf);
void git_buf_consume(git_buf *buf, const char *end); void git_buf_consume(git_buf *buf, const char *end);
void git_buf_join_n(git_buf *buf, char separator, int nbuf, ...); void git_buf_truncate(git_buf *buf, ssize_t len);
void git_buf_join(git_buf *buf, char separator, const char *str_a, const char *str_b);
int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...);
int git_buf_join(git_buf *buf, char separator, const char *str_a, const char *str_b);
/**
* Join two strings as paths, inserting a slash between as needed.
* @return error code or GIT_SUCCESS
*/
GIT_INLINE (int) git_buf_joinpath(git_buf *buf, const char *a, const char *b)
{
return git_buf_join(buf, '/', a, b);
}
const char *git_buf_cstr(git_buf *buf); const char *git_buf_cstr(git_buf *buf);
char *git_buf_take_cstr(git_buf *buf); void git_buf_copy_cstr(char *data, size_t datasize, const git_buf *buf);
void git_buf_copy_cstr(char *data, size_t datasize, git_buf *buf);
#define git_buf_PUTS(buf, str) git_buf_put(buf, str, sizeof(str) - 1) #define git_buf_PUTS(buf, str) git_buf_put(buf, str, sizeof(str) - 1)
......
...@@ -129,7 +129,8 @@ int git_commit_create( ...@@ -129,7 +129,8 @@ int git_commit_create(
git_buf_puts(&commit, message); git_buf_puts(&commit, message);
if (git_buf_oom(&commit)) { if (git_buf_oom(&commit)) {
error = git__throw(GIT_ENOMEM, "Not enough memory to build the commit data"); error = git__throw(git_buf_lasterror(&commit),
"Not enough memory to build the commit data");
goto cleanup; goto cleanup;
} }
......
...@@ -330,9 +330,25 @@ int git_config_get_string(git_config *cfg, const char *name, const char **out) ...@@ -330,9 +330,25 @@ int git_config_get_string(git_config *cfg, const char *name, const char **out)
int git_config_find_global(char *global_config_path) int git_config_find_global(char *global_config_path)
{ {
const char *home; git_buf path = GIT_BUF_INIT;
int error = git_config_find_global_r(&path);
if (error == GIT_SUCCESS) {
if (path.size > GIT_PATH_MAX)
error = git__throw(GIT_ESHORTBUFFER, "Path is too long");
else
git_buf_copy_cstr(global_config_path, GIT_PATH_MAX, &path);
}
git_buf_free(&path);
home = getenv("HOME"); return error;
}
int git_config_find_global_r(git_buf *path)
{
int error;
const char *home = getenv("HOME");
#ifdef GIT_WIN32 #ifdef GIT_WIN32
if (home == NULL) if (home == NULL)
...@@ -342,10 +358,13 @@ int git_config_find_global(char *global_config_path) ...@@ -342,10 +358,13 @@ int git_config_find_global(char *global_config_path)
if (home == NULL) if (home == NULL)
return git__throw(GIT_EOSERR, "Failed to open global config file. Cannot locate the user's home directory"); return git__throw(GIT_EOSERR, "Failed to open global config file. Cannot locate the user's home directory");
git_path_join(global_config_path, home, GIT_CONFIG_FILENAME); if ((error = git_buf_joinpath(path, home, GIT_CONFIG_FILENAME)) < GIT_SUCCESS)
return error;
if (git_futils_exists(global_config_path) < GIT_SUCCESS) if (git_futils_exists(path->ptr) < GIT_SUCCESS) {
git_buf_clear(path);
return git__throw(GIT_EOSERR, "Failed to open global config file. The file does not exist"); return git__throw(GIT_EOSERR, "Failed to open global config file. The file does not exist");
}
return GIT_SUCCESS; return GIT_SUCCESS;
} }
...@@ -353,7 +372,7 @@ int git_config_find_global(char *global_config_path) ...@@ -353,7 +372,7 @@ int git_config_find_global(char *global_config_path)
#if GIT_WIN32 #if GIT_WIN32
static int win32_find_system(char *system_config_path) static int win32_find_system(git_buf *system_config_path)
{ {
const wchar_t *query = L"%PROGRAMFILES%\\Git\\etc\\gitconfig"; const wchar_t *query = L"%PROGRAMFILES%\\Git\\etc\\gitconfig";
wchar_t *apphome_utf16; wchar_t *apphome_utf16;
...@@ -378,25 +397,21 @@ static int win32_find_system(char *system_config_path) ...@@ -378,25 +397,21 @@ static int win32_find_system(char *system_config_path)
apphome_utf8 = gitwin_from_utf16(apphome_utf16); apphome_utf8 = gitwin_from_utf16(apphome_utf16);
git__free(apphome_utf16); git__free(apphome_utf16);
if (strlen(apphome_utf8) >= GIT_PATH_MAX) { git_buf_attach(system_config_path, apphome_utf8, 0);
git__free(apphome_utf8);
return git__throw(GIT_ESHORTBUFFER, "Path is too long");
}
strcpy(system_config_path, apphome_utf8);
git__free(apphome_utf8);
return GIT_SUCCESS; return GIT_SUCCESS;
} }
#endif #endif
int git_config_find_system(char *system_config_path) int git_config_find_system_r(git_buf *system_config_path)
{ {
const char *etc = "/etc/gitconfig"; if (git_buf_sets(system_config_path, "/etc/gitconfig") < GIT_SUCCESS)
return git_buf_lasterror(system_config_path);
if (git_futils_exists(etc) == GIT_SUCCESS) { if (git_futils_exists(system_config_path->ptr) == GIT_SUCCESS)
memcpy(system_config_path, etc, strlen(etc) + 1);
return GIT_SUCCESS; return GIT_SUCCESS;
}
git_buf_clear(system_config_path);
#if GIT_WIN32 #if GIT_WIN32
return win32_find_system(system_config_path); return win32_find_system(system_config_path);
...@@ -405,6 +420,23 @@ int git_config_find_system(char *system_config_path) ...@@ -405,6 +420,23 @@ int git_config_find_system(char *system_config_path)
#endif #endif
} }
int git_config_find_system(char *system_config_path)
{
git_buf path = GIT_BUF_INIT;
int error = git_config_find_system_r(&path);
if (error == GIT_SUCCESS) {
if (path.size > GIT_PATH_MAX)
error = git__throw(GIT_ESHORTBUFFER, "Path is too long");
else
git_buf_copy_cstr(system_config_path, GIT_PATH_MAX, &path);
}
git_buf_free(&path);
return error;
}
int git_config_open_global(git_config **out) int git_config_open_global(git_config **out)
{ {
int error; int error;
......
...@@ -21,4 +21,7 @@ struct git_config { ...@@ -21,4 +21,7 @@ struct git_config {
git_vector files; git_vector files;
}; };
extern int git_config_find_global_r(git_buf *global_config_path);
extern int git_config_find_system_r(git_buf *system_config_path);
#endif #endif
...@@ -115,25 +115,31 @@ int git_fetch_download_pack(char **out, git_remote *remote) ...@@ -115,25 +115,31 @@ int git_fetch_download_pack(char **out, git_remote *remote)
} }
/* Receiving data from a socket and storing it is pretty much the same for git and HTTP */ /* Receiving data from a socket and storing it is pretty much the same for git and HTTP */
int git_fetch__download_pack(char **out, const char *buffered, size_t buffered_size, int git_fetch__download_pack(
GIT_SOCKET fd, git_repository *repo) char **out,
const char *buffered,
size_t buffered_size,
GIT_SOCKET fd,
git_repository *repo)
{ {
git_filebuf file = GIT_FILEBUF_INIT; git_filebuf file = GIT_FILEBUF_INIT;
int error; int error;
char buff[1024], path[GIT_PATH_MAX]; char buff[1024];
git_buf path = GIT_BUF_INIT;
static const char suff[] = "/objects/pack/pack-received"; static const char suff[] = "/objects/pack/pack-received";
gitno_buffer buf; gitno_buffer buf;
git_path_join(path, repo->path_repository, suff);
gitno_buffer_setup(&buf, buff, sizeof(buff), fd); gitno_buffer_setup(&buf, buff, sizeof(buff), fd);
if (memcmp(buffered, "PACK", strlen("PACK"))) { if (memcmp(buffered, "PACK", strlen("PACK"))) {
return git__throw(GIT_ERROR, "The pack doesn't start with the signature"); return git__throw(GIT_ERROR, "The pack doesn't start with the signature");
} }
error = git_filebuf_open(&file, path, GIT_FILEBUF_TEMPORARY); error = git_buf_joinpath(&path, repo->path_repository, suff);
if (error < GIT_SUCCESS)
goto cleanup;
error = git_filebuf_open(&file, path.ptr, GIT_FILEBUF_TEMPORARY);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
...@@ -166,7 +172,7 @@ int git_fetch__download_pack(char **out, const char *buffered, size_t buffered_s ...@@ -166,7 +172,7 @@ int git_fetch__download_pack(char **out, const char *buffered, size_t buffered_s
cleanup: cleanup:
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
git_filebuf_cleanup(&file); git_filebuf_cleanup(&file);
git_buf_free(&path);
return error; return error;
} }
...@@ -196,18 +196,19 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags) ...@@ -196,18 +196,19 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags)
/* If we are writing to a temp file */ /* If we are writing to a temp file */
if (flags & GIT_FILEBUF_TEMPORARY) { if (flags & GIT_FILEBUF_TEMPORARY) {
char tmp_path[GIT_PATH_MAX]; git_buf tmp_path = GIT_BUF_INIT;
/* Open the file as temporary for locking */ /* Open the file as temporary for locking */
file->fd = git_futils_mktmp(tmp_path, path); file->fd = git_futils_mktmp(&tmp_path, path);
if (file->fd < 0) { if (file->fd < 0) {
git_buf_free(&tmp_path);
error = GIT_EOSERR; error = GIT_EOSERR;
goto cleanup; goto cleanup;
} }
/* No original path */ /* No original path */
file->path_original = NULL; file->path_original = NULL;
file->path_lock = git__strdup(tmp_path); file->path_lock = git_buf_detach(&tmp_path);
if (file->path_lock == NULL) { if (file->path_lock == NULL) {
error = GIT_ENOMEM; error = GIT_ENOMEM;
......
...@@ -10,35 +10,40 @@ ...@@ -10,35 +10,40 @@
int git_futils_mkpath2file(const char *file_path, const mode_t mode) int git_futils_mkpath2file(const char *file_path, const mode_t mode)
{ {
int error = GIT_SUCCESS; int error;
char target_folder_path[GIT_PATH_MAX]; git_buf target_folder = GIT_BUF_INIT;
error = git_path_dirname_r(target_folder_path, sizeof(target_folder_path), file_path); error = git_path_dirname_r(&target_folder, file_path);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS) {
git_buf_free(&target_folder);
return git__throw(GIT_EINVALIDPATH, "Failed to recursively build `%s` tree structure. Unable to parse parent folder name", file_path); return git__throw(GIT_EINVALIDPATH, "Failed to recursively build `%s` tree structure. Unable to parse parent folder name", file_path);
} else {
/* reset error */
error = GIT_SUCCESS;
}
/* Does the containing folder exist? */ /* Does the containing folder exist? */
if (git_futils_isdir(target_folder_path)) { if (git_futils_isdir(target_folder.ptr) != GIT_SUCCESS)
git_path_join(target_folder_path, target_folder_path, ""); /* Ensure there's a trailing slash */
/* Let's create the tree structure */ /* Let's create the tree structure */
error = git_futils_mkdir_r(target_folder_path, mode); error = git_futils_mkdir_r(target_folder.ptr, NULL, mode);
if (error < GIT_SUCCESS)
return error; /* The callee already takes care of setting the correct error message. */
}
return GIT_SUCCESS; git_buf_free(&target_folder);
return error;
} }
int git_futils_mktmp(char *path_out, const char *filename) int git_futils_mktmp(git_buf *path_out, const char *filename)
{ {
int fd; int fd;
strcpy(path_out, filename); git_buf_sets(path_out, filename);
strcat(path_out, "_git2_XXXXXX"); git_buf_puts(path_out, "_git2_XXXXXX");
if (git_buf_oom(path_out))
return git__rethrow(git_buf_lasterror(path_out),
"Failed to create temporary file for %s", filename);
if ((fd = p_mkstemp(path_out)) < 0) if ((fd = p_mkstemp(path_out->ptr)) < 0)
return git__throw(GIT_EOSERR, "Failed to create temporary file %s", path_out); return git__throw(GIT_EOSERR, "Failed to create temporary file %s", path_out->ptr);
return fd; return fd;
} }
...@@ -180,6 +185,14 @@ int git_futils_readbuffer(git_fbuffer *obj, const char *path) ...@@ -180,6 +185,14 @@ int git_futils_readbuffer(git_fbuffer *obj, const char *path)
return git_futils_readbuffer_updated(obj, path, NULL, NULL); return git_futils_readbuffer_updated(obj, path, NULL, NULL);
} }
void git_futils_fbuffer_rtrim(git_fbuffer *obj)
{
unsigned char *buff = obj->data;
while (obj->len > 0 && isspace(buff[obj->len - 1]))
obj->len--;
buff[obj->len] = '\0';
}
void git_futils_freebuffer(git_fbuffer *obj) void git_futils_freebuffer(git_fbuffer *obj)
{ {
assert(obj); assert(obj);
...@@ -215,76 +228,72 @@ GIT_INLINE(int) is_dot_or_dotdot(const char *name) ...@@ -215,76 +228,72 @@ GIT_INLINE(int) is_dot_or_dotdot(const char *name)
} }
int git_futils_direach( int git_futils_direach(
char *path, git_buf *path,
size_t path_sz, int (*fn)(void *, git_buf *),
int (*fn)(void *, char *),
void *arg) void *arg)
{ {
size_t wd_len = strlen(path); ssize_t wd_len;
DIR *dir; DIR *dir;
struct dirent *de; struct dirent *de;
if (!wd_len || path_sz < wd_len + 2) if (git_path_to_dir(path) < GIT_SUCCESS)
return git__throw(GIT_EINVALIDARGS, "Failed to process `%s` tree structure. Path is either empty or buffer size is too short", path); return git_buf_lasterror(path);
while (path[wd_len - 1] == '/')
wd_len--;
path[wd_len++] = '/';
path[wd_len] = '\0';
dir = opendir(path); wd_len = path->size;
dir = opendir(path->ptr);
if (!dir) if (!dir)
return git__throw(GIT_EOSERR, "Failed to process `%s` tree structure. An error occured while opening the directory", path); return git__throw(GIT_EOSERR, "Failed to process `%s` tree structure. An error occured while opening the directory", path->ptr);
while ((de = readdir(dir)) != NULL) { while ((de = readdir(dir)) != NULL) {
size_t de_len;
int result; int result;
if (is_dot_or_dotdot(de->d_name)) if (is_dot_or_dotdot(de->d_name))
continue; continue;
de_len = strlen(de->d_name); if (git_buf_puts(path, de->d_name) < GIT_SUCCESS)
if (path_sz < wd_len + de_len + 1) { return git_buf_lasterror(path);
closedir(dir);
return git__throw(GIT_ERROR, "Failed to process `%s` tree structure. Buffer size is too short", path);
}
strcpy(path + wd_len, de->d_name);
result = fn(arg, path); result = fn(arg, path);
if (result < GIT_SUCCESS) {
git_buf_truncate(path, wd_len); /* restore path */
if (result != GIT_SUCCESS) {
closedir(dir); closedir(dir);
return result; /* The callee is reponsible for setting the correct error message */ return result; /* The callee is reponsible for setting the correct error message */
} }
if (result > 0) {
closedir(dir);
return result;
}
} }
closedir(dir); closedir(dir);
return GIT_SUCCESS; return GIT_SUCCESS;
} }
int git_futils_mkdir_r(const char *path, const mode_t mode) int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode)
{ {
int error, root_path_offset; int error, root_path_offset;
git_buf make_path = GIT_BUF_INIT;
size_t start;
char *pp, *sp; char *pp, *sp;
char *path_copy = git__strdup(path);
if (path_copy == NULL) if (base != NULL) {
return GIT_ENOMEM; start = strlen(base);
error = git_buf_joinpath(&make_path, base, path);
} else {
start = 0;
error = git_buf_puts(&make_path, path);
}
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to create `%s` tree structure", path);
error = GIT_SUCCESS; pp = make_path.ptr + start;
pp = path_copy;
root_path_offset = git_path_root(pp); root_path_offset = git_path_root(make_path.ptr);
if (root_path_offset > 0) if (root_path_offset > 0)
pp += root_path_offset; /* On Windows, will skip the drive name (eg. C: or D:) */ pp += root_path_offset; /* On Windows, will skip the drive name (eg. C: or D:) */
while (error == GIT_SUCCESS && (sp = strchr(pp, '/')) != NULL) { while (error == GIT_SUCCESS && (sp = strchr(pp, '/')) != NULL) {
if (sp != pp && git_futils_isdir(path_copy) < GIT_SUCCESS) { if (sp != pp && git_futils_isdir(make_path.ptr) < GIT_SUCCESS) {
*sp = 0; *sp = 0;
error = p_mkdir(path_copy, mode); error = p_mkdir(make_path.ptr, mode);
/* Do not choke while trying to recreate an existing directory */ /* Do not choke while trying to recreate an existing directory */
if (errno == EEXIST) if (errno == EEXIST)
...@@ -297,12 +306,12 @@ int git_futils_mkdir_r(const char *path, const mode_t mode) ...@@ -297,12 +306,12 @@ int git_futils_mkdir_r(const char *path, const mode_t mode)
} }
if (*pp != '\0' && error == GIT_SUCCESS) { if (*pp != '\0' && error == GIT_SUCCESS) {
error = p_mkdir(path, mode); error = p_mkdir(make_path.ptr, mode);
if (errno == EEXIST) if (errno == EEXIST)
error = GIT_SUCCESS; error = GIT_SUCCESS;
} }
git__free(path_copy); git_buf_free(&make_path);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__throw(error, "Failed to recursively create `%s` tree structure", path); return git__throw(error, "Failed to recursively create `%s` tree structure", path);
...@@ -310,32 +319,34 @@ int git_futils_mkdir_r(const char *path, const mode_t mode) ...@@ -310,32 +319,34 @@ int git_futils_mkdir_r(const char *path, const mode_t mode)
return GIT_SUCCESS; return GIT_SUCCESS;
} }
static int _rmdir_recurs_foreach(void *opaque, char *path) static int _rmdir_recurs_foreach(void *opaque, git_buf *path)
{ {
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
int force = *(int *)opaque; int force = *(int *)opaque;
if (git_futils_isdir(path) == GIT_SUCCESS) { if (git_futils_isdir(path->ptr) == GIT_SUCCESS) {
size_t root_size = strlen(path); error = git_futils_direach(path, _rmdir_recurs_foreach, opaque);
if (error < GIT_SUCCESS)
if ((error = git_futils_direach(path, GIT_PATH_MAX, _rmdir_recurs_foreach, opaque)) < GIT_SUCCESS) return git__rethrow(error, "Failed to remove directory `%s`", path->ptr);
return git__rethrow(error, "Failed to remove directory `%s`", path); return p_rmdir(path->ptr);
path[root_size] = '\0';
return p_rmdir(path);
} else if (force) { } else if (force) {
return p_unlink(path); return p_unlink(path->ptr);
} }
return git__rethrow(error, "Failed to remove directory. `%s` is not empty", path); return git__rethrow(error, "Failed to remove directory. `%s` is not empty", path->ptr);
} }
int git_futils_rmdir_r(const char *path, int force) int git_futils_rmdir_r(const char *path, int force)
{ {
char p[GIT_PATH_MAX]; int error;
strncpy(p, path, GIT_PATH_MAX); git_buf p = GIT_BUF_INIT;
return _rmdir_recurs_foreach(&force, p);
error = git_buf_sets(&p, path);
if (error == GIT_SUCCESS)
error = _rmdir_recurs_foreach(&force, &p);
git_buf_free(&p);
return error;
} }
int git_futils_cmp_path(const char *name1, int len1, int isdir1, int git_futils_cmp_path(const char *name1, int len1, int isdir1,
...@@ -356,3 +367,39 @@ int git_futils_cmp_path(const char *name1, int len1, int isdir1, ...@@ -356,3 +367,39 @@ int git_futils_cmp_path(const char *name1, int len1, int isdir1,
return 0; return 0;
} }
static int _check_dir_contents(
git_buf *dir,
const char *sub,
int append_on_success,
int (*predicate)(const char *))
{
int error = GIT_SUCCESS;
size_t dir_size = dir->size;
size_t sub_size = strlen(sub);
/* leave base valid even if we could not make space for subdir */
if ((error = git_buf_try_grow(dir, dir_size + sub_size + 2)) < GIT_SUCCESS)
return error;
/* save excursion */
git_buf_joinpath(dir, dir->ptr, sub);
error = (*predicate)(dir->ptr);
/* restore excursion */
if (!append_on_success || error != GIT_SUCCESS)
git_buf_truncate(dir, dir_size);
return error;
}
int git_futils_contains_dir(git_buf *base, const char *subdir, int append_if_exists)
{
return _check_dir_contents(base, subdir, append_if_exists, &git_futils_isdir);
}
int git_futils_contains_file(git_buf *base, const char *file, int append_if_exists)
{
return _check_dir_contents(base, file, append_if_exists, &git_futils_isfile);
}
...@@ -28,6 +28,7 @@ typedef struct { /* file io buffer */ ...@@ -28,6 +28,7 @@ typedef struct { /* file io buffer */
extern int git_futils_readbuffer(git_fbuffer *obj, const char *path); extern int git_futils_readbuffer(git_fbuffer *obj, const char *path);
extern int git_futils_readbuffer_updated(git_fbuffer *obj, const char *path, time_t *mtime, int *updated); extern int git_futils_readbuffer_updated(git_fbuffer *obj, const char *path, time_t *mtime, int *updated);
extern void git_futils_freebuffer(git_fbuffer *obj); extern void git_futils_freebuffer(git_fbuffer *obj);
extern void git_futils_fbuffer_rtrim(git_fbuffer *obj);
/** /**
* File utils * File utils
...@@ -72,9 +73,25 @@ extern int git_futils_isdir(const char *path); ...@@ -72,9 +73,25 @@ extern int git_futils_isdir(const char *path);
extern int git_futils_isfile(const char *path); extern int git_futils_isfile(const char *path);
/** /**
* Check if the given path contains the given subdirectory.
*
* If `append_if_exists` is true, then the subdir will be appended to the
* parent path if it does exists.
*/
extern int git_futils_contains_dir(git_buf *parent, const char *subdir, int append_if_exists);
/**
* Check if the given path contains the given file
*
* If `append_if_exists` is true, then the filename will be appended to the
* parent path if it does exists.
*/
extern int git_futils_contains_file(git_buf *parent, const char *file, int append_if_exists);
/**
* Create a path recursively * Create a path recursively
*/ */
extern int git_futils_mkdir_r(const char *path, const mode_t mode); extern int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode);
/** /**
* Create all the folders required to contain * Create all the folders required to contain
...@@ -85,9 +102,11 @@ extern int git_futils_mkpath2file(const char *path, const mode_t mode); ...@@ -85,9 +102,11 @@ extern int git_futils_mkpath2file(const char *path, const mode_t mode);
extern int git_futils_rmdir_r(const char *path, int force); extern int git_futils_rmdir_r(const char *path, int force);
/** /**
* Create and open a temporary file with a `_git2_` suffix * Create and open a temporary file with a `_git2_` suffix.
* Writes the filename into path_out.
* @return On success, an open file descriptor, else an error code < 0.
*/ */
extern int git_futils_mktmp(char *path_out, const char *filename); extern int git_futils_mktmp(git_buf *path_out, const char *filename);
/** /**
* Move a file on the filesystem, create the * Move a file on the filesystem, create the
...@@ -133,16 +152,14 @@ extern void git_futils_mmap_free(git_map *map); ...@@ -133,16 +152,14 @@ extern void git_futils_mmap_free(git_map *map);
* *
* @param pathbuf buffer the function reads the initial directory * @param pathbuf buffer the function reads the initial directory
* path from, and updates with each successive entry's name. * path from, and updates with each successive entry's name.
* @param pathmax maximum allocation of pathbuf.
* @param fn function to invoke with each entry. The first arg is * @param fn function to invoke with each entry. The first arg is
* the input state and the second arg is pathbuf. The function * the input state and the second arg is pathbuf. The function
* may modify the pathbuf, but only by appending new text. * may modify the pathbuf, but only by appending new text.
* @param state to pass to fn as the first arg. * @param state to pass to fn as the first arg.
*/ */
extern int git_futils_direach( extern int git_futils_direach(
char *pathbuf, git_buf *pathbuf,
size_t pathmax, int (*fn)(void *, git_buf *),
int (*fn)(void *, char *),
void *state); void *state);
extern int git_futils_cmp_path(const char *name1, int len1, int isdir1, extern int git_futils_cmp_path(const char *name1, int len1, int isdir1,
......
...@@ -294,40 +294,30 @@ git_index_entry *git_index_get(git_index *index, unsigned int n) ...@@ -294,40 +294,30 @@ git_index_entry *git_index_get(git_index *index, unsigned int n)
static int index_entry_init(git_index_entry **entry_out, git_index *index, const char *rel_path, int stage) static int index_entry_init(git_index_entry **entry_out, git_index *index, const char *rel_path, int stage)
{ {
git_index_entry *entry; git_index_entry *entry = NULL;
char full_path[GIT_PATH_MAX];
struct stat st; struct stat st;
git_oid oid; git_oid oid;
int error; int error;
const char *workdir;
if (INDEX_OWNER(index) == NULL) if (INDEX_OWNER(index) == NULL)
return git__throw(GIT_EBAREINDEX, return git__throw(GIT_EBAREINDEX,
"Failed to initialize entry. Repository is bare"); "Failed to initialize entry. Repository is bare");
workdir = git_repository_workdir(INDEX_OWNER(index));
if (workdir == NULL)
return git__throw(GIT_EBAREINDEX,
"Failed to initialize entry. Cannot resolved workdir");
git_path_join(full_path, workdir, rel_path);
if (p_lstat(full_path, &st) < 0)
return git__throw(GIT_ENOTFOUND,
"Failed to initialize entry. '%s' cannot be opened", full_path);
if (stage < 0 || stage > 3) if (stage < 0 || stage > 3)
return git__throw(GIT_ERROR, return git__throw(GIT_ERROR,
"Failed to initialize entry. Invalid stage %i", stage); "Failed to initialize entry. Invalid stage %i", stage);
/* There is no need to validate the rel_path here, since it will be
* immediately validated by the call to git_blob_create_fromfile.
*/
/* write the blob to disk and get the oid */ /* write the blob to disk and get the oid */
if ((error = git_blob_create_fromfile(&oid, INDEX_OWNER(index), rel_path)) < GIT_SUCCESS) if ((error = git_blob_create_fromfile(&oid, INDEX_OWNER(index), rel_path)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to initialize index entry"); return git__rethrow(error, "Failed to initialize index entry");
entry = git__malloc(sizeof(git_index_entry)); entry = git__calloc(1, sizeof(git_index_entry));
if (!entry) if (!entry)
return GIT_ENOMEM; return GIT_ENOMEM;
memset(entry, 0x0, sizeof(git_index_entry));
entry->ctime.seconds = (git_time_t)st.st_ctime; entry->ctime.seconds = (git_time_t)st.st_ctime;
entry->mtime.seconds = (git_time_t)st.st_mtime; entry->mtime.seconds = (git_time_t)st.st_mtime;
......
...@@ -151,28 +151,35 @@ cleanup: ...@@ -151,28 +151,35 @@ cleanup:
return error; return error;
} }
static void index_path(char *path, git_indexer *idx) static int index_path(git_buf *path, git_indexer *idx)
{ {
char *ptr;
const char prefix[] = "pack-", suffix[] = ".idx"; const char prefix[] = "pack-", suffix[] = ".idx";
size_t slash = (size_t)path->size;
ptr = strrchr(path, '/') + 1; /* search backwards for '/' */
while (slash > 0 && path->ptr[slash - 1] != '/')
slash--;
memcpy(ptr, prefix, strlen(prefix)); if (git_buf_grow(path, slash + 1 + strlen(prefix) +
ptr += strlen(prefix); GIT_OID_HEXSZ + strlen(suffix) + 1) < GIT_SUCCESS)
git_oid_fmt(ptr, &idx->hash); return GIT_ENOMEM;
ptr += GIT_OID_HEXSZ;
memcpy(ptr, suffix, strlen(suffix) + 1); git_buf_truncate(path, slash + 1);
git_buf_puts(path, prefix);
git_oid_fmt(path->ptr + path->size, &idx->hash);
path->size += GIT_OID_HEXSZ;
git_buf_puts(path, suffix);
return git_buf_lasterror(path);
} }
int git_indexer_write(git_indexer *idx) int git_indexer_write(git_indexer *idx)
{ {
git_mwindow *w = NULL; git_mwindow *w = NULL;
int error; int error;
size_t namelen;
unsigned int i, long_offsets = 0, left; unsigned int i, long_offsets = 0, left;
struct git_pack_idx_header hdr; struct git_pack_idx_header hdr;
char filename[GIT_PATH_MAX]; git_buf filename = GIT_BUF_INIT;
struct entry *entry; struct entry *entry;
void *packfile_hash; void *packfile_hash;
git_oid file_hash; git_oid file_hash;
...@@ -180,16 +187,23 @@ int git_indexer_write(git_indexer *idx) ...@@ -180,16 +187,23 @@ int git_indexer_write(git_indexer *idx)
git_vector_sort(&idx->objects); git_vector_sort(&idx->objects);
namelen = strlen(idx->pack->pack_name); git_buf_sets(&filename, idx->pack->pack_name);
memcpy(filename, idx->pack->pack_name, namelen); git_buf_truncate(&filename, filename.size - strlen("pack"));
memcpy(filename + namelen - strlen("pack"), "idx", strlen("idx") + 1); git_buf_puts(&filename, "idx");
error = git_filebuf_open(&idx->file, filename, GIT_FILEBUF_HASH_CONTENTS); if ((error = git_buf_lasterror(&filename)) < GIT_SUCCESS)
goto cleanup;
error = git_filebuf_open(&idx->file, filename.ptr, GIT_FILEBUF_HASH_CONTENTS);
if (error < GIT_SUCCESS)
goto cleanup;
/* Write out the header */ /* Write out the header */
hdr.idx_signature = htonl(PACK_IDX_SIGNATURE); hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
hdr.idx_version = htonl(2); hdr.idx_version = htonl(2);
error = git_filebuf_write(&idx->file, &hdr, sizeof(hdr)); error = git_filebuf_write(&idx->file, &hdr, sizeof(hdr));
if (error < GIT_SUCCESS)
goto cleanup;
/* Write out the fanout table */ /* Write out the fanout table */
for (i = 0; i < 256; ++i) { for (i = 0; i < 256; ++i) {
...@@ -270,14 +284,18 @@ int git_indexer_write(git_indexer *idx) ...@@ -270,14 +284,18 @@ int git_indexer_write(git_indexer *idx)
goto cleanup; goto cleanup;
/* Figure out what the final name should be */ /* Figure out what the final name should be */
index_path(filename, idx); error = index_path(&filename, idx);
if (error < GIT_SUCCESS)
goto cleanup;
/* Commit file */ /* Commit file */
error = git_filebuf_commit_at(&idx->file, filename, GIT_PACK_FILE_MODE); error = git_filebuf_commit_at(&idx->file, filename.ptr, GIT_PACK_FILE_MODE);
cleanup: cleanup:
git_mwindow_free_all(&idx->pack->mwf); git_mwindow_free_all(&idx->pack->mwf);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
git_filebuf_cleanup(&idx->file); git_filebuf_cleanup(&idx->file);
git_buf_free(&filename);
return error; return error;
} }
......
...@@ -344,40 +344,47 @@ static int add_default_backends(git_odb *db, const char *objects_dir, int as_alt ...@@ -344,40 +344,47 @@ static int add_default_backends(git_odb *db, const char *objects_dir, int as_alt
static int load_alternates(git_odb *odb, const char *objects_dir) static int load_alternates(git_odb *odb, const char *objects_dir)
{ {
char alternates_path[GIT_PATH_MAX]; git_buf alternates_path = GIT_BUF_INIT;
char *buffer, *alternate; char *buffer;
git_fbuffer alternates_buf = GIT_FBUFFER_INIT; git_fbuffer alternates_buf = GIT_FBUFFER_INIT;
const char *alternate;
int error; int error;
git_path_join(alternates_path, objects_dir, GIT_ALTERNATES_FILE); error = git_buf_joinpath(&alternates_path, objects_dir, GIT_ALTERNATES_FILE);
if (error < GIT_SUCCESS)
return error;
if (git_futils_exists(alternates_path) < GIT_SUCCESS) if (git_futils_exists(alternates_path.ptr) < GIT_SUCCESS) {
git_buf_free(&alternates_path);
return GIT_SUCCESS; return GIT_SUCCESS;
}
if (git_futils_readbuffer(&alternates_buf, alternates_path) < GIT_SUCCESS) if (git_futils_readbuffer(&alternates_buf, alternates_path.ptr) < GIT_SUCCESS) {
git_buf_free(&alternates_path);
return git__throw(GIT_EOSERR, "Failed to add backend. Can't read alternates"); return git__throw(GIT_EOSERR, "Failed to add backend. Can't read alternates");
}
buffer = (char *)alternates_buf.data; buffer = (char *)alternates_buf.data;
error = GIT_SUCCESS; error = GIT_SUCCESS;
/* add each alternate as a new backend; one alternate per line */ /* add each alternate as a new backend; one alternate per line */
while ((alternate = git__strtok(&buffer, "\r\n")) != NULL) { while ((alternate = git__strtok(&buffer, "\r\n")) != NULL) {
char full_path[GIT_PATH_MAX];
if (*alternate == '\0' || *alternate == '#') if (*alternate == '\0' || *alternate == '#')
continue; continue;
/* relative path: build based on the current `objects` folder */ /* relative path: build based on the current `objects` folder */
if (*alternate == '.') { if (*alternate == '.') {
git_path_join(full_path, objects_dir, alternate); error = git_buf_joinpath(&alternates_path, objects_dir, alternate);
alternate = full_path; if (error < GIT_SUCCESS)
break;
alternate = git_buf_cstr(&alternates_path);
} }
if ((error = add_default_backends(odb, alternate, 1)) < GIT_SUCCESS) if ((error = add_default_backends(odb, alternate, 1)) < GIT_SUCCESS)
break; break;
} }
git_buf_free(&alternates_path);
git_futils_freebuffer(&alternates_buf); git_futils_freebuffer(&alternates_buf);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to load alternates"); return git__rethrow(error, "Failed to load alternates");
......
...@@ -26,7 +26,6 @@ typedef struct { /* object header data */ ...@@ -26,7 +26,6 @@ typedef struct { /* object header data */
typedef struct { typedef struct {
git_odb_stream stream; git_odb_stream stream;
git_filebuf fbuf; git_filebuf fbuf;
int finished;
} loose_writestream; } loose_writestream;
typedef struct loose_backend { typedef struct loose_backend {
...@@ -51,31 +50,28 @@ typedef struct { ...@@ -51,31 +50,28 @@ typedef struct {
} loose_locate_object_state; } loose_locate_object_state;
/*********************************************************** /***********************************************************
* *
* MISCELANEOUS HELPER FUNCTIONS * MISCELANEOUS HELPER FUNCTIONS
* *
***********************************************************/ ***********************************************************/
static size_t object_file_name(char *name, size_t n, char *dir, const git_oid *id) static int object_file_name(git_buf *name, const char *dir, const git_oid *id)
{ {
size_t len = strlen(dir); git_buf_sets(name, dir);
/* check length: 43 = 40 hex sha1 chars + 2 * '/' + '\0' */ /* expand length for 40 hex sha1 chars + 2 * '/' + '\0' */
if (len+43 > n) if (git_buf_grow(name, name->size + GIT_OID_HEXSZ + 3) < GIT_SUCCESS)
return len+43; return GIT_ENOMEM;
/* the object dir: eg $GIT_DIR/objects */ git_path_to_dir(name);
strcpy(name, dir);
if (name[len-1] != '/')
name[len++] = '/';
/* loose object filename: aa/aaa... (41 bytes) */ /* loose object filename: aa/aaa... (41 bytes) */
git_oid_pathfmt(&name[len], id); git_oid_pathfmt(name->ptr + name->size, id);
name[len+41] = '\0'; name->size += GIT_OID_HEXSZ + 1;
name->ptr[name->size] = '\0';
return 0; return GIT_SUCCESS;
} }
...@@ -384,18 +380,21 @@ static int inflate_disk_obj(git_rawobj *out, git_fbuffer *obj) ...@@ -384,18 +380,21 @@ static int inflate_disk_obj(git_rawobj *out, git_fbuffer *obj)
* *
***********************************************************/ ***********************************************************/
static int read_loose(git_rawobj *out, const char *loc) static int read_loose(git_rawobj *out, git_buf *loc)
{ {
int error; int error;
git_fbuffer obj = GIT_FBUFFER_INIT; git_fbuffer obj = GIT_FBUFFER_INIT;
assert(out && loc); assert(out && loc);
if ((error = git_buf_lasterror(loc)) < GIT_SUCCESS)
return error;
out->data = NULL; out->data = NULL;
out->len = 0; out->len = 0;
out->type = GIT_OBJ_BAD; out->type = GIT_OBJ_BAD;
if (git_futils_readbuffer(&obj, loc) < 0) if (git_futils_readbuffer(&obj, loc->ptr) < 0)
return git__throw(GIT_ENOTFOUND, "Failed to read loose object. File not found"); return git__throw(GIT_ENOTFOUND, "Failed to read loose object. File not found");
error = inflate_disk_obj(out, &obj); error = inflate_disk_obj(out, &obj);
...@@ -404,7 +403,7 @@ static int read_loose(git_rawobj *out, const char *loc) ...@@ -404,7 +403,7 @@ static int read_loose(git_rawobj *out, const char *loc)
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to read loose object"); return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to read loose object");
} }
static int read_header_loose(git_rawobj *out, const char *loc) static int read_header_loose(git_rawobj *out, git_buf *loc)
{ {
int error = GIT_SUCCESS, z_return = Z_ERRNO, read_bytes; int error = GIT_SUCCESS, z_return = Z_ERRNO, read_bytes;
git_file fd; git_file fd;
...@@ -414,9 +413,12 @@ static int read_header_loose(git_rawobj *out, const char *loc) ...@@ -414,9 +413,12 @@ static int read_header_loose(git_rawobj *out, const char *loc)
assert(out && loc); assert(out && loc);
if ((error = git_buf_lasterror(loc)) < GIT_SUCCESS)
return error;
out->data = NULL; out->data = NULL;
if ((fd = p_open(loc, O_RDONLY)) < 0) if ((fd = p_open(loc->ptr, O_RDONLY)) < 0)
return git__throw(GIT_ENOTFOUND, "Failed to read loose object header. File not found"); return git__throw(GIT_ENOTFOUND, "Failed to read loose object header. File not found");
init_stream(&zs, inflated_buffer, sizeof(inflated_buffer)); init_stream(&zs, inflated_buffer, sizeof(inflated_buffer));
...@@ -456,33 +458,39 @@ cleanup: ...@@ -456,33 +458,39 @@ cleanup:
return GIT_SUCCESS; return GIT_SUCCESS;
} }
static int locate_object(char *object_location, loose_backend *backend, const git_oid *oid) static int locate_object(
git_buf *object_location,
loose_backend *backend,
const git_oid *oid)
{ {
object_file_name(object_location, GIT_PATH_MAX, backend->objects_dir, oid); int error = object_file_name(object_location, backend->objects_dir, oid);
return git_futils_exists(object_location);
if (error == GIT_SUCCESS)
error = git_futils_exists(git_buf_cstr(object_location));
return error;
} }
/* Explore an entry of a directory and see if it matches a short oid */ /* Explore an entry of a directory and see if it matches a short oid */
static int fn_locate_object_short_oid(void *state, char *pathbuf) { static int fn_locate_object_short_oid(void *state, git_buf *pathbuf) {
loose_locate_object_state *sstate = (loose_locate_object_state *)state; loose_locate_object_state *sstate = (loose_locate_object_state *)state;
size_t pathbuf_len = strlen(pathbuf); if (pathbuf->size - sstate->dir_len != GIT_OID_HEXSZ - 2) {
if (pathbuf_len - sstate->dir_len != GIT_OID_HEXSZ - 2) {
/* Entry cannot be an object. Continue to next entry */ /* Entry cannot be an object. Continue to next entry */
return GIT_SUCCESS; return GIT_SUCCESS;
} }
if (!git_futils_exists(pathbuf) && git_futils_isdir(pathbuf)) { if (!git_futils_exists(pathbuf->ptr) && git_futils_isdir(pathbuf->ptr)) {
/* We are already in the directory matching the 2 first hex characters, /* We are already in the directory matching the 2 first hex characters,
* compare the first ncmp characters of the oids */ * compare the first ncmp characters of the oids */
if (!memcmp(sstate->short_oid + 2, if (!memcmp(sstate->short_oid + 2,
(unsigned char *)pathbuf + sstate->dir_len, (unsigned char *)pathbuf->ptr + sstate->dir_len,
sstate->short_oid_len - 2)) { sstate->short_oid_len - 2)) {
if (!sstate->found) { if (!sstate->found) {
sstate->res_oid[0] = sstate->short_oid[0]; sstate->res_oid[0] = sstate->short_oid[0];
sstate->res_oid[1] = sstate->short_oid[1]; sstate->res_oid[1] = sstate->short_oid[1];
memcpy(sstate->res_oid+2, pathbuf+sstate->dir_len, GIT_OID_HEXSZ-2); memcpy(sstate->res_oid+2, pathbuf->ptr+sstate->dir_len, GIT_OID_HEXSZ-2);
} }
sstate->found++; sstate->found++;
} }
...@@ -494,39 +502,50 @@ static int fn_locate_object_short_oid(void *state, char *pathbuf) { ...@@ -494,39 +502,50 @@ static int fn_locate_object_short_oid(void *state, char *pathbuf) {
} }
/* Locate an object matching a given short oid */ /* Locate an object matching a given short oid */
static int locate_object_short_oid(char *object_location, git_oid *res_oid, loose_backend *backend, const git_oid *short_oid, unsigned int len) static int locate_object_short_oid(
git_buf *object_location,
git_oid *res_oid,
loose_backend *backend,
const git_oid *short_oid,
unsigned int len)
{ {
char *objects_dir = backend->objects_dir; char *objects_dir = backend->objects_dir;
size_t dir_len = strlen(objects_dir); size_t dir_len = strlen(objects_dir);
loose_locate_object_state state; loose_locate_object_state state;
int error; int error;
if (dir_len+43 > GIT_PATH_MAX) /* prealloc memory for OBJ_DIR/xx/ */
return git__throw(GIT_ERROR, "Failed to locate object from short oid. Object path too long"); if ((error = git_buf_grow(object_location, dir_len + 5)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to locate object from short oid");
strcpy(object_location, objects_dir); git_buf_sets(object_location, objects_dir);
git_path_to_dir(object_location);
/* Add a separator if not already there */ /* save adjusted position at end of dir so it can be restored later */
if (object_location[dir_len-1] != '/') dir_len = object_location->size;
object_location[dir_len++] = '/';
/* Convert raw oid to hex formatted oid */ /* Convert raw oid to hex formatted oid */
git_oid_fmt((char *)state.short_oid, short_oid); git_oid_fmt((char *)state.short_oid, short_oid);
/* Explore OBJ_DIR/xx/ where xx is the beginning of hex formatted short oid */ /* Explore OBJ_DIR/xx/ where xx is the beginning of hex formatted short oid */
sprintf(object_location+dir_len, "%.2s/", state.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");
/* Check that directory exists */ /* Check that directory exists */
if (git_futils_exists(object_location) || git_futils_isdir(object_location)) if (git_futils_exists(object_location->ptr) ||
git_futils_isdir(object_location->ptr))
return git__throw(GIT_ENOTFOUND, "Failed to locate object from short oid. Object not found"); return git__throw(GIT_ENOTFOUND, "Failed to locate object from short oid. Object not found");
state.dir_len = dir_len+3; state.dir_len = object_location->size;
state.short_oid_len = len; state.short_oid_len = len;
state.found = 0; state.found = 0;
/* Explore directory to find a unique object matching short_oid */ /* Explore directory to find a unique object matching short_oid */
error = git_futils_direach(object_location, GIT_PATH_MAX, fn_locate_object_short_oid, &state); error = git_futils_direach(object_location, fn_locate_object_short_oid, &state);
if (error) { if (error)
return git__rethrow(error, "Failed to locate object from short oid"); return git__rethrow(error, "Failed to locate object from short oid");
}
if (!state.found) { if (!state.found) {
return git__throw(GIT_ENOTFOUND, "Failed to locate object from short oid. Object not found"); return git__throw(GIT_ENOTFOUND, "Failed to locate object from short oid. Object not found");
} }
...@@ -538,7 +557,16 @@ static int locate_object_short_oid(char *object_location, git_oid *res_oid, loos ...@@ -538,7 +557,16 @@ static int locate_object_short_oid(char *object_location, git_oid *res_oid, loos
} }
/* Update the location according to the oid obtained */ /* Update the location according to the oid obtained */
git_oid_pathfmt(object_location+dir_len, res_oid);
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");
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 GIT_SUCCESS;
} }
...@@ -561,45 +589,49 @@ static int locate_object_short_oid(char *object_location, git_oid *res_oid, loos ...@@ -561,45 +589,49 @@ static int locate_object_short_oid(char *object_location, git_oid *res_oid, loos
static int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid) static int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
{ {
char object_path[GIT_PATH_MAX]; git_buf object_path = GIT_BUF_INIT;
git_rawobj raw; git_rawobj raw;
int error; int error = GIT_SUCCESS;
assert(backend && oid); assert(backend && oid);
raw.len = 0; raw.len = 0;
raw.type = GIT_OBJ_BAD; raw.type = GIT_OBJ_BAD;
if (locate_object(object_path, (loose_backend *)backend, oid) < 0) if (locate_object(&object_path, (loose_backend *)backend, oid) < 0)
return git__throw(GIT_ENOTFOUND, "Failed to read loose backend header. Object not found"); 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) {
*len_p = raw.len;
*type_p = raw.type;
}
if ((error = read_header_loose(&raw, object_path)) < GIT_SUCCESS) git_buf_free(&object_path);
return error;
*len_p = raw.len; return error;
*type_p = raw.type;
return GIT_SUCCESS;
} }
static int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid) static int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
{ {
char object_path[GIT_PATH_MAX]; git_buf object_path = GIT_BUF_INIT;
git_rawobj raw; git_rawobj raw;
int error; int error = GIT_SUCCESS;
assert(backend && oid); assert(backend && oid);
if (locate_object(object_path, (loose_backend *)backend, oid) < 0) if (locate_object(&object_path, (loose_backend *)backend, oid) < 0)
return git__throw(GIT_ENOTFOUND, "Failed to read loose backend. Object not found"); error = git__throw(GIT_ENOTFOUND, "Failed to read loose backend. Object not found");
else if ((error = read_loose(&raw, &object_path)) == GIT_SUCCESS) {
if ((error = read_loose(&raw, object_path)) < GIT_SUCCESS) *buffer_p = raw.data;
return git__rethrow(error, "Failed to read loose backend"); *len_p = raw.len;
*type_p = raw.type;
}
else {
git__rethrow(error, "Failed to read loose backend");
}
*buffer_p = raw.data; git_buf_free(&object_path);
*len_p = raw.len;
*type_p = raw.type;
return GIT_SUCCESS; return error;
} }
static int loose_backend__read_prefix( static int loose_backend__read_prefix(
...@@ -611,45 +643,52 @@ static int loose_backend__read_prefix( ...@@ -611,45 +643,52 @@ static int loose_backend__read_prefix(
const git_oid *short_oid, const git_oid *short_oid,
unsigned int len) unsigned int len)
{ {
int error = GIT_SUCCESS;
if (len < GIT_OID_MINPREFIXLEN) if (len < GIT_OID_MINPREFIXLEN)
return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to read loose backend. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN); return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to read loose "
"backend. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN);
if (len >= GIT_OID_HEXSZ) { if (len >= GIT_OID_HEXSZ) {
/* We can fall back to regular read method */ /* We can fall back to regular read method */
int error = loose_backend__read(buffer_p, len_p, type_p, backend, short_oid); error = loose_backend__read(buffer_p, len_p, type_p, backend, short_oid);
if (error == GIT_SUCCESS) if (error == GIT_SUCCESS)
git_oid_cpy(out_oid, short_oid); git_oid_cpy(out_oid, short_oid);
return error;
} else { } else {
char object_path[GIT_PATH_MAX]; git_buf object_path = GIT_BUF_INIT;
git_rawobj raw; git_rawobj raw;
int error;
assert(backend && short_oid); assert(backend && short_oid);
if ((error = locate_object_short_oid(object_path, out_oid, (loose_backend *)backend, short_oid, len)) < 0) { if ((error = locate_object_short_oid(&object_path, out_oid,
return git__rethrow(error, "Failed to read loose backend"); (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 {
*buffer_p = raw.data;
*len_p = raw.len;
*type_p = raw.type;
} }
if ((error = read_loose(&raw, object_path)) < GIT_SUCCESS) git_buf_free(&object_path);
return git__rethrow(error, "Failed to read loose backend");
*buffer_p = raw.data;
*len_p = raw.len;
*type_p = raw.type;
} }
return GIT_SUCCESS; return error;
} }
static int loose_backend__exists(git_odb_backend *backend, const git_oid *oid) static int loose_backend__exists(git_odb_backend *backend, const git_oid *oid)
{ {
char object_path[GIT_PATH_MAX]; git_buf object_path = GIT_BUF_INIT;
int error;
assert(backend && oid); assert(backend && oid);
return locate_object(object_path, (loose_backend *)backend, oid) == GIT_SUCCESS; error = locate_object(&object_path, (loose_backend *)backend, oid);
git_buf_free(&object_path);
return (error == GIT_SUCCESS);
} }
static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream) static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream)
...@@ -658,30 +697,39 @@ static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream) ...@@ -658,30 +697,39 @@ static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream)
loose_backend *backend = (loose_backend *)_stream->backend; loose_backend *backend = (loose_backend *)_stream->backend;
int error; int error;
char final_path[GIT_PATH_MAX]; git_buf final_path = GIT_BUF_INIT;
if ((error = git_filebuf_hash(oid, &stream->fbuf)) < GIT_SUCCESS) if ((error = git_filebuf_hash(oid, &stream->fbuf)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to write loose backend"); goto cleanup;
if (object_file_name(final_path, sizeof(final_path), backend->objects_dir, oid)) if ((error = object_file_name(&final_path, backend->objects_dir, oid)) < GIT_SUCCESS)
return GIT_ENOMEM; goto cleanup;
if ((error = git_futils_mkpath2file(final_path, GIT_OBJECT_DIR_MODE)) < GIT_SUCCESS) if ((error = git_buf_lasterror(&final_path)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to write loose backend"); goto cleanup;
stream->finished = 1; if ((error = git_futils_mkpath2file(final_path.ptr, GIT_OBJECT_DIR_MODE)) < GIT_SUCCESS)
goto cleanup;
/* /*
* Don't try to add an existing object to the repository. This * Don't try to add an existing object to the repository. This
* is what git does and allows us to sidestep the fact that * is what git does and allows us to sidestep the fact that
* we're not allowed to overwrite a read-only file on Windows. * we're not allowed to overwrite a read-only file on Windows.
*/ */
if (git_futils_exists(final_path) == GIT_SUCCESS) { if (git_futils_exists(final_path.ptr) == GIT_SUCCESS) {
git_filebuf_cleanup(&stream->fbuf); git_filebuf_cleanup(&stream->fbuf);
return GIT_SUCCESS; goto cleanup;
} }
return git_filebuf_commit_at(&stream->fbuf, final_path, 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;
} }
static int loose_backend__stream_write(git_odb_stream *_stream, const char *data, size_t len) static int loose_backend__stream_write(git_odb_stream *_stream, const char *data, size_t len)
...@@ -694,9 +742,7 @@ static void loose_backend__stream_free(git_odb_stream *_stream) ...@@ -694,9 +742,7 @@ static void loose_backend__stream_free(git_odb_stream *_stream)
{ {
loose_writestream *stream = (loose_writestream *)_stream; loose_writestream *stream = (loose_writestream *)_stream;
if (!stream->finished) git_filebuf_cleanup(&stream->fbuf);
git_filebuf_cleanup(&stream->fbuf);
git__free(stream); git__free(stream);
} }
...@@ -718,7 +764,8 @@ static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_ ...@@ -718,7 +764,8 @@ static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_
loose_backend *backend; loose_backend *backend;
loose_writestream *stream; loose_writestream *stream;
char hdr[64], tmp_path[GIT_PATH_MAX]; char hdr[64];
git_buf tmp_path = GIT_BUF_INIT;
int hdrlen; int hdrlen;
int error; int error;
...@@ -742,33 +789,38 @@ static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_ ...@@ -742,33 +789,38 @@ static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_
stream->stream.free = &loose_backend__stream_free; stream->stream.free = &loose_backend__stream_free;
stream->stream.mode = GIT_STREAM_WRONLY; stream->stream.mode = GIT_STREAM_WRONLY;
git_path_join(tmp_path, backend->objects_dir, "tmp_object"); 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, error = git_filebuf_open(&stream->fbuf, tmp_path.ptr,
GIT_FILEBUF_HASH_CONTENTS | GIT_FILEBUF_HASH_CONTENTS |
GIT_FILEBUF_TEMPORARY | GIT_FILEBUF_TEMPORARY |
(backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT)); (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT));
if (error < GIT_SUCCESS)
if (error < GIT_SUCCESS) { goto cleanup;
git__free(stream);
return git__rethrow(error, "Failed to create loose backend stream");
}
error = stream->stream.write((git_odb_stream *)stream, hdr, hdrlen); error = stream->stream.write((git_odb_stream *)stream, hdr, hdrlen);
if (error < GIT_SUCCESS) { if (error < GIT_SUCCESS)
git_filebuf_cleanup(&stream->fbuf); goto cleanup;
git__free(stream);
return git__rethrow(error, "Failed to create loose backend stream"); git_buf_free(&tmp_path);
}
*stream_out = (git_odb_stream *)stream; *stream_out = (git_odb_stream *)stream;
return GIT_SUCCESS; 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");
} }
static int loose_backend__write(git_oid *oid, git_odb_backend *_backend, const void *data, size_t len, git_otype type) static int loose_backend__write(git_oid *oid, git_odb_backend *_backend, const void *data, size_t len, git_otype type)
{ {
int error, header_len; int error, header_len;
char final_path[GIT_PATH_MAX], header[64]; git_buf final_path = GIT_BUF_INIT;
char header[64];
git_filebuf fbuf = GIT_FILEBUF_INIT; git_filebuf fbuf = GIT_FILEBUF_INIT;
loose_backend *backend; loose_backend *backend;
...@@ -781,30 +833,35 @@ static int loose_backend__write(git_oid *oid, git_odb_backend *_backend, const v ...@@ -781,30 +833,35 @@ static int loose_backend__write(git_oid *oid, git_odb_backend *_backend, const v
return GIT_EOBJCORRUPTED; return GIT_EOBJCORRUPTED;
} }
git_path_join(final_path, backend->objects_dir, "tmp_object"); error = git_buf_joinpath(&final_path, backend->objects_dir, "tmp_object");
if (error < GIT_SUCCESS)
goto cleanup;
error = git_filebuf_open(&fbuf, final_path, error = git_filebuf_open(&fbuf, final_path.ptr,
GIT_FILEBUF_HASH_CONTENTS | GIT_FILEBUF_HASH_CONTENTS |
GIT_FILEBUF_TEMPORARY | GIT_FILEBUF_TEMPORARY |
(backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT)); (backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT));
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; goto cleanup;
git_filebuf_write(&fbuf, header, header_len); git_filebuf_write(&fbuf, header, header_len);
git_filebuf_write(&fbuf, data, len); git_filebuf_write(&fbuf, data, len);
git_filebuf_hash(oid, &fbuf); git_filebuf_hash(oid, &fbuf);
if ((error = object_file_name(final_path, sizeof(final_path), backend->objects_dir, oid)) < GIT_SUCCESS) error = object_file_name(&final_path, backend->objects_dir, oid);
if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
if ((error = git_futils_mkpath2file(final_path, GIT_OBJECT_DIR_MODE)) < GIT_SUCCESS) error = git_futils_mkpath2file(final_path.ptr, GIT_OBJECT_DIR_MODE);
if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
return git_filebuf_commit_at(&fbuf, final_path, GIT_OBJECT_FILE_MODE); error = git_filebuf_commit_at(&fbuf, final_path.ptr, GIT_OBJECT_FILE_MODE);
cleanup: cleanup:
git_filebuf_cleanup(&fbuf); if (error < GIT_SUCCESS)
git_filebuf_cleanup(&fbuf);
git_buf_free(&final_path);
return error; return error;
} }
......
...@@ -133,7 +133,7 @@ static int pack_window_contains(git_mwindow *win, off_t offset); ...@@ -133,7 +133,7 @@ static int pack_window_contains(git_mwindow *win, off_t offset);
static int packfile_sort__cb(const void *a_, const void *b_); static int packfile_sort__cb(const void *a_, const void *b_);
static int packfile_load__cb(void *_data, char *path); static int packfile_load__cb(void *_data, git_buf *path);
static int packfile_refresh_all(struct pack_backend *backend); static int packfile_refresh_all(struct pack_backend *backend);
static int pack_entry_find(struct git_pack_entry *e, static int pack_entry_find(struct git_pack_entry *e,
...@@ -207,23 +207,23 @@ static int packfile_sort__cb(const void *a_, const void *b_) ...@@ -207,23 +207,23 @@ static int packfile_sort__cb(const void *a_, const void *b_)
static int packfile_load__cb(void *_data, char *path) static int packfile_load__cb(void *_data, git_buf *path)
{ {
struct pack_backend *backend = (struct pack_backend *)_data; struct pack_backend *backend = (struct pack_backend *)_data;
struct git_pack_file *pack; struct git_pack_file *pack;
int error; int error;
size_t i; size_t i;
if (git__suffixcmp(path, ".idx") != 0) if (git__suffixcmp(path->ptr, ".idx") != 0)
return GIT_SUCCESS; /* not an index */ return GIT_SUCCESS; /* not an index */
for (i = 0; i < backend->packs.length; ++i) { for (i = 0; i < backend->packs.length; ++i) {
struct git_pack_file *p = git_vector_get(&backend->packs, i); struct git_pack_file *p = git_vector_get(&backend->packs, i);
if (memcmp(p->pack_name, path, strlen(path) - strlen(".idx")) == 0) if (memcmp(p->pack_name, path->ptr, path->size - strlen(".idx")) == 0)
return GIT_SUCCESS; return GIT_SUCCESS;
} }
error = git_packfile_check(&pack, path); error = git_packfile_check(&pack, path->ptr);
if (error == GIT_ENOTFOUND) { if (error == GIT_ENOTFOUND) {
/* ignore missing .pack file as git does */ /* ignore missing .pack file as git does */
return GIT_SUCCESS; return GIT_SUCCESS;
...@@ -250,11 +250,13 @@ static int packfile_refresh_all(struct pack_backend *backend) ...@@ -250,11 +250,13 @@ static int packfile_refresh_all(struct pack_backend *backend)
return git__throw(GIT_ENOTFOUND, "Failed to refresh packfiles. Backend not found"); return git__throw(GIT_ENOTFOUND, "Failed to refresh packfiles. Backend not found");
if (st.st_mtime != backend->pack_folder_mtime) { if (st.st_mtime != backend->pack_folder_mtime) {
char path[GIT_PATH_MAX]; git_buf path = GIT_BUF_INIT;
strcpy(path, backend->pack_folder); git_buf_sets(&path, backend->pack_folder);
/* reload all packs */ /* reload all packs */
error = git_futils_direach(path, GIT_PATH_MAX, packfile_load__cb, (void *)backend); error = git_futils_direach(&path, packfile_load__cb, (void *)backend);
git_buf_free(&path);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to refresh packfiles"); return git__rethrow(error, "Failed to refresh packfiles");
...@@ -451,27 +453,25 @@ static void pack_backend__free(git_odb_backend *_backend) ...@@ -451,27 +453,25 @@ static void pack_backend__free(git_odb_backend *_backend)
int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
{ {
struct pack_backend *backend; struct pack_backend *backend = NULL;
char path[GIT_PATH_MAX]; git_buf path = GIT_BUF_INIT;
int error = GIT_SUCCESS;
backend = git__calloc(1, sizeof(struct pack_backend)); backend = git__calloc(1, sizeof(struct pack_backend));
if (backend == NULL) if (backend == NULL)
return GIT_ENOMEM; return GIT_ENOMEM;
if (git_vector_init(&backend->packs, 8, packfile_sort__cb) < GIT_SUCCESS) { error = git_vector_init(&backend->packs, 8, packfile_sort__cb);
git__free(backend); if (error < GIT_SUCCESS)
return GIT_ENOMEM; goto cleanup;
}
git_path_join(path, objects_dir, "pack"); error = git_buf_joinpath(&path, objects_dir, "pack");
if (git_futils_isdir(path) == GIT_SUCCESS) { if (error < GIT_SUCCESS)
backend->pack_folder = git__strdup(path); goto cleanup;
backend->pack_folder_mtime = 0;
if (backend->pack_folder == NULL) { if (git_futils_isdir(git_buf_cstr(&path)) == GIT_SUCCESS) {
git__free(backend); backend->pack_folder = git_buf_detach(&path);
return GIT_ENOMEM; backend->pack_folder_mtime = 0;
}
} }
backend->parent.read = &pack_backend__read; backend->parent.read = &pack_backend__read;
...@@ -481,5 +481,11 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) ...@@ -481,5 +481,11 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
backend->parent.free = &pack_backend__free; backend->parent.free = &pack_backend__free;
*backend_out = (git_odb_backend *)backend; *backend_out = (git_odb_backend *)backend;
return GIT_SUCCESS;
cleanup:
if (error < GIT_SUCCESS)
git__free(backend);
git_buf_free(&path);
return error;
} }
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* Based on the Android implementation, BSD licensed. * Based on the Android implementation, BSD licensed.
* Check http://android.git.kernel.org/ * Check http://android.git.kernel.org/
*/ */
int git_path_basename_r(char *buffer, size_t bufflen, const char *path) int git_path_basename_r(git_buf *buffer, const char *path)
{ {
const char *endp, *startp; const char *endp, *startp;
int len, result; int len, result;
...@@ -49,18 +49,13 @@ int git_path_basename_r(char *buffer, size_t bufflen, const char *path) ...@@ -49,18 +49,13 @@ int git_path_basename_r(char *buffer, size_t bufflen, const char *path)
Exit: Exit:
result = len; result = len;
if (buffer == NULL) {
return result;
}
if (len > (int)bufflen-1) {
len = (int)bufflen-1;
result = GIT_ENOMEM;
}
if (len >= 0) { if (buffer != NULL) {
memmove(buffer, startp, len); if (git_buf_set(buffer, startp, len) < GIT_SUCCESS)
buffer[len] = 0; return git__rethrow(git_buf_lasterror(buffer),
"Could not get basename of '%s'", path);
} }
return result; return result;
} }
...@@ -68,7 +63,7 @@ Exit: ...@@ -68,7 +63,7 @@ Exit:
* Based on the Android implementation, BSD licensed. * Based on the Android implementation, BSD licensed.
* Check http://android.git.kernel.org/ * Check http://android.git.kernel.org/
*/ */
int git_path_dirname_r(char *buffer, size_t bufflen, const char *path) int git_path_dirname_r(git_buf *buffer, const char *path)
{ {
const char *endp; const char *endp;
int result, len; int result, len;
...@@ -114,59 +109,39 @@ int git_path_dirname_r(char *buffer, size_t bufflen, const char *path) ...@@ -114,59 +109,39 @@ int git_path_dirname_r(char *buffer, size_t bufflen, const char *path)
Exit: Exit:
result = len; result = len;
if (len+1 > GIT_PATH_MAX) {
return GIT_ENOMEM;
}
if (buffer == NULL)
return result;
if (len > (int)bufflen-1) { if (buffer != NULL) {
len = (int)bufflen-1; if (git_buf_set(buffer, path, len) < GIT_SUCCESS)
result = GIT_ENOMEM; return git__rethrow(git_buf_lasterror(buffer),
"Could not get dirname of '%s'", path);
} }
if (len >= 0) {
memmove(buffer, path, len);
buffer[len] = 0;
}
return result; return result;
} }
char *git_path_dirname(const char *path) char *git_path_dirname(const char *path)
{ {
char *dname = NULL; git_buf buf = GIT_BUF_INIT;
int len; char *dirname;
len = (path ? strlen(path) : 0) + 2; git_path_dirname_r(&buf, path);
dname = (char *)git__malloc(len); dirname = git_buf_detach(&buf);
if (dname == NULL) git_buf_free(&buf); /* avoid memleak if error occurs */
return NULL;
if (git_path_dirname_r(dname, len, path) < GIT_SUCCESS) { return dirname;
git__free(dname);
return NULL;
}
return dname;
} }
char *git_path_basename(const char *path) char *git_path_basename(const char *path)
{ {
char *bname = NULL; git_buf buf = GIT_BUF_INIT;
int len; char *basename;
len = (path ? strlen(path) : 0) + 2;
bname = (char *)git__malloc(len);
if (bname == NULL)
return NULL;
if (git_path_basename_r(bname, len, path) < GIT_SUCCESS) { git_path_basename_r(&buf, path);
git__free(bname); basename = git_buf_detach(&buf);
return NULL; git_buf_free(&buf); /* avoid memleak if error occurs */
}
return bname; return basename;
} }
...@@ -188,39 +163,6 @@ const char *git_path_topdir(const char *path) ...@@ -188,39 +163,6 @@ const char *git_path_topdir(const char *path)
return &path[i + 1]; return &path[i + 1];
} }
void git_path_join_n(char *buffer_out, int count, ...)
{
va_list ap;
int i;
char *buffer_start = buffer_out;
va_start(ap, count);
for (i = 0; i < count; ++i) {
const char *path;
int len;
path = va_arg(ap, const char *);
assert((i == 0) || path != buffer_start);
if (i > 0 && *path == '/' && buffer_out > buffer_start && buffer_out[-1] == '/')
path++;
if (!*path)
continue;
len = strlen(path);
memmove(buffer_out, path, len);
buffer_out = buffer_out + len;
if (i < count - 1 && buffer_out[-1] != '/')
*buffer_out++ = '/';
}
va_end(ap);
*buffer_out = '\0';
}
int git_path_root(const char *path) int git_path_root(const char *path)
{ {
int offset = 0; int offset = 0;
...@@ -237,34 +179,61 @@ int git_path_root(const char *path) ...@@ -237,34 +179,61 @@ int git_path_root(const char *path)
return -1; /* Not a real error. Rather a signal than the path is not rooted */ return -1; /* Not a real error. Rather a signal than the path is not rooted */
} }
int git_path_prettify(char *path_out, const char *path, const char *base) int git_path_prettify(git_buf *path_out, const char *path, const char *base)
{ {
char *result; char *result = NULL;
int error = GIT_SUCCESS;
git_buf_clear(path_out);
/* construct path if needed */
if (base != NULL && git_path_root(path) < 0) {
if ((error = git_buf_joinpath(path_out, base, path)) < GIT_SUCCESS)
return error;
path = path_out->ptr;
}
/* allow realpath to allocate the buffer */
if (path != NULL)
result = p_realpath(path, NULL);
if (base == NULL || git_path_root(path) >= 0) { if (result) {
result = p_realpath(path, path_out); error = git_buf_sets(path_out, result);
git__free(result);
} else { } else {
char aux_path[GIT_PATH_MAX]; error = GIT_EOSERR;
git_path_join(aux_path, base, path);
result = p_realpath(aux_path, path_out);
} }
return result ? GIT_SUCCESS : GIT_EOSERR; return error;
} }
int git_path_prettify_dir(char *path_out, const char *path, const char *base) int git_path_prettify_dir(git_buf *path_out, const char *path, const char *base)
{ {
size_t end; int error = git_path_prettify(path_out, path, base);
if (git_path_prettify(path_out, path, base) < GIT_SUCCESS) if (error == GIT_SUCCESS)
return GIT_EOSERR; error = git_path_to_dir(path_out);
end = strlen(path_out); return error;
}
if (end && path_out[end - 1] != '/') { int git_path_to_dir(git_buf *path)
path_out[end] = '/'; {
path_out[end + 1] = '\0'; if (path->asize > 0 &&
} path->size > 0 &&
path->ptr[path->size - 1] != '/')
git_buf_putc(path, '/');
return GIT_SUCCESS; return git_buf_lasterror(path);
} }
void git_path_string_to_dir(char* path, size_t size)
{
size_t end = strlen(path);
if (end && path[end - 1] != '/' && end < size) {
path[end] = '/';
path[end + 1] = '\0';
}
}
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#define INCLUDE_path_h__ #define INCLUDE_path_h__
#include "common.h" #include "common.h"
#include "buffer.h"
/* /*
* The dirname() function shall take a pointer to a character string * The dirname() function shall take a pointer to a character string
...@@ -22,11 +23,13 @@ ...@@ -22,11 +23,13 @@
* The `git_path_dirname` implementation is thread safe. The returned * The `git_path_dirname` implementation is thread safe. The returned
* string must be manually free'd. * string must be manually free'd.
* *
* The `git_path_dirname_r` implementation expects a string allocated * The `git_path_dirname_r` implementation writes the dirname to a `git_buf`
* by the user with big enough size. * if the buffer pointer is not NULL.
* It returns an error code < 0 if there is an allocation error, otherwise
* the length of the dirname (which will be > 0).
*/ */
extern char *git_path_dirname(const char *path); extern char *git_path_dirname(const char *path);
extern int git_path_dirname_r(char *buffer, size_t bufflen, const char *path); extern int git_path_dirname_r(git_buf *buffer, const char *path);
/* /*
* This function returns the basename of the file, which is the last * This function returns the basename of the file, which is the last
...@@ -40,32 +43,22 @@ extern int git_path_dirname_r(char *buffer, size_t bufflen, const char *path); ...@@ -40,32 +43,22 @@ extern int git_path_dirname_r(char *buffer, size_t bufflen, const char *path);
* The `git_path_basename` implementation is thread safe. The returned * The `git_path_basename` implementation is thread safe. The returned
* string must be manually free'd. * string must be manually free'd.
* *
* The `git_path_basename_r` implementation expects a string allocated * The `git_path_basename_r` implementation writes the basename to a `git_buf`.
* by the user with big enough size. * It returns an error code < 0 if there is an allocation error, otherwise
* the length of the basename (which will be >= 0).
*/ */
extern char *git_path_basename(const char *path); extern char *git_path_basename(const char *path);
extern int git_path_basename_r(char *buffer, size_t bufflen, const char *path); extern int git_path_basename_r(git_buf *buffer, const char *path);
extern const char *git_path_topdir(const char *path); extern const char *git_path_topdir(const char *path);
/** extern int git_path_root(const char *path);
* Join two paths together. Takes care of properly fixing the
* middle slashes and everything
*
* The paths are joined together into buffer_out; this is expected
* to be an user allocated buffer of `GIT_PATH_MAX` size
*/
extern void git_path_join_n(char *buffer_out, int npath, ...);
GIT_INLINE(void) git_path_join(char *buffer_out, const char *path_a, const char *path_b)
{
git_path_join_n(buffer_out, 2, path_a, path_b);
}
int git_path_root(const char *path); extern int git_path_prettify(git_buf *path_out, const char *path, const char *base);
extern int git_path_prettify_dir(git_buf *path_out, const char *path, const char *base);
int git_path_prettify(char *path_out, const char *path, const char *base); extern int git_path_to_dir(git_buf *path);
int git_path_prettify_dir(char *path_out, const char *path, const char *base); extern void git_path_string_to_dir(char* path, size_t size);
#ifdef GIT_WIN32 #ifdef GIT_WIN32
GIT_INLINE(void) git_path_mkposix(char *path) GIT_INLINE(void) git_path_mkposix(char *path)
......
...@@ -268,8 +268,7 @@ void git_pkt_free(git_pkt *pkt) ...@@ -268,8 +268,7 @@ void git_pkt_free(git_pkt *pkt)
int git_pkt_buffer_flush(git_buf *buf) int git_pkt_buffer_flush(git_buf *buf)
{ {
git_buf_put(buf, pkt_flush_str, strlen(pkt_flush_str)); return git_buf_put(buf, pkt_flush_str, strlen(pkt_flush_str));
return git_buf_oom(buf) ? GIT_ENOMEM : GIT_SUCCESS;
} }
int git_pkt_send_flush(int s) int git_pkt_send_flush(int s)
...@@ -291,9 +290,7 @@ static int buffer_want_with_caps(git_remote_head *head, git_transport_caps *caps ...@@ -291,9 +290,7 @@ static int buffer_want_with_caps(git_remote_head *head, git_transport_caps *caps
git_buf_grow(buf, buf->size + len); git_buf_grow(buf, buf->size + len);
git_oid_fmt(oid, &head->oid); git_oid_fmt(oid, &head->oid);
git_buf_printf(buf, "%04xwant %s%c%s\n", len, oid, 0, capstr); return git_buf_printf(buf, "%04xwant %s%c%s\n", len, oid, 0, capstr);
return git_buf_oom(buf) ? GIT_ENOMEM : GIT_SUCCESS;
} }
static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps, GIT_SOCKET fd) static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps, GIT_SOCKET fd)
...@@ -401,8 +398,7 @@ int git_pkt_buffer_have(git_oid *oid, git_buf *buf) ...@@ -401,8 +398,7 @@ int git_pkt_buffer_have(git_oid *oid, git_buf *buf)
memset(oidhex, 0x0, sizeof(oidhex)); memset(oidhex, 0x0, sizeof(oidhex));
git_oid_fmt(oidhex, oid); git_oid_fmt(oidhex, oid);
git_buf_printf(buf, "%s%s\n", pkt_have_prefix, oidhex); return git_buf_printf(buf, "%s%s\n", pkt_have_prefix, oidhex);
return git_buf_oom(buf) ? GIT_ENOMEM : GIT_SUCCESS;
} }
int git_pkt_send_have(git_oid *oid, int fd) int git_pkt_send_have(git_oid *oid, int fd)
...@@ -416,8 +412,7 @@ int git_pkt_send_have(git_oid *oid, int fd) ...@@ -416,8 +412,7 @@ int git_pkt_send_have(git_oid *oid, int fd)
int git_pkt_buffer_done(git_buf *buf) int git_pkt_buffer_done(git_buf *buf)
{ {
git_buf_puts(buf, pkt_done_str); return git_buf_puts(buf, pkt_done_str);
return git_buf_oom(buf) ? GIT_ENOMEM : GIT_SUCCESS;
} }
int git_pkt_send_done(int fd) int git_pkt_send_done(int fd)
......
...@@ -35,7 +35,8 @@ int p_getcwd(char *buffer_out, size_t size) ...@@ -35,7 +35,8 @@ int p_getcwd(char *buffer_out, size_t size)
git_path_mkposix(buffer_out); git_path_mkposix(buffer_out);
git_path_join(buffer_out, buffer_out, ""); //Ensure the path ends with a trailing slash git_path_string_to_dir(buffer_out, size); //Ensure the path ends with a trailing slash
return GIT_SUCCESS; return GIT_SUCCESS;
} }
......
...@@ -51,7 +51,7 @@ static int reflog_write(const char *log_path, const char *oid_old, ...@@ -51,7 +51,7 @@ static int reflog_write(const char *log_path, const char *oid_old,
git_buf_puts(&log, oid_new); git_buf_puts(&log, oid_new);
git_signature__writebuf(&log, " ", committer); git_signature__writebuf(&log, " ", committer);
log.size--; /* drop LF */ git_buf_truncate(&log, log.size - 1); /* drop LF */
if (msg) { if (msg) {
if (strchr(msg, '\n')) { if (strchr(msg, '\n')) {
...@@ -65,15 +65,21 @@ static int reflog_write(const char *log_path, const char *oid_old, ...@@ -65,15 +65,21 @@ static int reflog_write(const char *log_path, const char *oid_old,
git_buf_putc(&log, '\n'); git_buf_putc(&log, '\n');
if ((error = git_buf_lasterror(&log)) < GIT_SUCCESS) {
git_buf_free(&log);
return git__rethrow(error, "Failed to write reflog. Memory allocation failure");
}
if ((error = git_filebuf_open(&fbuf, log_path, GIT_FILEBUF_APPEND)) < GIT_SUCCESS) { if ((error = git_filebuf_open(&fbuf, log_path, GIT_FILEBUF_APPEND)) < GIT_SUCCESS) {
git_buf_free(&log); git_buf_free(&log);
return git__throw(GIT_ERROR, "Failed to write reflog. Cannot open reflog `%s`", log_path); return git__rethrow(error, "Failed to write reflog. Cannot open reflog `%s`", log_path);
} }
git_filebuf_write(&fbuf, log.ptr, log.size); git_filebuf_write(&fbuf, log.ptr, log.size);
error = git_filebuf_commit(&fbuf, GIT_REFLOG_FILE_MODE); error = git_filebuf_commit(&fbuf, GIT_REFLOG_FILE_MODE);
git_buf_free(&log); git_buf_free(&log);
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write reflog"); return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write reflog");
} }
...@@ -176,7 +182,7 @@ void git_reflog_free(git_reflog *reflog) ...@@ -176,7 +182,7 @@ void git_reflog_free(git_reflog *reflog)
int git_reflog_read(git_reflog **reflog, git_reference *ref) int git_reflog_read(git_reflog **reflog, git_reference *ref)
{ {
int error; int error;
char log_path[GIT_PATH_MAX]; git_buf log_path = GIT_BUF_INIT;
git_fbuffer log_file = GIT_FBUFFER_INIT; git_fbuffer log_file = GIT_FBUFFER_INIT;
git_reflog *log = NULL; git_reflog *log = NULL;
...@@ -185,23 +191,28 @@ int git_reflog_read(git_reflog **reflog, git_reference *ref) ...@@ -185,23 +191,28 @@ int git_reflog_read(git_reflog **reflog, git_reference *ref)
if ((error = reflog_init(&log, ref)) < GIT_SUCCESS) if ((error = reflog_init(&log, ref)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to read reflog. Cannot init reflog"); return git__rethrow(error, "Failed to read reflog. Cannot init reflog");
git_path_join_n(log_path, 3, ref->owner->path_repository, GIT_REFLOG_DIR, ref->name); error = git_buf_join_n(&log_path, '/', 3,
ref->owner->path_repository, GIT_REFLOG_DIR, ref->name);
if (error < GIT_SUCCESS)
goto cleanup;
if ((error = git_futils_readbuffer(&log_file, log_path)) < GIT_SUCCESS) { if ((error = git_futils_readbuffer(&log_file, log_path.ptr)) < GIT_SUCCESS) {
git_reflog_free(log); git__rethrow(error, "Failed to read reflog. Cannot read file `%s`", log_path.ptr);
return git__rethrow(error, "Failed to read reflog. Cannot read file `%s`", log_path); goto cleanup;
} }
error = reflog_parse(log, log_file.data, log_file.len); if ((error = reflog_parse(log, log_file.data, log_file.len)) < GIT_SUCCESS)
git__rethrow(error, "Failed to read reflog");
git_futils_freebuffer(&log_file);
if (error == GIT_SUCCESS)
*reflog = log;
else else
*reflog = log;
cleanup:
if (error != GIT_SUCCESS && log != NULL)
git_reflog_free(log); git_reflog_free(log);
git_futils_freebuffer(&log_file);
git_buf_free(&log_path);
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to read reflog"); return error;
} }
int git_reflog_write(git_reference *ref, const git_oid *oid_old, int git_reflog_write(git_reference *ref, const git_oid *oid_old,
...@@ -210,7 +221,7 @@ int git_reflog_write(git_reference *ref, const git_oid *oid_old, ...@@ -210,7 +221,7 @@ int git_reflog_write(git_reference *ref, const git_oid *oid_old,
int error; int error;
char old[GIT_OID_HEXSZ+1]; char old[GIT_OID_HEXSZ+1];
char new[GIT_OID_HEXSZ+1]; char new[GIT_OID_HEXSZ+1];
char log_path[GIT_PATH_MAX]; git_buf log_path = GIT_BUF_INIT;
git_reference *r; git_reference *r;
const git_oid *oid; const git_oid *oid;
...@@ -220,65 +231,83 @@ int git_reflog_write(git_reference *ref, const git_oid *oid_old, ...@@ -220,65 +231,83 @@ int git_reflog_write(git_reference *ref, const git_oid *oid_old,
oid = git_reference_oid(r); oid = git_reference_oid(r);
if (oid == NULL) { if (oid == NULL) {
git_reference_free(r); error = git__throw(GIT_ERROR,
return git__throw(GIT_ERROR,
"Failed to write reflog. Cannot resolve reference `%s`", r->name); "Failed to write reflog. Cannot resolve reference `%s`", r->name);
git_reference_free(r);
return error;
} }
git_reference_free(r);
git_oid_to_string(new, GIT_OID_HEXSZ+1, oid); git_oid_to_string(new, GIT_OID_HEXSZ+1, oid);
git_path_join_n(log_path, 3, error = git_buf_join_n(&log_path, '/', 3,
ref->owner->path_repository, GIT_REFLOG_DIR, ref->name); ref->owner->path_repository, GIT_REFLOG_DIR, ref->name);
if (error < GIT_SUCCESS)
goto cleanup;
git_reference_free(r); if (git_futils_exists(log_path.ptr)) {
error = git_futils_mkpath2file(log_path.ptr, GIT_REFLOG_DIR_MODE);
if (git_futils_exists(log_path)) {
error = git_futils_mkpath2file(log_path, GIT_REFLOG_DIR_MODE);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, git__rethrow(error,
"Failed to write reflog. Cannot create reflog directory"); "Failed to write reflog. Cannot create reflog directory");
} else if (git_futils_isfile(log_path.ptr)) {
} else if (git_futils_isfile(log_path)) { error = git__throw(GIT_ERROR,
return git__throw(GIT_ERROR, "Failed to write reflog. `%s` is directory", log_path.ptr);
"Failed to write reflog. `%s` is directory", log_path);
} else if (oid_old == NULL) { } else if (oid_old == NULL) {
return git__throw(GIT_ERROR, error = git__throw(GIT_ERROR,
"Failed to write reflog. Old OID cannot be NULL for existing reference"); "Failed to write reflog. Old OID cannot be NULL for existing reference");
} }
if (error < GIT_SUCCESS)
goto cleanup;
if (oid_old) if (oid_old)
git_oid_to_string(old, GIT_OID_HEXSZ+1, oid_old); git_oid_to_string(old, sizeof(old), oid_old);
else else
p_snprintf(old, GIT_OID_HEXSZ+1, "%0*d", GIT_OID_HEXSZ, 0); p_snprintf(old, sizeof(old), "%0*d", GIT_OID_HEXSZ, 0);
error = reflog_write(log_path.ptr, old, new, committer, msg);
return reflog_write(log_path, old, new, committer, msg); cleanup:
git_buf_free(&log_path);
return error;
} }
int git_reflog_rename(git_reference *ref, const char *new_name) int git_reflog_rename(git_reference *ref, const char *new_name)
{ {
char old_path[GIT_PATH_MAX]; int error;
char new_path[GIT_PATH_MAX]; git_buf old_path = GIT_BUF_INIT;
git_buf new_path = GIT_BUF_INIT;
if (git_buf_join_n(&old_path, '/', 3, ref->owner->path_repository,
GIT_REFLOG_DIR, ref->name) &&
git_buf_join_n(&new_path, '/', 3, ref->owner->path_repository,
GIT_REFLOG_DIR, new_name))
error = p_rename(git_buf_cstr(&old_path), git_buf_cstr(&new_path));
else
error = GIT_ENOMEM;
git_path_join_n(old_path, 3, ref->owner->path_repository, git_buf_free(&old_path);
GIT_REFLOG_DIR, ref->name); git_buf_free(&new_path);
git_path_join_n(new_path, 3, ref->owner->path_repository,
GIT_REFLOG_DIR, new_name);
return p_rename(old_path, new_path); return error;
} }
int git_reflog_delete(git_reference *ref) int git_reflog_delete(git_reference *ref)
{ {
char path[GIT_PATH_MAX]; int error = GIT_SUCCESS;
git_buf path = GIT_BUF_INIT;
error = git_buf_join_n(&path, '/', 3,
ref->owner->path_repository, GIT_REFLOG_DIR, ref->name);
git_path_join_n(path, 3, ref->owner->path_repository, if (error == GIT_SUCCESS && git_futils_exists(path.ptr) == 0)
GIT_REFLOG_DIR, ref->name); error = p_unlink(path.ptr);
if (git_futils_exists(path)) git_buf_free(&path);
return GIT_SUCCESS;
return p_unlink(path); return error;
} }
unsigned int git_reflog_entrycount(git_reflog *reflog) unsigned int git_reflog_entrycount(git_reflog *reflog)
......
...@@ -88,9 +88,12 @@ void git_reference_free(git_reference *reference) ...@@ -88,9 +88,12 @@ void git_reference_free(git_reference *reference)
return; return;
git__free(reference->name); git__free(reference->name);
reference->name = NULL;
if (reference->flags & GIT_REF_SYMBOLIC) if (reference->flags & GIT_REF_SYMBOLIC) {
git__free(reference->target.symbolic); git__free(reference->target.symbolic);
reference->target.symbolic = NULL;
}
git__free(reference); git__free(reference);
} }
...@@ -123,14 +126,18 @@ static int reference_create( ...@@ -123,14 +126,18 @@ static int reference_create(
static int reference_read(git_fbuffer *file_content, time_t *mtime, const char *repo_path, const char *ref_name, int *updated) static int reference_read(git_fbuffer *file_content, time_t *mtime, const char *repo_path, const char *ref_name, int *updated)
{ {
char path[GIT_PATH_MAX]; git_buf path = GIT_BUF_INIT;
int error = GIT_SUCCESS;
assert(file_content && repo_path && ref_name); assert(file_content && repo_path && ref_name);
/* Determine the full path of the file */ /* Determine the full path of the file */
git_path_join(path, repo_path, ref_name); if ((error = git_buf_joinpath(&path, repo_path, ref_name)) == GIT_SUCCESS)
error = git_futils_readbuffer_updated(file_content, path.ptr, mtime, updated);
git_buf_free(&path);
return git_futils_readbuffer_updated(file_content, path, mtime, updated); return error;
} }
static int loose_parse_symbolic(git_reference *ref, git_fbuffer *file_content) static int loose_parse_symbolic(git_reference *ref, git_fbuffer *file_content)
...@@ -195,14 +202,14 @@ static int loose_parse_oid(git_oid *oid, git_fbuffer *file_content) ...@@ -195,14 +202,14 @@ static int loose_parse_oid(git_oid *oid, git_fbuffer *file_content)
return GIT_SUCCESS; return GIT_SUCCESS;
} }
static git_rtype loose_guess_rtype(const char *full_path) static git_rtype loose_guess_rtype(const git_buf *full_path)
{ {
git_fbuffer ref_file = GIT_FBUFFER_INIT; git_fbuffer ref_file = GIT_FBUFFER_INIT;
git_rtype type; git_rtype type;
type = GIT_REF_INVALID; type = GIT_REF_INVALID;
if (git_futils_readbuffer(&ref_file, full_path) == GIT_SUCCESS) { if (git_futils_readbuffer(&ref_file, full_path->ptr) == GIT_SUCCESS) {
if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0) if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0)
type = GIT_REF_SYMBOLIC; type = GIT_REF_SYMBOLIC;
else else
...@@ -287,14 +294,17 @@ cleanup: ...@@ -287,14 +294,17 @@ cleanup:
static int loose_write(git_reference *ref) static int loose_write(git_reference *ref)
{ {
git_filebuf file = GIT_FILEBUF_INIT; git_filebuf file = GIT_FILEBUF_INIT;
char ref_path[GIT_PATH_MAX]; git_buf ref_path = GIT_BUF_INIT;
int error; int error;
struct stat st; struct stat st;
git_path_join(ref_path, ref->owner->path_repository, ref->name); error = git_buf_joinpath(&ref_path, ref->owner->path_repository, ref->name);
if (error < GIT_SUCCESS)
goto unlock;
if ((error = git_filebuf_open(&file, ref_path, GIT_FILEBUF_FORCE)) < GIT_SUCCESS) error = git_filebuf_open(&file, ref_path.ptr, GIT_FILEBUF_FORCE);
return git__rethrow(error, "Failed to write loose reference"); if (error < GIT_SUCCESS)
goto unlock;
if (ref->flags & GIT_REF_OID) { if (ref->flags & GIT_REF_OID) {
char oid[GIT_OID_HEXSZ + 1]; char oid[GIT_OID_HEXSZ + 1];
...@@ -314,12 +324,15 @@ static int loose_write(git_reference *ref) ...@@ -314,12 +324,15 @@ static int loose_write(git_reference *ref)
goto unlock; goto unlock;
} }
if (p_stat(ref_path, &st) == GIT_SUCCESS) if (p_stat(ref_path.ptr, &st) == GIT_SUCCESS)
ref->mtime = st.st_mtime; ref->mtime = st.st_mtime;
git_buf_free(&ref_path);
return git_filebuf_commit(&file, GIT_REFS_FILE_MODE); return git_filebuf_commit(&file, GIT_REFS_FILE_MODE);
unlock: unlock:
git_buf_free(&ref_path);
git_filebuf_cleanup(&file); git_filebuf_cleanup(&file);
return git__rethrow(error, "Failed to write loose reference"); return git__rethrow(error, "Failed to write loose reference");
} }
...@@ -518,14 +531,13 @@ struct dirent_list_data { ...@@ -518,14 +531,13 @@ struct dirent_list_data {
void *callback_payload; void *callback_payload;
}; };
static int _dirent_loose_listall(void *_data, char *full_path) static int _dirent_loose_listall(void *_data, git_buf *full_path)
{ {
struct dirent_list_data *data = (struct dirent_list_data *)_data; struct dirent_list_data *data = (struct dirent_list_data *)_data;
char *file_path = full_path + data->repo_path_len; const char *file_path = full_path->ptr + data->repo_path_len;
if (git_futils_isdir(full_path) == GIT_SUCCESS) if (git_futils_isdir(full_path->ptr) == GIT_SUCCESS)
return git_futils_direach(full_path, GIT_PATH_MAX, return git_futils_direach(full_path, _dirent_loose_listall, _data);
_dirent_loose_listall, _data);
/* do not add twice a reference that exists already in the packfile */ /* do not add twice a reference that exists already in the packfile */
if ((data->list_flags & GIT_REF_PACKED) != 0 && if ((data->list_flags & GIT_REF_PACKED) != 0 &&
...@@ -540,20 +552,18 @@ static int _dirent_loose_listall(void *_data, char *full_path) ...@@ -540,20 +552,18 @@ static int _dirent_loose_listall(void *_data, char *full_path)
return data->callback(file_path, data->callback_payload); return data->callback(file_path, data->callback_payload);
} }
static int _dirent_loose_load(void *data, char *full_path) static int _dirent_loose_load(void *data, git_buf *full_path)
{ {
git_repository *repository = (git_repository *)data; git_repository *repository = (git_repository *)data;
void *old_ref = NULL; void *old_ref = NULL;
struct packref *ref; struct packref *ref;
char *file_path; const char *file_path;
int error; int error;
if (git_futils_isdir(full_path) == GIT_SUCCESS) if (git_futils_isdir(full_path->ptr) == GIT_SUCCESS)
return git_futils_direach( return git_futils_direach(full_path, _dirent_loose_load, repository);
full_path, GIT_PATH_MAX,
_dirent_loose_load, repository);
file_path = full_path + strlen(repository->path_repository); file_path = full_path->ptr + strlen(repository->path_repository);
error = loose_lookup_to_packfile(&ref, repository, file_path); error = loose_lookup_to_packfile(&ref, repository, file_path);
if (error == GIT_SUCCESS) { if (error == GIT_SUCCESS) {
...@@ -582,21 +592,24 @@ static int _dirent_loose_load(void *data, char *full_path) ...@@ -582,21 +592,24 @@ static int _dirent_loose_load(void *data, char *full_path)
*/ */
static int packed_loadloose(git_repository *repository) static int packed_loadloose(git_repository *repository)
{ {
char refs_path[GIT_PATH_MAX]; int error = GIT_SUCCESS;
git_buf refs_path = GIT_BUF_INIT;
/* the packfile must have been previously loaded! */ /* the packfile must have been previously loaded! */
assert(repository->references.packfile); assert(repository->references.packfile);
git_path_join(refs_path, repository->path_repository, GIT_REFS_DIR); if ((error = git_buf_joinpath(&refs_path,
repository->path_repository, GIT_REFS_DIR)) < GIT_SUCCESS)
return error;
/* /*
* Load all the loose files from disk into the Packfile table. * Load all the loose files from disk into the Packfile table.
* This will overwrite any old packed entries with their * This will overwrite any old packed entries with their
* updated loose versions * updated loose versions
*/ */
return git_futils_direach( error = git_futils_direach(&refs_path, _dirent_loose_load, repository);
refs_path, GIT_PATH_MAX, git_buf_free(&refs_path);
_dirent_loose_load, repository); return error;
} }
/* /*
...@@ -704,20 +717,26 @@ static int packed_find_peel(git_repository *repo, struct packref *ref) ...@@ -704,20 +717,26 @@ static int packed_find_peel(git_repository *repo, struct packref *ref)
static int packed_remove_loose(git_repository *repo, git_vector *packing_list) static int packed_remove_loose(git_repository *repo, git_vector *packing_list)
{ {
unsigned int i; unsigned int i;
char full_path[GIT_PATH_MAX]; git_buf full_path = GIT_BUF_INIT;
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
for (i = 0; i < packing_list->length; ++i) { for (i = 0; i < packing_list->length; ++i) {
struct packref *ref = git_vector_get(packing_list, i); struct packref *ref = git_vector_get(packing_list, i);
int an_error;
if ((ref->flags & GIT_PACKREF_WAS_LOOSE) == 0) if ((ref->flags & GIT_PACKREF_WAS_LOOSE) == 0)
continue; continue;
git_path_join(full_path, repo->path_repository, ref->name); an_error = git_buf_joinpath(&full_path, repo->path_repository, ref->name);
if (an_error == GIT_SUCCESS &&
git_futils_exists(full_path.ptr) == GIT_SUCCESS &&
p_unlink(full_path.ptr) < GIT_SUCCESS)
an_error = GIT_EOSERR;
if (git_futils_exists(full_path) == GIT_SUCCESS && /* keep the error if we haven't seen one yet */
p_unlink(full_path) < GIT_SUCCESS) if (error > an_error)
error = GIT_EOSERR; error = an_error;
/* /*
* if we fail to remove a single file, this is *not* good, * if we fail to remove a single file, this is *not* good,
...@@ -727,6 +746,8 @@ static int packed_remove_loose(git_repository *repo, git_vector *packing_list) ...@@ -727,6 +746,8 @@ static int packed_remove_loose(git_repository *repo, git_vector *packing_list)
*/ */
} }
git_buf_free(&full_path);
return error == GIT_SUCCESS ? return error == GIT_SUCCESS ?
GIT_SUCCESS : GIT_SUCCESS :
git__rethrow(error, "Failed to remove loose packed reference"); git__rethrow(error, "Failed to remove loose packed reference");
...@@ -747,9 +768,9 @@ static int packed_write(git_repository *repo) ...@@ -747,9 +768,9 @@ static int packed_write(git_repository *repo)
{ {
git_filebuf pack_file = GIT_FILEBUF_INIT; git_filebuf pack_file = GIT_FILEBUF_INIT;
int error; int error;
const char *errmsg = "Failed to write packed references file";
unsigned int i; unsigned int i;
char pack_file_path[GIT_PATH_MAX]; git_buf pack_file_path = GIT_BUF_INIT;
git_vector packing_list; git_vector packing_list;
size_t total_refs; size_t total_refs;
...@@ -758,7 +779,7 @@ static int packed_write(git_repository *repo) ...@@ -758,7 +779,7 @@ static int packed_write(git_repository *repo)
total_refs = repo->references.packfile->key_count; total_refs = repo->references.packfile->key_count;
if ((error = if ((error =
git_vector_init(&packing_list, total_refs, packed_sort)) < GIT_SUCCESS) git_vector_init(&packing_list, total_refs, packed_sort)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to init packed refernces list"); return git__rethrow(error, "Failed to init packed references list");
/* Load all the packfile into a vector */ /* Load all the packfile into a vector */
{ {
...@@ -775,16 +796,23 @@ static int packed_write(git_repository *repo) ...@@ -775,16 +796,23 @@ static int packed_write(git_repository *repo)
git_vector_sort(&packing_list); git_vector_sort(&packing_list);
/* Now we can open the file! */ /* Now we can open the file! */
git_path_join(pack_file_path, repo->path_repository, GIT_PACKEDREFS_FILE); error = git_buf_joinpath(&pack_file_path, repo->path_repository, GIT_PACKEDREFS_FILE);
if ((error = git_filebuf_open(&pack_file, pack_file_path, 0)) < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to write open packed references file"); goto cleanup;
if ((error = git_filebuf_open(&pack_file, pack_file_path.ptr, 0)) < GIT_SUCCESS) {
errmsg = "Failed to open packed references file";
goto cleanup;
}
/* Packfiles have a header... apparently /* Packfiles have a header... apparently
* This is in fact not required, but we might as well print it * This is in fact not required, but we might as well print it
* just for kicks */ * just for kicks */
if ((error = if ((error =
git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < GIT_SUCCESS) git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < GIT_SUCCESS) {
return git__rethrow(error, "Failed to write packed references file header"); errmsg = "Failed to write packed references file header";
goto cleanup;
}
for (i = 0; i < packing_list.length; ++i) { for (i = 0; i < packing_list.length; ++i) {
struct packref *ref = (struct packref *)git_vector_get(&packing_list, i); struct packref *ref = (struct packref *)git_vector_get(&packing_list, i);
...@@ -812,17 +840,19 @@ cleanup: ...@@ -812,17 +840,19 @@ cleanup:
error = packed_remove_loose(repo, &packing_list); error = packed_remove_loose(repo, &packing_list);
if (p_stat(pack_file_path, &st) == GIT_SUCCESS) if (p_stat(pack_file_path.ptr, &st) == GIT_SUCCESS)
repo->references.packfile_time = st.st_mtime; repo->references.packfile_time = st.st_mtime;
} }
} }
else git_filebuf_cleanup(&pack_file); else git_filebuf_cleanup(&pack_file);
git_vector_free(&packing_list); git_vector_free(&packing_list);
git_buf_free(&pack_file_path);
return error == GIT_SUCCESS ? if (error < GIT_SUCCESS)
GIT_SUCCESS : git__rethrow(error, "%s", errmsg);
git__rethrow(error, "Failed to write packed references file");
return error;
} }
static int _reference_available_cb(const char *ref, void *data) static int _reference_available_cb(const char *ref, void *data)
...@@ -873,21 +903,25 @@ static int reference_available( ...@@ -873,21 +903,25 @@ static int reference_available(
static int reference_exists(int *exists, git_repository *repo, const char *ref_name) static int reference_exists(int *exists, git_repository *repo, const char *ref_name)
{ {
int error; int error;
char ref_path[GIT_PATH_MAX]; git_buf ref_path = GIT_BUF_INIT;
error = packed_load(repo); error = packed_load(repo);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, "Cannot resolve if a reference exists"); return git__rethrow(error, "Cannot resolve if a reference exists");
git_path_join(ref_path, repo->path_repository, ref_name); error = git_buf_joinpath(&ref_path, repo->path_repository, ref_name);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Cannot resolve if a reference exists");
if (git_futils_isfile(ref_path) == GIT_SUCCESS || if (git_futils_isfile(ref_path.ptr) == GIT_SUCCESS ||
git_hashtable_lookup(repo->references.packfile, ref_path) != NULL) { git_hashtable_lookup(repo->references.packfile, ref_path.ptr) != NULL) {
*exists = 1; *exists = 1;
} else { } else {
*exists = 0; *exists = 0;
} }
git_buf_free(&ref_path);
return GIT_SUCCESS; return GIT_SUCCESS;
} }
...@@ -972,12 +1006,15 @@ static int reference_delete(git_reference *ref) ...@@ -972,12 +1006,15 @@ static int reference_delete(git_reference *ref)
/* If the reference is loose, we can just remove the reference /* If the reference is loose, we can just remove the reference
* from the filesystem */ * from the filesystem */
} else { } else {
char full_path[GIT_PATH_MAX];
git_reference *ref_in_pack; git_reference *ref_in_pack;
git_buf full_path = GIT_BUF_INIT;
git_path_join(full_path, ref->owner->path_repository, ref->name); error = git_buf_joinpath(&full_path, ref->owner->path_repository, ref->name);
if (error < GIT_SUCCESS)
goto cleanup;
error = p_unlink(full_path); error = p_unlink(full_path.ptr);
git_buf_free(&full_path); /* done with path at this point */
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
...@@ -1261,8 +1298,7 @@ int git_reference_set_target(git_reference *ref, const char *target) ...@@ -1261,8 +1298,7 @@ int git_reference_set_target(git_reference *ref, const char *target)
int git_reference_rename(git_reference *ref, const char *new_name, int force) int git_reference_rename(git_reference *ref, const char *new_name, int force)
{ {
int error; int error;
git_buf aux_path = GIT_BUF_INIT;
char aux_path[GIT_PATH_MAX];
char normalized[GIT_REFNAME_MAX]; char normalized[GIT_REFNAME_MAX];
const char *head_target = NULL; const char *head_target = NULL;
...@@ -1309,6 +1345,13 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force) ...@@ -1309,6 +1345,13 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
return git__rethrow(error, return git__rethrow(error,
"Failed to rename reference. Reference already exists"); "Failed to rename reference. Reference already exists");
/* Initialize path now so we won't get an allocation failure once
* we actually start removing things.
*/
error = git_buf_joinpath(&aux_path, ref->owner->path_repository, new_name);
if (error < GIT_SUCCESS)
goto cleanup;
/* /*
* Now delete the old ref and remove an possibly existing directory * Now delete the old ref and remove an possibly existing directory
* named `new_name`. Note that using the internal `reference_delete` * named `new_name`. Note that using the internal `reference_delete`
...@@ -1318,10 +1361,9 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force) ...@@ -1318,10 +1361,9 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
if ((error = reference_delete(ref)) < GIT_SUCCESS) if ((error = reference_delete(ref)) < GIT_SUCCESS)
goto cleanup; goto cleanup;
git_path_join(aux_path, ref->owner->path_repository, new_name); if (git_futils_exists(aux_path.ptr) == GIT_SUCCESS) {
if (git_futils_exists(aux_path) == GIT_SUCCESS) { if (git_futils_isdir(aux_path.ptr) == GIT_SUCCESS) {
if (git_futils_isdir(aux_path) == GIT_SUCCESS) { if ((error = git_futils_rmdir_r(aux_path.ptr, 0)) < GIT_SUCCESS)
if ((error = git_futils_rmdir_r(aux_path, 0)) < GIT_SUCCESS)
goto rollback; goto rollback;
} else goto rollback; } else goto rollback;
} }
...@@ -1360,9 +1402,12 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force) ...@@ -1360,9 +1402,12 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
/* /*
* Rename the reflog file. * Rename the reflog file.
*/ */
git_path_join_n(aux_path, 3, ref->owner->path_repository, error = git_buf_join_n(&aux_path, '/', 3, ref->owner->path_repository,
GIT_REFLOG_DIR, ref->name); GIT_REFLOG_DIR, ref->name);
if (git_futils_exists(aux_path) == GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup;
if (git_futils_exists(aux_path.ptr) == GIT_SUCCESS)
error = git_reflog_rename(ref, new_name); error = git_reflog_rename(ref, new_name);
/* /*
...@@ -1377,6 +1422,7 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force) ...@@ -1377,6 +1422,7 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
cleanup: cleanup:
/* We no longer need the newly created reference nor the head */ /* We no longer need the newly created reference nor the head */
git_reference_free(head); git_reference_free(head);
git_buf_free(&aux_path);
return error == GIT_SUCCESS ? return error == GIT_SUCCESS ?
GIT_SUCCESS : GIT_SUCCESS :
git__rethrow(error, "Failed to rename reference"); git__rethrow(error, "Failed to rename reference");
...@@ -1395,6 +1441,8 @@ rollback: ...@@ -1395,6 +1441,8 @@ rollback:
/* The reference is no longer packed */ /* The reference is no longer packed */
ref->flags &= ~GIT_REF_PACKED; ref->flags &= ~GIT_REF_PACKED;
git_buf_free(&aux_path);
return error == GIT_SUCCESS ? return error == GIT_SUCCESS ?
git__rethrow(GIT_ERROR, "Failed to rename reference. Did rollback") : git__rethrow(GIT_ERROR, "Failed to rename reference. Did rollback") :
git__rethrow(error, "Failed to rename reference. Failed to rollback"); git__rethrow(error, "Failed to rename reference. Failed to rollback");
...@@ -1467,7 +1515,7 @@ int git_reference_foreach( ...@@ -1467,7 +1515,7 @@ int git_reference_foreach(
{ {
int error; int error;
struct dirent_list_data data; struct dirent_list_data data;
char refs_path[GIT_PATH_MAX]; git_buf refs_path = GIT_BUF_INIT;
/* list all the packed references first */ /* list all the packed references first */
if (list_flags & GIT_REF_PACKED) { if (list_flags & GIT_REF_PACKED) {
...@@ -1493,8 +1541,15 @@ int git_reference_foreach( ...@@ -1493,8 +1541,15 @@ int git_reference_foreach(
data.callback = callback; data.callback = callback;
data.callback_payload = payload; data.callback_payload = payload;
git_path_join(refs_path, repo->path_repository, GIT_REFS_DIR); if ((error = git_buf_joinpath(&refs_path,
return git_futils_direach(refs_path, GIT_PATH_MAX, _dirent_loose_listall, &data); repo->path_repository, GIT_REFS_DIR)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to alloc space for references");
error = git_futils_direach(&refs_path, _dirent_loose_listall, &data);
git_buf_free(&refs_path);
return error;
} }
static int cb__reflist_add(const char *ref, void *data) static int cb__reflist_add(const char *ref, void *data)
......
...@@ -93,3 +93,21 @@ int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, con ...@@ -93,3 +93,21 @@ int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, con
return GIT_SUCCESS; return GIT_SUCCESS;
} }
int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *name)
{
if (git_buf_sets(out, spec->dst) < GIT_SUCCESS)
return git_buf_lasterror(out);
/*
* No '*' at the end means that it's mapped to one specific local
* branch, so no actual transformation is needed.
*/
if (out->size > 0 && out->ptr[out->size - 1] != '*')
return GIT_SUCCESS;
git_buf_truncate(out, out->size - 1); /* remove trailing '*' */
git_buf_puts(out, name);
return git_buf_lasterror(out);
}
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#define INCLUDE_refspec_h__ #define INCLUDE_refspec_h__
#include "git2/refspec.h" #include "git2/refspec.h"
#include "buffer.h"
struct git_refspec { struct git_refspec {
struct git_refspec *next; struct git_refspec *next;
...@@ -20,4 +21,15 @@ struct git_refspec { ...@@ -20,4 +21,15 @@ struct git_refspec {
int git_refspec_parse(struct git_refspec *refspec, const char *str); int git_refspec_parse(struct git_refspec *refspec, const char *str);
/**
* Transform a reference to its target following the refspec's rules,
* and writes the results into a git_buf.
*
* @param out where to store the target name
* @param spec the refspec
* @param name the name of the reference to transform
* @return GIT_SUCCESS or error if buffer allocation fails
*/
int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *name);
#endif #endif
...@@ -263,7 +263,7 @@ int git_remote_update_tips(git_remote *remote) ...@@ -263,7 +263,7 @@ int git_remote_update_tips(git_remote *remote)
{ {
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
unsigned int i = 0; unsigned int i = 0;
char refname[GIT_PATH_MAX]; git_buf refname = GIT_BUF_INIT;
git_vector *refs = &remote->refs; git_vector *refs = &remote->refs;
git_remote_head *head; git_remote_head *head;
git_reference *ref; git_reference *ref;
...@@ -271,8 +271,6 @@ int git_remote_update_tips(git_remote *remote) ...@@ -271,8 +271,6 @@ int git_remote_update_tips(git_remote *remote)
assert(remote); assert(remote);
memset(refname, 0x0, sizeof(refname));
if (refs->length == 0) if (refs->length == 0)
return GIT_SUCCESS; return GIT_SUCCESS;
...@@ -289,18 +287,20 @@ int git_remote_update_tips(git_remote *remote) ...@@ -289,18 +287,20 @@ int git_remote_update_tips(git_remote *remote)
for (; i < refs->length; ++i) { for (; i < refs->length; ++i) {
head = refs->contents[i]; head = refs->contents[i];
error = git_refspec_transform(refname, sizeof(refname), spec, head->name); error = git_refspec_transform_r(&refname, spec, head->name);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; break;
error = git_reference_create_oid(&ref, remote->repo, refname, &head->oid, 1); error = git_reference_create_oid(&ref, remote->repo, refname.ptr, &head->oid, 1);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; break;
git_reference_free(ref); git_reference_free(ref);
} }
return GIT_SUCCESS; git_buf_free(&refname);
return error;
} }
int git_remote_connected(git_remote *remote) int git_remote_connected(git_remote *remote)
......
...@@ -75,21 +75,17 @@ void git_repository_free(git_repository *repo) ...@@ -75,21 +75,17 @@ void git_repository_free(git_repository *repo)
* *
* Open a repository object from its path * Open a repository object from its path
*/ */
static int quickcheck_repository_dir(const char *repository_path) static int quickcheck_repository_dir(git_buf *repository_path)
{ {
char path_aux[GIT_PATH_MAX]; /* Check OBJECTS_DIR first, since it will generate the longest path name */
if (git_futils_contains_dir(repository_path, GIT_OBJECTS_DIR, 0) < 0)
/* Ensure HEAD file exists */
git_path_join(path_aux, repository_path, GIT_HEAD_FILE);
if (git_futils_isfile(path_aux) < 0)
return GIT_ERROR; return GIT_ERROR;
git_path_join(path_aux, repository_path, GIT_OBJECTS_DIR); /* Ensure HEAD file exists */
if (git_futils_isdir(path_aux) < 0) if (git_futils_contains_file(repository_path, GIT_HEAD_FILE, 0) < 0)
return GIT_ERROR; return GIT_ERROR;
git_path_join(path_aux, repository_path, GIT_REFS_DIR); if (git_futils_contains_dir(repository_path, GIT_REFS_DIR, 0) < 0)
if (git_futils_isdir(path_aux) < 0)
return GIT_ERROR; return GIT_ERROR;
return GIT_SUCCESS; return GIT_SUCCESS;
...@@ -135,74 +131,74 @@ static int load_config_data(git_repository *repo) ...@@ -135,74 +131,74 @@ static int load_config_data(git_repository *repo)
static int load_workdir(git_repository *repo) static int load_workdir(git_repository *repo)
{ {
if (!repo->is_bare) { int error;
char workdir_buf[GIT_PATH_MAX]; git_buf workdir_buf = GIT_BUF_INIT;
if (git_path_dirname_r(workdir_buf, sizeof(workdir_buf), repo->path_repository) < 0) if (repo->is_bare)
return git__throw(GIT_EOSERR, return GIT_SUCCESS;
"Failed to resolved working directory");
git_path_join(workdir_buf, workdir_buf, ""); git_path_dirname_r(&workdir_buf, repo->path_repository);
git_path_to_dir(&workdir_buf);
repo->workdir = git__strdup(workdir_buf); if ((error = git_buf_lasterror(&workdir_buf)) == GIT_SUCCESS)
if (repo->workdir == NULL) repo->workdir = git_buf_detach(&workdir_buf);
return GIT_ENOMEM;
}
return GIT_SUCCESS; git_buf_free(&workdir_buf);
return error;
} }
int git_repository_open(git_repository **repo_out, const char *path) int git_repository_open(git_repository **repo_out, const char *path)
{ {
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
char path_buf[GIT_PATH_MAX]; git_buf path_buf = GIT_BUF_INIT;
size_t path_len;
git_repository *repo = NULL; git_repository *repo = NULL;
error = git_path_prettify_dir(path_buf, path, NULL); error = git_path_prettify_dir(&path_buf, path, NULL);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to open repository"); goto cleanup;
path_len = strlen(path_buf);
/** /**
* Check if the path we've been given is actually the path * Check if the path we've been given is actually the path
* of the working dir, by testing if it contains a `.git` * of the working dir, by testing if it contains a `.git`
* folder inside of it. * folder inside of it.
*/ */
git_path_join(path_buf, path_buf, DOT_GIT); git_futils_contains_dir(&path_buf, DOT_GIT, 1); /* append on success */
if (git_futils_isdir(path_buf) < GIT_SUCCESS) { /* ignore error, since it just means `path/.git` doesn't exist */
path_buf[path_len] = 0;
}
if (quickcheck_repository_dir(path_buf) < GIT_SUCCESS) if (quickcheck_repository_dir(&path_buf) < GIT_SUCCESS) {
return git__throw(GIT_ENOTAREPO, error = git__throw(GIT_ENOTAREPO,
"The given path is not a valid Git repository"); "The given path is not a valid Git repository");
goto cleanup;
}
repo = repository_alloc(); repo = repository_alloc();
if (repo == NULL) if (repo == NULL) {
return GIT_ENOMEM; error = GIT_ENOMEM;
goto cleanup;
}
repo->path_repository = git__strdup(path_buf); repo->path_repository = git_buf_detach(&path_buf);
if (repo->path_repository == NULL) { if (repo->path_repository == NULL) {
git_repository_free(repo); error = GIT_ENOMEM;
return GIT_ENOMEM; goto cleanup;
} }
error = load_config_data(repo); error = load_config_data(repo);
if (error < GIT_SUCCESS) { if (error < GIT_SUCCESS)
git_repository_free(repo); goto cleanup;
return error;
}
error = load_workdir(repo); error = load_workdir(repo);
if (error < GIT_SUCCESS) { if (error < GIT_SUCCESS)
git_repository_free(repo); goto cleanup;
return error;
}
*repo_out = repo; *repo_out = repo;
return GIT_SUCCESS; return GIT_SUCCESS;
cleanup:
git_repository_free(repo);
git_buf_free(&path_buf);
return error;
} }
static int load_config( static int load_config(
...@@ -211,7 +207,7 @@ static int load_config( ...@@ -211,7 +207,7 @@ static int load_config(
const char *global_config_path, const char *global_config_path,
const char *system_config_path) const char *system_config_path)
{ {
char config_path[GIT_PATH_MAX]; git_buf config_path = GIT_BUF_INIT;
int error; int error;
git_config *cfg = NULL; git_config *cfg = NULL;
...@@ -221,8 +217,13 @@ static int load_config( ...@@ -221,8 +217,13 @@ static int load_config(
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; return error;
git_path_join(config_path, repo->path_repository, GIT_CONFIG_FILENAME_INREPO); error = git_buf_joinpath(&config_path, repo->path_repository,
error = git_config_add_file_ondisk(cfg, config_path, 3); GIT_CONFIG_FILENAME_INREPO);
if (error < GIT_SUCCESS)
goto cleanup;
error = git_config_add_file_ondisk(cfg, config_path.ptr, 3);
git_buf_free(&config_path); /* done with config_path now */
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
...@@ -251,19 +252,22 @@ int git_repository_config__weakptr(git_config **out, git_repository *repo) ...@@ -251,19 +252,22 @@ int git_repository_config__weakptr(git_config **out, git_repository *repo)
{ {
if (repo->_config == NULL) { if (repo->_config == NULL) {
int error; int error;
git_buf global_buf = GIT_BUF_INIT, system_buf = GIT_BUF_INIT;
char buf_global[GIT_PATH_MAX], buf_system[GIT_PATH_MAX];
const char *global_config_path = NULL; const char *global_config_path = NULL;
const char *system_config_path = NULL; const char *system_config_path = NULL;
if (git_config_find_global(buf_global) == GIT_SUCCESS) if (git_config_find_global_r(&global_buf) == GIT_SUCCESS)
global_config_path = buf_global; global_config_path = global_buf.ptr;
if (git_config_find_system(buf_system) == GIT_SUCCESS) if (git_config_find_system_r(&system_buf) == GIT_SUCCESS)
system_config_path = buf_system; system_config_path = system_buf.ptr;
error = load_config(&repo->_config, repo, global_config_path, system_config_path); error = load_config(&repo->_config, repo, global_config_path, system_config_path);
git_buf_free(&global_buf);
git_buf_free(&system_buf);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; return error;
...@@ -301,11 +305,14 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo) ...@@ -301,11 +305,14 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
if (repo->_odb == NULL) { if (repo->_odb == NULL) {
int error; int error;
char odb_path[GIT_PATH_MAX]; git_buf odb_path = GIT_BUF_INIT;
git_path_join(odb_path, repo->path_repository, GIT_OBJECTS_DIR); error = git_buf_joinpath(&odb_path, repo->path_repository, GIT_OBJECTS_DIR);
if (error < GIT_SUCCESS)
return error;
error = git_odb_open(&repo->_odb, odb_path); error = git_odb_open(&repo->_odb, odb_path.ptr);
git_buf_free(&odb_path); /* done with path */
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; return error;
...@@ -346,11 +353,14 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo) ...@@ -346,11 +353,14 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo)
if (repo->_index == NULL) { if (repo->_index == NULL) {
int error; int error;
char index_path[GIT_PATH_MAX]; git_buf index_path = GIT_BUF_INIT;
git_path_join(index_path, repo->path_repository, GIT_INDEX_FILE); error = git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE);
if (error < GIT_SUCCESS)
return error;
error = git_index_open(&repo->_index, index_path); error = git_index_open(&repo->_index, index_path.ptr);
git_buf_free(&index_path); /* done with path */
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; return error;
...@@ -397,7 +407,17 @@ static int retrieve_device(dev_t *device_out, const char *path) ...@@ -397,7 +407,17 @@ static int retrieve_device(dev_t *device_out, const char *path)
return GIT_SUCCESS; return GIT_SUCCESS;
} }
static int retrieve_ceiling_directories_offset(const char *path, const char *ceiling_directories) /*
* This function returns furthest offset into path where a ceiling dir
* is found, so we can stop processing the path at that point.
*
* Note: converting this to use git_bufs instead of GIT_PATH_MAX buffers on
* the stack could remove directories name limits, but at the cost of doing
* repeated malloc/frees inside the loop below, so let's not do it now.
*/
static int retrieve_ceiling_directories_offset(
const char *path,
const char *ceiling_directories)
{ {
char buf[GIT_PATH_MAX + 1]; char buf[GIT_PATH_MAX + 1];
char buf2[GIT_PATH_MAX + 1]; char buf2[GIT_PATH_MAX + 1];
...@@ -416,7 +436,7 @@ static int retrieve_ceiling_directories_offset(const char *path, const char *cei ...@@ -416,7 +436,7 @@ static int retrieve_ceiling_directories_offset(const char *path, const char *cei
for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++); for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++);
len = sep - ceil; len = sep - ceil;
if (len == 0 || len > GIT_PATH_MAX || git_path_root(ceil) == -1) if (len == 0 || len >= (int)sizeof(buf) || git_path_root(ceil) == -1)
continue; continue;
strncpy(buf, ceil, len); strncpy(buf, ceil, len);
...@@ -440,45 +460,43 @@ static int retrieve_ceiling_directories_offset(const char *path, const char *cei ...@@ -440,45 +460,43 @@ static int retrieve_ceiling_directories_offset(const char *path, const char *cei
return max_len <= min_len ? min_len : max_len; return max_len <= min_len ? min_len : max_len;
} }
static int read_gitfile(char *path_out, const char *file_path, const char *base_path) /*
* Read the contents of `file_path` and set `path_out` to the repo dir that
* it points to. Before calling, set `path_out` to the base directory that
* should be used if the contents of `file_path` are a relative path.
*/
static int read_gitfile(git_buf *path_out, const char *file_path, const char *base_path)
{ {
git_fbuffer file; git_fbuffer file;
int error; int error;
size_t end_offset;
char *data;
assert(path_out && file_path && base_path); assert(path_out && file_path);
error = git_futils_readbuffer(&file, file_path); error = git_futils_readbuffer(&file, file_path);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; return error;
data = (char*)(file.data); if (git__prefixcmp((char *)file.data, GIT_FILE_CONTENT_PREFIX)) {
if (git__prefixcmp(data, GIT_FILE_CONTENT_PREFIX)) {
git_futils_freebuffer(&file); git_futils_freebuffer(&file);
return git__throw(GIT_ENOTFOUND, "Invalid gitfile format `%s`", file_path); return git__throw(GIT_ENOTFOUND, "Invalid gitfile format `%s`", file_path);
} }
end_offset = strlen(data) - 1; git_futils_fbuffer_rtrim(&file);
for (;data[end_offset] == '\r' || data[end_offset] == '\n'; --end_offset); if (strlen(GIT_FILE_CONTENT_PREFIX) == file.len) {
data[end_offset + 1] = '\0';
if (strlen(GIT_FILE_CONTENT_PREFIX) == end_offset + 1) {
git_futils_freebuffer(&file); git_futils_freebuffer(&file);
return git__throw(GIT_ENOTFOUND, "No path in git file `%s`", file_path); return git__throw(GIT_ENOTFOUND, "No path in git file `%s`", file_path);
} }
data = data + strlen(GIT_FILE_CONTENT_PREFIX); error = git_path_prettify_dir(path_out,
error = git_path_prettify_dir(path_out, data, base_path); ((char *)file.data) + strlen(GIT_FILE_CONTENT_PREFIX), base_path);
git_futils_freebuffer(&file); git_futils_freebuffer(&file);
if (error == 0 && git_futils_exists(path_out) == 0) if (error == GIT_SUCCESS && git_futils_exists(path_out->ptr) == 0)
return GIT_SUCCESS; return GIT_SUCCESS;
return git__throw(GIT_EOBJCORRUPTED, "The `.git` file points to an inexisting path"); return git__throw(GIT_EOBJCORRUPTED, "The `.git` file points to a nonexistent path");
} }
int git_repository_discover( int git_repository_discover(
...@@ -489,54 +507,62 @@ int git_repository_discover( ...@@ -489,54 +507,62 @@ int git_repository_discover(
const char *ceiling_dirs) const char *ceiling_dirs)
{ {
int error, ceiling_offset; int error, ceiling_offset;
char bare_path[GIT_PATH_MAX]; git_buf bare_path = GIT_BUF_INIT;
char normal_path[GIT_PATH_MAX]; git_buf normal_path = GIT_BUF_INIT;
char *found_path; git_buf *found_path = NULL;
dev_t current_device = 0; dev_t current_device = 0;
assert(start_path && repository_path); assert(start_path && repository_path);
error = git_path_prettify_dir(bare_path, start_path, NULL); *repository_path = '\0';
error = git_path_prettify_dir(&bare_path, start_path, NULL);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; goto cleanup;
if (!across_fs) { if (!across_fs) {
error = retrieve_device(&current_device, bare_path); error = retrieve_device(&current_device, bare_path.ptr);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; goto cleanup;
} }
ceiling_offset = retrieve_ceiling_directories_offset(bare_path, ceiling_dirs); ceiling_offset = retrieve_ceiling_directories_offset(bare_path.ptr, ceiling_dirs);
git_path_join(normal_path, bare_path, DOT_GIT);
while(1) { while(1) {
error = git_buf_joinpath(&normal_path, bare_path.ptr, DOT_GIT);
if (error < GIT_SUCCESS)
break;
/** /**
* If the `.git` file is regular instead of * If the `.git` file is regular instead of
* a directory, it should contain the path of the actual git repository * a directory, it should contain the path of the actual git repository
*/ */
if (git_futils_isfile(normal_path) == GIT_SUCCESS) { if (git_futils_isfile(normal_path.ptr) == GIT_SUCCESS) {
error = read_gitfile(repository_path, normal_path, bare_path); git_buf gitfile_path = GIT_BUF_INIT;
if (error < GIT_SUCCESS)
return git__rethrow(error,
"Unable to read git file `%s`", normal_path);
error = quickcheck_repository_dir(repository_path); error = read_gitfile(&gitfile_path, normal_path.ptr, bare_path.ptr);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__throw(GIT_ENOTFOUND, git__rethrow(error, "Unable to read git file `%s`", normal_path.ptr);
"The `.git` file found at '%s' points" else if ((error = quickcheck_repository_dir(&gitfile_path)) < GIT_SUCCESS)
"to an inexisting Git folder", normal_path); git__throw(GIT_ENOTFOUND,
"The `.git` file found at '%s' points "
"to a nonexistent git folder", normal_path.ptr);
else {
git_buf_swap(&normal_path, &gitfile_path);
found_path = &normal_path;
}
return GIT_SUCCESS; git_buf_free(&gitfile_path);
break;
} }
/** /**
* If the `.git` file is a folder, we check inside of it * If the `.git` file is a folder, we check inside of it
*/ */
if (git_futils_isdir(normal_path) == GIT_SUCCESS) { if (git_futils_isdir(normal_path.ptr) == GIT_SUCCESS) {
error = quickcheck_repository_dir(normal_path); error = quickcheck_repository_dir(&normal_path);
if (error == GIT_SUCCESS) { if (error == GIT_SUCCESS) {
found_path = normal_path; found_path = &normal_path;
break; break;
} }
} }
...@@ -545,44 +571,63 @@ int git_repository_discover( ...@@ -545,44 +571,63 @@ int git_repository_discover(
* Otherwise, the repository may be bare, let's check * Otherwise, the repository may be bare, let's check
* the root anyway * the root anyway
*/ */
error = quickcheck_repository_dir(bare_path); error = quickcheck_repository_dir(&bare_path);
if (error == GIT_SUCCESS) { if (error == GIT_SUCCESS) {
found_path = bare_path; found_path = &bare_path;
break; break;
} }
if (git_path_dirname_r(normal_path, sizeof(normal_path), bare_path) < GIT_SUCCESS) /**
return git__throw(GIT_EOSERR, "Failed to dirname '%s'", bare_path); * If we didn't find it, walk up the tree
*/
error = git_path_dirname_r(&normal_path, bare_path.ptr);
if (error < GIT_SUCCESS) {
git__rethrow(GIT_EOSERR, "Failed to dirname '%s'", bare_path.ptr);
break;
}
git_buf_swap(&bare_path, &normal_path);
if (!across_fs) { if (!across_fs) {
dev_t new_device; dev_t new_device;
error = retrieve_device(&new_device, normal_path); error = retrieve_device(&new_device, bare_path.ptr);
if (error < GIT_SUCCESS || current_device != new_device) { if (error < GIT_SUCCESS || current_device != new_device) {
return git__throw(GIT_ENOTAREPO, error = git__throw(GIT_ENOTAREPO,
"Not a git repository (or any parent up to mount parent %s)\n" "Not a git repository (or any parent up to mount parent %s)\n"
"Stopping at filesystem boundary.", bare_path); "Stopping at filesystem boundary.", normal_path.ptr);
break;
} }
current_device = new_device; current_device = new_device;
} }
strcpy(bare_path, normal_path); /* nothing has been found, lets try the parent directory
git_path_join(normal_path, bare_path, DOT_GIT); * but stop if we hit one of the ceiling directories
*/
// nothing has been found, lets try the parent directory if (bare_path.ptr[ceiling_offset] == '\0') {
if (bare_path[ceiling_offset] == '\0') { error = git__throw(GIT_ENOTAREPO,
return git__throw(GIT_ENOTAREPO,
"Not a git repository (or any of the parent directories): %s", start_path); "Not a git repository (or any of the parent directories): %s", start_path);
break;
} }
} }
if (size < strlen(found_path) + 2) { assert(found_path || error != GIT_SUCCESS);
return git__throw(GIT_ESHORTBUFFER,
"The repository buffer is not long enough to handle the repository path `%s`", found_path); if (found_path) {
if ((error = git_path_to_dir(found_path)) < GIT_SUCCESS)
git__rethrow(error, "Could not convert git repository to directory");
else if (size < (size_t)(found_path->size + 1))
error = git__throw(GIT_ESHORTBUFFER,
"The repository buffer is not long enough to "
"handle the repository path `%s`", found_path->ptr);
else
git_buf_copy_cstr(repository_path, size, found_path);
} }
git_path_join(repository_path, found_path, ""); cleanup:
return GIT_SUCCESS; git_buf_free(&bare_path);
git_buf_free(&normal_path);
return error;
} }
static int repo_init_reinit(const char *repository_path, int is_bare) static int repo_init_reinit(const char *repository_path, int is_bare)
...@@ -596,21 +641,23 @@ static int repo_init_reinit(const char *repository_path, int is_bare) ...@@ -596,21 +641,23 @@ static int repo_init_reinit(const char *repository_path, int is_bare)
static int repo_init_createhead(const char *git_dir) static int repo_init_createhead(const char *git_dir)
{ {
char ref_path[GIT_PATH_MAX]; int error;
git_buf ref_path = GIT_BUF_INIT;
git_filebuf ref = GIT_FILEBUF_INIT; git_filebuf ref = GIT_FILEBUF_INIT;
git_path_join(ref_path, git_dir, GIT_HEAD_FILE); if (!(error = git_buf_joinpath(&ref_path, git_dir, GIT_HEAD_FILE)) &&
!(error = git_filebuf_open(&ref, ref_path.ptr, 0)) &&
git_filebuf_open(&ref, ref_path, 0); !(error = git_filebuf_printf(&ref, "ref: refs/heads/master\n")))
git_filebuf_printf(&ref, "ref: refs/heads/master\n"); error = git_filebuf_commit(&ref, GIT_REFS_FILE_MODE);
return git_filebuf_commit(&ref, GIT_REFS_FILE_MODE); git_buf_free(&ref_path);
return error;
} }
static int repo_init_config(const char *git_dir, int is_bare) static int repo_init_config(const char *git_dir, int is_bare)
{ {
char cfg_path[GIT_PATH_MAX]; git_buf cfg_path = GIT_BUF_INIT;
git_config *config; git_config *config = NULL;
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
#define SET_REPO_CONFIG(type, name, val) {\ #define SET_REPO_CONFIG(type, name, val) {\
...@@ -619,29 +666,40 @@ static int repo_init_config(const char *git_dir, int is_bare) ...@@ -619,29 +666,40 @@ static int repo_init_config(const char *git_dir, int is_bare)
goto cleanup;\ goto cleanup;\
} }
git_path_join(cfg_path, git_dir, GIT_CONFIG_FILENAME_INREPO); error = git_buf_joinpath(&cfg_path, git_dir, GIT_CONFIG_FILENAME_INREPO);
if (error < GIT_SUCCESS)
goto cleanup;
error = git_config_open_ondisk(&config, cfg_path); error = git_config_open_ondisk(&config, cfg_path.ptr);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return error; goto cleanup;
SET_REPO_CONFIG(bool, "core.bare", is_bare); SET_REPO_CONFIG(bool, "core.bare", is_bare);
SET_REPO_CONFIG(int32, "core.repositoryformatversion", 0); SET_REPO_CONFIG(int32, "core.repositoryformatversion", 0);
/* TODO: what other defaults? */ /* TODO: what other defaults? */
cleanup: cleanup:
git_buf_free(&cfg_path);
git_config_free(config); git_config_free(config);
return error; return error;
} }
static int repo_init_structure(const char *git_dir, int is_bare) static int repo_init_structure(const char *git_dir, int is_bare)
{ {
int error; int error, i;
struct { const char *dir; mode_t mode; } dirs[] = {
char temp_path[GIT_PATH_MAX]; { GIT_OBJECTS_INFO_DIR, GIT_OBJECT_DIR_MODE }, /* '/objects/info/' */
{ GIT_OBJECTS_PACK_DIR, GIT_OBJECT_DIR_MODE }, /* '/objects/pack/' */
if (git_futils_mkdir_r(git_dir, is_bare ? GIT_BARE_DIR_MODE : GIT_DIR_MODE)) { GIT_REFS_HEADS_DIR, GIT_REFS_DIR_MODE }, /* '/refs/heads/' */
return git__throw(GIT_ERROR, "Failed to initialize repository structure. Could not mkdir"); { GIT_REFS_TAGS_DIR, GIT_REFS_DIR_MODE }, /* '/refs/tags/' */
{ NULL, 0 }
};
/* Make the base directory */
error = git_futils_mkdir_r(git_dir, NULL, is_bare ?
GIT_BARE_DIR_MODE : GIT_DIR_MODE);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to initialize repository structure. Could not mkdir");
/* Hides the ".git" directory */ /* Hides the ".git" directory */
if (!is_bare) { if (!is_bare) {
...@@ -652,67 +710,52 @@ static int repo_init_structure(const char *git_dir, int is_bare) ...@@ -652,67 +710,52 @@ static int repo_init_structure(const char *git_dir, int is_bare)
#endif #endif
} }
/* Creates the '/objects/info/' directory */ /* Make subdirectories as needed */
git_path_join(temp_path, git_dir, GIT_OBJECTS_INFO_DIR); for (i = 0; dirs[i].dir != NULL; ++i) {
error = git_futils_mkdir_r(temp_path, GIT_OBJECT_DIR_MODE); error = git_futils_mkdir_r(dirs[i].dir, git_dir, dirs[i].mode);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to initialize repository structure"); return git__rethrow(error,
"Failed to create repository folder `%s`", dirs[i].dir);
/* Creates the '/objects/pack/' directory */ }
git_path_join(temp_path, git_dir, GIT_OBJECTS_PACK_DIR);
error = p_mkdir(temp_path, GIT_OBJECT_DIR_MODE);
if (error < GIT_SUCCESS)
return git__throw(error, "Unable to create `%s` folder", temp_path);
/* Creates the '/refs/heads/' directory */
git_path_join(temp_path, git_dir, GIT_REFS_HEADS_DIR);
error = git_futils_mkdir_r(temp_path, GIT_REFS_DIR_MODE);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to initialize repository structure");
/* Creates the '/refs/tags/' directory */
git_path_join(temp_path, git_dir, GIT_REFS_TAGS_DIR);
error = p_mkdir(temp_path, GIT_REFS_DIR_MODE);
if (error < GIT_SUCCESS)
return git__throw(error, "Unable to create `%s` folder", temp_path);
/* TODO: what's left? templates? */ /* TODO: what's left? templates? */
return GIT_SUCCESS; return error;
} }
int git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare) int git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare)
{ {
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
git_repository *repo = NULL; git_repository *repo = NULL;
char repository_path[GIT_PATH_MAX]; git_buf repository_path = GIT_BUF_INIT;
assert(repo_out && path); assert(repo_out && path);
git_path_join(repository_path, path, is_bare ? "" : GIT_DIR); error = git_buf_joinpath(&repository_path, path, is_bare ? "" : GIT_DIR);
if (error < GIT_SUCCESS)
return error;
if (git_futils_isdir(repository_path)) { if (git_futils_isdir(repository_path.ptr) == GIT_SUCCESS) {
if (quickcheck_repository_dir(repository_path) == GIT_SUCCESS) if (quickcheck_repository_dir(&repository_path) == GIT_SUCCESS) {
return repo_init_reinit(repository_path, is_bare); error = repo_init_reinit(repository_path.ptr, is_bare);
git_buf_free(&repository_path);
return error;
}
} }
error = repo_init_structure(repository_path, is_bare); if (!(error = repo_init_structure(repository_path.ptr, is_bare)) &&
if (error < GIT_SUCCESS) !(error = repo_init_config(repository_path.ptr, is_bare)) &&
goto cleanup; !(error = repo_init_createhead(repository_path.ptr)))
error = git_repository_open(repo_out, repository_path.ptr);
error = repo_init_config(repository_path, is_bare); else
if (error < GIT_SUCCESS) git_repository_free(repo);
goto cleanup;
error = repo_init_createhead(repository_path); git_buf_free(&repository_path);
if (error < GIT_SUCCESS)
goto cleanup;
return git_repository_open(repo_out, repository_path); if (error != GIT_SUCCESS)
git__rethrow(error, "Failed to (re)init the repository `%s`", path);
cleanup: return error;
git_repository_free(repo);
return git__rethrow(error, "Failed to (re)init the repository `%s`", path);
} }
int git_repository_head_detached(git_repository *repo) int git_repository_head_detached(git_repository *repo)
......
...@@ -16,7 +16,9 @@ void git_signature_free(git_signature *sig) ...@@ -16,7 +16,9 @@ void git_signature_free(git_signature *sig)
return; return;
git__free(sig->name); git__free(sig->name);
sig->name = NULL;
git__free(sig->email); git__free(sig->email);
sig->email = NULL;
git__free(sig); git__free(sig);
} }
......
...@@ -28,12 +28,10 @@ struct status_entry { ...@@ -28,12 +28,10 @@ struct status_entry {
static struct status_entry *status_entry_new(git_vector *entries, const char *path) static struct status_entry *status_entry_new(git_vector *entries, const char *path)
{ {
struct status_entry *e = git__malloc(sizeof(*e) + strlen(path) + 1); struct status_entry *e = git__calloc(sizeof(*e) + strlen(path) + 1, 1);
if (e == NULL) if (e == NULL)
return NULL; return NULL;
memset(e, 0x0, sizeof(*e));
if (entries != NULL) if (entries != NULL)
git_vector_insert(entries, e); git_vector_insert(entries, e);
...@@ -73,7 +71,7 @@ static void status_entry_update_from_index(struct status_entry *e, git_index *in ...@@ -73,7 +71,7 @@ static void status_entry_update_from_index(struct status_entry *e, git_index *in
status_entry_update_from_index_entry(e, index_entry); status_entry_update_from_index_entry(e, index_entry);
} }
static int status_entry_update_from_workdir(struct status_entry *e, char* full_path) static int status_entry_update_from_workdir(struct status_entry *e, const char* full_path)
{ {
struct stat filest; struct stat filest;
...@@ -125,7 +123,7 @@ struct status_st { ...@@ -125,7 +123,7 @@ struct status_st {
git_tree *tree; git_tree *tree;
int workdir_path_len; int workdir_path_len;
char* head_tree_relative_path; git_buf head_tree_relative_path;
int head_tree_relative_path_len; int head_tree_relative_path_len;
unsigned int tree_position; unsigned int tree_position;
unsigned int index_position; unsigned int index_position;
...@@ -155,6 +153,7 @@ static int retrieve_head_tree(git_tree **tree_out, git_repository *repo) ...@@ -155,6 +153,7 @@ static int retrieve_head_tree(git_tree **tree_out, git_repository *repo)
return git__rethrow(error, "The tip of HEAD can't be retrieved"); return git__rethrow(error, "The tip of HEAD can't be retrieved");
git_reference_free(resolved_head_ref); git_reference_free(resolved_head_ref);
if ((error = git_commit_tree(&tree, head_commit)) < GIT_SUCCESS) { if ((error = git_commit_tree(&tree, head_commit)) < GIT_SUCCESS) {
error = git__rethrow(error, "The tree of HEAD can't be retrieved"); error = git__rethrow(error, "The tree of HEAD can't be retrieved");
goto exit; goto exit;
...@@ -174,12 +173,15 @@ enum path_type { ...@@ -174,12 +173,15 @@ enum path_type {
GIT_STATUS_PATH_FOLDER, GIT_STATUS_PATH_FOLDER,
}; };
static int dirent_cb(void *state, char *full_path); static int dirent_cb(void *state, git_buf *full_path);
static int alphasorted_futils_direach( static int alphasorted_futils_direach(
char *path, size_t path_sz, git_buf *path, int (*fn)(void *, git_buf *), void *arg);
int (*fn)(void *, char *), void *arg);
static int process_folder(struct status_st *st, const git_tree_entry *tree_entry, char *full_path, enum path_type path_type) static int process_folder(
struct status_st *st,
const git_tree_entry *tree_entry,
git_buf *full_path,
enum path_type path_type)
{ {
git_object *subtree = NULL; git_object *subtree = NULL;
git_tree *pushed_tree = NULL; git_tree *pushed_tree = NULL;
...@@ -209,10 +211,9 @@ static int process_folder(struct status_st *st, const git_tree_entry *tree_entry ...@@ -209,10 +211,9 @@ static int process_folder(struct status_st *st, const git_tree_entry *tree_entry
} }
if (full_path != NULL && path_type == GIT_STATUS_PATH_FOLDER) if (full_path != NULL && path_type == GIT_STATUS_PATH_FOLDER)
error = alphasorted_futils_direach(full_path, GIT_PATH_MAX, dirent_cb, st); error = alphasorted_futils_direach(full_path, dirent_cb, st);
else { else
error = dirent_cb(st, NULL); error = dirent_cb(st, NULL);
}
if (tree_entry_type == GIT_OBJ_TREE) { if (tree_entry_type == GIT_OBJ_TREE) {
git_object_free(subtree); git_object_free(subtree);
...@@ -229,7 +230,7 @@ static int store_if_changed(struct status_st *st, struct status_entry *e) ...@@ -229,7 +230,7 @@ static int store_if_changed(struct status_st *st, struct status_entry *e)
{ {
int error; int error;
if ((error = status_entry_update_flags(e)) < GIT_SUCCESS) if ((error = status_entry_update_flags(e)) < GIT_SUCCESS)
return git__throw(error, "Failed to process the file '%s'. It doesn't exist in the workdir, in the HEAD nor in the index", e->path); return git__throw(error, "Failed to process the file '%s'. It doesn't exist in the workdir, in the HEAD nor in the index", e->path);
if (e->status_flags == GIT_STATUS_CURRENT) { if (e->status_flags == GIT_STATUS_CURRENT) {
git__free(e); git__free(e);
...@@ -243,7 +244,7 @@ static int determine_status(struct status_st *st, ...@@ -243,7 +244,7 @@ static int determine_status(struct status_st *st,
int in_head, int in_index, int in_workdir, int in_head, int in_index, int in_workdir,
const git_tree_entry *tree_entry, const git_tree_entry *tree_entry,
const git_index_entry *index_entry, const git_index_entry *index_entry,
char *full_path, git_buf *full_path,
const char *status_path, const char *status_path,
enum path_type path_type) enum path_type path_type)
{ {
...@@ -273,7 +274,8 @@ static int determine_status(struct status_st *st, ...@@ -273,7 +274,8 @@ static int determine_status(struct status_st *st,
} }
if (in_workdir) if (in_workdir)
if ((error = status_entry_update_from_workdir(e, full_path)) < GIT_SUCCESS) if ((error = status_entry_update_from_workdir(e, full_path->ptr
)) < GIT_SUCCESS)
return error; /* The callee has already set the error message */ return error; /* The callee has already set the error message */
return store_if_changed(st, e); return store_if_changed(st, e);
...@@ -284,7 +286,7 @@ static int determine_status(struct status_st *st, ...@@ -284,7 +286,7 @@ static int determine_status(struct status_st *st,
return process_folder(st, tree_entry, full_path, path_type); return process_folder(st, tree_entry, full_path, path_type);
} }
static int path_type_from(char *full_path, int is_dir) static int path_type_from(git_buf *full_path, int is_dir)
{ {
if (full_path == NULL) if (full_path == NULL)
return GIT_STATUS_PATH_NULL; return GIT_STATUS_PATH_NULL;
...@@ -292,7 +294,7 @@ static int path_type_from(char *full_path, int is_dir) ...@@ -292,7 +294,7 @@ static int path_type_from(char *full_path, int is_dir)
if (!is_dir) if (!is_dir)
return GIT_STATUS_PATH_FILE; return GIT_STATUS_PATH_FILE;
if (!git__suffixcmp(full_path, "/" DOT_GIT "/")) if (!git__suffixcmp(full_path->ptr, "/" DOT_GIT "/"))
return GIT_STATUS_PATH_IGNORE; return GIT_STATUS_PATH_IGNORE;
return GIT_STATUS_PATH_FOLDER; return GIT_STATUS_PATH_FOLDER;
...@@ -330,7 +332,7 @@ static int compare(const char *left, const char *right) ...@@ -330,7 +332,7 @@ static int compare(const char *left, const char *right)
/* Greatly inspired from JGit IndexTreeWalker */ /* Greatly inspired from JGit IndexTreeWalker */
/* https://github.com/spearce/jgit/blob/ed47e29c777accfa78c6f50685a5df2b8f5b8ff5/org.spearce.jgit/src/org/spearce/jgit/lib/IndexTreeWalker.java#L88 */ /* https://github.com/spearce/jgit/blob/ed47e29c777accfa78c6f50685a5df2b8f5b8ff5/org.spearce.jgit/src/org/spearce/jgit/lib/IndexTreeWalker.java#L88 */
static int dirent_cb(void *state, char *a) static int dirent_cb(void *state, git_buf *a)
{ {
const git_tree_entry *m; const git_tree_entry *m;
const git_index_entry *entry; const git_index_entry *entry;
...@@ -346,7 +348,7 @@ static int dirent_cb(void *state, char *a) ...@@ -346,7 +348,7 @@ static int dirent_cb(void *state, char *a)
if (path_type == GIT_STATUS_PATH_IGNORE) if (path_type == GIT_STATUS_PATH_IGNORE)
return GIT_SUCCESS; /* Let's skip the ".git" directory */ return GIT_SUCCESS; /* Let's skip the ".git" directory */
a_name = (path_type != GIT_STATUS_PATH_NULL) ? a + st->workdir_path_len : NULL; a_name = (path_type != GIT_STATUS_PATH_NULL) ? a->ptr + st->workdir_path_len : NULL;
while (1) { while (1) {
if (st->tree == NULL) if (st->tree == NULL)
...@@ -360,15 +362,18 @@ static int dirent_cb(void *state, char *a) ...@@ -360,15 +362,18 @@ static int dirent_cb(void *state, char *a)
return GIT_SUCCESS; return GIT_SUCCESS;
if (m != NULL) { if (m != NULL) {
st->head_tree_relative_path[st->head_tree_relative_path_len] = '\0'; git_buf_truncate(&st->head_tree_relative_path,
st->head_tree_relative_path_len);
git_buf_joinpath(&st->head_tree_relative_path,
st->head_tree_relative_path.ptr, m->filename);
/* When the tree entry is a folder, append a forward slash to its name */ /* When the tree entry is a folder, append a forward slash to its name */
if (git_tree_entry_type(m) == GIT_OBJ_TREE) if (git_tree_entry_type(m) == GIT_OBJ_TREE)
git_path_join_n(st->head_tree_relative_path, 3, st->head_tree_relative_path, m->filename, ""); git_path_to_dir(&st->head_tree_relative_path);
else
git_path_join(st->head_tree_relative_path, st->head_tree_relative_path, m->filename); if (error < GIT_SUCCESS)
return git__rethrow(error, "An error occured while determining the status of '%s'", a->ptr);
m_name = st->head_tree_relative_path;
m_name = st->head_tree_relative_path.ptr;
} else } else
m_name = NULL; m_name = NULL;
...@@ -383,7 +388,7 @@ static int dirent_cb(void *state, char *a) ...@@ -383,7 +388,7 @@ static int dirent_cb(void *state, char *a)
pi = ((cmpmi >= 0) && (cmpai >= 0)) ? i_name : NULL; pi = ((cmpmi >= 0) && (cmpai >= 0)) ? i_name : NULL;
if((error = determine_status(st, pm != NULL, pi != NULL, pa != NULL, m, entry, a, status_path(pm, pi, pa), path_type)) < GIT_SUCCESS) if((error = determine_status(st, pm != NULL, pi != NULL, pa != NULL, m, entry, a, status_path(pm, pi, pa), path_type)) < GIT_SUCCESS)
return git__rethrow(error, "An error occured while determining the status of '%s'", a); return git__rethrow(error, "An error occured while determining the status of '%s'", a->ptr);
if ((pa != NULL) || (path_type == GIT_STATUS_PATH_FOLDER)) if ((pa != NULL) || (path_type == GIT_STATUS_PATH_FOLDER))
return GIT_SUCCESS; return GIT_SUCCESS;
...@@ -404,9 +409,8 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig ...@@ -404,9 +409,8 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig
{ {
git_vector entries; git_vector entries;
git_index *index = NULL; git_index *index = NULL;
char temp_path[GIT_PATH_MAX]; git_buf temp_path = GIT_BUF_INIT;
char tree_path[GIT_PATH_MAX] = ""; struct status_st dirent_st = {0};
struct status_st dirent_st;
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
unsigned int i; unsigned int i;
git_tree *tree; git_tree *tree;
...@@ -435,23 +439,21 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig ...@@ -435,23 +439,21 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig
dirent_st.tree = tree; dirent_st.tree = tree;
dirent_st.index = index; dirent_st.index = index;
dirent_st.vector = &entries; dirent_st.vector = &entries;
dirent_st.head_tree_relative_path = tree_path; git_buf_init(&dirent_st.head_tree_relative_path, 0);
dirent_st.head_tree_relative_path_len = 0; dirent_st.head_tree_relative_path_len = 0;
dirent_st.is_dir = 1; dirent_st.is_dir = 1;
strcpy(temp_path, workdir); if (git_futils_isdir(workdir)) {
if (git_futils_isdir(temp_path)) {
error = git__throw(GIT_EINVALIDPATH, error = git__throw(GIT_EINVALIDPATH,
"Failed to determine status of file '%s'. " "Failed to determine status of file '%s'. "
"The given path doesn't lead to a folder", temp_path); "The given path doesn't lead to a folder", workdir);
goto exit; goto exit;
} }
git_buf_sets(&temp_path, workdir);
error = alphasorted_futils_direach( error = alphasorted_futils_direach(
temp_path, sizeof(temp_path), &temp_path, dirent_cb, &dirent_st);
dirent_cb, &dirent_st
);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
error = git__rethrow(error, error = git__rethrow(error,
...@@ -477,6 +479,8 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig ...@@ -477,6 +479,8 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig
} }
exit: exit:
git_buf_free(&dirent_st.head_tree_relative_path);
git_buf_free(&temp_path);
git_vector_free(&entries); git_vector_free(&entries);
git_tree_free(tree); git_tree_free(tree);
return error; return error;
...@@ -521,7 +525,7 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char ...@@ -521,7 +525,7 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char
{ {
struct status_entry *e; struct status_entry *e;
git_index *index = NULL; git_index *index = NULL;
char temp_path[GIT_PATH_MAX]; git_buf temp_path = GIT_BUF_INIT;
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
git_tree *tree = NULL; git_tree *tree = NULL;
const char *workdir; const char *workdir;
...@@ -532,60 +536,72 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char ...@@ -532,60 +536,72 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char
return git__throw(GIT_ERROR, return git__throw(GIT_ERROR,
"Cannot retrieve status on a bare repository"); "Cannot retrieve status on a bare repository");
git_path_join(temp_path, workdir, path); if ((error = git_buf_joinpath(&temp_path, workdir, path)) < GIT_SUCCESS)
if (git_futils_isdir(temp_path) == GIT_SUCCESS) return git__rethrow(error,
"Failed to determine status of file '%s'", path);
if (git_futils_isdir(temp_path.ptr) == GIT_SUCCESS) {
git_buf_free(&temp_path);
return git__throw(GIT_EINVALIDPATH, return git__throw(GIT_EINVALIDPATH,
"Failed to determine status of file '%s'. " "Failed to determine status of file '%s'. "
"Given path leads to a folder, not a file", path); "Given path leads to a folder, not a file", path);
}
e = status_entry_new(NULL, path); e = status_entry_new(NULL, path);
if (e == NULL) if (e == NULL) {
git_buf_free(&temp_path);
return GIT_ENOMEM; return GIT_ENOMEM;
}
/* Find file in Workdir */ /* Find file in Workdir */
if (git_futils_exists(temp_path) == GIT_SUCCESS) { if (git_futils_exists(temp_path.ptr) == GIT_SUCCESS) {
if ((error = status_entry_update_from_workdir(e, temp_path)) < GIT_SUCCESS) if ((error = status_entry_update_from_workdir(e, temp_path.ptr)) < GIT_SUCCESS)
goto exit; /* The callee has already set the error message */ goto cleanup; /* The callee has already set the error message */
} }
/* Find file in Index */ /* Find file in Index */
if ((error = git_repository_index__weakptr(&index, repo)) < GIT_SUCCESS) { if ((error = git_repository_index__weakptr(&index, repo)) < GIT_SUCCESS) {
error = git__rethrow(error, git__rethrow(error,
"Failed to determine status of file '%s'." "Failed to determine status of file '%s'."
"Index can't be opened", path); "Index can't be opened", path);
goto exit; goto cleanup;
} }
status_entry_update_from_index(e, index); status_entry_update_from_index(e, index);
if ((error = retrieve_head_tree(&tree, repo)) < GIT_SUCCESS) { if ((error = retrieve_head_tree(&tree, repo)) < GIT_SUCCESS) {
error = git__rethrow(error, git__rethrow(error,
"Failed to determine status of file '%s'", path); "Failed to determine status of file '%s'", path);
goto exit; goto cleanup;
} }
/* If the repository is not empty, try and locate the file in HEAD */ /* If the repository is not empty, try and locate the file in HEAD */
if (tree != NULL) { if (tree != NULL) {
strcpy(temp_path, path); if ((error = git_buf_sets(&temp_path, path)) < GIT_SUCCESS) {
git__rethrow(error,
"Failed to determine status of file '%s'", path);
goto cleanup;
}
error = recurse_tree_entry(tree, e, temp_path); error = recurse_tree_entry(tree, e, temp_path.ptr);
if (error < GIT_SUCCESS) { if (error < GIT_SUCCESS) {
error = git__rethrow(error, git__rethrow(error,
"Failed to determine status of file '%s'. " "Failed to determine status of file '%s'. "
"An error occured while processing the tree", path); "An error occured while processing the tree", path);
goto exit; goto cleanup;
} }
} }
/* Determine status */ /* Determine status */
if ((error = status_entry_update_flags(e)) < GIT_SUCCESS) { if ((error = status_entry_update_flags(e)) < GIT_SUCCESS) {
error = git__throw(error, "Nonexistent file"); git__throw(error, "Nonexistent file");
goto exit; goto cleanup;
} }
*status_flags = e->status_flags; *status_flags = e->status_flags;
exit: cleanup:
git_buf_free(&temp_path);
git_tree_free(tree); git_tree_free(tree);
git__free(e); git__free(e);
return error; return error;
...@@ -600,37 +616,34 @@ exit: ...@@ -600,37 +616,34 @@ exit:
struct alphasorted_dirent_info { struct alphasorted_dirent_info {
int is_dir; int is_dir;
char path[GIT_FLEX_ARRAY]; /* more */ char path[GIT_FLEX_ARRAY]; /* more */
}; };
static struct alphasorted_dirent_info *alphasorted_dirent_info_new(const char *path) static struct alphasorted_dirent_info *alphasorted_dirent_info_new(const git_buf *path)
{ {
int is_dir, size; int is_dir, size;
struct alphasorted_dirent_info *di; struct alphasorted_dirent_info *di;
is_dir = git_futils_isdir(path) == GIT_SUCCESS ? 1 : 0; is_dir = git_futils_isdir(path->ptr) == GIT_SUCCESS ? 1 : 0;
size = sizeof(*di) + (is_dir ? GIT_PATH_MAX : strlen(path)) + 2; size = sizeof(*di) + path->size + is_dir + 1;
di = git__malloc(size); di = git__calloc(size, 1);
if (di == NULL) if (di == NULL)
return NULL; return NULL;
memset(di, 0x0, size); git_buf_copy_cstr(di->path, path->size + 1, path);
strcpy(di->path, path);
if (is_dir) { if (is_dir) {
di->is_dir = 1; di->is_dir = 1;
/* /*
* Append a forward slash to the name to force folders * Append a forward slash to the name to force folders
* to be ordered in a similar way than in a tree * to be ordered in a similar way than in a tree
* *
* The file "subdir" should appear before the file "subdir.txt" * The file "subdir" should appear before the file "subdir.txt"
* The folder "subdir" should appear after the file "subdir.txt" * The folder "subdir" should appear after the file "subdir.txt"
*/ */
di->path[strlen(path)] = '/'; di->path[path->size] = '/';
} }
return di; return di;
...@@ -644,7 +657,7 @@ static int alphasorted_dirent_info_cmp(const void *a, const void *b) ...@@ -644,7 +657,7 @@ static int alphasorted_dirent_info_cmp(const void *a, const void *b)
return strcmp(stra->path, strb->path); return strcmp(stra->path, strb->path);
} }
static int alphasorted_dirent_cb(void *state, char *full_path) static int alphasorted_dirent_cb(void *state, git_buf *full_path)
{ {
struct alphasorted_dirent_info *entry; struct alphasorted_dirent_info *entry;
git_vector *entry_names; git_vector *entry_names;
...@@ -664,34 +677,42 @@ static int alphasorted_dirent_cb(void *state, char *full_path) ...@@ -664,34 +677,42 @@ static int alphasorted_dirent_cb(void *state, char *full_path)
} }
static int alphasorted_futils_direach( static int alphasorted_futils_direach(
char *path, git_buf *path,
size_t path_sz, int (*fn)(void *, git_buf *),
int (*fn)(void *, char *),
void *arg) void *arg)
{ {
struct alphasorted_dirent_info *entry; struct alphasorted_dirent_info *entry;
git_vector entry_names; git_vector entry_names;
unsigned int idx; unsigned int idx;
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
git_buf entry_path = GIT_BUF_INIT;
if (git_vector_init(&entry_names, 16, alphasorted_dirent_info_cmp) < GIT_SUCCESS) if (git_vector_init(&entry_names, 16, alphasorted_dirent_info_cmp) < GIT_SUCCESS)
return GIT_ENOMEM; return GIT_ENOMEM;
error = git_futils_direach(path, path_sz, alphasorted_dirent_cb, &entry_names); error = git_futils_direach(path, alphasorted_dirent_cb, &entry_names);
git_vector_sort(&entry_names); git_vector_sort(&entry_names);
for (idx = 0; idx < entry_names.length; ++idx) { for (idx = 0; idx < entry_names.length; ++idx) {
entry = (struct alphasorted_dirent_info *)git_vector_get(&entry_names, idx); entry = (struct alphasorted_dirent_info *)git_vector_get(&entry_names, idx);
/* We have to walk the entire vector even if there was an error,
* in order to free up memory, but we stop making callbacks after
* an error.
*/
if (error == GIT_SUCCESS)
error = git_buf_sets(&entry_path, entry->path);
if (error == GIT_SUCCESS) { if (error == GIT_SUCCESS) {
((struct status_st *)arg)->is_dir = entry->is_dir; ((struct status_st *)arg)->is_dir = entry->is_dir;
error = fn(arg, entry->path); error = fn(arg, &entry_path);
} }
git__free(entry); git__free(entry);
} }
git_buf_free(&entry_path);
git_vector_free(&entry_names); git_vector_free(&entry_names);
return error; return error;
} }
...@@ -148,15 +148,22 @@ static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer ...@@ -148,15 +148,22 @@ static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer
return GIT_SUCCESS; return GIT_SUCCESS;
} }
static int retrieve_tag_reference(git_reference **tag_reference_out, char *ref_name_out, git_repository *repo, const char *tag_name) static int retrieve_tag_reference(
git_reference **tag_reference_out,
git_buf *ref_name_out,
git_repository *repo,
const char *tag_name)
{ {
git_reference *tag_ref; git_reference *tag_ref;
int error; int error;
*tag_reference_out = NULL; *tag_reference_out = NULL;
git_path_join(ref_name_out, GIT_REFS_TAGS_DIR, tag_name); error = git_buf_joinpath(ref_name_out, GIT_REFS_TAGS_DIR, tag_name);
error = git_reference_lookup(&tag_ref, repo, ref_name_out); if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to retrieve tag reference");
error = git_reference_lookup(&tag_ref, repo, ref_name_out->ptr);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to retrieve tag reference"); return git__rethrow(error, "Failed to retrieve tag reference");
...@@ -184,9 +191,10 @@ static int write_tag_annotation( ...@@ -184,9 +191,10 @@ static int write_tag_annotation(
git_buf_putc(&tag, '\n'); git_buf_putc(&tag, '\n');
git_buf_puts(&tag, message); git_buf_puts(&tag, message);
if (git_buf_oom(&tag)) { error = git_buf_lasterror(&tag);
if (error < GIT_SUCCESS) {
git_buf_free(&tag); git_buf_free(&tag);
return git__throw(GIT_ENOMEM, "Not enough memory to build the tag data"); return git__rethrow(error, "Not enough memory to build the tag data");
} }
error = git_repository_odb__weakptr(&odb, repo); error = git_repository_odb__weakptr(&odb, repo);
...@@ -215,56 +223,54 @@ static int git_tag_create__internal( ...@@ -215,56 +223,54 @@ static int git_tag_create__internal(
int create_tag_annotation) int create_tag_annotation)
{ {
git_reference *new_ref = NULL; git_reference *new_ref = NULL;
char ref_name[GIT_REFNAME_MAX]; git_buf ref_name = GIT_BUF_INIT;
int error, should_update_ref = 0; int error, should_update_ref = 0;
const char *errmsg = "Failed to create tag";
assert(repo && tag_name && target); assert(repo && tag_name && target);
assert(!create_tag_annotation || (tagger && message)); assert(!create_tag_annotation || (tagger && message));
if (git_object_owner(target) != repo) if (git_object_owner(target) != repo)
return git__throw(GIT_EINVALIDARGS, "The given target does not belong to this repository"); return git__throw(GIT_EINVALIDARGS,
"The given target does not belong to this repository");
error = retrieve_tag_reference(&new_ref, ref_name, repo, tag_name);
switch (error) {
case GIT_SUCCESS:
case GIT_ENOTFOUND:
break;
default: error = retrieve_tag_reference(&new_ref, &ref_name, repo, tag_name);
git_reference_free(new_ref); if (error < GIT_SUCCESS && error != GIT_ENOTFOUND)
return git__rethrow(error, "Failed to create tag"); goto cleanup;
}
/** Ensure the tag name doesn't conflict with an already existing /** Ensure the tag name doesn't conflict with an already existing
* reference unless overwriting has explictly been requested **/ * reference unless overwriting has explictly been requested **/
if (new_ref != NULL) { if (new_ref != NULL) {
if (!allow_ref_overwrite) { if (!allow_ref_overwrite) {
git_oid_cpy(oid, git_reference_oid(new_ref)); git_oid_cpy(oid, git_reference_oid(new_ref));
git_reference_free(new_ref); error = GIT_EEXISTS;
return git__throw(GIT_EEXISTS, "Tag already exists"); errmsg = "Tag already exists";
goto cleanup;
} else { } else {
should_update_ref = 1; should_update_ref = 1;
} }
} }
if (create_tag_annotation) { if (create_tag_annotation) {
if ((error = write_tag_annotation(oid, repo, tag_name, target, tagger, message)) < GIT_SUCCESS) { if ((error = write_tag_annotation(oid, repo, tag_name, target, tagger, message)) < GIT_SUCCESS)
git_reference_free(new_ref); goto cleanup;
return error;
}
} else } else
git_oid_cpy(oid, git_object_id(target)); git_oid_cpy(oid, git_object_id(target));
if (!should_update_ref) if (!should_update_ref)
error = git_reference_create_oid(&new_ref, repo, ref_name, oid, 0); error = git_reference_create_oid(&new_ref, repo, ref_name.ptr, oid, 0);
else else
error = git_reference_set_oid(new_ref, oid); error = git_reference_set_oid(new_ref, oid);
cleanup:
git_reference_free(new_ref); git_reference_free(new_ref);
git_buf_free(&ref_name);
if (error < GIT_SUCCESS)
git__rethrow(error, "%s", errmsg);
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create tag"); return error;
} }
int git_tag_create( int git_tag_create(
...@@ -293,12 +299,13 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu ...@@ -293,12 +299,13 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
{ {
git_tag tag; git_tag tag;
int error, should_update_ref = 0; int error, should_update_ref = 0;
const char *errmsg = "Failed to create tag";
git_odb *odb; git_odb *odb;
git_odb_stream *stream; git_odb_stream *stream;
git_odb_object *target_obj; git_odb_object *target_obj;
git_reference *new_ref = NULL; git_reference *new_ref = NULL;
char ref_name[GIT_REFNAME_MAX]; git_buf ref_name = GIT_BUF_INIT;
assert(oid && buffer); assert(oid && buffer);
...@@ -310,78 +317,77 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu ...@@ -310,78 +317,77 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
/* validate the buffer */ /* validate the buffer */
if ((error = parse_tag_buffer(&tag, buffer, buffer + strlen(buffer))) < GIT_SUCCESS) if ((error = parse_tag_buffer(&tag, buffer, buffer + strlen(buffer))) < GIT_SUCCESS)
return git__rethrow(error, "Failed to create tag"); goto cleanup;
/* validate the target */ /* validate the target */
if ((error = git_odb_read(&target_obj, odb, &tag.target)) < GIT_SUCCESS) if ((error = git_odb_read(&target_obj, odb, &tag.target)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to create tag"); goto cleanup;
if (tag.type != target_obj->raw.type) if (tag.type != target_obj->raw.type) {
return git__throw(error, "The type for the given target is invalid"); error = GIT_EINVALIDTYPE;
errmsg = "The type for the given target is invalid";
goto cleanup;
}
git_odb_object_free(target_obj); git_odb_object_free(target_obj);
error = retrieve_tag_reference(&new_ref, ref_name, repo, tag.tag_name); error = retrieve_tag_reference(&new_ref, &ref_name, repo, tag.tag_name);
if (error < GIT_SUCCESS && error != GIT_ENOTFOUND)
switch (error) { goto cleanup;
case GIT_SUCCESS:
case GIT_ENOTFOUND:
break;
default:
git_reference_free(new_ref);
return git__rethrow(error, "Failed to create tag");
}
/** Ensure the tag name doesn't conflict with an already existing /** Ensure the tag name doesn't conflict with an already existing
* reference unless overwriting has explictly been requested **/ * reference unless overwriting has explictly been requested **/
if (new_ref != NULL) { if (new_ref != NULL) {
if (!allow_ref_overwrite) { if (!allow_ref_overwrite) {
git_oid_cpy(oid, git_reference_oid(new_ref)); git_oid_cpy(oid, git_reference_oid(new_ref));
git_reference_free(new_ref); error = GIT_EEXISTS;
return git__throw(GIT_EEXISTS, "Tag already exists"); errmsg = "Tag already exists";
goto cleanup;
} else { } else {
should_update_ref = 1; should_update_ref = 1;
} }
} }
/* write the buffer */ /* write the buffer */
if ((error = git_odb_open_wstream(&stream, odb, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS) { if ((error = git_odb_open_wstream(&stream, odb, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS)
git_reference_free(new_ref); goto cleanup;
return git__rethrow(error, "Failed to create tag");
}
stream->write(stream, buffer, strlen(buffer)); stream->write(stream, buffer, strlen(buffer));
error = stream->finalize_write(oid, stream); error = stream->finalize_write(oid, stream);
stream->free(stream); stream->free(stream);
if (error < GIT_SUCCESS) { if (error < GIT_SUCCESS)
git_reference_free(new_ref); goto cleanup;
return git__rethrow(error, "Failed to create tag");
}
if (!should_update_ref) if (!should_update_ref)
error = git_reference_create_oid(&new_ref, repo, ref_name, oid, 0); error = git_reference_create_oid(&new_ref, repo, ref_name.ptr, oid, 0);
else else
error = git_reference_set_oid(new_ref, oid); error = git_reference_set_oid(new_ref, oid);
cleanup:
git_reference_free(new_ref); git_reference_free(new_ref);
git_signature_free(tag.tagger); git_signature_free(tag.tagger);
git__free(tag.tag_name); git__free(tag.tag_name);
git__free(tag.message); git__free(tag.message);
git_buf_free(&ref_name);
if (error < GIT_SUCCESS)
git__rethrow(error, "%s", errmsg);
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create tag"); return error;
} }
int git_tag_delete(git_repository *repo, const char *tag_name) int git_tag_delete(git_repository *repo, const char *tag_name)
{ {
int error; int error;
git_reference *tag_ref; git_reference *tag_ref;
char ref_name[GIT_REFNAME_MAX]; git_buf ref_name = GIT_BUF_INIT;
error = retrieve_tag_reference(&tag_ref, &ref_name, repo, tag_name);
git_buf_free(&ref_name);
error = retrieve_tag_reference(&tag_ref, ref_name, repo, tag_name);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to delete tag"); return git__rethrow(error, "Failed to delete tag");
......
...@@ -68,7 +68,7 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url) ...@@ -68,7 +68,7 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url)
git_buf_put(request, url, delim - url); git_buf_put(request, url, delim - url);
git_buf_putc(request, '\0'); git_buf_putc(request, '\0');
return git_buf_oom(request); return git_buf_lasterror(request);
} }
static int send_request(GIT_SOCKET s, const char *cmd, const char *url) static int send_request(GIT_SOCKET s, const char *cmd, const char *url)
......
...@@ -77,10 +77,7 @@ static int gen_request(git_buf *buf, const char *url, const char *host, const ch ...@@ -77,10 +77,7 @@ static int gen_request(git_buf *buf, const char *url, const char *host, const ch
} }
git_buf_puts(buf, "\r\n"); git_buf_puts(buf, "\r\n");
if (git_buf_oom(buf)) return git_buf_lasterror(buf);
return GIT_ENOMEM;
return GIT_SUCCESS;
} }
static int do_connect(transport_http *t, const char *host, const char *port) static int do_connect(transport_http *t, const char *host, const char *port)
...@@ -608,8 +605,9 @@ static int http_download_pack(char **out, git_transport *transport, git_reposito ...@@ -608,8 +605,9 @@ static int http_download_pack(char **out, git_transport *transport, git_reposito
char buffer[1024]; char buffer[1024];
gitno_buffer buf; gitno_buffer buf;
download_pack_cbdata data; download_pack_cbdata data;
git_filebuf file; git_filebuf file = GIT_FILEBUF_INIT;
char path[GIT_PATH_MAX], suff[] = "/objects/pack/pack-received\0"; git_buf path = GIT_BUF_INIT;
char suff[] = "/objects/pack/pack-received\0";
/* /*
* This is part of the previous response, so we don't want to * This is part of the previous response, so we don't want to
...@@ -625,13 +623,15 @@ static int http_download_pack(char **out, git_transport *transport, git_reposito ...@@ -625,13 +623,15 @@ static int http_download_pack(char **out, git_transport *transport, git_reposito
gitno_buffer_setup(&buf, buffer, sizeof(buffer), t->socket); gitno_buffer_setup(&buf, buffer, sizeof(buffer), t->socket);
git_path_join(path, repo->path_repository, suff);
if (memcmp(oldbuf->ptr, "PACK", strlen("PACK"))) { if (memcmp(oldbuf->ptr, "PACK", strlen("PACK"))) {
return git__throw(GIT_ERROR, "The pack doesn't start with the signature"); return git__throw(GIT_ERROR, "The pack doesn't start with the signature");
} }
error = git_filebuf_open(&file, path, GIT_FILEBUF_TEMPORARY); error = git_buf_joinpath(&path, repo->path_repository, suff);
if (error < GIT_SUCCESS)
goto cleanup;
error = git_filebuf_open(&file, path.ptr, GIT_FILEBUF_TEMPORARY);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
goto cleanup; goto cleanup;
...@@ -671,6 +671,7 @@ static int http_download_pack(char **out, git_transport *transport, git_reposito ...@@ -671,6 +671,7 @@ static int http_download_pack(char **out, git_transport *transport, git_reposito
cleanup: cleanup:
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
git_filebuf_cleanup(&file); git_filebuf_cleanup(&file);
git_buf_free(&path);
return error; return error;
} }
......
...@@ -577,9 +577,9 @@ int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *b ...@@ -577,9 +577,9 @@ int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *b
git_buf_put(&tree, (char *)entry->oid.id, GIT_OID_RAWSZ); git_buf_put(&tree, (char *)entry->oid.id, GIT_OID_RAWSZ);
} }
if (git_buf_oom(&tree)) { if ((error = git_buf_lasterror(&tree)) < GIT_SUCCESS) {
git_buf_free(&tree); git_buf_free(&tree);
return git__throw(GIT_ENOMEM, "Not enough memory to build the tree data"); return git__rethrow(error, "Not enough memory to build the tree data");
} }
error = git_repository_odb__weakptr(&odb, repo); error = git_repository_odb__weakptr(&odb, repo);
...@@ -631,7 +631,7 @@ void git_treebuilder_free(git_treebuilder *bld) ...@@ -631,7 +631,7 @@ void git_treebuilder_free(git_treebuilder *bld)
static int tree_frompath( static int tree_frompath(
git_tree **parent_out, git_tree **parent_out,
git_tree *root, git_tree *root,
const char *treeentry_path, git_buf *treeentry_path,
int offset) int offset)
{ {
char *slash_pos = NULL; char *slash_pos = NULL;
...@@ -639,11 +639,11 @@ static int tree_frompath( ...@@ -639,11 +639,11 @@ static int tree_frompath(
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
git_tree *subtree; git_tree *subtree;
if (!*(treeentry_path + offset)) if (!*(treeentry_path->ptr + offset))
return git__rethrow(GIT_EINVALIDPATH, return git__rethrow(GIT_EINVALIDPATH,
"Invalid relative path to a tree entry '%s'.", treeentry_path); "Invalid relative path to a tree entry '%s'.", treeentry_path->ptr);
slash_pos = (char *)strchr(treeentry_path + offset, '/'); slash_pos = (char *)strchr(treeentry_path->ptr + offset, '/');
if (slash_pos == NULL) if (slash_pos == NULL)
return git_tree_lookup( return git_tree_lookup(
...@@ -652,13 +652,13 @@ static int tree_frompath( ...@@ -652,13 +652,13 @@ static int tree_frompath(
git_object_id((const git_object *)root) git_object_id((const git_object *)root)
); );
if (slash_pos == treeentry_path + offset) if (slash_pos == treeentry_path->ptr + offset)
return git__rethrow(GIT_EINVALIDPATH, return git__rethrow(GIT_EINVALIDPATH,
"Invalid relative path to a tree entry '%s'.", treeentry_path); "Invalid relative path to a tree entry '%s'.", treeentry_path->ptr);
*slash_pos = '\0'; *slash_pos = '\0';
entry = git_tree_entry_byname(root, treeentry_path + offset); entry = git_tree_entry_byname(root, treeentry_path->ptr + offset);
if (slash_pos != NULL) if (slash_pos != NULL)
*slash_pos = '/'; *slash_pos = '/';
...@@ -666,7 +666,7 @@ static int tree_frompath( ...@@ -666,7 +666,7 @@ static int tree_frompath(
if (entry == NULL) if (entry == NULL)
return git__rethrow(GIT_ENOTFOUND, return git__rethrow(GIT_ENOTFOUND,
"No tree entry can be found from " "No tree entry can be found from "
"the given tree and relative path '%s'.", treeentry_path); "the given tree and relative path '%s'.", treeentry_path->ptr);
error = git_tree_lookup(&subtree, root->object.repo, &entry->oid); error = git_tree_lookup(&subtree, root->object.repo, &entry->oid);
...@@ -677,7 +677,7 @@ static int tree_frompath( ...@@ -677,7 +677,7 @@ static int tree_frompath(
parent_out, parent_out,
subtree, subtree,
treeentry_path, treeentry_path,
slash_pos - treeentry_path + 1 (slash_pos - treeentry_path->ptr) + 1
); );
git_tree_free(subtree); git_tree_free(subtree);
...@@ -689,70 +689,82 @@ int git_tree_get_subtree( ...@@ -689,70 +689,82 @@ int git_tree_get_subtree(
git_tree *root, git_tree *root,
const char *subtree_path) const char *subtree_path)
{ {
char buffer[GIT_PATH_MAX]; int error;
git_buf buffer = GIT_BUF_INIT;
assert(subtree && root && subtree_path); assert(subtree && root && subtree_path);
strncpy(buffer, subtree_path, GIT_PATH_MAX); if ((error = git_buf_sets(&buffer, subtree_path)) == GIT_SUCCESS)
return tree_frompath(subtree, root, buffer, 0); error = tree_frompath(subtree, root, &buffer, 0);
git_buf_free(&buffer);
return error;
} }
static int tree_walk_post( static int tree_walk_post(
git_tree *tree, git_tree *tree,
git_treewalk_cb callback, git_treewalk_cb callback,
char *root, git_buf *path,
size_t root_len,
void *payload) void *payload)
{ {
int error; int error = GIT_SUCCESS;
unsigned int i; unsigned int i;
for (i = 0; i < tree->entries.length; ++i) { for (i = 0; i < tree->entries.length; ++i) {
git_tree_entry *entry = tree->entries.contents[i]; git_tree_entry *entry = tree->entries.contents[i];
root[root_len] = '\0'; if (callback(path->ptr, entry, payload) < 0)
if (callback(root, entry, payload) < 0)
continue; continue;
if (ENTRY_IS_TREE(entry)) { if (ENTRY_IS_TREE(entry)) {
git_tree *subtree; git_tree *subtree;
size_t path_len = path->size;
if ((error = git_tree_lookup( if ((error = git_tree_lookup(
&subtree, tree->object.repo, &entry->oid)) < 0) &subtree, tree->object.repo, &entry->oid)) < 0)
return error; break;
strcpy(root + root_len, entry->filename); /* append the next entry to the path */
root[root_len + entry->filename_len] = '/'; git_buf_puts(path, entry->filename);
git_buf_putc(path, '/');
if ((error = git_buf_lasterror(path)) < GIT_SUCCESS)
break;
tree_walk_post(subtree, error = tree_walk_post(subtree, callback, path, payload);
callback, root, if (error < GIT_SUCCESS)
root_len + entry->filename_len + 1, break;
payload
);
git_buf_truncate(path, path_len);
git_tree_free(subtree); git_tree_free(subtree);
} }
} }
return GIT_SUCCESS; return error;
} }
int git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode, void *payload) int git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode, void *payload)
{ {
char root_path[GIT_PATH_MAX]; int error = GIT_SUCCESS;
git_buf root_path = GIT_BUF_INIT;
root_path[0] = '\0';
switch (mode) { switch (mode) {
case GIT_TREEWALK_POST: case GIT_TREEWALK_POST:
return tree_walk_post(tree, callback, root_path, 0, payload); error = tree_walk_post(tree, callback, &root_path, payload);
break;
case GIT_TREEWALK_PRE: case GIT_TREEWALK_PRE:
return git__throw(GIT_ENOTIMPLEMENTED, error = git__throw(GIT_ENOTIMPLEMENTED,
"Preorder tree walking is still not implemented"); "Preorder tree walking is still not implemented");
break;
default: default:
return git__throw(GIT_EINVALIDARGS, error = git__throw(GIT_EINVALIDARGS,
"Invalid walking mode for tree walk"); "Invalid walking mode for tree walk");
break;
} }
git_buf_free(&root_path);
return error;
} }
...@@ -304,32 +304,37 @@ int p_hide_directory__w32(const char *path) ...@@ -304,32 +304,37 @@ int p_hide_directory__w32(const char *path)
char *p_realpath(const char *orig_path, char *buffer) char *p_realpath(const char *orig_path, char *buffer)
{ {
int ret, alloc = 0; int ret;
wchar_t* orig_path_w = gitwin_to_utf16(orig_path); wchar_t* orig_path_w = gitwin_to_utf16(orig_path);
wchar_t* buffer_w = (wchar_t*)git__malloc(GIT_PATH_MAX * sizeof(wchar_t)); wchar_t* buffer_w = (wchar_t*)git__malloc(GIT_PATH_MAX * sizeof(wchar_t));
if (buffer == NULL) {
buffer = (char *)git__malloc(GIT_PATH_MAX);
alloc = 1;
}
ret = GetFullPathNameW(orig_path_w, GIT_PATH_MAX, buffer_w, NULL); ret = GetFullPathNameW(orig_path_w, GIT_PATH_MAX, buffer_w, NULL);
git__free(orig_path_w); git__free(orig_path_w);
if (!ret || ret > GIT_PATH_MAX) { if (!ret || ret > GIT_PATH_MAX) {
git__free(buffer_w); buffer = NULL;
if (alloc) git__free(buffer); goto done;
return NULL;
} }
if (!WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, buffer, GIT_PATH_MAX, NULL, NULL)) { if (buffer == NULL) {
git__free(buffer_w); int buffer_sz = WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, NULL, 0, NULL, NULL);
if (alloc) git__free(buffer);
if (!buffer_sz ||
!(buffer = (char *)git__malloc(buffer_sz)) ||
!WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, buffer, buffer_sz, NULL, NULL))
{
git__free(buffer);
buffer = NULL;
}
} else {
if (!WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, buffer, GIT_PATH_MAX, NULL, NULL))
buffer = NULL;
} }
done:
git__free(buffer_w); git__free(buffer_w);
git_path_mkposix(buffer); if (buffer)
git_path_mkposix(buffer);
return buffer; return buffer;
} }
......
...@@ -111,6 +111,7 @@ extern void test_core_path__1(void); ...@@ -111,6 +111,7 @@ extern void test_core_path__1(void);
extern void test_core_path__2(void); extern void test_core_path__2(void);
extern void test_core_path__5(void); extern void test_core_path__5(void);
extern void test_core_path__6(void); extern void test_core_path__6(void);
extern void test_core_path__7(void);
extern void test_core_rmdir__delete_recursive(void); extern void test_core_rmdir__delete_recursive(void);
extern void test_core_rmdir__fail_to_delete_non_empty_dir(void); extern void test_core_rmdir__fail_to_delete_non_empty_dir(void);
extern void test_core_rmdir__initialize(void); extern void test_core_rmdir__initialize(void);
......
...@@ -42,4 +42,13 @@ GIT_INLINE(void) cl_assert_strequal_internal( ...@@ -42,4 +42,13 @@ GIT_INLINE(void) cl_assert_strequal_internal(
} }
} }
/*
* Some utility macros for building long strings
*/
#define REP4(STR) STR STR STR STR
#define REP15(STR) REP4(STR) REP4(STR) REP4(STR) STR STR STR
#define REP16(STR) REP4(REP4(STR))
#define REP256(STR) REP16(REP16(STR))
#define REP1024(STR) REP4(REP256(STR))
#endif #endif
...@@ -171,7 +171,8 @@ static const struct clay_func _clay_cb_core_path[] = { ...@@ -171,7 +171,8 @@ static const struct clay_func _clay_cb_core_path[] = {
{"1", &test_core_path__1}, {"1", &test_core_path__1},
{"2", &test_core_path__2}, {"2", &test_core_path__2},
{"5", &test_core_path__5}, {"5", &test_core_path__5},
{"6", &test_core_path__6} {"6", &test_core_path__6},
{"7", &test_core_path__7}
}; };
static const struct clay_func _clay_cb_core_rmdir[] = { static const struct clay_func _clay_cb_core_rmdir[] = {
{"delete_recursive", &test_core_rmdir__delete_recursive}, {"delete_recursive", &test_core_rmdir__delete_recursive},
...@@ -351,7 +352,7 @@ static const struct clay_suite _clay_suites[] = { ...@@ -351,7 +352,7 @@ static const struct clay_suite _clay_suites[] = {
"core::path", "core::path",
{NULL, NULL}, {NULL, NULL},
{NULL, NULL}, {NULL, NULL},
_clay_cb_core_path, 5 _clay_cb_core_path, 6
}, },
{ {
"core::rmdir", "core::rmdir",
...@@ -494,7 +495,7 @@ static const struct clay_suite _clay_suites[] = { ...@@ -494,7 +495,7 @@ static const struct clay_suite _clay_suites[] = {
}; };
static size_t _clay_suite_count = 34; static size_t _clay_suite_count = 34;
static size_t _clay_callback_count = 113; static size_t _clay_callback_count = 114;
/* Core test functions */ /* Core test functions */
static void static void
......
...@@ -5,9 +5,6 @@ ...@@ -5,9 +5,6 @@
const char *test_string = TESTSTR; const char *test_string = TESTSTR;
const char *test_string_x2 = TESTSTR TESTSTR; const char *test_string_x2 = TESTSTR TESTSTR;
#define REP4(STR) STR STR STR STR
#define REP16(STR) REP4(REP4(STR))
#define REP1024(STR) REP16(REP16(REP4(STR)))
#define TESTSTR_4096 REP1024("1234") #define TESTSTR_4096 REP1024("1234")
#define TESTSTR_8192 REP1024("12341234") #define TESTSTR_8192 REP1024("12341234")
const char *test_4096 = TESTSTR_4096; const char *test_4096 = TESTSTR_4096;
...@@ -52,7 +49,7 @@ void test_core_buffer__2(void) ...@@ -52,7 +49,7 @@ void test_core_buffer__2(void)
{ {
git_buf buf = GIT_BUF_INIT; git_buf buf = GIT_BUF_INIT;
int i; int i;
char data[100]; char data[128];
cl_assert(buf.size == 0); cl_assert(buf.size == 0);
...@@ -135,22 +132,28 @@ void test_core_buffer__2(void) ...@@ -135,22 +132,28 @@ void test_core_buffer__2(void)
git_buf_puts(&buf, REP4("0123456789")); git_buf_puts(&buf, REP4("0123456789"));
cl_assert(git_buf_oom(&buf) == 0); cl_assert(git_buf_oom(&buf) == 0);
git_buf_copy_cstr(data, 100, &buf); git_buf_copy_cstr(data, sizeof(data), &buf);
cl_assert_strequal(data, REP4("0123456789")); cl_assert_strequal(REP4("0123456789"), data);
git_buf_copy_cstr(data, 11, &buf); git_buf_copy_cstr(data, 11, &buf);
cl_assert_strequal(data, "0123456789"); cl_assert_strequal("0123456789", data);
git_buf_copy_cstr(data, 3, &buf); git_buf_copy_cstr(data, 3, &buf);
cl_assert_strequal(data, "01"); cl_assert_strequal("01", data);
git_buf_copy_cstr(data, 1, &buf); git_buf_copy_cstr(data, 1, &buf);
cl_assert_strequal(data, ""); cl_assert_strequal("", data);
git_buf_copy_cstr(data, 100, &buf); git_buf_copy_cstr(data, sizeof(data), &buf);
cl_assert_strequal(data, REP4("0123456789")); cl_assert_strequal(REP4("0123456789"), data);
git_buf_sets(&buf, REP256("x"));
git_buf_copy_cstr(data, sizeof(data), &buf);
/* since sizeof(data) == 128, only 127 bytes should be copied */
cl_assert_strequal(REP4(REP16("x")) REP16("x") REP16("x")
REP16("x") "xxxxxxxxxxxxxxx", data);
git_buf_free(&buf); git_buf_free(&buf);
git_buf_copy_cstr(data, 100, &buf); git_buf_copy_cstr(data, sizeof(data), &buf);
cl_assert_strequal(data, ""); cl_assert_strequal("", data);
} }
/* let's do some tests with larger buffers to push our limits */ /* let's do some tests with larger buffers to push our limits */
...@@ -340,9 +343,10 @@ void test_core_buffer__6(void) ...@@ -340,9 +343,10 @@ void test_core_buffer__6(void)
} }
/* test take cstr data */ /* test detach/attach data */
void test_core_buffer__7(void) void test_core_buffer__7(void)
{ {
const char *fun = "This is fun";
git_buf a = GIT_BUF_INIT; git_buf a = GIT_BUF_INIT;
char *b = NULL; char *b = NULL;
...@@ -350,18 +354,36 @@ void test_core_buffer__7(void) ...@@ -350,18 +354,36 @@ void test_core_buffer__7(void)
cl_assert(git_buf_oom(&a) == 0); cl_assert(git_buf_oom(&a) == 0);
cl_assert_strequal("foo", git_buf_cstr(&a)); cl_assert_strequal("foo", git_buf_cstr(&a));
b = git_buf_take_cstr(&a); b = git_buf_detach(&a);
cl_assert_strequal("foo", b); cl_assert_strequal("foo", b);
cl_assert_strequal("", a.ptr); cl_assert_strequal("", a.ptr);
git__free(b); git__free(b);
b = git_buf_take_cstr(&a); b = git_buf_detach(&a);
cl_assert_strequal(NULL, b); cl_assert_strequal(NULL, b);
cl_assert_strequal("", a.ptr); cl_assert_strequal("", a.ptr);
git_buf_free(&a); git_buf_free(&a);
b = git__strdup(fun);
git_buf_attach(&a, b, 0);
cl_assert_strequal(fun, a.ptr);
cl_assert(a.size == (ssize_t)strlen(fun));
cl_assert(a.asize == (ssize_t)strlen(fun) + 1);
git_buf_free(&a);
b = git__strdup(fun);
git_buf_attach(&a, b, strlen(fun) + 1);
cl_assert_strequal(fun, a.ptr);
cl_assert(a.size == (ssize_t)strlen(fun));
cl_assert(a.asize == (ssize_t)strlen(fun) + 1);
git_buf_free(&a);
} }
......
...@@ -9,10 +9,10 @@ typedef struct name_data { ...@@ -9,10 +9,10 @@ typedef struct name_data {
typedef struct walk_data { typedef struct walk_data {
char *sub; /* sub-directory name */ char *sub; /* sub-directory name */
name_data *names; /* name state data */ name_data *names; /* name state data */
git_buf path;
} walk_data; } walk_data;
static char path_buffer[GIT_PATH_MAX];
static char *top_dir = "dir-walk"; static char *top_dir = "dir-walk";
static walk_data *state_loc; static walk_data *state_loc;
...@@ -27,7 +27,8 @@ static void setup(walk_data *d) ...@@ -27,7 +27,8 @@ static void setup(walk_data *d)
if (strcmp(d->sub, ".") != 0) if (strcmp(d->sub, ".") != 0)
cl_must_pass(p_mkdir(d->sub, 0777)); cl_must_pass(p_mkdir(d->sub, 0777));
strcpy(path_buffer, d->sub); cl_git_pass(git_buf_sets(&d->path, d->sub));
state_loc = d; state_loc = d;
for (n = d->names; n->name; n++) { for (n = d->names; n->name; n++) {
...@@ -53,6 +54,8 @@ static void dirent_cleanup__cb(void *_d) ...@@ -53,6 +54,8 @@ static void dirent_cleanup__cb(void *_d)
cl_must_pass(p_chdir("..")); cl_must_pass(p_chdir(".."));
cl_must_pass(p_rmdir(top_dir)); cl_must_pass(p_rmdir(top_dir));
git_buf_free(&d->path);
} }
static void check_counts(walk_data *d) static void check_counts(walk_data *d)
...@@ -64,7 +67,7 @@ static void check_counts(walk_data *d) ...@@ -64,7 +67,7 @@ static void check_counts(walk_data *d)
} }
} }
static int one_entry(void *state, char *path) static int one_entry(void *state, git_buf *path)
{ {
walk_data *d = (walk_data *) state; walk_data *d = (walk_data *) state;
name_data *n; name_data *n;
...@@ -72,11 +75,11 @@ static int one_entry(void *state, char *path) ...@@ -72,11 +75,11 @@ static int one_entry(void *state, char *path)
if (state != state_loc) if (state != state_loc)
return GIT_ERROR; return GIT_ERROR;
if (path != path_buffer) if (path != &d->path)
return GIT_ERROR; return GIT_ERROR;
for (n = d->names; n->name; n++) { for (n = d->names; n->name; n++) {
if (!strcmp(n->name, path)) { if (!strcmp(n->name, path->ptr)) {
n->count++; n->count++;
return 0; return 0;
} }
...@@ -85,7 +88,7 @@ static int one_entry(void *state, char *path) ...@@ -85,7 +88,7 @@ static int one_entry(void *state, char *path)
return GIT_ERROR; return GIT_ERROR;
} }
static int dont_call_me(void *GIT_UNUSED(state), char *GIT_UNUSED(path)) static int dont_call_me(void *GIT_UNUSED(state), git_buf *GIT_UNUSED(path))
{ {
GIT_UNUSED_ARG(state) GIT_UNUSED_ARG(state)
GIT_UNUSED_ARG(path) GIT_UNUSED_ARG(path)
...@@ -102,7 +105,8 @@ static name_data dot_names[] = { ...@@ -102,7 +105,8 @@ static name_data dot_names[] = {
}; };
static walk_data dot = { static walk_data dot = {
".", ".",
dot_names dot_names,
GIT_BUF_INIT
}; };
/* make sure that the '.' folder is not traversed */ /* make sure that the '.' folder is not traversed */
...@@ -111,8 +115,7 @@ void test_core_dirent__dont_traverse_dot(void) ...@@ -111,8 +115,7 @@ void test_core_dirent__dont_traverse_dot(void)
cl_set_cleanup(&dirent_cleanup__cb, &dot); cl_set_cleanup(&dirent_cleanup__cb, &dot);
setup(&dot); setup(&dot);
cl_git_pass(git_futils_direach(path_buffer, cl_git_pass(git_futils_direach(&dot.path,
sizeof(path_buffer),
one_entry, one_entry,
&dot)); &dot));
...@@ -128,7 +131,8 @@ static name_data sub_names[] = { ...@@ -128,7 +131,8 @@ static name_data sub_names[] = {
}; };
static walk_data sub = { static walk_data sub = {
"sub", "sub",
sub_names sub_names,
GIT_BUF_INIT
}; };
/* traverse a subfolder */ /* traverse a subfolder */
...@@ -137,8 +141,7 @@ void test_core_dirent__traverse_subfolder(void) ...@@ -137,8 +141,7 @@ void test_core_dirent__traverse_subfolder(void)
cl_set_cleanup(&dirent_cleanup__cb, &sub); cl_set_cleanup(&dirent_cleanup__cb, &sub);
setup(&sub); setup(&sub);
cl_git_pass(git_futils_direach(path_buffer, cl_git_pass(git_futils_direach(&sub.path,
sizeof(path_buffer),
one_entry, one_entry,
&sub)); &sub));
...@@ -148,7 +151,8 @@ void test_core_dirent__traverse_subfolder(void) ...@@ -148,7 +151,8 @@ void test_core_dirent__traverse_subfolder(void)
static walk_data sub_slash = { static walk_data sub_slash = {
"sub/", "sub/",
sub_names sub_names,
GIT_BUF_INIT
}; };
/* traverse a slash-terminated subfolder */ /* traverse a slash-terminated subfolder */
...@@ -157,8 +161,7 @@ void test_core_dirent__traverse_slash_terminated_folder(void) ...@@ -157,8 +161,7 @@ void test_core_dirent__traverse_slash_terminated_folder(void)
cl_set_cleanup(&dirent_cleanup__cb, &sub_slash); cl_set_cleanup(&dirent_cleanup__cb, &sub_slash);
setup(&sub_slash); setup(&sub_slash);
cl_git_pass(git_futils_direach(path_buffer, cl_git_pass(git_futils_direach(&sub_slash.path,
sizeof(path_buffer),
one_entry, one_entry,
&sub_slash)); &sub_slash));
...@@ -171,7 +174,8 @@ static name_data empty_names[] = { ...@@ -171,7 +174,8 @@ static name_data empty_names[] = {
}; };
static walk_data empty = { static walk_data empty = {
"empty", "empty",
empty_names empty_names,
GIT_BUF_INIT
}; };
/* make sure that empty folders are not traversed */ /* make sure that empty folders are not traversed */
...@@ -180,16 +184,14 @@ void test_core_dirent__dont_traverse_empty_folders(void) ...@@ -180,16 +184,14 @@ void test_core_dirent__dont_traverse_empty_folders(void)
cl_set_cleanup(&dirent_cleanup__cb, &empty); cl_set_cleanup(&dirent_cleanup__cb, &empty);
setup(&empty); setup(&empty);
cl_git_pass(git_futils_direach(path_buffer, cl_git_pass(git_futils_direach(&empty.path,
sizeof(path_buffer),
one_entry, one_entry,
&empty)); &empty));
check_counts(&empty); check_counts(&empty);
/* make sure callback not called */ /* make sure callback not called */
cl_git_pass(git_futils_direach(path_buffer, cl_git_pass(git_futils_direach(&empty.path,
sizeof(path_buffer),
dont_call_me, dont_call_me,
&empty)); &empty));
} }
...@@ -204,7 +206,8 @@ static name_data odd_names[] = { ...@@ -204,7 +206,8 @@ static name_data odd_names[] = {
}; };
static walk_data odd = { static walk_data odd = {
"odd", "odd",
odd_names odd_names,
GIT_BUF_INIT
}; };
/* make sure that strange looking filenames ('..c') are traversed */ /* make sure that strange looking filenames ('..c') are traversed */
...@@ -213,8 +216,7 @@ void test_core_dirent__traverse_weird_filenames(void) ...@@ -213,8 +216,7 @@ void test_core_dirent__traverse_weird_filenames(void)
cl_set_cleanup(&dirent_cleanup__cb, &odd); cl_set_cleanup(&dirent_cleanup__cb, &odd);
setup(&odd); setup(&odd);
cl_git_pass(git_futils_direach(path_buffer, cl_git_pass(git_futils_direach(&odd.path,
sizeof(path_buffer),
one_entry, one_entry,
&odd)); &odd));
......
...@@ -4,26 +4,30 @@ ...@@ -4,26 +4,30 @@
static void static void
check_dirname(const char *A, const char *B) check_dirname(const char *A, const char *B)
{ {
char dir[64], *dir2; git_buf dir = GIT_BUF_INIT;
char *dir2;
cl_assert(git_path_dirname_r(dir, sizeof(dir), A) >= 0); cl_assert(git_path_dirname_r(&dir, A) >= 0);
cl_assert(strcmp(dir, B) == 0); cl_assert_strequal(B, dir.ptr);
cl_assert((dir2 = git_path_dirname(A)) != NULL); git_buf_free(&dir);
cl_assert(strcmp(dir2, B) == 0);
cl_assert((dir2 = git_path_dirname(A)) != NULL);
cl_assert_strequal(B, dir2);
git__free(dir2); git__free(dir2);
} }
static void static void
check_basename(const char *A, const char *B) check_basename(const char *A, const char *B)
{ {
char base[64], *base2; git_buf base = GIT_BUF_INIT;
char *base2;
cl_assert(git_path_basename_r(base, sizeof(base), A) >= 0); cl_assert(git_path_basename_r(&base, A) >= 0);
cl_assert(strcmp(base, B) == 0); cl_assert_strequal(B, base.ptr);
cl_assert((base2 = git_path_basename(A)) != NULL); git_buf_free(&base);
cl_assert(strcmp(base2, B) == 0);
cl_assert((base2 = git_path_basename(A)) != NULL);
cl_assert_strequal(B, base2);
git__free(base2); git__free(base2);
} }
...@@ -33,16 +37,18 @@ check_topdir(const char *A, const char *B) ...@@ -33,16 +37,18 @@ check_topdir(const char *A, const char *B)
const char *dir; const char *dir;
cl_assert((dir = git_path_topdir(A)) != NULL); cl_assert((dir = git_path_topdir(A)) != NULL);
cl_assert(strcmp(dir, B) == 0); cl_assert_strequal(B, dir);
} }
static void static void
check_joinpath(const char *path_a, const char *path_b, const char *expected_path) check_joinpath(const char *path_a, const char *path_b, const char *expected_path)
{ {
char joined_path[GIT_PATH_MAX]; git_buf joined_path = GIT_BUF_INIT;
git_path_join(joined_path, path_a, path_b); cl_git_pass(git_buf_joinpath(&joined_path, path_a, path_b));
cl_assert(strcmp(joined_path, expected_path) == 0); cl_assert_strequal(expected_path, joined_path.ptr);
git_buf_free(&joined_path);
} }
static void static void
...@@ -53,17 +59,19 @@ check_joinpath_n( ...@@ -53,17 +59,19 @@ check_joinpath_n(
const char *path_d, const char *path_d,
const char *expected_path) const char *expected_path)
{ {
char joined_path[GIT_PATH_MAX]; git_buf joined_path = GIT_BUF_INIT;
cl_git_pass(git_buf_join_n(&joined_path, '/', 4,
path_a, path_b, path_c, path_d));
cl_assert_strequal(expected_path, joined_path.ptr);
git_path_join_n(joined_path, 4, path_a, path_b, path_c, path_d); git_buf_free(&joined_path);
cl_assert(strcmp(joined_path, expected_path) == 0);
} }
/* get the dirname of a path */ /* get the dirname of a path */
void test_core_path__0(void) void test_core_path__0(void)
{ {
check_dirname(NULL, "."); check_dirname(NULL, ".");
check_dirname("", "."); check_dirname("", ".");
check_dirname("a", "."); check_dirname("a", ".");
...@@ -77,6 +85,8 @@ void test_core_path__0(void) ...@@ -77,6 +85,8 @@ void test_core_path__0(void)
check_dirname("usr/lib/", "usr"); check_dirname("usr/lib/", "usr");
check_dirname("usr/lib//", "usr"); check_dirname("usr/lib//", "usr");
check_dirname(".git/", "."); check_dirname(".git/", ".");
check_dirname(REP16("/abc"), REP15("/abc"));
} }
/* get the base name of a path */ /* get the base name of a path */
...@@ -91,6 +101,9 @@ void test_core_path__1(void) ...@@ -91,6 +101,9 @@ void test_core_path__1(void)
check_basename("/usr/lib", "lib"); check_basename("/usr/lib", "lib");
check_basename("/usr/lib//", "lib"); check_basename("/usr/lib//", "lib");
check_basename("usr/lib", "lib"); check_basename("usr/lib", "lib");
check_basename(REP16("/abc"), "abc");
check_basename(REP1024("/abc"), "abc");
} }
/* get the latest component in a path */ /* get the latest component in a path */
...@@ -125,6 +138,20 @@ void test_core_path__5(void) ...@@ -125,6 +138,20 @@ void test_core_path__5(void)
check_joinpath("/a", "/b/", "/a/b/"); check_joinpath("/a", "/b/", "/a/b/");
check_joinpath("/a/", "b/", "/a/b/"); check_joinpath("/a/", "b/", "/a/b/");
check_joinpath("/a/", "/b/", "/a/b/"); check_joinpath("/a/", "/b/", "/a/b/");
check_joinpath("/abcd", "/defg", "/abcd/defg");
check_joinpath("/abcd", "/defg/", "/abcd/defg/");
check_joinpath("/abcd/", "defg/", "/abcd/defg/");
check_joinpath("/abcd/", "/defg/", "/abcd/defg/");
check_joinpath("/abcdefgh", "/12345678", "/abcdefgh/12345678");
check_joinpath("/abcdefgh", "/12345678/", "/abcdefgh/12345678/");
check_joinpath("/abcdefgh/", "12345678/", "/abcdefgh/12345678/");
check_joinpath(REP1024("aaaa"), REP1024("bbbb"),
REP1024("aaaa") "/" REP1024("bbbb"));
check_joinpath(REP1024("/aaaa"), REP1024("/bbbb"),
REP1024("/aaaa") REP1024("/bbbb"));
} }
/* properly join path components for more than one path */ /* properly join path components for more than one path */
...@@ -136,4 +163,74 @@ void test_core_path__6(void) ...@@ -136,4 +163,74 @@ void test_core_path__6(void)
check_joinpath_n("", "", "", "a", "a"); check_joinpath_n("", "", "", "a", "a");
check_joinpath_n("a", "b", "", "/c/d/", "a/b/c/d/"); check_joinpath_n("a", "b", "", "/c/d/", "a/b/c/d/");
check_joinpath_n("a", "b", "", "/c/d", "a/b/c/d"); check_joinpath_n("a", "b", "", "/c/d", "a/b/c/d");
check_joinpath_n("abcd", "efgh", "ijkl", "mnop", "abcd/efgh/ijkl/mnop");
check_joinpath_n("abcd/", "efgh/", "ijkl/", "mnop/", "abcd/efgh/ijkl/mnop/");
check_joinpath_n("/abcd/", "/efgh/", "/ijkl/", "/mnop/", "/abcd/efgh/ijkl/mnop/");
check_joinpath_n(REP1024("a"), REP1024("b"), REP1024("c"), REP1024("d"),
REP1024("a") "/" REP1024("b") "/"
REP1024("c") "/" REP1024("d"));
check_joinpath_n(REP1024("/a"), REP1024("/b"), REP1024("/c"), REP1024("/d"),
REP1024("/a") REP1024("/b")
REP1024("/c") REP1024("/d"));
}
static void
check_path_to_dir(
const char* path,
const char* expected)
{
git_buf tgt = GIT_BUF_INIT;
git_buf_sets(&tgt, path);
cl_git_pass(git_path_to_dir(&tgt));
cl_assert_strequal(expected, tgt.ptr);
git_buf_free(&tgt);
}
static void
check_string_to_dir(
const char* path,
int maxlen,
const char* expected)
{
int len = strlen(path);
char *buf = git__malloc(len + 2);
strncpy(buf, path, len + 2);
git_path_string_to_dir(buf, maxlen);
cl_assert_strequal(expected, buf);
git__free(buf);
}
/* convert paths to dirs */
void test_core_path__7(void)
{
check_path_to_dir("", "");
check_path_to_dir(".", "./");
check_path_to_dir("./", "./");
check_path_to_dir("a/", "a/");
check_path_to_dir("ab", "ab/");
/* make sure we try just under and just over an expansion that will
* require a realloc
*/
check_path_to_dir("abcdef", "abcdef/");
check_path_to_dir("abcdefg", "abcdefg/");
check_path_to_dir("abcdefgh", "abcdefgh/");
check_path_to_dir("abcdefghi", "abcdefghi/");
check_path_to_dir(REP1024("abcd") "/", REP1024("abcd") "/");
check_path_to_dir(REP1024("abcd"), REP1024("abcd") "/");
check_string_to_dir("", 1, "");
check_string_to_dir(".", 1, ".");
check_string_to_dir(".", 2, "./");
check_string_to_dir(".", 3, "./");
check_string_to_dir("abcd", 3, "abcd");
check_string_to_dir("abcd", 4, "abcd");
check_string_to_dir("abcd", 5, "abcd/");
check_string_to_dir("abcd", 6, "abcd/");
} }
...@@ -5,24 +5,26 @@ static const char *empty_tmp_dir = "test_gitfo_rmdir_recurs_test"; ...@@ -5,24 +5,26 @@ static const char *empty_tmp_dir = "test_gitfo_rmdir_recurs_test";
void test_core_rmdir__initialize(void) void test_core_rmdir__initialize(void)
{ {
char path[GIT_PATH_MAX]; git_buf path = GIT_BUF_INIT;
cl_must_pass(p_mkdir(empty_tmp_dir, 0777)); cl_must_pass(p_mkdir(empty_tmp_dir, 0777));
git_path_join(path, empty_tmp_dir, "/one"); cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/one"));
cl_must_pass(p_mkdir(path, 0777)); cl_must_pass(p_mkdir(path.ptr, 0777));
git_path_join(path, empty_tmp_dir, "/one/two_one"); cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/one/two_one"));
cl_must_pass(p_mkdir(path, 0777)); cl_must_pass(p_mkdir(path.ptr, 0777));
git_path_join(path, empty_tmp_dir, "/one/two_two"); cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/one/two_two"));
cl_must_pass(p_mkdir(path, 0777)); cl_must_pass(p_mkdir(path.ptr, 0777));
git_path_join(path, empty_tmp_dir, "/one/two_two/three"); cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/one/two_two/three"));
cl_must_pass(p_mkdir(path, 0777)); cl_must_pass(p_mkdir(path.ptr, 0777));
git_path_join(path, empty_tmp_dir, "/two"); cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/two"));
cl_must_pass(p_mkdir(path, 0777)); cl_must_pass(p_mkdir(path.ptr, 0777));
git_buf_free(&path);
} }
/* make sure empty dir can be deleted recusively */ /* make sure empty dir can be deleted recusively */
...@@ -34,17 +36,19 @@ void test_core_rmdir__delete_recursive(void) ...@@ -34,17 +36,19 @@ void test_core_rmdir__delete_recursive(void)
/* make sure non-empty dir cannot be deleted recusively */ /* make sure non-empty dir cannot be deleted recusively */
void test_core_rmdir__fail_to_delete_non_empty_dir(void) void test_core_rmdir__fail_to_delete_non_empty_dir(void)
{ {
char file[GIT_PATH_MAX]; git_buf file = GIT_BUF_INIT;
int fd; int fd;
git_path_join(file, empty_tmp_dir, "/two/file.txt"); cl_git_pass(git_buf_joinpath(&file, empty_tmp_dir, "/two/file.txt"));
fd = p_creat(file, 0666); fd = p_creat(file.ptr, 0666);
cl_assert(fd >= 0); cl_assert(fd >= 0);
cl_must_pass(p_close(fd)); cl_must_pass(p_close(fd));
cl_git_fail(git_futils_rmdir_r(empty_tmp_dir, 0)); cl_git_fail(git_futils_rmdir_r(empty_tmp_dir, 0));
cl_must_pass(p_unlink(file)); cl_must_pass(p_unlink(file.ptr));
cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, 0)); cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, 0));
git_buf_free(&file);
} }
...@@ -77,17 +77,19 @@ void test_repo_init__bare_repo_noslash(void) ...@@ -77,17 +77,19 @@ void test_repo_init__bare_repo_noslash(void)
#if 0 #if 0
BEGIN_TEST(init2, "Initialize and open a bare repo with a relative path escaping out of the current working directory") BEGIN_TEST(init2, "Initialize and open a bare repo with a relative path escaping out of the current working directory")
char path_repository[GIT_PATH_MAX]; git_buf path_repository = GIT_BUF_INIT;
char current_workdir[GIT_PATH_MAX]; char current_workdir[GIT_PATH_MAX];
const mode_t mode = 0777; const mode_t mode = 0777;
git_repository* repo; git_repository* repo;
must_pass(p_getcwd(current_workdir, sizeof(current_workdir))); must_pass(p_getcwd(current_workdir, sizeof(current_workdir)));
git_path_join(path_repository, TEMP_REPO_FOLDER, "a/b/c/"); must_pass(git_buf_joinpath(&path_repository, TEMP_REPO_FOLDER, "a/b/c/"));
must_pass(git_futils_mkdir_r(path_repository, mode)); must_pass(git_futils_mkdir_r(path_repository.ptr, mode));
must_pass(chdir(path_repository)); must_pass(chdir(path_repository.ptr));
git_buf_free(&path_repository);
must_pass(git_repository_init(&repo, "../d/e.git", 1)); must_pass(git_repository_init(&repo, "../d/e.git", 1));
must_pass(git__suffixcmp(git_repository_path(_repo), "/a/b/d/e.git/")); must_pass(git__suffixcmp(git_repository_path(_repo), "/a/b/d/e.git/"));
......
...@@ -26,23 +26,24 @@ void test_repo_open__standard_empty_repo(void) ...@@ -26,23 +26,24 @@ void test_repo_open__standard_empty_repo(void)
/* TODO TODO */ /* TODO TODO */
#if 0 #if 0
BEGIN_TEST(open2, "Open a bare repository with a relative path escaping out of the current working directory") BEGIN_TEST(open2, "Open a bare repository with a relative path escaping out of the current working directory")
char new_current_workdir[GIT_PATH_MAX];
char current_workdir[GIT_PATH_MAX]; char current_workdir[GIT_PATH_MAX];
char path_repository[GIT_PATH_MAX]; git_buf new_current_workdir = GIT_BUF_INIT;
git_buf path_repository = GIT_BUF_INIT;
const mode_t mode = 0777; const mode_t mode = 0777;
git_repository* repo; git_repository* repo;
/* Setup the repository to open */ /* Setup the repository to open */
must_pass(p_getcwd(current_workdir, sizeof(current_workdir))); must_pass(p_getcwd(current_workdir, sizeof(current_workdir)));
strcpy(path_repository, current_workdir); must_pass(git_buf_join_n(&path_repository, 3, current_workdir, TEMP_REPO_FOLDER, "a/d/e.git"));
git_path_join_n(path_repository, 3, path_repository, TEMP_REPO_FOLDER, "a/d/e.git"); must_pass(copydir_recurs(REPOSITORY_FOLDER, path_repository.ptr));
must_pass(copydir_recurs(REPOSITORY_FOLDER, path_repository)); git_buf_free(&path_repository);
/* Change the current working directory */ /* Change the current working directory */
git_path_join(new_current_workdir, TEMP_REPO_FOLDER, "a/b/c/"); must_pass(git_buf_joinpath(&new_current_workdir, TEMP_REPO_FOLDER, "a/b/c/"));
must_pass(git_futils_mkdir_r(new_current_workdir, mode)); must_pass(git_futils_mkdir_r(new_current_workdir.ptr, mode));
must_pass(chdir(new_current_workdir)); must_pass(chdir(new_current_workdir.ptr));
git_buf_free(&new_current_workdir);
must_pass(git_repository_open(&repo, "../../d/e.git")); must_pass(git_repository_open(&repo, "../../d/e.git"));
......
...@@ -105,14 +105,15 @@ END_TEST ...@@ -105,14 +105,15 @@ END_TEST
BEGIN_TEST(path0, "get the dirname of a path") BEGIN_TEST(path0, "get the dirname of a path")
char dir[64], *dir2; git_buf dir = GIT_BUF_INIT;
char *dir2;
#define DIRNAME_TEST(A, B) { \ #define DIRNAME_TEST(A, B) { \
must_be_true(git_path_dirname_r(dir, sizeof(dir), A) >= 0); \ must_be_true(git_path_dirname_r(&dir, A) >= 0); \
must_be_true(strcmp(dir, B) == 0); \ must_be_true(strcmp(B, dir.ptr) == 0); \
must_be_true((dir2 = git_path_dirname(A)) != NULL); \ must_be_true((dir2 = git_path_dirname(A)) != NULL); \
must_be_true(strcmp(dir2, B) == 0); \ must_be_true(strcmp(dir2, B) == 0); \
git__free(dir2); \ git__free(dir2); \
} }
DIRNAME_TEST(NULL, "."); DIRNAME_TEST(NULL, ".");
...@@ -131,16 +132,18 @@ BEGIN_TEST(path0, "get the dirname of a path") ...@@ -131,16 +132,18 @@ BEGIN_TEST(path0, "get the dirname of a path")
#undef DIRNAME_TEST #undef DIRNAME_TEST
git_buf_free(&dir);
END_TEST END_TEST
BEGIN_TEST(path1, "get the base name of a path") BEGIN_TEST(path1, "get the base name of a path")
char base[64], *base2; git_buf base = GIT_BUF_INIT;
char *base2;
#define BASENAME_TEST(A, B) { \ #define BASENAME_TEST(A, B) { \
must_be_true(git_path_basename_r(base, sizeof(base), A) >= 0); \ must_be_true(git_path_basename_r(&base, A) >= 0); \
must_be_true(strcmp(base, B) == 0); \ must_be_true(strcmp(B, base.ptr) == 0); \
must_be_true((base2 = git_path_basename(A)) != NULL); \ must_be_true((base2 = git_path_basename(A)) != NULL); \
must_be_true(strcmp(base2, B) == 0); \ must_be_true(strcmp(base2, B) == 0); \
git__free(base2); \ git__free(base2); \
} }
...@@ -156,6 +159,7 @@ BEGIN_TEST(path1, "get the base name of a path") ...@@ -156,6 +159,7 @@ BEGIN_TEST(path1, "get the base name of a path")
#undef BASENAME_TEST #undef BASENAME_TEST
git_buf_free(&base);
END_TEST END_TEST
BEGIN_TEST(path2, "get the latest component in a path") BEGIN_TEST(path2, "get the latest component in a path")
...@@ -184,9 +188,13 @@ END_TEST ...@@ -184,9 +188,13 @@ END_TEST
static int ensure_joinpath(const char *path_a, const char *path_b, const char *expected_path) static int ensure_joinpath(const char *path_a, const char *path_b, const char *expected_path)
{ {
char joined_path[GIT_PATH_MAX]; int error = GIT_SUCCESS;
git_path_join(joined_path, path_a, path_b); git_buf joined_path = GIT_BUF_INIT;
return strcmp(joined_path, expected_path) == 0 ? GIT_SUCCESS : GIT_ERROR; if (!(error = git_buf_joinpath(&joined_path, path_a, path_b)))
error = strcmp(joined_path.ptr, expected_path) == 0 ?
GIT_SUCCESS : GIT_ERROR;
git_buf_free(&joined_path);
return error;
} }
BEGIN_TEST(path5, "properly join path components") BEGIN_TEST(path5, "properly join path components")
...@@ -206,9 +214,14 @@ END_TEST ...@@ -206,9 +214,14 @@ END_TEST
static int ensure_joinpath_n(const char *path_a, const char *path_b, const char *path_c, const char *path_d, const char *expected_path) static int ensure_joinpath_n(const char *path_a, const char *path_b, const char *path_c, const char *path_d, const char *expected_path)
{ {
char joined_path[GIT_PATH_MAX]; int error = GIT_SUCCESS;
git_path_join_n(joined_path, 4, path_a, path_b, path_c, path_d); git_buf joined_path = GIT_BUF_INIT;
return strcmp(joined_path, expected_path) == 0 ? GIT_SUCCESS : GIT_ERROR; if (!(error = git_buf_join_n(&joined_path, '/', 4,
path_a, path_b, path_c, path_d)))
error = strcmp(joined_path.ptr, expected_path) == 0 ?
GIT_SUCCESS : GIT_ERROR;
git_buf_free(&joined_path);
return error;
} }
BEGIN_TEST(path6, "properly join path components for more than one path") BEGIN_TEST(path6, "properly join path components for more than one path")
...@@ -228,10 +241,10 @@ typedef struct name_data { ...@@ -228,10 +241,10 @@ typedef struct name_data {
typedef struct walk_data { typedef struct walk_data {
char *sub; /* sub-directory name */ char *sub; /* sub-directory name */
name_data *names; /* name state data */ name_data *names; /* name state data */
git_buf path; /* buffer to store path */
} walk_data; } walk_data;
static char path_buffer[GIT_PATH_MAX];
static char *top_dir = "dir-walk"; static char *top_dir = "dir-walk";
static walk_data *state_loc; static walk_data *state_loc;
...@@ -260,7 +273,9 @@ static int setup(walk_data *d) ...@@ -260,7 +273,9 @@ static int setup(walk_data *d)
if (p_mkdir(d->sub, 0777) < 0) if (p_mkdir(d->sub, 0777) < 0)
return error("can't mkdir(\"%s\")", d->sub); return error("can't mkdir(\"%s\")", d->sub);
strcpy(path_buffer, d->sub); if (git_buf_sets(&d->path, d->sub) < 0)
return error("can't allocate space for \"%s\"", d->sub);
state_loc = d; state_loc = d;
for (n = d->names; n->name; n++) { for (n = d->names; n->name; n++) {
...@@ -278,6 +293,8 @@ static int knockdown(walk_data *d) ...@@ -278,6 +293,8 @@ static int knockdown(walk_data *d)
{ {
name_data *n; name_data *n;
git_buf_free(&d->path);
for (n = d->names; n->name; n++) { for (n = d->names; n->name; n++) {
if (p_unlink(n->name) < 0) if (p_unlink(n->name) < 0)
return error("can't unlink(\"%s\")", n->name); return error("can't unlink(\"%s\")", n->name);
...@@ -308,7 +325,7 @@ static int check_counts(walk_data *d) ...@@ -308,7 +325,7 @@ static int check_counts(walk_data *d)
return ret; return ret;
} }
static int one_entry(void *state, char *path) static int one_entry(void *state, git_buf *path)
{ {
walk_data *d = (walk_data *) state; walk_data *d = (walk_data *) state;
name_data *n; name_data *n;
...@@ -316,11 +333,11 @@ static int one_entry(void *state, char *path) ...@@ -316,11 +333,11 @@ static int one_entry(void *state, char *path)
if (state != state_loc) if (state != state_loc)
return GIT_ERROR; return GIT_ERROR;
if (path != path_buffer) if (path != &d->path)
return GIT_ERROR; return GIT_ERROR;
for (n = d->names; n->name; n++) { for (n = d->names; n->name; n++) {
if (!strcmp(n->name, path)) { if (!strcmp(n->name, path->ptr)) {
n->count++; n->count++;
return 0; return 0;
} }
...@@ -338,15 +355,14 @@ static name_data dot_names[] = { ...@@ -338,15 +355,14 @@ static name_data dot_names[] = {
}; };
static walk_data dot = { static walk_data dot = {
".", ".",
dot_names dot_names,
GIT_BUF_INIT
}; };
BEGIN_TEST(dirent0, "make sure that the '.' folder is not traversed") BEGIN_TEST(dirent0, "make sure that the '.' folder is not traversed")
must_pass(setup(&dot)); must_pass(setup(&dot));
must_pass(git_futils_direach(path_buffer, must_pass(git_futils_direach(&dot.path,
sizeof(path_buffer),
one_entry, one_entry,
&dot)); &dot));
...@@ -363,15 +379,15 @@ static name_data sub_names[] = { ...@@ -363,15 +379,15 @@ static name_data sub_names[] = {
}; };
static walk_data sub = { static walk_data sub = {
"sub", "sub",
sub_names sub_names,
GIT_BUF_INIT
}; };
BEGIN_TEST(dirent1, "traverse a subfolder") BEGIN_TEST(dirent1, "traverse a subfolder")
must_pass(setup(&sub)); must_pass(setup(&sub));
must_pass(git_futils_direach(path_buffer, must_pass(git_futils_direach(&sub.path,
sizeof(path_buffer),
one_entry, one_entry,
&sub)); &sub));
...@@ -382,15 +398,15 @@ END_TEST ...@@ -382,15 +398,15 @@ END_TEST
static walk_data sub_slash = { static walk_data sub_slash = {
"sub/", "sub/",
sub_names sub_names,
GIT_BUF_INIT
}; };
BEGIN_TEST(dirent2, "traverse a slash-terminated subfolder") BEGIN_TEST(dirent2, "traverse a slash-terminated subfolder")
must_pass(setup(&sub_slash)); must_pass(setup(&sub_slash));
must_pass(git_futils_direach(path_buffer, must_pass(git_futils_direach(&sub_slash.path,
sizeof(path_buffer),
one_entry, one_entry,
&sub_slash)); &sub_slash));
...@@ -404,10 +420,11 @@ static name_data empty_names[] = { ...@@ -404,10 +420,11 @@ static name_data empty_names[] = {
}; };
static walk_data empty = { static walk_data empty = {
"empty", "empty",
empty_names empty_names,
GIT_BUF_INIT
}; };
static int dont_call_me(void *GIT_UNUSED(state), char *GIT_UNUSED(path)) static int dont_call_me(void *GIT_UNUSED(state), git_buf *GIT_UNUSED(path))
{ {
GIT_UNUSED_ARG(state) GIT_UNUSED_ARG(state)
GIT_UNUSED_ARG(path) GIT_UNUSED_ARG(path)
...@@ -418,16 +435,14 @@ BEGIN_TEST(dirent3, "make sure that empty folders are not traversed") ...@@ -418,16 +435,14 @@ BEGIN_TEST(dirent3, "make sure that empty folders are not traversed")
must_pass(setup(&empty)); must_pass(setup(&empty));
must_pass(git_futils_direach(path_buffer, must_pass(git_futils_direach(&empty.path,
sizeof(path_buffer),
one_entry, one_entry,
&empty)); &empty));
must_pass(check_counts(&empty)); must_pass(check_counts(&empty));
/* make sure callback not called */ /* make sure callback not called */
must_pass(git_futils_direach(path_buffer, must_pass(git_futils_direach(&empty.path,
sizeof(path_buffer),
dont_call_me, dont_call_me,
&empty)); &empty));
...@@ -444,15 +459,15 @@ static name_data odd_names[] = { ...@@ -444,15 +459,15 @@ static name_data odd_names[] = {
}; };
static walk_data odd = { static walk_data odd = {
"odd", "odd",
odd_names odd_names,
GIT_BUF_INIT
}; };
BEGIN_TEST(dirent4, "make sure that strange looking filenames ('..c') are traversed") BEGIN_TEST(dirent4, "make sure that strange looking filenames ('..c') are traversed")
must_pass(setup(&odd)); must_pass(setup(&odd));
must_pass(git_futils_direach(path_buffer, must_pass(git_futils_direach(&odd.path,
sizeof(path_buffer),
one_entry, one_entry,
&odd)); &odd));
...@@ -508,32 +523,24 @@ static char *empty_tmp_dir = "test_gitfo_rmdir_recurs_test"; ...@@ -508,32 +523,24 @@ static char *empty_tmp_dir = "test_gitfo_rmdir_recurs_test";
static int setup_empty_tmp_dir(void) static int setup_empty_tmp_dir(void)
{ {
char path[GIT_PATH_MAX]; git_buf path = GIT_BUF_INIT;
if (p_mkdir(empty_tmp_dir, 0777)) int error =
return -1; p_mkdir(empty_tmp_dir, 0777) ||
git_buf_joinpath(&path, empty_tmp_dir, "/one") ||
git_path_join(path, empty_tmp_dir, "/one"); p_mkdir(path.ptr, 0777) ||
if (p_mkdir(path, 0777)) git_buf_joinpath(&path, empty_tmp_dir, "/one/two_one") ||
return -1; p_mkdir(path.ptr, 0777) ||
git_buf_joinpath(&path, empty_tmp_dir, "/one/two_two") ||
git_path_join(path, empty_tmp_dir, "/one/two_one"); p_mkdir(path.ptr, 0777) ||
if (p_mkdir(path, 0777)) git_buf_joinpath(&path, empty_tmp_dir, "/one/two_two/three") ||
return -1; p_mkdir(path.ptr, 0777) ||
git_buf_joinpath(&path, empty_tmp_dir, "/two") ||
git_path_join(path, empty_tmp_dir, "/one/two_two"); p_mkdir(path.ptr, 0777);
if (p_mkdir(path, 0777))
return -1; git_buf_free(&path);
git_path_join(path, empty_tmp_dir, "/one/two_two/three"); return error ? -1 : 0;
if (p_mkdir(path, 0777))
return -1;
git_path_join(path, empty_tmp_dir, "/two");
if (p_mkdir(path, 0777))
return -1;
return 0;
} }
BEGIN_TEST(rmdir0, "make sure empty dir can be deleted recusively") BEGIN_TEST(rmdir0, "make sure empty dir can be deleted recusively")
...@@ -542,17 +549,18 @@ BEGIN_TEST(rmdir0, "make sure empty dir can be deleted recusively") ...@@ -542,17 +549,18 @@ BEGIN_TEST(rmdir0, "make sure empty dir can be deleted recusively")
END_TEST END_TEST
BEGIN_TEST(rmdir1, "make sure non-empty dir cannot be deleted recusively") BEGIN_TEST(rmdir1, "make sure non-empty dir cannot be deleted recusively")
char file[GIT_PATH_MAX]; git_buf file = GIT_BUF_INIT;
int fd; int fd;
must_pass(setup_empty_tmp_dir()); must_pass(setup_empty_tmp_dir());
git_path_join(file, empty_tmp_dir, "/two/file.txt"); must_pass(git_buf_joinpath(&file, empty_tmp_dir, "/two/file.txt"));
fd = p_creat(file, 0777); fd = p_creat(file.ptr, 0777);
must_pass(fd); must_pass(fd);
must_pass(p_close(fd)); must_pass(p_close(fd));
must_fail(git_futils_rmdir_r(empty_tmp_dir, 0)); must_fail(git_futils_rmdir_r(empty_tmp_dir, 0));
must_pass(p_unlink(file)); must_pass(p_unlink(file.ptr));
must_pass(git_futils_rmdir_r(empty_tmp_dir, 0)); must_pass(git_futils_rmdir_r(empty_tmp_dir, 0));
git_buf_free(&file);
END_TEST END_TEST
BEGIN_TEST(strtol0, "parsing out 32 integers from a string") BEGIN_TEST(strtol0, "parsing out 32 integers from a string")
......
...@@ -37,7 +37,7 @@ BEGIN_TEST(readtag0, "lookup a loose tag reference") ...@@ -37,7 +37,7 @@ BEGIN_TEST(readtag0, "lookup a loose tag reference")
git_repository *repo; git_repository *repo;
git_reference *reference; git_reference *reference;
git_object *object; git_object *object;
char ref_name_from_tag_name[GIT_REFNAME_MAX]; git_buf ref_name_from_tag_name = GIT_BUF_INIT;
must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
...@@ -51,8 +51,9 @@ BEGIN_TEST(readtag0, "lookup a loose tag reference") ...@@ -51,8 +51,9 @@ BEGIN_TEST(readtag0, "lookup a loose tag reference")
must_be_true(git_object_type(object) == GIT_OBJ_TAG); must_be_true(git_object_type(object) == GIT_OBJ_TAG);
/* Ensure the name of the tag matches the name of the reference */ /* Ensure the name of the tag matches the name of the reference */
git_path_join(ref_name_from_tag_name, GIT_REFS_TAGS_DIR, git_tag_name((git_tag *)object)); must_pass(git_buf_joinpath(&ref_name_from_tag_name, GIT_REFS_TAGS_DIR, git_tag_name((git_tag *)object)));
must_be_true(strcmp(ref_name_from_tag_name, loose_tag_ref_name) == 0); must_be_true(strcmp(ref_name_from_tag_name.ptr, loose_tag_ref_name) == 0);
git_buf_free(&ref_name_from_tag_name);
git_object_free(object); git_object_free(object);
git_repository_free(repo); git_repository_free(repo);
...@@ -227,7 +228,7 @@ BEGIN_TEST(create0, "create a new symbolic reference") ...@@ -227,7 +228,7 @@ BEGIN_TEST(create0, "create a new symbolic reference")
git_reference *new_reference, *looked_up_ref, *resolved_ref; git_reference *new_reference, *looked_up_ref, *resolved_ref;
git_repository *repo, *repo2; git_repository *repo, *repo2;
git_oid id; git_oid id;
char ref_path[GIT_PATH_MAX]; git_buf ref_path = GIT_BUF_INIT;
const char *new_head_tracker = "another-head-tracker"; const char *new_head_tracker = "another-head-tracker";
...@@ -236,7 +237,8 @@ BEGIN_TEST(create0, "create a new symbolic reference") ...@@ -236,7 +237,8 @@ BEGIN_TEST(create0, "create a new symbolic reference")
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
/* Retrieve the physical path to the symbolic ref for further cleaning */ /* Retrieve the physical path to the symbolic ref for further cleaning */
git_path_join(ref_path, repo->path_repository, new_head_tracker); must_pass(git_buf_joinpath(&ref_path, repo->path_repository, new_head_tracker));
git_buf_free(&ref_path);
/* Create and write the new symbolic reference */ /* Create and write the new symbolic reference */
must_pass(git_reference_create_symbolic(&new_reference, repo, new_head_tracker, current_head_target, 0)); must_pass(git_reference_create_symbolic(&new_reference, repo, new_head_tracker, current_head_target, 0));
...@@ -276,7 +278,7 @@ BEGIN_TEST(create1, "create a deep symbolic reference") ...@@ -276,7 +278,7 @@ BEGIN_TEST(create1, "create a deep symbolic reference")
git_reference *new_reference, *looked_up_ref, *resolved_ref; git_reference *new_reference, *looked_up_ref, *resolved_ref;
git_repository *repo; git_repository *repo;
git_oid id; git_oid id;
char ref_path[GIT_PATH_MAX]; git_buf ref_path = GIT_BUF_INIT;
const char *new_head_tracker = "deep/rooted/tracker"; const char *new_head_tracker = "deep/rooted/tracker";
...@@ -284,7 +286,7 @@ BEGIN_TEST(create1, "create a deep symbolic reference") ...@@ -284,7 +286,7 @@ BEGIN_TEST(create1, "create a deep symbolic reference")
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
git_path_join(ref_path, repo->path_repository, new_head_tracker); must_pass(git_buf_joinpath(&ref_path, repo->path_repository, new_head_tracker));
must_pass(git_reference_create_symbolic(&new_reference, repo, new_head_tracker, current_head_target, 0)); must_pass(git_reference_create_symbolic(&new_reference, repo, new_head_tracker, current_head_target, 0));
must_pass(git_reference_lookup(&looked_up_ref, repo, new_head_tracker)); must_pass(git_reference_lookup(&looked_up_ref, repo, new_head_tracker));
must_pass(git_reference_resolve(&resolved_ref, looked_up_ref)); must_pass(git_reference_resolve(&resolved_ref, looked_up_ref));
...@@ -295,13 +297,14 @@ BEGIN_TEST(create1, "create a deep symbolic reference") ...@@ -295,13 +297,14 @@ BEGIN_TEST(create1, "create a deep symbolic reference")
git_reference_free(new_reference); git_reference_free(new_reference);
git_reference_free(looked_up_ref); git_reference_free(looked_up_ref);
git_reference_free(resolved_ref); git_reference_free(resolved_ref);
git_buf_free(&ref_path);
END_TEST END_TEST
BEGIN_TEST(create2, "create a new OID reference") BEGIN_TEST(create2, "create a new OID reference")
git_reference *new_reference, *looked_up_ref; git_reference *new_reference, *looked_up_ref;
git_repository *repo, *repo2; git_repository *repo, *repo2;
git_oid id; git_oid id;
char ref_path[GIT_PATH_MAX]; git_buf ref_path = GIT_BUF_INIT;
const char *new_head = "refs/heads/new-head"; const char *new_head = "refs/heads/new-head";
...@@ -310,7 +313,7 @@ BEGIN_TEST(create2, "create a new OID reference") ...@@ -310,7 +313,7 @@ BEGIN_TEST(create2, "create a new OID reference")
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
/* Retrieve the physical path to the symbolic ref for further cleaning */ /* Retrieve the physical path to the symbolic ref for further cleaning */
git_path_join(ref_path, repo->path_repository, new_head); must_pass(git_buf_joinpath(&ref_path, repo->path_repository, new_head));
/* Create and write the new object id reference */ /* Create and write the new object id reference */
must_pass(git_reference_create_oid(&new_reference, repo, new_head, &id, 0)); must_pass(git_reference_create_oid(&new_reference, repo, new_head, &id, 0));
...@@ -337,6 +340,7 @@ BEGIN_TEST(create2, "create a new OID reference") ...@@ -337,6 +340,7 @@ BEGIN_TEST(create2, "create a new OID reference")
git_reference_free(new_reference); git_reference_free(new_reference);
git_reference_free(looked_up_ref); git_reference_free(looked_up_ref);
git_buf_free(&ref_path);
END_TEST END_TEST
BEGIN_TEST(create3, "Can not create a new OID reference which targets at an unknown id") BEGIN_TEST(create3, "Can not create a new OID reference which targets at an unknown id")
...@@ -491,12 +495,13 @@ END_TEST ...@@ -491,12 +495,13 @@ END_TEST
BEGIN_TEST(pack0, "create a packfile for an empty folder") BEGIN_TEST(pack0, "create a packfile for an empty folder")
git_repository *repo; git_repository *repo;
char temp_path[GIT_PATH_MAX]; git_buf temp_path = GIT_BUF_INIT;
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
git_path_join_n(temp_path, 3, repo->path_repository, GIT_REFS_HEADS_DIR, "empty_dir"); must_pass(git_buf_join_n(&temp_path, '/', 3, repo->path_repository, GIT_REFS_HEADS_DIR, "empty_dir"));
must_pass(git_futils_mkdir_r(temp_path, GIT_REFS_DIR_MODE)); must_pass(git_futils_mkdir_r(temp_path.ptr, NULL, GIT_REFS_DIR_MODE));
git_buf_free(&temp_path);
must_pass(git_reference_packall(repo)); must_pass(git_reference_packall(repo));
...@@ -506,7 +511,7 @@ END_TEST ...@@ -506,7 +511,7 @@ END_TEST
BEGIN_TEST(pack1, "create a packfile from all the loose rn a repo") BEGIN_TEST(pack1, "create a packfile from all the loose rn a repo")
git_repository *repo; git_repository *repo;
git_reference *reference; git_reference *reference;
char temp_path[GIT_PATH_MAX]; git_buf temp_path = GIT_BUF_INIT;
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
...@@ -524,8 +529,8 @@ BEGIN_TEST(pack1, "create a packfile from all the loose rn a repo") ...@@ -524,8 +529,8 @@ BEGIN_TEST(pack1, "create a packfile from all the loose rn a repo")
must_pass(git_reference_packall(repo)); must_pass(git_reference_packall(repo));
/* Ensure the packed-refs file exists */ /* Ensure the packed-refs file exists */
git_path_join(temp_path, repo->path_repository, GIT_PACKEDREFS_FILE); must_pass(git_buf_joinpath(&temp_path, repo->path_repository, GIT_PACKEDREFS_FILE));
must_pass(git_futils_exists(temp_path)); must_pass(git_futils_exists(temp_path.ptr));
/* Ensure the known ref can still be looked up but is now packed */ /* Ensure the known ref can still be looked up but is now packed */
must_pass(git_reference_lookup(&reference, repo, loose_tag_ref_name)); must_pass(git_reference_lookup(&reference, repo, loose_tag_ref_name));
...@@ -533,25 +538,26 @@ BEGIN_TEST(pack1, "create a packfile from all the loose rn a repo") ...@@ -533,25 +538,26 @@ BEGIN_TEST(pack1, "create a packfile from all the loose rn a repo")
must_be_true(strcmp(reference->name, loose_tag_ref_name) == 0); must_be_true(strcmp(reference->name, loose_tag_ref_name) == 0);
/* Ensure the known ref has been removed from the loose folder structure */ /* Ensure the known ref has been removed from the loose folder structure */
git_path_join(temp_path, repo->path_repository, loose_tag_ref_name); must_pass(git_buf_joinpath(&temp_path, repo->path_repository, loose_tag_ref_name));
must_pass(!git_futils_exists(temp_path)); must_pass(!git_futils_exists(temp_path.ptr));
close_temp_repo(repo); close_temp_repo(repo);
git_reference_free(reference); git_reference_free(reference);
git_buf_free(&temp_path);
END_TEST END_TEST
BEGIN_TEST(rename0, "rename a loose reference") BEGIN_TEST(rename0, "rename a loose reference")
git_reference *looked_up_ref, *another_looked_up_ref; git_reference *looked_up_ref, *another_looked_up_ref;
git_repository *repo; git_repository *repo;
char temp_path[GIT_PATH_MAX]; git_buf temp_path = GIT_BUF_INIT;
const char *new_name = "refs/tags/Nemo/knows/refs.kung-fu"; const char *new_name = "refs/tags/Nemo/knows/refs.kung-fu";
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
/* Ensure the ref doesn't exist on the file system */ /* Ensure the ref doesn't exist on the file system */
git_path_join(temp_path, repo->path_repository, new_name); must_pass(git_buf_joinpath(&temp_path, repo->path_repository, new_name));
must_pass(!git_futils_exists(temp_path)); must_pass(!git_futils_exists(temp_path.ptr));
/* Retrieval of the reference to rename */ /* Retrieval of the reference to rename */
must_pass(git_reference_lookup(&looked_up_ref, repo, loose_tag_ref_name)); must_pass(git_reference_lookup(&looked_up_ref, repo, loose_tag_ref_name));
...@@ -575,26 +581,27 @@ BEGIN_TEST(rename0, "rename a loose reference") ...@@ -575,26 +581,27 @@ BEGIN_TEST(rename0, "rename a loose reference")
must_be_true(git_reference_is_packed(looked_up_ref) == 0); must_be_true(git_reference_is_packed(looked_up_ref) == 0);
/* ...and the ref can be found in the file system */ /* ...and the ref can be found in the file system */
git_path_join(temp_path, repo->path_repository, new_name); must_pass(git_buf_joinpath(&temp_path, repo->path_repository, new_name));
must_pass(git_futils_exists(temp_path)); must_pass(git_futils_exists(temp_path.ptr));
close_temp_repo(repo); close_temp_repo(repo);
git_reference_free(looked_up_ref); git_reference_free(looked_up_ref);
git_reference_free(another_looked_up_ref); git_reference_free(another_looked_up_ref);
git_buf_free(&temp_path);
END_TEST END_TEST
BEGIN_TEST(rename1, "rename a packed reference (should make it loose)") BEGIN_TEST(rename1, "rename a packed reference (should make it loose)")
git_reference *looked_up_ref, *another_looked_up_ref; git_reference *looked_up_ref, *another_looked_up_ref;
git_repository *repo; git_repository *repo;
char temp_path[GIT_PATH_MAX]; git_buf temp_path = GIT_BUF_INIT;
const char *brand_new_name = "refs/heads/brand_new_name"; const char *brand_new_name = "refs/heads/brand_new_name";
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
/* Ensure the ref doesn't exist on the file system */ /* Ensure the ref doesn't exist on the file system */
git_path_join(temp_path, repo->path_repository, packed_head_name); must_pass(git_buf_joinpath(&temp_path, repo->path_repository, packed_head_name));
must_pass(!git_futils_exists(temp_path)); must_pass(!git_futils_exists(temp_path.ptr));
/* The reference can however be looked-up... */ /* The reference can however be looked-up... */
must_pass(git_reference_lookup(&looked_up_ref, repo, packed_head_name)); must_pass(git_reference_lookup(&looked_up_ref, repo, packed_head_name));
...@@ -618,26 +625,27 @@ BEGIN_TEST(rename1, "rename a packed reference (should make it loose)") ...@@ -618,26 +625,27 @@ BEGIN_TEST(rename1, "rename a packed reference (should make it loose)")
must_be_true(git_reference_is_packed(looked_up_ref) == 0); must_be_true(git_reference_is_packed(looked_up_ref) == 0);
/* ...and the ref now happily lives in the file system */ /* ...and the ref now happily lives in the file system */
git_path_join(temp_path, repo->path_repository, brand_new_name); must_pass(git_buf_joinpath(&temp_path, repo->path_repository, brand_new_name));
must_pass(git_futils_exists(temp_path)); must_pass(git_futils_exists(temp_path.ptr));
close_temp_repo(repo); close_temp_repo(repo);
git_reference_free(looked_up_ref); git_reference_free(looked_up_ref);
git_reference_free(another_looked_up_ref); git_reference_free(another_looked_up_ref);
git_buf_free(&temp_path);
END_TEST END_TEST
BEGIN_TEST(rename2, "renaming a packed reference does not pack another reference which happens to be in both loose and pack state") BEGIN_TEST(rename2, "renaming a packed reference does not pack another reference which happens to be in both loose and pack state")
git_reference *looked_up_ref, *another_looked_up_ref; git_reference *looked_up_ref, *another_looked_up_ref;
git_repository *repo; git_repository *repo;
char temp_path[GIT_PATH_MAX]; git_buf temp_path = GIT_BUF_INIT;
const char *brand_new_name = "refs/heads/brand_new_name"; const char *brand_new_name = "refs/heads/brand_new_name";
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
/* Ensure the other reference exists on the file system */ /* Ensure the other reference exists on the file system */
git_path_join(temp_path, repo->path_repository, packed_test_head_name); must_pass(git_buf_joinpath(&temp_path, repo->path_repository, packed_test_head_name));
must_pass(git_futils_exists(temp_path)); must_pass(git_futils_exists(temp_path.ptr));
/* Lookup the other reference */ /* Lookup the other reference */
must_pass(git_reference_lookup(&another_looked_up_ref, repo, packed_test_head_name)); must_pass(git_reference_lookup(&another_looked_up_ref, repo, packed_test_head_name));
...@@ -662,12 +670,13 @@ BEGIN_TEST(rename2, "renaming a packed reference does not pack another reference ...@@ -662,12 +670,13 @@ BEGIN_TEST(rename2, "renaming a packed reference does not pack another reference
must_be_true(git_reference_is_packed(another_looked_up_ref) == 0); must_be_true(git_reference_is_packed(another_looked_up_ref) == 0);
/* Ensure the other ref still exists on the file system */ /* Ensure the other ref still exists on the file system */
must_pass(git_futils_exists(temp_path)); must_pass(git_futils_exists(temp_path.ptr));
close_temp_repo(repo); close_temp_repo(repo);
git_reference_free(looked_up_ref); git_reference_free(looked_up_ref);
git_reference_free(another_looked_up_ref); git_reference_free(another_looked_up_ref);
git_buf_free(&temp_path);
END_TEST END_TEST
BEGIN_TEST(rename3, "can not rename a reference with the name of an existing reference") BEGIN_TEST(rename3, "can not rename a reference with the name of an existing reference")
...@@ -884,13 +893,13 @@ END_TEST ...@@ -884,13 +893,13 @@ END_TEST
BEGIN_TEST(delete0, "deleting a ref which is both packed and loose should remove both tracks in the filesystem") BEGIN_TEST(delete0, "deleting a ref which is both packed and loose should remove both tracks in the filesystem")
git_reference *looked_up_ref, *another_looked_up_ref; git_reference *looked_up_ref, *another_looked_up_ref;
git_repository *repo; git_repository *repo;
char temp_path[GIT_PATH_MAX]; git_buf temp_path = GIT_BUF_INIT;
must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
/* Ensure the loose reference exists on the file system */ /* Ensure the loose reference exists on the file system */
git_path_join(temp_path, repo->path_repository, packed_test_head_name); must_pass(git_buf_joinpath(&temp_path, repo->path_repository, packed_test_head_name));
must_pass(git_futils_exists(temp_path)); must_pass(git_futils_exists(temp_path.ptr));
/* Lookup the reference */ /* Lookup the reference */
must_pass(git_reference_lookup(&looked_up_ref, repo, packed_test_head_name)); must_pass(git_reference_lookup(&looked_up_ref, repo, packed_test_head_name));
...@@ -905,11 +914,12 @@ BEGIN_TEST(delete0, "deleting a ref which is both packed and loose should remove ...@@ -905,11 +914,12 @@ BEGIN_TEST(delete0, "deleting a ref which is both packed and loose should remove
must_fail(git_reference_lookup(&another_looked_up_ref, repo, packed_test_head_name)); must_fail(git_reference_lookup(&another_looked_up_ref, repo, packed_test_head_name));
/* Ensure the loose reference doesn't exist any longer on the file system */ /* Ensure the loose reference doesn't exist any longer on the file system */
must_pass(!git_futils_exists(temp_path)); must_pass(!git_futils_exists(temp_path.ptr));
close_temp_repo(repo); close_temp_repo(repo);
git_reference_free(another_looked_up_ref); git_reference_free(another_looked_up_ref);
git_buf_free(&temp_path);
END_TEST END_TEST
BEGIN_TEST(delete1, "can delete a just packed reference") BEGIN_TEST(delete1, "can delete a just packed reference")
......
...@@ -87,31 +87,37 @@ static int write_file(const char *path, const char *content) ...@@ -87,31 +87,37 @@ static int write_file(const char *path, const char *content)
} }
//no check is performed on ceiling_dirs length, so be sure it's long enough //no check is performed on ceiling_dirs length, so be sure it's long enough
static int append_ceiling_dir(char *ceiling_dirs, const char *path) static int append_ceiling_dir(git_buf *ceiling_dirs, const char *path)
{ {
int len = strlen(ceiling_dirs); git_buf pretty_path = GIT_BUF_INIT;
int error; int error;
char ceiling_separator[2] = { GIT_PATH_LIST_SEPARATOR, '\0' };
error = git_path_prettify_dir(ceiling_dirs + len + (len ? 1 : 0), path, NULL); error = git_path_prettify_dir(&pretty_path, path, NULL);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to append ceiling directory."); return git__rethrow(error, "Failed to append ceiling directory.");
if (len) if (ceiling_dirs->size > 0)
ceiling_dirs[len] = GIT_PATH_LIST_SEPARATOR; git_buf_puts(ceiling_dirs, ceiling_separator);
git_buf_puts(ceiling_dirs, pretty_path.ptr);
return GIT_SUCCESS; git_buf_free(&pretty_path);
return git_buf_lasterror(ceiling_dirs);
} }
BEGIN_TEST(discover0, "test discover") BEGIN_TEST(discover0, "test discover")
git_repository *repo; git_repository *repo;
char ceiling_dirs[GIT_PATH_MAX * 2] = ""; git_buf ceiling_dirs_buf = GIT_BUF_INIT;
const char *ceiling_dirs;
char repository_path[GIT_PATH_MAX]; char repository_path[GIT_PATH_MAX];
char sub_repository_path[GIT_PATH_MAX]; char sub_repository_path[GIT_PATH_MAX];
char found_path[GIT_PATH_MAX]; char found_path[GIT_PATH_MAX];
const mode_t mode = 0777; const mode_t mode = 0777;
git_futils_mkdir_r(DISCOVER_FOLDER, mode); git_futils_mkdir_r(DISCOVER_FOLDER, NULL, mode);
must_pass(append_ceiling_dir(ceiling_dirs, TEMP_REPO_FOLDER)); must_pass(append_ceiling_dir(&ceiling_dirs_buf, TEMP_REPO_FOLDER));
ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf);
must_be_true(git_repository_discover(repository_path, sizeof(repository_path), DISCOVER_FOLDER, 0, ceiling_dirs) == GIT_ENOTAREPO); must_be_true(git_repository_discover(repository_path, sizeof(repository_path), DISCOVER_FOLDER, 0, ceiling_dirs) == GIT_ENOTAREPO);
...@@ -120,15 +126,15 @@ BEGIN_TEST(discover0, "test discover") ...@@ -120,15 +126,15 @@ BEGIN_TEST(discover0, "test discover")
git_repository_free(repo); git_repository_free(repo);
must_pass(git_repository_init(&repo, SUB_REPOSITORY_FOLDER, 0)); must_pass(git_repository_init(&repo, SUB_REPOSITORY_FOLDER, 0));
must_pass(git_futils_mkdir_r(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, mode)); must_pass(git_futils_mkdir_r(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, NULL, mode));
must_pass(git_repository_discover(sub_repository_path, sizeof(sub_repository_path), SUB_REPOSITORY_FOLDER, 0, ceiling_dirs)); must_pass(git_repository_discover(sub_repository_path, sizeof(sub_repository_path), SUB_REPOSITORY_FOLDER, 0, ceiling_dirs));
must_pass(git_futils_mkdir_r(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, mode)); must_pass(git_futils_mkdir_r(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, NULL, mode));
must_pass(ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs, sub_repository_path)); must_pass(ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs, sub_repository_path));
must_pass(ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path)); must_pass(ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path));
must_pass(ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, ceiling_dirs, sub_repository_path)); must_pass(ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, ceiling_dirs, sub_repository_path));
must_pass(git_futils_mkdir_r(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, mode)); must_pass(git_futils_mkdir_r(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, NULL, mode));
must_pass(write_file(REPOSITORY_ALTERNATE_FOLDER "/" DOT_GIT, "gitdir: ../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT)); must_pass(write_file(REPOSITORY_ALTERNATE_FOLDER "/" DOT_GIT, "gitdir: ../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT));
must_pass(write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB "/" DOT_GIT, "gitdir: ../../../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT)); must_pass(write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB "/" DOT_GIT, "gitdir: ../../../" SUB_REPOSITORY_FOLDER_NAME "/" DOT_GIT));
must_pass(write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB "/" DOT_GIT, "gitdir: ../../../../")); must_pass(write_file(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB "/" DOT_GIT, "gitdir: ../../../../"));
...@@ -137,20 +143,22 @@ BEGIN_TEST(discover0, "test discover") ...@@ -137,20 +143,22 @@ BEGIN_TEST(discover0, "test discover")
must_pass(ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path)); must_pass(ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path));
must_pass(ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs, repository_path)); must_pass(ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs, repository_path));
must_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER1, mode)); must_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER1, NULL, mode));
must_pass(write_file(ALTERNATE_MALFORMED_FOLDER1 "/" DOT_GIT, "Anything but not gitdir:")); must_pass(write_file(ALTERNATE_MALFORMED_FOLDER1 "/" DOT_GIT, "Anything but not gitdir:"));
must_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER2, mode)); must_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER2, NULL, mode));
must_pass(write_file(ALTERNATE_MALFORMED_FOLDER2 "/" DOT_GIT, "gitdir:")); must_pass(write_file(ALTERNATE_MALFORMED_FOLDER2 "/" DOT_GIT, "gitdir:"));
must_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER3, mode)); must_pass(git_futils_mkdir_r(ALTERNATE_MALFORMED_FOLDER3, NULL, mode));
must_pass(write_file(ALTERNATE_MALFORMED_FOLDER3 "/" DOT_GIT, "gitdir: \n\n\n")); must_pass(write_file(ALTERNATE_MALFORMED_FOLDER3 "/" DOT_GIT, "gitdir: \n\n\n"));
must_pass(git_futils_mkdir_r(ALTERNATE_NOT_FOUND_FOLDER, mode)); must_pass(git_futils_mkdir_r(ALTERNATE_NOT_FOUND_FOLDER, NULL, mode));
must_pass(write_file(ALTERNATE_NOT_FOUND_FOLDER "/" DOT_GIT, "gitdir: a_repository_that_surely_does_not_exist")); must_pass(write_file(ALTERNATE_NOT_FOUND_FOLDER "/" DOT_GIT, "gitdir: a_repository_that_surely_does_not_exist"));
must_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER1, 0, ceiling_dirs)); must_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER1, 0, ceiling_dirs));
must_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER2, 0, ceiling_dirs)); must_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER2, 0, ceiling_dirs));
must_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER3, 0, ceiling_dirs)); must_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_MALFORMED_FOLDER3, 0, ceiling_dirs));
must_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_NOT_FOUND_FOLDER, 0, ceiling_dirs)); must_fail(git_repository_discover(found_path, sizeof(found_path), ALTERNATE_NOT_FOUND_FOLDER, 0, ceiling_dirs));
must_pass(append_ceiling_dir(ceiling_dirs, SUB_REPOSITORY_FOLDER)); must_pass(append_ceiling_dir(&ceiling_dirs_buf, SUB_REPOSITORY_FOLDER));
ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf);
//this must pass as ceiling_directories cannot predent the current //this must pass as ceiling_directories cannot predent the current
//working directory to be checked //working directory to be checked
must_pass(git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER, 0, ceiling_dirs)); must_pass(git_repository_discover(found_path, sizeof(found_path), SUB_REPOSITORY_FOLDER, 0, ceiling_dirs));
...@@ -166,6 +174,7 @@ BEGIN_TEST(discover0, "test discover") ...@@ -166,6 +174,7 @@ BEGIN_TEST(discover0, "test discover")
must_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, 1)); must_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, 1));
git_repository_free(repo); git_repository_free(repo);
git_buf_free(&ceiling_dirs_buf);
END_TEST END_TEST
BEGIN_SUITE(repository) BEGIN_SUITE(repository)
......
...@@ -392,15 +392,15 @@ END_TEST ...@@ -392,15 +392,15 @@ END_TEST
BEGIN_TEST(singlestatus3, "test retrieving status for a new file in an empty repository") BEGIN_TEST(singlestatus3, "test retrieving status for a new file in an empty repository")
git_repository *repo; git_repository *repo;
unsigned int status_flags; unsigned int status_flags;
char file_path[GIT_PATH_MAX]; git_buf file_path = GIT_BUF_INIT;
char filename[] = "new_file"; char filename[] = "new_file";
int fd; int fd;
must_pass(copydir_recurs(EMPTY_REPOSITORY_FOLDER, TEST_STD_REPO_FOLDER)); must_pass(copydir_recurs(EMPTY_REPOSITORY_FOLDER, TEST_STD_REPO_FOLDER));
must_pass(remove_placeholders(TEST_STD_REPO_FOLDER, "dummy-marker.txt")); must_pass(remove_placeholders(TEST_STD_REPO_FOLDER, "dummy-marker.txt"));
git_path_join(file_path, TEMP_REPO_FOLDER, filename); must_pass(git_buf_joinpath(&file_path, TEMP_REPO_FOLDER, filename));
fd = p_creat(file_path, 0666); fd = p_creat(file_path.ptr, 0666);
must_pass(fd); must_pass(fd);
must_pass(p_write(fd, "new_file\n", 9)); must_pass(p_write(fd, "new_file\n", 9));
must_pass(p_close(fd)); must_pass(p_close(fd));
...@@ -411,6 +411,7 @@ BEGIN_TEST(singlestatus3, "test retrieving status for a new file in an empty rep ...@@ -411,6 +411,7 @@ BEGIN_TEST(singlestatus3, "test retrieving status for a new file in an empty rep
must_be_true(status_flags == GIT_STATUS_WT_NEW); must_be_true(status_flags == GIT_STATUS_WT_NEW);
git_repository_free(repo); git_repository_free(repo);
git_buf_free(&file_path);
git_futils_rmdir_r(TEMP_REPO_FOLDER, 1); git_futils_rmdir_r(TEMP_REPO_FOLDER, 1);
END_TEST END_TEST
......
...@@ -225,42 +225,49 @@ int cmp_files(const char *a, const char *b) ...@@ -225,42 +225,49 @@ int cmp_files(const char *a, const char *b)
} }
typedef struct { typedef struct {
size_t src_len, dst_len; git_buf src;
char *dst; size_t src_baselen;
git_buf dst;
size_t dst_baselen;
} copydir_data; } copydir_data;
static int copy_filesystem_element_recurs(void *_data, char *source) static int copy_filesystem_element_recurs(void *_data, git_buf *source)
{ {
copydir_data *data = (copydir_data *)_data; copydir_data *data = (copydir_data *)_data;
data->dst[data->dst_len] = 0; git_buf_truncate(&data->dst, data->dst_baselen);
git_path_join(data->dst, data->dst, source + data->src_len); git_buf_joinpath(&data->dst, data->dst.ptr, source->ptr + data->src_baselen);
if (git_futils_isdir(source) == GIT_SUCCESS) if (git_futils_isdir(source->ptr) == GIT_SUCCESS)
return git_futils_direach(source, GIT_PATH_MAX, copy_filesystem_element_recurs, _data); return git_futils_direach(source, copy_filesystem_element_recurs, _data);
else
return copy_file(source, data->dst); return copy_file(source->ptr, data->dst.ptr);
} }
int copydir_recurs(const char *source_directory_path, const char *destination_directory_path) int copydir_recurs(
const char *source_directory_path,
const char *destination_directory_path)
{ {
char source_buffer[GIT_PATH_MAX]; int error;
char dest_buffer[GIT_PATH_MAX]; copydir_data data = { GIT_BUF_INIT, 0, GIT_BUF_INIT, 0 };
copydir_data data;
/* Source has to exist, Destination hast to _not_ exist */ /* Source has to exist, Destination hast to _not_ exist */
if (git_futils_isdir(source_directory_path) != GIT_SUCCESS || if (git_futils_isdir(source_directory_path) != GIT_SUCCESS ||
git_futils_isdir(destination_directory_path) == GIT_SUCCESS) git_futils_isdir(destination_directory_path) == GIT_SUCCESS)
return GIT_EINVALIDPATH; return GIT_EINVALIDPATH;
git_path_join(source_buffer, source_directory_path, ""); git_buf_joinpath(&data.src, source_directory_path, "");
data.src_len = strlen(source_buffer); data.src_baselen = data.src.size;
git_buf_joinpath(&data.dst, destination_directory_path, "");
data.dst_baselen = data.dst.size;
error = copy_filesystem_element_recurs(&data, &data.src);
git_path_join(dest_buffer, destination_directory_path, ""); git_buf_free(&data.src);
data.dst = dest_buffer; git_buf_free(&data.dst);
data.dst_len = strlen(dest_buffer);
return copy_filesystem_element_recurs(&data, source_buffer); return error;
} }
int open_temp_repo(git_repository **repo, const char *path) int open_temp_repo(git_repository **repo, const char *path)
...@@ -281,30 +288,51 @@ void close_temp_repo(git_repository *repo) ...@@ -281,30 +288,51 @@ void close_temp_repo(git_repository *repo)
} }
} }
static int remove_placeholders_recurs(void *filename, char *path) typedef struct {
const char *filename;
size_t filename_len;
} remove_data;
static int remove_placeholders_recurs(void *_data, git_buf *path)
{ {
char passed_filename[GIT_PATH_MAX]; remove_data *data = (remove_data *)_data;
char *data = (char *)filename; size_t pathlen;
if (!git_futils_isdir(path)) if (!git_futils_isdir(path->ptr))
return git_futils_direach(path, GIT_PATH_MAX, remove_placeholders_recurs, data); return git_futils_direach(path, remove_placeholders_recurs, data);
if (git_path_basename_r(passed_filename, sizeof(passed_filename), path) < GIT_SUCCESS) pathlen = path->size;
return GIT_EINVALIDPATH;
if (!strcmp(data, passed_filename)) if (pathlen < data->filename_len)
return p_unlink(path); return GIT_SUCCESS;
/* if path ends in '/'+filename (or equals filename) */
if (!strcmp(data->filename, path->ptr + pathlen - data->filename_len) &&
(pathlen == data->filename_len ||
path->ptr[pathlen - data->filename_len - 1] == '/'))
return p_unlink(path->ptr);
return GIT_SUCCESS; return GIT_SUCCESS;
} }
int remove_placeholders(char *directory_path, char *filename) int remove_placeholders(const char *directory_path, const char *filename)
{ {
char buffer[GIT_PATH_MAX]; int error;
remove_data data;
git_buf buffer = GIT_BUF_INIT;
if (git_futils_isdir(directory_path)) if (git_futils_isdir(directory_path))
return GIT_EINVALIDPATH; return GIT_EINVALIDPATH;
strcpy(buffer, directory_path); if ((error = git_buf_sets(&buffer, directory_path)) < GIT_SUCCESS)
return remove_placeholders_recurs(filename, buffer); return error;
data.filename = filename;
data.filename_len = strlen(filename);
error = remove_placeholders_recurs(&data, &buffer);
git_buf_free(&buffer);
return error;
} }
...@@ -74,7 +74,7 @@ extern int cmp_files(const char *a, const char *b); ...@@ -74,7 +74,7 @@ extern int cmp_files(const char *a, const char *b);
extern int copy_file(const char *source, const char *dest); extern int copy_file(const char *source, const char *dest);
extern int rmdir_recurs(const char *directory_path); extern int rmdir_recurs(const char *directory_path);
extern int copydir_recurs(const char *source_directory_path, const char *destination_directory_path); extern int copydir_recurs(const char *source_directory_path, const char *destination_directory_path);
extern int remove_placeholders(char *directory_path, char *filename); extern int remove_placeholders(const char *directory_path, const char *filename);
extern int open_temp_repo(git_repository **repo, const char *path); extern int open_temp_repo(git_repository **repo, const char *path);
extern void close_temp_repo(git_repository *repo); extern void close_temp_repo(git_repository *repo);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment