Makefile: Set compiler switch for USE_NSEC
[gitweb.git] / builtin-clone.c
index 8e1a1d399580af3faa39c3c50350b3ca19df0634..f73029e2ba285bfb20bce1760cef711f7a55fd02 100644 (file)
@@ -19,6 +19,7 @@
 #include "strbuf.h"
 #include "dir.h"
 #include "pack-refs.h"
+#include "sigchain.h"
 
 /*
  * Overall FIXMEs:
@@ -134,9 +135,9 @@ static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
        }
 
        if (is_bare) {
-               char *result = xmalloc(end - start + 5);
-               sprintf(result, "%.*s.git", (int)(end - start), start);
-               return result;
+               struct strbuf result = STRBUF_INIT;
+               strbuf_addf(&result, "%.*s.git", (int)(end - start), start);
+               return strbuf_detach(&result, 0);
        }
 
        return xstrndup(start, end - start);
@@ -183,36 +184,38 @@ static void setup_reference(const char *repo)
        free(ref_git_copy);
 }
 
-static void copy_or_link_directory(char *src, char *dest)
+static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest)
 {
        struct dirent *de;
        struct stat buf;
        int src_len, dest_len;
        DIR *dir;
 
-       dir = opendir(src);
+       dir = opendir(src->buf);
        if (!dir)
-               die("failed to open %s\n", src);
+               die("failed to open %s", src->buf);
 
-       if (mkdir(dest, 0777)) {
+       if (mkdir(dest->buf, 0777)) {
                if (errno != EEXIST)
-                       die("failed to create directory %s\n", dest);
-               else if (stat(dest, &buf))
-                       die("failed to stat %s\n", dest);
+                       die("failed to create directory %s", dest->buf);
+               else if (stat(dest->buf, &buf))
+                       die("failed to stat %s", dest->buf);
                else if (!S_ISDIR(buf.st_mode))
-                       die("%s exists and is not a directory\n", dest);
+                       die("%s exists and is not a directory", dest->buf);
        }
 
-       src_len = strlen(src);
-       src[src_len] = '/';
-       dest_len = strlen(dest);
-       dest[dest_len] = '/';
+       strbuf_addch(src, '/');
+       src_len = src->len;
+       strbuf_addch(dest, '/');
+       dest_len = dest->len;
 
        while ((de = readdir(dir)) != NULL) {
-               strcpy(src + src_len + 1, de->d_name);
-               strcpy(dest + dest_len + 1, de->d_name);
-               if (stat(src, &buf)) {
-                       warning ("failed to stat %s\n", src);
+               strbuf_setlen(src, src_len);
+               strbuf_addstr(src, de->d_name);
+               strbuf_setlen(dest, dest_len);
+               strbuf_addstr(dest, de->d_name);
+               if (stat(src->buf, &buf)) {
+                       warning ("failed to stat %s\n", src->buf);
                        continue;
                }
                if (S_ISDIR(buf.st_mode)) {
@@ -221,17 +224,17 @@ static void copy_or_link_directory(char *src, char *dest)
                        continue;
                }
 
-               if (unlink(dest) && errno != ENOENT)
-                       die("failed to unlink %s\n", dest);
+               if (unlink(dest->buf) && errno != ENOENT)
+                       die("failed to unlink %s", dest->buf);
                if (!option_no_hardlinks) {
-                       if (!link(src, dest))
+                       if (!link(src->buf, dest->buf))
                                continue;
                        if (option_local)
-                               die("failed to create link %s\n", dest);
+                               die("failed to create link %s", dest->buf);
                        option_no_hardlinks = 1;
                }
-               if (copy_file(dest, src, 0666))
-                       die("failed to copy file to %s\n", dest);
+               if (copy_file(dest->buf, src->buf, 0666))
+                       die("failed to copy file to %s", dest->buf);
        }
        closedir(dir);
 }
@@ -240,17 +243,19 @@ static const struct ref *clone_local(const char *src_repo,
                                     const char *dest_repo)
 {
        const struct ref *ret;
-       char src[PATH_MAX];
-       char dest[PATH_MAX];
+       struct strbuf src = STRBUF_INIT;
+       struct strbuf dest = STRBUF_INIT;
        struct remote *remote;
        struct transport *transport;
 
        if (option_shared)
                add_to_alternates_file(src_repo);
        else {
-               snprintf(src, PATH_MAX, "%s/objects", src_repo);
-               snprintf(dest, PATH_MAX, "%s/objects", dest_repo);
-               copy_or_link_directory(src, dest);
+               strbuf_addf(&src, "%s/objects", src_repo);
+               strbuf_addf(&dest, "%s/objects", dest_repo);
+               copy_or_link_directory(&src, &dest);
+               strbuf_release(&src);
+               strbuf_release(&dest);
        }
 
        remote = remote_get(src_repo);
@@ -284,7 +289,7 @@ static void remove_junk(void)
 static void remove_junk_on_signal(int signo)
 {
        remove_junk();
-       signal(SIGINT, SIG_DFL);
+       sigchain_pop(signo);
        raise(signo);
 }
 
@@ -353,9 +358,10 @@ 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;
-       char branch_top[256], key[256], value[256];
-       struct strbuf reflog_msg = STRBUF_INIT;
+       struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
+       struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
        struct transport *transport = NULL;
        char *src_ref_prefix = "refs/heads/";
 
@@ -402,8 +408,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);
 
@@ -427,14 +435,14 @@ 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);
        }
        junk_git_dir = git_dir;
        atexit(remove_junk);
-       signal(SIGINT, remove_junk_on_signal);
+       sigchain_push_common(remove_junk_on_signal);
 
        setenv(CONFIG_ENVIRONMENT, xstrdup(mkpath("%s/config", git_dir)), 1);
 
@@ -459,35 +467,36 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        if (option_bare) {
                if (option_mirror)
                        src_ref_prefix = "refs/";
-               strcpy(branch_top, src_ref_prefix);
+               strbuf_addstr(&branch_top, src_ref_prefix);
 
                git_config_set("core.bare", "true");
        } else {
-               snprintf(branch_top, sizeof(branch_top),
-                        "refs/remotes/%s/", option_origin);
+               strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin);
        }
 
        if (option_mirror || !option_bare) {
                /* Configure the remote */
                if (option_mirror) {
-                       snprintf(key, sizeof(key),
-                                       "remote.%s.mirror", option_origin);
-                       git_config_set(key, "true");
+                       strbuf_addf(&key, "remote.%s.mirror", option_origin);
+                       git_config_set(key.buf, "true");
+                       strbuf_reset(&key);
                }
 
-               snprintf(key, sizeof(key), "remote.%s.url", option_origin);
-               git_config_set(key, repo);
+               strbuf_addf(&key, "remote.%s.url", option_origin);
+               git_config_set(key.buf, repo);
+                       strbuf_reset(&key);
 
-               snprintf(key, sizeof(key), "remote.%s.fetch", option_origin);
-               snprintf(value, sizeof(value),
-                               "+%s*:%s*", src_ref_prefix, branch_top);
-               git_config_set_multivar(key, value, "^$", 0);
+               strbuf_addf(&key, "remote.%s.fetch", option_origin);
+               strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
+               git_config_set_multivar(key.buf, value.buf, "^$", 0);
+               strbuf_reset(&key);
+               strbuf_reset(&value);
        }
 
        refspec.force = 0;
        refspec.pattern = 1;
        refspec.src = src_ref_prefix;
-       refspec.dst = branch_top;
+       refspec.dst = branch_top.buf;
 
        if (path && !is_bundle)
                refs = clone_local(path, git_dir);
@@ -514,14 +523,23 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                                             option_upload_pack);
 
                refs = transport_get_remote_refs(transport);
-               transport_fetch_refs(transport, refs);
+               if(refs)
+                       transport_fetch_refs(transport, refs);
        }
 
-       clear_extra_refs();
+       if (refs) {
+               clear_extra_refs();
 
-       mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf);
+               mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf);
 
-       head_points_at = locate_head(refs, mapped_refs, &remote_head);
+               head_points_at = locate_head(refs, mapped_refs, &remote_head);
+       }
+       else {
+               warning("You appear to have cloned an empty repository.");
+               head_points_at = NULL;
+               remote_head = NULL;
+               option_no_checkout = 1;
+       }
 
        if (head_points_at) {
                /* Local default branch link */
@@ -541,7 +559,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                                   head_points_at->old_sha1,
                                   NULL, 0, DIE_ON_ERR);
 
-                       strbuf_addstr(&head_ref, branch_top);
+                       strbuf_addstr(&head_ref, branch_top.buf);
                        strbuf_addstr(&head_ref, "HEAD");
 
                        /* Remote branch link */
@@ -549,10 +567,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                                      head_points_at->peer_ref->name,
                                      reflog_msg.buf);
 
-                       snprintf(key, sizeof(key), "branch.%s.remote", head);
-                       git_config_set(key, option_origin);
-                       snprintf(key, sizeof(key), "branch.%s.merge", head);
-                       git_config_set(key, head_points_at->name);
+                       strbuf_addf(&key, "branch.%s.remote", head);
+                       git_config_set(key.buf, option_origin);
+                       strbuf_reset(&key);
+                       strbuf_addf(&key, "branch.%s.merge", head);
+                       git_config_set(key.buf, head_points_at->name);
                }
        } else if (remote_head) {
                /* Source had detached HEAD pointing somewhere. */
@@ -602,6 +621,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        }
 
        strbuf_release(&reflog_msg);
+       strbuf_release(&branch_top);
+       strbuf_release(&key);
+       strbuf_release(&value);
        junk_pid = 0;
        return 0;
 }