1/*
2 * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5#ifndef VOLUME_H
6#define VOLUME_H
7
8
9#include <fs_interface.h>
10
11#include <condition_variable.h>
12#include <lock.h>
13#include <util/AutoLock.h>
14#include <util/DoublyLinkedList.h>
15#include <util/KMessage.h>
16
17#include "Index.h"
18#include "Node.h"
19#include "NodeListener.h"
20#include "PackageDomain.h"
21#include "PackageLinksListener.h"
22#include "Query.h"
23
24
25class Directory;
26class PackageFSRoot;
27class UnpackingNode;
28
29typedef IndexHashTable::Iterator IndexDirIterator;
30
31
32enum MountType {
33	MOUNT_TYPE_SYSTEM,
34	MOUNT_TYPE_COMMON,
35	MOUNT_TYPE_HOME,
36	MOUNT_TYPE_CUSTOM
37};
38
39
40class Volume : public DoublyLinkedListLinkImpl<Volume>,
41	private PackageLinksListener {
42public:
43								Volume(fs_volume* fsVolume);
44								~Volume();
45
46	inline	bool				ReadLock() const;
47	inline	void				ReadUnlock() const;
48	inline	bool				WriteLock();
49	inline	void				WriteUnlock();
50
51			fs_volume*			FSVolume() const	{ return fFSVolume; }
52			dev_t				ID() const			{ return fFSVolume->id; }
53			Directory*			RootDirectory() const { return fRootDirectory; }
54
55			::MountType			MountType() const	{ return fMountType; }
56
57			void				SetPackageFSRoot(::PackageFSRoot* root)
58									{ fPackageFSRoot = root; }
59			::PackageFSRoot*	PackageFSRoot() const
60									{ return fPackageFSRoot; }
61
62			dev_t				MountPointDeviceID() const
63									{ return fMountPoint.deviceID; }
64			ino_t				MountPointNodeID() const
65									{ return fMountPoint.nodeID; }
66
67			status_t			Mount(const char* parameterString);
68			void				Unmount();
69
70			Node*				FindNode(ino_t nodeID) const
71									{ return fNodes.Lookup(nodeID); }
72
73			// node listeners -- volume must be write-locked
74			void				AddNodeListener(NodeListener* listener,
75									Node* node);
76			void				RemoveNodeListener(NodeListener* listener);
77
78			// query support -- volume must be write-locked
79			void				AddQuery(Query* query);
80			void				RemoveQuery(Query* query);
81			void				UpdateLiveQueries(Node* node,
82									const char* attribute, int32 type,
83									const void* oldKey, size_t oldLength,
84									const void* newKey, size_t newLength);
85
86			Index*				FindIndex(const char* name) const
87									{ return fIndices.Lookup(name); }
88			IndexDirIterator	GetIndexDirIterator() const
89									{ return fIndices.GetIterator(); }
90
91			// VFS wrappers
92			status_t			GetVNode(ino_t nodeID, Node*& _node);
93			status_t			PutVNode(ino_t nodeID);
94			status_t			RemoveVNode(ino_t nodeID);
95			status_t			PublishVNode(Node* node);
96
97			status_t			AddPackageDomain(const char* path);
98
99private:
100	// PackageLinksListener
101	virtual	void				PackageLinkNodeAdded(Node* node);
102	virtual	void				PackageLinkNodeRemoved(Node* node);
103	virtual	void				PackageLinkNodeChanged(Node* node,
104									uint32 statFields,
105									const OldNodeAttributes& oldAttributes);
106
107private:
108			struct Job;
109			struct AddPackageDomainJob;
110			struct DomainDirectoryEventJob;
111			struct PackageLoaderErrorOutput;
112			struct PackageLoaderContentHandler;
113			struct DomainDirectoryListener;
114			struct ShineThroughDirectory;
115
116			friend struct AddPackageDomainJob;
117			friend struct DomainDirectoryEventJob;
118			friend struct DomainDirectoryListener;
119
120			typedef DoublyLinkedList<Job> JobList;
121			typedef DoublyLinkedList<PackageDomain> PackageDomainList;
122
123private:
124	static	status_t			_PackageLoaderEntry(void* data);
125			status_t			_PackageLoader();
126
127			void				_TerminatePackageLoader();
128
129			void				_PushJob(Job* job);
130
131			status_t			_AddInitialPackageDomain(const char* path);
132			status_t			_AddPackageDomain(PackageDomain* domain,
133									bool notify);
134			void				_RemovePackageDomain(PackageDomain* domain);
135			status_t			_LoadPackage(Package* package);
136
137			status_t			_AddPackageContent(Package* package,
138									bool notify);
139			void				_RemovePackageContent(Package* package,
140									PackageNode* endNode, bool notify);
141
142			status_t			_AddPackageContentRootNode(Package* package,
143									PackageNode* node, bool notify);
144			void				_RemovePackageContentRootNode(Package* package,
145									PackageNode* packageNode,
146									PackageNode* endPackageNode, bool notify);
147
148			status_t			_AddPackageNode(Directory* directory,
149									PackageNode* packageNode, bool notify,
150									Node*& _node);
151			void				_RemovePackageNode(Directory* directory,
152									PackageNode* packageNode, Node* node,
153									bool notify);
154
155			status_t			_CreateUnpackingNode(mode_t mode,
156									Directory* parent, const char* name,
157									UnpackingNode*& _node);
158									// does *not* return a reference
159			void				_RemoveNode(Node* node);
160			void				_RemoveNodeAndVNode(Node* node);
161									// caller must hold a reference
162
163			void				_DomainListenerEventOccurred(
164									PackageDomain* domain,
165									const KMessage* event);
166			void				_DomainEntryCreated(PackageDomain* domain,
167									dev_t deviceID, ino_t directoryID,
168									ino_t nodeID, const char* name,
169									bool addContent, bool notify);
170			void				_DomainEntryRemoved(PackageDomain* domain,
171									dev_t deviceID, ino_t directoryID,
172									ino_t nodeID, const char* name,
173									bool notify);
174			void				_DomainEntryMoved(PackageDomain* domain,
175									dev_t deviceID, ino_t fromDirectoryID,
176									ino_t toDirectoryID, dev_t nodeDeviceID,
177									ino_t nodeID, const char* fromName,
178									const char* name, bool notify);
179
180			status_t			_InitMountType(const char* mountType);
181			status_t			_CreateShineThroughDirectory(Directory* parent,
182									const char* name, Directory*& _directory);
183			status_t			_CreateShineThroughDirectories(
184									const char* shineThroughSetting);
185			status_t			_PublishShineThroughDirectories();
186
187			status_t			_AddPackageLinksDirectory();
188			void				_RemovePackageLinksDirectory();
189			void				_AddPackageLinksNode(Node* node);
190			void				_RemovePackageLinksNode(Node* node);
191
192	inline	Volume*				_SystemVolumeIfNotSelf() const;
193
194			void				_NotifyNodeAdded(Node* node);
195			void				_NotifyNodeRemoved(Node* node);
196			void				_NotifyNodeChanged(Node* node,
197									uint32 statFields,
198									const OldNodeAttributes& oldAttributes);
199
200private:
201	mutable	rw_lock				fLock;
202			fs_volume*			fFSVolume;
203			Directory*			fRootDirectory;
204			::PackageFSRoot*	fPackageFSRoot;
205			::MountType			fMountType;
206			thread_id			fPackageLoader;
207			PackageDomainList	fPackageDomains;
208
209			struct {
210				dev_t			deviceID;
211				ino_t			nodeID;
212			} fMountPoint;
213
214			NodeIDHashTable		fNodes;
215			NodeListenerHashTable fNodeListeners;
216			QueryList			fQueries;
217			IndexHashTable		fIndices;
218
219			JobList				fJobQueue;
220			mutex				fJobQueueLock;
221			ConditionVariable	fJobQueueCondition;
222
223			ino_t				fNextNodeID;
224
225	volatile bool				fTerminating;
226};
227
228
229bool
230Volume::ReadLock() const
231{
232	return rw_lock_read_lock(&fLock) == B_OK;
233}
234
235
236void
237Volume::ReadUnlock() const
238{
239	rw_lock_read_unlock(&fLock);
240}
241
242
243bool
244Volume::WriteLock()
245{
246	return rw_lock_write_lock(&fLock) == B_OK;
247}
248
249
250void
251Volume::WriteUnlock()
252{
253	rw_lock_write_unlock(&fLock);
254}
255
256
257typedef AutoLocker<const Volume, AutoLockerReadLocking<const Volume> >
258	VolumeReadLocker;
259typedef AutoLocker<Volume, AutoLockerWriteLocking<Volume> > VolumeWriteLocker;
260
261
262#endif	// VOLUME_H
263