diff options
| author | Sadeep Madurange <sadeep@asciimx.com> | 2026-03-07 22:42:47 +0800 |
|---|---|---|
| committer | Sadeep Madurange <sadeep@asciimx.com> | 2026-03-08 14:41:11 +0800 |
| commit | b6797b2440d01c6a13a882940dc4a6db4e84ffeb (patch) | |
| tree | 51f512a598dc20644cbff78fff0a6fd1c0b4dffe | |
| parent | 337114f01a6029778cbaefeef4f340e006872b91 (diff) | |
| download | cvn-b6797b2440d01c6a13a882940dc4a6db4e84ffeb.tar.gz | |
Hash(), dir/symlink/regular file handling.
| -rw-r--r-- | main.c | 99 |
1 files changed, 80 insertions, 19 deletions
@@ -2,6 +2,7 @@ #include <err.h> #include <errno.h> #include <fcntl.h> +#include <limits.h> #include <sha1.h> #include <stdio.h> #include <stdlib.h> @@ -10,8 +11,13 @@ #include <sys/stat.h> #include <sys/types.h> -#define REPO ".cvn" -#define INDEX "index" +#define REPO ".cvn" +#define INDEX "index" +#define HASH_LEN SHA1_DIGEST_LENGTH + +#define FLAG_DIR (1 << 0) // 0x01 +#define FLAG_EXE (1 << 1) // 0x02 +#define FLAG_LNK (1 << 2) // 0x04 #define MALLOC(s) _xmalloc((s), __FILE__, __LINE__) #define REALLOC(p, s) _xrealloc((p), (s), __FILE__, __LINE__) @@ -19,10 +25,6 @@ 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); @@ -30,6 +32,10 @@ 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 traverse(void); +static inline void hash(struct stack *st); +static inline int ignore(const char *path); + 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); @@ -105,7 +111,8 @@ static inline void status(int argc, char *argv[]) struct stack_ent { char *path; - int is_dir; + unsigned char flags; + unsigned char hash[HASH_LEN]; struct stack_ent *parent; }; @@ -129,7 +136,7 @@ static inline void traverse(void) root = MALLOC(sizeof(struct stack_ent)); root->path = strdup("."); - root->is_dir = 1; + root->flags = FLAG_DIR; root->parent = NULL; push(&stk, root); @@ -153,33 +160,86 @@ static inline void traverse(void) 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 { + if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || + S_ISLNK(st.st_mode)) { new_ent = MALLOC(sizeof(struct stack_ent)); new_ent->path = rel_path; - new_ent->is_dir = 0; + new_ent->flags = 0; new_ent->parent = cur_dir; - push(&work_tree, new_ent); + + if (S_ISLNK(st.st_mode)) + new_ent->flags |= FLAG_LNK; + + if (S_ISDIR(st.st_mode)) { + new_ent->flags |= FLAG_DIR; + push(&stk, new_ent); + } else + push(&work_tree, new_ent); } } closedir(dir); } + hash(&work_tree); + for (ssize_t i = work_tree.len - 1; i >= 0; i--) { - printf("Entry: %s, parent: %s\n", + printf("Entry: %s (p: %s): 0x", work_tree.ents[i]->path, work_tree.ents[i]->parent ? work_tree.ents[i]->parent->path : "NONE"); + for (int j = 0; j < HASH_LEN; j++) + printf("%02x", work_tree.ents[i]->hash[j]); + putchar('\n'); } stack_free(&stk); stack_free(&work_tree); } +static inline void hash(struct stack *st) +{ + int fd; + ssize_t i, j; + SHA1_CTX ctx; + unsigned char *buf; + ssize_t bytes_read, lnk_len; + struct stack_ent *ent, *prev_ent; + + const int buflen = 8192 > PATH_MAX ? 8192 : PATH_MAX; + buf = MALLOC(sizeof(buf[0]) * buflen); + + for (i = st->len - 1; i >= 0; i--) { + SHA1Init(&ctx); + ent = st->ents[i]; + if (!ent->flags) { /* regular file */ + if ((fd = open(ent->path, O_RDONLY)) == -1) + err(1, "Cannot open %s", ent->path); + while ((bytes_read = read(fd, buf, buflen)) > 0) + SHA1Update(&ctx, buf, (size_t)bytes_read); + if (bytes_read == -1) + err(1, "Read error on %s", ent->path); + close(fd); + } else if ((ent->flags & FLAG_LNK)) { + lnk_len = readlink(ent->path, buf, buflen - 1); + if (lnk_len != -1) { + buf[lnk_len] = '\0'; + SHA1Update(&ctx, buf, lnk_len); + } else + err(1, "readlink error on %s", ent->path); + } else { + // directory: walk the stack backwards and collect + // hashes from children + for (j = i + 1; j < st->len; j++) { + prev_ent = st->ents[j]; + if (prev_ent->parent != ent) + break; + SHA1Update(&ctx, prev_ent->hash, HASH_LEN); + } + } + SHA1Final(ent->hash, &ctx); + } + free(buf); +} + static inline void stack_alloc(struct stack *st) { st->len = 0; @@ -196,7 +256,8 @@ 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 = REALLOC(st->ents, + sizeof(struct stack_ent *) * st->cap); } st->ents[st->len++] = new_ent; } |
