summaryrefslogtreecommitdiffabout
authorJohan Herland <johan@herland.net>2010-11-15 19:41:00 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2011-02-19 13:25:14 (UTC)
commitdf522794c38934be3229a11e0e2432a1f2a3bc8d (patch) (unidiff)
treef11aef6d303a5327303a4471d47444764bea53d8
parent682adbc0cad2baa1a6119013b166f52de3ee3352 (diff)
downloadcgit-df522794c38934be3229a11e0e2432a1f2a3bc8d.zip
cgit-df522794c38934be3229a11e0e2432a1f2a3bc8d.tar.gz
cgit-df522794c38934be3229a11e0e2432a1f2a3bc8d.tar.bz2
scan_path(): Do not recurse into hidden directories by default
Paths that start with a period ('.') are considered hidden in the Unix world. scan_path() should arguably not recurse into these directories by default. This patch makes it so, and introduces the "scan-hidden-path" config variable for overriding the new default and revert to the old behaviour (scanning _all_ directories, including hidden .directories). Signed-off-by: Johan Herland <johan@herland.net> Signed-off-by: Lars Hjemli <larsh@prediktor.no>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c3
-rw-r--r--cgit.h1
-rw-r--r--cgitrc.5.txt8
-rw-r--r--scan-tree.c2
4 files changed, 14 insertions, 0 deletions
diff --git a/cgit.c b/cgit.c
index 412fbf0..6a76281 100644
--- a/cgit.c
+++ b/cgit.c
@@ -102,312 +102,315 @@ void config_cb(const char *name, const char *value)
102 else if (!strcmp(name, "root-readme")) 102 else if (!strcmp(name, "root-readme"))
103 ctx.cfg.root_readme = xstrdup(value); 103 ctx.cfg.root_readme = xstrdup(value);
104 else if (!strcmp(name, "css")) 104 else if (!strcmp(name, "css"))
105 ctx.cfg.css = xstrdup(value); 105 ctx.cfg.css = xstrdup(value);
106 else if (!strcmp(name, "favicon")) 106 else if (!strcmp(name, "favicon"))
107 ctx.cfg.favicon = xstrdup(value); 107 ctx.cfg.favicon = xstrdup(value);
108 else if (!strcmp(name, "footer")) 108 else if (!strcmp(name, "footer"))
109 ctx.cfg.footer = xstrdup(value); 109 ctx.cfg.footer = xstrdup(value);
110 else if (!strcmp(name, "head-include")) 110 else if (!strcmp(name, "head-include"))
111 ctx.cfg.head_include = xstrdup(value); 111 ctx.cfg.head_include = xstrdup(value);
112 else if (!strcmp(name, "header")) 112 else if (!strcmp(name, "header"))
113 ctx.cfg.header = xstrdup(value); 113 ctx.cfg.header = xstrdup(value);
114 else if (!strcmp(name, "logo")) 114 else if (!strcmp(name, "logo"))
115 ctx.cfg.logo = xstrdup(value); 115 ctx.cfg.logo = xstrdup(value);
116 else if (!strcmp(name, "index-header")) 116 else if (!strcmp(name, "index-header"))
117 ctx.cfg.index_header = xstrdup(value); 117 ctx.cfg.index_header = xstrdup(value);
118 else if (!strcmp(name, "index-info")) 118 else if (!strcmp(name, "index-info"))
119 ctx.cfg.index_info = xstrdup(value); 119 ctx.cfg.index_info = xstrdup(value);
120 else if (!strcmp(name, "logo-link")) 120 else if (!strcmp(name, "logo-link"))
121 ctx.cfg.logo_link = xstrdup(value); 121 ctx.cfg.logo_link = xstrdup(value);
122 else if (!strcmp(name, "module-link")) 122 else if (!strcmp(name, "module-link"))
123 ctx.cfg.module_link = xstrdup(value); 123 ctx.cfg.module_link = xstrdup(value);
124 else if (!strcmp(name, "strict-export")) 124 else if (!strcmp(name, "strict-export"))
125 ctx.cfg.strict_export = xstrdup(value); 125 ctx.cfg.strict_export = xstrdup(value);
126 else if (!strcmp(name, "virtual-root")) { 126 else if (!strcmp(name, "virtual-root")) {
127 ctx.cfg.virtual_root = trim_end(value, '/'); 127 ctx.cfg.virtual_root = trim_end(value, '/');
128 if (!ctx.cfg.virtual_root && (!strcmp(value, "/"))) 128 if (!ctx.cfg.virtual_root && (!strcmp(value, "/")))
129 ctx.cfg.virtual_root = ""; 129 ctx.cfg.virtual_root = "";
130 } else if (!strcmp(name, "nocache")) 130 } else if (!strcmp(name, "nocache"))
131 ctx.cfg.nocache = atoi(value); 131 ctx.cfg.nocache = atoi(value);
132 else if (!strcmp(name, "noplainemail")) 132 else if (!strcmp(name, "noplainemail"))
133 ctx.cfg.noplainemail = atoi(value); 133 ctx.cfg.noplainemail = atoi(value);
134 else if (!strcmp(name, "noheader")) 134 else if (!strcmp(name, "noheader"))
135 ctx.cfg.noheader = atoi(value); 135 ctx.cfg.noheader = atoi(value);
136 else if (!strcmp(name, "snapshots")) 136 else if (!strcmp(name, "snapshots"))
137 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); 137 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value);
138 else if (!strcmp(name, "enable-filter-overrides")) 138 else if (!strcmp(name, "enable-filter-overrides"))
139 ctx.cfg.enable_filter_overrides = atoi(value); 139 ctx.cfg.enable_filter_overrides = atoi(value);
140 else if (!strcmp(name, "enable-gitweb-owner")) 140 else if (!strcmp(name, "enable-gitweb-owner"))
141 ctx.cfg.enable_gitweb_owner = atoi(value); 141 ctx.cfg.enable_gitweb_owner = atoi(value);
142 else if (!strcmp(name, "enable-index-links")) 142 else if (!strcmp(name, "enable-index-links"))
143 ctx.cfg.enable_index_links = atoi(value); 143 ctx.cfg.enable_index_links = atoi(value);
144 else if (!strcmp(name, "enable-log-filecount")) 144 else if (!strcmp(name, "enable-log-filecount"))
145 ctx.cfg.enable_log_filecount = atoi(value); 145 ctx.cfg.enable_log_filecount = atoi(value);
146 else if (!strcmp(name, "enable-log-linecount")) 146 else if (!strcmp(name, "enable-log-linecount"))
147 ctx.cfg.enable_log_linecount = atoi(value); 147 ctx.cfg.enable_log_linecount = atoi(value);
148 else if (!strcmp(name, "enable-remote-branches")) 148 else if (!strcmp(name, "enable-remote-branches"))
149 ctx.cfg.enable_remote_branches = atoi(value); 149 ctx.cfg.enable_remote_branches = atoi(value);
150 else if (!strcmp(name, "enable-subject-links")) 150 else if (!strcmp(name, "enable-subject-links"))
151 ctx.cfg.enable_subject_links = atoi(value); 151 ctx.cfg.enable_subject_links = atoi(value);
152 else if (!strcmp(name, "enable-tree-linenumbers")) 152 else if (!strcmp(name, "enable-tree-linenumbers"))
153 ctx.cfg.enable_tree_linenumbers = atoi(value); 153 ctx.cfg.enable_tree_linenumbers = atoi(value);
154 else if (!strcmp(name, "max-stats")) 154 else if (!strcmp(name, "max-stats"))
155 ctx.cfg.max_stats = cgit_find_stats_period(value, NULL); 155 ctx.cfg.max_stats = cgit_find_stats_period(value, NULL);
156 else if (!strcmp(name, "cache-size")) 156 else if (!strcmp(name, "cache-size"))
157 ctx.cfg.cache_size = atoi(value); 157 ctx.cfg.cache_size = atoi(value);
158 else if (!strcmp(name, "cache-root")) 158 else if (!strcmp(name, "cache-root"))
159 ctx.cfg.cache_root = xstrdup(expand_macros(value)); 159 ctx.cfg.cache_root = xstrdup(expand_macros(value));
160 else if (!strcmp(name, "cache-root-ttl")) 160 else if (!strcmp(name, "cache-root-ttl"))
161 ctx.cfg.cache_root_ttl = atoi(value); 161 ctx.cfg.cache_root_ttl = atoi(value);
162 else if (!strcmp(name, "cache-repo-ttl")) 162 else if (!strcmp(name, "cache-repo-ttl"))
163 ctx.cfg.cache_repo_ttl = atoi(value); 163 ctx.cfg.cache_repo_ttl = atoi(value);
164 else if (!strcmp(name, "cache-scanrc-ttl")) 164 else if (!strcmp(name, "cache-scanrc-ttl"))
165 ctx.cfg.cache_scanrc_ttl = atoi(value); 165 ctx.cfg.cache_scanrc_ttl = atoi(value);
166 else if (!strcmp(name, "cache-static-ttl")) 166 else if (!strcmp(name, "cache-static-ttl"))
167 ctx.cfg.cache_static_ttl = atoi(value); 167 ctx.cfg.cache_static_ttl = atoi(value);
168 else if (!strcmp(name, "cache-dynamic-ttl")) 168 else if (!strcmp(name, "cache-dynamic-ttl"))
169 ctx.cfg.cache_dynamic_ttl = atoi(value); 169 ctx.cfg.cache_dynamic_ttl = atoi(value);
170 else if (!strcmp(name, "about-filter")) 170 else if (!strcmp(name, "about-filter"))
171 ctx.cfg.about_filter = new_filter(value, 0); 171 ctx.cfg.about_filter = new_filter(value, 0);
172 else if (!strcmp(name, "commit-filter")) 172 else if (!strcmp(name, "commit-filter"))
173 ctx.cfg.commit_filter = new_filter(value, 0); 173 ctx.cfg.commit_filter = new_filter(value, 0);
174 else if (!strcmp(name, "embedded")) 174 else if (!strcmp(name, "embedded"))
175 ctx.cfg.embedded = atoi(value); 175 ctx.cfg.embedded = atoi(value);
176 else if (!strcmp(name, "max-atom-items")) 176 else if (!strcmp(name, "max-atom-items"))
177 ctx.cfg.max_atom_items = atoi(value); 177 ctx.cfg.max_atom_items = atoi(value);
178 else if (!strcmp(name, "max-message-length")) 178 else if (!strcmp(name, "max-message-length"))
179 ctx.cfg.max_msg_len = atoi(value); 179 ctx.cfg.max_msg_len = atoi(value);
180 else if (!strcmp(name, "max-repodesc-length")) 180 else if (!strcmp(name, "max-repodesc-length"))
181 ctx.cfg.max_repodesc_len = atoi(value); 181 ctx.cfg.max_repodesc_len = atoi(value);
182 else if (!strcmp(name, "max-blob-size")) 182 else if (!strcmp(name, "max-blob-size"))
183 ctx.cfg.max_blob_size = atoi(value); 183 ctx.cfg.max_blob_size = atoi(value);
184 else if (!strcmp(name, "max-repo-count")) 184 else if (!strcmp(name, "max-repo-count"))
185 ctx.cfg.max_repo_count = atoi(value); 185 ctx.cfg.max_repo_count = atoi(value);
186 else if (!strcmp(name, "max-commit-count")) 186 else if (!strcmp(name, "max-commit-count"))
187 ctx.cfg.max_commit_count = atoi(value); 187 ctx.cfg.max_commit_count = atoi(value);
188 else if (!strcmp(name, "project-list")) 188 else if (!strcmp(name, "project-list"))
189 ctx.cfg.project_list = xstrdup(expand_macros(value)); 189 ctx.cfg.project_list = xstrdup(expand_macros(value));
190 else if (!strcmp(name, "scan-path")) 190 else if (!strcmp(name, "scan-path"))
191 if (!ctx.cfg.nocache && ctx.cfg.cache_size) 191 if (!ctx.cfg.nocache && ctx.cfg.cache_size)
192 process_cached_repolist(expand_macros(value)); 192 process_cached_repolist(expand_macros(value));
193 else if (ctx.cfg.project_list) 193 else if (ctx.cfg.project_list)
194 scan_projects(expand_macros(value), 194 scan_projects(expand_macros(value),
195 ctx.cfg.project_list, repo_config); 195 ctx.cfg.project_list, repo_config);
196 else 196 else
197 scan_tree(expand_macros(value), repo_config); 197 scan_tree(expand_macros(value), repo_config);
198 else if (!strcmp(name, "scan-hidden-path"))
199 ctx.cfg.scan_hidden_path = atoi(value);
198 else if (!strcmp(name, "section-from-path")) 200 else if (!strcmp(name, "section-from-path"))
199 ctx.cfg.section_from_path = atoi(value); 201 ctx.cfg.section_from_path = atoi(value);
200 else if (!strcmp(name, "source-filter")) 202 else if (!strcmp(name, "source-filter"))
201 ctx.cfg.source_filter = new_filter(value, 1); 203 ctx.cfg.source_filter = new_filter(value, 1);
202 else if (!strcmp(name, "summary-log")) 204 else if (!strcmp(name, "summary-log"))
203 ctx.cfg.summary_log = atoi(value); 205 ctx.cfg.summary_log = atoi(value);
204 else if (!strcmp(name, "summary-branches")) 206 else if (!strcmp(name, "summary-branches"))
205 ctx.cfg.summary_branches = atoi(value); 207 ctx.cfg.summary_branches = atoi(value);
206 else if (!strcmp(name, "summary-tags")) 208 else if (!strcmp(name, "summary-tags"))
207 ctx.cfg.summary_tags = atoi(value); 209 ctx.cfg.summary_tags = atoi(value);
208 else if (!strcmp(name, "side-by-side-diffs")) 210 else if (!strcmp(name, "side-by-side-diffs"))
209 ctx.cfg.ssdiff = atoi(value); 211 ctx.cfg.ssdiff = atoi(value);
210 else if (!strcmp(name, "agefile")) 212 else if (!strcmp(name, "agefile"))
211 ctx.cfg.agefile = xstrdup(value); 213 ctx.cfg.agefile = xstrdup(value);
212 else if (!strcmp(name, "renamelimit")) 214 else if (!strcmp(name, "renamelimit"))
213 ctx.cfg.renamelimit = atoi(value); 215 ctx.cfg.renamelimit = atoi(value);
214 else if (!strcmp(name, "remove-suffix")) 216 else if (!strcmp(name, "remove-suffix"))
215 ctx.cfg.remove_suffix = atoi(value); 217 ctx.cfg.remove_suffix = atoi(value);
216 else if (!strcmp(name, "robots")) 218 else if (!strcmp(name, "robots"))
217 ctx.cfg.robots = xstrdup(value); 219 ctx.cfg.robots = xstrdup(value);
218 else if (!strcmp(name, "clone-prefix")) 220 else if (!strcmp(name, "clone-prefix"))
219 ctx.cfg.clone_prefix = xstrdup(value); 221 ctx.cfg.clone_prefix = xstrdup(value);
220 else if (!strcmp(name, "local-time")) 222 else if (!strcmp(name, "local-time"))
221 ctx.cfg.local_time = atoi(value); 223 ctx.cfg.local_time = atoi(value);
222 else if (!prefixcmp(name, "mimetype.")) 224 else if (!prefixcmp(name, "mimetype."))
223 add_mimetype(name + 9, value); 225 add_mimetype(name + 9, value);
224 else if (!strcmp(name, "include")) 226 else if (!strcmp(name, "include"))
225 parse_configfile(expand_macros(value), config_cb); 227 parse_configfile(expand_macros(value), config_cb);
226} 228}
227 229
228static void querystring_cb(const char *name, const char *value) 230static void querystring_cb(const char *name, const char *value)
229{ 231{
230 if (!value) 232 if (!value)
231 value = ""; 233 value = "";
232 234
233 if (!strcmp(name,"r")) { 235 if (!strcmp(name,"r")) {
234 ctx.qry.repo = xstrdup(value); 236 ctx.qry.repo = xstrdup(value);
235 ctx.repo = cgit_get_repoinfo(value); 237 ctx.repo = cgit_get_repoinfo(value);
236 } else if (!strcmp(name, "p")) { 238 } else if (!strcmp(name, "p")) {
237 ctx.qry.page = xstrdup(value); 239 ctx.qry.page = xstrdup(value);
238 } else if (!strcmp(name, "url")) { 240 } else if (!strcmp(name, "url")) {
239 if (*value == '/') 241 if (*value == '/')
240 value++; 242 value++;
241 ctx.qry.url = xstrdup(value); 243 ctx.qry.url = xstrdup(value);
242 cgit_parse_url(value); 244 cgit_parse_url(value);
243 } else if (!strcmp(name, "qt")) { 245 } else if (!strcmp(name, "qt")) {
244 ctx.qry.grep = xstrdup(value); 246 ctx.qry.grep = xstrdup(value);
245 } else if (!strcmp(name, "q")) { 247 } else if (!strcmp(name, "q")) {
246 ctx.qry.search = xstrdup(value); 248 ctx.qry.search = xstrdup(value);
247 } else if (!strcmp(name, "h")) { 249 } else if (!strcmp(name, "h")) {
248 ctx.qry.head = xstrdup(value); 250 ctx.qry.head = xstrdup(value);
249 ctx.qry.has_symref = 1; 251 ctx.qry.has_symref = 1;
250 } else if (!strcmp(name, "id")) { 252 } else if (!strcmp(name, "id")) {
251 ctx.qry.sha1 = xstrdup(value); 253 ctx.qry.sha1 = xstrdup(value);
252 ctx.qry.has_sha1 = 1; 254 ctx.qry.has_sha1 = 1;
253 } else if (!strcmp(name, "id2")) { 255 } else if (!strcmp(name, "id2")) {
254 ctx.qry.sha2 = xstrdup(value); 256 ctx.qry.sha2 = xstrdup(value);
255 ctx.qry.has_sha1 = 1; 257 ctx.qry.has_sha1 = 1;
256 } else if (!strcmp(name, "ofs")) { 258 } else if (!strcmp(name, "ofs")) {
257 ctx.qry.ofs = atoi(value); 259 ctx.qry.ofs = atoi(value);
258 } else if (!strcmp(name, "path")) { 260 } else if (!strcmp(name, "path")) {
259 ctx.qry.path = trim_end(value, '/'); 261 ctx.qry.path = trim_end(value, '/');
260 } else if (!strcmp(name, "name")) { 262 } else if (!strcmp(name, "name")) {
261 ctx.qry.name = xstrdup(value); 263 ctx.qry.name = xstrdup(value);
262 } else if (!strcmp(name, "mimetype")) { 264 } else if (!strcmp(name, "mimetype")) {
263 ctx.qry.mimetype = xstrdup(value); 265 ctx.qry.mimetype = xstrdup(value);
264 } else if (!strcmp(name, "s")){ 266 } else if (!strcmp(name, "s")){
265 ctx.qry.sort = xstrdup(value); 267 ctx.qry.sort = xstrdup(value);
266 } else if (!strcmp(name, "showmsg")) { 268 } else if (!strcmp(name, "showmsg")) {
267 ctx.qry.showmsg = atoi(value); 269 ctx.qry.showmsg = atoi(value);
268 } else if (!strcmp(name, "period")) { 270 } else if (!strcmp(name, "period")) {
269 ctx.qry.period = xstrdup(value); 271 ctx.qry.period = xstrdup(value);
270 } else if (!strcmp(name, "ss")) { 272 } else if (!strcmp(name, "ss")) {
271 ctx.qry.ssdiff = atoi(value); 273 ctx.qry.ssdiff = atoi(value);
272 } else if (!strcmp(name, "all")) { 274 } else if (!strcmp(name, "all")) {
273 ctx.qry.show_all = atoi(value); 275 ctx.qry.show_all = atoi(value);
274 } else if (!strcmp(name, "context")) { 276 } else if (!strcmp(name, "context")) {
275 ctx.qry.context = atoi(value); 277 ctx.qry.context = atoi(value);
276 } else if (!strcmp(name, "ignorews")) { 278 } else if (!strcmp(name, "ignorews")) {
277 ctx.qry.ignorews = atoi(value); 279 ctx.qry.ignorews = atoi(value);
278 } 280 }
279} 281}
280 282
281char *xstrdupn(const char *str) 283char *xstrdupn(const char *str)
282{ 284{
283 return (str ? xstrdup(str) : NULL); 285 return (str ? xstrdup(str) : NULL);
284} 286}
285 287
286static void prepare_context(struct cgit_context *ctx) 288static void prepare_context(struct cgit_context *ctx)
287{ 289{
288 memset(ctx, 0, sizeof(*ctx)); 290 memset(ctx, 0, sizeof(*ctx));
289 ctx->cfg.agefile = "info/web/last-modified"; 291 ctx->cfg.agefile = "info/web/last-modified";
290 ctx->cfg.nocache = 0; 292 ctx->cfg.nocache = 0;
291 ctx->cfg.cache_size = 0; 293 ctx->cfg.cache_size = 0;
292 ctx->cfg.cache_dynamic_ttl = 5; 294 ctx->cfg.cache_dynamic_ttl = 5;
293 ctx->cfg.cache_max_create_time = 5; 295 ctx->cfg.cache_max_create_time = 5;
294 ctx->cfg.cache_repo_ttl = 5; 296 ctx->cfg.cache_repo_ttl = 5;
295 ctx->cfg.cache_root = CGIT_CACHE_ROOT; 297 ctx->cfg.cache_root = CGIT_CACHE_ROOT;
296 ctx->cfg.cache_root_ttl = 5; 298 ctx->cfg.cache_root_ttl = 5;
297 ctx->cfg.cache_scanrc_ttl = 15; 299 ctx->cfg.cache_scanrc_ttl = 15;
298 ctx->cfg.cache_static_ttl = -1; 300 ctx->cfg.cache_static_ttl = -1;
299 ctx->cfg.css = "/cgit.css"; 301 ctx->cfg.css = "/cgit.css";
300 ctx->cfg.logo = "/cgit.png"; 302 ctx->cfg.logo = "/cgit.png";
301 ctx->cfg.local_time = 0; 303 ctx->cfg.local_time = 0;
302 ctx->cfg.enable_gitweb_owner = 1; 304 ctx->cfg.enable_gitweb_owner = 1;
303 ctx->cfg.enable_tree_linenumbers = 1; 305 ctx->cfg.enable_tree_linenumbers = 1;
304 ctx->cfg.max_repo_count = 50; 306 ctx->cfg.max_repo_count = 50;
305 ctx->cfg.max_commit_count = 50; 307 ctx->cfg.max_commit_count = 50;
306 ctx->cfg.max_lock_attempts = 5; 308 ctx->cfg.max_lock_attempts = 5;
307 ctx->cfg.max_msg_len = 80; 309 ctx->cfg.max_msg_len = 80;
308 ctx->cfg.max_repodesc_len = 80; 310 ctx->cfg.max_repodesc_len = 80;
309 ctx->cfg.max_blob_size = 0; 311 ctx->cfg.max_blob_size = 0;
310 ctx->cfg.max_stats = 0; 312 ctx->cfg.max_stats = 0;
311 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; 313 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
312 ctx->cfg.project_list = NULL; 314 ctx->cfg.project_list = NULL;
313 ctx->cfg.renamelimit = -1; 315 ctx->cfg.renamelimit = -1;
314 ctx->cfg.remove_suffix = 0; 316 ctx->cfg.remove_suffix = 0;
315 ctx->cfg.robots = "index, nofollow"; 317 ctx->cfg.robots = "index, nofollow";
316 ctx->cfg.root_title = "Git repository browser"; 318 ctx->cfg.root_title = "Git repository browser";
317 ctx->cfg.root_desc = "a fast webinterface for the git dscm"; 319 ctx->cfg.root_desc = "a fast webinterface for the git dscm";
320 ctx->cfg.scan_hidden_path = 0;
318 ctx->cfg.script_name = CGIT_SCRIPT_NAME; 321 ctx->cfg.script_name = CGIT_SCRIPT_NAME;
319 ctx->cfg.section = ""; 322 ctx->cfg.section = "";
320 ctx->cfg.summary_branches = 10; 323 ctx->cfg.summary_branches = 10;
321 ctx->cfg.summary_log = 10; 324 ctx->cfg.summary_log = 10;
322 ctx->cfg.summary_tags = 10; 325 ctx->cfg.summary_tags = 10;
323 ctx->cfg.max_atom_items = 10; 326 ctx->cfg.max_atom_items = 10;
324 ctx->cfg.ssdiff = 0; 327 ctx->cfg.ssdiff = 0;
325 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG")); 328 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG"));
326 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST")); 329 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST"));
327 ctx->env.https = xstrdupn(getenv("HTTPS")); 330 ctx->env.https = xstrdupn(getenv("HTTPS"));
328 ctx->env.no_http = xstrdupn(getenv("NO_HTTP")); 331 ctx->env.no_http = xstrdupn(getenv("NO_HTTP"));
329 ctx->env.path_info = xstrdupn(getenv("PATH_INFO")); 332 ctx->env.path_info = xstrdupn(getenv("PATH_INFO"));
330 ctx->env.query_string = xstrdupn(getenv("QUERY_STRING")); 333 ctx->env.query_string = xstrdupn(getenv("QUERY_STRING"));
331 ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD")); 334 ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD"));
332 ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME")); 335 ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME"));
333 ctx->env.server_name = xstrdupn(getenv("SERVER_NAME")); 336 ctx->env.server_name = xstrdupn(getenv("SERVER_NAME"));
334 ctx->env.server_port = xstrdupn(getenv("SERVER_PORT")); 337 ctx->env.server_port = xstrdupn(getenv("SERVER_PORT"));
335 ctx->page.mimetype = "text/html"; 338 ctx->page.mimetype = "text/html";
336 ctx->page.charset = PAGE_ENCODING; 339 ctx->page.charset = PAGE_ENCODING;
337 ctx->page.filename = NULL; 340 ctx->page.filename = NULL;
338 ctx->page.size = 0; 341 ctx->page.size = 0;
339 ctx->page.modified = time(NULL); 342 ctx->page.modified = time(NULL);
340 ctx->page.expires = ctx->page.modified; 343 ctx->page.expires = ctx->page.modified;
341 ctx->page.etag = NULL; 344 ctx->page.etag = NULL;
342 memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list)); 345 memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list));
343 if (ctx->env.script_name) 346 if (ctx->env.script_name)
344 ctx->cfg.script_name = ctx->env.script_name; 347 ctx->cfg.script_name = ctx->env.script_name;
345 if (ctx->env.query_string) 348 if (ctx->env.query_string)
346 ctx->qry.raw = ctx->env.query_string; 349 ctx->qry.raw = ctx->env.query_string;
347 if (!ctx->env.cgit_config) 350 if (!ctx->env.cgit_config)
348 ctx->env.cgit_config = CGIT_CONFIG; 351 ctx->env.cgit_config = CGIT_CONFIG;
349} 352}
350 353
351struct refmatch { 354struct refmatch {
352 char *req_ref; 355 char *req_ref;
353 char *first_ref; 356 char *first_ref;
354 int match; 357 int match;
355}; 358};
356 359
357int find_current_ref(const char *refname, const unsigned char *sha1, 360int find_current_ref(const char *refname, const unsigned char *sha1,
358 int flags, void *cb_data) 361 int flags, void *cb_data)
359{ 362{
360 struct refmatch *info; 363 struct refmatch *info;
361 364
362 info = (struct refmatch *)cb_data; 365 info = (struct refmatch *)cb_data;
363 if (!strcmp(refname, info->req_ref)) 366 if (!strcmp(refname, info->req_ref))
364 info->match = 1; 367 info->match = 1;
365 if (!info->first_ref) 368 if (!info->first_ref)
366 info->first_ref = xstrdup(refname); 369 info->first_ref = xstrdup(refname);
367 return info->match; 370 return info->match;
368} 371}
369 372
370char *find_default_branch(struct cgit_repo *repo) 373char *find_default_branch(struct cgit_repo *repo)
371{ 374{
372 struct refmatch info; 375 struct refmatch info;
373 char *ref; 376 char *ref;
374 377
375 info.req_ref = repo->defbranch; 378 info.req_ref = repo->defbranch;
376 info.first_ref = NULL; 379 info.first_ref = NULL;
377 info.match = 0; 380 info.match = 0;
378 for_each_branch_ref(find_current_ref, &info); 381 for_each_branch_ref(find_current_ref, &info);
379 if (info.match) 382 if (info.match)
380 ref = info.req_ref; 383 ref = info.req_ref;
381 else 384 else
382 ref = info.first_ref; 385 ref = info.first_ref;
383 if (ref) 386 if (ref)
384 ref = xstrdup(ref); 387 ref = xstrdup(ref);
385 return ref; 388 return ref;
386} 389}
387 390
388static int prepare_repo_cmd(struct cgit_context *ctx) 391static int prepare_repo_cmd(struct cgit_context *ctx)
389{ 392{
390 char *tmp; 393 char *tmp;
391 unsigned char sha1[20]; 394 unsigned char sha1[20];
392 int nongit = 0; 395 int nongit = 0;
393 396
394 setenv("GIT_DIR", ctx->repo->path, 1); 397 setenv("GIT_DIR", ctx->repo->path, 1);
395 setup_git_directory_gently(&nongit); 398 setup_git_directory_gently(&nongit);
396 if (nongit) { 399 if (nongit) {
397 ctx->page.title = fmt("%s - %s", ctx->cfg.root_title, 400 ctx->page.title = fmt("%s - %s", ctx->cfg.root_title,
398 "config error"); 401 "config error");
399 tmp = fmt("Not a git repository: '%s'", ctx->repo->path); 402 tmp = fmt("Not a git repository: '%s'", ctx->repo->path);
400 ctx->repo = NULL; 403 ctx->repo = NULL;
401 cgit_print_http_headers(ctx); 404 cgit_print_http_headers(ctx);
402 cgit_print_docstart(ctx); 405 cgit_print_docstart(ctx);
403 cgit_print_pageheader(ctx); 406 cgit_print_pageheader(ctx);
404 cgit_print_error(tmp); 407 cgit_print_error(tmp);
405 cgit_print_docend(); 408 cgit_print_docend();
406 return 1; 409 return 1;
407 } 410 }
408 ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc); 411 ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc);
409 412
410 if (!ctx->qry.head) { 413 if (!ctx->qry.head) {
411 ctx->qry.nohead = 1; 414 ctx->qry.nohead = 1;
412 ctx->qry.head = find_default_branch(ctx->repo); 415 ctx->qry.head = find_default_branch(ctx->repo);
413 ctx->repo->defbranch = ctx->qry.head; 416 ctx->repo->defbranch = ctx->qry.head;
diff --git a/cgit.h b/cgit.h
index f5f68ac..ad94905 100644
--- a/cgit.h
+++ b/cgit.h
@@ -114,192 +114,193 @@ struct taginfo {
114struct refinfo { 114struct refinfo {
115 const char *refname; 115 const char *refname;
116 struct object *object; 116 struct object *object;
117 union { 117 union {
118 struct taginfo *tag; 118 struct taginfo *tag;
119 struct commitinfo *commit; 119 struct commitinfo *commit;
120 }; 120 };
121}; 121};
122 122
123struct reflist { 123struct reflist {
124 struct refinfo **refs; 124 struct refinfo **refs;
125 int alloc; 125 int alloc;
126 int count; 126 int count;
127}; 127};
128 128
129struct cgit_query { 129struct cgit_query {
130 int has_symref; 130 int has_symref;
131 int has_sha1; 131 int has_sha1;
132 char *raw; 132 char *raw;
133 char *repo; 133 char *repo;
134 char *page; 134 char *page;
135 char *search; 135 char *search;
136 char *grep; 136 char *grep;
137 char *head; 137 char *head;
138 char *sha1; 138 char *sha1;
139 char *sha2; 139 char *sha2;
140 char *path; 140 char *path;
141 char *name; 141 char *name;
142 char *mimetype; 142 char *mimetype;
143 char *url; 143 char *url;
144 char *period; 144 char *period;
145 int ofs; 145 int ofs;
146 int nohead; 146 int nohead;
147 char *sort; 147 char *sort;
148 int showmsg; 148 int showmsg;
149 int ssdiff; 149 int ssdiff;
150 int show_all; 150 int show_all;
151 int context; 151 int context;
152 int ignorews; 152 int ignorews;
153 char *vpath; 153 char *vpath;
154}; 154};
155 155
156struct cgit_config { 156struct cgit_config {
157 char *agefile; 157 char *agefile;
158 char *cache_root; 158 char *cache_root;
159 char *clone_prefix; 159 char *clone_prefix;
160 char *css; 160 char *css;
161 char *favicon; 161 char *favicon;
162 char *footer; 162 char *footer;
163 char *head_include; 163 char *head_include;
164 char *header; 164 char *header;
165 char *index_header; 165 char *index_header;
166 char *index_info; 166 char *index_info;
167 char *logo; 167 char *logo;
168 char *logo_link; 168 char *logo_link;
169 char *module_link; 169 char *module_link;
170 char *project_list; 170 char *project_list;
171 char *readme; 171 char *readme;
172 char *robots; 172 char *robots;
173 char *root_title; 173 char *root_title;
174 char *root_desc; 174 char *root_desc;
175 char *root_readme; 175 char *root_readme;
176 char *script_name; 176 char *script_name;
177 char *section; 177 char *section;
178 char *virtual_root; 178 char *virtual_root;
179 char *strict_export; 179 char *strict_export;
180 int cache_size; 180 int cache_size;
181 int cache_dynamic_ttl; 181 int cache_dynamic_ttl;
182 int cache_max_create_time; 182 int cache_max_create_time;
183 int cache_repo_ttl; 183 int cache_repo_ttl;
184 int cache_root_ttl; 184 int cache_root_ttl;
185 int cache_scanrc_ttl; 185 int cache_scanrc_ttl;
186 int cache_static_ttl; 186 int cache_static_ttl;
187 int embedded; 187 int embedded;
188 int enable_filter_overrides; 188 int enable_filter_overrides;
189 int enable_gitweb_owner; 189 int enable_gitweb_owner;
190 int enable_index_links; 190 int enable_index_links;
191 int enable_log_filecount; 191 int enable_log_filecount;
192 int enable_log_linecount; 192 int enable_log_linecount;
193 int enable_remote_branches; 193 int enable_remote_branches;
194 int enable_subject_links; 194 int enable_subject_links;
195 int enable_tree_linenumbers; 195 int enable_tree_linenumbers;
196 int local_time; 196 int local_time;
197 int max_atom_items; 197 int max_atom_items;
198 int max_repo_count; 198 int max_repo_count;
199 int max_commit_count; 199 int max_commit_count;
200 int max_lock_attempts; 200 int max_lock_attempts;
201 int max_msg_len; 201 int max_msg_len;
202 int max_repodesc_len; 202 int max_repodesc_len;
203 int max_blob_size; 203 int max_blob_size;
204 int max_stats; 204 int max_stats;
205 int nocache; 205 int nocache;
206 int noplainemail; 206 int noplainemail;
207 int noheader; 207 int noheader;
208 int renamelimit; 208 int renamelimit;
209 int remove_suffix; 209 int remove_suffix;
210 int scan_hidden_path;
210 int section_from_path; 211 int section_from_path;
211 int snapshots; 212 int snapshots;
212 int summary_branches; 213 int summary_branches;
213 int summary_log; 214 int summary_log;
214 int summary_tags; 215 int summary_tags;
215 int ssdiff; 216 int ssdiff;
216 struct string_list mimetypes; 217 struct string_list mimetypes;
217 struct cgit_filter *about_filter; 218 struct cgit_filter *about_filter;
218 struct cgit_filter *commit_filter; 219 struct cgit_filter *commit_filter;
219 struct cgit_filter *source_filter; 220 struct cgit_filter *source_filter;
220}; 221};
221 222
222struct cgit_page { 223struct cgit_page {
223 time_t modified; 224 time_t modified;
224 time_t expires; 225 time_t expires;
225 size_t size; 226 size_t size;
226 char *mimetype; 227 char *mimetype;
227 char *charset; 228 char *charset;
228 char *filename; 229 char *filename;
229 char *etag; 230 char *etag;
230 char *title; 231 char *title;
231 int status; 232 int status;
232 char *statusmsg; 233 char *statusmsg;
233}; 234};
234 235
235struct cgit_environment { 236struct cgit_environment {
236 char *cgit_config; 237 char *cgit_config;
237 char *http_host; 238 char *http_host;
238 char *https; 239 char *https;
239 char *no_http; 240 char *no_http;
240 char *path_info; 241 char *path_info;
241 char *query_string; 242 char *query_string;
242 char *request_method; 243 char *request_method;
243 char *script_name; 244 char *script_name;
244 char *server_name; 245 char *server_name;
245 char *server_port; 246 char *server_port;
246}; 247};
247 248
248struct cgit_context { 249struct cgit_context {
249 struct cgit_environment env; 250 struct cgit_environment env;
250 struct cgit_query qry; 251 struct cgit_query qry;
251 struct cgit_config cfg; 252 struct cgit_config cfg;
252 struct cgit_repo *repo; 253 struct cgit_repo *repo;
253 struct cgit_page page; 254 struct cgit_page page;
254}; 255};
255 256
256struct cgit_snapshot_format { 257struct cgit_snapshot_format {
257 const char *suffix; 258 const char *suffix;
258 const char *mimetype; 259 const char *mimetype;
259 write_archive_fn_t write_func; 260 write_archive_fn_t write_func;
260 int bit; 261 int bit;
261}; 262};
262 263
263extern const char *cgit_version; 264extern const char *cgit_version;
264 265
265extern struct cgit_repolist cgit_repolist; 266extern struct cgit_repolist cgit_repolist;
266extern struct cgit_context ctx; 267extern struct cgit_context ctx;
267extern const struct cgit_snapshot_format cgit_snapshot_formats[]; 268extern const struct cgit_snapshot_format cgit_snapshot_formats[];
268 269
269extern struct cgit_repo *cgit_add_repo(const char *url); 270extern struct cgit_repo *cgit_add_repo(const char *url);
270extern struct cgit_repo *cgit_get_repoinfo(const char *url); 271extern struct cgit_repo *cgit_get_repoinfo(const char *url);
271extern void cgit_repo_config_cb(const char *name, const char *value); 272extern void cgit_repo_config_cb(const char *name, const char *value);
272 273
273extern int chk_zero(int result, char *msg); 274extern int chk_zero(int result, char *msg);
274extern int chk_positive(int result, char *msg); 275extern int chk_positive(int result, char *msg);
275extern int chk_non_negative(int result, char *msg); 276extern int chk_non_negative(int result, char *msg);
276 277
277extern char *trim_end(const char *str, char c); 278extern char *trim_end(const char *str, char c);
278extern char *strlpart(char *txt, int maxlen); 279extern char *strlpart(char *txt, int maxlen);
279extern char *strrpart(char *txt, int maxlen); 280extern char *strrpart(char *txt, int maxlen);
280 281
281extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); 282extern void cgit_add_ref(struct reflist *list, struct refinfo *ref);
282extern int cgit_refs_cb(const char *refname, const unsigned char *sha1, 283extern int cgit_refs_cb(const char *refname, const unsigned char *sha1,
283 int flags, void *cb_data); 284 int flags, void *cb_data);
284 285
285extern void *cgit_free_commitinfo(struct commitinfo *info); 286extern void *cgit_free_commitinfo(struct commitinfo *info);
286 287
287extern int cgit_diff_files(const unsigned char *old_sha1, 288extern int cgit_diff_files(const unsigned char *old_sha1,
288 const unsigned char *new_sha1, 289 const unsigned char *new_sha1,
289 unsigned long *old_size, unsigned long *new_size, 290 unsigned long *old_size, unsigned long *new_size,
290 int *binary, int context, int ignorews, 291 int *binary, int context, int ignorews,
291 linediff_fn fn); 292 linediff_fn fn);
292 293
293extern void cgit_diff_tree(const unsigned char *old_sha1, 294extern void cgit_diff_tree(const unsigned char *old_sha1,
294 const unsigned char *new_sha1, 295 const unsigned char *new_sha1,
295 filepair_fn fn, const char *prefix, int ignorews); 296 filepair_fn fn, const char *prefix, int ignorews);
296 297
297extern void cgit_diff_commit(struct commit *commit, filepair_fn fn, 298extern void cgit_diff_commit(struct commit *commit, filepair_fn fn,
298 const char *prefix); 299 const char *prefix);
299 300
300__attribute__((format (printf,1,2))) 301__attribute__((format (printf,1,2)))
301extern char *fmt(const char *format,...); 302extern char *fmt(const char *format,...);
302 303
303extern struct commitinfo *cgit_parse_commit(struct commit *commit); 304extern struct commitinfo *cgit_parse_commit(struct commit *commit);
304extern struct taginfo *cgit_parse_tag(struct tag *tag); 305extern struct taginfo *cgit_parse_tag(struct tag *tag);
305extern void cgit_parse_url(const char *url); 306extern void cgit_parse_url(const char *url);
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index 8e51ca5..1dc3cce 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -176,192 +176,200 @@ logo-link::
176 Url loaded when clicking on the cgit logo image. If unspecified the 176 Url loaded when clicking on the cgit logo image. If unspecified the
177 calculated url of the repository index page will be used. Default 177 calculated url of the repository index page will be used. Default
178 value: none. 178 value: none.
179 179
180max-atom-items:: 180max-atom-items::
181 Specifies the number of items to display in atom feeds view. Default 181 Specifies the number of items to display in atom feeds view. Default
182 value: "10". 182 value: "10".
183 183
184max-commit-count:: 184max-commit-count::
185 Specifies the number of entries to list per page in "log" view. Default 185 Specifies the number of entries to list per page in "log" view. Default
186 value: "50". 186 value: "50".
187 187
188max-message-length:: 188max-message-length::
189 Specifies the maximum number of commit message characters to display in 189 Specifies the maximum number of commit message characters to display in
190 "log" view. Default value: "80". 190 "log" view. Default value: "80".
191 191
192max-repo-count:: 192max-repo-count::
193 Specifies the number of entries to list per page on therepository 193 Specifies the number of entries to list per page on therepository
194 index page. Default value: "50". 194 index page. Default value: "50".
195 195
196max-repodesc-length:: 196max-repodesc-length::
197 Specifies the maximum number of repo description characters to display 197 Specifies the maximum number of repo description characters to display
198 on the repository index page. Default value: "80". 198 on the repository index page. Default value: "80".
199 199
200max-blob-size:: 200max-blob-size::
201 Specifies the maximum size of a blob to display HTML for in KBytes. 201 Specifies the maximum size of a blob to display HTML for in KBytes.
202 Default value: "0" (limit disabled). 202 Default value: "0" (limit disabled).
203 203
204max-stats:: 204max-stats::
205 Set the default maximum statistics period. Valid values are "week", 205 Set the default maximum statistics period. Valid values are "week",
206 "month", "quarter" and "year". If unspecified, statistics are 206 "month", "quarter" and "year". If unspecified, statistics are
207 disabled. Default value: none. See also: "repo.max-stats". 207 disabled. Default value: none. See also: "repo.max-stats".
208 208
209mimetype.<ext>:: 209mimetype.<ext>::
210 Set the mimetype for the specified filename extension. This is used 210 Set the mimetype for the specified filename extension. This is used
211 by the `plain` command when returning blob content. 211 by the `plain` command when returning blob content.
212 212
213module-link:: 213module-link::
214 Text which will be used as the formatstring for a hyperlink when a 214 Text which will be used as the formatstring for a hyperlink when a
215 submodule is printed in a directory listing. The arguments for the 215 submodule is printed in a directory listing. The arguments for the
216 formatstring are the path and SHA1 of the submodule commit. Default 216 formatstring are the path and SHA1 of the submodule commit. Default
217 value: "./?repo=%s&page=commit&id=%s" 217 value: "./?repo=%s&page=commit&id=%s"
218 218
219nocache:: 219nocache::
220 If set to the value "1" caching will be disabled. This settings is 220 If set to the value "1" caching will be disabled. This settings is
221 deprecated, and will not be honored starting with cgit-1.0. Default 221 deprecated, and will not be honored starting with cgit-1.0. Default
222 value: "0". 222 value: "0".
223 223
224noplainemail:: 224noplainemail::
225 If set to "1" showing full author email adresses will be disabled. 225 If set to "1" showing full author email adresses will be disabled.
226 Default value: "0". 226 Default value: "0".
227 227
228noheader:: 228noheader::
229 Flag which, when set to "1", will make cgit omit the standard header 229 Flag which, when set to "1", will make cgit omit the standard header
230 on all pages. Default value: none. See also: "embedded". 230 on all pages. Default value: none. See also: "embedded".
231 231
232project-list:: 232project-list::
233 A list of subdirectories inside of scan-path, relative to it, that 233 A list of subdirectories inside of scan-path, relative to it, that
234 should loaded as git repositories. This must be defined prior to 234 should loaded as git repositories. This must be defined prior to
235 scan-path. Default value: none. See also: scan-path. 235 scan-path. Default value: none. See also: scan-path.
236 236
237readme:: 237readme::
238 Text which will be used as default value for "repo.readme". Default 238 Text which will be used as default value for "repo.readme". Default
239 value: none. 239 value: none.
240 240
241remove-suffix:: 241remove-suffix::
242 If set to "1" and scan-path is enabled, if any repositories are found 242 If set to "1" and scan-path is enabled, if any repositories are found
243 with a suffix of ".git", this suffix will be removed for the url and 243 with a suffix of ".git", this suffix will be removed for the url and
244 name. Default value: "0". See also: scan-path. 244 name. Default value: "0". See also: scan-path.
245 245
246renamelimit:: 246renamelimit::
247 Maximum number of files to consider when detecting renames. The value 247 Maximum number of files to consider when detecting renames. The value
248 "-1" uses the compiletime value in git (for further info, look at 248 "-1" uses the compiletime value in git (for further info, look at
249 `man git-diff`). Default value: "-1". 249 `man git-diff`). Default value: "-1".
250 250
251repo.group:: 251repo.group::
252 Legacy alias for "section". This option is deprecated and will not be 252 Legacy alias for "section". This option is deprecated and will not be
253 supported in cgit-1.0. 253 supported in cgit-1.0.
254 254
255robots:: 255robots::
256 Text used as content for the "robots" meta-tag. Default value: 256 Text used as content for the "robots" meta-tag. Default value:
257 "index, nofollow". 257 "index, nofollow".
258 258
259root-desc:: 259root-desc::
260 Text printed below the heading on the repository index page. Default 260 Text printed below the heading on the repository index page. Default
261 value: "a fast webinterface for the git dscm". 261 value: "a fast webinterface for the git dscm".
262 262
263root-readme:: 263root-readme::
264 The content of the file specified with this option will be included 264 The content of the file specified with this option will be included
265 verbatim below the "about" link on the repository index page. Default 265 verbatim below the "about" link on the repository index page. Default
266 value: none. 266 value: none.
267 267
268root-title:: 268root-title::
269 Text printed as heading on the repository index page. Default value: 269 Text printed as heading on the repository index page. Default value:
270 "Git Repository Browser". 270 "Git Repository Browser".
271 271
272scan-hidden-path::
273 If set to "1" and scan-path is enabled, scan-path will recurse into
274 directories whose name starts with a period ('.'). Otherwise,
275 scan-path will stay away from such directories (considered as
276 "hidden"). Note that this does not apply to the ".git" directory in
277 non-bare repos. This must be defined prior to scan-path.
278 Default value: 0. See also: scan-path.
279
272scan-path:: 280scan-path::
273 A path which will be scanned for repositories. If caching is enabled, 281 A path which will be scanned for repositories. If caching is enabled,
274 the result will be cached as a cgitrc include-file in the cache 282 the result will be cached as a cgitrc include-file in the cache
275 directory. If project-list has been defined prior to scan-path, 283 directory. If project-list has been defined prior to scan-path,
276 scan-path loads only the directories listed in the file pointed to by 284 scan-path loads only the directories listed in the file pointed to by
277 project-list. Default value: none. See also: cache-scanrc-ttl, 285 project-list. Default value: none. See also: cache-scanrc-ttl,
278 project-list. 286 project-list.
279 287
280section:: 288section::
281 The name of the current repository section - all repositories defined 289 The name of the current repository section - all repositories defined
282 after this option will inherit the current section name. Default value: 290 after this option will inherit the current section name. Default value:
283 none. 291 none.
284 292
285section-from-path:: 293section-from-path::
286 A number which, if specified before scan-path, specifies how many 294 A number which, if specified before scan-path, specifies how many
287 path elements from each repo path to use as a default section name. 295 path elements from each repo path to use as a default section name.
288 If negative, cgit will discard the specified number of path elements 296 If negative, cgit will discard the specified number of path elements
289 above the repo directory. Default value: 0. 297 above the repo directory. Default value: 0.
290 298
291side-by-side-diffs:: 299side-by-side-diffs::
292 If set to "1" shows side-by-side diffs instead of unidiffs per 300 If set to "1" shows side-by-side diffs instead of unidiffs per
293 default. Default value: "0". 301 default. Default value: "0".
294 302
295snapshots:: 303snapshots::
296 Text which specifies the default set of snapshot formats generated by 304 Text which specifies the default set of snapshot formats generated by
297 cgit. The value is a space-separated list of zero or more of the 305 cgit. The value is a space-separated list of zero or more of the
298 values "tar", "tar.gz", "tar.bz2" and "zip". Default value: none. 306 values "tar", "tar.gz", "tar.bz2" and "zip". Default value: none.
299 307
300source-filter:: 308source-filter::
301 Specifies a command which will be invoked to format plaintext blobs 309 Specifies a command which will be invoked to format plaintext blobs
302 in the tree view. The command will get the blob content on its STDIN 310 in the tree view. The command will get the blob content on its STDIN
303 and the name of the blob as its only command line argument. The STDOUT 311 and the name of the blob as its only command line argument. The STDOUT
304 from the command will be included verbatim as the blob contents, i.e. 312 from the command will be included verbatim as the blob contents, i.e.
305 this can be used to implement e.g. syntax highlighting. Default value: 313 this can be used to implement e.g. syntax highlighting. Default value:
306 none. 314 none.
307 315
308summary-branches:: 316summary-branches::
309 Specifies the number of branches to display in the repository "summary" 317 Specifies the number of branches to display in the repository "summary"
310 view. Default value: "10". 318 view. Default value: "10".
311 319
312summary-log:: 320summary-log::
313 Specifies the number of log entries to display in the repository 321 Specifies the number of log entries to display in the repository
314 "summary" view. Default value: "10". 322 "summary" view. Default value: "10".
315 323
316summary-tags:: 324summary-tags::
317 Specifies the number of tags to display in the repository "summary" 325 Specifies the number of tags to display in the repository "summary"
318 view. Default value: "10". 326 view. Default value: "10".
319 327
320strict-export:: 328strict-export::
321 Filename which, if specified, needs to be present within the repository 329 Filename which, if specified, needs to be present within the repository
322 for cgit to allow access to that repository. This can be used to emulate 330 for cgit to allow access to that repository. This can be used to emulate
323 gitweb's EXPORT_OK and STRICT_EXPORT functionality and limit cgit's 331 gitweb's EXPORT_OK and STRICT_EXPORT functionality and limit cgit's
324 repositories to match those exported by git-daemon. This option MUST come 332 repositories to match those exported by git-daemon. This option MUST come
325 before 'scan-path'. 333 before 'scan-path'.
326 334
327virtual-root:: 335virtual-root::
328 Url which, if specified, will be used as root for all cgit links. It 336 Url which, if specified, will be used as root for all cgit links. It
329 will also cause cgit to generate 'virtual urls', i.e. urls like 337 will also cause cgit to generate 'virtual urls', i.e. urls like
330 '/cgit/tree/README' as opposed to '?r=cgit&p=tree&path=README'. Default 338 '/cgit/tree/README' as opposed to '?r=cgit&p=tree&path=README'. Default
331 value: none. 339 value: none.
332 NOTE: cgit has recently learned how to use PATH_INFO to achieve the 340 NOTE: cgit has recently learned how to use PATH_INFO to achieve the
333 same kind of virtual urls, so this option will probably be deprecated. 341 same kind of virtual urls, so this option will probably be deprecated.
334 342
335REPOSITORY SETTINGS 343REPOSITORY SETTINGS
336------------------- 344-------------------
337repo.about-filter:: 345repo.about-filter::
338 Override the default about-filter. Default value: none. See also: 346 Override the default about-filter. Default value: none. See also:
339 "enable-filter-overrides". 347 "enable-filter-overrides".
340 348
341repo.clone-url:: 349repo.clone-url::
342 A list of space-separated urls which can be used to clone this repo. 350 A list of space-separated urls which can be used to clone this repo.
343 Default value: none. 351 Default value: none.
344 352
345repo.commit-filter:: 353repo.commit-filter::
346 Override the default commit-filter. Default value: none. See also: 354 Override the default commit-filter. Default value: none. See also:
347 "enable-filter-overrides". 355 "enable-filter-overrides".
348 356
349repo.defbranch:: 357repo.defbranch::
350 The name of the default branch for this repository. If no such branch 358 The name of the default branch for this repository. If no such branch
351 exists in the repository, the first branch name (when sorted) is used 359 exists in the repository, the first branch name (when sorted) is used
352 as default instead. Default value: "master". 360 as default instead. Default value: "master".
353 361
354repo.desc:: 362repo.desc::
355 The value to show as repository description. Default value: none. 363 The value to show as repository description. Default value: none.
356 364
357repo.enable-log-filecount:: 365repo.enable-log-filecount::
358 A flag which can be used to disable the global setting 366 A flag which can be used to disable the global setting
359 `enable-log-filecount'. Default value: none. 367 `enable-log-filecount'. Default value: none.
360 368
361repo.enable-log-linecount:: 369repo.enable-log-linecount::
362 A flag which can be used to disable the global setting 370 A flag which can be used to disable the global setting
363 `enable-log-linecount'. Default value: none. 371 `enable-log-linecount'. Default value: none.
364 372
365repo.enable-remote-branches:: 373repo.enable-remote-branches::
366 Flag which, when set to "1", will make cgit display remote branches 374 Flag which, when set to "1", will make cgit display remote branches
367 in the summary and refs views. Default value: <enable-remote-branches>. 375 in the summary and refs views. Default value: <enable-remote-branches>.
diff --git a/scan-tree.c b/scan-tree.c
index eda8c67..627af1b 100644
--- a/scan-tree.c
+++ b/scan-tree.c
@@ -90,150 +90,152 @@ static void add_repo(const char *base, const char *path, repo_config_fn fn)
90 90
91 owner = NULL; 91 owner = NULL;
92 if (ctx.cfg.enable_gitweb_owner) 92 if (ctx.cfg.enable_gitweb_owner)
93 git_config_from_file(git_owner_config, fmt("%s/config", path), NULL); 93 git_config_from_file(git_owner_config, fmt("%s/config", path), NULL);
94 if (base == path) 94 if (base == path)
95 rel = xstrdup(fmt("%s", path)); 95 rel = xstrdup(fmt("%s", path));
96 else 96 else
97 rel = xstrdup(fmt("%s", path + strlen(base) + 1)); 97 rel = xstrdup(fmt("%s", path + strlen(base) + 1));
98 98
99 if (!strcmp(rel + strlen(rel) - 5, "/.git")) 99 if (!strcmp(rel + strlen(rel) - 5, "/.git"))
100 rel[strlen(rel) - 5] = '\0'; 100 rel[strlen(rel) - 5] = '\0';
101 101
102 repo = cgit_add_repo(rel); 102 repo = cgit_add_repo(rel);
103 if (ctx.cfg.remove_suffix) 103 if (ctx.cfg.remove_suffix)
104 if ((p = strrchr(repo->url, '.')) && !strcmp(p, ".git")) 104 if ((p = strrchr(repo->url, '.')) && !strcmp(p, ".git"))
105 *p = '\0'; 105 *p = '\0';
106 repo->name = repo->url; 106 repo->name = repo->url;
107 repo->path = xstrdup(path); 107 repo->path = xstrdup(path);
108 while (!owner) { 108 while (!owner) {
109 if ((pwd = getpwuid(st.st_uid)) == NULL) { 109 if ((pwd = getpwuid(st.st_uid)) == NULL) {
110 fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n", 110 fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n",
111 path, strerror(errno), errno); 111 path, strerror(errno), errno);
112 break; 112 break;
113 } 113 }
114 if (pwd->pw_gecos) 114 if (pwd->pw_gecos)
115 if ((p = strchr(pwd->pw_gecos, ','))) 115 if ((p = strchr(pwd->pw_gecos, ',')))
116 *p = '\0'; 116 *p = '\0';
117 owner = xstrdup(pwd->pw_gecos ? pwd->pw_gecos : pwd->pw_name); 117 owner = xstrdup(pwd->pw_gecos ? pwd->pw_gecos : pwd->pw_name);
118 } 118 }
119 repo->owner = owner; 119 repo->owner = owner;
120 120
121 p = fmt("%s/description", path); 121 p = fmt("%s/description", path);
122 if (!stat(p, &st)) 122 if (!stat(p, &st))
123 readfile(p, &repo->desc, &size); 123 readfile(p, &repo->desc, &size);
124 124
125 if (!repo->readme) { 125 if (!repo->readme) {
126 p = fmt("%s/README.html", path); 126 p = fmt("%s/README.html", path);
127 if (!stat(p, &st)) 127 if (!stat(p, &st))
128 repo->readme = "README.html"; 128 repo->readme = "README.html";
129 } 129 }
130 if (ctx.cfg.section_from_path) { 130 if (ctx.cfg.section_from_path) {
131 n = ctx.cfg.section_from_path; 131 n = ctx.cfg.section_from_path;
132 if (n > 0) { 132 if (n > 0) {
133 slash = rel; 133 slash = rel;
134 while (slash && n && (slash = strchr(slash, '/'))) 134 while (slash && n && (slash = strchr(slash, '/')))
135 n--; 135 n--;
136 } else { 136 } else {
137 slash = rel + strlen(rel); 137 slash = rel + strlen(rel);
138 while (slash && n && (slash = xstrrchr(rel, slash, '/'))) 138 while (slash && n && (slash = xstrrchr(rel, slash, '/')))
139 n++; 139 n++;
140 } 140 }
141 if (slash && !n) { 141 if (slash && !n) {
142 *slash = '\0'; 142 *slash = '\0';
143 repo->section = xstrdup(rel); 143 repo->section = xstrdup(rel);
144 *slash = '/'; 144 *slash = '/';
145 if (!prefixcmp(repo->name, repo->section)) { 145 if (!prefixcmp(repo->name, repo->section)) {
146 repo->name += strlen(repo->section); 146 repo->name += strlen(repo->section);
147 if (*repo->name == '/') 147 if (*repo->name == '/')
148 repo->name++; 148 repo->name++;
149 } 149 }
150 } 150 }
151 } 151 }
152 152
153 p = fmt("%s/cgitrc", path); 153 p = fmt("%s/cgitrc", path);
154 if (!stat(p, &st)) { 154 if (!stat(p, &st)) {
155 config_fn = fn; 155 config_fn = fn;
156 parse_configfile(xstrdup(p), &repo_config); 156 parse_configfile(xstrdup(p), &repo_config);
157 } 157 }
158} 158}
159 159
160static void scan_path(const char *base, const char *path, repo_config_fn fn) 160static void scan_path(const char *base, const char *path, repo_config_fn fn)
161{ 161{
162 DIR *dir = opendir(path); 162 DIR *dir = opendir(path);
163 struct dirent *ent; 163 struct dirent *ent;
164 char *buf; 164 char *buf;
165 struct stat st; 165 struct stat st;
166 166
167 if (!dir) { 167 if (!dir) {
168 fprintf(stderr, "Error opening directory %s: %s (%d)\n", 168 fprintf(stderr, "Error opening directory %s: %s (%d)\n",
169 path, strerror(errno), errno); 169 path, strerror(errno), errno);
170 return; 170 return;
171 } 171 }
172 if (is_git_dir(path)) { 172 if (is_git_dir(path)) {
173 add_repo(base, path, fn); 173 add_repo(base, path, fn);
174 goto end; 174 goto end;
175 } 175 }
176 if (is_git_dir(fmt("%s/.git", path))) { 176 if (is_git_dir(fmt("%s/.git", path))) {
177 add_repo(base, fmt("%s/.git", path), fn); 177 add_repo(base, fmt("%s/.git", path), fn);
178 goto end; 178 goto end;
179 } 179 }
180 while((ent = readdir(dir)) != NULL) { 180 while((ent = readdir(dir)) != NULL) {
181 if (ent->d_name[0] == '.') { 181 if (ent->d_name[0] == '.') {
182 if (ent->d_name[1] == '\0') 182 if (ent->d_name[1] == '\0')
183 continue; 183 continue;
184 if (ent->d_name[1] == '.' && ent->d_name[2] == '\0') 184 if (ent->d_name[1] == '.' && ent->d_name[2] == '\0')
185 continue; 185 continue;
186 if (!ctx.cfg.scan_hidden_path)
187 continue;
186 } 188 }
187 buf = malloc(strlen(path) + strlen(ent->d_name) + 2); 189 buf = malloc(strlen(path) + strlen(ent->d_name) + 2);
188 if (!buf) { 190 if (!buf) {
189 fprintf(stderr, "Alloc error on %s: %s (%d)\n", 191 fprintf(stderr, "Alloc error on %s: %s (%d)\n",
190 path, strerror(errno), errno); 192 path, strerror(errno), errno);
191 exit(1); 193 exit(1);
192 } 194 }
193 sprintf(buf, "%s/%s", path, ent->d_name); 195 sprintf(buf, "%s/%s", path, ent->d_name);
194 if (stat(buf, &st)) { 196 if (stat(buf, &st)) {
195 fprintf(stderr, "Error checking path %s: %s (%d)\n", 197 fprintf(stderr, "Error checking path %s: %s (%d)\n",
196 buf, strerror(errno), errno); 198 buf, strerror(errno), errno);
197 free(buf); 199 free(buf);
198 continue; 200 continue;
199 } 201 }
200 if (S_ISDIR(st.st_mode)) 202 if (S_ISDIR(st.st_mode))
201 scan_path(base, buf, fn); 203 scan_path(base, buf, fn);
202 free(buf); 204 free(buf);
203 } 205 }
204end: 206end:
205 closedir(dir); 207 closedir(dir);
206} 208}
207 209
208#define lastc(s) s[strlen(s) - 1] 210#define lastc(s) s[strlen(s) - 1]
209 211
210void scan_projects(const char *path, const char *projectsfile, repo_config_fn fn) 212void scan_projects(const char *path, const char *projectsfile, repo_config_fn fn)
211{ 213{
212 char line[MAX_PATH * 2], *z; 214 char line[MAX_PATH * 2], *z;
213 FILE *projects; 215 FILE *projects;
214 int err; 216 int err;
215 217
216 projects = fopen(projectsfile, "r"); 218 projects = fopen(projectsfile, "r");
217 if (!projects) { 219 if (!projects) {
218 fprintf(stderr, "Error opening projectsfile %s: %s (%d)\n", 220 fprintf(stderr, "Error opening projectsfile %s: %s (%d)\n",
219 projectsfile, strerror(errno), errno); 221 projectsfile, strerror(errno), errno);
220 } 222 }
221 while (fgets(line, sizeof(line), projects) != NULL) { 223 while (fgets(line, sizeof(line), projects) != NULL) {
222 for (z = &lastc(line); 224 for (z = &lastc(line);
223 strlen(line) && strchr("\n\r", *z); 225 strlen(line) && strchr("\n\r", *z);
224 z = &lastc(line)) 226 z = &lastc(line))
225 *z = '\0'; 227 *z = '\0';
226 if (strlen(line)) 228 if (strlen(line))
227 scan_path(path, fmt("%s/%s", path, line), fn); 229 scan_path(path, fmt("%s/%s", path, line), fn);
228 } 230 }
229 if ((err = ferror(projects))) { 231 if ((err = ferror(projects))) {
230 fprintf(stderr, "Error reading from projectsfile %s: %s (%d)\n", 232 fprintf(stderr, "Error reading from projectsfile %s: %s (%d)\n",
231 projectsfile, strerror(err), err); 233 projectsfile, strerror(err), err);
232 } 234 }
233 fclose(projects); 235 fclose(projects);
234} 236}
235 237
236void scan_tree(const char *path, repo_config_fn fn) 238void scan_tree(const char *path, repo_config_fn fn)
237{ 239{
238 scan_path(path, path, fn); 240 scan_path(path, path, fn);
239} 241}