1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5#ifndef USERLAND_FS_FUSE_VOLUME_H
6#define USERLAND_FS_FUSE_VOLUME_H
7
8#include <AutoLocker.h>
9#include <RWLockManager.h>
10
11#include "Locker.h"
12
13#include "fuse_fs.h"
14#include "FUSEEntry.h"
15#include "FUSEFileSystem.h"
16
17#include "../Volume.h"
18
19
20namespace UserlandFS {
21
22class FUSEFileSystem;
23
24
25class FUSEVolume : public Volume {
26public:
27								FUSEVolume(FUSEFileSystem* fileSystem,
28									dev_t id);
29	virtual						~FUSEVolume();
30
31			status_t			Init();
32
33			void				SetFS(fuse_fs* fs)	{ fFS = fs; }
34
35	// FS
36	virtual	status_t			Mount(const char* device, uint32 flags,
37									const char* parameters, ino_t* rootID);
38	virtual	status_t			Unmount();
39	virtual	status_t			Sync();
40	virtual	status_t			ReadFSInfo(fs_info* info);
41
42	// vnodes
43	virtual	status_t			Lookup(void* dir, const char* entryName,
44									ino_t* vnid);
45	virtual	status_t			GetVNodeName(void* node, char* buffer,
46									size_t bufferSize);
47	virtual	status_t			ReadVNode(ino_t vnid, bool reenter,
48									void** node, int* type, uint32* flags,
49									FSVNodeCapabilities* _capabilities);
50	virtual	status_t			WriteVNode(void* node, bool reenter);
51	virtual	status_t			RemoveVNode(void* node, bool reenter);
52
53	// asynchronous I/O
54	virtual	status_t			DoIO(void* node, void* cookie,
55									const IORequestInfo& requestInfo);
56
57	// nodes
58	virtual	status_t			SetFlags(void* node, void* cookie,
59									int flags);
60
61	virtual	status_t			FSync(void* node);
62
63	virtual	status_t			ReadSymlink(void* node, char* buffer,
64									size_t bufferSize, size_t* bytesRead);
65	virtual	status_t			CreateSymlink(void* dir, const char* name,
66									const char* target, int mode);
67
68	virtual	status_t			Link(void* dir, const char* name,
69									void* node);
70	virtual	status_t			Unlink(void* dir, const char* name);
71	virtual	status_t			Rename(void* oldDir, const char* oldName,
72									void* newDir, const char* newName);
73
74	virtual	status_t			Access(void* node, int mode);
75	virtual	status_t			ReadStat(void* node, struct stat* st);
76	virtual	status_t			WriteStat(void* node, const struct stat* st,
77									uint32 mask);
78
79	// files
80	virtual	status_t			Create(void* dir, const char* name,
81									int openMode, int mode, void** cookie,
82									ino_t* vnid);
83	virtual	status_t			Open(void* node, int openMode,
84									void** cookie);
85	virtual	status_t			Close(void* node, void* cookie);
86	virtual	status_t			FreeCookie(void* node, void* cookie);
87	virtual	status_t			Read(void* node, void* cookie, off_t pos,
88									void* buffer, size_t bufferSize,
89									size_t* bytesRead);
90	virtual	status_t			Write(void* node, void* cookie,
91									off_t pos, const void* buffer,
92									size_t bufferSize, size_t* bytesWritten);
93
94	// directories
95	virtual	status_t			CreateDir(void* dir, const char* name,
96									int mode);
97	virtual	status_t			RemoveDir(void* dir, const char* name);
98	virtual	status_t			OpenDir(void* node, void** cookie);
99	virtual	status_t			CloseDir(void* node, void* cookie);
100	virtual	status_t			FreeDirCookie(void* node, void* cookie);
101	virtual	status_t			ReadDir(void* node, void* cookie,
102									void* buffer, size_t bufferSize,
103									uint32 count, uint32* countRead);
104	virtual	status_t			RewindDir(void* node, void* cookie);
105
106	// attribute directories
107	virtual	status_t			OpenAttrDir(void* node, void** cookie);
108	virtual	status_t			CloseAttrDir(void* node, void* cookie);
109	virtual	status_t			FreeAttrDirCookie(void* node,
110									void* cookie);
111	virtual	status_t			ReadAttrDir(void* node, void* cookie,
112									void* buffer, size_t bufferSize,
113									uint32 count, uint32* countRead);
114	virtual	status_t			RewindAttrDir(void* node, void* cookie);
115
116	// attributes
117	virtual	status_t			OpenAttr(void* node, const char* name,
118									int openMode, void** cookie);
119	virtual	status_t			CloseAttr(void* node, void* cookie);
120	virtual	status_t			FreeAttrCookie(void* node, void* cookie);
121	virtual	status_t			ReadAttr(void* node, void* cookie,
122									off_t pos, void* buffer, size_t bufferSize,
123									size_t* bytesRead);
124	virtual	status_t			ReadAttrStat(void* node, void* cookie,
125									struct stat* st);
126
127private:
128	struct DirEntryCache;
129	struct DirCookie;
130	struct FileCookie;
131	struct AttrDirCookie;
132	struct AttrCookie;
133	struct ReadDirBuffer;
134	struct LockIterator;
135	struct RWLockableReadLocking;
136	struct RWLockableWriteLocking;
137	struct RWLockableReadLocker;
138	struct RWLockableWriteLocker;
139	struct NodeLocker;
140	struct NodeReadLocker;
141	struct NodeWriteLocker;
142	struct MultiNodeLocker;
143
144	friend struct LockIterator;
145	friend struct RWLockableReadLocking;
146	friend struct RWLockableWriteLocking;
147	friend struct NodeLocker;
148	friend struct MultiNodeLocker;
149
150private:
151	inline	FUSEFileSystem*		_FileSystem() const
152									{ return static_cast<FUSEFileSystem*>(fFileSystem); }
153
154			ino_t				_GenerateNodeID();
155
156			bool				_GetNodeID(FUSENode* dir, const char* entryName,
157									ino_t* _nodeID);
158			status_t			_GetNode(FUSENode* dir, const char* entryName,
159									FUSENode** _node);
160			status_t			_InternalGetNode(FUSENode* dir,
161									const char* entryName, FUSENode** _node,
162									AutoLocker<Locker>& locker);
163			void				_PutNode(FUSENode* node);
164			void				_PutNodes(FUSENode* const* nodes, int32 count);
165
166			void				_RemoveEntry(FUSEEntry* entry);
167			status_t			_RemoveEntry(FUSENode* dir, const char* name);
168			status_t			_RenameEntry(FUSENode* oldDir,
169									const char* oldName, FUSENode* newDir,
170									const char* newName);
171
172			status_t			_LockNodeChain(FUSENode* node, bool lockParent,
173									bool writeLock);
174			void				_UnlockNodeChain(FUSENode* node, bool parent,
175									bool writeLock);
176			void				_UnlockNodeChainInternal(FUSENode* node,
177									bool writeLock, FUSENode* stopNode,
178									FUSENode* stopBeforeNode);
179
180			status_t			_LockNodeChains(FUSENode* node1,
181									bool lockParent1, bool writeLock1,
182									FUSENode* node2, bool lockParent2,
183									bool writeLock2);
184			status_t			_LockNodeChainsInternal(FUSENode* node1,
185									bool lockParent1, bool writeLock1,
186									FUSENode* node2, bool lockParent2,
187									bool writeLock2, bool* _retry);
188			void				_UnlockNodeChains(FUSENode* node1, bool parent1,
189									bool writeLock1, FUSENode* node2,
190									bool parent2, bool writeLock2);
191
192			bool				_FindCommonAncestor(FUSENode* node1,
193									FUSENode* node2, FUSENode** _commonAncestor,
194									bool* _inverseLockingOrder);
195			bool				_GetNodeAncestors(FUSENode* node,
196									FUSENode** ancestors, uint32* _count);
197
198			status_t			_BuildPath(FUSENode* dir, const char* entryName,
199									char* path, size_t& pathLen);
200			status_t			_BuildPath(FUSENode* node, char* path,
201									size_t& pathLen);
202
203	static	int					_AddReadDirEntryLowLevel(void* buffer, char* buf, size_t bufsize,
204									const char* name, const struct stat* st, off_t offset);
205	static	int					_AddReadDirEntry(void* buffer, const char* name,
206									const struct stat* st, off_t offset);
207	static	int					_AddReadDirEntryGetDir(fuse_dirh_t handle,
208									const char* name, int type, ino_t nodeID);
209			int					_AddReadDirEntryLowLevel(ReadDirBuffer* buffer,
210									char* buf, size_t bufSize, const char* name, int type,
211									ino_t nodeID, off_t offset);
212			int					_AddReadDirEntry(ReadDirBuffer* buffer,
213									const char* name, int type, ino_t nodeID,
214									off_t offset);
215			status_t			_InternalIO(FUSENode* node, FileCookie* cookie, const char* path,
216									off_t pos, char* buffer, size_t& bytes, bool isWrite);
217
218private:
219			RWLockManager		fLockManager;
220			Locker				fLock;
221	const	fuse_lowlevel_ops*	fOps;
222			fuse_fs*			fFS;
223			FUSEEntryTable		fEntries;
224			FUSENodeTable		fNodes;
225			FUSENode*			fRootNode;
226			ino_t				fNextNodeID;
227			bool				fUseNodeIDs;
228			char				fName[B_OS_NAME_LENGTH];
229};
230
231}	// namespace UserlandFS
232
233using UserlandFS::FUSEVolume;
234
235#endif	// USERLAND_FS_FUSE_VOLUME_H
236