aboutsummaryrefslogtreecommitdiffstats
path: root/scan-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'scan-tree.c')
-rw-r--r--scan-tree.c160
1 files changed, 89 insertions, 71 deletions
diff --git a/scan-tree.c b/scan-tree.c
index 05caba5..beb584b 100644
--- a/scan-tree.c
+++ b/scan-tree.c
@@ -12,38 +12,38 @@
12#include "configfile.h" 12#include "configfile.h"
13#include "html.h" 13#include "html.h"
14 14
15#define MAX_PATH 4096
16
17/* return 1 if path contains a objects/ directory and a HEAD file */ 15/* return 1 if path contains a objects/ directory and a HEAD file */
18static int is_git_dir(const char *path) 16static int is_git_dir(const char *path)
19{ 17{
20 struct stat st; 18 struct stat st;
21 static char buf[MAX_PATH]; 19 struct strbuf pathbuf = STRBUF_INIT;
20 int result = 0;
22 21
23 if (snprintf(buf, MAX_PATH, "%s/objects", path) >= MAX_PATH) { 22 strbuf_addf(&pathbuf, "%s/objects", path);
24 fprintf(stderr, "Insanely long path: %s\n", path); 23 if (stat(pathbuf.buf, &st)) {
25 return 0;
26 }
27 if (stat(buf, &st)) {
28 if (errno != ENOENT) 24 if (errno != ENOENT)
29 fprintf(stderr, "Error checking path %s: %s (%d)\n", 25 fprintf(stderr, "Error checking path %s: %s (%d)\n",
30 path, strerror(errno), errno); 26 path, strerror(errno), errno);
31 return 0; 27 goto out;
32 } 28 }
33 if (!S_ISDIR(st.st_mode)) 29 if (!S_ISDIR(st.st_mode))
34 return 0; 30 goto out;
35 31
36 sprintf(buf, "%s/HEAD", path); 32 strbuf_reset(&pathbuf);
37 if (stat(buf, &st)) { 33 strbuf_addf(&pathbuf, "%s/HEAD", path);
34 if (stat(pathbuf.buf, &st)) {
38 if (errno != ENOENT) 35 if (errno != ENOENT)
39 fprintf(stderr, "Error checking path %s: %s (%d)\n", 36 fprintf(stderr, "Error checking path %s: %s (%d)\n",
40 path, strerror(errno), errno); 37 path, strerror(errno), errno);
41 return 0; 38 goto out;
42 } 39 }
43 if (!S_ISREG(st.st_mode)) 40 if (!S_ISREG(st.st_mode))
44 return 0; 41 goto out;
45 42
46 return 1; 43 result = 1;
44out:
45 strbuf_release(&pathbuf);
46 return result;
47} 47}
48 48
49struct cgit_repo *repo; 49struct cgit_repo *repo;
@@ -75,47 +75,61 @@ static char *xstrrchr(char *s, char *from, int c)
75 return from < s ? NULL : from; 75 return from < s ? NULL : from;
76} 76}
77 77
78static void add_repo(const char *base, const char *path, repo_config_fn fn) 78static void add_repo(const char *base, struct strbuf *path, repo_config_fn fn)
79{ 79{
80 struct stat st; 80 struct stat st;
81 struct passwd *pwd; 81 struct passwd *pwd;
82 char *rel, *p, *slash; 82 size_t pathlen;
83 struct strbuf rel = STRBUF_INIT;
84 char *p, *slash;
83 int n; 85 int n;
84 size_t size; 86 size_t size;
85 87
86 if (stat(path, &st)) { 88 if (stat(path->buf, &st)) {
87 fprintf(stderr, "Error accessing %s: %s (%d)\n", 89 fprintf(stderr, "Error accessing %s: %s (%d)\n",
88 path, strerror(errno), errno); 90 path->buf, strerror(errno), errno);
89 return; 91 return;
90 } 92 }
91 93
92 if (ctx.cfg.strict_export && stat(fmt("%s/%s", path, ctx.cfg.strict_export), &st)) 94 strbuf_addch(path, '/');
93 return; 95 pathlen = path->len;
94 96
95 if (!stat(fmt("%s/noweb", path), &st)) 97 if (ctx.cfg.strict_export) {
98 strbuf_addstr(path, ctx.cfg.strict_export);
99 if(stat(path->buf, &st))
100 return;
101 strbuf_setlen(path, pathlen);
102 }
103
104 strbuf_addstr(path, "noweb");
105 if (!stat(path->buf, &st))
96 return; 106 return;
107 strbuf_setlen(path, pathlen);
97 108
98 if (base == path) 109 if (strncmp(base, path->buf, strlen(base)))
99 rel = xstrdup(path); 110 strbuf_addbuf(&rel, path);
100 else 111 else
101 rel = xstrdup(path + strlen(base) + 1); 112 strbuf_addstr(&rel, path->buf + strlen(base) + 1);
102 113
103 if (!strcmp(rel + strlen(rel) - 5, "/.git")) 114 if (!strcmp(rel.buf + rel.len - 5, "/.git"))
104 rel[strlen(rel) - 5] = '\0'; 115 strbuf_setlen(&rel, rel.len - 5);
105 116
106 repo = cgit_add_repo(rel); 117 repo = cgit_add_repo(rel.buf);
107 config_fn = fn; 118 config_fn = fn;
108 if (ctx.cfg.enable_git_config) 119 if (ctx.cfg.enable_git_config) {
109 git_config_from_file(gitconfig_config, fmt("%s/config", path), NULL); 120 strbuf_addstr(path, "config");
121 git_config_from_file(gitconfig_config, path->buf, NULL);
122 strbuf_setlen(path, pathlen);
123 }
110 124
111 if (ctx.cfg.remove_suffix) 125 if (ctx.cfg.remove_suffix)
112 if ((p = strrchr(repo->url, '.')) && !strcmp(p, ".git")) 126 if ((p = strrchr(repo->url, '.')) && !strcmp(p, ".git"))
113 *p = '\0'; 127 *p = '\0';
114 repo->path = xstrdup(path); 128 repo->path = xstrdup(path->buf);
115 while (!repo->owner) { 129 while (!repo->owner) {
116 if ((pwd = getpwuid(st.st_uid)) == NULL) { 130 if ((pwd = getpwuid(st.st_uid)) == NULL) {
117 fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n", 131 fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n",
118 path, strerror(errno), errno); 132 path->buf, strerror(errno), errno);
119 break; 133 break;
120 } 134 }
121 if (pwd->pw_gecos) 135 if (pwd->pw_gecos)
@@ -125,30 +139,32 @@ static void add_repo(const char *base, const char *path, repo_config_fn fn)
125 } 139 }
126 140
127 if (repo->desc == cgit_default_repo_desc || !repo->desc) { 141 if (repo->desc == cgit_default_repo_desc || !repo->desc) {
128 p = fmt("%s/description", path); 142 strbuf_addstr(path, "description");
129 if (!stat(p, &st)) 143 if (!stat(path->buf, &st))
130 readfile(p, &repo->desc, &size); 144 readfile(path->buf, &repo->desc, &size);
145 strbuf_setlen(path, pathlen);
131 } 146 }
132 147
133 if (!repo->readme) { 148 if (!repo->readme) {
134 p = fmt("%s/README.html", path); 149 strbuf_addstr(path, "README.html");
135 if (!stat(p, &st)) 150 if (!stat(path->buf, &st))
136 repo->readme = "README.html"; 151 repo->readme = "README.html";
152 strbuf_setlen(path, pathlen);
137 } 153 }
138 if (ctx.cfg.section_from_path) { 154 if (ctx.cfg.section_from_path) {
139 n = ctx.cfg.section_from_path; 155 n = ctx.cfg.section_from_path;
140 if (n > 0) { 156 if (n > 0) {
141 slash = rel; 157 slash = rel.buf;
142 while (slash && n && (slash = strchr(slash, '/'))) 158 while (slash && n && (slash = strchr(slash, '/')))
143 n--; 159 n--;
144 } else { 160 } else {
145 slash = rel + strlen(rel); 161 slash = rel.buf + rel.len;
146 while (slash && n && (slash = xstrrchr(rel, slash, '/'))) 162 while (slash && n && (slash = xstrrchr(rel.buf, slash, '/')))
147 n++; 163 n++;
148 } 164 }
149 if (slash && !n) { 165 if (slash && !n) {
150 *slash = '\0'; 166 *slash = '\0';
151 repo->section = xstrdup(rel); 167 repo->section = xstrdup(rel.buf);
152 *slash = '/'; 168 *slash = '/';
153 if (!prefixcmp(repo->name, repo->section)) { 169 if (!prefixcmp(repo->name, repo->section)) {
154 repo->name += strlen(repo->section); 170 repo->name += strlen(repo->section);
@@ -158,19 +174,19 @@ static void add_repo(const char *base, const char *path, repo_config_fn fn)
158 } 174 }
159 } 175 }
160 176
161 p = fmt("%s/cgitrc", path); 177 strbuf_addstr(path, "cgitrc");
162 if (!stat(p, &st)) 178 if (!stat(path->buf, &st))
163 parse_configfile(xstrdup(p), &repo_config); 179 parse_configfile(xstrdup(path->buf), &repo_config);
164
165 180
166 free(rel); 181 strbuf_release(&rel);
167} 182}
168 183
169static void scan_path(const char *base, const char *path, repo_config_fn fn) 184static void scan_path(const char *base, const char *path, repo_config_fn fn)
170{ 185{
171 DIR *dir = opendir(path); 186 DIR *dir = opendir(path);
172 struct dirent *ent; 187 struct dirent *ent;
173 char *buf; 188 struct strbuf pathbuf = STRBUF_INIT;
189 size_t pathlen = strlen(path);
174 struct stat st; 190 struct stat st;
175 191
176 if (!dir) { 192 if (!dir) {
@@ -178,14 +194,22 @@ static void scan_path(const char *base, const char *path, repo_config_fn fn)
178 path, strerror(errno), errno); 194 path, strerror(errno), errno);
179 return; 195 return;
180 } 196 }
181 if (is_git_dir(path)) { 197
182 add_repo(base, path, fn); 198 strbuf_add(&pathbuf, path, strlen(path));
199 if (is_git_dir(pathbuf.buf)) {
200 add_repo(base, &pathbuf, fn);
183 goto end; 201 goto end;
184 } 202 }
185 if (is_git_dir(fmt("%s/.git", path))) { 203 strbuf_addstr(&pathbuf, "/.git");
186 add_repo(base, fmt("%s/.git", path), fn); 204 if (is_git_dir(pathbuf.buf)) {
205 add_repo(base, &pathbuf, fn);
187 goto end; 206 goto end;
188 } 207 }
208 /*
209 * Add one because we don't want to lose the trailing '/' when we
210 * reset the length of pathbuf in the loop below.
211 */
212 pathlen++;
189 while ((ent = readdir(dir)) != NULL) { 213 while ((ent = readdir(dir)) != NULL) {
190 if (ent->d_name[0] == '.') { 214 if (ent->d_name[0] == '.') {
191 if (ent->d_name[1] == '\0') 215 if (ent->d_name[1] == '\0')
@@ -195,24 +219,18 @@ static void scan_path(const char *base, const char *path, repo_config_fn fn)
195 if (!ctx.cfg.scan_hidden_path) 219 if (!ctx.cfg.scan_hidden_path)
196 continue; 220 continue;
197 } 221 }
198 buf = malloc(strlen(path) + strlen(ent->d_name) + 2); 222 strbuf_setlen(&pathbuf, pathlen);
199 if (!buf) { 223 strbuf_addstr(&pathbuf, ent->d_name);
200 fprintf(stderr, "Alloc error on %s: %s (%d)\n", 224 if (stat(pathbuf.buf, &st)) {
201 path, strerror(errno), errno);
202 exit(1);
203 }
204 sprintf(buf, "%s/%s", path, ent->d_name);
205 if (stat(buf, &st)) {
206 fprintf(stderr, "Error checking path %s: %s (%d)\n", 225 fprintf(stderr, "Error checking path %s: %s (%d)\n",
207 buf, strerror(errno), errno); 226 pathbuf.buf, strerror(errno), errno);
208 free(buf);
209 continue; 227 continue;
210 } 228 }
211 if (S_ISDIR(st.st_mode)) 229 if (S_ISDIR(st.st_mode))
212 scan_path(base, buf, fn); 230 scan_path(base, pathbuf.buf, fn);
213 free(buf);
214 } 231 }
215end: 232end:
233 strbuf_release(&pathbuf);
216 closedir(dir); 234 closedir(dir);
217} 235}
218 236
@@ -220,7 +238,7 @@ end:
220 238
221void scan_projects(const char *path, const char *projectsfile, repo_config_fn fn) 239void scan_projects(const char *path, const char *projectsfile, repo_config_fn fn)
222{ 240{
223 char line[MAX_PATH * 2], *z; 241 struct strbuf line = STRBUF_INIT;
224 FILE *projects; 242 FILE *projects;
225 int err; 243 int err;
226 244
@@ -230,19 +248,19 @@ void scan_projects(const char *path, const char *projectsfile, repo_config_fn fn
230 projectsfile, strerror(errno), errno); 248 projectsfile, strerror(errno), errno);
231 return; 249 return;
232 } 250 }
233 while (fgets(line, sizeof(line), projects) != NULL) { 251 while (strbuf_getline(&line, projects, '\n') != EOF) {
234 for (z = &lastc(line); 252 if (!line.len)
235 strlen(line) && strchr("\n\r", *z); 253 continue;
236 z = &lastc(line)) 254 strbuf_insert(&line, 0, "/", 1);
237 *z = '\0'; 255 strbuf_insert(&line, 0, path, strlen(path));
238 if (strlen(line)) 256 scan_path(path, line.buf, fn);
239 scan_path(path, fmt("%s/%s", path, line), fn);
240 } 257 }
241 if ((err = ferror(projects))) { 258 if ((err = ferror(projects))) {
242 fprintf(stderr, "Error reading from projectsfile %s: %s (%d)\n", 259 fprintf(stderr, "Error reading from projectsfile %s: %s (%d)\n",
243 projectsfile, strerror(err), err); 260 projectsfile, strerror(err), err);
244 } 261 }
245 fclose(projects); 262 fclose(projects);
263 strbuf_release(&line);
246} 264}
247 265
248void scan_tree(const char *path, repo_config_fn fn) 266void scan_tree(const char *path, repo_config_fn fn)