summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes2017-11-10 12:22:07 -0600
committerElliott Hughes2017-11-10 15:18:10 -0600
commit8e9aeb9053695a14539653093937158d15385ca6 (patch)
treeb02f7ad2149812eea2cb2802b7f238856b66619c /libcutils/fs.cpp
parent6707ef139d9786887649e3e3c2e3e251a95dc96d (diff)
downloadplatform-system-core-8e9aeb9053695a14539653093937158d15385ca6.tar.gz
platform-system-core-8e9aeb9053695a14539653093937158d15385ca6.tar.xz
platform-system-core-8e9aeb9053695a14539653093937158d15385ca6.zip
Move libcutils source to C++.
Just the minimial changes to get this to actually build, because otherwise we always bog down trying to rewrite everything (when the real answer is usually "stop using libcutils, it's awful"). This doesn't move a handful of files: two are basically just BSD libc source, a couple have outstanding code reviews, and one can be deleted (but I'll do that in a separate change). I'm also skipping the presubmit hooks because otherwise clang-format wants to reformat everything. I'll follow up with that... Bug: N/A Test: builds Change-Id: I06403f465b67c8e493bad466dd76b1151eed5993
Diffstat (limited to 'libcutils/fs.cpp')
-rw-r--r--libcutils/fs.cpp276
1 files changed, 276 insertions, 0 deletions
diff --git a/libcutils/fs.cpp b/libcutils/fs.cpp
new file mode 100644
index 000000000..ef85accce
--- /dev/null
+++ b/libcutils/fs.cpp
@@ -0,0 +1,276 @@
1/*
2 * Copyright (C) 2012 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 <cutils/fs.h>
18
19#define LOG_TAG "cutils"
20
21/* These defines are only needed because prebuilt headers are out of date */
22#define __USE_XOPEN2K8 1
23#define _ATFILE_SOURCE 1
24#define _GNU_SOURCE 1
25
26#include <dirent.h>
27#include <errno.h>
28#include <fcntl.h>
29#include <limits.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <sys/stat.h>
34#include <sys/types.h>
35#include <unistd.h>
36
37#include <log/log.h>
38
39#define ALL_PERMS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
40#define BUF_SIZE 64
41
42static int fs_prepare_path_impl(const char* path, mode_t mode, uid_t uid, gid_t gid,
43 int allow_fixup, int prepare_as_dir) {
44 // TODO: fix the goto hell below.
45 int type_ok;
46 int owner_match;
47 int mode_match;
48
49 // Check if path needs to be created
50 struct stat sb;
51 int create_result = -1;
52 if (TEMP_FAILURE_RETRY(lstat(path, &sb)) == -1) {
53 if (errno == ENOENT) {
54 goto create;
55 } else {
56 ALOGE("Failed to lstat(%s): %s", path, strerror(errno));
57 return -1;
58 }
59 }
60
61 // Exists, verify status
62 type_ok = prepare_as_dir ? S_ISDIR(sb.st_mode) : S_ISREG(sb.st_mode);
63 if (!type_ok) {
64 ALOGE("Not a %s: %s", (prepare_as_dir ? "directory" : "regular file"), path);
65 return -1;
66 }
67
68 owner_match = ((sb.st_uid == uid) && (sb.st_gid == gid));
69 mode_match = ((sb.st_mode & ALL_PERMS) == mode);
70 if (owner_match && mode_match) {
71 return 0;
72 } else if (allow_fixup) {
73 goto fixup;
74 } else {
75 if (!owner_match) {
76 ALOGE("Expected path %s with owner %d:%d but found %d:%d",
77 path, uid, gid, sb.st_uid, sb.st_gid);
78 return -1;
79 } else {
80 ALOGW("Expected path %s with mode %o but found %o",
81 path, mode, (sb.st_mode & ALL_PERMS));
82 return 0;
83 }
84 }
85
86create:
87 create_result = prepare_as_dir
88 ? TEMP_FAILURE_RETRY(mkdir(path, mode))
89 : TEMP_FAILURE_RETRY(open(path, O_CREAT | O_CLOEXEC | O_NOFOLLOW | O_RDONLY, 0644));
90 if (create_result == -1) {
91 if (errno != EEXIST) {
92 ALOGE("Failed to %s(%s): %s",
93 (prepare_as_dir ? "mkdir" : "open"), path, strerror(errno));
94 return -1;
95 }
96 } else if (!prepare_as_dir) {
97 // For regular files we need to make sure we close the descriptor
98 if (close(create_result) == -1) {
99 ALOGW("Failed to close file after create %s: %s", path, strerror(errno));
100 }
101 }
102fixup:
103 if (TEMP_FAILURE_RETRY(chmod(path, mode)) == -1) {
104 ALOGE("Failed to chmod(%s, %d): %s", path, mode, strerror(errno));
105 return -1;
106 }
107 if (TEMP_FAILURE_RETRY(chown(path, uid, gid)) == -1) {
108 ALOGE("Failed to chown(%s, %d, %d): %s", path, uid, gid, strerror(errno));
109 return -1;
110 }
111
112 return 0;
113}
114
115int fs_prepare_dir(const char* path, mode_t mode, uid_t uid, gid_t gid) {
116 return fs_prepare_path_impl(path, mode, uid, gid, /*allow_fixup*/ 1, /*prepare_as_dir*/ 1);
117}
118
119int fs_prepare_dir_strict(const char* path, mode_t mode, uid_t uid, gid_t gid) {
120 return fs_prepare_path_impl(path, mode, uid, gid, /*allow_fixup*/ 0, /*prepare_as_dir*/ 1);
121}
122
123int fs_prepare_file_strict(const char* path, mode_t mode, uid_t uid, gid_t gid) {
124 return fs_prepare_path_impl(path, mode, uid, gid, /*allow_fixup*/ 0, /*prepare_as_dir*/ 0);
125}
126
127int fs_read_atomic_int(const char* path, int* out_value) {
128 int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY));
129 if (fd == -1) {
130 ALOGE("Failed to read %s: %s", path, strerror(errno));
131 return -1;
132 }
133
134 char buf[BUF_SIZE];
135 if (TEMP_FAILURE_RETRY(read(fd, buf, BUF_SIZE)) == -1) {
136 ALOGE("Failed to read %s: %s", path, strerror(errno));
137 goto fail;
138 }
139 if (sscanf(buf, "%d", out_value) != 1) {
140 ALOGE("Failed to parse %s: %s", path, strerror(errno));
141 goto fail;
142 }
143 close(fd);
144 return 0;
145
146fail:
147 close(fd);
148 *out_value = -1;
149 return -1;
150}
151
152int fs_write_atomic_int(const char* path, int value) {
153 char temp[PATH_MAX];
154 if (snprintf(temp, PATH_MAX, "%s.XXXXXX", path) >= PATH_MAX) {
155 ALOGE("Path too long");
156 return -1;
157 }
158
159 int fd = TEMP_FAILURE_RETRY(mkstemp(temp));
160 if (fd == -1) {
161 ALOGE("Failed to open %s: %s", temp, strerror(errno));
162 return -1;
163 }
164
165 char buf[BUF_SIZE];
166 int len = snprintf(buf, BUF_SIZE, "%d", value) + 1;
167 if (len > BUF_SIZE) {
168 ALOGE("Value %d too large: %s", value, strerror(errno));
169 goto fail;
170 }
171 if (TEMP_FAILURE_RETRY(write(fd, buf, len)) < len) {
172 ALOGE("Failed to write %s: %s", temp, strerror(errno));
173 goto fail;
174 }
175 if (close(fd) == -1) {
176 ALOGE("Failed to close %s: %s", temp, strerror(errno));
177 goto fail_closed;
178 }
179
180 if (rename(temp, path) == -1) {
181 ALOGE("Failed to rename %s to %s: %s", temp, path, strerror(errno));
182 goto fail_closed;
183 }
184
185 return 0;
186
187fail:
188 close(fd);
189fail_closed:
190 unlink(temp);
191 return -1;
192}
193
194#ifndef __APPLE__
195
196int fs_mkdirs(const char* path, mode_t mode) {
197 if (*path != '/') {
198 ALOGE("Relative paths are not allowed: %s", path);
199 return -EINVAL;
200 }
201
202 int fd = open("/", 0);
203 if (fd == -1) {
204 ALOGE("Failed to open(/): %s", strerror(errno));
205 return -errno;
206 }
207
208 struct stat sb;
209 int res = 0;
210 char* buf = strdup(path);
211 char* segment = buf + 1;
212 char* p = segment;
213 while (*p != '\0') {
214 if (*p == '/') {
215 *p = '\0';
216
217 if (!strcmp(segment, "..") || !strcmp(segment, ".") || !strcmp(segment, "")) {
218 ALOGE("Invalid path: %s", buf);
219 res = -EINVAL;
220 goto done_close;
221 }
222
223 if (fstatat(fd, segment, &sb, AT_SYMLINK_NOFOLLOW) != 0) {
224 if (errno == ENOENT) {
225 /* Nothing there yet; let's create it! */
226 if (mkdirat(fd, segment, mode) != 0) {
227 if (errno == EEXIST) {
228 /* We raced with someone; ignore */
229 } else {
230 ALOGE("Failed to mkdirat(%s): %s", buf, strerror(errno));
231 res = -errno;
232 goto done_close;
233 }
234 }
235 } else {
236 ALOGE("Failed to fstatat(%s): %s", buf, strerror(errno));
237 res = -errno;
238 goto done_close;
239 }
240 } else {
241 if (S_ISLNK(sb.st_mode)) {
242 ALOGE("Symbolic links are not allowed: %s", buf);
243 res = -ELOOP;
244 goto done_close;
245 }
246 if (!S_ISDIR(sb.st_mode)) {
247 ALOGE("Existing segment not a directory: %s", buf);
248 res = -ENOTDIR;
249 goto done_close;
250 }
251 }
252
253 /* Yay, segment is ready for us to step into */
254 int next_fd;
255 if ((next_fd = openat(fd, segment, O_NOFOLLOW | O_CLOEXEC)) == -1) {
256 ALOGE("Failed to openat(%s): %s", buf, strerror(errno));
257 res = -errno;
258 goto done_close;
259 }
260
261 close(fd);
262 fd = next_fd;
263
264 *p = '/';
265 segment = p + 1;
266 }
267 p++;
268 }
269
270done_close:
271 close(fd);
272 free(buf);
273 return res;
274}
275
276#endif