1c9323289SIngo Weinhold /*
2c9323289SIngo Weinhold * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3c9323289SIngo Weinhold * Distributed under the terms of the MIT License.
4c9323289SIngo Weinhold */
5c9323289SIngo Weinhold
6c9323289SIngo Weinhold #include "FUSEFileSystem.h"
7c9323289SIngo Weinhold
8c9323289SIngo Weinhold #include <stdlib.h>
9c9323289SIngo Weinhold #include <string.h>
10c9323289SIngo Weinhold
11c9323289SIngo Weinhold #include <new>
12c9323289SIngo Weinhold
13f06f7337SIngo Weinhold #include "fuse_fs.h"
140604d554SPulkoMandy #include "FUSELowLevel.h"
15c9323289SIngo Weinhold #include "FUSEVolume.h"
16c9323289SIngo Weinhold
17e66cd9d7SIngo Weinhold #include "../RequestThread.h"
18e66cd9d7SIngo Weinhold
19c9323289SIngo Weinhold
20c9323289SIngo Weinhold class FUSEFileSystem::ArgumentVector {
21c9323289SIngo Weinhold private:
22c9323289SIngo Weinhold enum { MAX_ARGUMENTS = 128 };
23c9323289SIngo Weinhold
24c9323289SIngo Weinhold public:
ArgumentVector()25c9323289SIngo Weinhold ArgumentVector()
26c9323289SIngo Weinhold :
27c9323289SIngo Weinhold fBuffer(NULL),
28c9323289SIngo Weinhold fCount(0)
29c9323289SIngo Weinhold {
30c9323289SIngo Weinhold }
31c9323289SIngo Weinhold
~ArgumentVector()32c9323289SIngo Weinhold ~ArgumentVector()
33c9323289SIngo Weinhold {
34c9323289SIngo Weinhold free(fBuffer);
35c9323289SIngo Weinhold }
36c9323289SIngo Weinhold
Arguments() const37c9323289SIngo Weinhold const char* const* Arguments() const
38c9323289SIngo Weinhold {
39c9323289SIngo Weinhold return fArguments;
40c9323289SIngo Weinhold }
41c9323289SIngo Weinhold
ArgumentCount() const42c9323289SIngo Weinhold int ArgumentCount() const
43c9323289SIngo Weinhold {
44c9323289SIngo Weinhold return fCount;
45c9323289SIngo Weinhold }
46c9323289SIngo Weinhold
Init(const char * firstElement,const char * arguments)47c9323289SIngo Weinhold status_t Init(const char* firstElement, const char* arguments)
48c9323289SIngo Weinhold {
49c9323289SIngo Weinhold size_t firstElementSize = firstElement != NULL
50c9323289SIngo Weinhold ? strlen(firstElement) + 1 : 0;
51c9323289SIngo Weinhold
52c9323289SIngo Weinhold // allocate the buffer
53c9323289SIngo Weinhold fBuffer = (char*)malloc(firstElementSize + strlen(arguments) + 1);
54c9323289SIngo Weinhold if (fBuffer == NULL)
55c9323289SIngo Weinhold return B_NO_MEMORY;
56c9323289SIngo Weinhold
57c9323289SIngo Weinhold fCount = 0;
58c9323289SIngo Weinhold
59c9323289SIngo Weinhold bool inArgument = false;
60c9323289SIngo Weinhold int bufferIndex = 0;
61c9323289SIngo Weinhold
62c9323289SIngo Weinhold // push the first element, if given
63c9323289SIngo Weinhold if (firstElement != NULL) {
64c9323289SIngo Weinhold memcpy(fBuffer, firstElement, firstElementSize);
65c9323289SIngo Weinhold fArguments[fCount++] = fBuffer;
66c9323289SIngo Weinhold bufferIndex = firstElementSize;
67c9323289SIngo Weinhold }
68c9323289SIngo Weinhold
69c9323289SIngo Weinhold // parse the given string
70c9323289SIngo Weinhold for (; *arguments != '\0'; arguments++) {
71c9323289SIngo Weinhold char c = *arguments;
72c9323289SIngo Weinhold switch (c) {
73c9323289SIngo Weinhold case ' ':
74c9323289SIngo Weinhold case '\t':
75c9323289SIngo Weinhold case '\r':
76c9323289SIngo Weinhold case '\n':
77c9323289SIngo Weinhold // white-space marks argument boundaries
78c9323289SIngo Weinhold if (inArgument) {
79c9323289SIngo Weinhold // terminate the current argument
80c9323289SIngo Weinhold fBuffer[bufferIndex++] = '\0';
81c9323289SIngo Weinhold inArgument = false;
82c9323289SIngo Weinhold }
83c9323289SIngo Weinhold break;
84c9323289SIngo Weinhold case '\\':
85c9323289SIngo Weinhold c = *++arguments;
86c9323289SIngo Weinhold if (c == '\0')
87c9323289SIngo Weinhold break;
88c9323289SIngo Weinhold // fall through
89c9323289SIngo Weinhold default:
90c9323289SIngo Weinhold if (!inArgument) {
91c9323289SIngo Weinhold // push a new argument
92c9323289SIngo Weinhold if (fCount == MAX_ARGUMENTS)
93c9323289SIngo Weinhold break;
94c9323289SIngo Weinhold
95c9323289SIngo Weinhold fArguments[fCount++] = fBuffer + bufferIndex;
96c9323289SIngo Weinhold inArgument = true;
97c9323289SIngo Weinhold }
98c9323289SIngo Weinhold
99c9323289SIngo Weinhold fBuffer[bufferIndex++] = c;
100c9323289SIngo Weinhold break;
101c9323289SIngo Weinhold }
102c9323289SIngo Weinhold }
103c9323289SIngo Weinhold
104c9323289SIngo Weinhold // terminate the last argument
105c9323289SIngo Weinhold if (inArgument)
106c9323289SIngo Weinhold fBuffer[bufferIndex++] = '\0';
107c9323289SIngo Weinhold
108c9323289SIngo Weinhold // NULL terminate the argument array
109c9323289SIngo Weinhold fArguments[fCount] = NULL;
110c9323289SIngo Weinhold
111c9323289SIngo Weinhold return B_OK;
112c9323289SIngo Weinhold }
113c9323289SIngo Weinhold
114c9323289SIngo Weinhold private:
115c9323289SIngo Weinhold char* fBuffer;
116c9323289SIngo Weinhold const char* fArguments[MAX_ARGUMENTS + 1];
117c9323289SIngo Weinhold int fCount;
118c9323289SIngo Weinhold };
119c9323289SIngo Weinhold
120c9323289SIngo Weinhold
FUSEFileSystem(const char * fsName,int (* mainFunction)(int,const char * const *))12169cd702bSIngo Weinhold FUSEFileSystem::FUSEFileSystem(const char* fsName,
12269cd702bSIngo Weinhold int (*mainFunction)(int, const char* const*))
123c9323289SIngo Weinhold :
12469cd702bSIngo Weinhold FileSystem(fsName),
1251d077f83SIngo Weinhold fMainFunction(mainFunction),
1261d077f83SIngo Weinhold fInitThread(-1),
1271d077f83SIngo Weinhold fInitStatus(B_NO_INIT),
1281d077f83SIngo Weinhold fInitSemaphore(-1),
1291d077f83SIngo Weinhold fExitSemaphore(-1),
1301d077f83SIngo Weinhold fInitParameters(NULL),
1310604d554SPulkoMandy fUserData(NULL),
1321d077f83SIngo Weinhold fFS(NULL)
133c9323289SIngo Weinhold {
134f06f7337SIngo Weinhold fClientFSType = CLIENT_FS_FUSE;
135f06f7337SIngo Weinhold
136f06f7337SIngo Weinhold // FS capabilities
137f06f7337SIngo Weinhold fCapabilities.ClearAll();
138f06f7337SIngo Weinhold fCapabilities.Set(FS_CAPABILITY_MOUNT, true);
139c9323289SIngo Weinhold }
140c9323289SIngo Weinhold
141c9323289SIngo Weinhold
~FUSEFileSystem()142c9323289SIngo Weinhold FUSEFileSystem::~FUSEFileSystem()
143c9323289SIngo Weinhold {
1441d077f83SIngo Weinhold if (fInitSemaphore >= 0)
1451d077f83SIngo Weinhold delete_sem(fInitSemaphore);
1461d077f83SIngo Weinhold
1471d077f83SIngo Weinhold if (fExitSemaphore >= 0)
1481d077f83SIngo Weinhold delete_sem(fExitSemaphore);
1491d077f83SIngo Weinhold
1501d077f83SIngo Weinhold if (fInitThread >= 0)
1511d077f83SIngo Weinhold wait_for_thread(fInitThread, NULL);
152c9323289SIngo Weinhold }
153c9323289SIngo Weinhold
154c9323289SIngo Weinhold
155c9323289SIngo Weinhold status_t
CreateVolume(Volume ** _volume,dev_t id)156c9323289SIngo Weinhold FUSEFileSystem::CreateVolume(Volume** _volume, dev_t id)
157c9323289SIngo Weinhold {
158c9323289SIngo Weinhold printf("FUSEFileSystem::CreateVolume()\n");
1591d077f83SIngo Weinhold // Only one volume is possible
1601d077f83SIngo Weinhold if (!fVolumes.IsEmpty())
1611d077f83SIngo Weinhold RETURN_ERROR(B_BUSY);
1621d077f83SIngo Weinhold
163c9323289SIngo Weinhold // create the volume
164c9323289SIngo Weinhold FUSEVolume* volume = new(std::nothrow) FUSEVolume(this, id);
165c9323289SIngo Weinhold if (volume == NULL)
166c9323289SIngo Weinhold return B_NO_MEMORY;
167c9323289SIngo Weinhold
168f06f7337SIngo Weinhold status_t error = volume->Init();
169f06f7337SIngo Weinhold if (error != B_OK) {
170f06f7337SIngo Weinhold delete volume;
171f06f7337SIngo Weinhold return error;
172f06f7337SIngo Weinhold }
173f06f7337SIngo Weinhold
174c9323289SIngo Weinhold *_volume = volume;
175c9323289SIngo Weinhold return B_OK;
176c9323289SIngo Weinhold }
177c9323289SIngo Weinhold
178c9323289SIngo Weinhold
179c9323289SIngo Weinhold status_t
DeleteVolume(Volume * volume)180c9323289SIngo Weinhold FUSEFileSystem::DeleteVolume(Volume* volume)
181c9323289SIngo Weinhold {
182c9323289SIngo Weinhold delete volume;
183c9323289SIngo Weinhold return B_OK;
184c9323289SIngo Weinhold }
185c9323289SIngo Weinhold
186c9323289SIngo Weinhold
187e66cd9d7SIngo Weinhold void
InitRequestThreadContext(RequestThreadContext * context)188e66cd9d7SIngo Weinhold FUSEFileSystem::InitRequestThreadContext(RequestThreadContext* context)
189e66cd9d7SIngo Weinhold {
190e66cd9d7SIngo Weinhold // Statically assert that fuse_context fits in the RequestThreadContext
191e66cd9d7SIngo Weinhold // FS data. We can't include <Debug.h> as it clashes with our "Debug.h".
192e66cd9d7SIngo Weinhold do {
193e66cd9d7SIngo Weinhold static const int staticAssertHolds
194e66cd9d7SIngo Weinhold = sizeof(fuse_context) <= REQUEST_THREAD_CONTEXT_FS_DATA_SIZE;
195e66cd9d7SIngo Weinhold struct __staticAssertStruct__ {
196e66cd9d7SIngo Weinhold char __static_assert_failed__[2 * staticAssertHolds - 1];
197e66cd9d7SIngo Weinhold };
198e66cd9d7SIngo Weinhold } while (false);
199e66cd9d7SIngo Weinhold
200e66cd9d7SIngo Weinhold // init a fuse_context
201e66cd9d7SIngo Weinhold KernelRequest* request = context->GetRequest();
202e66cd9d7SIngo Weinhold fuse_context* fuseContext = (fuse_context*)context->GetFSData();
203e66cd9d7SIngo Weinhold fuseContext->fuse = (struct fuse*)this;
204e66cd9d7SIngo Weinhold fuseContext->uid = request->user;
205e66cd9d7SIngo Weinhold fuseContext->gid = request->group;
206e66cd9d7SIngo Weinhold fuseContext->pid = request->team;
207e66cd9d7SIngo Weinhold fuseContext->private_data = fFS != NULL ? fFS->userData : NULL;
208e66cd9d7SIngo Weinhold }
209e66cd9d7SIngo Weinhold
210e66cd9d7SIngo Weinhold
211c9323289SIngo Weinhold status_t
InitClientFS(const char * parameters)212c9323289SIngo Weinhold FUSEFileSystem::InitClientFS(const char* parameters)
213c9323289SIngo Weinhold {
214f06f7337SIngo Weinhold PRINT(("FUSEFileSystem::InitClientFS()\n"));
2151d077f83SIngo Weinhold // create the semaphores we need
2161d077f83SIngo Weinhold fInitSemaphore = create_sem(0, "FUSE init sem");
2171d077f83SIngo Weinhold if (fInitSemaphore < 0)
2181d077f83SIngo Weinhold RETURN_ERROR(fInitSemaphore);
2191d077f83SIngo Weinhold
2201d077f83SIngo Weinhold fExitSemaphore = create_sem(0, "FUSE exit sem");
2211d077f83SIngo Weinhold if (fExitSemaphore < 0)
2221d077f83SIngo Weinhold RETURN_ERROR(fExitSemaphore);
2231d077f83SIngo Weinhold
2241d077f83SIngo Weinhold fInitStatus = 1;
2251d077f83SIngo Weinhold fInitParameters = parameters;
2261d077f83SIngo Weinhold
2271d077f83SIngo Weinhold // Start the initialization thread -- it will call main() and won't return
2281d077f83SIngo Weinhold // until unmounting.
2291d077f83SIngo Weinhold fInitThread = spawn_thread(&_InitializationThreadEntry,
2301d077f83SIngo Weinhold "FUSE init", B_NORMAL_PRIORITY, this);
2311d077f83SIngo Weinhold if (fInitThread < 0)
2321d077f83SIngo Weinhold RETURN_ERROR(fInitThread);
2331d077f83SIngo Weinhold
2341d077f83SIngo Weinhold resume_thread(fInitThread);
2351d077f83SIngo Weinhold
2361d077f83SIngo Weinhold // wait for the initialization to finish
237f06f7337SIngo Weinhold PRINT((" waiting for init thread...\n"));
2381d077f83SIngo Weinhold while (acquire_sem(fInitSemaphore) == B_INTERRUPTED) {
2391d077f83SIngo Weinhold }
2401d077f83SIngo Weinhold
241f06f7337SIngo Weinhold PRINT((" waiting for init thread done\n"));
2421d077f83SIngo Weinhold fInitSemaphore = -1;
2431d077f83SIngo Weinhold
2441d077f83SIngo Weinhold if (fInitStatus > 0)
2451d077f83SIngo Weinhold RETURN_ERROR(B_ERROR);
2461d077f83SIngo Weinhold if (fInitStatus != B_OK)
2471d077f83SIngo Weinhold RETURN_ERROR(fInitStatus);
2481d077f83SIngo Weinhold
2491d077f83SIngo Weinhold // initialization went fine
2501d077f83SIngo Weinhold return B_OK;
2511d077f83SIngo Weinhold }
2521d077f83SIngo Weinhold
2531d077f83SIngo Weinhold
2541d077f83SIngo Weinhold void
ExitClientFS(status_t status)2551d077f83SIngo Weinhold FUSEFileSystem::ExitClientFS(status_t status)
2561d077f83SIngo Weinhold {
2571d077f83SIngo Weinhold // set the exit status and notify the initialization thread
2581d077f83SIngo Weinhold fExitStatus = status;
2591d077f83SIngo Weinhold if (fExitSemaphore >= 0)
2601d077f83SIngo Weinhold delete_sem(fExitSemaphore);
261f06f7337SIngo Weinhold
262f06f7337SIngo Weinhold if (fInitThread >= 0)
263f06f7337SIngo Weinhold wait_for_thread(fInitThread, NULL);
2641d077f83SIngo Weinhold }
2651d077f83SIngo Weinhold
2661d077f83SIngo Weinhold
2671d077f83SIngo Weinhold status_t
FinishInitClientFS(fuse_config * config,const fuse_operations * ops,size_t opSize,void * userData)26839f2d9e6SIngo Weinhold FUSEFileSystem::FinishInitClientFS(fuse_config* config,
26939f2d9e6SIngo Weinhold const fuse_operations* ops, size_t opSize, void* userData)
2701d077f83SIngo Weinhold {
271f06f7337SIngo Weinhold PRINT(("FUSEFileSystem::FinishInitClientFS()\n"));
2721d077f83SIngo Weinhold fExitStatus = B_ERROR;
2731d077f83SIngo Weinhold
274a7731138SIngo Weinhold fFUSEConfig = *config;
275a7731138SIngo Weinhold
2761d077f83SIngo Weinhold // do the initialization
277861dbb48SIngo Weinhold fInitStatus = _InitClientFS(ops, opSize, userData);
278861dbb48SIngo Weinhold return fInitStatus;
279861dbb48SIngo Weinhold }
2801d077f83SIngo Weinhold
281861dbb48SIngo Weinhold
282861dbb48SIngo Weinhold status_t
FinishInitClientFS(fuse_config * config,const fuse_lowlevel_ops * ops,size_t opSize,void * userData)2830604d554SPulkoMandy FUSEFileSystem::FinishInitClientFS(fuse_config* config,
2840604d554SPulkoMandy const fuse_lowlevel_ops* ops, size_t opSize, void* userData)
2850604d554SPulkoMandy {
2860604d554SPulkoMandy PRINT(("FUSEFileSystem::FinishInitClientFS()\n"));
2870604d554SPulkoMandy fExitStatus = B_ERROR;
2880604d554SPulkoMandy
2890604d554SPulkoMandy fFUSEConfig = *config;
2900604d554SPulkoMandy
2910604d554SPulkoMandy // do the initialization
2920604d554SPulkoMandy fInitStatus = _InitClientFS(ops, opSize, userData);
2930604d554SPulkoMandy return fInitStatus;
2940604d554SPulkoMandy }
2950604d554SPulkoMandy
2960604d554SPulkoMandy
2970604d554SPulkoMandy status_t
MainLoop(bool multithreaded)298861dbb48SIngo Weinhold FUSEFileSystem::MainLoop(bool multithreaded)
299861dbb48SIngo Weinhold {
300861dbb48SIngo Weinhold // TODO: Respect the multithreaded flag!
301861dbb48SIngo Weinhold
302861dbb48SIngo Weinhold PRINT(("FUSEFileSystem::FinishMounting()\n"));
3031d077f83SIngo Weinhold // notify the mount thread
304f06f7337SIngo Weinhold PRINT((" notifying mount thread\n"));
3051d077f83SIngo Weinhold delete_sem(fInitSemaphore);
3061d077f83SIngo Weinhold
3071d077f83SIngo Weinhold // loop until unmounting
308f06f7337SIngo Weinhold PRINT((" waiting for unmounting...\n"));
3091d077f83SIngo Weinhold while (acquire_sem(fExitSemaphore) == B_INTERRUPTED) {
3101d077f83SIngo Weinhold }
311f06f7337SIngo Weinhold PRINT((" waiting for unmounting done\n"));
3121d077f83SIngo Weinhold
3131d077f83SIngo Weinhold fExitSemaphore = -1;
3141d077f83SIngo Weinhold
315861dbb48SIngo Weinhold if (fFS != NULL)
3161d077f83SIngo Weinhold fuse_fs_destroy(fFS);
3170604d554SPulkoMandy else
3180604d554SPulkoMandy fuse_ll_destroy(&fLowLevelOps, fUserData);
3191d077f83SIngo Weinhold
320861dbb48SIngo Weinhold return fExitStatus;
3211d077f83SIngo Weinhold }
3221d077f83SIngo Weinhold
3231d077f83SIngo Weinhold
3241d077f83SIngo Weinhold /*static*/ status_t
_InitializationThreadEntry(void * data)3251d077f83SIngo Weinhold FUSEFileSystem::_InitializationThreadEntry(void* data)
3261d077f83SIngo Weinhold {
3271d077f83SIngo Weinhold return ((FUSEFileSystem*)data)->_InitializationThread();
3281d077f83SIngo Weinhold }
3291d077f83SIngo Weinhold
3301d077f83SIngo Weinhold
3311d077f83SIngo Weinhold status_t
_InitializationThread()3321d077f83SIngo Weinhold FUSEFileSystem::_InitializationThread()
3331d077f83SIngo Weinhold {
334c9323289SIngo Weinhold // parse the parameters
335c9323289SIngo Weinhold ArgumentVector args;
3361d077f83SIngo Weinhold status_t error = args.Init(GetName(), fInitParameters);
3371d077f83SIngo Weinhold if (error != B_OK) {
3381d077f83SIngo Weinhold fInitStatus = error;
3391d077f83SIngo Weinhold delete_sem(fInitSemaphore);
3401d077f83SIngo Weinhold return B_OK;
3411d077f83SIngo Weinhold }
342c9323289SIngo Weinhold
3431d077f83SIngo Weinhold // call main -- should not return until unmounting
344c9323289SIngo Weinhold fMainFunction(args.ArgumentCount(), args.Arguments());
3451d077f83SIngo Weinhold printf("FUSEFileSystem::_InitializationThread(): main() returned!\n");
346c9323289SIngo Weinhold
3471d077f83SIngo Weinhold if (fInitStatus > 0 && fInitSemaphore >= 0) {
3481d077f83SIngo Weinhold // something went wrong early -- main() returned without calling
3491d077f83SIngo Weinhold // fuse_main()
3501d077f83SIngo Weinhold fInitStatus = B_ERROR;
3511d077f83SIngo Weinhold delete_sem(fInitSemaphore);
3521d077f83SIngo Weinhold }
3531d077f83SIngo Weinhold
3541d077f83SIngo Weinhold return B_OK;
3551d077f83SIngo Weinhold }
3561d077f83SIngo Weinhold
3571d077f83SIngo Weinhold
3581d077f83SIngo Weinhold status_t
_InitClientFS(const fuse_operations * ops,size_t opSize,void * userData)3591d077f83SIngo Weinhold FUSEFileSystem::_InitClientFS(const fuse_operations* ops, size_t opSize,
3601d077f83SIngo Weinhold void* userData)
3611d077f83SIngo Weinhold {
3621d077f83SIngo Weinhold // create a fuse_fs object
3631d077f83SIngo Weinhold fFS = fuse_fs_new(ops, opSize, userData);
3641d077f83SIngo Weinhold if (fFS == NULL)
3651d077f83SIngo Weinhold return B_ERROR;
3661d077f83SIngo Weinhold
367f06f7337SIngo Weinhold _InitCapabilities();
368f06f7337SIngo Weinhold PRINT(("volume capabilities:\n"));
369f06f7337SIngo Weinhold fVolumeCapabilities.Dump();
370f06f7337SIngo Weinhold PRINT(("node capabilities:\n"));
371f06f7337SIngo Weinhold fNodeCapabilities.Dump();
372f06f7337SIngo Weinhold
3731d077f83SIngo Weinhold // init connection info
3741d077f83SIngo Weinhold fConnectionInfo.proto_major = 0;
3751d077f83SIngo Weinhold fConnectionInfo.proto_minor = 0;
3761d077f83SIngo Weinhold fConnectionInfo.async_read = false;
3771d077f83SIngo Weinhold fConnectionInfo.max_write = 64 * 1024;
3781d077f83SIngo Weinhold fConnectionInfo.max_readahead = 64 * 1024;
37949a00a12SPulkoMandy fConnectionInfo.capable = FUSE_CAP_ATOMIC_O_TRUNC | FUSE_CAP_BIG_WRITES | FUSE_CAP_IOCTL_DIR
38049a00a12SPulkoMandy | FUSE_CAP_HAIKU_FUSE_EXTENSIONS;
3811d077f83SIngo Weinhold
3821d077f83SIngo Weinhold fuse_fs_init(fFS, &fConnectionInfo);
383c9323289SIngo Weinhold
384c9323289SIngo Weinhold return B_OK;
385c9323289SIngo Weinhold }
386c9323289SIngo Weinhold
387c9323289SIngo Weinhold
3880604d554SPulkoMandy status_t
_InitClientFS(const fuse_lowlevel_ops * lowLevelOps,size_t lowLevelOpSize,void * userData)3890604d554SPulkoMandy FUSEFileSystem::_InitClientFS(const fuse_lowlevel_ops* lowLevelOps, size_t lowLevelOpSize,
3900604d554SPulkoMandy void* userData)
3910604d554SPulkoMandy {
3920604d554SPulkoMandy fLowLevelOps = *lowLevelOps;
3930604d554SPulkoMandy
3940604d554SPulkoMandy _InitCapabilities();
3950604d554SPulkoMandy PRINT(("volume capabilities:\n"));
3960604d554SPulkoMandy fVolumeCapabilities.Dump();
3970604d554SPulkoMandy PRINT(("node capabilities:\n"));
3980604d554SPulkoMandy fNodeCapabilities.Dump();
3990604d554SPulkoMandy
4000604d554SPulkoMandy // init connection info
4010604d554SPulkoMandy fConnectionInfo.proto_major = 0;
4020604d554SPulkoMandy fConnectionInfo.proto_minor = 0;
4030604d554SPulkoMandy fConnectionInfo.async_read = false;
4040604d554SPulkoMandy fConnectionInfo.max_write = 64 * 1024;
4050604d554SPulkoMandy fConnectionInfo.max_readahead = 64 * 1024;
4060604d554SPulkoMandy fUserData = userData;
4070604d554SPulkoMandy
4080604d554SPulkoMandy fuse_ll_init(&fLowLevelOps, userData, &fConnectionInfo);
4090604d554SPulkoMandy
4100604d554SPulkoMandy return B_OK;
4110604d554SPulkoMandy }
4120604d554SPulkoMandy
4130604d554SPulkoMandy
414f06f7337SIngo Weinhold void
_InitCapabilities()415f06f7337SIngo Weinhold FUSEFileSystem::_InitCapabilities()
416f06f7337SIngo Weinhold {
417f06f7337SIngo Weinhold fVolumeCapabilities.ClearAll();
418f06f7337SIngo Weinhold fNodeCapabilities.ClearAll();
419f06f7337SIngo Weinhold
420f06f7337SIngo Weinhold // Volume operations
421f06f7337SIngo Weinhold fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_UNMOUNT, true);
422f06f7337SIngo Weinhold fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_GET_VNODE, true);
423f06f7337SIngo Weinhold // emulated
424fd4f53a7SIngo Weinhold
4250604d554SPulkoMandy // vnode operations
4260604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_LOOKUP, true);
4270604d554SPulkoMandy // emulated
4280604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_GET_VNODE_NAME, true);
4290604d554SPulkoMandy // emulated
4300604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_PUT_VNODE, true);
4310604d554SPulkoMandy // emulated
4320604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REMOVE_VNODE, true);
4330604d554SPulkoMandy // emulated
4340604d554SPulkoMandy
435*55f3abb4STrung Nguyen // asynchronous I/O
436*55f3abb4STrung Nguyen fNodeCapabilities.Set(FS_VNODE_CAPABILITY_IO, true);
437*55f3abb4STrung Nguyen // emulated
438*55f3abb4STrung Nguyen
439cd4ee847SIngo Weinhold // index directory & index operations
440cd4ee847SIngo Weinhold // missing: FS_VOLUME_CAPABILITY_OPEN_INDEX_DIR
441cd4ee847SIngo Weinhold // missing: FS_VOLUME_CAPABILITY_CLOSE_INDEX_DIR
442cd4ee847SIngo Weinhold // missing: FS_VOLUME_CAPABILITY_FREE_INDEX_DIR_COOKIE
443cd4ee847SIngo Weinhold // missing: FS_VOLUME_CAPABILITY_READ_INDEX_DIR
444cd4ee847SIngo Weinhold // missing: FS_VOLUME_CAPABILITY_REWIND_INDEX_DIR
445cd4ee847SIngo Weinhold
446cd4ee847SIngo Weinhold // missing: FS_VOLUME_CAPABILITY_CREATE_INDEX
447cd4ee847SIngo Weinhold // missing: FS_VOLUME_CAPABILITY_REMOVE_INDEX
448cd4ee847SIngo Weinhold // missing: FS_VOLUME_CAPABILITY_READ_INDEX_STAT
449fd4f53a7SIngo Weinhold
450fd4f53a7SIngo Weinhold // query operations
451cd4ee847SIngo Weinhold // missing: FS_VOLUME_CAPABILITY_OPEN_QUERY
452cd4ee847SIngo Weinhold // missing: FS_VOLUME_CAPABILITY_CLOSE_QUERY
453cd4ee847SIngo Weinhold // missing: FS_VOLUME_CAPABILITY_FREE_QUERY_COOKIE
454cd4ee847SIngo Weinhold // missing: FS_VOLUME_CAPABILITY_READ_QUERY
455cd4ee847SIngo Weinhold // missing: FS_VOLUME_CAPABILITY_REWIND_QUERY
456fd4f53a7SIngo Weinhold
457fd4f53a7SIngo Weinhold // VM file access
458cd4ee847SIngo Weinhold // missing: FS_VNODE_CAPABILITY_CAN_PAGE
459cd4ee847SIngo Weinhold // missing: FS_VNODE_CAPABILITY_READ_PAGES
460cd4ee847SIngo Weinhold // missing: FS_VNODE_CAPABILITY_WRITE_PAGES
461fd4f53a7SIngo Weinhold
462fd4f53a7SIngo Weinhold // cache file access
463cd4ee847SIngo Weinhold // missing: FS_VNODE_CAPABILITY_GET_FILE_MAP
464fd4f53a7SIngo Weinhold
465fd4f53a7SIngo Weinhold // common operations
466cd4ee847SIngo Weinhold // missing: FS_VNODE_CAPABILITY_IOCTL
467edae667bSIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_SET_FLAGS, true);
468edae667bSIngo Weinhold // emulated
469cd4ee847SIngo Weinhold // missing: FS_VNODE_CAPABILITY_SELECT
470cd4ee847SIngo Weinhold // missing: FS_VNODE_CAPABILITY_DESELECT
4710604d554SPulkoMandy
4720604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE_ATTR, false);
4730604d554SPulkoMandy
4740604d554SPulkoMandy if (fFS == NULL) {
4750604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FSYNC, fLowLevelOps.fsync);
4760604d554SPulkoMandy
4770604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_SYMLINK, fLowLevelOps.readlink);
4780604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_SYMLINK, fLowLevelOps.symlink);
4790604d554SPulkoMandy
4800604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_LINK, fLowLevelOps.link);
4810604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_UNLINK, fLowLevelOps.unlink);
4820604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_RENAME, fLowLevelOps.rename);
4830604d554SPulkoMandy
4840604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_ACCESS, fLowLevelOps.access);
4850604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_STAT, fLowLevelOps.getattr);
4860604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_STAT, fLowLevelOps.setattr != NULL);
4870604d554SPulkoMandy
4880604d554SPulkoMandy fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_READ_FS_INFO, fLowLevelOps.statfs);
4890604d554SPulkoMandy // missing: FS_VOLUME_CAPABILITY_WRITE_FS_INFO
4900604d554SPulkoMandy fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_SYNC, fLowLevelOps.fsync);
4910604d554SPulkoMandy // emulated via fsync()
4920604d554SPulkoMandy
4930604d554SPulkoMandy // file operations
4940604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE, fLowLevelOps.create);
4950604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN, fLowLevelOps.open);
4960604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE, fLowLevelOps.flush);
4970604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_COOKIE, fLowLevelOps.release);
4980604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ, fLowLevelOps.read);
4990604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE, fLowLevelOps.write);
5000604d554SPulkoMandy
5010604d554SPulkoMandy // directory operations
5020604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_DIR, fLowLevelOps.mkdir);
5030604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REMOVE_DIR, fLowLevelOps.rmdir);
5040604d554SPulkoMandy bool readDirSupport = fLowLevelOps.opendir != NULL || fLowLevelOps.readdir != NULL;
5050604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_DIR, readDirSupport);
5060604d554SPulkoMandy // not needed: FS_VNODE_CAPABILITY_CLOSE_DIR
5070604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_DIR_COOKIE, readDirSupport);
5080604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_DIR, readDirSupport);
5090604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_DIR, readDirSupport);
5100604d554SPulkoMandy
5110604d554SPulkoMandy // attribute directory operations
5120604d554SPulkoMandy bool hasAttributes = fLowLevelOps.listxattr != NULL;
5130604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR, hasAttributes);
5140604d554SPulkoMandy // not needed: FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR
515f0ee02b2SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE, hasAttributes);
5160604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_DIR, hasAttributes);
5170604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_ATTR_DIR, hasAttributes);
5180604d554SPulkoMandy
5190604d554SPulkoMandy // attribute operations
5200604d554SPulkoMandy // // we emulate open_attr() and free_attr_dir_cookie() if either read_attr()
5210604d554SPulkoMandy // // or write_attr() is present
5220604d554SPulkoMandy // bool hasAttributes = (fLowLevelOps.read_attr || fLowLevelOps.write_attr);
5230604d554SPulkoMandy // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_ATTR, hasAttributes);
5240604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR, hasAttributes);
5250604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE, hasAttributes);
5260604d554SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR, fLowLevelOps.getxattr);
5270604d554SPulkoMandy // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_ATTR, fLowLevelOps.write_attr);
5280604d554SPulkoMandy
529f0ee02b2SPulkoMandy fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_STAT, fLowLevelOps.getxattr);
5300604d554SPulkoMandy // // missing: FS_VNODE_CAPABILITY_WRITE_ATTR_STAT
5310604d554SPulkoMandy // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_RENAME_ATTR, fLowLevelOps.rename_attr);
5320604d554SPulkoMandy } else {
533edae667bSIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FSYNC, fFS->ops.fsync);
534fd4f53a7SIngo Weinhold
535fd4f53a7SIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_SYMLINK, fFS->ops.readlink);
536cd4ee847SIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_SYMLINK, fFS->ops.symlink);
537fd4f53a7SIngo Weinhold
53840b0400dSIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_LINK, fFS->ops.link);
539cd4ee847SIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_UNLINK, fFS->ops.unlink);
54040b0400dSIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_RENAME, fFS->ops.rename);
541fd4f53a7SIngo Weinhold
542fd4f53a7SIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_ACCESS, fFS->ops.access);
543f06f7337SIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_STAT, fFS->ops.getattr);
544b747212fSIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_STAT,
545b747212fSIngo Weinhold fFS->ops.chmod != NULL || fFS->ops.chown != NULL
546d7b73de2SRene Gollent || fFS->ops.truncate != NULL || fFS->ops.utimens != NULL
547b747212fSIngo Weinhold || fFS->ops.utime != NULL);
548fd4f53a7SIngo Weinhold
5490604d554SPulkoMandy fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_READ_FS_INFO, fFS->ops.statfs);
5500604d554SPulkoMandy // missing: FS_VOLUME_CAPABILITY_WRITE_FS_INFO
5510604d554SPulkoMandy fVolumeCapabilities.Set(FS_VOLUME_CAPABILITY_SYNC, fFS->ops.fsync);
5520604d554SPulkoMandy // emulated via fsync()
5530604d554SPulkoMandy
554fd4f53a7SIngo Weinhold // file operations
555d16ba4b9SIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE, fFS->ops.create);
556fe24dc3dSIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN, fFS->ops.open);
557fe24dc3dSIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CLOSE, fFS->ops.flush);
558fe24dc3dSIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_COOKIE, fFS->ops.release);
559b5884f05SIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ, fFS->ops.read);
560d16ba4b9SIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE, fFS->ops.write);
561fd4f53a7SIngo Weinhold
562fd4f53a7SIngo Weinhold // directory operations
563cd4ee847SIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_DIR, fFS->ops.mkdir);
564cd4ee847SIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REMOVE_DIR, fFS->ops.rmdir);
5658d0f474cSIngo Weinhold bool readDirSupport = fFS->ops.opendir != NULL || fFS->ops.readdir != NULL
5668d0f474cSIngo Weinhold || fFS->ops.getdir;
5678d0f474cSIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_DIR, readDirSupport);
568cd4ee847SIngo Weinhold // not needed: FS_VNODE_CAPABILITY_CLOSE_DIR
5698d0f474cSIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_DIR_COOKIE, readDirSupport);
5708d0f474cSIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_DIR, readDirSupport);
5718d0f474cSIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_DIR, readDirSupport);
572fd4f53a7SIngo Weinhold
573fd4f53a7SIngo Weinhold // attribute directory operations
574f11f1730SIngo Weinhold bool hasAttributes = fFS->ops.listxattr != NULL;
575f11f1730SIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR, hasAttributes);
576cd4ee847SIngo Weinhold // not needed: FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR
577f11f1730SIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE,
578f11f1730SIngo Weinhold hasAttributes);
579f11f1730SIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_DIR, hasAttributes);
580f11f1730SIngo Weinhold fNodeCapabilities.Set(FS_VNODE_CAPABILITY_REWIND_ATTR_DIR, hasAttributes);
581fd4f53a7SIngo Weinhold
582fd4f53a7SIngo Weinhold // attribute operations
583f06f7337SIngo Weinhold // // we emulate open_attr() and free_attr_dir_cookie() if either read_attr()
584f06f7337SIngo Weinhold // // or write_attr() is present
585f06f7337SIngo Weinhold // bool hasAttributes = (fFS->ops.read_attr || fFS->ops.write_attr);
586f06f7337SIngo Weinhold // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_CREATE_ATTR, hasAttributes);
5875adf34b0SJulian Harnath fNodeCapabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR, hasAttributes);
5885adf34b0SJulian Harnath fNodeCapabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE, hasAttributes);
5895adf34b0SJulian Harnath fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR, fFS->ops.getxattr);
590f06f7337SIngo Weinhold // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_WRITE_ATTR, fFS->ops.write_attr);
591fd4f53a7SIngo Weinhold
5925adf34b0SJulian Harnath fNodeCapabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_STAT,
5935adf34b0SJulian Harnath fFS->ops.getxattr);
594f06f7337SIngo Weinhold // // missing: FS_VNODE_CAPABILITY_WRITE_ATTR_STAT
595f06f7337SIngo Weinhold // fNodeCapabilities.Set(FS_VNODE_CAPABILITY_RENAME_ATTR, fFS->ops.rename_attr);
5960604d554SPulkoMandy }
597f06f7337SIngo Weinhold }
598f06f7337SIngo Weinhold
599f06f7337SIngo Weinhold
600c9323289SIngo Weinhold // #pragma mark - bootstrapping
601c9323289SIngo Weinhold
602c9323289SIngo Weinhold
603c9323289SIngo Weinhold status_t
userlandfs_create_file_system(const char * fsName,image_id image,FileSystem ** _fileSystem)604c9323289SIngo Weinhold userlandfs_create_file_system(const char* fsName, image_id image,
605c9323289SIngo Weinhold FileSystem** _fileSystem)
606c9323289SIngo Weinhold {
607c9323289SIngo Weinhold printf("userlandfs_create_file_system()\n");
608c9323289SIngo Weinhold // look up the main() function of the add-on
609c9323289SIngo Weinhold int (*mainFunction)(int argc, const char* const* argv);
610c9323289SIngo Weinhold status_t error = get_image_symbol(image, "main", B_SYMBOL_TYPE_TEXT,
611c9323289SIngo Weinhold (void**)&mainFunction);
612c9323289SIngo Weinhold if (error != B_OK)
613c9323289SIngo Weinhold return error;
614c9323289SIngo Weinhold printf("userlandfs_create_file_system(): found main: %p\n", mainFunction);
615c9323289SIngo Weinhold
616c9323289SIngo Weinhold // create the file system
61769cd702bSIngo Weinhold FUSEFileSystem* fileSystem = new(std::nothrow) FUSEFileSystem(fsName,
61869cd702bSIngo Weinhold mainFunction);
619c9323289SIngo Weinhold if (fileSystem == NULL)
620c9323289SIngo Weinhold return B_NO_MEMORY;
621c9323289SIngo Weinhold
622c9323289SIngo Weinhold *_fileSystem = fileSystem;
623c9323289SIngo Weinhold return B_OK;
624c9323289SIngo Weinhold }
625