1 /* 2 * Copyright 2017, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 /*! Shim over the host Haiku fs_attr API */ 7 8 9 #ifdef BUILDING_FS_SHELL 10 # include "compat.h" 11 # define B_OK 0 12 # define B_BAD_VALUE EINVAL 13 # define B_FILE_ERROR EBADF 14 # define B_ERROR EINVAL 15 # define B_ENTRY_NOT_FOUND ENOENT 16 # define B_NO_MEMORY ENOMEM 17 #else 18 # include <syscalls.h> 19 20 # include "fs_impl.h" 21 # include "fs_descriptors.h" 22 #endif 23 24 #include <dirent.h> 25 #include <errno.h> 26 #include <fcntl.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <sys/stat.h> 31 32 #include <map> 33 #include <string> 34 35 #include <fs_attr.h> 36 37 38 namespace BPrivate {} 39 using namespace BPrivate; 40 41 42 namespace { 43 44 // LocalFD 45 #include "LocalFD.h" 46 47 } // unnamed namspace 48 49 50 // # pragma mark - Public API 51 52 53 // fs_open_attr_dir 54 extern "C" DIR * 55 _haiku_build_fs_open_attr_dir(const char *path) 56 { 57 return fs_open_attr_dir(path); 58 } 59 60 // fs_lopen_attr_dir 61 extern "C" DIR* 62 _haiku_build_fs_lopen_attr_dir(const char *path) 63 { 64 return fs_lopen_attr_dir(path); 65 } 66 67 // fs_fopen_attr_dir 68 extern "C" DIR* 69 _haiku_build_fs_fopen_attr_dir(int fd) 70 { 71 LocalFD localFD; 72 status_t error = localFD.Init(fd); 73 if (error != B_OK) { 74 errno = error; 75 return NULL; 76 } 77 78 if (localFD.FD() < 0) { 79 return fs_lopen_attr_dir(localFD.Path()); 80 } else { 81 return fs_fopen_attr_dir(localFD.FD()); 82 } 83 } 84 85 // fs_close_attr_dir 86 extern "C" int 87 _haiku_build_fs_close_attr_dir(DIR *dir) 88 { 89 return fs_close_attr_dir(dir); 90 } 91 92 // fs_read_attr_dir 93 extern "C" struct dirent * 94 _haiku_build_fs_read_attr_dir(DIR *dir) 95 { 96 return fs_read_attr_dir(dir); 97 } 98 99 // fs_rewind_attr_dir 100 extern "C" void 101 _haiku_build_fs_rewind_attr_dir(DIR *dir) 102 { 103 return fs_rewind_attr_dir(dir); 104 } 105 106 // fs_fopen_attr 107 extern "C" int 108 _haiku_build_fs_fopen_attr(int fd, const char *attribute, uint32 type, int openMode) 109 { 110 if (fd < 0) { 111 errno = B_BAD_VALUE; 112 return -1; 113 } 114 115 LocalFD localFD; 116 status_t error = localFD.Init(fd); 117 if (error != B_OK) { 118 errno = error; 119 return -1; 120 } 121 122 if (localFD.FD() < 0) { 123 return fs_open_attr(localFD.Path(), attribute, type, 124 openMode | O_NOTRAVERSE); 125 } else { 126 return fs_fopen_attr(localFD.FD(), attribute, type, openMode); 127 } 128 } 129 130 // fs_close_attr 131 extern "C" int 132 _haiku_build_fs_close_attr(int fd) 133 { 134 return fs_close_attr(fd); 135 } 136 137 // fs_read_attr 138 extern "C" ssize_t 139 _haiku_build_fs_read_attr(int fd, const char* attribute, uint32 type, off_t pos, 140 void *buffer, size_t readBytes) 141 { 142 LocalFD localFD; 143 status_t error = localFD.Init(fd); 144 if (error != B_OK) { 145 errno = error; 146 return -1; 147 } 148 149 ssize_t bytesRead; 150 if (localFD.FD() < 0) { 151 int fd = open(localFD.Path(), O_RDONLY | O_NOTRAVERSE); 152 bytesRead = fs_read_attr(fd, attribute, type, 153 pos, buffer, readBytes); 154 close(fd); 155 } else { 156 bytesRead = fs_read_attr(localFD.FD(), attribute, type, 157 pos, buffer, readBytes); 158 } 159 if (bytesRead < 0) { 160 // Make sure, the error code is B_ENTRY_NOT_FOUND, if the attribute 161 // doesn't exist. 162 if (errno == ENOATTR || errno == ENODATA) 163 errno = B_ENTRY_NOT_FOUND; 164 return -1; 165 } 166 167 return bytesRead; 168 } 169 170 // fs_write_attr 171 extern "C" ssize_t 172 _haiku_build_fs_write_attr(int fd, const char* attribute, uint32 type, off_t pos, 173 const void *buffer, size_t writeBytes) 174 { 175 LocalFD localFD; 176 status_t error = localFD.Init(fd); 177 if (error != B_OK) { 178 errno = error; 179 return -1; 180 } 181 182 ssize_t written; 183 if (localFD.FD() < 0) { 184 int fd = open(localFD.Path(), O_NOTRAVERSE | O_WRONLY); 185 written = fs_write_attr(fd, attribute, type, 186 pos, buffer, writeBytes); 187 close(fd); 188 } else { 189 written = fs_write_attr(localFD.FD(), attribute, type, 190 pos, buffer, writeBytes); 191 } 192 193 return written; 194 } 195 196 // fs_remove_attr 197 extern "C" int 198 _haiku_build_fs_remove_attr(int fd, const char* attribute) 199 { 200 LocalFD localFD; 201 status_t error = localFD.Init(fd); 202 if (error != B_OK) { 203 errno = error; 204 return -1; 205 } 206 207 // remove attribute 208 int result; 209 if (localFD.FD() < 0) { 210 int fd = open(localFD.Path(), O_NOTRAVERSE | O_WRONLY); 211 result = fs_remove_attr(fd, attribute); 212 close(fd); 213 } else { 214 result = fs_remove_attr(localFD.FD(), attribute); 215 } 216 217 if (result < 0) { 218 // Make sure, the error code is B_ENTRY_NOT_FOUND, if the attribute 219 // doesn't exist. 220 if (errno == ENOATTR || errno == ENODATA) 221 errno = B_ENTRY_NOT_FOUND; 222 return -1; 223 } 224 return 0; 225 } 226 227 // fs_stat_attr 228 extern "C" int 229 _haiku_build_fs_stat_attr(int fd, const char *attribute, struct attr_info *attrInfo) 230 { 231 if (!attribute || !attrInfo) { 232 errno = B_BAD_VALUE; 233 return -1; 234 } 235 236 LocalFD localFD; 237 status_t error = localFD.Init(fd); 238 if (error != B_OK) { 239 errno = error; 240 return -1; 241 } 242 243 int result; 244 if (localFD.FD() < 0) { 245 int fd = open(localFD.Path(), O_NOTRAVERSE | O_RDONLY); 246 result = fs_stat_attr(fd, attribute, attrInfo); 247 close(fd); 248 } else { 249 result = fs_stat_attr(localFD.FD(), attribute, attrInfo); 250 } 251 252 return result; 253 } 254 255 256 // #pragma mark - Private Syscalls 257 258 259 #ifndef BUILDING_FS_SHELL 260 261 // _kern_open_attr_dir 262 int 263 _kern_open_attr_dir(int fd, const char *path) 264 { 265 // get node ref for the node 266 struct stat st; 267 status_t error = _kern_read_stat(fd, path, false, &st, 268 sizeof(struct stat)); 269 if (error != B_OK) { 270 errno = error; 271 return -1; 272 } 273 NodeRef ref(st); 274 275 DIR* dir; 276 if (path) { 277 // If a path was given, get a usable path. 278 string realPath; 279 status_t error = get_path(fd, path, realPath); 280 if (error != B_OK) 281 return error; 282 283 dir = _haiku_build_fs_open_attr_dir(realPath.c_str()); 284 } else 285 dir = _haiku_build_fs_fopen_attr_dir(fd); 286 287 if (!dir) 288 return errno; 289 290 // create descriptor 291 AttrDirDescriptor *descriptor = new AttrDirDescriptor(dir, ref); 292 return add_descriptor(descriptor); 293 } 294 295 // _kern_rename_attr 296 status_t 297 _kern_rename_attr(int fromFile, const char *fromName, int toFile, 298 const char *toName) 299 { 300 // not supported ATM 301 return B_BAD_VALUE; 302 } 303 304 // _kern_remove_attr 305 status_t 306 _kern_remove_attr(int fd, const char *name) 307 { 308 if (!name) 309 return B_BAD_VALUE; 310 311 if (_haiku_build_fs_remove_attr(fd, name) < 0) 312 return errno; 313 return B_OK; 314 } 315 316 #endif // ! BUILDING_FS_SHELL 317