2 fuse_xattrs - Add xattrs support using sidecar files
4 Copyright (C) 2016 Felipe Barriga Richards <felipe {at} felipebarriga.cl>
6 This program can be distributed under the terms of the GNU GPL.
16 #include "binary_storage.h"
18 #include "fuse_xattrs_config.h"
20 #include <attr/xattr.h>
22 struct on_memory_attr {
30 void __print_on_memory_attr(struct on_memory_attr *attr)
33 char *sanitized_value = sanitize_value(attr->value, attr->value_size);
34 debug_print("--------------\n");
35 debug_print("name size: %hu\n", attr->name_size);
36 debug_print("name: '%s'\n", attr->name);
37 debug_print("value size: %zu\n", attr->value_size);
38 debug_print("sanitized_value: '%s'\n", sanitized_value);
39 debug_print("--------------\n");
40 free(sanitized_value);
44 void __free_on_memory_attr(struct on_memory_attr *attr)
46 if(attr->name != NULL)
49 if(attr->value != NULL)
55 char *__read_file(const char *path, int *buffer_size)
57 FILE *file = fopen(path, "r");
61 debug_print("file not found: %s\n", path);
62 *buffer_size = -ENOENT;
66 debug_print("file found, reading it: %s\n", path);
68 fseek(file, 0, SEEK_END);
69 *buffer_size = (int)ftell(file);
71 if (*buffer_size == -1) {
72 error_print("error: path: %s, size: %d, errno=%d\n", path, *buffer_size, errno);
78 if (*buffer_size > MAX_METADATA_SIZE) {
79 error_print("metadata file too big. path: %s, size: %d\n", path, *buffer_size);
80 *buffer_size = -ENOSPC;
85 if (*buffer_size == 0) {
86 debug_print("empty file.\n");
87 *buffer_size = -ENOENT;
91 assert(*buffer_size > 0);
92 size_t _buffer_size = (size_t) *buffer_size;
94 fseek(file, 0, SEEK_SET);
95 buffer = malloc(_buffer_size);
97 *buffer_size = -ENOMEM;
98 error_print("cannot allocate memory.\n");
103 memset(buffer, '\0', _buffer_size);
104 fread(buffer, 1, _buffer_size, file);
110 char *__read_file_sidecar(const char *path, int *buffer_size)
112 char *sidecar_path = get_sidecar_path(path);
113 debug_print("path=%s sidecar_path=%s\n", path, sidecar_path);
115 char *buffer = __read_file(sidecar_path, buffer_size);
120 int __cmp_name(const char *name, size_t name_length, struct on_memory_attr *attr)
122 if (attr->name_size == name_length && memcmp(attr->name, name, name_length) == 0) {
123 debug_print("match: name=%s, name_length=%zu\n", name, name_length);
124 __print_on_memory_attr(attr);
128 debug_print("doesn't match: name=%s, name_length=%zu\n", name, name_length);
129 __print_on_memory_attr(attr);
134 struct on_memory_attr *__read_on_memory_attr(size_t *offset, char *buffer, size_t buffer_size)
136 debug_print("offset=%zu\n", *offset);
137 struct on_memory_attr *attr = malloc(sizeof(struct on_memory_attr));
141 ////////////////////////////////
143 size_t data_size = sizeof(u_int16_t);
144 if (*offset + data_size > buffer_size) {
145 error_print("Error, sizes doesn't match.\n");
146 __free_on_memory_attr(attr);
149 memcpy(&attr->name_size, buffer + *offset, data_size);
150 *offset += data_size;
151 debug_print("attr->name_size=%hu\n", attr->name_size);
153 ////////////////////////////////
155 data_size = attr->name_size;
156 if (*offset + data_size > buffer_size) {
157 error_print("Error, sizes doesn't match.\n");
158 __free_on_memory_attr(attr);
161 attr->name = malloc(data_size);
162 memcpy(attr->name, buffer + *offset, data_size);
163 *offset += data_size;
165 ////////////////////////////////
167 data_size = sizeof(size_t);
168 if (*offset + data_size > buffer_size) {
169 error_print("Error, sizes doesn't match.\n");
170 __free_on_memory_attr(attr);
173 memcpy(&attr->value_size, buffer + *offset, data_size);
174 *offset += data_size;
175 debug_print("attr->value_size=%zu\n", attr->value_size);
177 ////////////////////////////////
179 data_size = attr->value_size;
180 if (*offset + data_size > buffer_size) {
181 error_print("Error, sizes doesn't match. data_size=%zu buffer_size=%zu\n",
182 data_size, buffer_size);
184 __free_on_memory_attr(attr);
187 attr->value = malloc(data_size);
188 memcpy(attr->value, buffer + *offset, data_size);
189 *offset += data_size;
194 int __write_to_file(FILE *file, const char *name, const char *value, const size_t value_size)
196 const u_int16_t name_size = (int) strlen(name) + 1;
199 char *sanitized_value = sanitize_value(value, value_size);
200 debug_print("name='%s' name_size=%zu sanitized_value='%s' value_size=%zu\n", name, name_size, sanitized_value, value_size);
201 free(sanitized_value);
205 if (fwrite(&name_size, sizeof(u_int16_t), 1, file) != 1) {
208 if (fwrite(name, name_size, 1, file) != 1) {
213 if (fwrite(&value_size, sizeof(size_t), 1, file) != 1) {
216 // write value content only if we have something to write.
217 if (value_size > 0) {
218 if (fwrite(value, value_size, 1, file) != 1) {
228 * @param path - path to file.
229 * @param name - attribute name. string null terminated. size <= XATTR_NAME_MAX bytes
230 * @param value - attribute value. size < XATTR_SIZE_MAX
232 * @param flags - XATTR_CREATE and/or XATTR_REPLACE
233 * @return On success, zero is returned. On failure, -errno is returnted.
235 int binary_storage_write_key(const char *path, const char *name, const char *value, size_t size, int flags)
238 char *sanitized_value = sanitize_value(value, size);
239 debug_print("path=%s name=%s sanitized_value=%s size=%zu flags=%d\n", path, name, sanitized_value, size, flags);
240 free(sanitized_value);
244 char *buffer = __read_file_sidecar(path, &buffer_size);
246 if (buffer == NULL && buffer_size == -ENOENT && flags & XATTR_REPLACE) {
247 error_print("No xattr. (flag XATTR_REPLACE)");
251 if (buffer == NULL && buffer_size != -ENOENT) {
256 char *sidecar_path = get_sidecar_path(path);
257 FILE *file = fopen(sidecar_path, "w");
260 if (buffer == NULL) {
261 debug_print("new file, writing directly...\n");
262 status = __write_to_file(file, name, value, size);
268 assert(buffer_size >= 0);
269 size_t _buffer_size = (size_t)buffer_size;
273 size_t name_len = strlen(name) + 1; // null byte
275 while(offset < _buffer_size)
277 debug_print("replaced=%d offset=%zu buffer_size=%zu\n", replaced, offset, _buffer_size);
278 struct on_memory_attr *attr = __read_on_memory_attr(&offset, buffer, _buffer_size);
280 // FIXME: handle attr == NULL
281 assert(attr != NULL);
283 if (memcmp(attr->name, name, name_len) == 0) {
284 assert(replaced == 0);
285 if (flags & XATTR_CREATE) {
286 error_print("Key already exists. (flag XATTR_CREATE)");
287 status = __write_to_file(file, attr->name, attr->value, attr->value_size);
291 status = __write_to_file(file, name, value, size);
296 status = __write_to_file(file, attr->name, attr->value, attr->value_size);
299 __free_on_memory_attr(attr);
302 if (replaced == 0 && res == 0) {
303 if (flags & XATTR_REPLACE) {
304 error_print("Key doesn't exists. (flag XATTR_REPLACE)");
307 status = __write_to_file(file, name, value, size);
317 int binary_storage_read_key(const char *path, const char *name, char *value, size_t size)
320 char *buffer = __read_file_sidecar(path, &buffer_size);
322 if (buffer == NULL) {
323 if (buffer_size == -ENOENT) {
328 assert(buffer_size >= 0);
329 size_t _buffer_size = (size_t)buffer_size;
332 memset(value, '\0', size);
335 size_t name_len = strlen(name) + 1; // null byte \0
337 while(offset < _buffer_size)
339 struct on_memory_attr *attr = __read_on_memory_attr(&offset, buffer, _buffer_size);
345 if (__cmp_name(name, name_len, attr) == 1) {
346 int value_size = (int)attr->value_size;
350 } else if (attr->value_size <= size) {
351 memcpy(value, attr->value, attr->value_size);
354 error_print("error, attr->value_size=%zu > size=%zu\n", attr->value_size, size);
358 __free_on_memory_attr(attr);
361 __free_on_memory_attr(attr);
368 int binary_storage_list_keys(const char *path, char *list, size_t size)
371 char *buffer = __read_file_sidecar(path, &buffer_size);
373 if (buffer == NULL) {
374 debug_print("buffer == NULL buffer_size=%d\n", buffer_size);
375 if (buffer_size == -ENOENT) {
381 assert(buffer_size > 0);
382 size_t _buffer_size = (size_t)buffer_size;
385 memset(list, '\0', size);
390 while(offset < _buffer_size)
392 struct on_memory_attr *attr = __read_on_memory_attr(&offset, buffer, _buffer_size);
399 if (attr->name_size + res > size) {
400 error_print("Not enough memory allocated. allocated=%zu required=%ld\n",
401 size, attr->name_size + res);
402 __free_on_memory_attr(attr);
406 memcpy(list + res, attr->name, attr->name_size);
407 res += attr->name_size;
410 res += attr->name_size;
412 __free_on_memory_attr(attr);
416 if (size == 0 && res > XATTR_LIST_MAX) {
417 // FIXME: we should return the size or an error ?
424 int binary_storage_remove_key(const char *path, const char *name)
426 debug_print("path=%s name=%s\n", path, name);
428 char *buffer = __read_file_sidecar(path, &buffer_size);
430 if (buffer == NULL) {
433 assert(buffer_size > 0);
434 size_t _buffer_size = (size_t) buffer_size;
436 char *sidecar_path = get_sidecar_path(path);
437 FILE *file = fopen(sidecar_path, "w");
441 size_t name_len = strlen(name) + 1; // null byte \0
444 while(offset < _buffer_size)
446 debug_print("removed=%d offset=%zu buffer_size=%zu\n", removed, offset, _buffer_size);
448 struct on_memory_attr *attr = __read_on_memory_attr(&offset, buffer, _buffer_size);
450 error_print("error reading file. corrupted ?");
454 if (memcmp(attr->name, name, name_len) == 0) {
457 int status = __write_to_file(file, attr->name, attr->value, attr->value_size);
460 __free_on_memory_attr(attr);
465 debug_print("key removed successfully.\n");
466 } else if (removed == 0) {
467 error_print("key not found.\n");
470 debug_print("removed %d keys (was duplicated)\n", removed);