The die() message changed accordingly. The previous behaviour was to only allow cloning when the destination directory doesn't exist. A new inline function is_pseudo_dir_name is used to check if the directory name is either "." or "..". It returns a non-zero value if the given string is "." or "..". It's applicable to a lot of other Git source code. Signed-off-by: Alexander Potashev <aspotashev@xxxxxxxxx> --- builtin-clone.c | 8 +++++--- dir.c | 19 +++++++++++++++++++ dir.h | 8 ++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/builtin-clone.c b/builtin-clone.c index f1a1a0c..e732f15 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -357,6 +357,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) struct stat buf; const char *repo_name, *repo, *work_tree, *git_dir; char *path, *dir; + int dest_exists; const struct ref *refs, *head_points_at, *remote_head, *mapped_refs; struct strbuf key = STRBUF_INIT, value = STRBUF_INIT; struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT; @@ -406,8 +407,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix) dir = guess_dir_name(repo_name, is_bundle, option_bare); strip_trailing_slashes(dir); - if (!stat(dir, &buf)) - die("destination directory '%s' already exists.", dir); + if ((dest_exists = !stat(dir, &buf)) && !is_empty_dir(dir)) + die("destination path '%s' already exists and is not " + "an empty directory.", dir); strbuf_addf(&reflog_msg, "clone: from %s", repo); @@ -431,7 +433,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (safe_create_leading_directories_const(work_tree) < 0) die("could not create leading directories of '%s': %s", work_tree, strerror(errno)); - if (mkdir(work_tree, 0755)) + if (!dest_exists && mkdir(work_tree, 0755)) die("could not create work tree dir '%s': %s.", work_tree, strerror(errno)); set_git_work_tree(work_tree); diff --git a/dir.c b/dir.c index 0131983..bd97e50 100644 --- a/dir.c +++ b/dir.c @@ -779,6 +779,25 @@ int is_inside_dir(const char *dir) return get_relative_cwd(buffer, sizeof(buffer), dir) != NULL; } +int is_empty_dir(const char *path) +{ + DIR *dir = opendir(path); + struct dirent *e; + int ret = 1; + + if (!dir) + return 0; + + while ((e = readdir(dir)) != NULL) + if (!is_pseudo_dir_name(e->d_name)) { + ret = 0; + break; + } + + closedir(dir); + return ret; +} + int remove_dir_recursively(struct strbuf *path, int only_empty) { DIR *dir = opendir(path->buf); diff --git a/dir.h b/dir.h index 768425a..940e057 100644 --- a/dir.h +++ b/dir.h @@ -77,6 +77,14 @@ extern int file_exists(const char *); extern char *get_relative_cwd(char *buffer, int size, const char *dir); extern int is_inside_dir(const char *dir); +static inline int is_pseudo_dir_name(const char *name) +{ + return name[0] == '.' && (name[1] == '\0' || + (name[1] == '.' && name[2] == '\0')); /* "." and ".." */ +} + +extern int is_empty_dir(const char *dir); + extern void setup_standard_excludes(struct dir_struct *dir); extern int remove_dir_recursively(struct strbuf *path, int only_empty); -- 1.6.1.77.g84c9 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html