diff --git a/src/filebuf.c b/src/filebuf.c index a71c57a47..73f0a70f4 100644 --- a/src/filebuf.c +++ b/src/filebuf.c @@ -192,7 +192,7 @@ int git_filebuf_commit(git_filebuf *file) gitfo_close(file->fd); file->fd = -1; - error = gitfo_move_file(file->path_lock, file->path_original); + error = gitfo_mv(file->path_lock, file->path_original); cleanup: git_filebuf_cleanup(file); diff --git a/src/fileops.c b/src/fileops.c index 9938011d7..7691129f6 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -142,7 +142,7 @@ void gitfo_free_buf(gitfo_buf *obj) obj->data = NULL; } -int gitfo_move_file(char *from, char *to) +int gitfo_mv(const char *from, const char *to) { #ifdef GIT_WIN32 /* @@ -165,6 +165,29 @@ int gitfo_move_file(char *from, char *to) #endif } +int gitfo_mv_force(const char *from, const char *to) +{ + 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); + if (error < GIT_SUCCESS) + return error; + + /* Does the containing folder exist? */ + if (gitfo_isdir(target_folder_path)) { + git__joinpath(target_folder_path, target_folder_path, ""); /* Ensure there's a trailing slash */ + + /* Let's create the tree structure */ + error = gitfo_mkdir_recurs(target_folder_path, mode); + if (error < GIT_SUCCESS) + return error; + } + + return gitfo_mv(from, to); +} + int gitfo_map_ro(git_map *out, git_file fd, git_off_t begin, size_t len) { if (git__mmap(out, len, GIT_PROT_READ, GIT_MAP_SHARED, fd, begin) < GIT_SUCCESS) diff --git a/src/fileops.h b/src/fileops.h index 16e71038b..fd150df5e 100644 --- a/src/fileops.h +++ b/src/fileops.h @@ -68,7 +68,13 @@ extern git_off_t gitfo_size(git_file fd); extern int gitfo_read_file(gitfo_buf *obj, const char *path); extern void gitfo_free_buf(gitfo_buf *obj); -extern int gitfo_move_file(char *from, char *to); + +/* Move (rename) a file; this operation is atomic */ +extern int gitfo_mv(const char *from, const char *to); + +/* Move a file (forced); this will create the destination + * path if it doesn't exist */ +extern int gitfo_mv_force(const char *from, const char *to); #define gitfo_stat(p,b) stat(p, b) #define gitfo_fstat(f,b) fstat(f, b) diff --git a/src/odb_loose.c b/src/odb_loose.c index 735d9394f..4e2d9a639 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -528,7 +528,7 @@ static int write_obj(gitfo_buf *buf, git_oid *id, loose_backend *backend) gitfo_close(fd); gitfo_chmod(temp, 0444); - if (gitfo_move_file(temp, file) < 0) { + if (gitfo_mv(temp, file) < 0) { gitfo_unlink(temp); return GIT_EOSERR; } diff --git a/src/refs.c b/src/refs.c index 19f5406a4..5bbc7770e 100644 --- a/src/refs.c +++ b/src/refs.c @@ -1183,7 +1183,7 @@ int git_reference_rename(git_reference *ref, const char *new_name) git__joinpath(old_path, ref->owner->path_repository, old_name); git__joinpath(new_path, ref->owner->path_repository, ref->name); - error = gitfo_move_file(old_path, new_path); + error = gitfo_mv_force(old_path, new_path); if (error < GIT_SUCCESS) goto cleanup; @@ -1218,7 +1218,7 @@ rename_loose_to_old_name: git__joinpath(new_path, ref->owner->path_repository, old_name); /* No error checking. We'll return the initial error */ - gitfo_move_file(old_path, new_path); + gitfo_mv_force(old_path, new_path); /* restore the old name */ free(ref->name);