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
31int 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
67static 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
85int FL(open)(const char* path, int flags, mode_t mode);
86int 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
92DIR* FL(opendir)(const char* path);
93DIR* 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
101int FL(chdir)(const char* path);
102int 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
108int FL(mkdir)(const char* path, mode_t mode);
109int 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
115int FL(unlink)(const char* path);
116int 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
122int FL(rmdir)(const char* path);
123int 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
129int FL(remove)(const char* path);
130int 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
136int FL(truncate)(const char* path, off_t len);
137int 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
143int FL(rename)(const char* oldpath, const char* newpath);
144int 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
152char* FL(realpath)(const char* path, char* resolved_path);
153char* 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
161int FL(renameat)(int olddirfd, const char* oldpath, int newdirfd, const char* newpath);
162int 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
170int FL(link)(const char* oldpath, const char* newpath);
171int 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
179int FL(symlink)(const char* oldpath, const char* newpath);
180int 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
188int FL(stat)(const char* fn, struct stat* s);
189int 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
195int FL(utimes)(const char* fn, struct timeval t[2]);
196int 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