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