#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 uint8_t ignore(const char *path); static inline int cmp(const void *a, const void *b); 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[]) { 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; 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(); } struct node { char *path; unsigned char is_dir; struct node *parent; }; static inline void traverse(void) { DIR *dir; char *rel_path; struct stat st; struct dirent *entry; struct node *cur_dir, *root, *new_node; struct node **dirs, **tree; size_t dirs_len, tree_len; size_t dirs_cap, tree_cap; tree_len = 0, tree_cap = 512; tree = MALLOC(sizeof(tree[0]) * tree_cap); dirs_len = 0, dirs_cap = 512; dirs = MALLOC(sizeof(dirs[0]) * dirs_cap); root = MALLOC(sizeof(struct node)); root->path = strdup("."); root->is_dir = 1; root->parent = NULL; dirs[dirs_len++] = root; while (dirs_len > 0) { cur_dir = dirs[--dirs_len]; if (!(dir = opendir(cur_dir->path))) { warn("Failed to open directory %s", cur_dir->path); continue; } if (tree_len >= tree_cap - 1) { tree_cap <<= 1; tree = REALLOC(tree, sizeof(tree[0]) * tree_cap); } tree[tree_len++] = 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)) { if (dirs_len >= dirs_cap) { dirs_cap <<= 1; dirs = REALLOC(dirs, sizeof(dirs[0]) * dirs_cap); } new_node = MALLOC(sizeof(struct node)); new_node->path = rel_path; new_node->is_dir = 1; new_node->parent = cur_dir; dirs[dirs_len++] = new_node; } else { if (tree_len >= tree_cap) { tree_cap <<= 1; tree = REALLOC(tree, sizeof(tree[0]) * tree_cap); } new_node = MALLOC(sizeof(struct node)); new_node->path = rel_path; new_node->is_dir = 0; new_node->parent = cur_dir; tree[tree_len++] = new_node; } } closedir(dir); } for (int i = (int)tree_len - 1; i >= 0; i--) { printf("Entry: %s, parent: %s\n", tree[i]->path, tree[i]->parent ? tree[i]->parent->path : "NONE"); } for (size_t i = 0; i < tree_len; i++) { free(tree[i]->path); free(tree[i]); } free(tree); free(dirs); } static inline int cmp(const void *a, const void *b) { return strcmp(*(const char **)a, *(const char **)b); } static inline unsigned char 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 = malloc(s); if (!p) 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 = realloc(ptr, s); if (!p) err(1, "%s:%d: realloc", file, line); return p; }