1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // for S_IF*
6 #define _XOPEN_SOURCE
7
8 #include <dirent.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <limits.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <unistd.h>
16
17 #include <sys/stat.h>
18 #include <sys/time.h>
19
20 #include <lib/fdio/vfs.h>
21
22 #include "filesystems.h"
23
24 // The __wrap_* symbols are generated by the linker, but this is done after all
25 // bitcode has been translated when doing the LTO build, and as such compiler
26 // might optimize these out as unused. To avoid this, we need to explicitly mark
27 // these as used.
28 #define FN(n) __attribute__((used)) __wrap_##n
29 #define FL(n) __real_##n
30
status_to_errno(zx_status_t status)31 int status_to_errno(zx_status_t status) {
32 switch (status) {
33 case ZX_OK:
34 return 0;
35 default:
36 return EIO;
37 }
38 }
39
40 #define FAIL(err) \
41 do { \
42 return err ? -1 : 0; \
43 } while (0)
44 #define STATUS(status) \
45 FAIL(status_to_errno(status))
46 #define PATH_WRAP(path_in, path_out) \
47 do { \
48 if (wrap_path(path_in, path_out)) \
49 FAIL(EINVAL); \
50 } while (0)
51 #define DO_REAL(name, args...) \
52 do { \
53 int status = __real_##name(args); \
54 if (status < 0) \
55 STATUS(status); \
56 return status; \
57 } while (0)
58
59 #define PATH_PREFIX "::"
60 #define PREFIX_SIZE 2
61
62 // Occasionally, we test with paths that push against PATH_MAX.
63 // Our 'wrap' functions should *not* be the cause of error; rather, we should see errors emerging
64 // from either libc or our filesystems themselves.
65 #define WPATH_MAX (PATH_MAX * 2)
66
wrap_path(const char * path_in,char * path_out)67 static inline int wrap_path(const char* path_in, char* path_out) {
68 path_out[0] = '\0';
69 int bytes_left = WPATH_MAX - 1;
70 if (strncmp(path_in, PATH_PREFIX, PREFIX_SIZE) || (kMountPath == NULL)) {
71 // Unfiltered path
72 strncat(path_out, path_in, bytes_left);
73 return 0;
74 }
75 // Remove the "::" prefix, and substitute the actual path
76 strncat(path_out, kMountPath, bytes_left);
77 bytes_left -= strlen(kMountPath);
78 strncat(path_out, "/", bytes_left);
79 bytes_left -= 1;
80 strncat(path_out, path_in + PREFIX_SIZE, bytes_left);
81
82 return 0;
83 }
84
85 int FL(open)(const char* path, int flags, mode_t mode);
FN(open)86 int FN(open)(const char* path, int flags, mode_t mode) {
87 char real_path[WPATH_MAX];
88 PATH_WRAP(path, real_path);
89 DO_REAL(open, real_path, flags, mode);
90 }
91
92 DIR* FL(opendir)(const char* path);
FN(opendir)93 DIR* FN(opendir)(const char* path) {
94 char real_path[WPATH_MAX];
95 if (wrap_path(path, real_path)) {
96 return NULL;
97 }
98 return __real_opendir(real_path);
99 }
100
101 int FL(chdir)(const char* path);
FN(chdir)102 int FN(chdir)(const char* path) {
103 char real_path[WPATH_MAX];
104 PATH_WRAP(path, real_path);
105 DO_REAL(chdir, real_path);
106 }
107
108 int FL(mkdir)(const char* path, mode_t mode);
FN(mkdir)109 int FN(mkdir)(const char* path, mode_t mode) {
110 char real_path[WPATH_MAX];
111 PATH_WRAP(path, real_path);
112 DO_REAL(mkdir, real_path, mode);
113 }
114
115 int FL(unlink)(const char* path);
FN(unlink)116 int FN(unlink)(const char* path) {
117 char real_path[WPATH_MAX];
118 PATH_WRAP(path, real_path);
119 DO_REAL(unlink, real_path);
120 }
121
122 int FL(rmdir)(const char* path);
FN(rmdir)123 int FN(rmdir)(const char* path) {
124 char real_path[WPATH_MAX];
125 PATH_WRAP(path, real_path);
126 DO_REAL(rmdir, real_path);
127 }
128
129 int FL(remove)(const char* path);
FN(remove)130 int FN(remove)(const char* path) {
131 char real_path[WPATH_MAX];
132 PATH_WRAP(path, real_path);
133 DO_REAL(remove, real_path);
134 }
135
136 int FL(truncate)(const char* path, off_t len);
FN(truncate)137 int FN(truncate)(const char* path, off_t len) {
138 char real_path[WPATH_MAX];
139 PATH_WRAP(path, real_path);
140 DO_REAL(truncate, real_path, len);
141 }
142
143 int FL(rename)(const char* oldpath, const char* newpath);
FN(rename)144 int FN(rename)(const char* oldpath, const char* newpath) {
145 char real_oldpath[WPATH_MAX];
146 char real_newpath[WPATH_MAX];
147 PATH_WRAP(oldpath, real_oldpath);
148 PATH_WRAP(newpath, real_newpath);
149 DO_REAL(rename, real_oldpath, real_newpath);
150 }
151
152 char* FL(realpath)(const char* path, char* resolved_path);
FN(realpath)153 char* FN(realpath)(const char* path, char* resolved_path) {
154 char real_path[WPATH_MAX];
155 if (wrap_path(path, real_path)) {
156 return NULL;
157 }
158 return __real_realpath(real_path, resolved_path);
159 }
160
161 int FL(renameat)(int olddirfd, const char* oldpath, int newdirfd, const char* newpath);
FN(renameat)162 int FN(renameat)(int olddirfd, const char* oldpath, int newdirfd, const char* newpath) {
163 char real_oldpath[WPATH_MAX];
164 char real_newpath[WPATH_MAX];
165 PATH_WRAP(oldpath, real_oldpath);
166 PATH_WRAP(newpath, real_newpath);
167 DO_REAL(renameat, olddirfd, real_oldpath, newdirfd, real_newpath);
168 }
169
170 int FL(link)(const char* oldpath, const char* newpath);
FN(link)171 int FN(link)(const char* oldpath, const char* newpath) {
172 char real_oldpath[WPATH_MAX];
173 char real_newpath[WPATH_MAX];
174 PATH_WRAP(oldpath, real_oldpath);
175 PATH_WRAP(newpath, real_newpath);
176 DO_REAL(link, real_oldpath, real_newpath);
177 }
178
179 int FL(symlink)(const char* oldpath, const char* newpath);
FN(symlink)180 int FN(symlink)(const char* oldpath, const char* newpath) {
181 char real_oldpath[WPATH_MAX];
182 char real_newpath[WPATH_MAX];
183 PATH_WRAP(oldpath, real_oldpath);
184 PATH_WRAP(newpath, real_newpath);
185 DO_REAL(symlink, real_oldpath, real_newpath);
186 }
187
188 int FL(stat)(const char* fn, struct stat* s);
FN(stat)189 int FN(stat)(const char* fn, struct stat* s) {
190 char real_fn[WPATH_MAX];
191 PATH_WRAP(fn, real_fn);
192 DO_REAL(stat, real_fn, s);
193 }
194
195 int FL(utimes)(const char* fn, struct timeval t[2]);
FN(utimes)196 int FN(utimes)(const char* fn, struct timeval t[2]) {
197 char real_fn[WPATH_MAX];
198 PATH_WRAP(fn, real_fn);
199 DO_REAL(utimes, real_fn, t);
200 }
201