#include #include #include #include #include #include #include #include #include #include #include #define REPO ".cvn" #define INDEX "index" #define MALLOC(s) _xmalloc((s), __FILE__, __LINE__) #define REALLOC(p, s) _xrealloc((p), (s), __FILE__, __LINE__) static inline void init(int argc, char *argv[]); static inline void status(int argc, char *argv[]); static inline void traverse(void); static inline int ignore(const char *path); static inline int cmp(const void *a, const void *b); struct stack; struct stack_ent; static inline void stack_alloc(struct stack *st); static inline struct stack_ent *pop(struct stack *st); static inline void push(struct stack *st, struct stack_ent *new_ent); static inline void stack_free(struct stack *st); static inline void *_xmalloc(size_t s, const char *file, int line); static inline void *_xrealloc(void *ptr, size_t s, const char *file, int line); 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[]) { int i; if (argc < 2) errx(1, "Usage: %s []", argv[0]); 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; while ((opt = getopt(argc, argv, "b:")) != -1) { switch (opt) { case 'b': branch = optarg; break; default: break; } } if (mkdir(REPO, 0755) == -1) { if (errno != EEXIST) err(1, "Failed to create repository"); } if ((repo_fd = open(REPO, O_RDONLY | O_DIRECTORY)) == -1) err(1, "Failed to open repository"); if ((idx_fd = openat(repo_fd, INDEX, O_WRONLY | O_CREAT | O_EXCL, 0644)) == -1) { if (errno != EEXIST) { close(repo_fd); err(1, "Failed to create index"); } } else close(idx_fd); close(repo_fd); printf("Initialized repository in %s\n", REPO); } static inline void status(int argc, char *argv[]) { traverse(); } struct stack_ent { char *path; int is_dir; struct stack_ent *parent; }; struct stack { struct stack_ent **ents; size_t len; size_t cap; }; static inline void traverse(void) { DIR *dir; char *rel_path; struct stat st; struct dirent *entry; struct stack work_tree, stk; struct stack_ent *cur_dir, *root, *new_ent; stack_alloc(&stk); stack_alloc(&work_tree); root = MALLOC(sizeof(struct stack_ent)); root->path = strdup("."); root->is_dir = 1; root->parent = NULL; push(&stk, root); while (stk.len > 0) { cur_dir = pop(&stk); if (!(dir = opendir(cur_dir->path))) { warn("Failed to open directory %s", cur_dir->path); continue; } push(&work_tree, cur_dir); while ((entry = readdir(dir))) { if (ignore(entry->d_name)) continue; if (asprintf(&rel_path, "%s/%s", cur_dir->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)) { new_ent = MALLOC(sizeof(struct stack_ent)); new_ent->path = rel_path; new_ent->is_dir = 1; new_ent->parent = cur_dir; push(&stk, new_ent); } else { new_ent = MALLOC(sizeof(struct stack_ent)); new_ent->path = rel_path; new_ent->is_dir = 0; new_ent->parent = cur_dir; push(&work_tree, new_ent); } } closedir(dir); } for (ssize_t i = work_tree.len - 1; i >= 0; i--) { printf("Entry: %s, parent: %s\n", work_tree.ents[i]->path, work_tree.ents[i]->parent ? work_tree.ents[i]->parent->path : "NONE"); } stack_free(&stk); stack_free(&work_tree); } static inline void stack_alloc(struct stack *st) { st->len = 0; st->cap = 512; st->ents = MALLOC(sizeof(st->ents[0]) * st->cap); } static inline struct stack_ent *pop(struct stack *st) { return st->ents[--(st->len)]; } static inline void push(struct stack *st, struct stack_ent *new_ent) { if (st->len >= st->cap) { st->cap <<= 1; st->ents = REALLOC(st->ents, sizeof(struct stack_ent *) * st->cap); } st->ents[st->len++] = new_ent; } static inline void stack_free(struct stack *st) { size_t i; for (i = 0; i < st->len; i++) { free(st->ents[i]->path); free(st->ents[i]); } free(st->ents); } static inline int ignore(const char *path) { return strcmp(path, ".") == 0 || strcmp(path, "..") == 0 || strcmp(path, REPO) == 0; } static inline void *_xmalloc(size_t s, const char *file, int line) { void *p; if (!(p = malloc(s))) err(1, "%s:%d: malloc", file, line); return p; } static inline void *_xrealloc(void *ptr, size_t s, const char *file, int line) { void *p; if (!(p = realloc(ptr, s))) err(1, "%s:%d: realloc", file, line); return p; }