xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEFileSystem.cpp (revision 55f3abb4c9e74b9fc7ff9cb5f7155461dbdd9602)
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