static char *guess_dir_name(const char *repo, int is_bundle, int is_bare) { const char *end = repo + strlen(repo), *start, *ptr; size_t len; char *dir; /* * Skip scheme. */ start = strstr(repo, "://"); if (start == NULL) start = repo; else start += 3; /* * Skip authentication data. The stripping does happen * greedily, such that we strip up to the last '@' inside * the host part. */ for (ptr = start; ptr < end && !is_dir_sep(*ptr); ptr++) { if (*ptr == '@') start = ptr + 1; } /* * Strip trailing spaces, slashes and /.git */ while (start < end && (is_dir_sep(end[-1]) || isspace(end[-1]))) end--; if (end - start > 5 && is_dir_sep(end[-5]) && !strncmp(end - 4, ".git", 4)) { end -= 5; while (start < end && is_dir_sep(end[-1])) end--; } /* * Strip trailing port number if we've got only a * hostname (that is, there is no dir separator but a * colon). This check is required such that we do not * strip URI's like '/foo/bar:2222.git', which should * result in a dir '2222' being guessed due to backwards * compatibility. */ if (memchr(start, '/', end - start) == NULL && memchr(start, ':', end - start) != NULL) { ptr = end; while (start < ptr && isdigit(ptr[-1]) && ptr[-1] != ':') ptr--; if (start < ptr && ptr[-1] == ':') end = ptr - 1; } /* * Find last component. To remain backwards compatible we * also regard colons as path separators, such that * cloning a repository 'foo:bar.git' would result in a * directory 'bar' being guessed. */ ptr = end; while (start < ptr && !is_dir_sep(ptr[-1]) && ptr[-1] != ':') ptr--; start = ptr; /* * Strip .{bundle,git}. */ len = end - start; strip_suffix_mem(start, &len, is_bundle ? ".bundle" : ".git"); if (!len || (len == 1 && *start == '/')) die(_("No directory name could be guessed.\n" "Please specify a directory on the command line")); if (is_bare) dir = xstrfmt("%.*s.git", (int)len, start); else dir = xstrndup(start, len); /* * Replace sequences of 'control' characters and whitespace * with one ascii space, remove leading and trailing spaces. */ if (*dir) { char *out = dir; int prev_space = 1 /* strip leading whitespace */; for (end = dir; *end; ++end) { char ch = *end; if ((unsigned char)ch < '\x20') ch = '\x20'; if (isspace(ch)) { if (prev_space) continue; prev_space = 1; } else prev_space = 0; *out++ = ch; } *out = '\0'; if (out > dir && prev_space) out[-1] = '\0'; } return dir; }
static void add_repo(const char *base, struct strbuf *path, repo_config_fn fn) { struct stat st; struct passwd *pwd; size_t pathlen; struct strbuf rel = STRBUF_INIT; char *p, *slash; int n; size_t size; if (stat(path->buf, &st)) { fprintf(stderr, "Error accessing %s: %s (%d)\n", path->buf, strerror(errno), errno); return; } strbuf_addch(path, '/'); pathlen = path->len; if (ctx.cfg.strict_export) { strbuf_addstr(path, ctx.cfg.strict_export); if(stat(path->buf, &st)) return; strbuf_setlen(path, pathlen); } strbuf_addstr(path, "noweb"); if (!stat(path->buf, &st)) return; strbuf_setlen(path, pathlen); if (!starts_with(path->buf, base)) strbuf_addbuf(&rel, path); else strbuf_addstr(&rel, path->buf + strlen(base) + 1); if (!strcmp(rel.buf + rel.len - 5, "/.git")) strbuf_setlen(&rel, rel.len - 5); else if (rel.len && rel.buf[rel.len - 1] == '/') strbuf_setlen(&rel, rel.len - 1); repo = cgit_add_repo(rel.buf); config_fn = fn; if (ctx.cfg.enable_git_config) { strbuf_addstr(path, "config"); git_config_from_file(gitconfig_config, path->buf, NULL); strbuf_setlen(path, pathlen); } if (ctx.cfg.remove_suffix) { size_t urllen; strip_suffix(repo->url, ".git", &urllen); strip_suffix_mem(repo->url, &urllen, "/"); repo->url[urllen] = '\0'; } repo->path = xstrdup(path->buf); while (!repo->owner) { if ((pwd = getpwuid(st.st_uid)) == NULL) { fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n", path->buf, strerror(errno), errno); break; } if (pwd->pw_gecos) if ((p = strchr(pwd->pw_gecos, ','))) *p = '\0'; repo->owner = xstrdup(pwd->pw_gecos ? pwd->pw_gecos : pwd->pw_name); } if (repo->desc == cgit_default_repo_desc || !repo->desc) { strbuf_addstr(path, "description"); if (!stat(path->buf, &st)) readfile(path->buf, &repo->desc, &size); strbuf_setlen(path, pathlen); } if (ctx.cfg.section_from_path) { n = ctx.cfg.section_from_path; if (n > 0) { slash = rel.buf - 1; while (slash && n && (slash = strchr(slash + 1, '/'))) n--; } else { slash = rel.buf + rel.len; while (slash && n && (slash = xstrrchr(rel.buf, slash - 1, '/'))) n++; } if (slash && !n) { *slash = '\0'; repo->section = xstrdup(rel.buf); *slash = '/'; if (starts_with(repo->name, repo->section)) { repo->name += strlen(repo->section); if (*repo->name == '/') repo->name++; } } } strbuf_addstr(path, "cgitrc"); if (!stat(path->buf, &st)) parse_configfile(path->buf, &repo_config); strbuf_release(&rel); }