diff options
-rw-r--r-- | builtin-clone.c | 9 | ||||
-rw-r--r-- | builtin-count-objects.c | 5 | ||||
-rw-r--r-- | builtin-fsck.c | 14 | ||||
-rw-r--r-- | builtin-prune.c | 14 | ||||
-rw-r--r-- | builtin-rerere.c | 11 | ||||
-rw-r--r-- | dir.c | 31 | ||||
-rw-r--r-- | dir.h | 9 | ||||
-rw-r--r-- | entry.c | 5 | ||||
-rw-r--r-- | remote.c | 6 | ||||
-rwxr-xr-x | t/t5601-clone.sh | 19 | ||||
-rw-r--r-- | transport.c | 4 |
11 files changed, 77 insertions, 50 deletions
diff --git a/builtin-clone.c b/builtin-clone.c index f1a1a0c365..f7e5a7b0a0 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,10 @@ 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); + dest_exists = !stat(dir, &buf); + if (dest_exists && !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 +434,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/builtin-count-objects.c b/builtin-count-objects.c index ab35b65b07..62fd1f0961 100644 --- a/builtin-count-objects.c +++ b/builtin-count-objects.c @@ -5,6 +5,7 @@ */ #include "cache.h" +#include "dir.h" #include "builtin.h" #include "parse-options.h" @@ -21,9 +22,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose, const char *cp; int bad = 0; - if ((ent->d_name[0] == '.') && - (ent->d_name[1] == 0 || - ((ent->d_name[1] == '.') && (ent->d_name[2] == 0)))) + if (is_dot_or_dotdot(ent->d_name)) continue; for (cp = ent->d_name; *cp; cp++) { int ch = *cp; diff --git a/builtin-fsck.c b/builtin-fsck.c index 5c4c77adaa..aecc8280a0 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -10,6 +10,7 @@ #include "tree-walk.h" #include "fsck.h" #include "parse-options.h" +#include "dir.h" #define REACHABLE 0x0001 #define SEEN 0x0002 @@ -395,19 +396,12 @@ static void fsck_dir(int i, char *path) while ((de = readdir(dir)) != NULL) { char name[100]; unsigned char sha1[20]; - int len = strlen(de->d_name); - switch (len) { - case 2: - if (de->d_name[1] != '.') - break; - case 1: - if (de->d_name[0] != '.') - break; + if (is_dot_or_dotdot(de->d_name)) continue; - case 38: + if (strlen(de->d_name) == 38) { sprintf(name, "%02x", i); - memcpy(name+2, de->d_name, len+1); + memcpy(name+2, de->d_name, 39); if (get_sha1_hex(name, sha1) < 0) break; add_sha1_list(sha1, DIRENT_SORT_HINT(de)); diff --git a/builtin-prune.c b/builtin-prune.c index 7b4ec80e62..545e9c1f94 100644 --- a/builtin-prune.c +++ b/builtin-prune.c @@ -5,6 +5,7 @@ #include "builtin.h" #include "reachable.h" #include "parse-options.h" +#include "dir.h" static const char * const prune_usage[] = { "git prune [-n] [-v] [--expire <time>] [--] [<head>...]", @@ -61,19 +62,12 @@ static int prune_dir(int i, char *path) while ((de = readdir(dir)) != NULL) { char name[100]; unsigned char sha1[20]; - int len = strlen(de->d_name); - switch (len) { - case 2: - if (de->d_name[1] != '.') - break; - case 1: - if (de->d_name[0] != '.') - break; + if (is_dot_or_dotdot(de->d_name)) continue; - case 38: + if (strlen(de->d_name) == 38) { sprintf(name, "%02x", i); - memcpy(name+2, de->d_name, len+1); + memcpy(name+2, de->d_name, 39); if (get_sha1_hex(name, sha1) < 0) break; diff --git a/builtin-rerere.c b/builtin-rerere.c index d4dec6b715..bd8fc77a7a 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "dir.h" #include "string-list.h" #include "rerere.h" #include "xdiff/xdiff.h" @@ -59,17 +60,15 @@ static void garbage_collect(struct string_list *rr) git_config(git_rerere_gc_config, NULL); dir = opendir(git_path("rr-cache")); while ((e = readdir(dir))) { - const char *name = e->d_name; - if (name[0] == '.' && - (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) + if (is_dot_or_dotdot(e->d_name)) continue; - then = rerere_created_at(name); + then = rerere_created_at(e->d_name); if (!then) continue; - cutoff = (has_resolution(name) + cutoff = (has_resolution(e->d_name) ? cutoff_resolve : cutoff_noresolve); if (then < now - cutoff * 86400) - string_list_append(name, &to_remove); + string_list_append(e->d_name, &to_remove); } for (i = 0; i < to_remove.nr; i++) unlink_rr_item(to_remove.items[i].string); @@ -585,10 +585,8 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co int len, dtype; int exclude; - if ((de->d_name[0] == '.') && - (de->d_name[1] == 0 || - !strcmp(de->d_name + 1, ".") || - !strcmp(de->d_name + 1, "git"))) + if (is_dot_or_dotdot(de->d_name) || + !strcmp(de->d_name, ".git")) continue; len = strlen(de->d_name); /* Ignore overly long pathnames! */ @@ -779,6 +777,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_dot_or_dotdot(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); @@ -793,10 +810,8 @@ int remove_dir_recursively(struct strbuf *path, int only_empty) len = path->len; while ((e = readdir(dir)) != NULL) { struct stat st; - if ((e->d_name[0] == '.') && - ((e->d_name[1] == 0) || - ((e->d_name[1] == '.') && e->d_name[2] == 0))) - continue; /* "." and ".." */ + if (is_dot_or_dotdot(e->d_name)) + continue; strbuf_setlen(path, len); strbuf_addstr(path, e->d_name); @@ -77,6 +77,15 @@ 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_dot_or_dotdot(const char *name) +{ + return (name[0] == '.' && + (name[1] == '\0' || + (name[1] == '.' && name[2] == '\0'))); +} + +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,5 +1,6 @@ #include "cache.h" #include "blob.h" +#include "dir.h" static void create_directories(const char *path, const struct checkout *state) { @@ -62,9 +63,7 @@ static void remove_subtree(const char *path) *name++ = '/'; while ((de = readdir(dir)) != NULL) { struct stat st; - if ((de->d_name[0] == '.') && - ((de->d_name[1] == 0) || - ((de->d_name[1] == '.') && de->d_name[2] == 0))) + if (is_dot_or_dotdot(de->d_name)) continue; strcpy(name, de->d_name); if (lstat(pathbuf, &st)) @@ -4,6 +4,7 @@ #include "commit.h" #include "diff.h" #include "revision.h" +#include "dir.h" static struct refspec s_tag_refspec = { 0, @@ -634,10 +635,7 @@ static struct refspec *parse_push_refspec(int nr_refspec, const char **refspec) static int valid_remote_nick(const char *name) { - if (!name[0] || /* not empty */ - (name[0] == '.' && /* not "." */ - (!name[1] || /* not ".." */ - (name[1] == '.' && !name[2])))) + if (!name[0] || is_dot_or_dotdot(name)) return 0; return !strchr(name, '/'); /* no slash */ } diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 78a3fa639c..fe287d31fb 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -125,4 +125,23 @@ test_expect_success 'clone to destination with extra trailing /' ' ' +test_expect_success 'clone to an existing empty directory' ' + mkdir target-3 && + git clone src target-3 && + T=$( cd target-3 && git rev-parse HEAD ) && + S=$( cd src && git rev-parse HEAD ) && + test "$T" = "$S" +' + +test_expect_success 'clone to an existing non-empty directory' ' + mkdir target-4 && + >target-4/Fakefile && + test_must_fail git clone src target-4 +' + +test_expect_success 'clone to an existing path' ' + >target-5 && + test_must_fail git clone src target-5 +' + test_done diff --git a/transport.c b/transport.c index 56831c57c5..9ad4a16c31 100644 --- a/transport.c +++ b/transport.c @@ -50,9 +50,7 @@ static int read_loose_refs(struct strbuf *path, int name_offset, memset (&list, 0, sizeof(list)); while ((de = readdir(dir))) { - if (de->d_name[0] == '.' && (de->d_name[1] == '\0' || - (de->d_name[1] == '.' && - de->d_name[2] == '\0'))) + if (is_dot_or_dotdot(de->d_name)) continue; ALLOC_GROW(list.entries, list.nr + 1, list.alloc); list.entries[list.nr++] = xstrdup(de->d_name); |