reposerve server half way done
[reposerve] / src / proto.c
diff --git a/src/proto.c b/src/proto.c
new file mode 100644 (file)
index 0000000..9d548a6
--- /dev/null
@@ -0,0 +1,141 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include "proto.h"
+#include "md5.h"
+
+struct flist *flist_create(void)
+{
+       struct flist *flist;
+
+       if(!(flist = calloc(1, sizeof *flist))) {
+               perror("flist_create");
+               return 0;
+       }
+       flist->final_size = -1;
+       return flist;
+}
+
+void flist_destroy(struct flist *flist)
+{
+       if(flist) {
+               free(flist->flist);
+               free(flist->data);
+               free(flist);
+       }
+}
+
+int flist_add(struct flist *flist, const char *fname, int contents)
+{
+       FILE *fp;
+       struct proto_file_entry fent;
+       int namelen, datalen, sz;
+       struct stat st;
+       char *dptr;
+       char buf[1024];
+       struct md5_state md;
+
+       if(flist->final_size >= 0) {
+               fprintf(stderr, "flist_add: can't add more files to a finalized file list\n");
+               return -1;
+       }
+
+       if(!(fp = fopen(fname, "rb"))) {
+               fprintf(stderr, "flist_add: failed to open file: %s: %s\n", fname, strerror(errno));
+               return -1;
+       }
+       fstat(fileno(fp), &st);
+
+       fent.size = st.st_size;
+       fent.mtime = st.st_mtime;
+
+       namelen = datalen = strlen(fname);
+       if(contents) {
+               datalen += fent.size;
+       }
+
+       if(flist->flist->num_files >= flist->max_files) {
+               struct proto_flist *tmp;
+               int newsz = flist->max_files ? flist->max_files << 1 : 32;
+
+               if(!(tmp = realloc(flist->flist, sizeof *tmp + (newsz - 1) * sizeof *tmp->files))) {
+                       fprintf(stderr, "flist_add: failed to resize file list to %d entries\n", newsz);
+                       return -1;
+               }
+               flist->flist = tmp;
+               flist->max_files = newsz;
+       }
+       if(flist->data_sz + datalen >= flist->max_data_sz) {
+               char *tmp;
+               int newsz = flist->max_data_sz + datalen;
+               newsz |= newsz >> 1;
+               newsz |= newsz >> 2;
+               newsz |= newsz >> 4;
+               newsz |= newsz >> 8;
+               newsz |= newsz >> 16;
+               newsz += 1;
+
+               if(!(tmp = realloc(flist->data, newsz))) {
+                       fprintf(stderr, "flist_add: failed to resize data buffer to %d bytes\n", newsz);
+                       return -1;
+               }
+               flist->data = tmp;
+               flist->max_data_sz = newsz;
+       }
+
+       fent.nameoffs = flist->data_sz;
+       fent.namelen = namelen;
+       dptr = flist->data + flist->data_sz;
+       memcpy(dptr, fname, namelen);
+
+       md5_begin(&md);
+       if(contents) {
+               dptr += namelen;
+
+               while((sz = fread(dptr, 1, st.st_size, fp)) > 0) {
+                       md5_msg(&md, dptr, sz);
+                       dptr += sz;
+                       st.st_size -= sz;
+               }
+       } else {
+               while((sz = fread(buf, 1, sizeof buf, fp)) > 0) {
+                       md5_msg(&md, buf, sz);
+               }
+       }
+       md5_end(&md);
+       memcpy(fent.csum, md.sum, sizeof fent.csum);
+
+       fclose(fp);
+
+       flist->flist->files[flist->flist->num_files++] = fent;
+       flist->data_sz += datalen;
+       return 0;
+}
+
+int flist_finalize(struct flist *flist)
+{
+       int newsz;
+       struct proto_flist *tmp;
+
+       if(!flist->flist || flist->flist->num_files <= 0) {
+               fprintf(stderr, "flist_finalize: nothing to finalize, file list empty\n");
+               return -1;
+       }
+
+       newsz = sizeof *tmp + (flist->flist->num_files - 1) * sizeof *tmp->files + flist->data_sz;
+       if(!(tmp = realloc(flist->flist, newsz))) {
+               fprintf(stderr, "flist_finalize: failed to resize file list buffer to %d bytes\n", newsz);
+               return -1;
+       }
+
+       memcpy(tmp->files + flist->flist->num_files, flist->data, flist->data_sz);
+       free(flist->data);
+
+       memset(flist, 0, sizeof *flist);
+       flist->flist = tmp;
+       flist->final_size = newsz;
+       return 0;
+}