blob: 4aa3425b7a42abce34d7f8623bb6ac684e4a245e [file] [log] [blame]
Ethan Yonker8d039f72017-02-03 14:26:15 -06001/*
2** Copyright 2008, The Android Open Source Project
3**
4** Licensed under the Apache License, Version 2.0 (the "License");
5** you may not use this file except in compliance with the License.
6** You may obtain a copy of the License at
7**
8** http://www.apache.org/licenses/LICENSE-2.0
9**
10** Unless required by applicable law or agreed to in writing, software
11** distributed under the License is distributed on an "AS IS" BASIS,
12** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13** See the License for the specific language governing permissions and
14** limitations under the License.
15*/
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <ctype.h>
20#include <sys/types.h>
21#include <sys/xattr.h>
22#include <string.h>
23#include <linux/limits.h>
24#include <errno.h>
25
26#include "libtar.h"
27#include "android_utils.h"
28
29/* This code may come in handy later if we ever need to extend to storing more user.inode_* xattrs
30#define USER_INODE_SEPARATOR "\0"
31#define ANDROID_USER_INODE_XATTR_PREFIX "user.inode_"
32#define ANDROID_USER_INODE_XATTR_PREFIX_LEN strlen(ANDROID_USER_INODE_XATTR_PREFIX)
33
34char* scan_xattrs_for_user_inode (const char *realname, size_t *return_size)
35{
36 ssize_t size;
37 char xattr_list[PATH_MAX];
38 size = listxattr(realname, xattr_list, sizeof(xattr_list));
39 if (size < 0) {
40 return NULL;
41 }
42 char xattr[T_BLOCKSIZE];
43 char *xattr_ptr;
44 int first = 1;
45 *return_size = 0;
46 for (int i = 0; i < size; i++) {
47 if (xattr_list[i]) {
48 xattr_ptr = xattr_list + i;
49 if (strncmp(xattr_ptr, ANDROID_USER_INODE_XATTR_PREFIX, ANDROID_USER_INODE_XATTR_PREFIX_LEN) == 0) {
50 // found a user.inode xattr
51 if (first) {
52 first = 0;
53 strcpy(xattr, xattr_ptr);
54 *return_size = strlen(xattr_ptr);
55 } else {
56 char *ptr = xattr + *return_size;
57 snprintf(ptr, T_BLOCKSIZE - *return_size, "%s", xattr_ptr);
58 *return_size += strlen(xattr_ptr) + 1; // + 1 for null separator
59 if (*return_size >= T_BLOCKSIZE) {
60 *return_size = 0;
61 return NULL;
62 }
63 }
64 }
65 i += strlen(xattr_ptr);
66 }
67 }
68 if (first)
69 return NULL;
70 return strdup(xattr);
71}*/
72
73/*
74 * get_path_inode and write_path_inode were taken from frameworks/native/cmds/installd/utils.cpp
75 */
76
77static int get_path_inode(const char* path, ino_t *inode) {
78 struct stat buf;
79 memset(&buf, 0, sizeof(buf));
80 if (stat(path, &buf) != 0) {
81 printf("failed to stat %s\n", path);
82 return -1;
83 }
84 *inode = buf.st_ino;
85 return 0;
86}
87
88/**
89 * Write the inode of a specific child file into the given xattr on the
90 * parent directory. This allows you to find the child later, even if its
91 * name is encrypted.
92 */
93int write_path_inode(const char* parent, const char* name, const char* inode_xattr) {
94 ino_t inode = 0;
95 uint64_t inode_raw = 0;
96 char path[PATH_MAX];
97 snprintf(path, PATH_MAX, "%s/%s", parent, name);
98
99 if (mkdirhier(path) == -1) {
100 printf("failed to mkdirhier for %s\n", path);
101 return -1;
102 }
103
104 if (get_path_inode(path, &inode) != 0) {
105 return -1;
106 }
107
108 // Check to see if already set correctly
109 if (getxattr(parent, inode_xattr, &inode_raw, sizeof(inode_raw)) == sizeof(inode_raw)) {
110 if (inode_raw == inode) {
111 // Already set correctly; skip writing
112 return 0;
113 }
114 }
115
116 inode_raw = inode;
117 printf("setting %s on %s pointing to %s\n", inode_xattr, parent, path);
118 if (setxattr(parent, inode_xattr, &inode_raw, sizeof(inode_raw), 0) != 0 && errno != EOPNOTSUPP) {
119 printf("Failed to write xattr %s at %s (%s)\n", inode_xattr, parent, strerror(errno));
120 return -1;
121 }
122 return 0;
123}