Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRussell Belfer <arrbee@arrbee.com>2011-11-30 23:27:15 +0400
committerRussell Belfer <arrbee@arrbee.com>2011-12-08 11:08:15 +0400
commit97769280ba9938ae27f6e06cbd0d5e8a768a86b9 (patch)
tree4fe43e99acb55f904f6b586bd7c5158610f9512f /src
parenta22b14d32dd8d5f06f121aa154d45bac3b10a305 (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/blob.c51
-rw-r--r--src/buffer.c96
-rw-r--r--src/buffer.h79
-rw-r--r--src/commit.c3
-rw-r--r--src/config.c64
-rw-r--r--src/config.h3
-rw-r--r--src/fetch.c22
-rw-r--r--src/filebuf.c7
-rw-r--r--src/fileops.c181
-rw-r--r--src/fileops.h31
-rw-r--r--src/index.c22
-rw-r--r--src/indexer.c50
-rw-r--r--src/odb.c27
-rw-r--r--src/odb_loose.c283
-rw-r--r--src/odb_pack.c52
-rw-r--r--src/path.c167
-rw-r--r--src/path.h37
-rw-r--r--src/pkt.c13
-rw-r--r--src/posix.c3
-rw-r--r--src/reflog.c119
-rw-r--r--src/refs.c183
-rw-r--r--src/refspec.c18
-rw-r--r--src/refspec.h12
-rw-r--r--src/remote.c16
-rw-r--r--src/repository.c405
-rw-r--r--src/signature.c2
-rw-r--r--src/status.c167
-rw-r--r--src/tag.c120
-rw-r--r--src/transports/git.c2
-rw-r--r--src/transports/http.c19
-rw-r--r--src/tree.c80
-rw-r--r--src/win32/posix_w32.c35
32 files changed, 1414 insertions, 955 deletions
diff --git a/src/blob.c b/src/blob.c
index 87f5686af..7497ba7bf 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -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 error, islnk;
+ int error = GIT_SUCCESS;
+ int islnk = 0;
int fd = 0;
- char full_path[GIT_PATH_MAX];
+ git_buf full_path = GIT_BUF_INIT;
char buffer[2048];
git_off_t size;
- git_odb_stream *stream;
+ git_odb_stream *stream = NULL;
struct stat st;
const char *workdir;
git_odb *odb;
@@ -81,11 +82,14 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
if (workdir == NULL)
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) {
- 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);
@@ -93,18 +97,18 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
error = git_repository_odb__weakptr(&odb, repo);
if (error < GIT_SUCCESS)
- return error;
+ goto cleanup;
if (!islnk) {
- if ((fd = p_open(full_path, O_RDONLY)) < 0)
- return git__throw(GIT_ENOTFOUND, "Failed to create blob. Could not open '%s'", full_path);
+ if ((fd = p_open(full_path.ptr, O_RDONLY)) < 0) {
+ 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) {
ssize_t read_len;
@@ -112,13 +116,11 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
if (!islnk)
read_len = p_read(fd, buffer, sizeof(buffer));
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 (!islnk)
- p_close(fd);
- stream->free(stream);
- return git__throw(GIT_EOSERR, "Failed to create blob. Can't read full file");
+ error = git__throw(GIT_EOSERR, "Failed to create blob. Can't read full file");
+ goto cleanup;
}
stream->write(stream, buffer, read_len);
@@ -126,10 +128,15 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
}
error = stream->finalize_write(oid, stream);
- stream->free(stream);
- if (!islnk)
+
+cleanup:
+ if (stream)
+ stream->free(stream);
+ if (!islnk && 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");
}
diff --git a/src/buffer.c b/src/buffer.c
index b90dd29c5..295b87e1a 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -15,7 +15,8 @@ char git_buf_initbuf[1];
#define ENSURE_SIZE(b, d) \
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)
{
@@ -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 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;
size_t new_size;
@@ -55,10 +64,9 @@ int git_buf_grow(git_buf *buf, size_t target_size)
new_size = (new_size + 7) & ~7;
new_ptr = git__realloc(new_ptr, new_size);
- if (!new_ptr) {
- buf->asize = -1;
+ /* if realloc fails, return without modifying the git_buf */
+ if (!new_ptr)
return GIT_ENOMEM;
- }
buf->asize = new_size;
buf->ptr = new_ptr;
@@ -93,7 +101,12 @@ int git_buf_oom(const git_buf *buf)
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) {
git_buf_clear(buf);
@@ -103,35 +116,38 @@ void git_buf_set(git_buf *buf, const char *data, size_t len)
buf->size = len;
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);
buf->ptr[buf->size++] = c;
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);
memmove(buf->ptr + buf->size, data, len);
buf->size += len;
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);
- 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;
va_list arglist;
@@ -145,16 +161,18 @@ void git_buf_printf(git_buf *buf, const char *format, ...)
if (len < 0) {
buf->asize = -1;
- return;
+ return GIT_ENOMEM;
}
if (len + 1 <= buf->asize - buf->size) {
buf->size += len;
- return;
+ break;
}
ENSURE_SIZE(buf, buf->size + len + 1);
}
+
+ return GIT_SUCCESS;
}
const char *git_buf_cstr(git_buf *buf)
@@ -162,7 +180,7 @@ const char *git_buf_cstr(git_buf *buf)
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;
@@ -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)
{
git_buf t = *buf_a;
@@ -197,7 +223,7 @@ void git_buf_swap(git_buf *buf_a, git_buf *buf_b)
*buf_b = t;
}
-char *git_buf_take_cstr(git_buf *buf)
+char *git_buf_detach(git_buf *buf)
{
char *data = buf->ptr;
@@ -209,18 +235,34 @@ char *git_buf_take_cstr(git_buf *buf)
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;
- int i;
+ int i, error = GIT_SUCCESS;
size_t total_size = 0;
char *out;
if (buf->size > 0 && buf->ptr[buf->size - 1] != separator)
++total_size; /* space for initial separator */
+ /* Make two passes to avoid multiple reallocation */
+
va_start(ap, nbuf);
for (i = 0; i < nbuf; ++i) {
const char* segment;
@@ -237,7 +279,10 @@ void git_buf_join_n(git_buf *buf, char separator, int nbuf, ...)
}
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;
@@ -274,14 +319,17 @@ void git_buf_join_n(git_buf *buf, char separator, int nbuf, ...)
/* set size based on num characters actually written */
buf->size = out - buf->ptr;
buf->ptr[buf->size] = '\0';
+
+ return error;
}
-void git_buf_join(
+int git_buf_join(
git_buf *buf,
char separator,
const char *str_a,
const char *str_b)
{
+ int error = GIT_SUCCESS;
size_t strlen_a = strlen(str_a);
size_t strlen_b = strlen(str_b);
int need_sep = 0;
@@ -293,7 +341,9 @@ void git_buf_join(
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);
if (need_sep)
@@ -302,4 +352,6 @@ void git_buf_join(
buf->size = strlen_a + strlen_b + need_sep;
buf->ptr[buf->size] = '\0';
+
+ return error;
}
diff --git a/src/buffer.h b/src/buffer.h
index fa0c7f0b8..30658f3c2 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -18,34 +18,87 @@ extern char git_buf_initbuf[];
#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);
+
+/**
+ * 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);
+
+/**
+ * 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_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
* 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
- * git_buf_oom() at the end of your sequence and it will be true if you ran
- * out of memory at any point with that buffer.
+ * further calls to modify the buffer will fail. Check git_buf_oom() at the
+ * end of your sequence and it will be true if you ran out of memory at any
+ * point with that buffer.
+ * @return 0 if no error, 1 if allocation error.
*/
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);
-void git_buf_putc(git_buf *buf, char c);
-void git_buf_put(git_buf *buf, const char *data, size_t len);
-void git_buf_puts(git_buf *buf, const char *string);
-void git_buf_printf(git_buf *buf, const char *format, ...) GIT_FORMAT_PRINTF(2, 3);
+/**
+ * Just like git_buf_oom, except returns appropriate error code.
+ * @return GIT_ENOMEM if allocation error, GIT_SUCCESS if not.
+ */
+int git_buf_lasterror(const git_buf *buf);
+
+/*
+ * 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_consume(git_buf *buf, const char *end);
-void git_buf_join_n(git_buf *buf, char separator, int nbuf, ...);
-void git_buf_join(git_buf *buf, char separator, const char *str_a, const char *str_b);
+void git_buf_truncate(git_buf *buf, ssize_t len);
+
+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);
-char *git_buf_take_cstr(git_buf *buf);
-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);
#define git_buf_PUTS(buf, str) git_buf_put(buf, str, sizeof(str) - 1)
diff --git a/src/commit.c b/src/commit.c
index bf6ca7855..5d077d54e 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -129,7 +129,8 @@ int git_commit_create(
git_buf_puts(&commit, message);
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;
}
diff --git a/src/config.c b/src/config.c
index a8e15405b..2e341d256 100644
--- a/src/config.c
+++ b/src/config.c
@@ -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)
{
- 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
if (home == NULL)
@@ -342,10 +358,13 @@ int git_config_find_global(char *global_config_path)
if (home == NULL)
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_SUCCESS;
}
@@ -353,7 +372,7 @@ int git_config_find_global(char *global_config_path)
#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";
wchar_t *apphome_utf16;
@@ -378,25 +397,21 @@ static int win32_find_system(char *system_config_path)
apphome_utf8 = gitwin_from_utf16(apphome_utf16);
git__free(apphome_utf16);
- if (strlen(apphome_utf8) >= GIT_PATH_MAX) {
- git__free(apphome_utf8);
- return git__throw(GIT_ESHORTBUFFER, "Path is too long");
- }
+ git_buf_attach(system_config_path, apphome_utf8, 0);
- strcpy(system_config_path, apphome_utf8);
- git__free(apphome_utf8);
return GIT_SUCCESS;
}
#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) {
- memcpy(system_config_path, etc, strlen(etc) + 1);
+ if (git_futils_exists(system_config_path->ptr) == GIT_SUCCESS)
return GIT_SUCCESS;
- }
+
+ git_buf_clear(system_config_path);
#if GIT_WIN32
return win32_find_system(system_config_path);
@@ -405,6 +420,23 @@ int git_config_find_system(char *system_config_path)
#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 error;
diff --git a/src/config.h b/src/config.h
index 7f3494edc..fc639c6d4 100644
--- a/src/config.h
+++ b/src/config.h
@@ -21,4 +21,7 @@ struct git_config {
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
diff --git a/src/fetch.c b/src/fetch.c
index f447248c5..f9e15b232 100644
--- a/src/fetch.c
+++ b/src/fetch.c
@@ -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 */
-int git_fetch__download_pack(char **out, const char *buffered, size_t buffered_size,
- GIT_SOCKET fd, git_repository *repo)
+int git_fetch__download_pack(
+ char **out,
+ const char *buffered,
+ size_t buffered_size,
+ GIT_SOCKET fd,
+ git_repository *repo)
{
git_filebuf file = GIT_FILEBUF_INIT;
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";
gitno_buffer buf;
-
- git_path_join(path, repo->path_repository, suff);
-
gitno_buffer_setup(&buf, buff, sizeof(buff), fd);
if (memcmp(buffered, "PACK", strlen("PACK"))) {
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)
goto cleanup;
@@ -166,7 +172,7 @@ int git_fetch__download_pack(char **out, const char *buffered, size_t buffered_s
cleanup:
if (error < GIT_SUCCESS)
git_filebuf_cleanup(&file);
+ git_buf_free(&path);
return error;
-
}
diff --git a/src/filebuf.c b/src/filebuf.c
index 6600bfa4b..aa47d5eb0 100644
--- a/src/filebuf.c
+++ b/src/filebuf.c
@@ -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 (flags & GIT_FILEBUF_TEMPORARY) {
- char tmp_path[GIT_PATH_MAX];
+ git_buf tmp_path = GIT_BUF_INIT;
/* 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) {
+ git_buf_free(&tmp_path);
error = GIT_EOSERR;
goto cleanup;
}
/* No original path */
file->path_original = NULL;
- file->path_lock = git__strdup(tmp_path);
+ file->path_lock = git_buf_detach(&tmp_path);
if (file->path_lock == NULL) {
error = GIT_ENOMEM;
diff --git a/src/fileops.c b/src/fileops.c
index 955bb1bf6..fb2f954d7 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -10,35 +10,40 @@
int git_futils_mkpath2file(const char *file_path, const mode_t mode)
{
- int error = GIT_SUCCESS;
- char target_folder_path[GIT_PATH_MAX];
+ int error;
+ git_buf target_folder = GIT_BUF_INIT;
- error = git_path_dirname_r(target_folder_path, sizeof(target_folder_path), file_path);
- if (error < GIT_SUCCESS)
+ error = git_path_dirname_r(&target_folder, file_path);
+ 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);
+ } else {
+ /* reset error */
+ error = GIT_SUCCESS;
+ }
/* Does the containing folder exist? */
- if (git_futils_isdir(target_folder_path)) {
- git_path_join(target_folder_path, target_folder_path, ""); /* Ensure there's a trailing slash */
-
+ if (git_futils_isdir(target_folder.ptr) != GIT_SUCCESS)
/* Let's create the tree structure */
- error = git_futils_mkdir_r(target_folder_path, mode);
- if (error < GIT_SUCCESS)
- return error; /* The callee already takes care of setting the correct error message. */
- }
+ error = git_futils_mkdir_r(target_folder.ptr, NULL, mode);
- 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;
- strcpy(path_out, filename);
- strcat(path_out, "_git2_XXXXXX");
+ git_buf_sets(path_out, filename);
+ 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)
- return git__throw(GIT_EOSERR, "Failed to create temporary file %s", path_out);
+ if ((fd = p_mkstemp(path_out->ptr)) < 0)
+ return git__throw(GIT_EOSERR, "Failed to create temporary file %s", path_out->ptr);
return fd;
}
@@ -180,6 +185,14 @@ int git_futils_readbuffer(git_fbuffer *obj, const char *path)
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)
{
assert(obj);
@@ -215,76 +228,72 @@ GIT_INLINE(int) is_dot_or_dotdot(const char *name)
}
int git_futils_direach(
- char *path,
- size_t path_sz,
- int (*fn)(void *, char *),
+ git_buf *path,
+ int (*fn)(void *, git_buf *),
void *arg)
{
- size_t wd_len = strlen(path);
+ ssize_t wd_len;
DIR *dir;
struct dirent *de;
- if (!wd_len || path_sz < wd_len + 2)
- return git__throw(GIT_EINVALIDARGS, "Failed to process `%s` tree structure. Path is either empty or buffer size is too short", path);
-
- while (path[wd_len - 1] == '/')
- wd_len--;
- path[wd_len++] = '/';
- path[wd_len] = '\0';
+ if (git_path_to_dir(path) < GIT_SUCCESS)
+ return git_buf_lasterror(path);
- dir = opendir(path);
+ wd_len = path->size;
+ dir = opendir(path->ptr);
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) {
- size_t de_len;
int result;
if (is_dot_or_dotdot(de->d_name))
continue;
- de_len = strlen(de->d_name);
- if (path_sz < wd_len + de_len + 1) {
- closedir(dir);
- return git__throw(GIT_ERROR, "Failed to process `%s` tree structure. Buffer size is too short", path);
- }
+ if (git_buf_puts(path, de->d_name) < GIT_SUCCESS)
+ return git_buf_lasterror(path);
- strcpy(path + wd_len, de->d_name);
result = fn(arg, path);
- if (result < GIT_SUCCESS) {
+
+ git_buf_truncate(path, wd_len); /* restore path */
+
+ if (result != GIT_SUCCESS) {
closedir(dir);
return result; /* The callee is reponsible for setting the correct error message */
}
- if (result > 0) {
- closedir(dir);
- return result;
- }
}
closedir(dir);
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;
+ git_buf make_path = GIT_BUF_INIT;
+ size_t start;
char *pp, *sp;
- char *path_copy = git__strdup(path);
- if (path_copy == NULL)
- return GIT_ENOMEM;
+ if (base != NULL) {
+ 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 = path_copy;
+ pp = make_path.ptr + start;
- root_path_offset = git_path_root(pp);
+ root_path_offset = git_path_root(make_path.ptr);
if (root_path_offset > 0)
pp += root_path_offset; /* On Windows, will skip the drive name (eg. C: or D:) */
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;
- error = p_mkdir(path_copy, mode);
+ error = p_mkdir(make_path.ptr, mode);
/* Do not choke while trying to recreate an existing directory */
if (errno == EEXIST)
@@ -297,12 +306,12 @@ int git_futils_mkdir_r(const char *path, const mode_t mode)
}
if (*pp != '\0' && error == GIT_SUCCESS) {
- error = p_mkdir(path, mode);
+ error = p_mkdir(make_path.ptr, mode);
if (errno == EEXIST)
error = GIT_SUCCESS;
}
- git__free(path_copy);
+ git_buf_free(&make_path);
if (error < GIT_SUCCESS)
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)
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 force = *(int *)opaque;
- if (git_futils_isdir(path) == GIT_SUCCESS) {
- size_t root_size = strlen(path);
-
- 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);
-
- path[root_size] = '\0';
- return p_rmdir(path);
+ if (git_futils_isdir(path->ptr) == GIT_SUCCESS) {
+ error = git_futils_direach(path, _rmdir_recurs_foreach, opaque);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to remove directory `%s`", path->ptr);
+ return p_rmdir(path->ptr);
} 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)
{
- char p[GIT_PATH_MAX];
- strncpy(p, path, GIT_PATH_MAX);
- return _rmdir_recurs_foreach(&force, p);
+ int error;
+ git_buf p = GIT_BUF_INIT;
+
+ 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,
@@ -356,3 +367,39 @@ int git_futils_cmp_path(const char *name1, int len1, int isdir1,
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);
+}
+
diff --git a/src/fileops.h b/src/fileops.h
index e1a59f633..df135d0db 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -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_updated(git_fbuffer *obj, const char *path, time_t *mtime, int *updated);
extern void git_futils_freebuffer(git_fbuffer *obj);
+extern void git_futils_fbuffer_rtrim(git_fbuffer *obj);
/**
* File utils
@@ -72,9 +73,25 @@ extern int git_futils_isdir(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
*/
-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
@@ -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);
/**
- * 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
@@ -133,16 +152,14 @@ extern void git_futils_mmap_free(git_map *map);
*
* @param pathbuf buffer the function reads the initial directory
* 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
* the input state and the second arg is pathbuf. The function
* may modify the pathbuf, but only by appending new text.
* @param state to pass to fn as the first arg.
*/
extern int git_futils_direach(
- char *pathbuf,
- size_t pathmax,
- int (*fn)(void *, char *),
+ git_buf *pathbuf,
+ int (*fn)(void *, git_buf *),
void *state);
extern int git_futils_cmp_path(const char *name1, int len1, int isdir1,
diff --git a/src/index.c b/src/index.c
index 9f336ba0a..9baab16a9 100644
--- a/src/index.c
+++ b/src/index.c
@@ -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)
{
- git_index_entry *entry;
- char full_path[GIT_PATH_MAX];
+ git_index_entry *entry = NULL;
struct stat st;
git_oid oid;
int error;
- const char *workdir;
if (INDEX_OWNER(index) == NULL)
return git__throw(GIT_EBAREINDEX,
"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)
return git__throw(GIT_ERROR,
"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 */
if ((error = git_blob_create_fromfile(&oid, INDEX_OWNER(index), rel_path)) < GIT_SUCCESS)
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)
return GIT_ENOMEM;
- memset(entry, 0x0, sizeof(git_index_entry));
entry->ctime.seconds = (git_time_t)st.st_ctime;
entry->mtime.seconds = (git_time_t)st.st_mtime;
diff --git a/src/indexer.c b/src/indexer.c
index a69ab850c..8fdf89d9d 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -151,28 +151,35 @@ cleanup:
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";
+ 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));
- ptr += strlen(prefix);
- git_oid_fmt(ptr, &idx->hash);
- ptr += GIT_OID_HEXSZ;
- memcpy(ptr, suffix, strlen(suffix) + 1);
+ if (git_buf_grow(path, slash + 1 + strlen(prefix) +
+ GIT_OID_HEXSZ + strlen(suffix) + 1) < GIT_SUCCESS)
+ return GIT_ENOMEM;
+
+ 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)
{
git_mwindow *w = NULL;
int error;
- size_t namelen;
unsigned int i, long_offsets = 0, left;
struct git_pack_idx_header hdr;
- char filename[GIT_PATH_MAX];
+ git_buf filename = GIT_BUF_INIT;
struct entry *entry;
void *packfile_hash;
git_oid file_hash;
@@ -180,16 +187,23 @@ int git_indexer_write(git_indexer *idx)
git_vector_sort(&idx->objects);
- namelen = strlen(idx->pack->pack_name);
- memcpy(filename, idx->pack->pack_name, namelen);
- memcpy(filename + namelen - strlen("pack"), "idx", strlen("idx") + 1);
+ git_buf_sets(&filename, idx->pack->pack_name);
+ git_buf_truncate(&filename, filename.size - strlen("pack"));
+ 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 */
hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
hdr.idx_version = htonl(2);
error = git_filebuf_write(&idx->file, &hdr, sizeof(hdr));
+ if (error < GIT_SUCCESS)
+ goto cleanup;
/* Write out the fanout table */
for (i = 0; i < 256; ++i) {
@@ -270,14 +284,18 @@ int git_indexer_write(git_indexer *idx)
goto cleanup;
/* 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 */
- 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:
git_mwindow_free_all(&idx->pack->mwf);
if (error < GIT_SUCCESS)
git_filebuf_cleanup(&idx->file);
+ git_buf_free(&filename);
return error;
}
diff --git a/src/odb.c b/src/odb.c
index d31f93f73..b52f87078 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -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)
{
- char alternates_path[GIT_PATH_MAX];
- char *buffer, *alternate;
-
+ git_buf alternates_path = GIT_BUF_INIT;
+ char *buffer;
git_fbuffer alternates_buf = GIT_FBUFFER_INIT;
+ const char *alternate;
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;
+ }
- 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");
+ }
buffer = (char *)alternates_buf.data;
error = GIT_SUCCESS;
/* add each alternate as a new backend; one alternate per line */
while ((alternate = git__strtok(&buffer, "\r\n")) != NULL) {
- char full_path[GIT_PATH_MAX];
-
if (*alternate == '\0' || *alternate == '#')
continue;
/* relative path: build based on the current `objects` folder */
if (*alternate == '.') {
- git_path_join(full_path, objects_dir, alternate);
- alternate = full_path;
+ error = git_buf_joinpath(&alternates_path, objects_dir, alternate);
+ if (error < GIT_SUCCESS)
+ break;
+ alternate = git_buf_cstr(&alternates_path);
}
if ((error = add_default_backends(odb, alternate, 1)) < GIT_SUCCESS)
break;
}
+ git_buf_free(&alternates_path);
git_futils_freebuffer(&alternates_buf);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to load alternates");
diff --git a/src/odb_loose.c b/src/odb_loose.c
index f1789e071..f177af86c 100644
--- a/src/odb_loose.c
+++ b/src/odb_loose.c
@@ -26,7 +26,6 @@ typedef struct { /* object header data */
typedef struct {
git_odb_stream stream;
git_filebuf fbuf;
- int finished;
} loose_writestream;
typedef struct loose_backend {
@@ -51,31 +50,28 @@ typedef struct {
} loose_locate_object_state;
-
/***********************************************************
*
* MISCELANEOUS HELPER FUNCTIONS
*
***********************************************************/
-static size_t object_file_name(char *name, size_t n, char *dir, const git_oid *id)
+static int object_file_name(git_buf *name, const char *dir, const git_oid *id)
{
- size_t len = strlen(dir);
+ git_buf_sets(name, dir);
- /* check length: 43 = 40 hex sha1 chars + 2 * '/' + '\0' */
- if (len+43 > n)
- return len+43;
+ /* expand length for 40 hex sha1 chars + 2 * '/' + '\0' */
+ if (git_buf_grow(name, name->size + GIT_OID_HEXSZ + 3) < GIT_SUCCESS)
+ return GIT_ENOMEM;
- /* the object dir: eg $GIT_DIR/objects */
- strcpy(name, dir);
- if (name[len-1] != '/')
- name[len++] = '/';
+ git_path_to_dir(name);
/* loose object filename: aa/aaa... (41 bytes) */
- git_oid_pathfmt(&name[len], id);
- name[len+41] = '\0';
+ git_oid_pathfmt(name->ptr + name->size, id);
+ name->size += GIT_OID_HEXSZ + 1;
+ name->ptr[name->size] = '\0';
- return 0;
+ return GIT_SUCCESS;
}
@@ -384,18 +380,21 @@ static int inflate_disk_obj(git_rawobj *out, git_fbuffer *obj)
*
***********************************************************/
-static int read_loose(git_rawobj *out, const char *loc)
+static int read_loose(git_rawobj *out, git_buf *loc)
{
int error;
git_fbuffer obj = GIT_FBUFFER_INIT;
assert(out && loc);
+ if ((error = git_buf_lasterror(loc)) < GIT_SUCCESS)
+ return error;
+
out->data = NULL;
out->len = 0;
out->type = GIT_OBJ_BAD;
- if (git_futils_readbuffer(&obj, loc) < 0)
+ if (git_futils_readbuffer(&obj, loc->ptr) < 0)
return git__throw(GIT_ENOTFOUND, "Failed to read loose object. File not found");
error = inflate_disk_obj(out, &obj);
@@ -404,7 +403,7 @@ static int read_loose(git_rawobj *out, const char *loc)
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to read loose object");
}
-static int read_header_loose(git_rawobj *out, const char *loc)
+static int read_header_loose(git_rawobj *out, git_buf *loc)
{
int error = GIT_SUCCESS, z_return = Z_ERRNO, read_bytes;
git_file fd;
@@ -414,9 +413,12 @@ static int read_header_loose(git_rawobj *out, const char *loc)
assert(out && loc);
+ if ((error = git_buf_lasterror(loc)) < GIT_SUCCESS)
+ return error;
+
out->data = NULL;
- if ((fd = p_open(loc, O_RDONLY)) < 0)
+ if ((fd = p_open(loc->ptr, O_RDONLY)) < 0)
return git__throw(GIT_ENOTFOUND, "Failed to read loose object header. File not found");
init_stream(&zs, inflated_buffer, sizeof(inflated_buffer));
@@ -456,33 +458,39 @@ cleanup:
return GIT_SUCCESS;
}
-static int locate_object(char *object_location, loose_backend *backend, const git_oid *oid)
+static int locate_object(
+ git_buf *object_location,
+ loose_backend *backend,
+ const git_oid *oid)
{
- object_file_name(object_location, GIT_PATH_MAX, backend->objects_dir, oid);
- return git_futils_exists(object_location);
+ int error = object_file_name(object_location, backend->objects_dir, oid);
+
+ if (error == GIT_SUCCESS)
+ error = git_futils_exists(git_buf_cstr(object_location));
+
+ return error;
}
/* Explore an entry of a directory and see if it matches a short oid */
-static int fn_locate_object_short_oid(void *state, char *pathbuf) {
+static int fn_locate_object_short_oid(void *state, git_buf *pathbuf) {
loose_locate_object_state *sstate = (loose_locate_object_state *)state;
- size_t pathbuf_len = strlen(pathbuf);
- if (pathbuf_len - sstate->dir_len != GIT_OID_HEXSZ - 2) {
+ if (pathbuf->size - sstate->dir_len != GIT_OID_HEXSZ - 2) {
/* Entry cannot be an object. Continue to next entry */
return GIT_SUCCESS;
}
- if (!git_futils_exists(pathbuf) && git_futils_isdir(pathbuf)) {
+ if (!git_futils_exists(pathbuf->ptr) && git_futils_isdir(pathbuf->ptr)) {
/* We are already in the directory matching the 2 first hex characters,
* compare the first ncmp characters of the oids */
if (!memcmp(sstate->short_oid + 2,
- (unsigned char *)pathbuf + sstate->dir_len,
+ (unsigned char *)pathbuf->ptr + sstate->dir_len,
sstate->short_oid_len - 2)) {
if (!sstate->found) {
sstate->res_oid[0] = sstate->short_oid[0];
sstate->res_oid[1] = sstate->short_oid[1];
- memcpy(sstate->res_oid+2, pathbuf+sstate->dir_len, GIT_OID_HEXSZ-2);
+ memcpy(sstate->res_oid+2, pathbuf->ptr+sstate->dir_len, GIT_OID_HEXSZ-2);
}
sstate->found++;
}
@@ -494,39 +502,50 @@ static int fn_locate_object_short_oid(void *state, char *pathbuf) {
}
/* Locate an object matching a given short oid */
-static int locate_object_short_oid(char *object_location, git_oid *res_oid, loose_backend *backend, const git_oid *short_oid, unsigned int len)
+static int locate_object_short_oid(
+ git_buf *object_location,
+ git_oid *res_oid,
+ loose_backend *backend,
+ const git_oid *short_oid,
+ unsigned int len)
{
char *objects_dir = backend->objects_dir;
size_t dir_len = strlen(objects_dir);
loose_locate_object_state state;
int error;
- if (dir_len+43 > GIT_PATH_MAX)
- return git__throw(GIT_ERROR, "Failed to locate object from short oid. Object path too long");
+ /* prealloc memory for OBJ_DIR/xx/ */
+ if ((error = git_buf_grow(object_location, dir_len + 5)) < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to locate object from short oid");
- strcpy(object_location, objects_dir);
+ git_buf_sets(object_location, objects_dir);
+ git_path_to_dir(object_location);
- /* Add a separator if not already there */
- if (object_location[dir_len-1] != '/')
- object_location[dir_len++] = '/';
+ /* save adjusted position at end of dir so it can be restored later */
+ dir_len = object_location->size;
/* Convert raw oid to hex formatted oid */
git_oid_fmt((char *)state.short_oid, short_oid);
+
/* Explore OBJ_DIR/xx/ where xx is the beginning of hex formatted short oid */
- sprintf(object_location+dir_len, "%.2s/", state.short_oid);
+ error = git_buf_printf(object_location, "%.2s/", state.short_oid);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to locate object from short oid");
/* Check that directory exists */
- if (git_futils_exists(object_location) || git_futils_isdir(object_location))
+ if (git_futils_exists(object_location->ptr) ||
+ git_futils_isdir(object_location->ptr))
return git__throw(GIT_ENOTFOUND, "Failed to locate object from short oid. Object not found");
- state.dir_len = dir_len+3;
+ state.dir_len = object_location->size;
state.short_oid_len = len;
state.found = 0;
+
/* Explore directory to find a unique object matching short_oid */
- error = git_futils_direach(object_location, GIT_PATH_MAX, fn_locate_object_short_oid, &state);
- if (error) {
+ error = git_futils_direach(object_location, fn_locate_object_short_oid, &state);
+ if (error)
return git__rethrow(error, "Failed to locate object from short oid");
- }
+
if (!state.found) {
return git__throw(GIT_ENOTFOUND, "Failed to locate object from short oid. Object not found");
}
@@ -538,7 +557,16 @@ static int locate_object_short_oid(char *object_location, git_oid *res_oid, loos
}
/* Update the location according to the oid obtained */
- git_oid_pathfmt(object_location+dir_len, res_oid);
+
+ git_buf_truncate(object_location, dir_len);
+ error = git_buf_grow(object_location, dir_len + GIT_OID_HEXSZ + 2);
+ if (error)
+ return git__rethrow(error, "Failed to locate object from short oid");
+
+ git_oid_pathfmt(object_location->ptr + dir_len, res_oid);
+
+ object_location->size += GIT_OID_HEXSZ + 1;
+ object_location->ptr[object_location->size] = '\0';
return GIT_SUCCESS;
}
@@ -561,45 +589,49 @@ static int locate_object_short_oid(char *object_location, git_oid *res_oid, loos
static int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
{
- char object_path[GIT_PATH_MAX];
+ git_buf object_path = GIT_BUF_INIT;
git_rawobj raw;
- int error;
+ int error = GIT_SUCCESS;
assert(backend && oid);
raw.len = 0;
raw.type = GIT_OBJ_BAD;
- if (locate_object(object_path, (loose_backend *)backend, oid) < 0)
- return git__throw(GIT_ENOTFOUND, "Failed to read loose backend header. Object not found");
+ if (locate_object(&object_path, (loose_backend *)backend, oid) < 0)
+ error = git__throw(GIT_ENOTFOUND, "Failed to read loose backend header. Object not found");
+ else if ((error = read_header_loose(&raw, &object_path)) == GIT_SUCCESS) {
+ *len_p = raw.len;
+ *type_p = raw.type;
+ }
- if ((error = read_header_loose(&raw, object_path)) < GIT_SUCCESS)
- return error;
+ git_buf_free(&object_path);
- *len_p = raw.len;
- *type_p = raw.type;
- return GIT_SUCCESS;
+ return error;
}
static int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
{
- char object_path[GIT_PATH_MAX];
+ git_buf object_path = GIT_BUF_INIT;
git_rawobj raw;
- int error;
+ int error = GIT_SUCCESS;
assert(backend && oid);
- if (locate_object(object_path, (loose_backend *)backend, oid) < 0)
- return git__throw(GIT_ENOTFOUND, "Failed to read loose backend. Object not found");
-
- if ((error = read_loose(&raw, object_path)) < GIT_SUCCESS)
- return git__rethrow(error, "Failed to read loose backend");
+ if (locate_object(&object_path, (loose_backend *)backend, oid) < 0)
+ error = git__throw(GIT_ENOTFOUND, "Failed to read loose backend. Object not found");
+ else if ((error = read_loose(&raw, &object_path)) == GIT_SUCCESS) {
+ *buffer_p = raw.data;
+ *len_p = raw.len;
+ *type_p = raw.type;
+ }
+ else {
+ git__rethrow(error, "Failed to read loose backend");
+ }
- *buffer_p = raw.data;
- *len_p = raw.len;
- *type_p = raw.type;
+ git_buf_free(&object_path);
- return GIT_SUCCESS;
+ return error;
}
static int loose_backend__read_prefix(
@@ -611,45 +643,52 @@ static int loose_backend__read_prefix(
const git_oid *short_oid,
unsigned int len)
{
+ int error = GIT_SUCCESS;
+
if (len < GIT_OID_MINPREFIXLEN)
- return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to read loose backend. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN);
+ return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to read loose "
+ "backend. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN);
if (len >= GIT_OID_HEXSZ) {
/* We can fall back to regular read method */
- int error = loose_backend__read(buffer_p, len_p, type_p, backend, short_oid);
+ error = loose_backend__read(buffer_p, len_p, type_p, backend, short_oid);
if (error == GIT_SUCCESS)
git_oid_cpy(out_oid, short_oid);
-
- return error;
} else {
- char object_path[GIT_PATH_MAX];
+ git_buf object_path = GIT_BUF_INIT;
git_rawobj raw;
- int error;
assert(backend && short_oid);
- if ((error = locate_object_short_oid(object_path, out_oid, (loose_backend *)backend, short_oid, len)) < 0) {
- return git__rethrow(error, "Failed to read loose backend");
+ if ((error = locate_object_short_oid(&object_path, out_oid,
+ (loose_backend *)backend, short_oid, len)) < 0)
+ git__rethrow(error, "Failed to read loose backend");
+ else if ((error = read_loose(&raw, &object_path)) < GIT_SUCCESS)
+ git__rethrow(error, "Failed to read loose backend");
+ else {
+ *buffer_p = raw.data;
+ *len_p = raw.len;
+ *type_p = raw.type;
}
- if ((error = read_loose(&raw, object_path)) < GIT_SUCCESS)
- return git__rethrow(error, "Failed to read loose backend");
-
- *buffer_p = raw.data;
- *len_p = raw.len;
- *type_p = raw.type;
+ git_buf_free(&object_path);
}
- return GIT_SUCCESS;
+ return error;
}
static int loose_backend__exists(git_odb_backend *backend, const git_oid *oid)
{
- char object_path[GIT_PATH_MAX];
+ git_buf object_path = GIT_BUF_INIT;
+ int error;
assert(backend && oid);
- return locate_object(object_path, (loose_backend *)backend, oid) == GIT_SUCCESS;
+ error = locate_object(&object_path, (loose_backend *)backend, oid);
+
+ git_buf_free(&object_path);
+
+ return (error == GIT_SUCCESS);
}
static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream)
@@ -658,30 +697,39 @@ static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream)
loose_backend *backend = (loose_backend *)_stream->backend;
int error;
- char final_path[GIT_PATH_MAX];
+ git_buf final_path = GIT_BUF_INIT;
if ((error = git_filebuf_hash(oid, &stream->fbuf)) < GIT_SUCCESS)
- return git__rethrow(error, "Failed to write loose backend");
+ goto cleanup;
- if (object_file_name(final_path, sizeof(final_path), backend->objects_dir, oid))
- return GIT_ENOMEM;
+ if ((error = object_file_name(&final_path, backend->objects_dir, oid)) < GIT_SUCCESS)
+ goto cleanup;
- if ((error = git_futils_mkpath2file(final_path, GIT_OBJECT_DIR_MODE)) < GIT_SUCCESS)
- return git__rethrow(error, "Failed to write loose backend");
+ if ((error = git_buf_lasterror(&final_path)) < GIT_SUCCESS)
+ goto cleanup;
- stream->finished = 1;
+ if ((error = git_futils_mkpath2file(final_path.ptr, GIT_OBJECT_DIR_MODE)) < GIT_SUCCESS)
+ goto cleanup;
/*
* Don't try to add an existing object to the repository. This
* is what git does and allows us to sidestep the fact that
* we're not allowed to overwrite a read-only file on Windows.
*/
- if (git_futils_exists(final_path) == GIT_SUCCESS) {
+ if (git_futils_exists(final_path.ptr) == GIT_SUCCESS) {
git_filebuf_cleanup(&stream->fbuf);
- return GIT_SUCCESS;
+ goto cleanup;
}
- return git_filebuf_commit_at(&stream->fbuf, final_path, GIT_OBJECT_FILE_MODE);
+ error = git_filebuf_commit_at(&stream->fbuf, final_path.ptr, GIT_OBJECT_FILE_MODE);
+
+cleanup:
+ git_buf_free(&final_path);
+
+ if (error < GIT_SUCCESS)
+ git__rethrow(error, "Failed to write loose backend");
+
+ return error;
}
static int loose_backend__stream_write(git_odb_stream *_stream, const char *data, size_t len)
@@ -694,9 +742,7 @@ static void loose_backend__stream_free(git_odb_stream *_stream)
{
loose_writestream *stream = (loose_writestream *)_stream;
- if (!stream->finished)
- git_filebuf_cleanup(&stream->fbuf);
-
+ git_filebuf_cleanup(&stream->fbuf);
git__free(stream);
}
@@ -718,7 +764,8 @@ static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_
loose_backend *backend;
loose_writestream *stream;
- char hdr[64], tmp_path[GIT_PATH_MAX];
+ char hdr[64];
+ git_buf tmp_path = GIT_BUF_INIT;
int hdrlen;
int error;
@@ -742,33 +789,38 @@ static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_
stream->stream.free = &loose_backend__stream_free;
stream->stream.mode = GIT_STREAM_WRONLY;
- git_path_join(tmp_path, backend->objects_dir, "tmp_object");
+ error = git_buf_joinpath(&tmp_path, backend->objects_dir, "tmp_object");
+ if (error < GIT_SUCCESS)
+ goto cleanup;
- error = git_filebuf_open(&stream->fbuf, tmp_path,
+ error = git_filebuf_open(&stream->fbuf, tmp_path.ptr,
GIT_FILEBUF_HASH_CONTENTS |
GIT_FILEBUF_TEMPORARY |
(backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT));
-
- if (error < GIT_SUCCESS) {
- git__free(stream);
- return git__rethrow(error, "Failed to create loose backend stream");
- }
+ if (error < GIT_SUCCESS)
+ goto cleanup;
error = stream->stream.write((git_odb_stream *)stream, hdr, hdrlen);
- if (error < GIT_SUCCESS) {
- git_filebuf_cleanup(&stream->fbuf);
- git__free(stream);
- return git__rethrow(error, "Failed to create loose backend stream");
- }
+ if (error < GIT_SUCCESS)
+ goto cleanup;
+
+ git_buf_free(&tmp_path);
*stream_out = (git_odb_stream *)stream;
return GIT_SUCCESS;
+
+cleanup:
+ git_buf_free(&tmp_path);
+ git_filebuf_cleanup(&stream->fbuf);
+ git__free(stream);
+ return git__rethrow(error, "Failed to create loose backend stream");
}
static int loose_backend__write(git_oid *oid, git_odb_backend *_backend, const void *data, size_t len, git_otype type)
{
int error, header_len;
- char final_path[GIT_PATH_MAX], header[64];
+ git_buf final_path = GIT_BUF_INIT;
+ char header[64];
git_filebuf fbuf = GIT_FILEBUF_INIT;
loose_backend *backend;
@@ -781,30 +833,35 @@ static int loose_backend__write(git_oid *oid, git_odb_backend *_backend, const v
return GIT_EOBJCORRUPTED;
}
- git_path_join(final_path, backend->objects_dir, "tmp_object");
+ error = git_buf_joinpath(&final_path, backend->objects_dir, "tmp_object");
+ if (error < GIT_SUCCESS)
+ goto cleanup;
- error = git_filebuf_open(&fbuf, final_path,
+ error = git_filebuf_open(&fbuf, final_path.ptr,
GIT_FILEBUF_HASH_CONTENTS |
GIT_FILEBUF_TEMPORARY |
(backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT));
-
if (error < GIT_SUCCESS)
- return error;
+ goto cleanup;
git_filebuf_write(&fbuf, header, header_len);
git_filebuf_write(&fbuf, data, len);
git_filebuf_hash(oid, &fbuf);
- if ((error = object_file_name(final_path, sizeof(final_path), backend->objects_dir, oid)) < GIT_SUCCESS)
+ error = object_file_name(&final_path, backend->objects_dir, oid);
+ if (error < GIT_SUCCESS)
goto cleanup;
- if ((error = git_futils_mkpath2file(final_path, GIT_OBJECT_DIR_MODE)) < GIT_SUCCESS)
+ error = git_futils_mkpath2file(final_path.ptr, GIT_OBJECT_DIR_MODE);
+ if (error < GIT_SUCCESS)
goto cleanup;
- return git_filebuf_commit_at(&fbuf, final_path, GIT_OBJECT_FILE_MODE);
+ error = git_filebuf_commit_at(&fbuf, final_path.ptr, GIT_OBJECT_FILE_MODE);
cleanup:
- git_filebuf_cleanup(&fbuf);
+ if (error < GIT_SUCCESS)
+ git_filebuf_cleanup(&fbuf);
+ git_buf_free(&final_path);
return error;
}
diff --git a/src/odb_pack.c b/src/odb_pack.c
index 800e7b0da..757d6277e 100644
--- a/src/odb_pack.c
+++ b/src/odb_pack.c
@@ -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_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 pack_entry_find(struct git_pack_entry *e,
@@ -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 git_pack_file *pack;
int error;
size_t i;
- if (git__suffixcmp(path, ".idx") != 0)
+ if (git__suffixcmp(path->ptr, ".idx") != 0)
return GIT_SUCCESS; /* not an index */
for (i = 0; i < backend->packs.length; ++i) {
struct git_pack_file *p = git_vector_get(&backend->packs, i);
- if (memcmp(p->pack_name, path, strlen(path) - strlen(".idx")) == 0)
+ if (memcmp(p->pack_name, path->ptr, path->size - strlen(".idx")) == 0)
return GIT_SUCCESS;
}
- error = git_packfile_check(&pack, path);
+ error = git_packfile_check(&pack, path->ptr);
if (error == GIT_ENOTFOUND) {
/* ignore missing .pack file as git does */
return GIT_SUCCESS;
@@ -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");
if (st.st_mtime != backend->pack_folder_mtime) {
- char path[GIT_PATH_MAX];
- strcpy(path, backend->pack_folder);
+ git_buf path = GIT_BUF_INIT;
+ git_buf_sets(&path, backend->pack_folder);
/* 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)
return git__rethrow(error, "Failed to refresh packfiles");
@@ -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)
{
- struct pack_backend *backend;
- char path[GIT_PATH_MAX];
+ struct pack_backend *backend = NULL;
+ git_buf path = GIT_BUF_INIT;
+ int error = GIT_SUCCESS;
backend = git__calloc(1, sizeof(struct pack_backend));
if (backend == NULL)
return GIT_ENOMEM;
- if (git_vector_init(&backend->packs, 8, packfile_sort__cb) < GIT_SUCCESS) {
- git__free(backend);
- return GIT_ENOMEM;
- }
+ error = git_vector_init(&backend->packs, 8, packfile_sort__cb);
+ if (error < GIT_SUCCESS)
+ goto cleanup;
- git_path_join(path, objects_dir, "pack");
- if (git_futils_isdir(path) == GIT_SUCCESS) {
- backend->pack_folder = git__strdup(path);
- backend->pack_folder_mtime = 0;
+ error = git_buf_joinpath(&path, objects_dir, "pack");
+ if (error < GIT_SUCCESS)
+ goto cleanup;
- if (backend->pack_folder == NULL) {
- git__free(backend);
- return GIT_ENOMEM;
- }
+ if (git_futils_isdir(git_buf_cstr(&path)) == GIT_SUCCESS) {
+ backend->pack_folder = git_buf_detach(&path);
+ backend->pack_folder_mtime = 0;
}
backend->parent.read = &pack_backend__read;
@@ -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_out = (git_odb_backend *)backend;
- return GIT_SUCCESS;
+
+cleanup:
+ if (error < GIT_SUCCESS)
+ git__free(backend);
+ git_buf_free(&path);
+
+ return error;
}
diff --git a/src/path.c b/src/path.c
index a8851dfdc..e4b49f35d 100644
--- a/src/path.c
+++ b/src/path.c
@@ -16,7 +16,7 @@
* Based on the Android implementation, BSD licensed.
* 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;
int len, result;
@@ -49,18 +49,13 @@ int git_path_basename_r(char *buffer, size_t bufflen, const char *path)
Exit:
result = len;
- if (buffer == NULL) {
- return result;
- }
- if (len > (int)bufflen-1) {
- len = (int)bufflen-1;
- result = GIT_ENOMEM;
- }
- if (len >= 0) {
- memmove(buffer, startp, len);
- buffer[len] = 0;
+ if (buffer != NULL) {
+ if (git_buf_set(buffer, startp, len) < GIT_SUCCESS)
+ return git__rethrow(git_buf_lasterror(buffer),
+ "Could not get basename of '%s'", path);
}
+
return result;
}
@@ -68,7 +63,7 @@ Exit:
* Based on the Android implementation, BSD licensed.
* 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;
int result, len;
@@ -114,59 +109,39 @@ int git_path_dirname_r(char *buffer, size_t bufflen, const char *path)
Exit:
result = len;
- if (len+1 > GIT_PATH_MAX) {
- return GIT_ENOMEM;
- }
- if (buffer == NULL)
- return result;
- if (len > (int)bufflen-1) {
- len = (int)bufflen-1;
- result = GIT_ENOMEM;
+ if (buffer != NULL) {
+ if (git_buf_set(buffer, path, len) < GIT_SUCCESS)
+ 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;
}
char *git_path_dirname(const char *path)
{
- char *dname = NULL;
- int len;
+ git_buf buf = GIT_BUF_INIT;
+ char *dirname;
- len = (path ? strlen(path) : 0) + 2;
- dname = (char *)git__malloc(len);
- if (dname == NULL)
- return NULL;
+ git_path_dirname_r(&buf, path);
+ dirname = git_buf_detach(&buf);
+ git_buf_free(&buf); /* avoid memleak if error occurs */
- if (git_path_dirname_r(dname, len, path) < GIT_SUCCESS) {
- git__free(dname);
- return NULL;
- }
-
- return dname;
+ return dirname;
}
char *git_path_basename(const char *path)
{
- char *bname = NULL;
- int len;
-
- len = (path ? strlen(path) : 0) + 2;
- bname = (char *)git__malloc(len);
- if (bname == NULL)
- return NULL;
+ git_buf buf = GIT_BUF_INIT;
+ char *basename;
- if (git_path_basename_r(bname, len, path) < GIT_SUCCESS) {
- git__free(bname);
- return NULL;
- }
+ git_path_basename_r(&buf, path);
+ basename = git_buf_detach(&buf);
+ git_buf_free(&buf); /* avoid memleak if error occurs */
- return bname;
+ return basename;
}
@@ -188,39 +163,6 @@ const char *git_path_topdir(const char *path)
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 offset = 0;
@@ -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 */
}
-int git_path_prettify(char *path_out, const char *path, const char *base)
+int git_path_prettify(git_buf *path_out, const char *path, const char *base)
{
- char *result;
+ char *result = NULL;
+ int error = GIT_SUCCESS;
+
+ git_buf_clear(path_out);
+
+ /* construct path if needed */
+ if (base != NULL && git_path_root(path) < 0) {
+ if ((error = git_buf_joinpath(path_out, base, path)) < GIT_SUCCESS)
+ return error;
+ path = path_out->ptr;
+ }
+
+ /* allow realpath to allocate the buffer */
+ if (path != NULL)
+ result = p_realpath(path, NULL);
- if (base == NULL || git_path_root(path) >= 0) {
- result = p_realpath(path, path_out);
+ if (result) {
+ error = git_buf_sets(path_out, result);
+ git__free(result);
} else {
- char aux_path[GIT_PATH_MAX];
- git_path_join(aux_path, base, path);
- result = p_realpath(aux_path, path_out);
+ error = GIT_EOSERR;
}
- 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)
- return GIT_EOSERR;
+ if (error == GIT_SUCCESS)
+ error = git_path_to_dir(path_out);
- end = strlen(path_out);
+ return error;
+}
- if (end && path_out[end - 1] != '/') {
- path_out[end] = '/';
- path_out[end + 1] = '\0';
- }
+int git_path_to_dir(git_buf *path)
+{
+ if (path->asize > 0 &&
+ path->size > 0 &&
+ path->ptr[path->size - 1] != '/')
+ git_buf_putc(path, '/');
- return GIT_SUCCESS;
+ return git_buf_lasterror(path);
}
+
+void git_path_string_to_dir(char* path, size_t size)
+{
+ size_t end = strlen(path);
+
+ if (end && path[end - 1] != '/' && end < size) {
+ path[end] = '/';
+ path[end + 1] = '\0';
+ }
+}
+
diff --git a/src/path.h b/src/path.h
index 51bedeed7..0c8cc349c 100644
--- a/src/path.h
+++ b/src/path.h
@@ -8,6 +8,7 @@
#define INCLUDE_path_h__
#include "common.h"
+#include "buffer.h"
/*
* The dirname() function shall take a pointer to a character string
@@ -22,11 +23,13 @@
* The `git_path_dirname` implementation is thread safe. The returned
* string must be manually free'd.
*
- * The `git_path_dirname_r` implementation expects a string allocated
- * by the user with big enough size.
+ * The `git_path_dirname_r` implementation writes the dirname to a `git_buf`
+ * 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 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
@@ -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
* string must be manually free'd.
*
- * The `git_path_basename_r` implementation expects a string allocated
- * by the user with big enough size.
+ * The `git_path_basename_r` implementation writes the basename to a `git_buf`.
+ * 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 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);
-/**
- * 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);
-}
+extern int git_path_root(const char *path);
-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);
-int git_path_prettify_dir(char *path_out, const char *path, const char *base);
+extern int git_path_to_dir(git_buf *path);
+extern void git_path_string_to_dir(char* path, size_t size);
#ifdef GIT_WIN32
GIT_INLINE(void) git_path_mkposix(char *path)
diff --git a/src/pkt.c b/src/pkt.c
index 9dfc40255..324265089 100644
--- a/src/pkt.c
+++ b/src/pkt.c
@@ -268,8 +268,7 @@ void git_pkt_free(git_pkt *pkt)
int git_pkt_buffer_flush(git_buf *buf)
{
- git_buf_put(buf, pkt_flush_str, strlen(pkt_flush_str));
- return git_buf_oom(buf) ? GIT_ENOMEM : GIT_SUCCESS;
+ return git_buf_put(buf, pkt_flush_str, strlen(pkt_flush_str));
}
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
git_buf_grow(buf, buf->size + len);
git_oid_fmt(oid, &head->oid);
- git_buf_printf(buf, "%04xwant %s%c%s\n", len, oid, 0, capstr);
-
- return git_buf_oom(buf) ? GIT_ENOMEM : GIT_SUCCESS;
+ return git_buf_printf(buf, "%04xwant %s%c%s\n", len, oid, 0, capstr);
}
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)
memset(oidhex, 0x0, sizeof(oidhex));
git_oid_fmt(oidhex, oid);
- git_buf_printf(buf, "%s%s\n", pkt_have_prefix, oidhex);
- return git_buf_oom(buf) ? GIT_ENOMEM : GIT_SUCCESS;
+ return git_buf_printf(buf, "%s%s\n", pkt_have_prefix, oidhex);
}
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)
{
- git_buf_puts(buf, pkt_done_str);
- return git_buf_oom(buf) ? GIT_ENOMEM : GIT_SUCCESS;
+ return git_buf_puts(buf, pkt_done_str);
}
int git_pkt_send_done(int fd)
diff --git a/src/posix.c b/src/posix.c
index 8c19588ee..916aad726 100644
--- a/src/posix.c
+++ b/src/posix.c
@@ -35,7 +35,8 @@ int p_getcwd(char *buffer_out, size_t size)
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;
}
diff --git a/src/reflog.c b/src/reflog.c
index fbaaaea67..84ce52d91 100644
--- a/src/reflog.c
+++ b/src/reflog.c
@@ -51,7 +51,7 @@ static int reflog_write(const char *log_path, const char *oid_old,
git_buf_puts(&log, oid_new);
git_signature__writebuf(&log, " ", committer);
- log.size--; /* drop LF */
+ git_buf_truncate(&log, log.size - 1); /* drop LF */
if (msg) {
if (strchr(msg, '\n')) {
@@ -65,15 +65,21 @@ static int reflog_write(const char *log_path, const char *oid_old,
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) {
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);
error = git_filebuf_commit(&fbuf, GIT_REFLOG_FILE_MODE);
git_buf_free(&log);
+
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write reflog");
}
@@ -176,7 +182,7 @@ void git_reflog_free(git_reflog *reflog)
int git_reflog_read(git_reflog **reflog, git_reference *ref)
{
int error;
- char log_path[GIT_PATH_MAX];
+ git_buf log_path = GIT_BUF_INIT;
git_fbuffer log_file = GIT_FBUFFER_INIT;
git_reflog *log = NULL;
@@ -185,23 +191,28 @@ int git_reflog_read(git_reflog **reflog, git_reference *ref)
if ((error = reflog_init(&log, ref)) < GIT_SUCCESS)
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) {
- git_reflog_free(log);
- return git__rethrow(error, "Failed to read reflog. Cannot read file `%s`", log_path);
+ if ((error = git_futils_readbuffer(&log_file, log_path.ptr)) < GIT_SUCCESS) {
+ git__rethrow(error, "Failed to read reflog. Cannot read file `%s`", log_path.ptr);
+ goto cleanup;
}
- error = reflog_parse(log, log_file.data, log_file.len);
-
- git_futils_freebuffer(&log_file);
-
- if (error == GIT_SUCCESS)
- *reflog = log;
+ if ((error = reflog_parse(log, log_file.data, log_file.len)) < GIT_SUCCESS)
+ git__rethrow(error, "Failed to read reflog");
else
+ *reflog = log;
+
+cleanup:
+ if (error != GIT_SUCCESS && log != NULL)
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,
@@ -210,7 +221,7 @@ int git_reflog_write(git_reference *ref, const git_oid *oid_old,
int error;
char old[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;
const git_oid *oid;
@@ -220,65 +231,83 @@ int git_reflog_write(git_reference *ref, const git_oid *oid_old,
oid = git_reference_oid(r);
if (oid == NULL) {
- git_reference_free(r);
- return git__throw(GIT_ERROR,
+ error = git__throw(GIT_ERROR,
"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_path_join_n(log_path, 3,
+ error = git_buf_join_n(&log_path, '/', 3,
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)) {
- error = git_futils_mkpath2file(log_path, GIT_REFLOG_DIR_MODE);
+ if (git_futils_exists(log_path.ptr)) {
+ error = git_futils_mkpath2file(log_path.ptr, GIT_REFLOG_DIR_MODE);
if (error < GIT_SUCCESS)
- return git__rethrow(error,
+ git__rethrow(error,
"Failed to write reflog. Cannot create reflog directory");
-
- } else if (git_futils_isfile(log_path)) {
- return git__throw(GIT_ERROR,
- "Failed to write reflog. `%s` is directory", log_path);
-
+ } else if (git_futils_isfile(log_path.ptr)) {
+ error = git__throw(GIT_ERROR,
+ "Failed to write reflog. `%s` is directory", log_path.ptr);
} 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");
}
+ if (error < GIT_SUCCESS)
+ goto cleanup;
+
if (oid_old)
- git_oid_to_string(old, GIT_OID_HEXSZ+1, oid_old);
+ git_oid_to_string(old, sizeof(old), oid_old);
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)
{
- char old_path[GIT_PATH_MAX];
- char new_path[GIT_PATH_MAX];
+ int error;
+ 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_REFLOG_DIR, ref->name);
- git_path_join_n(new_path, 3, ref->owner->path_repository,
- GIT_REFLOG_DIR, new_name);
+ git_buf_free(&old_path);
+ git_buf_free(&new_path);
- return p_rename(old_path, new_path);
+ return error;
}
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,
- GIT_REFLOG_DIR, ref->name);
+ if (error == GIT_SUCCESS && git_futils_exists(path.ptr) == 0)
+ error = p_unlink(path.ptr);
- if (git_futils_exists(path))
- return GIT_SUCCESS;
+ git_buf_free(&path);
- return p_unlink(path);
+ return error;
}
unsigned int git_reflog_entrycount(git_reflog *reflog)
diff --git a/src/refs.c b/src/refs.c
index 8931d5bac..8c3f700ad 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -88,9 +88,12 @@ void git_reference_free(git_reference *reference)
return;
git__free(reference->name);
+ reference->name = NULL;
- if (reference->flags & GIT_REF_SYMBOLIC)
+ if (reference->flags & GIT_REF_SYMBOLIC) {
git__free(reference->target.symbolic);
+ reference->target.symbolic = NULL;
+ }
git__free(reference);
}
@@ -123,14 +126,18 @@ static int reference_create(
static int reference_read(git_fbuffer *file_content, time_t *mtime, const char *repo_path, const char *ref_name, int *updated)
{
- char path[GIT_PATH_MAX];
+ git_buf path = GIT_BUF_INIT;
+ int error = GIT_SUCCESS;
assert(file_content && repo_path && ref_name);
/* Determine the full path of the file */
- git_path_join(path, repo_path, ref_name);
+ if ((error = git_buf_joinpath(&path, repo_path, ref_name)) == GIT_SUCCESS)
+ error = git_futils_readbuffer_updated(file_content, path.ptr, mtime, updated);
+
+ git_buf_free(&path);
- return git_futils_readbuffer_updated(file_content, path, mtime, updated);
+ return error;
}
static int loose_parse_symbolic(git_reference *ref, git_fbuffer *file_content)
@@ -195,14 +202,14 @@ static int loose_parse_oid(git_oid *oid, git_fbuffer *file_content)
return GIT_SUCCESS;
}
-static git_rtype loose_guess_rtype(const char *full_path)
+static git_rtype loose_guess_rtype(const git_buf *full_path)
{
git_fbuffer ref_file = GIT_FBUFFER_INIT;
git_rtype type;
type = GIT_REF_INVALID;
- if (git_futils_readbuffer(&ref_file, full_path) == GIT_SUCCESS) {
+ if (git_futils_readbuffer(&ref_file, full_path->ptr) == GIT_SUCCESS) {
if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0)
type = GIT_REF_SYMBOLIC;
else
@@ -287,14 +294,17 @@ cleanup:
static int loose_write(git_reference *ref)
{
git_filebuf file = GIT_FILEBUF_INIT;
- char ref_path[GIT_PATH_MAX];
+ git_buf ref_path = GIT_BUF_INIT;
int error;
struct stat st;
- git_path_join(ref_path, ref->owner->path_repository, ref->name);
+ error = git_buf_joinpath(&ref_path, ref->owner->path_repository, ref->name);
+ if (error < GIT_SUCCESS)
+ goto unlock;
- if ((error = git_filebuf_open(&file, ref_path, GIT_FILEBUF_FORCE)) < GIT_SUCCESS)
- return git__rethrow(error, "Failed to write loose reference");
+ error = git_filebuf_open(&file, ref_path.ptr, GIT_FILEBUF_FORCE);
+ if (error < GIT_SUCCESS)
+ goto unlock;
if (ref->flags & GIT_REF_OID) {
char oid[GIT_OID_HEXSZ + 1];
@@ -314,12 +324,15 @@ static int loose_write(git_reference *ref)
goto unlock;
}
- if (p_stat(ref_path, &st) == GIT_SUCCESS)
+ if (p_stat(ref_path.ptr, &st) == GIT_SUCCESS)
ref->mtime = st.st_mtime;
+ git_buf_free(&ref_path);
+
return git_filebuf_commit(&file, GIT_REFS_FILE_MODE);
unlock:
+ git_buf_free(&ref_path);
git_filebuf_cleanup(&file);
return git__rethrow(error, "Failed to write loose reference");
}
@@ -518,14 +531,13 @@ struct dirent_list_data {
void *callback_payload;
};
-static int _dirent_loose_listall(void *_data, char *full_path)
+static int _dirent_loose_listall(void *_data, git_buf *full_path)
{
struct dirent_list_data *data = (struct dirent_list_data *)_data;
- char *file_path = full_path + data->repo_path_len;
+ const char *file_path = full_path->ptr + data->repo_path_len;
- if (git_futils_isdir(full_path) == GIT_SUCCESS)
- return git_futils_direach(full_path, GIT_PATH_MAX,
- _dirent_loose_listall, _data);
+ if (git_futils_isdir(full_path->ptr) == GIT_SUCCESS)
+ return git_futils_direach(full_path, _dirent_loose_listall, _data);
/* do not add twice a reference that exists already in the packfile */
if ((data->list_flags & GIT_REF_PACKED) != 0 &&
@@ -540,20 +552,18 @@ static int _dirent_loose_listall(void *_data, char *full_path)
return data->callback(file_path, data->callback_payload);
}
-static int _dirent_loose_load(void *data, char *full_path)
+static int _dirent_loose_load(void *data, git_buf *full_path)
{
git_repository *repository = (git_repository *)data;
void *old_ref = NULL;
struct packref *ref;
- char *file_path;
+ const char *file_path;
int error;
- if (git_futils_isdir(full_path) == GIT_SUCCESS)
- return git_futils_direach(
- full_path, GIT_PATH_MAX,
- _dirent_loose_load, repository);
+ if (git_futils_isdir(full_path->ptr) == GIT_SUCCESS)
+ return git_futils_direach(full_path, _dirent_loose_load, repository);
- file_path = full_path + strlen(repository->path_repository);
+ file_path = full_path->ptr + strlen(repository->path_repository);
error = loose_lookup_to_packfile(&ref, repository, file_path);
if (error == GIT_SUCCESS) {
@@ -582,21 +592,24 @@ static int _dirent_loose_load(void *data, char *full_path)
*/
static int packed_loadloose(git_repository *repository)
{
- char refs_path[GIT_PATH_MAX];
+ int error = GIT_SUCCESS;
+ git_buf refs_path = GIT_BUF_INIT;
/* the packfile must have been previously loaded! */
assert(repository->references.packfile);
- git_path_join(refs_path, repository->path_repository, GIT_REFS_DIR);
+ if ((error = git_buf_joinpath(&refs_path,
+ repository->path_repository, GIT_REFS_DIR)) < GIT_SUCCESS)
+ return error;
/*
* Load all the loose files from disk into the Packfile table.
* This will overwrite any old packed entries with their
* updated loose versions
*/
- return git_futils_direach(
- refs_path, GIT_PATH_MAX,
- _dirent_loose_load, repository);
+ error = git_futils_direach(&refs_path, _dirent_loose_load, repository);
+ git_buf_free(&refs_path);
+ return error;
}
/*
@@ -704,20 +717,26 @@ static int packed_find_peel(git_repository *repo, struct packref *ref)
static int packed_remove_loose(git_repository *repo, git_vector *packing_list)
{
unsigned int i;
- char full_path[GIT_PATH_MAX];
+ git_buf full_path = GIT_BUF_INIT;
int error = GIT_SUCCESS;
for (i = 0; i < packing_list->length; ++i) {
struct packref *ref = git_vector_get(packing_list, i);
+ int an_error;
if ((ref->flags & GIT_PACKREF_WAS_LOOSE) == 0)
continue;
- git_path_join(full_path, repo->path_repository, ref->name);
+ an_error = git_buf_joinpath(&full_path, repo->path_repository, ref->name);
+
+ if (an_error == GIT_SUCCESS &&
+ git_futils_exists(full_path.ptr) == GIT_SUCCESS &&
+ p_unlink(full_path.ptr) < GIT_SUCCESS)
+ an_error = GIT_EOSERR;
- if (git_futils_exists(full_path) == GIT_SUCCESS &&
- p_unlink(full_path) < GIT_SUCCESS)
- error = GIT_EOSERR;
+ /* keep the error if we haven't seen one yet */
+ if (error > an_error)
+ error = an_error;
/*
* if we fail to remove a single file, this is *not* good,
@@ -727,6 +746,8 @@ static int packed_remove_loose(git_repository *repo, git_vector *packing_list)
*/
}
+ git_buf_free(&full_path);
+
return error == GIT_SUCCESS ?
GIT_SUCCESS :
git__rethrow(error, "Failed to remove loose packed reference");
@@ -747,9 +768,9 @@ static int packed_write(git_repository *repo)
{
git_filebuf pack_file = GIT_FILEBUF_INIT;
int error;
+ const char *errmsg = "Failed to write packed references file";
unsigned int i;
- char pack_file_path[GIT_PATH_MAX];
-
+ git_buf pack_file_path = GIT_BUF_INIT;
git_vector packing_list;
size_t total_refs;
@@ -758,7 +779,7 @@ static int packed_write(git_repository *repo)
total_refs = repo->references.packfile->key_count;
if ((error =
git_vector_init(&packing_list, total_refs, packed_sort)) < GIT_SUCCESS)
- return git__rethrow(error, "Failed to init packed refernces list");
+ return git__rethrow(error, "Failed to init packed references list");
/* Load all the packfile into a vector */
{
@@ -775,16 +796,23 @@ static int packed_write(git_repository *repo)
git_vector_sort(&packing_list);
/* Now we can open the file! */
- git_path_join(pack_file_path, repo->path_repository, GIT_PACKEDREFS_FILE);
- if ((error = git_filebuf_open(&pack_file, pack_file_path, 0)) < GIT_SUCCESS)
- return git__rethrow(error, "Failed to write open packed references file");
+ error = git_buf_joinpath(&pack_file_path, repo->path_repository, GIT_PACKEDREFS_FILE);
+ if (error < GIT_SUCCESS)
+ goto cleanup;
+
+ if ((error = git_filebuf_open(&pack_file, pack_file_path.ptr, 0)) < GIT_SUCCESS) {
+ errmsg = "Failed to open packed references file";
+ goto cleanup;
+ }
/* Packfiles have a header... apparently
* This is in fact not required, but we might as well print it
* just for kicks */
if ((error =
- git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < GIT_SUCCESS)
- return git__rethrow(error, "Failed to write packed references file header");
+ git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < GIT_SUCCESS) {
+ errmsg = "Failed to write packed references file header";
+ goto cleanup;
+ }
for (i = 0; i < packing_list.length; ++i) {
struct packref *ref = (struct packref *)git_vector_get(&packing_list, i);
@@ -812,17 +840,19 @@ cleanup:
error = packed_remove_loose(repo, &packing_list);
- if (p_stat(pack_file_path, &st) == GIT_SUCCESS)
+ if (p_stat(pack_file_path.ptr, &st) == GIT_SUCCESS)
repo->references.packfile_time = st.st_mtime;
}
}
else git_filebuf_cleanup(&pack_file);
git_vector_free(&packing_list);
+ git_buf_free(&pack_file_path);
- return error == GIT_SUCCESS ?
- GIT_SUCCESS :
- git__rethrow(error, "Failed to write packed references file");
+ if (error < GIT_SUCCESS)
+ git__rethrow(error, "%s", errmsg);
+
+ return error;
}
static int _reference_available_cb(const char *ref, void *data)
@@ -873,21 +903,25 @@ static int reference_available(
static int reference_exists(int *exists, git_repository *repo, const char *ref_name)
{
int error;
- char ref_path[GIT_PATH_MAX];
+ git_buf ref_path = GIT_BUF_INIT;
error = packed_load(repo);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Cannot resolve if a reference exists");
- git_path_join(ref_path, repo->path_repository, ref_name);
+ error = git_buf_joinpath(&ref_path, repo->path_repository, ref_name);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Cannot resolve if a reference exists");
- if (git_futils_isfile(ref_path) == GIT_SUCCESS ||
- git_hashtable_lookup(repo->references.packfile, ref_path) != NULL) {
+ if (git_futils_isfile(ref_path.ptr) == GIT_SUCCESS ||
+ git_hashtable_lookup(repo->references.packfile, ref_path.ptr) != NULL) {
*exists = 1;
} else {
*exists = 0;
}
+ git_buf_free(&ref_path);
+
return GIT_SUCCESS;
}
@@ -972,12 +1006,15 @@ static int reference_delete(git_reference *ref)
/* If the reference is loose, we can just remove the reference
* from the filesystem */
} else {
- char full_path[GIT_PATH_MAX];
git_reference *ref_in_pack;
+ git_buf full_path = GIT_BUF_INIT;
- git_path_join(full_path, ref->owner->path_repository, ref->name);
+ error = git_buf_joinpath(&full_path, ref->owner->path_repository, ref->name);
+ if (error < GIT_SUCCESS)
+ goto cleanup;
- error = p_unlink(full_path);
+ error = p_unlink(full_path.ptr);
+ git_buf_free(&full_path); /* done with path at this point */
if (error < GIT_SUCCESS)
goto cleanup;
@@ -1261,8 +1298,7 @@ int git_reference_set_target(git_reference *ref, const char *target)
int git_reference_rename(git_reference *ref, const char *new_name, int force)
{
int error;
-
- char aux_path[GIT_PATH_MAX];
+ git_buf aux_path = GIT_BUF_INIT;
char normalized[GIT_REFNAME_MAX];
const char *head_target = NULL;
@@ -1309,6 +1345,13 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
return git__rethrow(error,
"Failed to rename reference. Reference already exists");
+ /* Initialize path now so we won't get an allocation failure once
+ * we actually start removing things.
+ */
+ error = git_buf_joinpath(&aux_path, ref->owner->path_repository, new_name);
+ if (error < GIT_SUCCESS)
+ goto cleanup;
+
/*
* Now delete the old ref and remove an possibly existing directory
* named `new_name`. Note that using the internal `reference_delete`
@@ -1318,10 +1361,9 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
if ((error = reference_delete(ref)) < GIT_SUCCESS)
goto cleanup;
- git_path_join(aux_path, ref->owner->path_repository, new_name);
- if (git_futils_exists(aux_path) == GIT_SUCCESS) {
- if (git_futils_isdir(aux_path) == GIT_SUCCESS) {
- if ((error = git_futils_rmdir_r(aux_path, 0)) < GIT_SUCCESS)
+ if (git_futils_exists(aux_path.ptr) == GIT_SUCCESS) {
+ if (git_futils_isdir(aux_path.ptr) == GIT_SUCCESS) {
+ if ((error = git_futils_rmdir_r(aux_path.ptr, 0)) < GIT_SUCCESS)
goto rollback;
} else goto rollback;
}
@@ -1360,9 +1402,12 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
/*
* Rename the reflog file.
*/
- git_path_join_n(aux_path, 3, ref->owner->path_repository,
- GIT_REFLOG_DIR, ref->name);
- if (git_futils_exists(aux_path) == GIT_SUCCESS)
+ error = git_buf_join_n(&aux_path, '/', 3, ref->owner->path_repository,
+ GIT_REFLOG_DIR, ref->name);
+ if (error < GIT_SUCCESS)
+ goto cleanup;
+
+ if (git_futils_exists(aux_path.ptr) == GIT_SUCCESS)
error = git_reflog_rename(ref, new_name);
/*
@@ -1377,6 +1422,7 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
cleanup:
/* We no longer need the newly created reference nor the head */
git_reference_free(head);
+ git_buf_free(&aux_path);
return error == GIT_SUCCESS ?
GIT_SUCCESS :
git__rethrow(error, "Failed to rename reference");
@@ -1395,6 +1441,8 @@ rollback:
/* The reference is no longer packed */
ref->flags &= ~GIT_REF_PACKED;
+ git_buf_free(&aux_path);
+
return error == GIT_SUCCESS ?
git__rethrow(GIT_ERROR, "Failed to rename reference. Did rollback") :
git__rethrow(error, "Failed to rename reference. Failed to rollback");
@@ -1467,7 +1515,7 @@ int git_reference_foreach(
{
int error;
struct dirent_list_data data;
- char refs_path[GIT_PATH_MAX];
+ git_buf refs_path = GIT_BUF_INIT;
/* list all the packed references first */
if (list_flags & GIT_REF_PACKED) {
@@ -1493,8 +1541,15 @@ int git_reference_foreach(
data.callback = callback;
data.callback_payload = payload;
- git_path_join(refs_path, repo->path_repository, GIT_REFS_DIR);
- return git_futils_direach(refs_path, GIT_PATH_MAX, _dirent_loose_listall, &data);
+ if ((error = git_buf_joinpath(&refs_path,
+ repo->path_repository, GIT_REFS_DIR)) < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to alloc space for references");
+
+ error = git_futils_direach(&refs_path, _dirent_loose_listall, &data);
+
+ git_buf_free(&refs_path);
+
+ return error;
}
static int cb__reflist_add(const char *ref, void *data)
diff --git a/src/refspec.c b/src/refspec.c
index 62683e7b7..7ce32ba14 100644
--- a/src/refspec.c
+++ b/src/refspec.c
@@ -93,3 +93,21 @@ int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, con
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);
+}
diff --git a/src/refspec.h b/src/refspec.h
index 7c389719b..cd9f894bf 100644
--- a/src/refspec.h
+++ b/src/refspec.h
@@ -8,6 +8,7 @@
#define INCLUDE_refspec_h__
#include "git2/refspec.h"
+#include "buffer.h"
struct git_refspec {
struct git_refspec *next;
@@ -20,4 +21,15 @@ struct git_refspec {
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
diff --git a/src/remote.c b/src/remote.c
index eca3f7748..ef42c6e2a 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -263,7 +263,7 @@ int git_remote_update_tips(git_remote *remote)
{
int error = GIT_SUCCESS;
unsigned int i = 0;
- char refname[GIT_PATH_MAX];
+ git_buf refname = GIT_BUF_INIT;
git_vector *refs = &remote->refs;
git_remote_head *head;
git_reference *ref;
@@ -271,8 +271,6 @@ int git_remote_update_tips(git_remote *remote)
assert(remote);
- memset(refname, 0x0, sizeof(refname));
-
if (refs->length == 0)
return GIT_SUCCESS;
@@ -289,18 +287,20 @@ int git_remote_update_tips(git_remote *remote)
for (; i < refs->length; ++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)
- 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)
- return error;
+ break;
git_reference_free(ref);
}
- return GIT_SUCCESS;
+ git_buf_free(&refname);
+
+ return error;
}
int git_remote_connected(git_remote *remote)
diff --git a/src/repository.c b/src/repository.c
index 0cd4a8123..67afa2ee2 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -75,21 +75,17 @@ void git_repository_free(git_repository *repo)
*
* Open a repository object from its path
*/
-static int quickcheck_repository_dir(const char *repository_path)
+static int quickcheck_repository_dir(git_buf *repository_path)
{
- char path_aux[GIT_PATH_MAX];
-
- /* Ensure HEAD file exists */
- git_path_join(path_aux, repository_path, GIT_HEAD_FILE);
- if (git_futils_isfile(path_aux) < 0)
+ /* Check OBJECTS_DIR first, since it will generate the longest path name */
+ if (git_futils_contains_dir(repository_path, GIT_OBJECTS_DIR, 0) < 0)
return GIT_ERROR;
- git_path_join(path_aux, repository_path, GIT_OBJECTS_DIR);
- if (git_futils_isdir(path_aux) < 0)
+ /* Ensure HEAD file exists */
+ if (git_futils_contains_file(repository_path, GIT_HEAD_FILE, 0) < 0)
return GIT_ERROR;
- git_path_join(path_aux, repository_path, GIT_REFS_DIR);
- if (git_futils_isdir(path_aux) < 0)
+ if (git_futils_contains_dir(repository_path, GIT_REFS_DIR, 0) < 0)
return GIT_ERROR;
return GIT_SUCCESS;
@@ -135,74 +131,74 @@ static int load_config_data(git_repository *repo)
static int load_workdir(git_repository *repo)
{
- if (!repo->is_bare) {
- char workdir_buf[GIT_PATH_MAX];
+ int error;
+ git_buf workdir_buf = GIT_BUF_INIT;
- if (git_path_dirname_r(workdir_buf, sizeof(workdir_buf), repo->path_repository) < 0)
- return git__throw(GIT_EOSERR,
- "Failed to resolved working directory");
+ if (repo->is_bare)
+ return GIT_SUCCESS;
- git_path_join(workdir_buf, workdir_buf, "");
+ git_path_dirname_r(&workdir_buf, repo->path_repository);
+ git_path_to_dir(&workdir_buf);
- repo->workdir = git__strdup(workdir_buf);
- if (repo->workdir == NULL)
- return GIT_ENOMEM;
- }
+ if ((error = git_buf_lasterror(&workdir_buf)) == GIT_SUCCESS)
+ repo->workdir = git_buf_detach(&workdir_buf);
- return GIT_SUCCESS;
+ git_buf_free(&workdir_buf);
+
+ return error;
}
int git_repository_open(git_repository **repo_out, const char *path)
{
int error = GIT_SUCCESS;
- char path_buf[GIT_PATH_MAX];
- size_t path_len;
+ git_buf path_buf = GIT_BUF_INIT;
git_repository *repo = NULL;
- error = git_path_prettify_dir(path_buf, path, NULL);
+ error = git_path_prettify_dir(&path_buf, path, NULL);
if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to open repository");
-
- path_len = strlen(path_buf);
+ goto cleanup;
/**
* Check if the path we've been given is actually the path
* of the working dir, by testing if it contains a `.git`
* folder inside of it.
*/
- git_path_join(path_buf, path_buf, DOT_GIT);
- if (git_futils_isdir(path_buf) < GIT_SUCCESS) {
- path_buf[path_len] = 0;
- }
+ git_futils_contains_dir(&path_buf, DOT_GIT, 1); /* append on success */
+ /* ignore error, since it just means `path/.git` doesn't exist */
- if (quickcheck_repository_dir(path_buf) < GIT_SUCCESS)
- return git__throw(GIT_ENOTAREPO,
+ if (quickcheck_repository_dir(&path_buf) < GIT_SUCCESS) {
+ error = git__throw(GIT_ENOTAREPO,
"The given path is not a valid Git repository");
+ goto cleanup;
+ }
repo = repository_alloc();
- if (repo == NULL)
- return GIT_ENOMEM;
+ if (repo == NULL) {
+ error = GIT_ENOMEM;
+ goto cleanup;
+ }
- repo->path_repository = git__strdup(path_buf);
+ repo->path_repository = git_buf_detach(&path_buf);
if (repo->path_repository == NULL) {
- git_repository_free(repo);
- return GIT_ENOMEM;
+ error = GIT_ENOMEM;
+ goto cleanup;
}
error = load_config_data(repo);
- if (error < GIT_SUCCESS) {
- git_repository_free(repo);
- return error;
- }
+ if (error < GIT_SUCCESS)
+ goto cleanup;
error = load_workdir(repo);
- if (error < GIT_SUCCESS) {
- git_repository_free(repo);
- return error;
- }
+ if (error < GIT_SUCCESS)
+ goto cleanup;
*repo_out = repo;
return GIT_SUCCESS;
+
+ cleanup:
+ git_repository_free(repo);
+ git_buf_free(&path_buf);
+ return error;
}
static int load_config(
@@ -211,7 +207,7 @@ static int load_config(
const char *global_config_path,
const char *system_config_path)
{
- char config_path[GIT_PATH_MAX];
+ git_buf config_path = GIT_BUF_INIT;
int error;
git_config *cfg = NULL;
@@ -221,8 +217,13 @@ static int load_config(
if (error < GIT_SUCCESS)
return error;
- git_path_join(config_path, repo->path_repository, GIT_CONFIG_FILENAME_INREPO);
- error = git_config_add_file_ondisk(cfg, config_path, 3);
+ error = git_buf_joinpath(&config_path, repo->path_repository,
+ GIT_CONFIG_FILENAME_INREPO);
+ if (error < GIT_SUCCESS)
+ goto cleanup;
+
+ error = git_config_add_file_ondisk(cfg, config_path.ptr, 3);
+ git_buf_free(&config_path); /* done with config_path now */
if (error < GIT_SUCCESS)
goto cleanup;
@@ -251,19 +252,22 @@ int git_repository_config__weakptr(git_config **out, git_repository *repo)
{
if (repo->_config == NULL) {
int error;
-
- char buf_global[GIT_PATH_MAX], buf_system[GIT_PATH_MAX];
+ git_buf global_buf = GIT_BUF_INIT, system_buf = GIT_BUF_INIT;
const char *global_config_path = NULL;
const char *system_config_path = NULL;
- if (git_config_find_global(buf_global) == GIT_SUCCESS)
- global_config_path = buf_global;
+ if (git_config_find_global_r(&global_buf) == GIT_SUCCESS)
+ global_config_path = global_buf.ptr;
- if (git_config_find_system(buf_system) == GIT_SUCCESS)
- system_config_path = buf_system;
+ if (git_config_find_system_r(&system_buf) == GIT_SUCCESS)
+ system_config_path = system_buf.ptr;
error = load_config(&repo->_config, repo, global_config_path, system_config_path);
+
+ git_buf_free(&global_buf);
+ git_buf_free(&system_buf);
+
if (error < GIT_SUCCESS)
return error;
@@ -301,11 +305,14 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
if (repo->_odb == NULL) {
int error;
- char odb_path[GIT_PATH_MAX];
+ git_buf odb_path = GIT_BUF_INIT;
- git_path_join(odb_path, repo->path_repository, GIT_OBJECTS_DIR);
+ error = git_buf_joinpath(&odb_path, repo->path_repository, GIT_OBJECTS_DIR);
+ if (error < GIT_SUCCESS)
+ return error;
- error = git_odb_open(&repo->_odb, odb_path);
+ error = git_odb_open(&repo->_odb, odb_path.ptr);
+ git_buf_free(&odb_path); /* done with path */
if (error < GIT_SUCCESS)
return error;
@@ -346,11 +353,14 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo)
if (repo->_index == NULL) {
int error;
- char index_path[GIT_PATH_MAX];
+ git_buf index_path = GIT_BUF_INIT;
- git_path_join(index_path, repo->path_repository, GIT_INDEX_FILE);
+ error = git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE);
+ if (error < GIT_SUCCESS)
+ return error;
- error = git_index_open(&repo->_index, index_path);
+ error = git_index_open(&repo->_index, index_path.ptr);
+ git_buf_free(&index_path); /* done with path */
if (error < GIT_SUCCESS)
return error;
@@ -397,7 +407,17 @@ static int retrieve_device(dev_t *device_out, const char *path)
return GIT_SUCCESS;
}
-static int retrieve_ceiling_directories_offset(const char *path, const char *ceiling_directories)
+/*
+ * This function returns furthest offset into path where a ceiling dir
+ * is found, so we can stop processing the path at that point.
+ *
+ * Note: converting this to use git_bufs instead of GIT_PATH_MAX buffers on
+ * the stack could remove directories name limits, but at the cost of doing
+ * repeated malloc/frees inside the loop below, so let's not do it now.
+ */
+static int retrieve_ceiling_directories_offset(
+ const char *path,
+ const char *ceiling_directories)
{
char buf[GIT_PATH_MAX + 1];
char buf2[GIT_PATH_MAX + 1];
@@ -416,7 +436,7 @@ static int retrieve_ceiling_directories_offset(const char *path, const char *cei
for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++);
len = sep - ceil;
- if (len == 0 || len > GIT_PATH_MAX || git_path_root(ceil) == -1)
+ if (len == 0 || len >= (int)sizeof(buf) || git_path_root(ceil) == -1)
continue;
strncpy(buf, ceil, len);
@@ -440,45 +460,43 @@ static int retrieve_ceiling_directories_offset(const char *path, const char *cei
return max_len <= min_len ? min_len : max_len;
}
-static int read_gitfile(char *path_out, const char *file_path, const char *base_path)
+/*
+ * Read the contents of `file_path` and set `path_out` to the repo dir that
+ * it points to. Before calling, set `path_out` to the base directory that
+ * should be used if the contents of `file_path` are a relative path.
+ */
+static int read_gitfile(git_buf *path_out, const char *file_path, const char *base_path)
{
git_fbuffer file;
int error;
- size_t end_offset;
- char *data;
- assert(path_out && file_path && base_path);
+ assert(path_out && file_path);
error = git_futils_readbuffer(&file, file_path);
-
if (error < GIT_SUCCESS)
return error;
- data = (char*)(file.data);
-
- if (git__prefixcmp(data, GIT_FILE_CONTENT_PREFIX)) {
+ if (git__prefixcmp((char *)file.data, GIT_FILE_CONTENT_PREFIX)) {
git_futils_freebuffer(&file);
return git__throw(GIT_ENOTFOUND, "Invalid gitfile format `%s`", file_path);
}
- end_offset = strlen(data) - 1;
+ git_futils_fbuffer_rtrim(&file);
- for (;data[end_offset] == '\r' || data[end_offset] == '\n'; --end_offset);
- data[end_offset + 1] = '\0';
-
- if (strlen(GIT_FILE_CONTENT_PREFIX) == end_offset + 1) {
+ if (strlen(GIT_FILE_CONTENT_PREFIX) == file.len) {
git_futils_freebuffer(&file);
return git__throw(GIT_ENOTFOUND, "No path in git file `%s`", file_path);
}
- data = data + strlen(GIT_FILE_CONTENT_PREFIX);
- error = git_path_prettify_dir(path_out, data, base_path);
+ error = git_path_prettify_dir(path_out,
+ ((char *)file.data) + strlen(GIT_FILE_CONTENT_PREFIX), base_path);
+
git_futils_freebuffer(&file);
- if (error == 0 && git_futils_exists(path_out) == 0)
+ if (error == GIT_SUCCESS && git_futils_exists(path_out->ptr) == 0)
return GIT_SUCCESS;
- return git__throw(GIT_EOBJCORRUPTED, "The `.git` file points to an inexisting path");
+ return git__throw(GIT_EOBJCORRUPTED, "The `.git` file points to a nonexistent path");
}
int git_repository_discover(
@@ -489,54 +507,62 @@ int git_repository_discover(
const char *ceiling_dirs)
{
int error, ceiling_offset;
- char bare_path[GIT_PATH_MAX];
- char normal_path[GIT_PATH_MAX];
- char *found_path;
+ git_buf bare_path = GIT_BUF_INIT;
+ git_buf normal_path = GIT_BUF_INIT;
+ git_buf *found_path = NULL;
dev_t current_device = 0;
assert(start_path && repository_path);
- error = git_path_prettify_dir(bare_path, start_path, NULL);
+ *repository_path = '\0';
+
+ error = git_path_prettify_dir(&bare_path, start_path, NULL);
if (error < GIT_SUCCESS)
- return error;
+ goto cleanup;
if (!across_fs) {
- error = retrieve_device(&current_device, bare_path);
+ error = retrieve_device(&current_device, bare_path.ptr);
if (error < GIT_SUCCESS)
- return error;
+ goto cleanup;
}
- ceiling_offset = retrieve_ceiling_directories_offset(bare_path, ceiling_dirs);
- git_path_join(normal_path, bare_path, DOT_GIT);
+ ceiling_offset = retrieve_ceiling_directories_offset(bare_path.ptr, ceiling_dirs);
while(1) {
+ error = git_buf_joinpath(&normal_path, bare_path.ptr, DOT_GIT);
+ if (error < GIT_SUCCESS)
+ break;
+
/**
* If the `.git` file is regular instead of
* a directory, it should contain the path of the actual git repository
*/
- if (git_futils_isfile(normal_path) == GIT_SUCCESS) {
- error = read_gitfile(repository_path, normal_path, bare_path);
-
- if (error < GIT_SUCCESS)
- return git__rethrow(error,
- "Unable to read git file `%s`", normal_path);
+ if (git_futils_isfile(normal_path.ptr) == GIT_SUCCESS) {
+ git_buf gitfile_path = GIT_BUF_INIT;
- error = quickcheck_repository_dir(repository_path);
+ error = read_gitfile(&gitfile_path, normal_path.ptr, bare_path.ptr);
if (error < GIT_SUCCESS)
- return git__throw(GIT_ENOTFOUND,
- "The `.git` file found at '%s' points"
- "to an inexisting Git folder", normal_path);
+ git__rethrow(error, "Unable to read git file `%s`", normal_path.ptr);
+ else if ((error = quickcheck_repository_dir(&gitfile_path)) < GIT_SUCCESS)
+ git__throw(GIT_ENOTFOUND,
+ "The `.git` file found at '%s' points "
+ "to a nonexistent git folder", normal_path.ptr);
+ else {
+ git_buf_swap(&normal_path, &gitfile_path);
+ found_path = &normal_path;
+ }
- return GIT_SUCCESS;
+ git_buf_free(&gitfile_path);
+ break;
}
/**
* If the `.git` file is a folder, we check inside of it
*/
- if (git_futils_isdir(normal_path) == GIT_SUCCESS) {
- error = quickcheck_repository_dir(normal_path);
+ if (git_futils_isdir(normal_path.ptr) == GIT_SUCCESS) {
+ error = quickcheck_repository_dir(&normal_path);
if (error == GIT_SUCCESS) {
- found_path = normal_path;
+ found_path = &normal_path;
break;
}
}
@@ -545,44 +571,63 @@ int git_repository_discover(
* Otherwise, the repository may be bare, let's check
* the root anyway
*/
- error = quickcheck_repository_dir(bare_path);
+ error = quickcheck_repository_dir(&bare_path);
if (error == GIT_SUCCESS) {
- found_path = bare_path;
+ found_path = &bare_path;
break;
}
- if (git_path_dirname_r(normal_path, sizeof(normal_path), bare_path) < GIT_SUCCESS)
- return git__throw(GIT_EOSERR, "Failed to dirname '%s'", bare_path);
+ /**
+ * If we didn't find it, walk up the tree
+ */
+ error = git_path_dirname_r(&normal_path, bare_path.ptr);
+ if (error < GIT_SUCCESS) {
+ git__rethrow(GIT_EOSERR, "Failed to dirname '%s'", bare_path.ptr);
+ break;
+ }
+
+ git_buf_swap(&bare_path, &normal_path);
if (!across_fs) {
dev_t new_device;
- error = retrieve_device(&new_device, normal_path);
+ error = retrieve_device(&new_device, bare_path.ptr);
if (error < GIT_SUCCESS || current_device != new_device) {
- return git__throw(GIT_ENOTAREPO,
+ error = git__throw(GIT_ENOTAREPO,
"Not a git repository (or any parent up to mount parent %s)\n"
- "Stopping at filesystem boundary.", bare_path);
+ "Stopping at filesystem boundary.", normal_path.ptr);
+ break;
}
current_device = new_device;
}
- strcpy(bare_path, normal_path);
- git_path_join(normal_path, bare_path, DOT_GIT);
-
- // nothing has been found, lets try the parent directory
- if (bare_path[ceiling_offset] == '\0') {
- return git__throw(GIT_ENOTAREPO,
+ /* nothing has been found, lets try the parent directory
+ * but stop if we hit one of the ceiling directories
+ */
+ if (bare_path.ptr[ceiling_offset] == '\0') {
+ error = git__throw(GIT_ENOTAREPO,
"Not a git repository (or any of the parent directories): %s", start_path);
+ break;
}
}
- if (size < strlen(found_path) + 2) {
- return git__throw(GIT_ESHORTBUFFER,
- "The repository buffer is not long enough to handle the repository path `%s`", found_path);
+ assert(found_path || error != GIT_SUCCESS);
+
+ if (found_path) {
+ if ((error = git_path_to_dir(found_path)) < GIT_SUCCESS)
+ git__rethrow(error, "Could not convert git repository to directory");
+ else if (size < (size_t)(found_path->size + 1))
+ error = git__throw(GIT_ESHORTBUFFER,
+ "The repository buffer is not long enough to "
+ "handle the repository path `%s`", found_path->ptr);
+ else
+ git_buf_copy_cstr(repository_path, size, found_path);
}
- git_path_join(repository_path, found_path, "");
- return GIT_SUCCESS;
+cleanup:
+ git_buf_free(&bare_path);
+ git_buf_free(&normal_path);
+ return error;
}
static int repo_init_reinit(const char *repository_path, int is_bare)
@@ -596,21 +641,23 @@ static int repo_init_reinit(const char *repository_path, int is_bare)
static int repo_init_createhead(const char *git_dir)
{
- char ref_path[GIT_PATH_MAX];
+ int error;
+ git_buf ref_path = GIT_BUF_INIT;
git_filebuf ref = GIT_FILEBUF_INIT;
- git_path_join(ref_path, git_dir, GIT_HEAD_FILE);
-
- git_filebuf_open(&ref, ref_path, 0);
- git_filebuf_printf(&ref, "ref: refs/heads/master\n");
+ if (!(error = git_buf_joinpath(&ref_path, git_dir, GIT_HEAD_FILE)) &&
+ !(error = git_filebuf_open(&ref, ref_path.ptr, 0)) &&
+ !(error = git_filebuf_printf(&ref, "ref: refs/heads/master\n")))
+ error = git_filebuf_commit(&ref, GIT_REFS_FILE_MODE);
- return git_filebuf_commit(&ref, GIT_REFS_FILE_MODE);
+ git_buf_free(&ref_path);
+ return error;
}
static int repo_init_config(const char *git_dir, int is_bare)
{
- char cfg_path[GIT_PATH_MAX];
- git_config *config;
+ git_buf cfg_path = GIT_BUF_INIT;
+ git_config *config = NULL;
int error = GIT_SUCCESS;
#define SET_REPO_CONFIG(type, name, val) {\
@@ -619,29 +666,40 @@ static int repo_init_config(const char *git_dir, int is_bare)
goto cleanup;\
}
- git_path_join(cfg_path, git_dir, GIT_CONFIG_FILENAME_INREPO);
+ error = git_buf_joinpath(&cfg_path, git_dir, GIT_CONFIG_FILENAME_INREPO);
+ if (error < GIT_SUCCESS)
+ goto cleanup;
- error = git_config_open_ondisk(&config, cfg_path);
+ error = git_config_open_ondisk(&config, cfg_path.ptr);
if (error < GIT_SUCCESS)
- return error;
+ goto cleanup;
SET_REPO_CONFIG(bool, "core.bare", is_bare);
SET_REPO_CONFIG(int32, "core.repositoryformatversion", 0);
/* TODO: what other defaults? */
cleanup:
+ git_buf_free(&cfg_path);
git_config_free(config);
return error;
}
static int repo_init_structure(const char *git_dir, int is_bare)
{
- int error;
-
- char temp_path[GIT_PATH_MAX];
-
- if (git_futils_mkdir_r(git_dir, is_bare ? GIT_BARE_DIR_MODE : GIT_DIR_MODE))
- return git__throw(GIT_ERROR, "Failed to initialize repository structure. Could not mkdir");
+ int error, i;
+ struct { const char *dir; mode_t mode; } dirs[] = {
+ { GIT_OBJECTS_INFO_DIR, GIT_OBJECT_DIR_MODE }, /* '/objects/info/' */
+ { GIT_OBJECTS_PACK_DIR, GIT_OBJECT_DIR_MODE }, /* '/objects/pack/' */
+ { GIT_REFS_HEADS_DIR, GIT_REFS_DIR_MODE }, /* '/refs/heads/' */
+ { GIT_REFS_TAGS_DIR, GIT_REFS_DIR_MODE }, /* '/refs/tags/' */
+ { NULL, 0 }
+ };
+
+ /* Make the base directory */
+ error = git_futils_mkdir_r(git_dir, NULL, is_bare ?
+ GIT_BARE_DIR_MODE : GIT_DIR_MODE);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to initialize repository structure. Could not mkdir");
/* Hides the ".git" directory */
if (!is_bare) {
@@ -652,67 +710,52 @@ static int repo_init_structure(const char *git_dir, int is_bare)
#endif
}
- /* Creates the '/objects/info/' directory */
- git_path_join(temp_path, git_dir, GIT_OBJECTS_INFO_DIR);
- error = git_futils_mkdir_r(temp_path, GIT_OBJECT_DIR_MODE);
- if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to initialize repository structure");
-
- /* Creates the '/objects/pack/' directory */
- git_path_join(temp_path, git_dir, GIT_OBJECTS_PACK_DIR);
- error = p_mkdir(temp_path, GIT_OBJECT_DIR_MODE);
- if (error < GIT_SUCCESS)
- return git__throw(error, "Unable to create `%s` folder", temp_path);
-
- /* Creates the '/refs/heads/' directory */
- git_path_join(temp_path, git_dir, GIT_REFS_HEADS_DIR);
- error = git_futils_mkdir_r(temp_path, GIT_REFS_DIR_MODE);
- if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to initialize repository structure");
-
- /* Creates the '/refs/tags/' directory */
- git_path_join(temp_path, git_dir, GIT_REFS_TAGS_DIR);
- error = p_mkdir(temp_path, GIT_REFS_DIR_MODE);
- if (error < GIT_SUCCESS)
- return git__throw(error, "Unable to create `%s` folder", temp_path);
+ /* Make subdirectories as needed */
+ for (i = 0; dirs[i].dir != NULL; ++i) {
+ error = git_futils_mkdir_r(dirs[i].dir, git_dir, dirs[i].mode);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error,
+ "Failed to create repository folder `%s`", dirs[i].dir);
+ }
/* TODO: what's left? templates? */
- return GIT_SUCCESS;
+ return error;
}
int git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare)
{
int error = GIT_SUCCESS;
git_repository *repo = NULL;
- char repository_path[GIT_PATH_MAX];
+ git_buf repository_path = GIT_BUF_INIT;
assert(repo_out && path);
- git_path_join(repository_path, path, is_bare ? "" : GIT_DIR);
+ error = git_buf_joinpath(&repository_path, path, is_bare ? "" : GIT_DIR);
+ if (error < GIT_SUCCESS)
+ return error;
- if (git_futils_isdir(repository_path)) {
- if (quickcheck_repository_dir(repository_path) == GIT_SUCCESS)
- return repo_init_reinit(repository_path, is_bare);
+ if (git_futils_isdir(repository_path.ptr) == GIT_SUCCESS) {
+ if (quickcheck_repository_dir(&repository_path) == GIT_SUCCESS) {
+ error = repo_init_reinit(repository_path.ptr, is_bare);
+ git_buf_free(&repository_path);
+ return error;
+ }
}
- error = repo_init_structure(repository_path, is_bare);
- if (error < GIT_SUCCESS)
- goto cleanup;
-
- error = repo_init_config(repository_path, is_bare);
- if (error < GIT_SUCCESS)
- goto cleanup;
+ if (!(error = repo_init_structure(repository_path.ptr, is_bare)) &&
+ !(error = repo_init_config(repository_path.ptr, is_bare)) &&
+ !(error = repo_init_createhead(repository_path.ptr)))
+ error = git_repository_open(repo_out, repository_path.ptr);
+ else
+ git_repository_free(repo);
- error = repo_init_createhead(repository_path);
- if (error < GIT_SUCCESS)
- goto cleanup;
+ git_buf_free(&repository_path);
- return git_repository_open(repo_out, repository_path);
+ if (error != GIT_SUCCESS)
+ git__rethrow(error, "Failed to (re)init the repository `%s`", path);
-cleanup:
- git_repository_free(repo);
- return git__rethrow(error, "Failed to (re)init the repository `%s`", path);
+ return error;
}
int git_repository_head_detached(git_repository *repo)
diff --git a/src/signature.c b/src/signature.c
index 832d6439c..fb2bb3cce 100644
--- a/src/signature.c
+++ b/src/signature.c
@@ -16,7 +16,9 @@ void git_signature_free(git_signature *sig)
return;
git__free(sig->name);
+ sig->name = NULL;
git__free(sig->email);
+ sig->email = NULL;
git__free(sig);
}
diff --git a/src/status.c b/src/status.c
index 26dd11ea8..05e07be0a 100644
--- a/src/status.c
+++ b/src/status.c
@@ -28,12 +28,10 @@ struct status_entry {
static struct status_entry *status_entry_new(git_vector *entries, const char *path)
{
- struct status_entry *e = git__malloc(sizeof(*e) + strlen(path) + 1);
+ struct status_entry *e = git__calloc(sizeof(*e) + strlen(path) + 1, 1);
if (e == NULL)
return NULL;
- memset(e, 0x0, sizeof(*e));
-
if (entries != NULL)
git_vector_insert(entries, e);
@@ -73,7 +71,7 @@ static void status_entry_update_from_index(struct status_entry *e, git_index *in
status_entry_update_from_index_entry(e, index_entry);
}
-static int status_entry_update_from_workdir(struct status_entry *e, char* full_path)
+static int status_entry_update_from_workdir(struct status_entry *e, const char* full_path)
{
struct stat filest;
@@ -125,7 +123,7 @@ struct status_st {
git_tree *tree;
int workdir_path_len;
- char* head_tree_relative_path;
+ git_buf head_tree_relative_path;
int head_tree_relative_path_len;
unsigned int tree_position;
unsigned int index_position;
@@ -155,6 +153,7 @@ static int retrieve_head_tree(git_tree **tree_out, git_repository *repo)
return git__rethrow(error, "The tip of HEAD can't be retrieved");
git_reference_free(resolved_head_ref);
+
if ((error = git_commit_tree(&tree, head_commit)) < GIT_SUCCESS) {
error = git__rethrow(error, "The tree of HEAD can't be retrieved");
goto exit;
@@ -174,12 +173,15 @@ enum path_type {
GIT_STATUS_PATH_FOLDER,
};
-static int dirent_cb(void *state, char *full_path);
+static int dirent_cb(void *state, git_buf *full_path);
static int alphasorted_futils_direach(
- char *path, size_t path_sz,
- int (*fn)(void *, char *), void *arg);
+ git_buf *path, int (*fn)(void *, git_buf *), void *arg);
-static int process_folder(struct status_st *st, const git_tree_entry *tree_entry, char *full_path, enum path_type path_type)
+static int process_folder(
+ struct status_st *st,
+ const git_tree_entry *tree_entry,
+ git_buf *full_path,
+ enum path_type path_type)
{
git_object *subtree = NULL;
git_tree *pushed_tree = NULL;
@@ -209,10 +211,9 @@ static int process_folder(struct status_st *st, const git_tree_entry *tree_entry
}
if (full_path != NULL && path_type == GIT_STATUS_PATH_FOLDER)
- error = alphasorted_futils_direach(full_path, GIT_PATH_MAX, dirent_cb, st);
- else {
+ error = alphasorted_futils_direach(full_path, dirent_cb, st);
+ else
error = dirent_cb(st, NULL);
- }
if (tree_entry_type == GIT_OBJ_TREE) {
git_object_free(subtree);
@@ -229,7 +230,7 @@ static int store_if_changed(struct status_st *st, struct status_entry *e)
{
int error;
if ((error = status_entry_update_flags(e)) < GIT_SUCCESS)
- return git__throw(error, "Failed to process the file '%s'. It doesn't exist in the workdir, in the HEAD nor in the index", e->path);
+ return git__throw(error, "Failed to process the file '%s'. It doesn't exist in the workdir, in the HEAD nor in the index", e->path);
if (e->status_flags == GIT_STATUS_CURRENT) {
git__free(e);
@@ -243,7 +244,7 @@ static int determine_status(struct status_st *st,
int in_head, int in_index, int in_workdir,
const git_tree_entry *tree_entry,
const git_index_entry *index_entry,
- char *full_path,
+ git_buf *full_path,
const char *status_path,
enum path_type path_type)
{
@@ -273,7 +274,8 @@ static int determine_status(struct status_st *st,
}
if (in_workdir)
- if ((error = status_entry_update_from_workdir(e, full_path)) < GIT_SUCCESS)
+ if ((error = status_entry_update_from_workdir(e, full_path->ptr
+)) < GIT_SUCCESS)
return error; /* The callee has already set the error message */
return store_if_changed(st, e);
@@ -284,7 +286,7 @@ static int determine_status(struct status_st *st,
return process_folder(st, tree_entry, full_path, path_type);
}
-static int path_type_from(char *full_path, int is_dir)
+static int path_type_from(git_buf *full_path, int is_dir)
{
if (full_path == NULL)
return GIT_STATUS_PATH_NULL;
@@ -292,7 +294,7 @@ static int path_type_from(char *full_path, int is_dir)
if (!is_dir)
return GIT_STATUS_PATH_FILE;
- if (!git__suffixcmp(full_path, "/" DOT_GIT "/"))
+ if (!git__suffixcmp(full_path->ptr, "/" DOT_GIT "/"))
return GIT_STATUS_PATH_IGNORE;
return GIT_STATUS_PATH_FOLDER;
@@ -330,7 +332,7 @@ static int compare(const char *left, const char *right)
/* Greatly inspired from JGit IndexTreeWalker */
/* https://github.com/spearce/jgit/blob/ed47e29c777accfa78c6f50685a5df2b8f5b8ff5/org.spearce.jgit/src/org/spearce/jgit/lib/IndexTreeWalker.java#L88 */
-static int dirent_cb(void *state, char *a)
+static int dirent_cb(void *state, git_buf *a)
{
const git_tree_entry *m;
const git_index_entry *entry;
@@ -346,7 +348,7 @@ static int dirent_cb(void *state, char *a)
if (path_type == GIT_STATUS_PATH_IGNORE)
return GIT_SUCCESS; /* Let's skip the ".git" directory */
- a_name = (path_type != GIT_STATUS_PATH_NULL) ? a + st->workdir_path_len : NULL;
+ a_name = (path_type != GIT_STATUS_PATH_NULL) ? a->ptr + st->workdir_path_len : NULL;
while (1) {
if (st->tree == NULL)
@@ -360,15 +362,18 @@ static int dirent_cb(void *state, char *a)
return GIT_SUCCESS;
if (m != NULL) {
- st->head_tree_relative_path[st->head_tree_relative_path_len] = '\0';
-
+ git_buf_truncate(&st->head_tree_relative_path,
+ st->head_tree_relative_path_len);
+ git_buf_joinpath(&st->head_tree_relative_path,
+ st->head_tree_relative_path.ptr, m->filename);
/* When the tree entry is a folder, append a forward slash to its name */
if (git_tree_entry_type(m) == GIT_OBJ_TREE)
- git_path_join_n(st->head_tree_relative_path, 3, st->head_tree_relative_path, m->filename, "");
- else
- git_path_join(st->head_tree_relative_path, st->head_tree_relative_path, m->filename);
-
- m_name = st->head_tree_relative_path;
+ git_path_to_dir(&st->head_tree_relative_path);
+
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "An error occured while determining the status of '%s'", a->ptr);
+
+ m_name = st->head_tree_relative_path.ptr;
} else
m_name = NULL;
@@ -383,7 +388,7 @@ static int dirent_cb(void *state, char *a)
pi = ((cmpmi >= 0) && (cmpai >= 0)) ? i_name : NULL;
if((error = determine_status(st, pm != NULL, pi != NULL, pa != NULL, m, entry, a, status_path(pm, pi, pa), path_type)) < GIT_SUCCESS)
- return git__rethrow(error, "An error occured while determining the status of '%s'", a);
+ return git__rethrow(error, "An error occured while determining the status of '%s'", a->ptr);
if ((pa != NULL) || (path_type == GIT_STATUS_PATH_FOLDER))
return GIT_SUCCESS;
@@ -404,9 +409,8 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig
{
git_vector entries;
git_index *index = NULL;
- char temp_path[GIT_PATH_MAX];
- char tree_path[GIT_PATH_MAX] = "";
- struct status_st dirent_st;
+ git_buf temp_path = GIT_BUF_INIT;
+ struct status_st dirent_st = {0};
int error = GIT_SUCCESS;
unsigned int i;
git_tree *tree;
@@ -435,23 +439,21 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig
dirent_st.tree = tree;
dirent_st.index = index;
dirent_st.vector = &entries;
- dirent_st.head_tree_relative_path = tree_path;
+ git_buf_init(&dirent_st.head_tree_relative_path, 0);
dirent_st.head_tree_relative_path_len = 0;
dirent_st.is_dir = 1;
- strcpy(temp_path, workdir);
-
- if (git_futils_isdir(temp_path)) {
+ if (git_futils_isdir(workdir)) {
error = git__throw(GIT_EINVALIDPATH,
"Failed to determine status of file '%s'. "
- "The given path doesn't lead to a folder", temp_path);
+ "The given path doesn't lead to a folder", workdir);
goto exit;
}
+ git_buf_sets(&temp_path, workdir);
+
error = alphasorted_futils_direach(
- temp_path, sizeof(temp_path),
- dirent_cb, &dirent_st
- );
+ &temp_path, dirent_cb, &dirent_st);
if (error < GIT_SUCCESS)
error = git__rethrow(error,
@@ -477,6 +479,8 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig
}
exit:
+ git_buf_free(&dirent_st.head_tree_relative_path);
+ git_buf_free(&temp_path);
git_vector_free(&entries);
git_tree_free(tree);
return error;
@@ -521,7 +525,7 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char
{
struct status_entry *e;
git_index *index = NULL;
- char temp_path[GIT_PATH_MAX];
+ git_buf temp_path = GIT_BUF_INIT;
int error = GIT_SUCCESS;
git_tree *tree = NULL;
const char *workdir;
@@ -532,60 +536,72 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char
return git__throw(GIT_ERROR,
"Cannot retrieve status on a bare repository");
- git_path_join(temp_path, workdir, path);
- if (git_futils_isdir(temp_path) == GIT_SUCCESS)
+ if ((error = git_buf_joinpath(&temp_path, workdir, path)) < GIT_SUCCESS)
+ return git__rethrow(error,
+ "Failed to determine status of file '%s'", path);
+
+ if (git_futils_isdir(temp_path.ptr) == GIT_SUCCESS) {
+ git_buf_free(&temp_path);
return git__throw(GIT_EINVALIDPATH,
"Failed to determine status of file '%s'. "
"Given path leads to a folder, not a file", path);
+ }
e = status_entry_new(NULL, path);
- if (e == NULL)
+ if (e == NULL) {
+ git_buf_free(&temp_path);
return GIT_ENOMEM;
+ }
/* Find file in Workdir */
- if (git_futils_exists(temp_path) == GIT_SUCCESS) {
- if ((error = status_entry_update_from_workdir(e, temp_path)) < GIT_SUCCESS)
- goto exit; /* The callee has already set the error message */
+ if (git_futils_exists(temp_path.ptr) == GIT_SUCCESS) {
+ if ((error = status_entry_update_from_workdir(e, temp_path.ptr)) < GIT_SUCCESS)
+ goto cleanup; /* The callee has already set the error message */
}
/* Find file in Index */
if ((error = git_repository_index__weakptr(&index, repo)) < GIT_SUCCESS) {
- error = git__rethrow(error,
+ git__rethrow(error,
"Failed to determine status of file '%s'."
"Index can't be opened", path);
- goto exit;
+ goto cleanup;
}
status_entry_update_from_index(e, index);
if ((error = retrieve_head_tree(&tree, repo)) < GIT_SUCCESS) {
- error = git__rethrow(error,
+ git__rethrow(error,
"Failed to determine status of file '%s'", path);
- goto exit;
+ goto cleanup;
}
/* If the repository is not empty, try and locate the file in HEAD */
if (tree != NULL) {
- strcpy(temp_path, path);
+ if ((error = git_buf_sets(&temp_path, path)) < GIT_SUCCESS) {
+ git__rethrow(error,
+ "Failed to determine status of file '%s'", path);
+ goto cleanup;
+ }
- error = recurse_tree_entry(tree, e, temp_path);
+ error = recurse_tree_entry(tree, e, temp_path.ptr);
if (error < GIT_SUCCESS) {
- error = git__rethrow(error,
+ git__rethrow(error,
"Failed to determine status of file '%s'. "
"An error occured while processing the tree", path);
- goto exit;
+ goto cleanup;
}
}
/* Determine status */
if ((error = status_entry_update_flags(e)) < GIT_SUCCESS) {
- error = git__throw(error, "Nonexistent file");
- goto exit;
+ git__throw(error, "Nonexistent file");
+ goto cleanup;
}
*status_flags = e->status_flags;
-exit:
+cleanup:
+ git_buf_free(&temp_path);
git_tree_free(tree);
git__free(e);
return error;
@@ -600,37 +616,34 @@ exit:
struct alphasorted_dirent_info {
int is_dir;
-
char path[GIT_FLEX_ARRAY]; /* more */
};
-static struct alphasorted_dirent_info *alphasorted_dirent_info_new(const char *path)
+static struct alphasorted_dirent_info *alphasorted_dirent_info_new(const git_buf *path)
{
int is_dir, size;
struct alphasorted_dirent_info *di;
- is_dir = git_futils_isdir(path) == GIT_SUCCESS ? 1 : 0;
- size = sizeof(*di) + (is_dir ? GIT_PATH_MAX : strlen(path)) + 2;
+ is_dir = git_futils_isdir(path->ptr) == GIT_SUCCESS ? 1 : 0;
+ size = sizeof(*di) + path->size + is_dir + 1;
- di = git__malloc(size);
+ di = git__calloc(size, 1);
if (di == NULL)
return NULL;
- memset(di, 0x0, size);
-
- strcpy(di->path, path);
+ git_buf_copy_cstr(di->path, path->size + 1, path);
if (is_dir) {
di->is_dir = 1;
- /*
- * Append a forward slash to the name to force folders
+ /*
+ * Append a forward slash to the name to force folders
* to be ordered in a similar way than in a tree
*
* The file "subdir" should appear before the file "subdir.txt"
* The folder "subdir" should appear after the file "subdir.txt"
*/
- di->path[strlen(path)] = '/';
+ di->path[path->size] = '/';
}
return di;
@@ -644,7 +657,7 @@ static int alphasorted_dirent_info_cmp(const void *a, const void *b)
return strcmp(stra->path, strb->path);
}
-static int alphasorted_dirent_cb(void *state, char *full_path)
+static int alphasorted_dirent_cb(void *state, git_buf *full_path)
{
struct alphasorted_dirent_info *entry;
git_vector *entry_names;
@@ -664,34 +677,42 @@ static int alphasorted_dirent_cb(void *state, char *full_path)
}
static int alphasorted_futils_direach(
- char *path,
- size_t path_sz,
- int (*fn)(void *, char *),
+ git_buf *path,
+ int (*fn)(void *, git_buf *),
void *arg)
{
struct alphasorted_dirent_info *entry;
git_vector entry_names;
unsigned int idx;
int error = GIT_SUCCESS;
+ git_buf entry_path = GIT_BUF_INIT;
if (git_vector_init(&entry_names, 16, alphasorted_dirent_info_cmp) < GIT_SUCCESS)
return GIT_ENOMEM;
- error = git_futils_direach(path, path_sz, alphasorted_dirent_cb, &entry_names);
+ error = git_futils_direach(path, alphasorted_dirent_cb, &entry_names);
git_vector_sort(&entry_names);
for (idx = 0; idx < entry_names.length; ++idx) {
entry = (struct alphasorted_dirent_info *)git_vector_get(&entry_names, idx);
+ /* We have to walk the entire vector even if there was an error,
+ * in order to free up memory, but we stop making callbacks after
+ * an error.
+ */
+ if (error == GIT_SUCCESS)
+ error = git_buf_sets(&entry_path, entry->path);
+
if (error == GIT_SUCCESS) {
((struct status_st *)arg)->is_dir = entry->is_dir;
- error = fn(arg, entry->path);
+ error = fn(arg, &entry_path);
}
git__free(entry);
}
+ git_buf_free(&entry_path);
git_vector_free(&entry_names);
return error;
}
diff --git a/src/tag.c b/src/tag.c
index 16d46ce16..31f96b0ea 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -148,15 +148,22 @@ static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer
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;
int error;
*tag_reference_out = NULL;
- git_path_join(ref_name_out, GIT_REFS_TAGS_DIR, tag_name);
- error = git_reference_lookup(&tag_ref, repo, ref_name_out);
+ error = git_buf_joinpath(ref_name_out, GIT_REFS_TAGS_DIR, tag_name);
+ 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)
return git__rethrow(error, "Failed to retrieve tag reference");
@@ -184,9 +191,10 @@ static int write_tag_annotation(
git_buf_putc(&tag, '\n');
git_buf_puts(&tag, message);
- if (git_buf_oom(&tag)) {
+ error = git_buf_lasterror(&tag);
+ if (error < GIT_SUCCESS) {
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);
@@ -215,56 +223,54 @@ static int git_tag_create__internal(
int create_tag_annotation)
{
git_reference *new_ref = NULL;
- char ref_name[GIT_REFNAME_MAX];
+ git_buf ref_name = GIT_BUF_INIT;
int error, should_update_ref = 0;
+ const char *errmsg = "Failed to create tag";
assert(repo && tag_name && target);
assert(!create_tag_annotation || (tagger && message));
if (git_object_owner(target) != repo)
- return git__throw(GIT_EINVALIDARGS, "The given target does not belong to this repository");
-
- error = retrieve_tag_reference(&new_ref, ref_name, repo, tag_name);
-
- switch (error) {
- case GIT_SUCCESS:
- case GIT_ENOTFOUND:
- break;
+ return git__throw(GIT_EINVALIDARGS,
+ "The given target does not belong to this repository");
- default:
- git_reference_free(new_ref);
- return git__rethrow(error, "Failed to create tag");
- }
+ error = retrieve_tag_reference(&new_ref, &ref_name, repo, tag_name);
+ if (error < GIT_SUCCESS && error != GIT_ENOTFOUND)
+ goto cleanup;
/** Ensure the tag name doesn't conflict with an already existing
* reference unless overwriting has explictly been requested **/
if (new_ref != NULL) {
if (!allow_ref_overwrite) {
git_oid_cpy(oid, git_reference_oid(new_ref));
- git_reference_free(new_ref);
- return git__throw(GIT_EEXISTS, "Tag already exists");
+ error = GIT_EEXISTS;
+ errmsg = "Tag already exists";
+ goto cleanup;
} else {
should_update_ref = 1;
}
}
if (create_tag_annotation) {
- if ((error = write_tag_annotation(oid, repo, tag_name, target, tagger, message)) < GIT_SUCCESS) {
- git_reference_free(new_ref);
- return error;
- }
+ if ((error = write_tag_annotation(oid, repo, tag_name, target, tagger, message)) < GIT_SUCCESS)
+ goto cleanup;
} else
git_oid_cpy(oid, git_object_id(target));
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
error = git_reference_set_oid(new_ref, oid);
+cleanup:
git_reference_free(new_ref);
+ git_buf_free(&ref_name);
+
+ if (error < GIT_SUCCESS)
+ git__rethrow(error, "%s", errmsg);
- return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create tag");
+ return error;
}
int git_tag_create(
@@ -293,12 +299,13 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
{
git_tag tag;
int error, should_update_ref = 0;
+ const char *errmsg = "Failed to create tag";
git_odb *odb;
git_odb_stream *stream;
git_odb_object *target_obj;
git_reference *new_ref = NULL;
- char ref_name[GIT_REFNAME_MAX];
+ git_buf ref_name = GIT_BUF_INIT;
assert(oid && buffer);
@@ -310,78 +317,77 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
/* validate the buffer */
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 */
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)
- return git__throw(error, "The type for the given target is invalid");
+ if (tag.type != target_obj->raw.type) {
+ error = GIT_EINVALIDTYPE;
+ errmsg = "The type for the given target is invalid";
+ goto cleanup;
+ }
git_odb_object_free(target_obj);
- error = retrieve_tag_reference(&new_ref, ref_name, repo, tag.tag_name);
-
- switch (error) {
- case GIT_SUCCESS:
- case GIT_ENOTFOUND:
- break;
-
- default:
- git_reference_free(new_ref);
- return git__rethrow(error, "Failed to create tag");
- }
+ error = retrieve_tag_reference(&new_ref, &ref_name, repo, tag.tag_name);
+ if (error < GIT_SUCCESS && error != GIT_ENOTFOUND)
+ goto cleanup;
/** Ensure the tag name doesn't conflict with an already existing
* reference unless overwriting has explictly been requested **/
if (new_ref != NULL) {
if (!allow_ref_overwrite) {
git_oid_cpy(oid, git_reference_oid(new_ref));
- git_reference_free(new_ref);
- return git__throw(GIT_EEXISTS, "Tag already exists");
+ error = GIT_EEXISTS;
+ errmsg = "Tag already exists";
+ goto cleanup;
} else {
should_update_ref = 1;
}
}
/* write the buffer */
- if ((error = git_odb_open_wstream(&stream, odb, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS) {
- git_reference_free(new_ref);
- return git__rethrow(error, "Failed to create tag");
- }
+ if ((error = git_odb_open_wstream(&stream, odb, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS)
+ goto cleanup;
stream->write(stream, buffer, strlen(buffer));
error = stream->finalize_write(oid, stream);
stream->free(stream);
- if (error < GIT_SUCCESS) {
- git_reference_free(new_ref);
- return git__rethrow(error, "Failed to create tag");
- }
+ if (error < GIT_SUCCESS)
+ goto cleanup;
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
error = git_reference_set_oid(new_ref, oid);
+cleanup:
git_reference_free(new_ref);
-
git_signature_free(tag.tagger);
git__free(tag.tag_name);
git__free(tag.message);
+ git_buf_free(&ref_name);
+
+ if (error < GIT_SUCCESS)
+ git__rethrow(error, "%s", errmsg);
- return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create tag");
+ return error;
}
int git_tag_delete(git_repository *repo, const char *tag_name)
{
int error;
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)
return git__rethrow(error, "Failed to delete tag");
diff --git a/src/transports/git.c b/src/transports/git.c
index bdb94d090..ece4d40a8 100644
--- a/src/transports/git.c
+++ b/src/transports/git.c
@@ -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_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)
diff --git a/src/transports/http.c b/src/transports/http.c
index e463a0f59..48ea78dce 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -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");
- if (git_buf_oom(buf))
- return GIT_ENOMEM;
-
- return GIT_SUCCESS;
+ return git_buf_lasterror(buf);
}
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
char buffer[1024];
gitno_buffer buf;
download_pack_cbdata data;
- git_filebuf file;
- char path[GIT_PATH_MAX], suff[] = "/objects/pack/pack-received\0";
+ git_filebuf file = GIT_FILEBUF_INIT;
+ 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
@@ -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);
- git_path_join(path, repo->path_repository, suff);
-
if (memcmp(oldbuf->ptr, "PACK", strlen("PACK"))) {
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)
goto cleanup;
@@ -671,6 +671,7 @@ static int http_download_pack(char **out, git_transport *transport, git_reposito
cleanup:
if (error < GIT_SUCCESS)
git_filebuf_cleanup(&file);
+ git_buf_free(&path);
return error;
}
diff --git a/src/tree.c b/src/tree.c
index 702095d14..23efb28e4 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -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);
}
- if (git_buf_oom(&tree)) {
+ if ((error = git_buf_lasterror(&tree)) < GIT_SUCCESS) {
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);
@@ -631,7 +631,7 @@ void git_treebuilder_free(git_treebuilder *bld)
static int tree_frompath(
git_tree **parent_out,
git_tree *root,
- const char *treeentry_path,
+ git_buf *treeentry_path,
int offset)
{
char *slash_pos = NULL;
@@ -639,11 +639,11 @@ static int tree_frompath(
int error = GIT_SUCCESS;
git_tree *subtree;
- if (!*(treeentry_path + offset))
+ if (!*(treeentry_path->ptr + offset))
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)
return git_tree_lookup(
@@ -652,13 +652,13 @@ static int tree_frompath(
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,
- "Invalid relative path to a tree entry '%s'.", treeentry_path);
+ "Invalid relative path to a tree entry '%s'.", treeentry_path->ptr);
*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)
*slash_pos = '/';
@@ -666,7 +666,7 @@ static int tree_frompath(
if (entry == NULL)
return git__rethrow(GIT_ENOTFOUND,
"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);
@@ -677,7 +677,7 @@ static int tree_frompath(
parent_out,
subtree,
treeentry_path,
- slash_pos - treeentry_path + 1
+ (slash_pos - treeentry_path->ptr) + 1
);
git_tree_free(subtree);
@@ -689,70 +689,82 @@ int git_tree_get_subtree(
git_tree *root,
const char *subtree_path)
{
- char buffer[GIT_PATH_MAX];
+ int error;
+ git_buf buffer = GIT_BUF_INIT;
assert(subtree && root && subtree_path);
- strncpy(buffer, subtree_path, GIT_PATH_MAX);
- return tree_frompath(subtree, root, buffer, 0);
+ if ((error = git_buf_sets(&buffer, subtree_path)) == GIT_SUCCESS)
+ error = tree_frompath(subtree, root, &buffer, 0);
+
+ git_buf_free(&buffer);
+
+ return error;
}
static int tree_walk_post(
git_tree *tree,
git_treewalk_cb callback,
- char *root,
- size_t root_len,
+ git_buf *path,
void *payload)
{
- int error;
+ int error = GIT_SUCCESS;
unsigned int i;
for (i = 0; i < tree->entries.length; ++i) {
git_tree_entry *entry = tree->entries.contents[i];
- root[root_len] = '\0';
-
- if (callback(root, entry, payload) < 0)
+ if (callback(path->ptr, entry, payload) < 0)
continue;
if (ENTRY_IS_TREE(entry)) {
git_tree *subtree;
+ size_t path_len = path->size;
if ((error = git_tree_lookup(
&subtree, tree->object.repo, &entry->oid)) < 0)
- return error;
+ break;
- strcpy(root + root_len, entry->filename);
- root[root_len + entry->filename_len] = '/';
+ /* append the next entry to the path */
+ git_buf_puts(path, entry->filename);
+ git_buf_putc(path, '/');
+ if ((error = git_buf_lasterror(path)) < GIT_SUCCESS)
+ break;
- tree_walk_post(subtree,
- callback, root,
- root_len + entry->filename_len + 1,
- payload
- );
+ error = tree_walk_post(subtree, callback, path, payload);
+ if (error < GIT_SUCCESS)
+ break;
+ git_buf_truncate(path, path_len);
git_tree_free(subtree);
}
}
- return GIT_SUCCESS;
+ return error;
}
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) {
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:
- return git__throw(GIT_ENOTIMPLEMENTED,
+ error = git__throw(GIT_ENOTIMPLEMENTED,
"Preorder tree walking is still not implemented");
+ break;
default:
- return git__throw(GIT_EINVALIDARGS,
+ error = git__throw(GIT_EINVALIDARGS,
"Invalid walking mode for tree walk");
+ break;
}
+
+ git_buf_free(&root_path);
+
+ return error;
}
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index 6f722581e..e406a8f6c 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -304,32 +304,37 @@ int p_hide_directory__w32(const char *path)
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* 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);
git__free(orig_path_w);
if (!ret || ret > GIT_PATH_MAX) {
- git__free(buffer_w);
- if (alloc) git__free(buffer);
-
- return NULL;
+ buffer = NULL;
+ goto done;
}
- if (!WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, buffer, GIT_PATH_MAX, NULL, NULL)) {
- git__free(buffer_w);
- if (alloc) git__free(buffer);
+ if (buffer == NULL) {
+ int buffer_sz = WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, NULL, 0, NULL, NULL);
+
+ 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_path_mkposix(buffer);
+ if (buffer)
+ git_path_mkposix(buffer);
return buffer;
}