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,32 +97,30 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat ...@@ -93,32 +97,30 @@ 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 (!islnk)
p_close(fd);
return git__rethrow(error, "Failed to create blob");
} }
if ((error = git_odb_open_wstream(&stream, odb, (size_t)size, GIT_OBJ_BLOB)) < GIT_SUCCESS)
goto cleanup;
while (size > 0) { while (size > 0) {
ssize_t read_len; ssize_t read_len;
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);
cleanup:
if (stream)
stream->free(stream); stream->free(stream);
if (!islnk) 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");
......
...@@ -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;
dname = (char *)git__malloc(len);
if (dname == NULL)
return NULL;
if (git_path_dirname_r(dname, len, path) < GIT_SUCCESS) { git_path_dirname_r(&buf, path);
git__free(dname); dirname = git_buf_detach(&buf);
return NULL; git_buf_free(&buf); /* avoid memleak if error occurs */
}
return dname; return dirname;
} }
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; git_path_basename_r(&buf, path);
bname = (char *)git__malloc(len); basename = git_buf_detach(&buf);
if (bname == NULL) git_buf_free(&buf); /* avoid memleak if error occurs */
return NULL;
if (git_path_basename_r(bname, len, path) < GIT_SUCCESS) { return basename;
git__free(bname);
return NULL;
}
return bname;
} }
...@@ -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;
}
if (base == NULL || git_path_root(path) >= 0) { /* allow realpath to allocate the buffer */
result = p_realpath(path, path_out); if (path != NULL)
result = p_realpath(path, NULL);
if (result) {
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_buf_lasterror(path);
}
void git_path_string_to_dir(char* path, size_t size)
{
size_t end = strlen(path);
return GIT_SUCCESS; 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)
......
...@@ -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)
......
...@@ -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);
} }
......
...@@ -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); error = retrieve_tag_reference(&new_ref, &ref_name, repo, 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;
} }
} }
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);
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create tag"); if (error < GIT_SUCCESS)
git__rethrow(error, "%s", errmsg);
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);
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create tag"); if (error < GIT_SUCCESS)
git__rethrow(error, "%s", errmsg);
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,31 +304,36 @@ int p_hide_directory__w32(const char *path) ...@@ -304,31 +304,36 @@ 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);
if (buffer)
git_path_mkposix(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,11 +105,12 @@ END_TEST ...@@ -105,11 +105,12 @@ 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); \
...@@ -131,14 +132,16 @@ BEGIN_TEST(path0, "get the dirname of a path") ...@@ -131,14 +132,16 @@ 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")
......
...@@ -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;
git_path_join(dest_buffer, destination_directory_path, ""); error = copy_filesystem_element_recurs(&data, &data.src);
data.dst = dest_buffer;
data.dst_len = strlen(dest_buffer);
return copy_filesystem_element_recurs(&data, source_buffer); git_buf_free(&data.src);
git_buf_free(&data.dst);
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