diff options
Diffstat (limited to 'scan-tree.c')
-rw-r--r-- | scan-tree.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/scan-tree.c b/scan-tree.c new file mode 100644 index 0000000..cdafb02 --- /dev/null +++ b/scan-tree.c | |||
@@ -0,0 +1,136 @@ | |||
1 | #include "cgit.h" | ||
2 | #include "html.h" | ||
3 | |||
4 | #define MAX_PATH 4096 | ||
5 | |||
6 | /* return 1 if path contains a objects/ directory and a HEAD file */ | ||
7 | static int is_git_dir(const char *path) | ||
8 | { | ||
9 | struct stat st; | ||
10 | static char buf[MAX_PATH]; | ||
11 | |||
12 | if (snprintf(buf, MAX_PATH, "%s/objects", path) >= MAX_PATH) { | ||
13 | fprintf(stderr, "Insanely long path: %s\n", path); | ||
14 | return 0; | ||
15 | } | ||
16 | if (stat(buf, &st)) { | ||
17 | if (errno != ENOENT) | ||
18 | fprintf(stderr, "Error checking path %s: %s (%d)\n", | ||
19 | path, strerror(errno), errno); | ||
20 | return 0; | ||
21 | } | ||
22 | if (!S_ISDIR(st.st_mode)) | ||
23 | return 0; | ||
24 | |||
25 | sprintf(buf, "%s/HEAD", path); | ||
26 | if (stat(buf, &st)) { | ||
27 | if (errno != ENOENT) | ||
28 | fprintf(stderr, "Error checking path %s: %s (%d)\n", | ||
29 | path, strerror(errno), errno); | ||
30 | return 0; | ||
31 | } | ||
32 | if (!S_ISREG(st.st_mode)) | ||
33 | return 0; | ||
34 | |||
35 | return 1; | ||
36 | } | ||
37 | |||
38 | char *readfile(const char *path) | ||
39 | { | ||
40 | FILE *f; | ||
41 | static char buf[MAX_PATH]; | ||
42 | |||
43 | if (!(f = fopen(path, "r"))) | ||
44 | return NULL; | ||
45 | fgets(buf, MAX_PATH, f); | ||
46 | fclose(f); | ||
47 | return buf; | ||
48 | } | ||
49 | |||
50 | static void add_repo(const char *base, const char *path) | ||
51 | { | ||
52 | struct cgit_repo *repo; | ||
53 | struct stat st; | ||
54 | struct passwd *pwd; | ||
55 | char *p; | ||
56 | |||
57 | if (stat(path, &st)) { | ||
58 | fprintf(stderr, "Error accessing %s: %s (%d)\n", | ||
59 | path, strerror(errno), errno); | ||
60 | return; | ||
61 | } | ||
62 | if ((pwd = getpwuid(st.st_uid)) == NULL) { | ||
63 | fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n", | ||
64 | path, strerror(errno), errno); | ||
65 | return; | ||
66 | } | ||
67 | if (base == path) | ||
68 | p = fmt("%s", path); | ||
69 | else | ||
70 | p = fmt("%s", path + strlen(base) + 1); | ||
71 | |||
72 | if (!strcmp(p + strlen(p) - 5, "/.git")) | ||
73 | p[strlen(p) - 5] = '\0'; | ||
74 | |||
75 | repo = cgit_add_repo(xstrdup(p)); | ||
76 | repo->name = repo->url; | ||
77 | repo->path = xstrdup(path); | ||
78 | repo->owner = (pwd ? xstrdup(pwd->pw_gecos ? pwd->pw_gecos : pwd->pw_name) : ""); | ||
79 | |||
80 | p = fmt("%s/description", path); | ||
81 | if (!stat(p, &st)) | ||
82 | repo->desc = xstrdup(readfile(p)); | ||
83 | |||
84 | p = fmt("%s/README.html", path); | ||
85 | if (!stat(p, &st)) | ||
86 | repo->readme = "README.html"; | ||
87 | } | ||
88 | |||
89 | static void scan_path(const char *base, const char *path) | ||
90 | { | ||
91 | DIR *dir; | ||
92 | struct dirent *ent; | ||
93 | char *buf; | ||
94 | struct stat st; | ||
95 | |||
96 | if (is_git_dir(path)) { | ||
97 | add_repo(base, path); | ||
98 | return; | ||
99 | } | ||
100 | dir = opendir(path); | ||
101 | if (!dir) { | ||
102 | fprintf(stderr, "Error opening directory %s: %s (%d)\n", | ||
103 | path, strerror(errno), errno); | ||
104 | return; | ||
105 | } | ||
106 | while((ent = readdir(dir)) != NULL) { | ||
107 | if (ent->d_name[0] == '.') { | ||
108 | if (ent->d_name[1] == '\0') | ||
109 | continue; | ||
110 | if (ent->d_name[1] == '.' && ent->d_name[2] == '\0') | ||
111 | continue; | ||
112 | } | ||
113 | buf = malloc(strlen(path) + strlen(ent->d_name) + 2); | ||
114 | if (!buf) { | ||
115 | fprintf(stderr, "Alloc error on %s: %s (%d)\n", | ||
116 | path, strerror(errno), errno); | ||
117 | exit(1); | ||
118 | } | ||
119 | sprintf(buf, "%s/%s", path, ent->d_name); | ||
120 | if (stat(buf, &st)) { | ||
121 | fprintf(stderr, "Error checking path %s: %s (%d)\n", | ||
122 | buf, strerror(errno), errno); | ||
123 | free(buf); | ||
124 | continue; | ||
125 | } | ||
126 | if (S_ISDIR(st.st_mode)) | ||
127 | scan_path(base, buf); | ||
128 | free(buf); | ||
129 | } | ||
130 | closedir(dir); | ||
131 | } | ||
132 | |||
133 | void scan_tree(const char *path) | ||
134 | { | ||
135 | scan_path(path, path); | ||
136 | } | ||