1 /* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "FUSEFileSystem.h" 7 8 #include <stdlib.h> 9 #include <string.h> 10 11 #include <new> 12 13 #include "fuse_fs.h" 14 #include "FUSELowLevel.h" 15 #include "FUSEVolume.h" 16 17 #include "../RequestThread.h" 18 19 20 class FUSEFileSystem::ArgumentVector { 21 private: 22 enum { MAX_ARGUMENTS = 128 }; 23 24 public: 25 ArgumentVector() 26 : 27 fBuffer(NULL), 28 fCount(0) 29 { 30 } 31 32 ~ArgumentVector() 33 { 34 free(fBuffer); 35 } 36 37 const char* const* Arguments() const 38 { 39 return fArguments; 40 } 41 42 int ArgumentCount() const 43 { 44 return fCount; 45 } 46 47 status_t Init(const char* firstElement, const char* arguments) 48 { 49 size_t firstElementSize = firstElement != NULL 50 ? strlen(firstElement) + 1 : 0; 51 52 // allocate the buffer 53 fBuffer = (char*)malloc(firstElementSize + strlen(arguments) + 1); 54 if (fBuffer == NULL) 55 return B_NO_MEMORY; 56 57 fCount = 0; 58 59 bool inArgument = false; 60 int bufferIndex = 0; 61 62 // push the first element, if given 63 if (firstElement != NULL) { 64 memcpy(fBuffer, firstElement, firstElementSize); 65 fArguments[fCount++] = fBuffer; 66 bufferIndex = firstElementSize; 67 } 68 69 // parse the given string 70 for (; *arguments != '\0'; arguments++) { 71 char c = *arguments; 72 switch (c) { 73 case ' ': 74 case '\t': 75 case '\r': 76 case '\n': 77 // white-space marks argument boundaries 78 if (inArgument) { 79 // terminate the current argument 80 fBuffer[bufferIndex++] = '\0'; 81 inArgument = false; 82 } 83 break; 84 case '\\': 85 c = *++arguments; 86 if (c == '\0') 87 break; 88 // fall through 89 default: 90 if (!inArgument) { 91 // push a new argument 92 if (fCount == MAX_ARGUMENTS) 93 break; 94 95 fArguments[fCount++] = fBuffer + bufferIndex; 96 inArgument = true; 97 } 98 99 fBuffer[bufferIndex++] = c; 100 break; 101 } 102 } 103 104 // terminate the last argument 105 if (inArgument) 106 fBuffer[bufferIndex++] = '\0'; 107 108 // NULL terminate the argument array 109 fArguments[fCount] = NULL; 110 111 return B_OK; 112 } 113 114 private: 115 char* fBuffer; 116 const char* fArguments[MAX_ARGUMENTS + 1]; 117 int fCount; 118 }; 119 120 121 FUSEFileSystem::FUSEFileSystem(const char* fsName, 122 int (*mainFunction)(int, const char* const*)) 123 : 124 FileSystem(fsName), 125 fMainFunction(mainFunction), 126 fInitThread(-1), 127 fInitStatus(B_NO_INIT), 128 fInitSemaphore(-1), 129 fExitSemaphore(-1), 130 fInitParameters(NULL), 131 fUserData(NULL), 132 fFS(NULL) 133 { 134 fClientFSType = CLIENT_FS_FUSE; 135 136 // FS capabilities 137 fCapabilities.ClearAll(); 138 fCapabilities.Set(FS_CAPABILITY_MOUNT, true); 139 } 140 141 142 FUSEFileSystem::~FUSEFileSystem() 143 { 144 if (fInitSemaphore >= 0) 145 delete_sem(fInitSemaphore); 146 147 if (fExitSemaphore >= 0) 148 delete_sem(fExitSemaphore); 149 150 if (fInitThread >= 0) 151 wait_for_thread(fInitThread, NULL); 152 } 153 154 155 status_t 156 FUSEFileSystem::CreateVolume(Volume** _volume, dev_t id) 157 { 158 printf("FUSEFileSystem::CreateVolume()\n"); 159 // Only one volume is possible 160 if (!fVolumes.IsEmpty()) 161 RETURN_ERROR(B_BUSY); 162 163 // create the volume 164 FUSEVolume* volume = new(std::nothrow) FUSEVolume(this, id); 165 if (volume == NULL) 166 return B_NO_MEMORY; 167 168 status_t error = volume->Init(); 169 if (error != B_OK) { 170 delete volume; 171 return error; 172 } 173 174 *_volume = volume; 175 return B_OK; 176 } 177 178 179 status_t 180 FUSEFileSystem::DeleteVolume(Volume* volume) 181 { 182 delete volume; 183 return B_OK; 184 } 185 186 187 void 188 FUSEFileSystem::InitRequestThreadContext(RequestThreadContext* context) 189 { 190 // Statically assert that fuse_context fits in the RequestThreadContext 191 // FS data. We can't include <Debug.h> as it clashes with our "Debug.h". 192 do { 193 static const int staticAssertHolds 194 = sizeof(fuse_context) <= REQUEST_THREAD_CONTEXT_FS_DATA_SIZE; 195 struct __staticAssertStruct__ { 196 char __static_assert_failed__[2 * staticAssertHolds - 1]; 197 }; 198 } while (false); 199 200 // init a fuse_context 201 KernelRequest* request = context->GetRequest(); 202 fuse_context* fuseContext = (fuse_context*)context->GetFSData(); 203 fuseContext->fuse = (struct fuse*)this; 204 fuseContext->uid = request->user; 205 fuseContext->gid = request->group; 206 fuseContext->pid = request->team; 207 fuseContext->private_data = fFS != NULL ? fFS->userData : NULL; 208 } 209 210 211 status_t 212 FUSEFileSystem::InitClientFS(const char* parameters) 213 { 214 PRINT(("FUSEFileSystem::InitClientFS()\n")); 215 // create the semaphores we need 216 fInitSemaphore = create_sem(0, "FUSE init sem"); 217 if (fInitSemaphore < 0) 218 RETURN_ERROR(fInitSemaphore); 219 220 fExitSemaphore = create_sem(0, "FUSE exit sem"); 221 if (fExitSemaphore < 0) 222 RETURN_ERROR(fExitSemaphore); 223 224 fInitStatus = 1; 225 fInitParameters = parameters; 226 227 // Start the initialization thread -- it will call main() and won't return 228 // until unmounting. 229 fInitThread = spawn_thread(&_InitializationThreadEntry, 230 "FUSE init", B_NORMAL_PRIORITY, this); 231 if (fInitThread < 0) 232 RETURN_ERROR(fInitThread); 233 234 resume_thread(fInitThread); 235 236 // wait for the initialization to finish 237 PRINT((" waiting for init thread...\n")); 238 while (acquire_sem(fInitSemaphore) == B_INTERRUPTED) { 239 } 240 241 PRINT((" waiting for init thread done\n")); 242 fInitSemaphore = -1; 243 244 if (fInitStatus > 0) 245 RETURN_ERROR(B_ERROR); 246 if (fInitStatus != B_OK) 247 RETURN_ERROR(fInitStatus); 248 249 // initialization went fine 250 return B_OK; 251 } 252 253 254 void 255 FUSEFileSystem::ExitClientFS(status_t status) 256 { 257 // set the exit status and notify the initialization thread 258 fExitStatus = status; 259 if (fExitSemaphore >= 0) 260 delete_sem(fExitSemaphore); 261 262 if (fInitThread >= 0) 263 wait_for_thread(fInitThread, NULL); 264 } 265 266 267 status_t 268 FUSEFileSystem::FinishInitClientFS(fuse_config* config, 269 const fuse_operations* ops, size_t opSize, void* userData) 270 { 271 PRINT(("FUSEFileSystem::FinishInitClientFS()\n")); 272 fExitStatus = B_ERROR; 273 274 fFUSEConfig = *config; 275 276 // do the initialization 277 fInitStatus = _InitClientFS(ops, opSize, userData); 278 return fInitStatus; 279 } 280 281 282 status_t 283 FUSEFileSystem::FinishInitClientFS(fuse_config* config, 284 const fuse_lowlevel_ops* ops, size_t opSize, void* userData) 285 { 286 PRINT(("FUSEFileSystem::FinishInitClientFS()\n")); 287 fExitStatus = B_ERROR; 288 289 fFUSEConfig = *config; 290 291 // do the initialization 292 fInitStatus = _InitClientFS(ops, opSize, userData); 293 return fInitStatus; 294 } 295 296 297 status_t 298 FUSEFileSystem::MainLoop(bool multithreaded) 299 { 300 // TODO: Respect the multithreaded flag! 301 302 PRINT(("FUSEFileSystem::FinishMounting()\n")); 303 // notify the mount thread 304 PRINT((" notifying mount thread\n")); 305 delete_sem(fInitSemaphore); 306 307 // loop until unmounting 308 PRINT((" waiting for unmounting...\n")); 309 while (acquire_sem(fExitSemaphore) == B_INTERRUPTED) { 310 } 311 PRINT((" waiting for unmounting done\n")); 312 313 fExitSemaphore = -1; 314 315 if (fFS != NULL) 316 fuse_fs_destroy(fFS); 317 else 318 fuse_ll_destroy(&fLowLevelOps, fUserData); 319 320 return fExitStatus; 321 } 322 323 324 /*static*/ status_t 325 FUSEFileSystem::_InitializationThreadEntry(void* data) 326 { 327 return ((FUSEFileSystem*)data)->_InitializationThread(); 328 } 329 330 331 status_t 332 FUSEFileSystem::_InitializationThread() 333 { 334 // parse the parameters 335 ArgumentVector args; 336 status_t error = args.Init(GetName(), fInitParameters); 337 if (error != B_OK) { 338 fInitStatus = error; 339 delete_sem(fInitSemaphore); 340 return B_OK; 341 } 342 343 // call main -- should not return until unmounting 344 fMainFunction(args.ArgumentCount(), args.Arguments()); 345 printf("FUSEFileSystem::_InitializationThread(): main() returned!\n"); 346 347 if (fInitStatus > 0 && fInitSemaphore >= 0) { 348 // something went wrong early -- main() returned without calling 349 // fuse_main() 350 fInitStatus = B_ERROR; 351 delete_sem(fInitSemaphore); 352 } 353 354 return B_OK; 355 } 356 357 358 status_t 359 FUSEFileSystem::_InitClientFS(const fuse_operations* ops, size_t opSize, 360 void* userData) 361 { 362 // create a fuse_fs object 363 fFS = fuse_fs_new(ops, opSize, userData); 364 if (fFS == NULL) 365 return B_ERROR; 366 367 _InitCapabilities(); 368 PRINT(("volume capabilities:\n")); 369 fVolumeCapabilities.Dump(); 370 PRINT(("node capabilities:\n")); 371 fNodeCapabilities.Dump(); 372 373 // init connection info 374 fConnectionInfo.proto_major = 0; 375 fConnectionInfo.proto_minor = 0; 376 fConnectionInfo.async_read = false; 377 fConnectionInfo.max_write = 64 * 1024; 378 fConnectionInfo.max_readahead = 64 * 1024; 379 fConnectionInfo.capable = FUSE_CAP_ATOMIC_O_TRUNC | FUSE_CAP_BIG_WRITES | FUSE_CAP_IOCTL_DIR 380 | FUSE_CAP_HAIKU_FUSE_EXTENSIONS; 381 382 fuse_fs_init(fFS, &fConnectionInfo); 383 384 return B_OK; 385 } 386 387 388 status_t 389 FUSEFileSystem::_InitClientFS(const fuse_lowlevel_ops* lowLevelOps, size_t lowLevelOpSize, 390 void* userData) 391 { 392 fLowLevelOps = *lowLevelOps; 393 394 _InitCapabilities(); 395 PRINT(("volume capabilities:\n")); 396 fVolumeCapabilities.Dump(); 397 PRINT(("node capabilities:\n")); 398 fNodeCapabilities.Dump(); 399 400 // init connection info 401 fConnectionInfo.proto_major = 0; 402 fConnectionInfo.proto_minor = 0; 403 fConnectionInfo.async_read = false; 404 fConnectionInfo.max_write = 64 * 1024; 405 fConnectionInfo.max_readahead = 64 * 1024; 406 fUserData = userData; 407 408 fuse_ll_init(&fLowLevelOps, userData, &fConnectionInfo); 409 410 return B_OK; 411 } 412 413 414 void 415 FUSEFileSystem::_InitCapabilities() 416 { 417 fVolumeCapabilities.ClearAll(); 418 fNodeCapabilities.ClearAll(); 419 420 // Volume operations 421 fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_UNMOUNT, true); 422 fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_GET_VNODE, true); 423 // emulated 424 425 // vnode operations 426 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_LOOKUP, true); 427 // emulated 428 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_GET_VNODE_NAME, true); 429 // emulated 430 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_PUT_VNODE, true); 431 // emulated 432 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REMOVE_VNODE, true); 433 // emulated 434 435 // index directory & index operations 436 // missing: FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR 437 // missing: FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR 438 // missing: FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE 439 // missing: FS_VOLUME_CAPABILITY_READ_INDEX_DIR 440 // missing: FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR 441 442 // missing: FS_VOLUME_CAPABILITY_CREATE_INDEX 443 // missing: FS_VOLUME_CAPABILITY_REMOVE_INDEX 444 // missing: FS_VOLUME_CAPABILITY_READ_INDEX_STAT 445 446 // query operations 447 // missing: FS_VOLUME_CAPABILITY_OPEN_QUERY 448 // missing: FS_VOLUME_CAPABILITY_CLOSE_QUERY 449 // missing: FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE 450 // missing: FS_VOLUME_CAPABILITY_READ_QUERY 451 // missing: FS_VOLUME_CAPABILITY_REWIND_QUERY 452 453 // VM file access 454 // missing: FS_VNODE_CAPABILITY_CAN_PAGE 455 // missing: FS_VNODE_CAPABILITY_READ_PAGES 456 // missing: FS_VNODE_CAPABILITY_WRITE_PAGES 457 458 // cache file access 459 // missing: FS_VNODE_CAPABILITY_GET_FILE_MAP 460 461 // common operations 462 // missing: FS_VNODE_CAPABILITY_IOCTL 463 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_SET_FLAGS, true); 464 // emulated 465 // missing: FS_VNODE_CAPABILITY_SELECT 466 // missing: FS_VNODE_CAPABILITY_DESELECT 467 468 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE_ATTR, false); 469 470 if (fFS == NULL) { 471 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FSYNC, fLowLevelOps.fsync); 472 473 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_SYMLINK, fLowLevelOps.readlink); 474 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_SYMLINK, fLowLevelOps.symlink); 475 476 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_LINK, fLowLevelOps.link); 477 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_UNLINK, fLowLevelOps.unlink); 478 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_RENAME, fLowLevelOps.rename); 479 480 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_ACCESS, fLowLevelOps.access); 481 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_STAT, fLowLevelOps.getattr); 482 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_STAT, fLowLevelOps.setattr != NULL); 483 484 fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_READ_FS_INFO, fLowLevelOps.statfs); 485 // missing: FS_VOLUME_CAPABILITY_WRITE_FS_INFO 486 fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_SYNC, fLowLevelOps.fsync); 487 // emulated via fsync() 488 489 // file operations 490 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE, fLowLevelOps.create); 491 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN, fLowLevelOps.open); 492 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE, fLowLevelOps.flush); 493 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_COOKIE, fLowLevelOps.release); 494 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ, fLowLevelOps.read); 495 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE, fLowLevelOps.write); 496 497 // directory operations 498 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_DIR, fLowLevelOps.mkdir); 499 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REMOVE_DIR, fLowLevelOps.rmdir); 500 bool readDirSupport = fLowLevelOps.opendir != NULL || fLowLevelOps.readdir != NULL; 501 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_DIR, readDirSupport); 502 // not needed: FS_VNODE_CAPABILITY_CLOSE_DIR 503 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_DIR_COOKIE, readDirSupport); 504 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_DIR, readDirSupport); 505 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_DIR, readDirSupport); 506 507 // attribute directory operations 508 bool hasAttributes = fLowLevelOps.listxattr != NULL; 509 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR, hasAttributes); 510 // not needed: FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR 511 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE, hasAttributes); 512 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_DIR, hasAttributes); 513 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_ATTR_DIR, hasAttributes); 514 515 // attribute operations 516 // // we emulate open_attr() and free_attr_dir_cookie() if either read_attr() 517 // // or write_attr() is present 518 // bool hasAttributes = (fLowLevelOps.read_attr || fLowLevelOps.write_attr); 519 // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_ATTR, hasAttributes); 520 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR, hasAttributes); 521 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE, hasAttributes); 522 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR, fLowLevelOps.getxattr); 523 // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_ATTR, fLowLevelOps.write_attr); 524 525 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_STAT, fLowLevelOps.getxattr); 526 // // missing: FS_VNODE_CAPABILITY_WRITE_ATTR_STAT 527 // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_RENAME_ATTR, fLowLevelOps.rename_attr); 528 } else { 529 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FSYNC, fFS->ops.fsync); 530 531 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_SYMLINK, fFS->ops.readlink); 532 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_SYMLINK, fFS->ops.symlink); 533 534 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_LINK, fFS->ops.link); 535 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_UNLINK, fFS->ops.unlink); 536 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_RENAME, fFS->ops.rename); 537 538 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_ACCESS, fFS->ops.access); 539 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_STAT, fFS->ops.getattr); 540 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_STAT, 541 fFS->ops.chmod != NULL || fFS->ops.chown != NULL 542 || fFS->ops.truncate != NULL || fFS->ops.utimens != NULL 543 || fFS->ops.utime != NULL); 544 545 fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_READ_FS_INFO, fFS->ops.statfs); 546 // missing: FS_VOLUME_CAPABILITY_WRITE_FS_INFO 547 fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_SYNC, fFS->ops.fsync); 548 // emulated via fsync() 549 550 // file operations 551 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE, fFS->ops.create); 552 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN, fFS->ops.open); 553 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE, fFS->ops.flush); 554 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_COOKIE, fFS->ops.release); 555 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ, fFS->ops.read); 556 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE, fFS->ops.write); 557 558 // directory operations 559 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_DIR, fFS->ops.mkdir); 560 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REMOVE_DIR, fFS->ops.rmdir); 561 bool readDirSupport = fFS->ops.opendir != NULL || fFS->ops.readdir != NULL 562 || fFS->ops.getdir; 563 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_DIR, readDirSupport); 564 // not needed: FS_VNODE_CAPABILITY_CLOSE_DIR 565 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_DIR_COOKIE, readDirSupport); 566 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_DIR, readDirSupport); 567 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_DIR, readDirSupport); 568 569 // attribute directory operations 570 bool hasAttributes = fFS->ops.listxattr != NULL; 571 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR, hasAttributes); 572 // not needed: FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR 573 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE, 574 hasAttributes); 575 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_DIR, hasAttributes); 576 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_ATTR_DIR, hasAttributes); 577 578 // attribute operations 579 // // we emulate open_attr() and free_attr_dir_cookie() if either read_attr() 580 // // or write_attr() is present 581 // bool hasAttributes = (fFS->ops.read_attr || fFS->ops.write_attr); 582 // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_ATTR, hasAttributes); 583 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR, hasAttributes); 584 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE, hasAttributes); 585 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR, fFS->ops.getxattr); 586 // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_ATTR, fFS->ops.write_attr); 587 588 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_STAT, 589 fFS->ops.getxattr); 590 // // missing: FS_VNODE_CAPABILITY_WRITE_ATTR_STAT 591 // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_RENAME_ATTR, fFS->ops.rename_attr); 592 } 593 } 594 595 596 // #pragma mark - bootstrapping 597 598 599 status_t 600 userlandfs_create_file_system(const char* fsName, image_id image, 601 FileSystem** _fileSystem) 602 { 603 printf("userlandfs_create_file_system()\n"); 604 // look up the main() function of the add-on 605 int (*mainFunction)(int argc, const char* const* argv); 606 status_t error = get_image_symbol(image, "main", B_SYMBOL_TYPE_TEXT, 607 (void**)&mainFunction); 608 if (error != B_OK) 609 return error; 610 printf("userlandfs_create_file_system(): found main: %p\n", mainFunction); 611 612 // create the file system 613 FUSEFileSystem* fileSystem = new(std::nothrow) FUSEFileSystem(fsName, 614 mainFunction); 615 if (fileSystem == NULL) 616 return B_NO_MEMORY; 617 618 *_fileSystem = fileSystem; 619 return B_OK; 620 } 621