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 | } | ||
