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_impl.h" 25 #include "fs_descriptors.h" 26 27 28 using namespace std; 29 using namespace BPrivate; 30 31 static const char *sAttributeDirBasePath = HAIKU_BUILD_ATTRIBUTES_DIR; 32 33 // init_attribute_dir_base_dir 34 static status_t 35 init_attribute_dir_base_dir() 36 { 37 static bool initialized = false; 38 static status_t initError; 39 40 if (initialized) 41 return initError; 42 43 // stat the dir 44 struct stat st; 45 initError = B_OK; 46 if (lstat(sAttributeDirBasePath, &st) == 0) { 47 if (!S_ISDIR(st.st_mode)) { 48 // the attribute dir base dir is no directory 49 fprintf(stderr, "init_attribute_dir_base_dir(): The Attribute " 50 "directory base directory exists, but is no directory!\n"); 51 initError = B_FILE_ERROR; 52 } 53 54 } else { 55 // doesn't exist yet: create it 56 if (mkdir(sAttributeDirBasePath, S_IRWXU | S_IRWXG | S_IRWXO) < 0) 57 initError = errno; 58 } 59 60 initialized = true; 61 return initError; 62 } 63 64 // escape_attr_name 65 static string 66 escape_attr_name(const char *name) 67 { 68 string escapedName("_"); 69 while (*name != '\0') { 70 // we replace '/' with "_s" and '_' with "__" 71 if (*name == '/') 72 escapedName += "_s"; 73 else if (*name == '_') 74 escapedName += "__"; 75 else 76 escapedName += *name; 77 78 name++; 79 } 80 81 return escapedName; 82 } 83 84 // deescape_attr_name 85 static string 86 deescape_attr_name(const char *name) 87 { 88 if (name[0] != '_') { 89 debugger("deescape_attr_name(): name doesn't start with '_'!\n"); 90 return "___"; 91 } 92 name++; 93 94 string deescapedName; 95 while (*name != '\0') { 96 if (*name == '_') { 97 name++; 98 if (*name == 's') { 99 deescapedName += '/'; 100 } else if (*name == '_') { 101 deescapedName += '_'; 102 } else { 103 debugger("deescape_attr_name(): name contains invalid escaped " 104 "sequence!\n"); 105 name--; 106 } 107 } else 108 deescapedName += *name; 109 110 name++; 111 } 112 113 return deescapedName; 114 } 115 116 // get_attribute_dir_path 117 static string 118 get_attribute_dir_path(NodeRef ref) 119 { 120 string attrDirPath(sAttributeDirBasePath); 121 char buffer[32]; 122 sprintf(buffer, "/%lld", (int64)ref.node); 123 attrDirPath += buffer; 124 return attrDirPath; 125 } 126 127 // ensure_attribute_dir_exists 128 static status_t 129 ensure_attribute_dir_exists(NodeRef ref, const char *path, int fd) 130 { 131 // init the base directory here 132 status_t error = init_attribute_dir_base_dir(); 133 if (error != B_OK) 134 return error; 135 136 // stat the dir 137 string attrDirPath(get_attribute_dir_path(ref)); 138 struct stat st; 139 if (lstat(attrDirPath.c_str(), &st) == 0) { 140 if (!S_ISDIR(st.st_mode)) { 141 // the attribute dir is no directory 142 fprintf(stderr, "ensure_attribute_dir_exists(): Attribute " 143 "directory for node %lld exists, but is no directory!\n", 144 ref.node); 145 return B_FILE_ERROR; 146 } 147 148 return B_OK; 149 } 150 151 // doesn't exist yet: create it 152 if (mkdir(attrDirPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) < 0) 153 return errno; 154 155 return B_OK; 156 } 157 158 // open_attr_dir 159 static DIR * 160 open_attr_dir(NodeRef ref, const char *path, int fd) 161 { 162 // make sure the directory exists 163 status_t error = ensure_attribute_dir_exists(ref, path, fd); 164 if (error != B_OK) { 165 errno = error; 166 return NULL; 167 } 168 169 // open it 170 string dirPath(get_attribute_dir_path(ref)); 171 return opendir(dirPath.c_str()); 172 } 173 174 // get_attribute_path 175 static status_t 176 get_attribute_path(NodeRef ref, const char *path, int fd, 177 const char *attribute, string &attrPath, string &typePath) 178 { 179 if (!attribute || strlen(attribute) == 0) 180 return B_BAD_VALUE; 181 182 // make sure the attribute dir for the node exits 183 status_t error = ensure_attribute_dir_exists(ref, path, fd); 184 if (error != B_OK) { 185 errno = error; 186 return -1; 187 } 188 189 // construct the attribute path 190 attrPath = get_attribute_dir_path(ref) + '/'; 191 string attrName(escape_attr_name(attribute)); 192 typePath = attrPath + "t" + attrName; 193 attrPath += attrName; 194 195 return B_OK; 196 } 197 198 // get_attribute_path 199 static status_t 200 get_attribute_path(int fd, const char *attribute, string &attrPath, 201 string &typePath) 202 { 203 // stat the file to get a NodeRef 204 struct stat st; 205 if (fstat(fd, &st) < 0) 206 return errno; 207 NodeRef ref(st); 208 209 return get_attribute_path(ref, NULL, fd, attribute, attrPath, typePath); 210 } 211 212 213 #ifndef BUILDING_FS_SHELL 214 215 // get_attribute_path_virtual_fd 216 static status_t 217 get_attribute_path_virtual_fd(int fd, const char *attribute, string &attrPath, 218 string &typePath) 219 { 220 // stat the file to get a NodeRef 221 struct stat st; 222 status_t error = _kern_read_stat(fd, NULL, false, &st, sizeof(st)); 223 if (error != B_OK) 224 return error; 225 NodeRef ref(st); 226 227 // Try to get a path. If we can't get a path, this is must be a "real" 228 // (i.e. system) file descriptor, which is just as well. 229 string path; 230 bool pathValid = (get_path(fd, NULL, path) == B_OK); 231 232 // get the attribute path 233 return get_attribute_path(ref, (pathValid ? path.c_str() : NULL), 234 (pathValid ? -1 : fd), attribute, attrPath, typePath); 235 } 236 237 #endif // ! BUILDING_FS_SHELL 238 239 240 // # pragma mark - Public API 241 242 243 // fs_open_attr_dir 244 DIR * 245 fs_open_attr_dir(const char *path) 246 { 247 struct stat st; 248 if (lstat(path, &st)) 249 return NULL; 250 251 return open_attr_dir(NodeRef(st), path, -1); 252 } 253 254 // fs_fopen_attr_dir 255 DIR * 256 fs_fopen_attr_dir(int fd) 257 { 258 struct stat st; 259 260 #ifdef BUILDING_FS_SHELL 261 262 if (fstat(fd, &st) < 0) 263 return NULL; 264 265 return open_attr_dir(NodeRef(st), NULL, fd); 266 267 #else 268 269 status_t error = _kern_read_stat(fd, NULL, false, &st, 270 sizeof(struct stat)); 271 if (error != B_OK) { 272 errno = error; 273 return NULL; 274 } 275 276 // Try to get a path. If we can't get a path, this is must be a "real" 277 // (i.e. system) file descriptor, which is just as well. 278 string path; 279 bool pathValid = (get_path(fd, NULL, path) == B_OK); 280 281 // get the attribute path 282 return open_attr_dir(NodeRef(st), (pathValid ? path.c_str() : NULL), 283 (pathValid ? -1 : fd)); 284 285 #endif 286 } 287 288 // fs_close_attr_dir 289 int 290 fs_close_attr_dir(DIR *dir) 291 { 292 return closedir(dir); 293 } 294 295 // fs_read_attr_dir 296 struct dirent * 297 fs_read_attr_dir(DIR *dir) 298 { 299 struct dirent *entry = NULL; 300 while (true) { 301 // read the next entry 302 entry = readdir(dir); 303 if (!entry) 304 return NULL; 305 306 // ignore administrative entries; the 307 if (entry->d_name[0] == '_') { 308 string attrName = deescape_attr_name(entry->d_name); 309 strcpy(entry->d_name, attrName.c_str()); 310 return entry; 311 } 312 } 313 } 314 315 // fs_rewind_attr_dir 316 void 317 fs_rewind_attr_dir(DIR *dir) 318 { 319 rewinddir(dir); 320 } 321 322 // fs_open_attr 323 int 324 fs_open_attr(int fd, const char *attribute, uint32 type, int openMode) 325 { 326 if (!attribute) { 327 errno = B_BAD_VALUE; 328 return -1; 329 } 330 331 // get the attribute path 332 string attrPath; 333 string typePath; 334 status_t error = get_attribute_path(fd, attribute, attrPath, typePath); 335 if (error != B_OK) { 336 errno = error; 337 return -1; 338 } 339 340 // check, if the attribute already exists 341 struct stat st; 342 bool exists = (lstat(attrPath.c_str(), &st) == 0); 343 344 // open the attribute 345 int attrFD = open(attrPath.c_str(), openMode, S_IRWXU | S_IRWXG | S_IRWXO); 346 if (attrFD < 0) 347 return -1; 348 349 // set the type, if the attribute didn't exist yet 350 if (!exists) { 351 // create a file prefixed "t" 352 int typeFD = creat(typePath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO); 353 if (typeFD >= 0) { 354 // write the type into the file 355 if (write(typeFD, &type, sizeof(type)) < 0) 356 error = errno; 357 358 close(typeFD); 359 360 } else 361 error = errno; 362 363 // remove type and attribute file, if something went wrong 364 if (error != B_OK) { 365 if (typeFD > 0) { 366 unlink(typePath.c_str()); 367 } 368 369 close(attrFD); 370 unlink(attrPath.c_str()); 371 372 errno = error; 373 return -1; 374 } 375 } 376 377 return attrFD; 378 } 379 380 // fs_close_attr 381 int 382 fs_close_attr(int fd) 383 { 384 return close(fd); 385 } 386 387 // fs_read_attr 388 ssize_t 389 fs_read_attr(int fd, const char *attribute, uint32 type, off_t pos, 390 void *buffer, size_t readBytes) 391 { 392 // open the attribute 393 int attrFD = fs_open_attr(fd, attribute, type, O_RDONLY); 394 if (attrFD < 0) 395 return attrFD; 396 397 // read 398 ssize_t bytesRead = read_pos(attrFD, pos, buffer, readBytes); 399 status_t error = errno; 400 401 // close the attribute 402 fs_close_attr(attrFD); 403 404 if (bytesRead < 0) { 405 errno = error; 406 return -1; 407 } 408 409 return bytesRead; 410 } 411 412 // fs_write_attr 413 ssize_t 414 fs_write_attr(int fd, const char *attribute, uint32 type, off_t pos, 415 const void *buffer, size_t readBytes) 416 { 417 // open the attribute 418 int attrFD = fs_open_attr(fd, attribute, type, 419 O_WRONLY | O_CREAT | O_TRUNC); 420 if (attrFD < 0) 421 return attrFD; 422 423 // read 424 ssize_t bytesWritten = write_pos(attrFD, pos, buffer, readBytes); 425 status_t error = errno; 426 427 // close the attribute 428 fs_close_attr(attrFD); 429 430 if (bytesWritten < 0) { 431 errno = error; 432 return -1; 433 } 434 435 return bytesWritten; 436 } 437 438 // fs_remove_attr 439 int 440 fs_remove_attr(int fd, const char *attribute) 441 { 442 if (!attribute) { 443 errno = B_BAD_VALUE; 444 return -1; 445 } 446 447 // get the attribute path 448 string attrPath; 449 string typePath; 450 status_t error = get_attribute_path(fd, attribute, attrPath, typePath); 451 if (error != B_OK) { 452 errno = error; 453 return -1; 454 } 455 456 // remove the attribute 457 if (unlink(attrPath.c_str()) < 0) 458 return -1; 459 460 unlink(typePath.c_str()); 461 462 return B_OK; 463 } 464 465 // fs_stat_attr 466 int 467 fs_stat_attr(int fd, const char *attribute, struct attr_info *attrInfo) 468 { 469 if (!attribute || !attrInfo) { 470 errno = B_BAD_VALUE; 471 return -1; 472 } 473 474 // get the attribute path 475 string attrPath; 476 string typePath; 477 status_t error = get_attribute_path(fd, attribute, attrPath, typePath); 478 if (error != B_OK) { 479 errno = error; 480 return -1; 481 } 482 483 // stat the attribute file to get the size of the attribute 484 struct stat st; 485 if (lstat(attrPath.c_str(), &st) < 0) 486 return -1; 487 488 attrInfo->size = st.st_size; 489 490 // now open the attribute type file and read the attribute's type 491 int typeFD = open(typePath.c_str(), O_RDONLY); 492 if (typeFD < 0) 493 return -1; 494 495 ssize_t bytesRead = read(typeFD, &attrInfo->type, sizeof(attrInfo->type)); 496 if (bytesRead < 0) 497 error = errno; 498 else if (bytesRead < (ssize_t)sizeof(attrInfo->type)) 499 error = B_FILE_ERROR; 500 501 close(typeFD); 502 503 // fail on error 504 if (error != B_OK) { 505 errno = error; 506 return -1; 507 } 508 509 return 0; 510 } 511 512 513 // #pragma mark - Private Syscalls 514 515 516 #ifndef BUILDING_FS_SHELL 517 518 // _kern_open_attr_dir 519 int 520 _kern_open_attr_dir(int fd, const char *path) 521 { 522 // get node ref for the node 523 struct stat st; 524 status_t error = _kern_read_stat(fd, path, false, &st, 525 sizeof(struct stat)); 526 if (error != B_OK) { 527 errno = error; 528 return -1; 529 } 530 NodeRef ref(st); 531 532 // If a path was given, get a usable path. 533 string realPath; 534 if (path) { 535 error = get_path(fd, path, realPath); 536 if (error != B_OK) 537 return error; 538 } 539 540 // open the attr dir 541 DIR *dir = open_attr_dir(ref, (path ? realPath.c_str() : NULL), 542 (path ? -1 : fd)); 543 if (!dir) 544 return errno; 545 546 // create descriptor 547 AttrDirDescriptor *descriptor = new AttrDirDescriptor(dir, ref); 548 return add_descriptor(descriptor); 549 } 550 551 // _kern_rename_attr 552 status_t 553 _kern_rename_attr(int fromFile, const char *fromName, int toFile, 554 const char *toName) 555 { 556 if (!fromName || !toName) 557 return B_BAD_VALUE; 558 559 // get the attribute paths 560 string fromAttrPath; 561 string fromTypePath; 562 status_t error = get_attribute_path_virtual_fd(fromFile, fromName, 563 fromAttrPath, fromTypePath); 564 if (error != B_OK) 565 return error; 566 567 string toAttrPath; 568 string toTypePath; 569 error = get_attribute_path_virtual_fd(toFile, toName, toAttrPath, 570 toTypePath); 571 if (error != B_OK) 572 return error; 573 574 // rename the attribute and type files 575 if (rename(fromAttrPath.c_str(), toAttrPath.c_str()) < 0) 576 return errno; 577 578 if (rename(fromTypePath.c_str(), toTypePath.c_str()) < 0) { 579 // renaming the type file failed: try to rename back the attribute file 580 error = errno; 581 582 rename(toAttrPath.c_str(), fromAttrPath.c_str()); 583 584 return error; 585 } 586 587 return B_OK; 588 } 589 590 // _kern_remove_attr 591 status_t 592 _kern_remove_attr(int fd, const char *name) 593 { 594 if (!name) 595 return B_BAD_VALUE; 596 597 // get the attribute path 598 string attrPath; 599 string typePath; 600 status_t error = get_attribute_path_virtual_fd(fd, name, attrPath, 601 typePath); 602 if (error != B_OK) 603 return error; 604 605 // remove the attribute 606 if (unlink(attrPath.c_str()) < 0) 607 return errno; 608 609 unlink(typePath.c_str()); 610 611 return B_OK; 612 } 613 614 #endif // ! BUILDING_FS_SHELL 615