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