summaryrefslogtreecommitdiff
path: root/src/fileops.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fileops.c')
-rw-r--r--src/fileops.c131
1 files changed, 104 insertions, 27 deletions
diff --git a/src/fileops.c b/src/fileops.c
index 76e689e8a..5dd4a3806 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -2,13 +2,13 @@
#include "fileops.h"
#include <ctype.h>
-static int force_path(const char *to)
+int gitfo_mkdir_2file(const char *file_path)
{
const int mode = 0755; /* or 0777 ? */
int error = GIT_SUCCESS;
char target_folder_path[GIT_PATH_MAX];
- error = git__dirname_r(target_folder_path, sizeof(target_folder_path), to);
+ error = git__dirname_r(target_folder_path, sizeof(target_folder_path), file_path);
if (error < GIT_SUCCESS)
return error;
@@ -25,6 +25,27 @@ static int force_path(const char *to)
return GIT_SUCCESS;
}
+int gitfo_mktemp(char *path_out, const char *filename)
+{
+ int fd;
+
+ strcpy(path_out, filename);
+ strcat(path_out, "_git2_XXXXXX");
+
+#if defined(_MSC_VER)
+ /* FIXME: there may be race conditions when multi-threading
+ * with the library */
+ if (_mktemp_s(path_out, GIT_PATH_MAX) != 0)
+ return GIT_EOSERR;
+
+ fd = gitfo_creat(path_out, 0744);
+#else
+ fd = mkstemp(path_out);
+#endif
+
+ return fd >= 0 ? fd : GIT_EOSERR;
+}
+
int gitfo_open(const char *path, int flags)
{
int fd = open(path, flags | O_BINARY);
@@ -39,7 +60,7 @@ int gitfo_creat(const char *path, int mode)
int gitfo_creat_force(const char *path, int mode)
{
- if (force_path(path) < GIT_SUCCESS)
+ if (gitfo_mkdir_2file(path) < GIT_SUCCESS)
return GIT_EOSERR;
return gitfo_creat(path, mode);
@@ -117,6 +138,7 @@ int gitfo_isdir(const char *path)
int gitfo_exists(const char *path)
{
+ assert(path);
return access(path, F_OK);
}
@@ -181,7 +203,7 @@ int gitfo_mv(const char *from, const char *to)
* file exists, the `rename` call fails. This is as
* close as it gets with the Win32 API.
*/
- return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING) ? GIT_SUCCESS : GIT_EOSERR;
+ return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? GIT_SUCCESS : GIT_EOSERR;
#else
/* Don't even try this on Win32 */
if (!link(from, to)) {
@@ -198,7 +220,7 @@ int gitfo_mv(const char *from, const char *to)
int gitfo_mv_force(const char *from, const char *to)
{
- if (force_path(to) < GIT_SUCCESS)
+ if (gitfo_mkdir_2file(to) < GIT_SUCCESS)
return GIT_EOSERR;
return gitfo_mv(from, to);
@@ -361,22 +383,29 @@ int gitfo_dirent(
return GIT_SUCCESS;
}
-#ifdef GIT_WIN32
-static int is_windows_rooted_path(const char *path)
+int retrieve_path_root_offset(const char *path)
{
+ int offset = 0;
+
+#ifdef GIT_WIN32
+
/* Does the root of the path look like a windows drive ? */
if (isalpha(path[0]) && (path[1] == ':'))
- return GIT_SUCCESS;
+ offset += 2;
+
+#endif
+
+ if (*(path + offset) == '/')
+ return offset;
return GIT_ERROR;
}
-#endif
int gitfo_mkdir_recurs(const char *path, int mode)
{
- int error;
+ int error, root_path_offset;
char *pp, *sp;
char *path_copy = git__strdup(path);
@@ -386,12 +415,9 @@ int gitfo_mkdir_recurs(const char *path, int mode)
error = GIT_SUCCESS;
pp = path_copy;
-#ifdef GIT_WIN32
-
- if (!is_windows_rooted_path(pp))
- pp += 2; /* Skip the drive name (eg. C: or D:) */
-
-#endif
+ root_path_offset = retrieve_path_root_offset(pp);
+ 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, '/')) != 0) {
if (sp != pp && gitfo_isdir(path_copy) < GIT_SUCCESS) {
@@ -417,8 +443,12 @@ int gitfo_mkdir_recurs(const char *path, int mode)
static int retrieve_previous_path_component_start(const char *path)
{
- int offset, len, start = 0;
-
+ int offset, len, root_offset, start = 0;
+
+ root_offset = retrieve_path_root_offset(path);
+ if (root_offset > -1)
+ start += root_offset;
+
len = strlen(path);
offset = len - 1;
@@ -430,7 +460,7 @@ static int retrieve_previous_path_component_start(const char *path)
if (path[offset] == '/')
offset--;
- if (offset < 0)
+ if (offset < root_offset)
return GIT_ERROR;
while (offset > start && path[offset-1] != '/') {
@@ -440,15 +470,25 @@ static int retrieve_previous_path_component_start(const char *path)
return offset;
}
-int gitfo_prettify_dir_path(char *buffer_out, const char *path)
+int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path)
{
- int len = 0, segment_len, only_dots;
+ int len = 0, segment_len, only_dots, root_path_offset, error = GIT_SUCCESS;
char *current;
const char *buffer_out_start, *buffer_end;
- buffer_out_start = buffer_out;
current = (char *)path;
buffer_end = path + strlen(path);
+ buffer_out_start = buffer_out;
+
+ root_path_offset = retrieve_path_root_offset(path);
+ if (root_path_offset < 0) {
+ error = gitfo_getcwd(buffer_out, size);
+ if (error < GIT_SUCCESS)
+ return error;
+
+ len = strlen(buffer_out);
+ buffer_out += len;
+ }
while (current < buffer_end) {
/* Prevent multiple slashes from being added to the output */
@@ -461,7 +501,7 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path)
segment_len = 0;
/* Copy path segment to the output */
- while (current < buffer_end && *current !='/')
+ while (current < buffer_end && *current != '/')
{
only_dots &= (*current == '.');
*buffer_out++ = *current++;
@@ -486,7 +526,9 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path)
*buffer_out ='\0';
len = retrieve_previous_path_component_start(buffer_out_start);
- if (len < GIT_SUCCESS)
+
+ /* Are we escaping out of the root dir? */
+ if (len < 0)
return GIT_EINVALIDPATH;
buffer_out = (char *)buffer_out_start + len;
@@ -494,7 +536,7 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path)
}
/* Guard against potential multiple dot path traversal (cf http://cwe.mitre.org/data/definitions/33.html) */
- if (only_dots &&segment_len > 0)
+ if (only_dots && segment_len > 0)
return GIT_EINVALIDPATH;
*buffer_out++ = '/';
@@ -506,20 +548,24 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path)
return GIT_SUCCESS;
}
-int gitfo_prettify_file_path(char *buffer_out, const char *path)
+int gitfo_prettify_file_path(char *buffer_out, size_t size, const char *path)
{
int error, path_len, i;
const char* pattern = "/..";
path_len = strlen(path);
+ /* Let's make sure the filename isn't empty nor a dot */
+ if (path_len == 0 || (path_len == 1 && *path == '.'))
+ return GIT_EINVALIDPATH;
+
/* Let's make sure the filename doesn't end with "/", "/." or "/.." */
for (i = 1; path_len > i && i < 4; i++) {
if (!strncmp(path + path_len - i, pattern, i))
return GIT_EINVALIDPATH;
}
- error = gitfo_prettify_dir_path(buffer_out, path);
+ error = gitfo_prettify_dir_path(buffer_out, size, path);
if (error < GIT_SUCCESS)
return error;
@@ -551,3 +597,34 @@ int gitfo_cmp_path(const char *name1, int len1, int isdir1,
return 0;
}
+static void posixify_path(char *path)
+{
+ while (*path) {
+ if (*path == '\\')
+ *path = '/';
+
+ path++;
+ }
+}
+
+int gitfo_getcwd(char *buffer_out, size_t size)
+{
+ char *cwd_buffer;
+
+ assert(buffer_out && size > 0);
+
+#ifdef GIT_WIN32
+ cwd_buffer = _getcwd(buffer_out, size);
+#else
+ cwd_buffer = getcwd(buffer_out, size); //TODO: Fixme. Ensure the required headers are correctly included
+#endif
+
+ if (cwd_buffer == NULL)
+ return GIT_EOSERR;
+
+ posixify_path(buffer_out);
+
+ git__joinpath(buffer_out, buffer_out, ""); //Ensure the path ends with a trailing slash
+
+ return GIT_SUCCESS;
+}