...
authoralex <[email protected]>
Sat, 30 Oct 2021 00:08:46 +0000 (17:08 -0700)
committeralex <[email protected]>
Sat, 30 Oct 2021 00:08:46 +0000 (17:08 -0700)
Makefile.am
inc/block.h [new file with mode: 0644]
inc/file.h
src/block.c [new file with mode: 0644]
src/file.c

index 90c8c4edebdc19b1eb03e84b129ed68c5cfe3926..16073d38a3f21f289915d7a1db6425f81de75638 100644 (file)
@@ -15,6 +15,7 @@ seederd_SOURCES = \
        src/add.c \
        src/bencode/decode.c \
        src/bencode/encode.c \
+       src/block.c \
        src/default.c \
        src/file.c \
        src/hash.c \
@@ -47,6 +48,7 @@ seederd_SOURCES = \
 seederd_SOURCES += \
        inc/add.h \
        inc/bencode.h \
+       inc/block.h \
        inc/default.h \
        inc/file.h \
        inc/hash.h \
diff --git a/inc/block.h b/inc/block.h
new file mode 100644 (file)
index 0000000..9bde2bf
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __BLOCK_H_
+#define __BLOCK_H_
+
+#include<sodium.h>
+
+#define BLOCK_SIZE 16384
+
+struct block {
+       uint8_t *data;
+       unsigned char hash[crypto_hash_sha256_BYTES];
+       struct block *next;
+};
+
+int block_append_blank(struct block*);
+int block_duplicate(struct block**,struct block*);
+void block_free(struct block*);
+int block_init(struct block**);
+size_t block_length(struct block*);
+int block_merkle_root(struct block*);
+
+#endif
index ac254b045b3c977486f3faf55a3c1f6bedd9f514..28501eee2d951eb608af9f124a30c8a4cc24635c 100644 (file)
@@ -8,10 +8,14 @@
 
 #include<sodium.h>
 
+#define FILE_MESSAGE_FREAD_FAILED "failed to read file: %s\n"
+
 struct file {
        char *name;
        char *path;
        unsigned char root[crypto_hash_sha256_BYTES];
+       struct block *blocks;
+       size_t size;
 };
 
 void file_free(struct file*);
diff --git a/src/block.c b/src/block.c
new file mode 100644 (file)
index 0000000..5a3b51b
--- /dev/null
@@ -0,0 +1,98 @@
+#include<block.h>
+
+int block_append_block(struct block *p) {
+       if(NULL==p) { return -1; }
+
+       while(p->next!=NULL) {
+               p = p->next;
+       }
+
+       if(block_init(&(p->next))<0) { return -1; }
+       memset(p->next->hash,0,crypto_hash_sha256_BYTES);
+
+       return 1;
+}
+
+int block_duplicate(struct block **p, struct block *to_dup) {
+       struct block *next;
+
+       if(NULL==p) { return -1; }
+       if(NULL==to_dup) { return -1; }
+
+       while(to_dup!=NULL) {
+               if(block_init(p)<0) { return -1; }
+               
+               memcpy((*p)->hash,to_dup->hash,crypto_hash_sha256_BYTES);
+               
+               (*p) = (*p)->next;
+               to_dup = to_dup->next;
+       }
+
+       return 1;
+}
+
+void block_free(struct block *p) {
+       struct block *next;
+
+       while(p!=NULL) {
+               if(p->data!=NULL) {
+                       free(p->data);
+               }
+
+               next = p->next;
+               free(p);
+               p = next;
+       }
+}
+
+int block_init(struct block **p) {
+       if(NULL==p) { return -1; }
+
+       *p = malloc(sizeof(struct block));
+       if(NULL==(*p)) {
+               perror("malloc");
+               return -1;
+       }
+
+       (*p)->data = NULL;
+       (*p)->next = NULL;
+
+       return 1;
+}
+
+size_t block_length(struct block *p) {
+       size_t i = 0;
+       while(p!=NULL) {
+               i++;
+               p = p->next;
+       }
+
+       return i;
+}
+
+int block_merkle_root(struct block *root) {
+       struct block *p, *to_free;
+       crypto_hash_sha256_state state;
+
+       if(NULL==root) { return -1; }
+
+       while(p!=NULL) {
+               if(NULL==p->next) { return -1; }
+               if(hash_init(&state)<0) { return -1; }
+
+               if(hash_update(&state,p->hash,crypto_hash_sha256_BYTES)<0) { return -1; }
+               if(hash_update(&state,p->next->hash,crypto_hash_sha256_BYTES)<0) { return -1; }
+
+               if(hash_final(&state,p->hash,crypto_hash_sha256_BYTES)<0) { return -1; }
+
+               to_free = p->next;
+               p = p->next->next;
+               block_free(to_free);
+
+               if((NULL==p)&&(p!=root)) {
+                       p = root;
+               }
+       }
+
+       return 1;
+}
index 009d11bc2fefe03e9663c92491e0eb78d05624fb..13c191f709f0cc4f8e30b7a81709a159b16d009b 100644 (file)
@@ -14,8 +14,75 @@ void file_free(struct file *p) {
        free(p);
 }
 
-int file_hash(struct file *p) {
+int file_hash(struct file *file_p) {
+       uint8_t data[BLOCK_SIZE];
+       struct block *start, *p, *next, *end;
+       FILE *fp;
+       int blocks_per_piece;
+
+       blocks_per_piece = global_opts.piece_length / BLOCK_SIZE;
+       
+       fp = fopen(file_p->path,"rb");
+       if(NULL==fp) { return -1; }
+
+       while(1) {
+               if(block_init(&start)<0) { goto clean; }
+               p = start;
+               for(size_t i=0;i<blocks_per_piece;i++) {
+                       size_t len = fread(data,sizeof(uint8_t),BLOCK_SIZE,fp);
+                       if((len<=BLOCK_SIZE)&&(ferror(fp)!=0)) {
+                               perror("fread");
+                               log_err(FILE_MESSAGE_FREAD_FAILED,file_p->path);
+                               goto clean;
+                       }
+
+                       if(len==0) { break; }
+
+                       file_p->size += len;
+
+                       if(block_init(&next)<0) { goto clean; }
+                       if(hash(data,len,next->hash,crypto_hash_sha256_BYTES)<0) { goto clean; }
+
+                       p->next = next;
+                       p = p->next;
+               }
+
+               ssize_t blocks = block_length(start);
+               if(blocks<=0) { goto clean; }
+
+               if(blocks!=blocks_per_piece) {
+                       // if the file is smaller than one piece then the block hashes
+                       // should be padded to the next power of two instead of the next
+                       // piece boundary
+                       size_t leaves_required = next_power_2(blocks);
+                       while(leaves_required>0) {
+                               if(block_append_blank(start)<0) { goto clean; }
+                               leaves_required--;
+                       }
+               }
+
+               if(block_merkle_root(start)<0) { goto clean; }
+       
+               if(NULL==file_p->blocks) {
+                       file_p->blocks = start;
+                       end = start;
+               }
+               
+               end->next = start;
+               end = end->next;
+       }
+
+       fclose(fp);
+
+       if(block_duplicate(&start,file_p->blocks)<0) { return -1; }
+       if(block_merkle_root(start)<0) { return -1; }
+       memcpy(file_p->root,start->hash,crypto_hash_sha256_BYTES);
+       block_free(start);
+       
        return 1;
+clean:
+       block_free(start);
+       fclose(fp);
 }
 
 int file_init(struct file **p, const char *path) {
@@ -36,6 +103,8 @@ int file_init(struct file **p, const char *path) {
        (*p)->name = strdup(b);
 
        memset((*p)->root,0,crypto_hash_sha256_BYTES);
+       (*p)->blocks = NULL;
+       (*p)->size = 0;
 
        return 1;
 }