| /* |
| * Create a squashfs filesystem. This is a highly compressed read only |
| * filesystem. |
| * |
| * Copyright (c) 2008, 2009, 2010, 2012, 2014 |
| * Phillip Lougher <phillip@squashfs.org.uk> |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version 2, |
| * or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| * |
| * xattr.c |
| */ |
| |
| #ifndef linux |
| #define __BYTE_ORDER BYTE_ORDER |
| #define __BIG_ENDIAN BIG_ENDIAN |
| #define __LITTLE_ENDIAN LITTLE_ENDIAN |
| #else |
| #include <endian.h> |
| #endif |
| |
| #define TRUE 1 |
| #define FALSE 0 |
| |
| #include <unistd.h> |
| #include <stdio.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include <dirent.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <sys/xattr.h> |
| |
| #ifdef XATTR_NOFOLLOW /* Apple's xattrs */ |
| #define llistxattr(path_, buf_, sz_) \ |
| listxattr(path_, buf_, sz_, XATTR_NOFOLLOW) |
| #define lgetxattr(path_, name_, val_, sz_) \ |
| getxattr(path_, name_, val_, sz_, 0, XATTR_NOFOLLOW) |
| #endif |
| |
| #include "squashfs_fs.h" |
| #include "squashfs_swap.h" |
| #include "mksquashfs.h" |
| #include "xattr.h" |
| #include "error.h" |
| #include "progressbar.h" |
| |
| /* ANDROID CHANGES START*/ |
| #ifdef ANDROID |
| #include "android.h" |
| #ifdef __ANDROID__ |
| #include <linux/capability.h> |
| #else |
| #include <private/android_filesystem_capability.h> |
| #endif |
| static struct selabel_handle *sehnd = NULL; |
| #endif |
| /* ANDROID CHANGES END */ |
| |
| /* compressed xattr table */ |
| static char *xattr_table = NULL; |
| static unsigned int xattr_size = 0; |
| |
| /* cached uncompressed xattr data */ |
| static char *data_cache = NULL; |
| static int cache_bytes = 0, cache_size = 0; |
| |
| /* cached uncompressed xattr id table */ |
| static struct squashfs_xattr_id *xattr_id_table = NULL; |
| static int xattr_ids = 0; |
| |
| /* saved compressed xattr table */ |
| unsigned int sxattr_bytes = 0, stotal_xattr_bytes = 0; |
| |
| /* saved cached uncompressed xattr data */ |
| static char *sdata_cache = NULL; |
| static int scache_bytes = 0; |
| |
| /* saved cached uncompressed xattr id table */ |
| static int sxattr_ids = 0; |
| |
| /* xattr hash table for value duplicate detection */ |
| static struct xattr_list *dupl_value[65536]; |
| |
| /* xattr hash table for id duplicate detection */ |
| static struct dupl_id *dupl_id[65536]; |
| |
| /* file system globals from mksquashfs.c */ |
| extern int no_xattrs, noX; |
| extern long long bytes; |
| extern int fd; |
| extern unsigned int xattr_bytes, total_xattr_bytes; |
| /* ANDROID CHANGES START*/ |
| extern char *context_file; |
| extern char *mount_point; |
| /* ANDROID CHANGES END */ |
| |
| /* helper functions from mksquashfs.c */ |
| extern unsigned short get_checksum(char *, int, unsigned short); |
| extern void write_destination(int, long long, int, void *); |
| extern long long generic_write_table(int, void *, int, void *, int); |
| extern int mangle(char *, char *, int, int, int, int); |
| extern char *pathname(struct dir_ent *); |
| /* ANDROID CHANGES START*/ |
| #ifdef ANDROID |
| extern char *subpathname(struct dir_ent *); |
| #endif |
| /* ANDROID CHANGES END */ |
| |
| /* helper functions and definitions from read_xattrs.c */ |
| extern int read_xattrs_from_disk(int, struct squashfs_super_block *); |
| extern struct xattr_list *get_xattr(int, unsigned int *, int); |
| extern struct prefix prefix_table[]; |
| |
| |
| static int get_prefix(struct xattr_list *xattr, char *name) |
| { |
| int i; |
| |
| xattr->full_name = strdup(name); |
| |
| for(i = 0; prefix_table[i].type != -1; i++) { |
| struct prefix *p = &prefix_table[i]; |
| if(strncmp(xattr->full_name, p->prefix, strlen(p->prefix)) == 0) |
| break; |
| } |
| |
| if(prefix_table[i].type != -1) { |
| xattr->name = xattr->full_name + strlen(prefix_table[i].prefix); |
| xattr->size = strlen(xattr->name); |
| } |
| |
| return prefix_table[i].type; |
| } |
| |
| |
| /* ANDROID CHANGES START*/ |
| #ifdef ANDROID |
| static struct xattr_list *next_xattr_list(int *xattr_count, struct xattr_list **xattrs) { |
| struct xattr_list *x; |
| x = realloc(*xattrs, ++*xattr_count * sizeof(struct xattr_list)); |
| if (x == NULL) MEM_ERROR(); |
| *xattrs = x; |
| return &x[*xattr_count - 1]; |
| } |
| |
| static void read_selinux_xattr_from_sehnd(char *filename, int mode, |
| struct selabel_handle *sehnd, struct xattr_list *xattrs) |
| { |
| char *attr_val; |
| |
| xattrs->type = get_prefix(xattrs, "security.selinux"); |
| attr_val = set_selabel(filename, mode, sehnd); |
| xattrs->value = (void *)attr_val; |
| xattrs->vsize = strlen(attr_val); |
| } |
| |
| static void set_caps_xattr(uint64_t caps, struct xattr_list *xattrs) |
| { |
| struct vfs_cap_data *attr_val; |
| attr_val = malloc(sizeof(*attr_val)); |
| if (attr_val == NULL) MEM_ERROR(); |
| |
| xattrs->type = get_prefix(xattrs, "security.capability"); |
| *attr_val = set_caps(caps); |
| xattrs->value = attr_val; |
| xattrs->vsize = sizeof(*attr_val); |
| } |
| #endif |
| /* ANDROID CHANGES END */ |
| |
| |
| static int read_xattrs_from_system(char *filename, struct xattr_list **xattrs) |
| { |
| ssize_t size, vsize; |
| char *xattr_names, *p; |
| int i; |
| struct xattr_list *xattr_list = NULL; |
| |
| while(1) { |
| size = llistxattr(filename, NULL, 0); |
| if(size <= 0) { |
| if(size < 0 && errno != ENOTSUP) { |
| ERROR_START("llistxattr for %s failed in " |
| "read_attrs, because %s", filename, |
| strerror(errno)); |
| ERROR_EXIT(". Ignoring"); |
| } |
| return 0; |
| } |
| |
| xattr_names = malloc(size); |
| if(xattr_names == NULL) |
| MEM_ERROR(); |
| |
| size = llistxattr(filename, xattr_names, size); |
| if(size < 0) { |
| free(xattr_names); |
| if(errno == ERANGE) |
| /* xattr list grew? Try again */ |
| continue; |
| else { |
| ERROR_START("llistxattr for %s failed in " |
| "read_attrs, because %s", filename, |
| strerror(errno)); |
| ERROR_EXIT(". Ignoring"); |
| return 0; |
| } |
| } |
| |
| break; |
| } |
| |
| for(i = 0, p = xattr_names; p < xattr_names + size; i++) { |
| struct xattr_list *x = realloc(xattr_list, (i + 1) * |
| sizeof(struct xattr_list)); |
| if(x == NULL) |
| MEM_ERROR(); |
| xattr_list = x; |
| |
| xattr_list[i].type = get_prefix(&xattr_list[i], p); |
| p += strlen(p) + 1; |
| if(xattr_list[i].type == -1) { |
| ERROR("Unrecognised xattr prefix %s\n", |
| xattr_list[i].full_name); |
| free(xattr_list[i].full_name); |
| i--; |
| continue; |
| } |
| |
| while(1) { |
| vsize = lgetxattr(filename, xattr_list[i].full_name, |
| NULL, 0); |
| if(vsize < 0) { |
| ERROR_START("lgetxattr failed for %s in " |
| "read_attrs, because %s", filename, |
| strerror(errno)); |
| ERROR_EXIT(". Ignoring"); |
| free(xattr_list[i].full_name); |
| goto failed; |
| } |
| |
| xattr_list[i].value = malloc(vsize); |
| if(xattr_list[i].value == NULL) |
| MEM_ERROR(); |
| |
| vsize = lgetxattr(filename, xattr_list[i].full_name, |
| xattr_list[i].value, vsize); |
| if(vsize < 0) { |
| free(xattr_list[i].value); |
| if(errno == ERANGE) |
| /* xattr grew? Try again */ |
| continue; |
| else { |
| ERROR_START("lgetxattr failed for %s " |
| "in read_attrs, because %s", |
| filename, strerror(errno)); |
| ERROR_EXIT(". Ignoring"); |
| free(xattr_list[i].full_name); |
| goto failed; |
| } |
| } |
| |
| break; |
| } |
| xattr_list[i].vsize = vsize; |
| |
| TRACE("read_xattrs_from_system: filename %s, xattr name %s," |
| " vsize %d\n", filename, xattr_list[i].full_name, |
| xattr_list[i].vsize); |
| } |
| free(xattr_names); |
| *xattrs = xattr_list; |
| return i; |
| |
| failed: |
| while(--i >= 0) { |
| free(xattr_list[i].full_name); |
| free(xattr_list[i].value); |
| } |
| free(xattr_list); |
| free(xattr_names); |
| return 0; |
| } |
| |
| |
| static int get_xattr_size(struct xattr_list *xattr) |
| { |
| int size = sizeof(struct squashfs_xattr_entry) + |
| sizeof(struct squashfs_xattr_val) + xattr->size; |
| |
| if(xattr->type & XATTR_VALUE_OOL) |
| size += XATTR_VALUE_OOL_SIZE; |
| else |
| size += xattr->vsize; |
| |
| return size; |
| } |
| |
| |
| static void *get_xattr_space(unsigned int req_size, long long *disk) |
| { |
| int data_space; |
| unsigned short c_byte; |
| |
| /* |
| * Move and compress cached uncompressed data into xattr table. |
| */ |
| while(cache_bytes >= SQUASHFS_METADATA_SIZE) { |
| if((xattr_size - xattr_bytes) < |
| ((SQUASHFS_METADATA_SIZE << 1)) + 2) { |
| xattr_table = realloc(xattr_table, xattr_size + |
| (SQUASHFS_METADATA_SIZE << 1) + 2); |
| if(xattr_table == NULL) |
| MEM_ERROR(); |
| xattr_size += (SQUASHFS_METADATA_SIZE << 1) + 2; |
| } |
| |
| c_byte = mangle(xattr_table + xattr_bytes + BLOCK_OFFSET, |
| data_cache, SQUASHFS_METADATA_SIZE, |
| SQUASHFS_METADATA_SIZE, noX, 0); |
| TRACE("Xattr block @ 0x%x, size %d\n", xattr_bytes, c_byte); |
| SQUASHFS_SWAP_SHORTS(&c_byte, xattr_table + xattr_bytes, 1); |
| xattr_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET; |
| memmove(data_cache, data_cache + SQUASHFS_METADATA_SIZE, |
| cache_bytes - SQUASHFS_METADATA_SIZE); |
| cache_bytes -= SQUASHFS_METADATA_SIZE; |
| } |
| |
| /* |
| * Ensure there's enough space in the uncompressed data cache |
| */ |
| data_space = cache_size - cache_bytes; |
| if(data_space < req_size) { |
| int realloc_size = req_size - data_space; |
| data_cache = realloc(data_cache, cache_size + |
| realloc_size); |
| if(data_cache == NULL) |
| MEM_ERROR(); |
| cache_size += realloc_size; |
| } |
| |
| if(disk) |
| *disk = ((long long) xattr_bytes << 16) | cache_bytes; |
| cache_bytes += req_size; |
| return data_cache + cache_bytes - req_size; |
| } |
| |
| |
| static struct dupl_id *check_id_dupl(struct xattr_list *xattr_list, int xattrs) |
| { |
| struct dupl_id *entry; |
| int i; |
| unsigned short checksum = 0; |
| |
| /* compute checksum over all xattrs */ |
| for(i = 0; i < xattrs; i++) { |
| struct xattr_list *xattr = &xattr_list[i]; |
| |
| checksum = get_checksum(xattr->full_name, |
| strlen(xattr->full_name), checksum); |
| checksum = get_checksum(xattr->value, |
| xattr->vsize, checksum); |
| } |
| |
| for(entry = dupl_id[checksum]; entry; entry = entry->next) { |
| if (entry->xattrs != xattrs) |
| continue; |
| |
| for(i = 0; i < xattrs; i++) { |
| struct xattr_list *xattr = &xattr_list[i]; |
| struct xattr_list *dup_xattr = &entry->xattr_list[i]; |
| |
| if(strcmp(xattr->full_name, dup_xattr->full_name)) |
| break; |
| |
| if(memcmp(xattr->value, dup_xattr->value, xattr->vsize)) |
| break; |
| } |
| |
| if(i == xattrs) |
| break; |
| } |
| |
| if(entry == NULL) { |
| /* no duplicate exists */ |
| entry = malloc(sizeof(*entry)); |
| if(entry == NULL) |
| MEM_ERROR(); |
| entry->xattrs = xattrs; |
| entry->xattr_list = xattr_list; |
| entry->xattr_id = SQUASHFS_INVALID_XATTR; |
| entry->next = dupl_id[checksum]; |
| dupl_id[checksum] = entry; |
| } |
| |
| return entry; |
| } |
| |
| |
| static void check_value_dupl(struct xattr_list *xattr) |
| { |
| struct xattr_list *entry; |
| |
| if(xattr->vsize < XATTR_VALUE_OOL_SIZE) |
| return; |
| |
| /* Check if this is a duplicate of an existing value */ |
| xattr->vchecksum = get_checksum(xattr->value, xattr->vsize, 0); |
| for(entry = dupl_value[xattr->vchecksum]; entry; entry = entry->vnext) { |
| if(entry->vsize != xattr->vsize) |
| continue; |
| |
| if(memcmp(entry->value, xattr->value, xattr->vsize) == 0) |
| break; |
| } |
| |
| if(entry == NULL) { |
| /* |
| * No duplicate exists, add to hash table, and mark as |
| * requiring writing |
| */ |
| xattr->vnext = dupl_value[xattr->vchecksum]; |
| dupl_value[xattr->vchecksum] = xattr; |
| xattr->ool_value = SQUASHFS_INVALID_BLK; |
| } else { |
| /* |
| * Duplicate exists, make type XATTR_VALUE_OOL, and |
| * remember where the duplicate is |
| */ |
| xattr->type |= XATTR_VALUE_OOL; |
| xattr->ool_value = entry->ool_value; |
| /* on appending don't free duplicate values because the |
| * duplicate value already points to the non-duplicate value */ |
| if(xattr->value != entry->value) { |
| free(xattr->value); |
| xattr->value = entry->value; |
| } |
| } |
| } |
| |
| |
| static int get_xattr_id(int xattrs, struct xattr_list *xattr_list, |
| long long xattr_disk, struct dupl_id *xattr_dupl) |
| { |
| int i, size = 0; |
| struct squashfs_xattr_id *xattr_id; |
| |
| xattr_id_table = realloc(xattr_id_table, (xattr_ids + 1) * |
| sizeof(struct squashfs_xattr_id)); |
| if(xattr_id_table == NULL) |
| MEM_ERROR(); |
| |
| /* get total uncompressed size of xattr data, needed for stat */ |
| for(i = 0; i < xattrs; i++) |
| size += strlen(xattr_list[i].full_name) + 1 + |
| xattr_list[i].vsize; |
| |
| xattr_id = &xattr_id_table[xattr_ids]; |
| xattr_id->xattr = xattr_disk; |
| xattr_id->count = xattrs; |
| xattr_id->size = size; |
| |
| /* |
| * keep track of total uncompressed xattr data, needed for mksquashfs |
| * file system summary |
| */ |
| total_xattr_bytes += size; |
| |
| xattr_dupl->xattr_id = xattr_ids ++; |
| return xattr_dupl->xattr_id; |
| } |
| |
| |
| long long write_xattrs() |
| { |
| unsigned short c_byte; |
| int i, avail_bytes; |
| char *datap = data_cache; |
| long long start_bytes = bytes; |
| struct squashfs_xattr_table header; |
| |
| if(xattr_ids == 0) |
| return SQUASHFS_INVALID_BLK; |
| |
| /* |
| * Move and compress cached uncompressed data into xattr table. |
| */ |
| while(cache_bytes) { |
| if((xattr_size - xattr_bytes) < |
| ((SQUASHFS_METADATA_SIZE << 1)) + 2) { |
| xattr_table = realloc(xattr_table, xattr_size + |
| (SQUASHFS_METADATA_SIZE << 1) + 2); |
| if(xattr_table == NULL) |
| MEM_ERROR(); |
| xattr_size += (SQUASHFS_METADATA_SIZE << 1) + 2; |
| } |
| |
| avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ? |
| SQUASHFS_METADATA_SIZE : cache_bytes; |
| c_byte = mangle(xattr_table + xattr_bytes + BLOCK_OFFSET, datap, |
| avail_bytes, SQUASHFS_METADATA_SIZE, noX, 0); |
| TRACE("Xattr block @ 0x%x, size %d\n", xattr_bytes, c_byte); |
| SQUASHFS_SWAP_SHORTS(&c_byte, xattr_table + xattr_bytes, 1); |
| xattr_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET; |
| datap += avail_bytes; |
| cache_bytes -= avail_bytes; |
| } |
| |
| /* |
| * Write compressed xattr table to file system |
| */ |
| write_destination(fd, bytes, xattr_bytes, xattr_table); |
| bytes += xattr_bytes; |
| |
| /* |
| * Swap if necessary the xattr id table |
| */ |
| for(i = 0; i < xattr_ids; i++) |
| SQUASHFS_INSWAP_XATTR_ID(&xattr_id_table[i]); |
| |
| header.xattr_ids = xattr_ids; |
| header.xattr_table_start = start_bytes; |
| SQUASHFS_INSWAP_XATTR_TABLE(&header); |
| |
| return generic_write_table(xattr_ids * sizeof(struct squashfs_xattr_id), |
| xattr_id_table, sizeof(header), &header, noX); |
| } |
| |
| |
| int generate_xattrs(int xattrs, struct xattr_list *xattr_list) |
| { |
| int total_size, i; |
| int xattr_value_max; |
| void *xp; |
| long long xattr_disk; |
| struct dupl_id *xattr_dupl; |
| |
| /* |
| * check if the file xattrs are a complete duplicate of a pre-existing |
| * id |
| */ |
| xattr_dupl = check_id_dupl(xattr_list, xattrs); |
| if(xattr_dupl->xattr_id != SQUASHFS_INVALID_XATTR) |
| return xattr_dupl->xattr_id; |
| |
| /* |
| * Scan the xattr_list deciding which type to assign to each |
| * xattr. The choice is fairly straightforward, and depends on the |
| * size of each xattr name/value and the overall size of the |
| * resultant xattr list stored in the xattr metadata table. |
| * |
| * Choices are whether to store data inline or out of line. |
| * |
| * The overall goal is to optimise xattr scanning and lookup, and |
| * to enable the file system layout to scale from a couple of |
| * small xattr name/values to a large number of large xattr |
| * names/values without affecting performance. While hopefully |
| * enabling the common case of a couple of small xattr name/values |
| * to be stored efficiently |
| * |
| * Code repeatedly scans, doing the following |
| * move xattr data out of line if it exceeds |
| * xattr_value_max. Where xattr_value_max is |
| * initially XATTR_INLINE_MAX. If the final uncompressed |
| * xattr list is larger than XATTR_TARGET_MAX then more |
| * aggressively move xattr data out of line by repeatedly |
| * setting inline threshold to 1/2, then 1/4, 1/8 of |
| * XATTR_INLINE_MAX until target achieved or there's |
| * nothing left to move out of line |
| */ |
| xattr_value_max = XATTR_INLINE_MAX; |
| while(1) { |
| for(total_size = 0, i = 0; i < xattrs; i++) { |
| struct xattr_list *xattr = &xattr_list[i]; |
| xattr->type &= XATTR_PREFIX_MASK; /* all inline */ |
| if (xattr->vsize > xattr_value_max) |
| xattr->type |= XATTR_VALUE_OOL; |
| |
| total_size += get_xattr_size(xattr); |
| } |
| |
| /* |
| * If the total size of the uncompressed xattr list is <= |
| * XATTR_TARGET_MAX we're done |
| */ |
| if(total_size <= XATTR_TARGET_MAX) |
| break; |
| |
| if(xattr_value_max == XATTR_VALUE_OOL_SIZE) |
| break; |
| |
| /* |
| * Inline target not yet at minimum and so reduce it, and |
| * try again |
| */ |
| xattr_value_max /= 2; |
| if(xattr_value_max < XATTR_VALUE_OOL_SIZE) |
| xattr_value_max = XATTR_VALUE_OOL_SIZE; |
| } |
| |
| /* |
| * Check xattr values for duplicates |
| */ |
| for(i = 0; i < xattrs; i++) { |
| check_value_dupl(&xattr_list[i]); |
| } |
| |
| /* |
| * Add each out of line value to the file system xattr table |
| * if it doesn't already exist as a duplicate |
| */ |
| for(i = 0; i < xattrs; i++) { |
| struct xattr_list *xattr = &xattr_list[i]; |
| |
| if((xattr->type & XATTR_VALUE_OOL) && |
| (xattr->ool_value == SQUASHFS_INVALID_BLK)) { |
| struct squashfs_xattr_val val; |
| int size = sizeof(val) + xattr->vsize; |
| xp = get_xattr_space(size, &xattr->ool_value); |
| val.vsize = xattr->vsize; |
| SQUASHFS_SWAP_XATTR_VAL(&val, xp); |
| memcpy(xp + sizeof(val), xattr->value, xattr->vsize); |
| } |
| } |
| |
| /* |
| * Create xattr list and add to file system xattr table |
| */ |
| get_xattr_space(0, &xattr_disk); |
| for(i = 0; i < xattrs; i++) { |
| struct xattr_list *xattr = &xattr_list[i]; |
| struct squashfs_xattr_entry entry; |
| struct squashfs_xattr_val val; |
| |
| xp = get_xattr_space(sizeof(entry) + xattr->size, NULL); |
| entry.type = xattr->type; |
| entry.size = xattr->size; |
| SQUASHFS_SWAP_XATTR_ENTRY(&entry, xp); |
| memcpy(xp + sizeof(entry), xattr->name, xattr->size); |
| |
| if(xattr->type & XATTR_VALUE_OOL) { |
| int size = sizeof(val) + XATTR_VALUE_OOL_SIZE; |
| xp = get_xattr_space(size, NULL); |
| val.vsize = XATTR_VALUE_OOL_SIZE; |
| SQUASHFS_SWAP_XATTR_VAL(&val, xp); |
| SQUASHFS_SWAP_LONG_LONGS(&xattr->ool_value, xp + |
| sizeof(val), 1); |
| } else { |
| int size = sizeof(val) + xattr->vsize; |
| xp = get_xattr_space(size, &xattr->ool_value); |
| val.vsize = xattr->vsize; |
| SQUASHFS_SWAP_XATTR_VAL(&val, xp); |
| memcpy(xp + sizeof(val), xattr->value, xattr->vsize); |
| } |
| } |
| |
| /* |
| * Add to xattr id lookup table |
| */ |
| return get_xattr_id(xattrs, xattr_list, xattr_disk, xattr_dupl); |
| } |
| |
| |
| int read_xattrs(void *d) |
| { |
| struct dir_ent *dir_ent = d; |
| struct inode_info *inode = dir_ent->inode; |
| char *filename = pathname(dir_ent); |
| /* ANDROID CHANGES START*/ |
| #ifdef ANDROID |
| // NOTE: xattr_list has to point to an array of xattr_list elements |
| struct xattr_list *xattr_list = NULL, *next_xattr = NULL; |
| int xattrs = 0; |
| #else |
| struct xattr_list *xattr_list; |
| int xattrs; |
| #endif |
| /* ANDROID CHANGES END */ |
| |
| if(no_xattrs || IS_PSEUDO(inode) || inode->root_entry) |
| return SQUASHFS_INVALID_XATTR; |
| |
| /* ANDROID CHANGES START*/ |
| #ifdef ANDROID |
| if (context_file) { |
| if (sehnd == NULL) |
| sehnd = get_sehnd(context_file); |
| if (mount_point) { |
| char *mounted_path; |
| alloc_mounted_path(mount_point, subpathname(dir_ent), &mounted_path); |
| next_xattr = next_xattr_list(&xattrs, &xattr_list); |
| read_selinux_xattr_from_sehnd(mounted_path, inode->buf.st_mode, |
| sehnd, next_xattr); |
| free(mounted_path); |
| } else { |
| next_xattr = next_xattr_list(&xattrs, &xattr_list); |
| read_selinux_xattr_from_sehnd(filename, inode->buf.st_mode, |
| sehnd, next_xattr); |
| } |
| } |
| if (dir_ent->capabilities != 0) { |
| next_xattr = next_xattr_list(&xattrs, &xattr_list); |
| set_caps_xattr(dir_ent->capabilities, next_xattr); |
| } |
| #else |
| xattrs = read_xattrs_from_system(filename, &xattr_list); |
| #endif |
| /* ANDROID CHANGES END */ |
| |
| if(xattrs == 0) |
| return SQUASHFS_INVALID_XATTR; |
| |
| return generate_xattrs(xattrs, xattr_list); |
| } |
| |
| |
| /* |
| * Add the existing xattr ids and xattr metadata in the file system being |
| * appended to, to the in-memory xattr cache. This allows duplicate checking to |
| * take place against the xattrs already in the file system being appended to, |
| * and ensures the pre-existing xattrs are written out along with any new xattrs |
| */ |
| int get_xattrs(int fd, struct squashfs_super_block *sBlk) |
| { |
| int ids, res, i, id; |
| unsigned int count; |
| |
| TRACE("get_xattrs\n"); |
| |
| res = read_xattrs_from_disk(fd, sBlk); |
| if(res == SQUASHFS_INVALID_BLK || res == 0) |
| goto done; |
| ids = res; |
| |
| /* |
| * for each xattr id read and construct its list of xattr |
| * name:value pairs, and add them to the in-memory xattr cache |
| */ |
| for(i = 0; i < ids; i++) { |
| struct xattr_list *xattr_list = get_xattr(i, &count, 0); |
| if(xattr_list == NULL) { |
| res = 0; |
| goto done; |
| } |
| id = generate_xattrs(count, xattr_list); |
| |
| /* |
| * Sanity check, the new xattr id should be the same as the |
| * xattr id in the original file system |
| */ |
| if(id != i) { |
| ERROR("BUG, different xattr_id in get_xattrs\n"); |
| res = 0; |
| goto done; |
| } |
| } |
| |
| done: |
| return res; |
| } |
| |
| |
| /* |
| * Save current state of xattrs, needed for restoring state in the event of an |
| * abort in appending |
| */ |
| void save_xattrs() |
| { |
| /* save the current state of the compressed xattr data */ |
| sxattr_bytes = xattr_bytes; |
| stotal_xattr_bytes = total_xattr_bytes; |
| |
| /* |
| * save the current state of the cached uncompressed xattr data. |
| * Note we have to save the contents of the data cache because future |
| * operations will delete the current contents |
| */ |
| sdata_cache = malloc(cache_bytes); |
| if(sdata_cache == NULL) |
| MEM_ERROR(); |
| |
| memcpy(sdata_cache, data_cache, cache_bytes); |
| scache_bytes = cache_bytes; |
| |
| /* save the current state of the xattr id table */ |
| sxattr_ids = xattr_ids; |
| } |
| |
| |
| /* |
| * Restore xattrs in the event of an abort in appending |
| */ |
| void restore_xattrs() |
| { |
| /* restore the state of the compressed xattr data */ |
| xattr_bytes = sxattr_bytes; |
| total_xattr_bytes = stotal_xattr_bytes; |
| |
| /* restore the state of the uncomoressed xattr data */ |
| memcpy(data_cache, sdata_cache, scache_bytes); |
| cache_bytes = scache_bytes; |
| |
| /* restore the state of the xattr id table */ |
| xattr_ids = sxattr_ids; |
| } |