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