/* SPDX-License-Identifier: GPL-3.0-or-later */ /* * filemap_xattr.c * * Copyright (C) 2022 Enno Boland */ #include "fstree.h" #include "mkfs.h" #include #define NEW_FILE_START "# file: " // Taken from attr-2.5.1/tools/setfattr.c static char * decode(const char *value, size_t *size) { char *decoded = NULL; if (*size == 0) return strdup(""); if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X')) { *size = ((*size) - 2) / 2; decoded = realloc(decoded, *size); if (decoded == NULL) { return NULL; } if (hex_decode(value + 2, (*size) * 2, decoded, *size)) { fprintf(stderr, "bad input encoding\n"); free(decoded); return NULL; } } else if (value[0] == '0' && (value[1] == 's' || value[1] == 'S')) { size_t input_len = *size - 2; *size = (input_len / 4) * 3; decoded = realloc(decoded, *size); if (decoded == NULL) { return NULL; } if (base64_decode(value + 2, input_len, decoded, size)) { free(decoded); fprintf(stderr, "bad input encoding\n"); return NULL; } } else { const char *v = value, *end = value + *size; char *d; if (end > v + 1 && *v == '"' && *(end - 1) == '"') { v++; end--; } decoded = realloc(decoded, *size); if (decoded == NULL) { return NULL; } d = decoded; while (v < end) { if (v[0] == '\\') { if (v[1] == '\\' || v[1] == '"') { *d++ = *++v; v++; } else if (v[1] >= '0' && v[1] <= '7') { int c = 0; v++; c = (*v++ - '0'); if (*v >= '0' && *v <= '7') c = (c << 3) + (*v++ - '0'); if (*v >= '0' && *v <= '7') c = (c << 3) + (*v++ - '0'); *d++ = c; } else *d++ = *v++; } else *d++ = *v++; } *size = d - decoded; } return decoded; } static int parse_file_name(char *line, struct XattrMap *map) { char *p; struct XattrMapPattern *current_file; char *file_name = &line[strlen(NEW_FILE_START)]; p = strchr(file_name, '\n'); if (p != NULL) { *p = '\0'; } file_name = strdup(file_name); if (file_name == NULL) { return -1; } current_file = calloc(1, sizeof(struct XattrMapPattern)); if (current_file == NULL) { free(file_name); return -1; } current_file->next = map->patterns; map->patterns = current_file; canonicalize_name(file_name); current_file->path = file_name; return 0; } static int parse_xattr(char *key_start, char *value_start, struct XattrMap *map) { char *p; size_t len; struct XattrMapPattern *current_pattern = map->patterns; struct XattrMapEntry *current_entry; *value_start = '\0'; value_start += 1; p = strchr(value_start, '\n'); if (p != NULL) { *p = '\0'; } current_entry = calloc(1, sizeof(struct XattrMapEntry)); if (current_entry == NULL) { return -1; } current_entry->next = current_pattern->entries; current_pattern->entries = current_entry; current_entry->key = strdup(key_start); len = strlen(value_start); current_entry->value = decode(value_start, &len); current_entry->value_len = len; return 0; } void * xattr_open_map_file(const char *path) { struct XattrMap *map; char *line = NULL; size_t line_size; char *p = NULL; FILE *file = fopen(path, "r"); if (file == NULL) { return NULL; } map = calloc(1, sizeof(struct XattrMap)); if (map == NULL) { fclose(file); return NULL; } while (getline(&line, &line_size, file) != -1) { if (strncmp(NEW_FILE_START, line, strlen(NEW_FILE_START)) == 0) { if (parse_file_name(line, map) < 0) { fclose(file); xattr_close_map_file(map); return NULL; } } else if ((p = strchr(line, '=')) && map->patterns) { if (parse_xattr(line, p, map) < 0) { fclose(file); xattr_close_map_file(map); return NULL; } } } free(line); fclose(file); return map; } void xattr_close_map_file(void *xattr_map) { struct XattrMap *map = xattr_map; while (map->patterns != NULL) { struct XattrMapPattern *file = map->patterns; map->patterns = file->next; while (file->entries != NULL) { struct XattrMapEntry *entry = file->entries; file->entries = entry->next; free(entry->key); entry->key = NULL; free(entry->value); entry->value = NULL; free(entry); } free(file->path); file->path = NULL; free(file); } free(xattr_map); } int xattr_apply_map_file(char *path, void *map, sqfs_xattr_writer_t *xwr) { struct XattrMap *xattr_map = map; int ret = 0; const struct XattrMapPattern *pat; const struct XattrMapEntry *entry; for (pat = xattr_map->patterns; pat != NULL; pat = pat->next) { char *patstr = pat->path; const char *stripped = path; if (patstr[0] != '/' && stripped[0] == '/') { stripped++; } if (strcmp(patstr, stripped) == 0) { printf("Applying xattrs for %s", path); for (entry = pat->entries; entry != NULL; entry = entry->next) { printf(" %s = \n", entry->key); fwrite(entry->value, entry->value_len, 1, stdout); puts("\n"); ret = sqfs_xattr_writer_add( xwr, entry->key, entry->value, entry->value_len); if (ret < 0) { return ret; } } } } return ret; }