xref: /aosp_15_r20/system/core/libcutils/fs.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
1*00c7fec1SAndroid Build Coastguard Worker /*
2*00c7fec1SAndroid Build Coastguard Worker  * Copyright (C) 2012 The Android Open Source Project
3*00c7fec1SAndroid Build Coastguard Worker  *
4*00c7fec1SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*00c7fec1SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*00c7fec1SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*00c7fec1SAndroid Build Coastguard Worker  *
8*00c7fec1SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*00c7fec1SAndroid Build Coastguard Worker  *
10*00c7fec1SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*00c7fec1SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*00c7fec1SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*00c7fec1SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*00c7fec1SAndroid Build Coastguard Worker  * limitations under the License.
15*00c7fec1SAndroid Build Coastguard Worker  */
16*00c7fec1SAndroid Build Coastguard Worker 
17*00c7fec1SAndroid Build Coastguard Worker #include <cutils/fs.h>
18*00c7fec1SAndroid Build Coastguard Worker 
19*00c7fec1SAndroid Build Coastguard Worker #define LOG_TAG "cutils"
20*00c7fec1SAndroid Build Coastguard Worker 
21*00c7fec1SAndroid Build Coastguard Worker /* These defines are only needed because prebuilt headers are out of date */
22*00c7fec1SAndroid Build Coastguard Worker #define __USE_XOPEN2K8 1
23*00c7fec1SAndroid Build Coastguard Worker #define _ATFILE_SOURCE 1
24*00c7fec1SAndroid Build Coastguard Worker #define _GNU_SOURCE 1
25*00c7fec1SAndroid Build Coastguard Worker 
26*00c7fec1SAndroid Build Coastguard Worker #include <dirent.h>
27*00c7fec1SAndroid Build Coastguard Worker #include <errno.h>
28*00c7fec1SAndroid Build Coastguard Worker #include <fcntl.h>
29*00c7fec1SAndroid Build Coastguard Worker #include <limits.h>
30*00c7fec1SAndroid Build Coastguard Worker #include <stdio.h>
31*00c7fec1SAndroid Build Coastguard Worker #include <stdlib.h>
32*00c7fec1SAndroid Build Coastguard Worker #include <string.h>
33*00c7fec1SAndroid Build Coastguard Worker #include <sys/stat.h>
34*00c7fec1SAndroid Build Coastguard Worker #include <sys/types.h>
35*00c7fec1SAndroid Build Coastguard Worker #include <unistd.h>
36*00c7fec1SAndroid Build Coastguard Worker 
37*00c7fec1SAndroid Build Coastguard Worker #include <log/log.h>
38*00c7fec1SAndroid Build Coastguard Worker 
39*00c7fec1SAndroid Build Coastguard Worker #define ALL_PERMS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
40*00c7fec1SAndroid Build Coastguard Worker #define BUF_SIZE 64
41*00c7fec1SAndroid Build Coastguard Worker 
fs_prepare_path_impl(const char * path,mode_t mode,uid_t uid,gid_t gid,int allow_fixup,int prepare_as_dir)42*00c7fec1SAndroid Build Coastguard Worker static int fs_prepare_path_impl(const char* path, mode_t mode, uid_t uid, gid_t gid,
43*00c7fec1SAndroid Build Coastguard Worker         int allow_fixup, int prepare_as_dir) {
44*00c7fec1SAndroid Build Coastguard Worker     // TODO: fix the goto hell below.
45*00c7fec1SAndroid Build Coastguard Worker     int type_ok;
46*00c7fec1SAndroid Build Coastguard Worker     int owner_match;
47*00c7fec1SAndroid Build Coastguard Worker     int mode_match;
48*00c7fec1SAndroid Build Coastguard Worker 
49*00c7fec1SAndroid Build Coastguard Worker     // Check if path needs to be created
50*00c7fec1SAndroid Build Coastguard Worker     struct stat sb;
51*00c7fec1SAndroid Build Coastguard Worker     int create_result = -1;
52*00c7fec1SAndroid Build Coastguard Worker     if (TEMP_FAILURE_RETRY(lstat(path, &sb)) == -1) {
53*00c7fec1SAndroid Build Coastguard Worker         if (errno == ENOENT) {
54*00c7fec1SAndroid Build Coastguard Worker             goto create;
55*00c7fec1SAndroid Build Coastguard Worker         } else {
56*00c7fec1SAndroid Build Coastguard Worker             ALOGE("Failed to lstat(%s): %s", path, strerror(errno));
57*00c7fec1SAndroid Build Coastguard Worker             return -1;
58*00c7fec1SAndroid Build Coastguard Worker         }
59*00c7fec1SAndroid Build Coastguard Worker     }
60*00c7fec1SAndroid Build Coastguard Worker 
61*00c7fec1SAndroid Build Coastguard Worker     // Exists, verify status
62*00c7fec1SAndroid Build Coastguard Worker     type_ok = prepare_as_dir ? S_ISDIR(sb.st_mode) : S_ISREG(sb.st_mode);
63*00c7fec1SAndroid Build Coastguard Worker     if (!type_ok) {
64*00c7fec1SAndroid Build Coastguard Worker         ALOGE("Not a %s: %s", (prepare_as_dir ? "directory" : "regular file"), path);
65*00c7fec1SAndroid Build Coastguard Worker         return -1;
66*00c7fec1SAndroid Build Coastguard Worker     }
67*00c7fec1SAndroid Build Coastguard Worker 
68*00c7fec1SAndroid Build Coastguard Worker     owner_match = ((sb.st_uid == uid) && (sb.st_gid == gid));
69*00c7fec1SAndroid Build Coastguard Worker     mode_match = ((sb.st_mode & ALL_PERMS) == mode);
70*00c7fec1SAndroid Build Coastguard Worker     if (owner_match && mode_match) {
71*00c7fec1SAndroid Build Coastguard Worker         return 0;
72*00c7fec1SAndroid Build Coastguard Worker     } else if (allow_fixup) {
73*00c7fec1SAndroid Build Coastguard Worker         goto fixup;
74*00c7fec1SAndroid Build Coastguard Worker     } else {
75*00c7fec1SAndroid Build Coastguard Worker         if (!owner_match) {
76*00c7fec1SAndroid Build Coastguard Worker             ALOGE("Expected path %s with owner %d:%d but found %d:%d",
77*00c7fec1SAndroid Build Coastguard Worker                     path, uid, gid, sb.st_uid, sb.st_gid);
78*00c7fec1SAndroid Build Coastguard Worker             return -1;
79*00c7fec1SAndroid Build Coastguard Worker         } else {
80*00c7fec1SAndroid Build Coastguard Worker             ALOGW("Expected path %s with mode %o but found %o",
81*00c7fec1SAndroid Build Coastguard Worker                     path, mode, (sb.st_mode & ALL_PERMS));
82*00c7fec1SAndroid Build Coastguard Worker             return 0;
83*00c7fec1SAndroid Build Coastguard Worker         }
84*00c7fec1SAndroid Build Coastguard Worker     }
85*00c7fec1SAndroid Build Coastguard Worker 
86*00c7fec1SAndroid Build Coastguard Worker create:
87*00c7fec1SAndroid Build Coastguard Worker     create_result = prepare_as_dir
88*00c7fec1SAndroid Build Coastguard Worker         ? TEMP_FAILURE_RETRY(mkdir(path, mode))
89*00c7fec1SAndroid Build Coastguard Worker         : TEMP_FAILURE_RETRY(open(path, O_CREAT | O_CLOEXEC | O_NOFOLLOW | O_RDONLY, 0644));
90*00c7fec1SAndroid Build Coastguard Worker     if (create_result == -1) {
91*00c7fec1SAndroid Build Coastguard Worker         if (errno != EEXIST) {
92*00c7fec1SAndroid Build Coastguard Worker             ALOGE("Failed to %s(%s): %s",
93*00c7fec1SAndroid Build Coastguard Worker                     (prepare_as_dir ? "mkdir" : "open"), path, strerror(errno));
94*00c7fec1SAndroid Build Coastguard Worker             return -1;
95*00c7fec1SAndroid Build Coastguard Worker         }
96*00c7fec1SAndroid Build Coastguard Worker     } else if (!prepare_as_dir) {
97*00c7fec1SAndroid Build Coastguard Worker         // For regular files we need to make sure we close the descriptor
98*00c7fec1SAndroid Build Coastguard Worker         if (close(create_result) == -1) {
99*00c7fec1SAndroid Build Coastguard Worker             ALOGW("Failed to close file after create %s: %s", path, strerror(errno));
100*00c7fec1SAndroid Build Coastguard Worker         }
101*00c7fec1SAndroid Build Coastguard Worker     }
102*00c7fec1SAndroid Build Coastguard Worker fixup:
103*00c7fec1SAndroid Build Coastguard Worker     if (TEMP_FAILURE_RETRY(chmod(path, mode)) == -1) {
104*00c7fec1SAndroid Build Coastguard Worker         ALOGE("Failed to chmod(%s, %d): %s", path, mode, strerror(errno));
105*00c7fec1SAndroid Build Coastguard Worker         return -1;
106*00c7fec1SAndroid Build Coastguard Worker     }
107*00c7fec1SAndroid Build Coastguard Worker     if (TEMP_FAILURE_RETRY(chown(path, uid, gid)) == -1) {
108*00c7fec1SAndroid Build Coastguard Worker         ALOGE("Failed to chown(%s, %d, %d): %s", path, uid, gid, strerror(errno));
109*00c7fec1SAndroid Build Coastguard Worker         return -1;
110*00c7fec1SAndroid Build Coastguard Worker     }
111*00c7fec1SAndroid Build Coastguard Worker 
112*00c7fec1SAndroid Build Coastguard Worker     return 0;
113*00c7fec1SAndroid Build Coastguard Worker }
114*00c7fec1SAndroid Build Coastguard Worker 
fs_prepare_dir(const char * path,mode_t mode,uid_t uid,gid_t gid)115*00c7fec1SAndroid Build Coastguard Worker int fs_prepare_dir(const char* path, mode_t mode, uid_t uid, gid_t gid) {
116*00c7fec1SAndroid Build Coastguard Worker     return fs_prepare_path_impl(path, mode, uid, gid, /*allow_fixup*/ 1, /*prepare_as_dir*/ 1);
117*00c7fec1SAndroid Build Coastguard Worker }
118*00c7fec1SAndroid Build Coastguard Worker 
fs_prepare_dir_strict(const char * path,mode_t mode,uid_t uid,gid_t gid)119*00c7fec1SAndroid Build Coastguard Worker int fs_prepare_dir_strict(const char* path, mode_t mode, uid_t uid, gid_t gid) {
120*00c7fec1SAndroid Build Coastguard Worker     return fs_prepare_path_impl(path, mode, uid, gid, /*allow_fixup*/ 0, /*prepare_as_dir*/ 1);
121*00c7fec1SAndroid Build Coastguard Worker }
122*00c7fec1SAndroid Build Coastguard Worker 
fs_prepare_file_strict(const char * path,mode_t mode,uid_t uid,gid_t gid)123*00c7fec1SAndroid Build Coastguard Worker int fs_prepare_file_strict(const char* path, mode_t mode, uid_t uid, gid_t gid) {
124*00c7fec1SAndroid Build Coastguard Worker     return fs_prepare_path_impl(path, mode, uid, gid, /*allow_fixup*/ 0, /*prepare_as_dir*/ 0);
125*00c7fec1SAndroid Build Coastguard Worker }
126*00c7fec1SAndroid Build Coastguard Worker 
fs_read_atomic_int(const char * path,int * out_value)127*00c7fec1SAndroid Build Coastguard Worker int fs_read_atomic_int(const char* path, int* out_value) {
128*00c7fec1SAndroid Build Coastguard Worker     int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY));
129*00c7fec1SAndroid Build Coastguard Worker     if (fd == -1) {
130*00c7fec1SAndroid Build Coastguard Worker         ALOGE("Failed to read %s: %s", path, strerror(errno));
131*00c7fec1SAndroid Build Coastguard Worker         return -1;
132*00c7fec1SAndroid Build Coastguard Worker     }
133*00c7fec1SAndroid Build Coastguard Worker 
134*00c7fec1SAndroid Build Coastguard Worker     char buf[BUF_SIZE];
135*00c7fec1SAndroid Build Coastguard Worker     if (TEMP_FAILURE_RETRY(read(fd, buf, BUF_SIZE)) == -1) {
136*00c7fec1SAndroid Build Coastguard Worker         ALOGE("Failed to read %s: %s", path, strerror(errno));
137*00c7fec1SAndroid Build Coastguard Worker         goto fail;
138*00c7fec1SAndroid Build Coastguard Worker     }
139*00c7fec1SAndroid Build Coastguard Worker     if (sscanf(buf, "%d", out_value) != 1) {
140*00c7fec1SAndroid Build Coastguard Worker         ALOGE("Failed to parse %s: %s", path, strerror(errno));
141*00c7fec1SAndroid Build Coastguard Worker         goto fail;
142*00c7fec1SAndroid Build Coastguard Worker     }
143*00c7fec1SAndroid Build Coastguard Worker     close(fd);
144*00c7fec1SAndroid Build Coastguard Worker     return 0;
145*00c7fec1SAndroid Build Coastguard Worker 
146*00c7fec1SAndroid Build Coastguard Worker fail:
147*00c7fec1SAndroid Build Coastguard Worker     close(fd);
148*00c7fec1SAndroid Build Coastguard Worker     *out_value = -1;
149*00c7fec1SAndroid Build Coastguard Worker     return -1;
150*00c7fec1SAndroid Build Coastguard Worker }
151*00c7fec1SAndroid Build Coastguard Worker 
fs_write_atomic_int(const char * path,int value)152*00c7fec1SAndroid Build Coastguard Worker int fs_write_atomic_int(const char* path, int value) {
153*00c7fec1SAndroid Build Coastguard Worker     char temp[PATH_MAX];
154*00c7fec1SAndroid Build Coastguard Worker     if (snprintf(temp, PATH_MAX, "%s.XXXXXX", path) >= PATH_MAX) {
155*00c7fec1SAndroid Build Coastguard Worker         ALOGE("Path too long");
156*00c7fec1SAndroid Build Coastguard Worker         return -1;
157*00c7fec1SAndroid Build Coastguard Worker     }
158*00c7fec1SAndroid Build Coastguard Worker 
159*00c7fec1SAndroid Build Coastguard Worker     int fd = TEMP_FAILURE_RETRY(mkstemp(temp));
160*00c7fec1SAndroid Build Coastguard Worker     if (fd == -1) {
161*00c7fec1SAndroid Build Coastguard Worker         ALOGE("Failed to open %s: %s", temp, strerror(errno));
162*00c7fec1SAndroid Build Coastguard Worker         return -1;
163*00c7fec1SAndroid Build Coastguard Worker     }
164*00c7fec1SAndroid Build Coastguard Worker 
165*00c7fec1SAndroid Build Coastguard Worker     char buf[BUF_SIZE];
166*00c7fec1SAndroid Build Coastguard Worker     int len = snprintf(buf, BUF_SIZE, "%d", value) + 1;
167*00c7fec1SAndroid Build Coastguard Worker     if (len > BUF_SIZE) {
168*00c7fec1SAndroid Build Coastguard Worker         ALOGE("Value %d too large: %s", value, strerror(errno));
169*00c7fec1SAndroid Build Coastguard Worker         goto fail;
170*00c7fec1SAndroid Build Coastguard Worker     }
171*00c7fec1SAndroid Build Coastguard Worker     if (TEMP_FAILURE_RETRY(write(fd, buf, len)) < len) {
172*00c7fec1SAndroid Build Coastguard Worker         ALOGE("Failed to write %s: %s", temp, strerror(errno));
173*00c7fec1SAndroid Build Coastguard Worker         goto fail;
174*00c7fec1SAndroid Build Coastguard Worker     }
175*00c7fec1SAndroid Build Coastguard Worker     if (close(fd) == -1) {
176*00c7fec1SAndroid Build Coastguard Worker         ALOGE("Failed to close %s: %s", temp, strerror(errno));
177*00c7fec1SAndroid Build Coastguard Worker         goto fail_closed;
178*00c7fec1SAndroid Build Coastguard Worker     }
179*00c7fec1SAndroid Build Coastguard Worker 
180*00c7fec1SAndroid Build Coastguard Worker     if (rename(temp, path) == -1) {
181*00c7fec1SAndroid Build Coastguard Worker         ALOGE("Failed to rename %s to %s: %s", temp, path, strerror(errno));
182*00c7fec1SAndroid Build Coastguard Worker         goto fail_closed;
183*00c7fec1SAndroid Build Coastguard Worker     }
184*00c7fec1SAndroid Build Coastguard Worker 
185*00c7fec1SAndroid Build Coastguard Worker     return 0;
186*00c7fec1SAndroid Build Coastguard Worker 
187*00c7fec1SAndroid Build Coastguard Worker fail:
188*00c7fec1SAndroid Build Coastguard Worker     close(fd);
189*00c7fec1SAndroid Build Coastguard Worker fail_closed:
190*00c7fec1SAndroid Build Coastguard Worker     unlink(temp);
191*00c7fec1SAndroid Build Coastguard Worker     return -1;
192*00c7fec1SAndroid Build Coastguard Worker }
193*00c7fec1SAndroid Build Coastguard Worker 
194*00c7fec1SAndroid Build Coastguard Worker #ifndef __APPLE__
195*00c7fec1SAndroid Build Coastguard Worker 
fs_mkdirs(const char * path,mode_t mode)196*00c7fec1SAndroid Build Coastguard Worker int fs_mkdirs(const char* path, mode_t mode) {
197*00c7fec1SAndroid Build Coastguard Worker     if (*path != '/') {
198*00c7fec1SAndroid Build Coastguard Worker         ALOGE("Relative paths are not allowed: %s", path);
199*00c7fec1SAndroid Build Coastguard Worker         return -EINVAL;
200*00c7fec1SAndroid Build Coastguard Worker     }
201*00c7fec1SAndroid Build Coastguard Worker 
202*00c7fec1SAndroid Build Coastguard Worker     int fd = open("/", 0);
203*00c7fec1SAndroid Build Coastguard Worker     if (fd == -1) {
204*00c7fec1SAndroid Build Coastguard Worker         ALOGE("Failed to open(/): %s", strerror(errno));
205*00c7fec1SAndroid Build Coastguard Worker         return -errno;
206*00c7fec1SAndroid Build Coastguard Worker     }
207*00c7fec1SAndroid Build Coastguard Worker 
208*00c7fec1SAndroid Build Coastguard Worker     struct stat sb;
209*00c7fec1SAndroid Build Coastguard Worker     int res = 0;
210*00c7fec1SAndroid Build Coastguard Worker     char* buf = strdup(path);
211*00c7fec1SAndroid Build Coastguard Worker     char* segment = buf + 1;
212*00c7fec1SAndroid Build Coastguard Worker     char* p = segment;
213*00c7fec1SAndroid Build Coastguard Worker     while (*p != '\0') {
214*00c7fec1SAndroid Build Coastguard Worker         if (*p == '/') {
215*00c7fec1SAndroid Build Coastguard Worker             *p = '\0';
216*00c7fec1SAndroid Build Coastguard Worker 
217*00c7fec1SAndroid Build Coastguard Worker             if (!strcmp(segment, "..") || !strcmp(segment, ".") || !strcmp(segment, "")) {
218*00c7fec1SAndroid Build Coastguard Worker                 ALOGE("Invalid path: %s", buf);
219*00c7fec1SAndroid Build Coastguard Worker                 res = -EINVAL;
220*00c7fec1SAndroid Build Coastguard Worker                 goto done_close;
221*00c7fec1SAndroid Build Coastguard Worker             }
222*00c7fec1SAndroid Build Coastguard Worker 
223*00c7fec1SAndroid Build Coastguard Worker             if (fstatat(fd, segment, &sb, AT_SYMLINK_NOFOLLOW) != 0) {
224*00c7fec1SAndroid Build Coastguard Worker                 if (errno == ENOENT) {
225*00c7fec1SAndroid Build Coastguard Worker                     /* Nothing there yet; let's create it! */
226*00c7fec1SAndroid Build Coastguard Worker                     if (mkdirat(fd, segment, mode) != 0) {
227*00c7fec1SAndroid Build Coastguard Worker                         if (errno == EEXIST) {
228*00c7fec1SAndroid Build Coastguard Worker                             /* We raced with someone; ignore */
229*00c7fec1SAndroid Build Coastguard Worker                         } else {
230*00c7fec1SAndroid Build Coastguard Worker                             ALOGE("Failed to mkdirat(%s): %s", buf, strerror(errno));
231*00c7fec1SAndroid Build Coastguard Worker                             res = -errno;
232*00c7fec1SAndroid Build Coastguard Worker                             goto done_close;
233*00c7fec1SAndroid Build Coastguard Worker                         }
234*00c7fec1SAndroid Build Coastguard Worker                     }
235*00c7fec1SAndroid Build Coastguard Worker                 } else {
236*00c7fec1SAndroid Build Coastguard Worker                     ALOGE("Failed to fstatat(%s): %s", buf, strerror(errno));
237*00c7fec1SAndroid Build Coastguard Worker                     res = -errno;
238*00c7fec1SAndroid Build Coastguard Worker                     goto done_close;
239*00c7fec1SAndroid Build Coastguard Worker                 }
240*00c7fec1SAndroid Build Coastguard Worker             } else {
241*00c7fec1SAndroid Build Coastguard Worker                 if (S_ISLNK(sb.st_mode)) {
242*00c7fec1SAndroid Build Coastguard Worker                     ALOGE("Symbolic links are not allowed: %s", buf);
243*00c7fec1SAndroid Build Coastguard Worker                     res = -ELOOP;
244*00c7fec1SAndroid Build Coastguard Worker                     goto done_close;
245*00c7fec1SAndroid Build Coastguard Worker                 }
246*00c7fec1SAndroid Build Coastguard Worker                 if (!S_ISDIR(sb.st_mode)) {
247*00c7fec1SAndroid Build Coastguard Worker                     ALOGE("Existing segment not a directory: %s", buf);
248*00c7fec1SAndroid Build Coastguard Worker                     res = -ENOTDIR;
249*00c7fec1SAndroid Build Coastguard Worker                     goto done_close;
250*00c7fec1SAndroid Build Coastguard Worker                 }
251*00c7fec1SAndroid Build Coastguard Worker             }
252*00c7fec1SAndroid Build Coastguard Worker 
253*00c7fec1SAndroid Build Coastguard Worker             /* Yay, segment is ready for us to step into */
254*00c7fec1SAndroid Build Coastguard Worker             int next_fd;
255*00c7fec1SAndroid Build Coastguard Worker             if ((next_fd = openat(fd, segment, O_NOFOLLOW | O_CLOEXEC)) == -1) {
256*00c7fec1SAndroid Build Coastguard Worker                 ALOGE("Failed to openat(%s): %s", buf, strerror(errno));
257*00c7fec1SAndroid Build Coastguard Worker                 res = -errno;
258*00c7fec1SAndroid Build Coastguard Worker                 goto done_close;
259*00c7fec1SAndroid Build Coastguard Worker             }
260*00c7fec1SAndroid Build Coastguard Worker 
261*00c7fec1SAndroid Build Coastguard Worker             close(fd);
262*00c7fec1SAndroid Build Coastguard Worker             fd = next_fd;
263*00c7fec1SAndroid Build Coastguard Worker 
264*00c7fec1SAndroid Build Coastguard Worker             *p = '/';
265*00c7fec1SAndroid Build Coastguard Worker             segment = p + 1;
266*00c7fec1SAndroid Build Coastguard Worker         }
267*00c7fec1SAndroid Build Coastguard Worker         p++;
268*00c7fec1SAndroid Build Coastguard Worker     }
269*00c7fec1SAndroid Build Coastguard Worker 
270*00c7fec1SAndroid Build Coastguard Worker done_close:
271*00c7fec1SAndroid Build Coastguard Worker     close(fd);
272*00c7fec1SAndroid Build Coastguard Worker     free(buf);
273*00c7fec1SAndroid Build Coastguard Worker     return res;
274*00c7fec1SAndroid Build Coastguard Worker }
275*00c7fec1SAndroid Build Coastguard Worker 
276*00c7fec1SAndroid Build Coastguard Worker #endif
277