Line data Source code
1 : /* 2 : This program is free software: you can redistribute it and/or modify 3 : it under the terms of the GNU General Public License as published by 4 : the Free Software Foundation, either version 3 of the License, or 5 : (at your option) any later version. 6 : 7 : This program is distributed in the hope that it will be useful, 8 : but WITHOUT ANY WARRANTY; without even the implied warranty of 9 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 : GNU General Public License for more details. 11 : 12 : You should have received a copy of the GNU General Public License 13 : along with this program. If not, see <http://www.gnu.org/licenses/>. 14 : */ 15 : /* 16 : ArduPilot filesystem interface for posix systems 17 : */ 18 : 19 : #include "AP_Filesystem_config.h" 20 : 21 : #if AP_FILESYSTEM_POSIX_ENABLED 22 : 23 : #include "AP_Filesystem.h" 24 : #include <AP_HAL/AP_HAL.h> 25 : #include <AP_Vehicle/AP_Vehicle_Type.h> 26 : 27 : #if defined(__APPLE__) || defined(__OpenBSD__) 28 : #include <sys/mount.h> 29 : #elif defined(__FreeBSD__) 30 : #include <sys/param.h> 31 : #include <sys/mount.h> 32 : #elif CONFIG_HAL_BOARD != HAL_BOARD_QURT 33 : #include <sys/vfs.h> 34 : #endif 35 : 36 : #if AP_FILESYSTEM_POSIX_HAVE_UTIME 37 : #include <utime.h> 38 : #endif 39 : 40 : extern const AP_HAL::HAL& hal; 41 : 42 : /* 43 : map a filename so operations are relative to the current directory if needed 44 : */ 45 304316 : static const char *map_filename(const char *fname) 46 : { 47 : #if AP_FILESYSTEM_POSIX_MAP_FILENAME_ALLOC 48 : // this system needs to add a prefix to the filename, which means 49 : // memory allocation. This is needed for QURT which lacks chdir() 50 : char *fname2 = nullptr; 51 : asprintf(&fname2, "%s/%s", AP_FILESYSTEM_POSIX_MAP_FILENAME_BASEDIR, fname); 52 : return fname2; 53 : #else 54 : 55 : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL && !APM_BUILD_TYPE(APM_BUILD_Replay) 56 : // on SITL only allow paths under subdirectory. Users can still 57 : // escape with .. if they want to 58 304316 : if (strcmp(fname, "/") == 0) { 59 3 : return "."; 60 : } 61 304313 : if (*fname == '/') { 62 142 : fname++; 63 : } 64 : #endif 65 : // on Linux allow original name 66 304313 : return fname; 67 : #endif // AP_FILESYSTEM_POSIX_MAP_FILENAME_ALLOC 68 : } 69 : 70 304316 : static void map_filename_free(const char *fname) 71 : { 72 : #if AP_FILESYSTEM_POSIX_MAP_FILENAME_ALLOC 73 : ::free(const_cast<char*>(fname)); 74 : #endif 75 304316 : } 76 : 77 58010 : int AP_Filesystem_Posix::open(const char *fname, int flags, bool allow_absolute_paths) 78 : { 79 58010 : FS_CHECK_ALLOWED(-1); 80 58010 : if (! allow_absolute_paths) { 81 49956 : fname = map_filename(fname); 82 : } 83 : struct stat st; 84 113337 : if (::stat(fname, &st) == 0 && 85 55327 : ((st.st_mode & S_IFMT) != S_IFREG && (st.st_mode & S_IFMT) != S_IFLNK)) { 86 : // only allow links and files 87 0 : if (!allow_absolute_paths) { 88 0 : map_filename_free(fname); 89 : } 90 0 : return -1; 91 : } 92 : 93 : // we automatically add O_CLOEXEC as we always want it for ArduPilot FS usage 94 58010 : auto ret = ::open(fname, flags | O_CLOEXEC, 0644); 95 58010 : if (!allow_absolute_paths) { 96 49956 : map_filename_free(fname); 97 : } 98 58010 : return ret; 99 : } 100 : 101 53350 : int AP_Filesystem_Posix::close(int fd) 102 : { 103 53350 : FS_CHECK_ALLOWED(-1); 104 53350 : return ::close(fd); 105 : } 106 : 107 422094 : int32_t AP_Filesystem_Posix::read(int fd, void *buf, uint32_t count) 108 : { 109 422094 : FS_CHECK_ALLOWED(-1); 110 422093 : return ::read(fd, buf, count); 111 : } 112 : 113 1028165 : int32_t AP_Filesystem_Posix::write(int fd, const void *buf, uint32_t count) 114 : { 115 1028165 : FS_CHECK_ALLOWED(-1); 116 1028165 : return ::write(fd, buf, count); 117 : } 118 : 119 5 : int AP_Filesystem_Posix::fsync(int fd) 120 : { 121 : #if AP_FILESYSTEM_POSIX_HAVE_FSYNC 122 5 : FS_CHECK_ALLOWED(-1); 123 5 : return ::fsync(fd); 124 : #else 125 : // we have to pass success here as otherwise it is assumed to be 126 : // failed IO and the caller may close the fd and give up 127 : return 0; 128 : #endif 129 : } 130 : 131 101533 : int32_t AP_Filesystem_Posix::lseek(int fd, int32_t offset, int seek_from) 132 : { 133 101533 : FS_CHECK_ALLOWED(-1); 134 101533 : return ::lseek(fd, offset, seek_from); 135 : } 136 : 137 96756 : int AP_Filesystem_Posix::stat(const char *pathname, struct stat *stbuf) 138 : { 139 96756 : FS_CHECK_ALLOWED(-1); 140 96756 : pathname = map_filename(pathname); 141 96756 : auto ret = ::stat(pathname, stbuf); 142 96756 : map_filename_free(pathname); 143 96756 : return ret; 144 : } 145 : 146 3 : int AP_Filesystem_Posix::unlink(const char *pathname) 147 : { 148 3 : FS_CHECK_ALLOWED(-1); 149 3 : pathname = map_filename(pathname); 150 : // we match the FATFS interface and use unlink 151 : // for both files and directories 152 3 : int ret = ::rmdir(const_cast<char*>(pathname)); 153 3 : if (ret == -1) { 154 2 : ret = ::unlink(pathname); 155 : } 156 3 : map_filename_free(pathname); 157 3 : return ret; 158 : } 159 : 160 1782 : int AP_Filesystem_Posix::mkdir(const char *pathname) 161 : { 162 1782 : FS_CHECK_ALLOWED(-1); 163 1782 : pathname = map_filename(pathname); 164 1782 : auto ret = ::mkdir(const_cast<char*>(pathname), 0775); 165 1782 : map_filename_free(pathname); 166 1782 : return ret; 167 : } 168 : 169 20517 : void *AP_Filesystem_Posix::opendir(const char *pathname) 170 : { 171 20517 : FS_CHECK_ALLOWED(nullptr); 172 20517 : pathname = map_filename(pathname); 173 20517 : auto *ret = (void*)::opendir(pathname); 174 20517 : map_filename_free(pathname); 175 20517 : return ret; 176 : } 177 : 178 1573488 : struct dirent *AP_Filesystem_Posix::readdir(void *dirp) 179 : { 180 1573488 : FS_CHECK_ALLOWED(nullptr); 181 1573488 : return ::readdir((DIR *)dirp); 182 : } 183 : 184 20516 : int AP_Filesystem_Posix::closedir(void *dirp) 185 : { 186 20516 : FS_CHECK_ALLOWED(-1); 187 20516 : return ::closedir((DIR *)dirp); 188 : } 189 : 190 4 : int AP_Filesystem_Posix::rename(const char *oldpath, const char *newpath) 191 : { 192 4 : FS_CHECK_ALLOWED(-1); 193 4 : oldpath = map_filename(oldpath); 194 4 : newpath = map_filename(newpath); 195 4 : auto ret = ::rename(oldpath, newpath); 196 4 : map_filename_free(oldpath); 197 4 : map_filename_free(newpath); 198 4 : return ret; 199 : } 200 : 201 : // return free disk space in bytes 202 135293 : int64_t AP_Filesystem_Posix::disk_free(const char *path) 203 : { 204 : #if AP_FILESYSTEM_POSIX_HAVE_STATFS 205 135293 : FS_CHECK_ALLOWED(-1); 206 135293 : path = map_filename(path); 207 : struct statfs stats; 208 135293 : if (::statfs(path, &stats) < 0) { 209 1 : map_filename_free(path); 210 1 : return -1; 211 : } 212 135292 : map_filename_free(path); 213 135292 : return (((int64_t)stats.f_bavail) * stats.f_bsize); 214 : #else 215 : return -1; 216 : #endif 217 : } 218 : 219 : // return total disk space in bytes 220 1 : int64_t AP_Filesystem_Posix::disk_space(const char *path) 221 : { 222 : #if AP_FILESYSTEM_POSIX_HAVE_STATFS 223 1 : FS_CHECK_ALLOWED(-1); 224 1 : path = map_filename(path); 225 : struct statfs stats; 226 1 : if (::statfs(path, &stats) < 0) { 227 1 : map_filename_free(path); 228 1 : return -1; 229 : } 230 0 : map_filename_free(path); 231 0 : return (((int64_t)stats.f_blocks) * stats.f_bsize); 232 : #else 233 : return -1; 234 : #endif 235 : } 236 : 237 : 238 : /* 239 : set mtime on a file 240 : */ 241 0 : bool AP_Filesystem_Posix::set_mtime(const char *filename, const uint32_t mtime_sec) 242 : { 243 : #if AP_FILESYSTEM_POSIX_HAVE_UTIME 244 0 : FS_CHECK_ALLOWED(false); 245 0 : filename = map_filename(filename); 246 0 : struct utimbuf times {}; 247 0 : times.actime = mtime_sec; 248 0 : times.modtime = mtime_sec; 249 : 250 0 : auto ret = utime(filename, ×) == 0; 251 0 : map_filename_free(filename); 252 0 : return ret; 253 : #else 254 : return false; 255 : #endif 256 : } 257 : 258 : #endif // AP_FILESYSTEM_POSIX_ENABLED