Distributed File System written in C
1#include "lib.h"
2#include "log.h"
3#include <stdlib.h>
4#include <string.h>
5#include <sys/stat.h>
6
7ImplList(Buffer)
8
9Buffer ListBuffer_serialize(ListBuffer list) {
10 Buffer out = {0};
11 for (ListBuffer lptr = list; lptr != NULL; lptr = lptr->rest) {
12 Buffer buf = lptr->head;
13 out = concat(out, Buffer_serialize(buf));
14 }
15 return out;
16}
17
18ListBuffer ListBuffer_deserialize(Buffer buf) {
19 ListBuffer out = NULL;
20 for (size_t len = 0; len < buf.len;) {
21 Buffer mbuf = Buffer_deserialize((Buffer) {
22 .buf = buf.len + (Byte*)len,
23 .len = 0,
24 });
25 len += mbuf.len + sizeof(size_t);
26 out = ListBuffer_cons(mbuf, out);
27 }
28
29 return out;
30}
31
32bool mkdir_p(SafeStr fpath, mode_t mode) {
33 char* tmp = calloc(fpath.len + 1, sizeof(char));
34 size_t len = 0;
35 for (size_t i = 0; i < fpath.len; ++i) {
36 char c = fpath.str[i];
37 if (c == '/') {
38 if (len != 0) {
39 if (mkdir(tmp, mode) != 0) {
40 if (errno != EEXIST)
41 try(-1);
42 }
43 }
44 }
45 tmp[len++] = c;
46 }
47 // INFO: This needs to get done one more time in case there isn't a '/' at
48 // the end of the fpath
49 if (mkdir(tmp, mode) != 0) {
50 if (errno != EEXIST)
51 try(-1);
52 }
53 return true;
54}
55
56void Buffer_deinit(Buffer kod) {
57 free(kod.buf);
58}
59
60void Buffer_write(Buffer buf, FILE* f) {
61 exists(f);
62 fwrite(buf.buf, sizeof(Byte), buf.len, f);
63}
64
65Buffer Buffer_read(FILE* f) {
66 exists(f);
67 fseek(f, 0, SEEK_END);
68 size_t len = (size_t)ftell(f);
69 fseek(f, 0, SEEK_SET);
70 Buffer buf = {
71 .buf = calloc(len, sizeof(Byte)),
72 .len = len,
73 };
74 exists(buf.buf);
75
76 size_t count = fread(buf.buf, sizeof(Byte), len, f);
77
78 if (count != len) {
79 log(FATAL, "Error reading file\n");
80 exit(EXIT_FAILURE);
81 }
82
83 return buf;
84}
85
86Byte* copy(Byte* src, size_t nbytes) {
87 exists(src);
88 Byte* out = (Byte*)malloc(nbytes * sizeof(Byte));
89 exists(out);
90 memcpy(out, src, nbytes);
91 return out;
92}
93
94/// Allocates new memory from src and returns a buffer to that memory. The user
95/// must free that memory.
96Buffer bufcpy(Buffer src) {
97 Byte* buf = (Byte*)malloc(src.len * sizeof(Byte));
98 exists(buf);
99 memcpy(buf, src.buf, src.len);
100 return (Buffer){
101 .buf = buf,
102 .len = src.len,
103 };
104}
105
106/// Checks whether the buffer contains a valid string and that the size provided
107/// matches the size of that string.
108Buffer validate_str(Buffer str, size_t max_len) {
109 size_t calculated_len = safe_strlen((const char*)str.buf, max_len);
110 if (str.len != calculated_len) {
111 log(ERROR, "%s:%d String's length (%zu) is not equal to given length (%zu).", __FILE__, __LINE__, calculated_len, str.len);
112
113 printf("\nBuffer contains: ");
114 for (size_t i = 0; i < max_len; ++i) printf("[%d] ", str.buf[i]);
115 printf("\n");
116
117 exit(1);
118 }
119 if (str.len > max_len) {
120 log(ERROR, "%s:%d String's length (%zu) is larger than the buffer that contains it (%zu)\n", str.len, calculated_len);
121
122 printf("\nBuffer contains: ");
123 for (size_t i = 0; i < max_len; ++i) printf("[%d] ", str.buf[i]);
124 printf("\n");
125
126 exit(1);
127 }
128 return str;
129}
130
131// uses memchr to calculate strlen.
132size_t safe_strlen(Str str, size_t max_len) {
133 char* last = memchr(str, '\0', max_len);
134 return last != NULL ? (size_t)last - (size_t)str : max_len;
135}
136
137// Esta funcion convierte un string a un buffer.
138Buffer atob(const char* str) {
139 return (Buffer){
140 .buf = (Byte*)str,
141 .len = strlen(str),
142 };
143}
144
145Buffer SafeStr_serialize(SafeStr str) {
146 return concat(size_t_serialize(str.len), to_buffer(str.str, str.len));
147}
148
149SafeStr SafeStr_deserialize(Buffer buf) {
150 size_t len = size_t_deserialize((Buffer) {
151 .buf = buf.buf,
152 .len = sizeof(size_t)
153 });
154 Str str = calloc(len + 1, sizeof(char));
155
156 memcpy((void*)str, (void*)(buf.buf + sizeof(size_t)), len);
157
158 return (SafeStr){
159 .str = str,
160 .len = len,
161 };
162}
163
164Buffer size_t_serialize(size_t a) {
165 Buffer out = {
166 .len = sizeof(size_t),
167 .buf = (Byte*)calloc(1, sizeof(size_t)),
168 };
169
170 memcpy(out.buf, &a, sizeof(size_t));
171
172 return out;
173}
174
175size_t size_t_deserialize(Buffer buf) {
176 size_t out = 0;
177
178 if (buf.len != sizeof(size_t)) {
179 log(FATAL, "size_t has incorrect size\n");
180 exit(EXIT_FAILURE);
181 }
182
183 memcpy(&out, buf.buf, sizeof(size_t));
184
185 return out;
186}
187
188Buffer concat(Buffer l, Buffer r) {
189 // INFO: Notice that whenever either is null, the other is returned.
190 if (l.buf == NULL) {
191 return r;
192 } else if (r.buf == NULL) {
193 return l;
194 }
195 Buffer out = {
196 .len = l.len + r.len,
197 .buf = (Byte*)calloc(l.len + r.len, sizeof(Byte)),
198 };
199 exists(out.buf);
200
201 memcpy(out.buf, l.buf, l.len);
202 memcpy(out.buf + l.len, r.buf, r.len);
203 free(l.buf);
204 free(r.buf);
205
206 return out;
207}
208
209bool Str_eq(Str l, Str r) {
210 return strcmp(l, r) == 0;
211}
212
213Buffer Buffer_serialize(Buffer buf) {
214 Buffer size = size_t_serialize(buf.len);
215 exists(size.buf);
216 return concat(size, buf);
217}
218
219Buffer Buffer_deserialize(Buffer buf) {
220 size_t size = size_t_deserialize((Buffer){ .buf = buf.buf, .len = sizeof(size_t) });
221
222 if (buf.len < size + sizeof(size_t)) {
223 log(FATAL, "Error deserializing buffer. Incorrect size. Got: %zu. Expected greater than: %zu\n", buf.len, size + sizeof(size_t));
224 exit(EXIT_FAILURE);
225 }
226
227 Buffer out = {
228 .buf = (Byte*)calloc(size, sizeof(Byte)),
229 .len = size,
230 };
231 exists(out.buf);
232
233 memcpy(out.buf, buf.buf + sizeof(size_t), size);
234 return out;
235}
236
237Buffer to_buffer(const void* thing, size_t nbytes) {
238 Buffer out = {
239 .buf = (Byte*)calloc(1, nbytes),
240 .len = nbytes,
241 };
242 exists(out.buf);
243
244 memcpy(out.buf, thing, nbytes);
245 return out;
246}
247
248
249Buffer uint8_t_serialize(uint8_t n) {
250 return to_buffer(&n, sizeof(uint8_t));
251}
252
253uint8_t uint8_t_deserialize(Buffer buf) {
254 exists(buf.buf);
255
256 if (buf.len != sizeof(uint8_t)) {
257 log(FATAL, "Could not deserialize uint8_t. Buffer length incorrect: %zu\n", buf.len);
258 exit(EXIT_FAILURE);
259 }
260
261 uint8_t x;
262 memcpy(&x, buf.buf, sizeof x);
263 return x;
264}
265
266
267Buffer uint16_t_serialize(uint16_t n) {
268 return to_buffer(&n, sizeof(uint16_t));
269}
270
271uint16_t uint16_t_deserialize(Buffer buf) {
272 exists(buf.buf);
273
274 if (buf.len != sizeof(uint16_t)) {
275 log(FATAL, "Could not deserialize uint16_t. Buffer length incorrect: %zu\n", buf.len);
276 exit(EXIT_FAILURE);
277 }
278
279 uint16_t x;
280 memcpy(&x, buf.buf, sizeof x);
281 return x;
282}
283
284Buffer uint32_t_serialize(uint32_t n) {
285 return to_buffer(&n, sizeof(uint32_t));
286}
287
288uint32_t uint32_t_deserialize(Buffer buf) {
289 exists(buf.buf);
290
291 if (buf.len != sizeof(uint32_t)) {
292 log(FATAL, "Could not deserialize uint32_t. Buffer length incorrect: %zu\n", buf.len);
293 exit(EXIT_FAILURE);
294 }
295
296 uint32_t x;
297 memcpy(&x, buf.buf, sizeof x);
298 return x;
299}
300
301SafeStr atoss(Str str) {
302 return (SafeStr) {
303 .str = str,
304 .len = strlen(str),
305 };
306}
307
308size_t min(size_t l, size_t r) {
309 return l < r ? l : r;
310}
311
312
313LazyBuffer open(Str fpath) {
314 FILE* f = fopen(fpath, "r");
315 exists(f);
316 fseek(f, 0, SEEK_END);
317 size_t size = (size_t)ftell(f);
318 fseek(f, 0, SEEK_SET);
319 return (LazyBuffer){
320 .fptr = f,
321 .buf = {0},
322 .len = 0,
323 .position = 0,
324 .size = size,
325 };
326}
327
328LazyBuffer next_chunk(LazyBuffer b) {
329 exists(b.fptr);
330
331 size_t read_len = min(b.size - b.position, CHUNK_SIZE);
332 if (read_len == 0) {
333 b.len = 0;
334 return b;
335 }
336 size_t count = fread(b.buf, sizeof(Byte), read_len, b.fptr);
337
338 if (count != read_len) {
339 log(FATAL, "Error reading file. Expected to read %zu bytes, got %zu\n", read_len, count);
340 exit(EXIT_FAILURE);
341 }
342
343 b.position += read_len;
344 b.len = read_len;
345 return b;
346}