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:
ArgumentVector()25 ArgumentVector()
26 :
27 fBuffer(NULL),
28 fCount(0)
29 {
30 }
31
~ArgumentVector()32 ~ArgumentVector()
33 {
34 free(fBuffer);
35 }
36
Arguments() const37 const char* const* Arguments() const
38 {
39 return fArguments;
40 }
41
ArgumentCount() const42 int ArgumentCount() const
43 {
44 return fCount;
45 }
46
Init(const char * firstElement,const char * arguments)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
FUSEFileSystem(const char * fsName,int (* mainFunction)(int,const char * const *))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
~FUSEFileSystem()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
CreateVolume(Volume ** _volume,dev_t id)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
DeleteVolume(Volume * volume)180 FUSEFileSystem::DeleteVolume(Volume* volume)
181 {
182 delete volume;
183 return B_OK;
184 }
185
186
187 void
InitRequestThreadContext(RequestThreadContext * context)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
InitClientFS(const char * parameters)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
ExitClientFS(status_t status)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
FinishInitClientFS(fuse_config * config,const fuse_operations * ops,size_t opSize,void * userData)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
FinishInitClientFS(fuse_config * config,const fuse_lowlevel_ops * ops,size_t opSize,void * userData)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
MainLoop(bool multithreaded)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
_InitializationThreadEntry(void * data)325 FUSEFileSystem::_InitializationThreadEntry(void* data)
326 {
327 return ((FUSEFileSystem*)data)->_InitializationThread();
328 }
329
330
331 status_t
_InitializationThread()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
_InitClientFS(const fuse_operations * ops,size_t opSize,void * userData)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
_InitClientFS(const fuse_lowlevel_ops * lowLevelOps,size_t lowLevelOpSize,void * userData)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
_InitCapabilities()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 // asynchronous I/O
436 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_IO, true);
437 // emulated
438
439 // index directory & index operations
440 // missing: FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR
441 // missing: FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR
442 // missing: FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE
443 // missing: FS_VOLUME_CAPABILITY_READ_INDEX_DIR
444 // missing: FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR
445
446 // missing: FS_VOLUME_CAPABILITY_CREATE_INDEX
447 // missing: FS_VOLUME_CAPABILITY_REMOVE_INDEX
448 // missing: FS_VOLUME_CAPABILITY_READ_INDEX_STAT
449
450 // query operations
451 // missing: FS_VOLUME_CAPABILITY_OPEN_QUERY
452 // missing: FS_VOLUME_CAPABILITY_CLOSE_QUERY
453 // missing: FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE
454 // missing: FS_VOLUME_CAPABILITY_READ_QUERY
455 // missing: FS_VOLUME_CAPABILITY_REWIND_QUERY
456
457 // VM file access
458 // missing: FS_VNODE_CAPABILITY_CAN_PAGE
459 // missing: FS_VNODE_CAPABILITY_READ_PAGES
460 // missing: FS_VNODE_CAPABILITY_WRITE_PAGES
461
462 // cache file access
463 // missing: FS_VNODE_CAPABILITY_GET_FILE_MAP
464
465 // common operations
466 // missing: FS_VNODE_CAPABILITY_IOCTL
467 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_SET_FLAGS, true);
468 // emulated
469 // missing: FS_VNODE_CAPABILITY_SELECT
470 // missing: FS_VNODE_CAPABILITY_DESELECT
471
472 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE_ATTR, false);
473
474 if (fFS == NULL) {
475 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FSYNC, fLowLevelOps.fsync);
476
477 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_SYMLINK, fLowLevelOps.readlink);
478 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_SYMLINK, fLowLevelOps.symlink);
479
480 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_LINK, fLowLevelOps.link);
481 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_UNLINK, fLowLevelOps.unlink);
482 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_RENAME, fLowLevelOps.rename);
483
484 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_ACCESS, fLowLevelOps.access);
485 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_STAT, fLowLevelOps.getattr);
486 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_STAT, fLowLevelOps.setattr != NULL);
487
488 fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_READ_FS_INFO, fLowLevelOps.statfs);
489 // missing: FS_VOLUME_CAPABILITY_WRITE_FS_INFO
490 fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_SYNC, fLowLevelOps.fsync);
491 // emulated via fsync()
492
493 // file operations
494 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE, fLowLevelOps.create);
495 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN, fLowLevelOps.open);
496 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE, fLowLevelOps.flush);
497 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_COOKIE, fLowLevelOps.release);
498 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ, fLowLevelOps.read);
499 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE, fLowLevelOps.write);
500
501 // directory operations
502 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_DIR, fLowLevelOps.mkdir);
503 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REMOVE_DIR, fLowLevelOps.rmdir);
504 bool readDirSupport = fLowLevelOps.opendir != NULL || fLowLevelOps.readdir != NULL;
505 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_DIR, readDirSupport);
506 // not needed: FS_VNODE_CAPABILITY_CLOSE_DIR
507 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_DIR_COOKIE, readDirSupport);
508 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_DIR, readDirSupport);
509 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_DIR, readDirSupport);
510
511 // attribute directory operations
512 bool hasAttributes = fLowLevelOps.listxattr != NULL;
513 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR, hasAttributes);
514 // not needed: FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR
515 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE, hasAttributes);
516 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_DIR, hasAttributes);
517 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_ATTR_DIR, hasAttributes);
518
519 // attribute operations
520 // // we emulate open_attr() and free_attr_dir_cookie() if either read_attr()
521 // // or write_attr() is present
522 // bool hasAttributes = (fLowLevelOps.read_attr || fLowLevelOps.write_attr);
523 // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_ATTR, hasAttributes);
524 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR, hasAttributes);
525 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE, hasAttributes);
526 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR, fLowLevelOps.getxattr);
527 // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_ATTR, fLowLevelOps.write_attr);
528
529 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_STAT, fLowLevelOps.getxattr);
530 // // missing: FS_VNODE_CAPABILITY_WRITE_ATTR_STAT
531 // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_RENAME_ATTR, fLowLevelOps.rename_attr);
532 } else {
533 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FSYNC, fFS->ops.fsync);
534
535 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_SYMLINK, fFS->ops.readlink);
536 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_SYMLINK, fFS->ops.symlink);
537
538 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_LINK, fFS->ops.link);
539 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_UNLINK, fFS->ops.unlink);
540 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_RENAME, fFS->ops.rename);
541
542 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_ACCESS, fFS->ops.access);
543 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_STAT, fFS->ops.getattr);
544 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_STAT,
545 fFS->ops.chmod != NULL || fFS->ops.chown != NULL
546 || fFS->ops.truncate != NULL || fFS->ops.utimens != NULL
547 || fFS->ops.utime != NULL);
548
549 fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_READ_FS_INFO, fFS->ops.statfs);
550 // missing: FS_VOLUME_CAPABILITY_WRITE_FS_INFO
551 fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_SYNC, fFS->ops.fsync);
552 // emulated via fsync()
553
554 // file operations
555 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE, fFS->ops.create);
556 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN, fFS->ops.open);
557 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE, fFS->ops.flush);
558 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_COOKIE, fFS->ops.release);
559 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ, fFS->ops.read);
560 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE, fFS->ops.write);
561
562 // directory operations
563 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_DIR, fFS->ops.mkdir);
564 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REMOVE_DIR, fFS->ops.rmdir);
565 bool readDirSupport = fFS->ops.opendir != NULL || fFS->ops.readdir != NULL
566 || fFS->ops.getdir;
567 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_DIR, readDirSupport);
568 // not needed: FS_VNODE_CAPABILITY_CLOSE_DIR
569 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_DIR_COOKIE, readDirSupport);
570 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_DIR, readDirSupport);
571 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_DIR, readDirSupport);
572
573 // attribute directory operations
574 bool hasAttributes = fFS->ops.listxattr != NULL;
575 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR, hasAttributes);
576 // not needed: FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR
577 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE,
578 hasAttributes);
579 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_DIR, hasAttributes);
580 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_ATTR_DIR, hasAttributes);
581
582 // attribute operations
583 // // we emulate open_attr() and free_attr_dir_cookie() if either read_attr()
584 // // or write_attr() is present
585 // bool hasAttributes = (fFS->ops.read_attr || fFS->ops.write_attr);
586 // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_ATTR, hasAttributes);
587 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR, hasAttributes);
588 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE, hasAttributes);
589 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR, fFS->ops.getxattr);
590 // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_ATTR, fFS->ops.write_attr);
591
592 fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_STAT,
593 fFS->ops.getxattr);
594 // // missing: FS_VNODE_CAPABILITY_WRITE_ATTR_STAT
595 // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_RENAME_ATTR, fFS->ops.rename_attr);
596 }
597 }
598
599
600 // #pragma mark - bootstrapping
601
602
603 status_t
userlandfs_create_file_system(const char * fsName,image_id image,FileSystem ** _fileSystem)604 userlandfs_create_file_system(const char* fsName, image_id image,
605 FileSystem** _fileSystem)
606 {
607 printf("userlandfs_create_file_system()\n");
608 // look up the main() function of the add-on
609 int (*mainFunction)(int argc, const char* const* argv);
610 status_t error = get_image_symbol(image, "main", B_SYMBOL_TYPE_TEXT,
611 (void**)&mainFunction);
612 if (error != B_OK)
613 return error;
614 printf("userlandfs_create_file_system(): found main: %p\n", mainFunction);
615
616 // create the file system
617 FUSEFileSystem* fileSystem = new(std::nothrow) FUSEFileSystem(fsName,
618 mainFunction);
619 if (fileSystem == NULL)
620 return B_NO_MEMORY;
621
622 *_fileSystem = fileSystem;
623 return B_OK;
624 }
625