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