ensure paret directories for sidecars
[rrq/fuse_xattrs.git] / binary_storage.c
1 /*
2   fuse_xattrs - Add xattrs support using sidecar files
3
4   Copyright (C) 2016  Felipe Barriga Richards <felipe {at} felipebarriga.cl>
5
6   This program can be distributed under the terms of the GNU GPL.
7   See the file COPYING.
8 */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <assert.h>
15 #include <unistd.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18
19 #include "binary_storage.h"
20 #include "utils.h"
21 #include "fuse_xattrs_config.h"
22 #include "stringmem.h"
23
24 #include <sys/xattr.h>
25
26 #ifndef ENOATTR
27     #define ENOATTR ENODATA
28 #endif
29
30 struct on_memory_attr {
31     u_int16_t name_size;
32     size_t value_size;
33
34     char *name;
35     char *value;
36 };
37
38 void __print_on_memory_attr(struct on_memory_attr *attr)
39 {
40 #ifdef DEBUG
41     char *sanitized_value = sanitize_value(attr->value, attr->value_size);
42     debug_print("--------------\n");
43     debug_print("name size: %hu\n", attr->name_size);
44     debug_print("name: '%s'\n", attr->name);
45     debug_print("value size: %zu\n", attr->value_size);
46     debug_print("sanitized_value: '%s'\n", sanitized_value);
47     debug_print("--------------\n");
48     strfree(sanitized_value);
49 #endif
50 }
51
52 void __free_on_memory_attr(struct on_memory_attr *attr)
53 {
54     if(attr->name != NULL)
55         strfree(attr->name);
56
57     if(attr->value != NULL)
58         strfree(attr->value);
59
60     free(attr);
61 }
62
63 char *__read_file(const char *path, int *buffer_size)
64 {
65     FILE *file = fopen(path, "r");
66     char *buffer = NULL;
67
68     if (file == NULL) {
69         debug_print("file not found: %s\n", path);
70         *buffer_size = -ENOENT;
71         return NULL;
72     }
73
74     debug_print("file found, reading it: %s\n", path);
75
76     fseek(file, 0, SEEK_END);
77     *buffer_size = (int)ftell(file);
78
79     if (*buffer_size == -1) {
80         error_print("error: path: %s, size: %d, errno=%d\n", path, *buffer_size, errno);
81         *buffer_size = errno;
82         fclose(file);
83         return NULL;
84     }
85
86     if (*buffer_size > MAX_METADATA_SIZE) {
87         error_print("metadata file too big. path: %s, size: %d\n", path, *buffer_size);
88         *buffer_size = -ENOSPC;
89         fclose(file);
90         return NULL;
91     }
92
93     if (*buffer_size == 0) {
94         debug_print("empty file.\n");
95         *buffer_size = -ENOENT;
96         fclose(file);
97         return NULL;
98     }
99     assert(*buffer_size > 0);
100     size_t _buffer_size = (size_t) *buffer_size;
101
102     fseek(file, 0, SEEK_SET);
103     buffer = malloc(_buffer_size);
104     if (buffer == NULL) {
105         *buffer_size = -ENOMEM;
106         error_print("cannot allocate memory.\n");
107         fclose(file);
108         return NULL;
109     }
110
111     memset(buffer, '\0', _buffer_size);
112     fread(buffer, 1, _buffer_size, file);
113     fclose(file);
114
115     return buffer;
116 }
117
118 char *__read_file_sidecar(const char *path, int *buffer_size)
119 {
120     char *sidecar_path = get_sidecar_path(path);
121     debug_print("path=%s sidecar_path=%s\n", path, sidecar_path);
122
123     char *buffer = __read_file(sidecar_path, buffer_size);
124     strfree (sidecar_path);
125     return buffer;
126 }
127
128 int __cmp_name(const char *name, size_t name_length, struct on_memory_attr *attr)
129 {
130     if (attr->name_size == name_length && memcmp(attr->name, name, name_length) == 0) {
131         debug_print("match: name=%s, name_length=%zu\n", name, name_length);
132         __print_on_memory_attr(attr);
133         return 1;
134     }
135
136     debug_print("doesn't match: name=%s, name_length=%zu\n", name, name_length);
137     __print_on_memory_attr(attr);
138
139     return 0;
140 }
141
142 struct on_memory_attr *__read_on_memory_attr(size_t *offset, char *buffer, size_t buffer_size)
143 {
144     debug_print("offset=%zu\n", *offset);
145     struct on_memory_attr *attr = malloc(sizeof(struct on_memory_attr));
146     attr->name = NULL;
147     attr->value = NULL;
148
149     ////////////////////////////////
150     // Read name size
151     size_t data_size = sizeof(u_int16_t);
152     if (*offset + data_size > buffer_size) {
153         error_print("Error, sizes doesn't match.\n");
154         __free_on_memory_attr(attr);
155         return NULL;
156     }
157     memcpy(&attr->name_size, buffer + *offset, data_size);
158     *offset += data_size;
159     debug_print("attr->name_size=%hu\n", attr->name_size);
160
161     ////////////////////////////////
162     // Read name data
163     data_size = attr->name_size;
164     if (*offset + data_size > buffer_size) {
165         error_print("Error, sizes doesn't match.\n");
166         __free_on_memory_attr(attr);
167         return NULL;
168     }
169     attr->name = malloc(data_size);
170     memcpy(attr->name, buffer + *offset, data_size);
171     *offset += data_size;
172
173     ////////////////////////////////
174     // Read value size
175     data_size = sizeof(size_t);
176     if (*offset + data_size > buffer_size) {
177         error_print("Error, sizes doesn't match.\n");
178         __free_on_memory_attr(attr);
179         return NULL;
180     }
181     memcpy(&attr->value_size, buffer + *offset, data_size);
182     *offset += data_size;
183     debug_print("attr->value_size=%zu\n", attr->value_size);
184
185     ////////////////////////////////
186     // Read value data
187     data_size = attr->value_size;
188     if (*offset + data_size > buffer_size) {
189         error_print("Error, sizes doesn't match. data_size=%zu buffer_size=%zu\n",
190             data_size, buffer_size);
191
192         __free_on_memory_attr(attr);
193         return NULL;
194     }
195     attr->value = malloc(data_size);
196     memcpy(attr->value, buffer + *offset, data_size);
197     *offset += data_size;
198
199     return attr;
200 }
201
202 int __write_to_file(FILE *file, const char *name, const char *value, const size_t value_size)
203 {
204     const u_int16_t name_size = (int) strlen(name) + 1;
205
206 #ifdef DEBUG
207     char *sanitized_value = sanitize_value(value, value_size);
208     debug_print("name='%s' name_size=%hu sanitized_value='%s' value_size=%zu\n", name, name_size, sanitized_value, value_size);
209     strfree(sanitized_value);
210 #endif
211
212     // write name
213     if (fwrite(&name_size, sizeof(u_int16_t), 1, file) != 1) {
214         return -1;
215     }
216     if (fwrite(name, name_size, 1, file) != 1) {
217         return -1;
218     }
219
220     // write value
221     if (fwrite(&value_size, sizeof(size_t), 1, file) != 1) {
222         return -1;
223     }
224     // write value content only if we have something to write.
225     if (value_size > 0) {
226         if (fwrite(value, value_size, 1, file) != 1) {
227             return -1;
228         }
229     }
230
231     return 0;
232 }
233
234 static int ensure_dirs(char *path) {
235     int n = strlen( path );
236     char *p = stralloc( n+1 );
237     memcpy( p, path, n+1 );
238     char *e = p + 1;
239     for ( ;; ) {
240         while ( *e && *e != '/' ) e++;
241         if ( *e ) {
242             *e = 0;
243             if ( access( p, F_OK ) && mkdir( p, 0777 ) ) {
244                 return 1;
245             }
246             *(e++) = '/';
247         } else {
248             return 0;
249         }
250     }
251 }
252
253 /**
254  *
255  * @param path - path to file.
256  * @param name - attribute name. string null terminated. size <= XATTR_NAME_MAX bytes
257  * @param value - attribute value. size < XATTR_SIZE_MAX
258  * @param size
259  * @param flags - XATTR_CREATE and/or XATTR_REPLACE
260  * @return On success, zero is returned.  On failure, -errno is returned.
261  */
262 int binary_storage_write_key(const char *path, const char *name, const char *value, size_t size, int flags)
263 {
264 #ifdef DEBUG
265     char *sanitized_value = sanitize_value(value, size);
266     debug_print("path=%s name=%s sanitized_value=%s size=%zu flags=%d\n", path, name, sanitized_value, size, flags);
267     strfree(sanitized_value);
268 #endif
269
270     int buffer_size;
271     char *buffer = __read_file_sidecar(path, &buffer_size);
272
273     if (buffer == NULL && buffer_size == -ENOENT && flags & XATTR_REPLACE) {
274         error_print("No xattr. (flag XATTR_REPLACE)");
275         return -ENOATTR;
276     }
277
278     if (buffer == NULL && buffer_size != -ENOENT) {
279         return buffer_size;
280     }
281
282     int status;
283     char *sidecar_path = get_sidecar_path(path);
284
285     if ( ensure_dirs( sidecar_path ) ) {
286         return -ENOATTR;
287     }
288
289     FILE *file = fopen(sidecar_path, "w");
290     strfree(sidecar_path);
291
292     if (buffer == NULL) {
293         debug_print("new file, writing directly...\n");
294         status = __write_to_file(file, name, value, size);
295         assert(status == 0);
296         fclose(file);
297         strfree(buffer);
298         return 0;
299     }
300     assert(buffer_size >= 0);
301     size_t _buffer_size = (size_t)buffer_size;
302
303     int res = 0;
304     size_t offset = 0;
305     size_t name_len = strlen(name) + 1; // null byte
306     int replaced = 0;
307     while(offset < _buffer_size)
308     {
309         debug_print("replaced=%d offset=%zu buffer_size=%zu\n", replaced, offset, _buffer_size);
310         struct on_memory_attr *attr = __read_on_memory_attr(&offset, buffer, _buffer_size);
311
312         // FIXME: handle attr == NULL
313         assert(attr != NULL);
314
315         if (memcmp(attr->name, name, name_len) == 0) {
316             assert(replaced == 0);
317             if (flags & XATTR_CREATE) {
318                 error_print("Key already exists. (flag XATTR_CREATE)");
319                 status = __write_to_file(file, attr->name, attr->value, attr->value_size);
320                 assert(status == 0);
321                 res = -EEXIST;
322             } else {
323                 status = __write_to_file(file, name, value, size);
324                 assert(status == 0);
325                 replaced = 1;
326             }
327         } else {
328             status = __write_to_file(file, attr->name, attr->value, attr->value_size);
329             assert(status == 0);
330         }
331         __free_on_memory_attr(attr);
332     }
333
334     if (replaced == 0 && res == 0) {
335         if (flags & XATTR_REPLACE) {
336             error_print("Key doesn't exists. (flag XATTR_REPLACE)");
337             res = -ENODATA;
338         } else {
339             status = __write_to_file(file, name, value, size);
340             assert(status == 0);
341         }
342     }
343
344     fclose(file);
345     strfree(buffer);
346     return res;
347 }
348
349 int binary_storage_read_key(const char *path, const char *name, char *value, size_t size)
350 {
351     int buffer_size;
352     char *buffer = __read_file_sidecar(path, &buffer_size);
353     
354     if (buffer == NULL) {
355         if (buffer_size == -ENOENT) {
356             return -ENOATTR;
357         }
358         return buffer_size;
359     }
360     assert(buffer_size >= 0);
361     size_t _buffer_size = (size_t)buffer_size;
362
363     if (size > 0) {
364         memset(value, '\0', size);
365     }
366
367     size_t name_len = strlen(name) + 1; // null byte \0
368     size_t offset = 0;
369     while(offset < _buffer_size)
370     {
371         struct on_memory_attr *attr = __read_on_memory_attr(&offset, buffer, _buffer_size);
372         if (attr == NULL) {
373             strfree(buffer);
374             return -EILSEQ;
375         }
376
377         if (__cmp_name(name, name_len, attr) == 1) {
378             int value_size = (int)attr->value_size;
379             int res;
380             if (size == 0) {
381                 res = value_size;
382             } else if (attr->value_size <= size) {
383                 memcpy(value, attr->value, attr->value_size);
384                 res = value_size;
385             } else {
386                 error_print("error, attr->value_size=%zu > size=%zu\n", attr->value_size, size);
387                 res = -ERANGE;
388             }
389             strfree(buffer);
390             __free_on_memory_attr(attr);
391             return res;
392         }
393         __free_on_memory_attr(attr);
394     }
395     strfree(buffer);
396
397     return -ENOATTR;
398 }
399
400 int binary_storage_list_keys(const char *path, char *list, size_t size)
401 {
402     int buffer_size;
403     char *buffer = __read_file_sidecar(path, &buffer_size);
404
405     if (buffer == NULL) {
406         debug_print("buffer == NULL buffer_size=%d\n", buffer_size);
407         if (buffer_size == -ENOENT) {
408             return 0;
409         }
410         return buffer_size;
411     }
412
413     assert(buffer_size > 0);
414     size_t _buffer_size = (size_t)buffer_size;
415
416     if (size > 0) {
417         memset(list, '\0', size);
418     }
419
420     size_t res = 0;
421     size_t offset = 0;
422     while(offset < _buffer_size)
423     {
424         struct on_memory_attr *attr = __read_on_memory_attr(&offset, buffer, _buffer_size);
425         if (attr == NULL) {
426             strfree(buffer);
427             return -EILSEQ;
428         }
429
430         if (size > 0) {
431             if (attr->name_size + res > size) {
432                 error_print("Not enough memory allocated. allocated=%zu required=%ld\n",
433                             size, attr->name_size + res);
434                 __free_on_memory_attr(attr);
435                 strfree(buffer);
436                 return -ERANGE;
437             } else {
438                 memcpy(list + res, attr->name, attr->name_size);
439                 res += attr->name_size;
440             }
441         } else {
442             res += attr->name_size;
443         }
444         __free_on_memory_attr(attr);
445     }
446     strfree(buffer);
447
448     if (size == 0 && res > XATTR_LIST_MAX) {
449         // FIXME: we should return the size or an error ?
450         return -ENOSPC;
451     }
452
453     return (int)res;
454 }
455
456 int binary_storage_remove_key(const char *path, const char *name)
457 {
458     debug_print("path=%s name=%s\n", path, name);
459     int buffer_size;
460     char *buffer = __read_file_sidecar(path, &buffer_size);
461
462     if (buffer == NULL) {
463         return buffer_size;
464     }
465     assert(buffer_size > 0);
466     size_t _buffer_size = (size_t) buffer_size;
467
468     char *sidecar_path = get_sidecar_path(path);
469     FILE *file = fopen(sidecar_path, "w");
470     strfree(sidecar_path);
471
472     size_t offset = 0;
473     size_t name_len = strlen(name) + 1; // null byte \0
474
475     int removed = 0;
476     while(offset < _buffer_size)
477     {
478         debug_print("removed=%d offset=%zu buffer_size=%zu\n", removed, offset, _buffer_size);
479
480         struct on_memory_attr *attr = __read_on_memory_attr(&offset, buffer, _buffer_size);
481         if (attr == NULL) {
482             error_print("error reading file. corrupted ?");
483             break;
484         }
485
486         if (memcmp(attr->name, name, name_len) == 0) {
487             removed++;
488         } else {
489             int status = __write_to_file(file, attr->name, attr->value, attr->value_size);
490             assert(status == 0);
491         }
492         __free_on_memory_attr(attr);
493     }
494
495     int res = 0;
496     if (removed == 1) {
497         debug_print("key removed successfully.\n");
498     } else if (removed == 0) {
499         error_print("key not found.\n");
500         res = -ENOATTR;
501     } else {
502         debug_print("removed %d keys (was duplicated)\n", removed);
503         res = -EILSEQ;
504     }
505
506     fclose(file);
507     strfree(buffer);
508     return res;
509 }