1 2 #ifdef BUILDING_FS_SHELL 3 # include "compat.h" 4 # define B_OK 0 5 # define B_BAD_VALUE EINVAL 6 # define B_FILE_ERROR EBADF 7 #else 8 # include <BeOSBuildCompatibility.h> 9 # include <syscalls.h> 10 #endif 11 12 #include <dirent.h> 13 #include <errno.h> 14 #include <fcntl.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <unistd.h> 18 #include <sys/stat.h> 19 20 #include <string> 21 22 #include <fs_attr.h> 23 24 #include "fs_attr_impl.h" 25 26 using namespace std; 27 using namespace BPrivate; 28 29 static const char *sAttributeDirBasePath = HAIKU_BUILD_ATTRIBUTES_DIR; 30 31 // init_attribute_dir_base_dir 32 static status_t 33 init_attribute_dir_base_dir() 34 { 35 static bool initialized = false; 36 static status_t initError; 37 38 if (initialized) 39 return initError; 40 41 // stat the dir 42 struct stat st; 43 initError = B_OK; 44 if (lstat(sAttributeDirBasePath, &st) == 0) { 45 if (!S_ISDIR(st.st_mode)) { 46 // the attribute dir base dir is no directory 47 fprintf(stderr, "init_attribute_dir_base_dir(): The Attribute " 48 "directory base directory exists, but is no directory!\n"); 49 initError = B_FILE_ERROR; 50 } 51 52 } else { 53 // doesn't exist yet: create it 54 if (mkdir(sAttributeDirBasePath, S_IRWXU | S_IRWXG | S_IRWXO) < 0) 55 initError = errno; 56 } 57 58 initialized = true; 59 return initError; 60 } 61 62 // escape_attr_name 63 static string 64 escape_attr_name(const char *name) 65 { 66 string escapedName("_"); 67 while (*name != '\0') { 68 // we replace '/' with "_s" and '_' with "__" 69 if (*name == '/') 70 escapedName += "_s"; 71 else if (*name == '_') 72 escapedName += "__"; 73 else 74 escapedName += *name; 75 76 name++; 77 } 78 79 return escapedName; 80 } 81 82 // deescape_attr_name 83 static string 84 deescape_attr_name(const char *name) 85 { 86 if (name[0] != '_') { 87 debugger("deescape_attr_name(): name doesn't start with '_'!\n"); 88 return "___"; 89 } 90 name++; 91 92 string deescapedName; 93 while (*name != '\0') { 94 if (*name == '_') { 95 name++; 96 if (*name == 's') { 97 deescapedName += '/'; 98 } else if (*name == '_') { 99 deescapedName += '_'; 100 } else { 101 debugger("deescape_attr_name(): name contains invalid escaped " 102 "sequence!\n"); 103 name--; 104 } 105 } else 106 deescapedName += *name; 107 108 name++; 109 } 110 111 return deescapedName; 112 } 113 114 // get_attribute_dir_path 115 static string 116 get_attribute_dir_path(NodeRef ref) 117 { 118 string attrDirPath(sAttributeDirBasePath); 119 char buffer[32]; 120 sprintf(buffer, "/%lld", (int64)ref.node); 121 attrDirPath += buffer; 122 return attrDirPath; 123 } 124 125 // ensure_attribute_dir_exists 126 static status_t 127 ensure_attribute_dir_exists(NodeRef ref) 128 { 129 // init the base directory here 130 status_t error = init_attribute_dir_base_dir(); 131 if (error != B_OK) 132 return error; 133 134 // stat the dir 135 string attrDirPath(get_attribute_dir_path(ref)); 136 struct stat st; 137 if (lstat(attrDirPath.c_str(), &st) == 0) { 138 if (!S_ISDIR(st.st_mode)) { 139 // the attribute dir is no directory 140 fprintf(stderr, "ensure_attribute_dir_exists(): Attribute " 141 "directory for node %lld exists, but is no directory!\n"); 142 return B_FILE_ERROR; 143 } 144 145 return B_OK; 146 } 147 148 // doesn't exist yet: create it 149 if (mkdir(attrDirPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) < 0) 150 return errno; 151 return B_OK; 152 } 153 154 // open_attr_dir 155 DIR * 156 BPrivate::open_attr_dir(NodeRef ref) 157 { 158 // make sure the directory exists 159 status_t error = ensure_attribute_dir_exists(ref); 160 if (error != B_OK) { 161 errno = error; 162 return NULL; 163 } 164 165 // open it 166 string dirPath(get_attribute_dir_path(ref)); 167 return opendir(dirPath.c_str()); 168 } 169 170 // get_attribute_path 171 status_t 172 BPrivate::get_attribute_path(NodeRef ref, const char *attribute, 173 string &attrPath, string &typePath) 174 { 175 if (!attribute || strlen(attribute) == 0) 176 return B_BAD_VALUE; 177 178 // make sure the attribute dir for the node exits 179 status_t error = ensure_attribute_dir_exists(ref); 180 if (error != B_OK) { 181 errno = error; 182 return -1; 183 } 184 185 // construct the attribute path 186 attrPath = get_attribute_dir_path(ref) + '/'; 187 string attrName(escape_attr_name(attribute)); 188 typePath = attrPath + "t" + attrName; 189 attrPath += attrName; 190 191 return B_OK; 192 } 193 194 // get_attribute_path 195 static status_t 196 get_attribute_path(int fd, const char *attribute, string &attrPath, 197 string &typePath) 198 { 199 // stat the file to get a NodeRef 200 struct stat st; 201 if (fstat(fd, &st) < 0) 202 return errno; 203 NodeRef ref(st); 204 205 return get_attribute_path(ref, attribute, attrPath, typePath); 206 } 207 208 // fs_open_attr_dir 209 DIR * 210 fs_open_attr_dir(const char *path) 211 { 212 struct stat st; 213 if (lstat(path, &st)) 214 return NULL; 215 216 return open_attr_dir(NodeRef(st)); 217 } 218 219 // fs_fopen_attr_dir 220 DIR * 221 fs_fopen_attr_dir(int fd) 222 { 223 struct stat st; 224 225 #ifdef BUILDING_FS_SHELL 226 227 if (fstat(fd, &st) < 0) 228 return NULL; 229 230 #else 231 232 status_t error = _kern_read_stat(fd, NULL, false, &st, 233 sizeof(struct stat)); 234 if (error != B_OK) { 235 errno = error; 236 return NULL; 237 } 238 239 #endif 240 241 return open_attr_dir(NodeRef(st)); 242 } 243 244 // fs_close_attr_dir 245 int 246 fs_close_attr_dir(DIR *dir) 247 { 248 return closedir(dir); 249 } 250 251 // fs_read_attr_dir 252 struct dirent * 253 fs_read_attr_dir(DIR *dir) 254 { 255 struct dirent *entry = NULL; 256 while (true) { 257 // read the next entry 258 entry = readdir(dir); 259 if (!entry) 260 return NULL; 261 262 // ignore administrative entries; the 263 if (entry->d_name[0] == '_') { 264 string attrName = deescape_attr_name(entry->d_name); 265 strcpy(entry->d_name, attrName.c_str()); 266 return entry; 267 } 268 } 269 } 270 271 // fs_rewind_attr_dir 272 void 273 fs_rewind_attr_dir(DIR *dir) 274 { 275 rewinddir(dir); 276 } 277 278 // fs_open_attr 279 int 280 fs_open_attr(int fd, const char *attribute, uint32 type, int openMode) 281 { 282 if (!attribute) { 283 errno = B_BAD_VALUE; 284 return -1; 285 } 286 287 // get the attribute path 288 string attrPath; 289 string typePath; 290 status_t error = get_attribute_path(fd, attribute, attrPath, typePath); 291 if (error != B_OK) { 292 errno = error; 293 return -1; 294 } 295 296 // check, if the attribute already exists 297 struct stat st; 298 bool exists = (lstat(attrPath.c_str(), &st) == 0); 299 300 // open the attribute 301 int attrFD = open(attrPath.c_str(), openMode, S_IRWXU | S_IRWXG | S_IRWXO); 302 if (attrFD < 0) 303 return -1; 304 305 // set the type, if the attribute didn't exist yet 306 if (!exists) { 307 // create a file prefixed "t" 308 int typeFD = creat(typePath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO); 309 if (typeFD >= 0) { 310 // write the type into the file 311 if (write(typeFD, &type, sizeof(type)) < 0) 312 error = errno; 313 314 close(typeFD); 315 316 } else 317 error = errno; 318 319 // remove type and attribute file, if something went wrong 320 if (error != B_OK) { 321 if (typeFD > 0) { 322 unlink(typePath.c_str()); 323 } 324 325 close(attrFD); 326 unlink(attrPath.c_str()); 327 328 errno = error; 329 return -1; 330 } 331 } 332 333 return attrFD; 334 } 335 336 // fs_close_attr 337 int 338 fs_close_attr(int fd) 339 { 340 return close(fd); 341 } 342 343 // fs_read_attr 344 ssize_t 345 fs_read_attr(int fd, const char *attribute, uint32 type, off_t pos, 346 void *buffer, size_t readBytes) 347 { 348 // open the attribute 349 int attrFD = fs_open_attr(fd, attribute, type, O_RDONLY); 350 if (attrFD < 0) 351 return attrFD; 352 353 // read 354 ssize_t bytesRead = read_pos(attrFD, pos, buffer, readBytes); 355 status_t error = errno; 356 357 // close the attribute 358 fs_close_attr(attrFD); 359 360 if (bytesRead < 0) { 361 errno = error; 362 return -1; 363 } 364 365 return bytesRead; 366 } 367 368 // fs_write_attr 369 ssize_t 370 fs_write_attr(int fd, const char *attribute, uint32 type, off_t pos, 371 const void *buffer, size_t readBytes) 372 { 373 // open the attribute 374 int attrFD = fs_open_attr(fd, attribute, type, 375 O_WRONLY | O_CREAT | O_TRUNC); 376 if (attrFD < 0) 377 return attrFD; 378 379 // read 380 ssize_t bytesWritten = write_pos(attrFD, pos, buffer, readBytes); 381 status_t error = errno; 382 383 // close the attribute 384 fs_close_attr(attrFD); 385 386 if (bytesWritten < 0) { 387 errno = error; 388 return -1; 389 } 390 391 return bytesWritten; 392 } 393 394 // fs_remove_attr 395 int 396 fs_remove_attr(int fd, const char *attribute) 397 { 398 if (!attribute) { 399 errno = B_BAD_VALUE; 400 return -1; 401 } 402 403 // get the attribute path 404 string attrPath; 405 string typePath; 406 status_t error = get_attribute_path(fd, attribute, attrPath, typePath); 407 if (error != B_OK) { 408 errno = error; 409 return -1; 410 } 411 412 // remove the attribute 413 if (unlink(attrPath.c_str()) < 0) 414 return -1; 415 416 unlink(typePath.c_str()); 417 418 return B_OK; 419 } 420 421 // fs_stat_attr 422 int 423 fs_stat_attr(int fd, const char *attribute, struct attr_info *attrInfo) 424 { 425 if (!attribute || !attrInfo) { 426 errno = B_BAD_VALUE; 427 return -1; 428 } 429 430 // get the attribute path 431 string attrPath; 432 string typePath; 433 status_t error = get_attribute_path(fd, attribute, attrPath, typePath); 434 if (error != B_OK) { 435 errno = error; 436 return -1; 437 } 438 439 // stat the attribute file to get the size of the attribute 440 struct stat st; 441 if (lstat(attrPath.c_str(), &st) < 0) 442 return -1; 443 444 attrInfo->size = st.st_size; 445 446 // now open the attribute type file and read the attribute's type 447 int typeFD = open(typePath.c_str(), O_RDONLY); 448 if (typeFD < 0) 449 return -1; 450 451 ssize_t bytesRead = read(typeFD, &attrInfo->type, sizeof(attrInfo->type)); 452 if (bytesRead < 0) 453 error = errno; 454 else if (bytesRead < (ssize_t)sizeof(attrInfo->type)) 455 error = B_FILE_ERROR; 456 457 close(typeFD); 458 459 // fail on error 460 if (error != B_OK) { 461 errno = error; 462 return -1; 463 } 464 465 return 0; 466 } 467 468