fixed filenames returned by flist
[reposerve] / src / proto.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <errno.h>
5 #include <unistd.h>
6 #include <sys/stat.h>
7 #include "proto.h"
8 #include "md5.h"
9
10 struct flist *flist_create(void)
11 {
12         struct flist *flist;
13
14         if(!(flist = calloc(1, sizeof *flist))) {
15                 perror("flist_create");
16                 return 0;
17         }
18         flist->final_size = -1;
19         return flist;
20 }
21
22 void flist_destroy(struct flist *flist)
23 {
24         if(flist) {
25                 free(flist->flist);
26                 free(flist->data);
27                 free(flist);
28         }
29 }
30
31 int flist_add(struct flist *flist, const char *name, const char *path, int contents)
32 {
33         FILE *fp;
34         struct proto_file_entry fent;
35         int namelen, datalen, sz;
36         struct stat st;
37         char *dptr;
38         char buf[1024];
39         struct md5_state md;
40
41         if(flist->final_size >= 0) {
42                 fprintf(stderr, "flist_add: can't add more files to a finalized file list\n");
43                 return -1;
44         }
45
46         if(!(fp = fopen(path, "rb"))) {
47                 fprintf(stderr, "flist_add: failed to open file: %s: %s\n", path, strerror(errno));
48                 return -1;
49         }
50         fstat(fileno(fp), &st);
51
52         fent.size = st.st_size;
53         fent.mtime = st.st_mtime;
54
55         namelen = datalen = strlen(name);
56         if(contents) {
57                 datalen += fent.size;
58         }
59
60         if(!flist->flist || flist->flist->num_files >= flist->max_files) {
61                 struct proto_flist *tmp;
62                 int newsz = flist->max_files ? flist->max_files << 1 : 32;
63
64                 if(!(tmp = realloc(flist->flist, sizeof *tmp + (newsz - 1) * sizeof *tmp->files))) {
65                         fprintf(stderr, "flist_add: failed to resize file list to %d entries\n", newsz);
66                         return -1;
67                 }
68                 if(!flist->flist) {
69                         tmp->num_files = 0;
70                 }
71                 flist->flist = tmp;
72                 flist->max_files = newsz;
73         }
74         if(flist->data_sz + datalen >= flist->max_data_sz) {
75                 char *tmp;
76                 int newsz = flist->max_data_sz + datalen;
77                 newsz |= newsz >> 1;
78                 newsz |= newsz >> 2;
79                 newsz |= newsz >> 4;
80                 newsz |= newsz >> 8;
81                 newsz |= newsz >> 16;
82                 newsz += 1;
83
84                 if(!(tmp = realloc(flist->data, newsz))) {
85                         fprintf(stderr, "flist_add: failed to resize data buffer to %d bytes\n", newsz);
86                         return -1;
87                 }
88                 flist->data = tmp;
89                 flist->max_data_sz = newsz;
90         }
91
92         fent.nameoffs = flist->data_sz;
93         fent.namelen = namelen;
94         dptr = flist->data + flist->data_sz;
95         memcpy(dptr, name, namelen);
96
97         md5_begin(&md);
98         if(contents) {
99                 dptr += namelen;
100
101                 while((sz = fread(dptr, 1, st.st_size, fp)) > 0) {
102                         md5_msg(&md, dptr, sz);
103                         dptr += sz;
104                         st.st_size -= sz;
105                 }
106         } else {
107                 while((sz = fread(buf, 1, sizeof buf, fp)) > 0) {
108                         md5_msg(&md, buf, sz);
109                 }
110         }
111         md5_end(&md);
112         memcpy(fent.csum, md.sum, sizeof fent.csum);
113
114         fclose(fp);
115
116         flist->flist->files[flist->flist->num_files++] = fent;
117         flist->data_sz += datalen;
118         return 0;
119 }
120
121 int flist_finalize(struct flist *flist)
122 {
123         int newsz;
124         struct proto_flist *tmp;
125
126         if(!flist->flist || flist->flist->num_files <= 0) {
127                 fprintf(stderr, "flist_finalize: nothing to finalize, file list empty\n");
128                 return -1;
129         }
130
131         newsz = sizeof *tmp + (flist->flist->num_files - 1) * sizeof *tmp->files + flist->data_sz;
132         if(!(tmp = realloc(flist->flist, newsz))) {
133                 fprintf(stderr, "flist_finalize: failed to resize file list buffer to %d bytes\n", newsz);
134                 return -1;
135         }
136
137         memcpy(tmp->files + flist->flist->num_files, flist->data, flist->data_sz);
138         free(flist->data);
139
140         memset(flist, 0, sizeof *flist);
141         flist->flist = tmp;
142         flist->final_size = newsz;
143         return 0;
144 }
145
146 int read_line(int s, char *buf, int bufsz)
147 {
148         char *ptr = buf;
149         while(bufsz > 1 && read(s, ptr, 1) > 0 && *ptr++ != '\n');
150         *ptr = 0;
151         return ptr == buf ? -1 : 0;
152 }
153
154 int read_resp(int s)
155 {
156         int sz, msglen = 0;
157         char buf[64];
158         char *ptr;
159
160         while(msglen < 3 && (sz = read(s, buf + msglen, 3 - msglen)) > 0) {
161                 msglen += sz;
162         }
163         if(msglen < 3) return -1;
164
165         if(memcmp(buf, "ERR", 3) == 0) {
166                 return -1;
167         }
168
169         ptr = buf;
170         while(read(s, ptr, 1) > 0 && *ptr++ != '\n');
171         *ptr = 0;
172
173         return atoi(buf);
174 }