#include #include #include #include #include #include #include #include #include #include #define REPO ".cvn" #define INDEX "index" #define MAX_SUBDIRS 256 static inline void init(int argc, char *argv[]); static inline void status(int argc, char *argv[]); /* helpers */ static inline void traverse(void); struct command { char *name; void (*func)(int argc, char *argv[]); }; struct command cmd[] = { {"init", init}, {"status", status}, {NULL, NULL} }; int main(int argc, char *argv[]) { uint8_t i; if (argc < 2) { fprintf(stderr, "Usage: %s []\n", argv[0]); return 1; } for (i = 0; cmd[i].name != NULL; i++) { if (strcmp(argv[1], cmd[i].name) == 0) { cmd[i].func(argc - 1, argv + 1); return 0; } } return 0; } static inline void init(int argc, char *argv[]) { char *branch; int opt, repo_fd, idx_fd; optind = 1; branch = "master"; while ((opt = getopt(argc, argv, "b:")) != -1) { switch (opt) { case 'b': branch = optarg; break; default: break; } } if (mkdir(REPO, 0755) == -1) { if (errno != EEXIST) { perror("Failed to create repository"); return; } } if ((repo_fd = open(REPO, O_RDONLY | O_DIRECTORY)) == -1) { perror("Failed to open repository"); return; } if ((idx_fd = openat(repo_fd, INDEX, O_WRONLY | O_CREAT | O_EXCL, 0644)) == -1) { if (errno != EEXIST) { close(repo_fd); perror("Failed to create index"); return; } } else close(idx_fd); close(repo_fd); printf("Initialized repository in %s\n", REPO); } static inline void status(int argc, char *argv[]) { traverse(); } static inline void traverse(void) { DIR *dir; char *path, *rel_path; struct stat st; struct dirent *entry; int subdirs_len; char *subdirs[MAX_SUBDIRS]; subdirs_len = 0; subdirs[subdirs_len++] = strdup("."); while (subdirs_len) { path = subdirs[--subdirs_len]; if (!(dir = opendir(path))) { warn("Failed to open directory %s", path); free(path); continue; } while ((entry = readdir(dir)) != NULL) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; if (asprintf(&rel_path, "%s/%s", path, entry->d_name) == -1) err(1, "asprintf() failed"); if (lstat(rel_path, &st) == -1) { warn("lstat() failed: %s", rel_path); free(rel_path); continue; } if (S_ISDIR(st.st_mode)) { if (subdirs_len >= MAX_SUBDIRS) errx(1, "Repository too large: directory tree too deep/wide"); subdirs[subdirs_len++] = rel_path; } else { printf("File: %s\n", rel_path); free(rel_path); } } free(path); closedir(dir); } }