summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSadeep Madurange <sadeep@asciimx.com>2026-03-07 22:42:47 +0800
committerSadeep Madurange <sadeep@asciimx.com>2026-03-08 14:41:11 +0800
commitb6797b2440d01c6a13a882940dc4a6db4e84ffeb (patch)
tree51f512a598dc20644cbff78fff0a6fd1c0b4dffe
parent337114f01a6029778cbaefeef4f340e006872b91 (diff)
downloadcvn-b6797b2440d01c6a13a882940dc4a6db4e84ffeb.tar.gz
Hash(), dir/symlink/regular file handling.
-rw-r--r--main.c99
1 files changed, 80 insertions, 19 deletions
diff --git a/main.c b/main.c
index 08ecf39..035c7d3 100644
--- a/main.c
+++ b/main.c
@@ -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;
}