diff options
Diffstat (limited to 'libtar/android_utils.c')
-rw-r--r-- | libtar/android_utils.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/libtar/android_utils.c b/libtar/android_utils.c new file mode 100644 index 000000000..4aa3425b7 --- /dev/null +++ b/libtar/android_utils.c @@ -0,0 +1,123 @@ +/* +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/xattr.h> +#include <string.h> +#include <linux/limits.h> +#include <errno.h> + +#include "libtar.h" +#include "android_utils.h" + +/* This code may come in handy later if we ever need to extend to storing more user.inode_* xattrs +#define USER_INODE_SEPARATOR "\0" +#define ANDROID_USER_INODE_XATTR_PREFIX "user.inode_" +#define ANDROID_USER_INODE_XATTR_PREFIX_LEN strlen(ANDROID_USER_INODE_XATTR_PREFIX) + +char* scan_xattrs_for_user_inode (const char *realname, size_t *return_size) +{ + ssize_t size; + char xattr_list[PATH_MAX]; + size = listxattr(realname, xattr_list, sizeof(xattr_list)); + if (size < 0) { + return NULL; + } + char xattr[T_BLOCKSIZE]; + char *xattr_ptr; + int first = 1; + *return_size = 0; + for (int i = 0; i < size; i++) { + if (xattr_list[i]) { + xattr_ptr = xattr_list + i; + if (strncmp(xattr_ptr, ANDROID_USER_INODE_XATTR_PREFIX, ANDROID_USER_INODE_XATTR_PREFIX_LEN) == 0) { + // found a user.inode xattr + if (first) { + first = 0; + strcpy(xattr, xattr_ptr); + *return_size = strlen(xattr_ptr); + } else { + char *ptr = xattr + *return_size; + snprintf(ptr, T_BLOCKSIZE - *return_size, "%s", xattr_ptr); + *return_size += strlen(xattr_ptr) + 1; // + 1 for null separator + if (*return_size >= T_BLOCKSIZE) { + *return_size = 0; + return NULL; + } + } + } + i += strlen(xattr_ptr); + } + } + if (first) + return NULL; + return strdup(xattr); +}*/ + +/* + * get_path_inode and write_path_inode were taken from frameworks/native/cmds/installd/utils.cpp + */ + +static int get_path_inode(const char* path, ino_t *inode) { + struct stat buf; + memset(&buf, 0, sizeof(buf)); + if (stat(path, &buf) != 0) { + printf("failed to stat %s\n", path); + return -1; + } + *inode = buf.st_ino; + return 0; +} + +/** + * Write the inode of a specific child file into the given xattr on the + * parent directory. This allows you to find the child later, even if its + * name is encrypted. + */ +int write_path_inode(const char* parent, const char* name, const char* inode_xattr) { + ino_t inode = 0; + uint64_t inode_raw = 0; + char path[PATH_MAX]; + snprintf(path, PATH_MAX, "%s/%s", parent, name); + + if (mkdirhier(path) == -1) { + printf("failed to mkdirhier for %s\n", path); + return -1; + } + + if (get_path_inode(path, &inode) != 0) { + return -1; + } + + // Check to see if already set correctly + if (getxattr(parent, inode_xattr, &inode_raw, sizeof(inode_raw)) == sizeof(inode_raw)) { + if (inode_raw == inode) { + // Already set correctly; skip writing + return 0; + } + } + + inode_raw = inode; + printf("setting %s on %s pointing to %s\n", inode_xattr, parent, path); + if (setxattr(parent, inode_xattr, &inode_raw, sizeof(inode_raw), 0) != 0 && errno != EOPNOTSUPP) { + printf("Failed to write xattr %s at %s (%s)\n", inode_xattr, parent, strerror(errno)); + return -1; + } + return 0; +} |