1// ShareVolume.cpp
2
3#include "ShareVolume.h"
4
5#include <new>
6#include <unistd.h>
7
8#include <AppDefs.h>	// for B_QUERY_UPDATE
9
10#include "AuthenticationServer.h"
11#include "AutoDeleter.h"
12#include "AutoLocker.h"
13#include "Compatibility.h"
14#include "Connection.h"
15#include "ConnectionFactory.h"
16#include "Debug.h"
17#include "ExtendedServerInfo.h"
18#include "HashMap.h"
19#include "Permissions.h"
20#include "Node.h"
21#include "QueryManager.h"
22#include "RequestChannel.h"
23#include "RequestConnection.h"
24#include "Requests.h"
25#include "RootVolume.h"
26#include "SendReceiveRequest.h"
27#include "ServerConnection.h"
28#include "ServerConnectionProvider.h"
29#include "ShareAttrDir.h"
30#include "ShareAttrDirIterator.h"
31#include "ShareNode.h"
32#include "Utils.h"
33#include "VolumeManager.h"
34#include "VolumeSupport.h"
35
36// TODO: Request timeouts!
37
38static const int32 kMaxWriteBufferSize	= 64 * 1024;	// 64 KB
39static const int32 kUserBufferSize = 256;
40static const int32 kPasswordBufferSize = 256;
41
42// connection states
43enum {
44	CONNECTION_NOT_INITIALIZED,
45	CONNECTION_READY,
46	CONNECTION_CLOSED,
47};
48
49// NodeMap
50struct ShareVolume::NodeMap : HashMap<HashKey64<ino_t>, ShareNode*> {
51};
52
53// EntryKey
54//
55// NOTE: This class doesn't make a copy of the name string it is constructed
56// with. So, when entering the key in a map, one must make sure, that the
57// string stays valid as long as the entry is in the map.
58struct ShareVolume::EntryKey {
59	EntryKey() {}
60
61	EntryKey(ino_t directoryID, const char* name)
62		: directoryID(directoryID),
63		  name(name)
64	{
65	}
66
67	EntryKey(const EntryKey& other)
68		: directoryID(other.directoryID),
69		  name(other.name)
70	{
71	}
72
73	uint32 GetHashCode() const
74	{
75		uint32 hash = (uint32)directoryID;
76		hash = 31 * hash + (uint32)(directoryID >> 32);
77		hash = 31 * hash + string_hash(name);
78		return hash;
79	}
80
81	EntryKey& operator=(const EntryKey& other)
82	{
83		directoryID = other.directoryID;
84		name = other.name;
85		return *this;
86	}
87
88	bool operator==(const EntryKey& other) const
89	{
90		if (directoryID != other.directoryID)
91			return false;
92
93		if (name)
94			return (other.name && strcmp(name, other.name) == 0);
95
96		return !other.name;
97	}
98
99	bool operator!=(const EntryKey& other) const
100	{
101		return !(*this == other);
102	}
103
104	ino_t		directoryID;
105	const char*	name;
106};
107
108// EntryMap
109struct ShareVolume::EntryMap : HashMap<EntryKey, ShareDirEntry*> {
110};
111
112// LocalNodeIDMap
113struct ShareVolume::LocalNodeIDMap : HashMap<NodeID, ino_t> {
114};
115
116// RemoteNodeIDMap
117struct ShareVolume::RemoteNodeIDMap : HashMap<HashKey64<ino_t>, NodeID> {
118};
119
120// DirCookie
121struct ShareVolume::DirCookie {
122	ShareDirIterator*	iterator;
123};
124
125// AttrDirCookie
126struct ShareVolume::AttrDirCookie {
127	AttrDirCookie()
128		: iterator(NULL),
129		  cookie(-1),
130		  rewind(false)
131	{
132	}
133
134	ShareAttrDirIterator*	iterator;
135	int32					cookie;
136	bool					rewind;
137};
138
139// AttrDirIteratorMap
140struct ShareVolume::AttrDirIteratorMap
141	: HashMap<HashKey64<ino_t>, DLList<ShareAttrDirIterator>*> {
142};
143
144
145// #pragma mark -
146
147// constructor
148ShareVolume::ShareVolume(VolumeManager* volumeManager,
149	ServerConnectionProvider* connectionProvider,
150	ExtendedServerInfo* serverInfo, ExtendedShareInfo* shareInfo)
151	: Volume(volumeManager),
152	  fID(-1),
153	  fFlags(0),
154	  fMountLock("share mount lock"),
155	  fNodes(NULL),
156	  fEntries(NULL),
157	  fAttrDirIterators(NULL),
158	  fLocalNodeIDs(NULL),
159	  fRemoteNodeIDs(NULL),
160	  fServerConnectionProvider(connectionProvider),
161	  fServerInfo(serverInfo),
162	  fShareInfo(shareInfo),
163	  fServerConnection(NULL),
164	  fConnection(NULL),
165	  fSharePermissions(0),
166	  fConnectionState(CONNECTION_NOT_INITIALIZED)
167{
168	fFlags = fVolumeManager->GetMountFlags();
169	if (fServerConnectionProvider)
170		fServerConnectionProvider->AddReference();
171	if (fServerInfo)
172		fServerInfo->AddReference();
173	if (fShareInfo)
174		fShareInfo->AddReference();
175}
176
177// destructor
178ShareVolume::~ShareVolume()
179{
180PRINT(("ShareVolume::~ShareVolume()\n"));
181	// delete the root node
182	if (fRootNode) {
183		if (fNodes)
184			fNodes->Remove(fRootNode->GetID());
185		delete fRootNode;
186		fRootNode = NULL;
187	}
188
189	// delete the nodes
190	if (fNodes) {
191		// there shouldn't be any more nodes
192		if (fNodes->Size() > 0) {
193			WARN(("ShareVolume::~ShareVolume(): WARNING: There are still "
194				"%ld nodes\n", fNodes->Size()));
195		}
196		for (NodeMap::Iterator it = fNodes->GetIterator(); it.HasNext();)
197			delete it.Next().value;
198		delete fNodes;
199	}
200
201	// delete the entries
202	if (fEntries) {
203		// there shouldn't be any more entries
204		if (fEntries->Size() > 0) {
205			WARN(("ShareVolume::~ShareVolume(): WARNING: There are still "
206				"%ld entries\n", fEntries->Size()));
207		}
208		for (EntryMap::Iterator it = fEntries->GetIterator(); it.HasNext();)
209			delete it.Next().value;
210		delete fEntries;
211	}
212
213	delete fLocalNodeIDs;
214	delete fRemoteNodeIDs;
215
216	if (fShareInfo)
217		fShareInfo->RemoveReference();
218	if (fServerInfo)
219		fServerInfo->RemoveReference();
220	if (fServerConnection)
221		fServerConnection->RemoveReference();
222	if (fServerConnectionProvider)
223		fServerConnectionProvider->RemoveReference();
224}
225
226// GetID
227nspace_id
228ShareVolume::GetID() const
229{
230	return fID;
231}
232
233// IsReadOnly
234bool
235ShareVolume::IsReadOnly() const
236{
237	return (fFlags & B_MOUNT_READ_ONLY);
238}
239
240// SupportsQueries
241bool
242ShareVolume::SupportsQueries() const
243{
244	return (fSharePermissions & QUERY_SHARE_PERMISSION);
245}
246
247// Init
248status_t
249ShareVolume::Init(const char* name)
250{
251	status_t error = Volume::Init(name);
252	if (error != B_OK)
253		return error;
254
255	// create node map
256	fNodes = new(nothrow) NodeMap;
257	if (!fNodes)
258		RETURN_ERROR(B_NO_MEMORY);
259	error = fNodes->InitCheck();
260	if (error != B_OK)
261		return error;
262
263	// create entry map
264	fEntries = new(nothrow) EntryMap;
265	if (!fEntries)
266		RETURN_ERROR(B_NO_MEMORY);
267	error = fEntries->InitCheck();
268	if (error != B_OK)
269		return error;
270
271	// create attribute iterator map
272	fAttrDirIterators = new(nothrow) AttrDirIteratorMap;
273	if (!fAttrDirIterators)
274		RETURN_ERROR(B_NO_MEMORY);
275	error = fAttrDirIterators->InitCheck();
276	if (error != B_OK)
277		return error;
278
279	// create local node ID map
280	fLocalNodeIDs = new(nothrow) LocalNodeIDMap;
281	if (!fLocalNodeIDs)
282		RETURN_ERROR(B_NO_MEMORY);
283	error = fLocalNodeIDs->InitCheck();
284	if (error != B_OK)
285		return error;
286
287	// create remote node ID map
288	fRemoteNodeIDs = new(nothrow) RemoteNodeIDMap;
289	if (!fRemoteNodeIDs)
290		RETURN_ERROR(B_NO_MEMORY);
291	error = fRemoteNodeIDs->InitCheck();
292	if (error != B_OK)
293		return error;
294
295	// get a local node ID for our root node
296	vnode_id localID = fVolumeManager->NewNodeID(this);
297	if (localID < 0)
298		return localID;
299
300	// create the root node
301	fRootNode = new(nothrow) ShareDir(this, localID, NULL);
302	if (!fRootNode) {
303		fVolumeManager->RemoveNodeID(localID);
304		return B_NO_MEMORY;
305	}
306
307	// add the root node to the node map
308	error = fNodes->Put(localID, fRootNode);
309	if (error != B_OK)
310		return error;
311
312	return B_OK;
313}
314
315// Uninit
316void
317ShareVolume::Uninit()
318{
319	Volume::Uninit();
320}
321
322// GetRootNode
323Node*
324ShareVolume::GetRootNode() const
325{
326	return fRootNode;
327}
328
329// PrepareToUnmount
330void
331ShareVolume::PrepareToUnmount()
332{
333PRINT(("ShareVolume::PrepareToUnmount()\n"));
334	Volume::PrepareToUnmount();
335
336	ConnectionClosed();
337
338	AutoLocker<Locker> locker(fLock);
339
340	// remove all entries and send respective "entry removed" events
341	for (EntryMap::Iterator it = fEntries->GetIterator(); it.HasNext();) {
342		ShareDirEntry* entry = it.Next().value;
343
344		NotifyListener(B_ENTRY_REMOVED, fVolumeManager->GetID(),
345			entry->GetDirectory()->GetID(), 0, entry->GetNode()->GetID(),
346			entry->GetName());
347
348		it.Remove();
349		_RemoveEntry(entry);
350	}
351
352	// get all IDs
353	int32 count = fNodes->Size();
354	if (count == 0)
355		return;
356PRINT(("  %ld nodes to remove\n", count));
357	vnode_id* ids = new(nothrow) vnode_id[count];
358	if (!ids) {
359		ERROR(("ShareVolume::PrepareToUnmount(): ERROR: Insufficient memory to "
360			"allocate the node ID array!\n"));
361		return;
362	}
363	ArrayDeleter<vnode_id> _(ids);
364	count = 0;
365	for (NodeMap::Iterator it = fNodes->GetIterator(); it.HasNext();) {
366		ShareNode* node = it.Next().value;
367		ids[count++] = node->GetID();
368	}
369
370	// Remove all nodes that are not known to the VFS right away.
371	// If the netfs is already in the process of being unmounted, GetVNode()
372	// will fail and the GetVNode(), RemoveVNode(), PutVNode() method won't
373	// work for removing them.
374	int32 remainingCount = 0;
375	for (int32 i = 0; i < count; i++) {
376		if (Node* node = fNodes->Get(ids[i])) {
377			if (node->IsKnownToVFS()) {
378				// node is known to VFS; we need to use the GetVNode(),
379				// RemoveVNode(), PutVNode() method
380				ids[remainingCount++] = ids[i];
381			} else {
382				// node is not known to VFS; just remove and delete it
383				fNodes->Remove(node->GetID());
384				_RemoveLocalNodeID(node->GetID());
385				if (node != fRootNode)
386					delete node;
387			}
388		}
389	}
390	count = remainingCount;
391
392	locker.Unlock();
393
394	// remove the nodes
395	for (int32 i = 0; i < count; i++) {
396		Node* node;
397		if (GetVNode(ids[i], &node) == B_OK) {
398PRINT(("  removing node %lld\n", ids[i]));
399			Volume::RemoveVNode(ids[i]);
400			PutVNode(ids[i]);
401		}
402	}
403
404	// remove ourselves for the server connection
405	if (fServerConnection)
406		fServerConnection->RemoveVolume(this);
407
408	// delete all entries
409
410PRINT(("ShareVolume::PrepareToUnmount() done\n"));
411}
412
413// RemoveChildVolume
414void
415ShareVolume::RemoveChildVolume(Volume* volume)
416{
417	// should never be called
418	WARN(("WARNING: ShareVolume::RemoveChildVolume(%p) invoked!\n", volume));
419}
420
421
422// #pragma mark -
423// #pragma mark ----- FS -----
424
425// Unmount
426status_t
427ShareVolume::Unmount()
428{
429	if (_IsConnected()) {
430		// send the request
431		UnmountRequest request;
432		request.volumeID = fID;
433		fConnection->SendRequest(&request);
434	}
435	return B_OK;
436}
437
438// Sync
439status_t
440ShareVolume::Sync()
441{
442	// TODO: Implement?
443	// We can't implement this without risking an endless recursion. The server
444	// could only invoke sync(), which would sync all FSs, including a NetFS
445	// which might be connected with a server running alongside this client.
446	// We could introduce a sync flag to break the recursion. This might be
447	// risky though.
448	return B_OK;
449}
450
451
452// #pragma mark -
453// #pragma mark ----- vnodes -----
454
455// ReadVNode
456status_t
457ShareVolume::ReadVNode(vnode_id vnid, char reenter, Node** _node)
458{
459	// check the map, maybe it's already loaded
460	ShareNode* node = NULL;
461	{
462		AutoLocker<Locker> _(fLock);
463		node = _GetNodeByLocalID(vnid);
464		if (node) {
465			node->SetKnownToVFS(true);
466			*_node = node;
467
468			// add a volume reference for the node
469			AddReference();
470
471			return B_OK;
472		}
473	}
474
475	// not yet loaded: send a request to the server
476	if (!_EnsureShareMounted())
477		return ERROR_NOT_CONNECTED;
478
479	// get the remote ID
480	NodeID remoteID;
481	status_t error = _GetRemoteNodeID(vnid, &remoteID);
482	if (error != B_OK)
483		return error;
484
485	// prepare the request
486	ReadVNodeRequest request;
487	request.volumeID = fID;
488	request.nodeID = remoteID;
489
490	// send the request
491	ReadVNodeReply* reply;
492	error = SendRequest(fConnection, &request, &reply);
493	if (error != B_OK)
494		RETURN_ERROR(error);
495	ObjectDeleter<Request> replyDeleter(reply);
496	if (reply->error != B_OK)
497		RETURN_ERROR(reply->error);
498
499	// add the node
500	AutoLocker<Locker> _(fLock);
501	error = _LoadNode(reply->nodeInfo, &node);
502	if (error != B_OK)
503		RETURN_ERROR(error);
504	node->SetKnownToVFS(true);
505	*_node = node;
506
507	// add a volume reference for the node
508	AddReference();
509
510	return B_OK;
511}
512
513// WriteVNode
514status_t
515ShareVolume::WriteVNode(Node* node, char reenter)
516{
517	AutoLocker<Locker> locker(fLock);
518	node->SetKnownToVFS(false);
519
520	// surrender the node's volume reference
521	locker.Unlock();
522	PutVolume();
523
524	return B_OK;
525}
526
527// RemoveVNode
528status_t
529ShareVolume::RemoveVNode(Node* node, char reenter)
530{
531	AutoLocker<Locker> locker(fLock);
532	node->SetKnownToVFS(false);
533	fNodes->Remove(node->GetID());
534	_RemoveLocalNodeID(node->GetID());
535	if (node != fRootNode)
536		delete node;
537
538	// surrender the node's volume reference
539	locker.Unlock();
540	PutVolume();
541
542	return B_OK;
543}
544
545
546// #pragma mark -
547// #pragma mark ----- nodes -----
548
549// FSync
550status_t
551ShareVolume::FSync(Node* _node)
552{
553	// TODO: Implement!
554	return B_BAD_VALUE;
555}
556
557// ReadStat
558status_t
559ShareVolume::ReadStat(Node* _node, struct stat* st)
560{
561	ShareNode* node = dynamic_cast<ShareNode*>(_node);
562
563	AutoLocker<Locker> _(fLock);
564	*st = node->GetNodeInfo().st;
565	st->st_dev = fVolumeManager->GetID();
566	st->st_ino = node->GetID();
567	// we set the UID/GID fields to the one who mounted the FS
568	st->st_uid = fVolumeManager->GetMountUID();
569	st->st_gid = fVolumeManager->GetMountGID();
570	return B_OK;
571}
572
573// WriteStat
574status_t
575ShareVolume::WriteStat(Node* _node, struct stat *st, uint32 mask)
576{
577	ShareNode* node = dynamic_cast<ShareNode*>(_node);
578
579	if (!_EnsureShareMounted())
580		return ERROR_NOT_CONNECTED;
581
582	// check read-only
583	if (IsReadOnly())
584		return B_PERMISSION_DENIED;
585	// prepare the request
586	WriteStatRequest request;
587	request.volumeID = fID;
588	request.nodeID = node->GetRemoteID();
589	request.nodeInfo.st = *st;
590	request.mask = mask;
591	// send the request
592	WriteStatReply* reply;
593	status_t error = SendRequest(fConnection, &request, &reply);
594	if (error != B_OK)
595		RETURN_ERROR(error);
596	ObjectDeleter<Request> replyDeleter(reply);
597	// update the node
598	if (reply->nodeInfoValid)
599		_UpdateNode(reply->nodeInfo);
600	if (reply->error != B_OK)
601		RETURN_ERROR(reply->error);
602	return B_OK;
603}
604
605// Access
606status_t
607ShareVolume::Access(Node* _node, int mode)
608{
609	// TODO: Implement.
610	return B_OK;
611}
612
613
614// #pragma mark -
615// #pragma mark ----- files -----
616
617// Create
618status_t
619ShareVolume::Create(Node* _dir, const char* name, int openMode, int mode,
620	vnode_id* vnid, void** cookie)
621{
622	ShareDir* dir = dynamic_cast<ShareDir*>(_dir);
623	if (!dir)
624		return B_BAD_VALUE;
625
626	if (!_EnsureShareMounted())
627		return ERROR_NOT_CONNECTED;
628
629	// check permissions
630	if (IsReadOnly())
631		return B_PERMISSION_DENIED;
632	if (IsVNodeRemoved(dir->GetID()) > 0)
633		RETURN_ERROR(B_NOT_ALLOWED);
634
635	// prepare the request
636	CreateFileRequest request;
637	request.volumeID = fID;
638	request.directoryID = dir->GetRemoteID();
639	request.name.SetTo(name);
640	request.openMode = openMode;
641	request.mode = mode;
642
643	// send the request
644	CreateFileReply* reply;
645	status_t error = SendRequest(fConnection, &request, &reply);
646	if (error != B_OK)
647		RETURN_ERROR(error);
648	ObjectDeleter<Request> replyDeleter(reply);
649	if (reply->error != B_OK)
650		RETURN_ERROR(reply->error);
651
652	// add/update the entry
653	vnode_id localID = -1;
654	EntryInfo* entryInfo = &reply->entryInfo;
655	while (true) {
656		// get an up to date entry info
657		WalkReply* walkReply = NULL;
658		if (!entryInfo) {
659			error = _Walk(reply->entryInfo.directoryID,
660				reply->entryInfo.name.GetString(), false, &walkReply);
661			if (error != B_OK)
662				break;
663
664			entryInfo = &walkReply->entryInfo;
665		}
666		ObjectDeleter<Request> walkReplyDeleter(walkReply);
667
668		AutoLocker<Locker> locker(fLock);
669
670		// check, if the info is obsolete
671		if (_IsObsoleteEntryInfo(*entryInfo)) {
672			entryInfo = NULL;
673			continue;
674		}
675
676		// load the entry
677		ShareDirEntry* entry;
678		error = _LoadEntry(dir, *entryInfo, &entry);
679		if (error == B_OK)
680			localID = entry->GetNode()->GetID();
681
682		break;
683	}
684
685	if (error == B_OK) {
686		Node* _node;
687		error = GetVNode(localID, &_node);
688	}
689
690	// set the results / close the handle on error
691	if (error == B_OK) {
692		*vnid = localID;
693		*cookie = (void*)reply->cookie;
694	} else
695		_Close(reply->cookie);
696
697	RETURN_ERROR(error);
698}
699
700// Open
701status_t
702ShareVolume::Open(Node* _node, int openMode, void** cookie)
703{
704	ShareNode* node = dynamic_cast<ShareNode*>(_node);
705
706// TODO: Allow opening the root node?
707	if (!_EnsureShareMounted())
708		return ERROR_NOT_CONNECTED;
709
710	// check the open mode
711	if (IsReadOnly()) {
712		if ((openMode & O_RWMASK) == O_WRONLY)
713			return B_PERMISSION_DENIED;
714		if (openMode & O_TRUNC)
715			return B_PERMISSION_DENIED;
716		if ((openMode & O_RWMASK) == O_RDWR)
717			openMode = openMode & ~O_RWMASK | O_RDONLY;
718	}
719	// prepare the request
720	OpenRequest request;
721	request.volumeID = fID;
722	request.nodeID = node->GetRemoteID();
723	request.openMode = openMode;
724	// send the request
725	OpenReply* reply;
726	status_t error = SendRequest(fConnection, &request, &reply);
727	if (error != B_OK)
728		RETURN_ERROR(error);
729	ObjectDeleter<Request> replyDeleter(reply);
730	if (reply->error != B_OK)
731		RETURN_ERROR(reply->error);
732	// update the node
733	_UpdateNode(reply->nodeInfo);
734	*cookie = (void*)reply->cookie;
735	return B_OK;
736}
737
738// Close
739status_t
740ShareVolume::Close(Node* _node, void* cookie)
741{
742	// no-op: FreeCookie does the job
743	return B_OK;
744}
745
746// FreeCookie
747status_t
748ShareVolume::FreeCookie(Node* _node, void* cookie)
749{
750	return _Close((int32)cookie);
751}
752
753// Read
754status_t
755ShareVolume::Read(Node* _node, void* cookie, off_t pos, void* _buffer,
756	size_t bufferSize, size_t* _bytesRead)
757{
758	if (!_EnsureShareMounted())
759		return ERROR_NOT_CONNECTED;
760
761	*_bytesRead = 0;
762	if (bufferSize == 0)
763		return B_OK;
764	uint8* buffer = (uint8*)_buffer;
765	// prepare the request
766	ReadRequest request;
767	request.volumeID = fID;
768	request.cookie = (int32)cookie;
769	request.pos = pos;
770	request.size = bufferSize;
771
772	struct ReadRequestHandler : public RequestHandler {
773		uint8*	buffer;
774		off_t	pos;
775		int32	bufferSize;
776		int32	bytesRead;
777
778		ReadRequestHandler(uint8* buffer, off_t pos, int32 bufferSize)
779			: buffer(buffer),
780			  pos(pos),
781			  bufferSize(bufferSize),
782			  bytesRead(0)
783		{
784		}
785
786		virtual status_t HandleRequest(Request* _reply, RequestChannel* channel)
787		{
788			// the passed request is deleted by the request port
789			ReadReply* reply = dynamic_cast<ReadReply*>(_reply);
790			if (!reply)
791				RETURN_ERROR(B_BAD_DATA);
792			// process the reply
793			status_t error = ProcessReply(reply);
794			if (error != B_OK)
795				return error;
796			bool moreToCome = reply->moreToCome;
797			while (moreToCome) {
798				// receive a reply
799				error = ReceiveRequest(channel, &reply);
800				if (error != B_OK)
801					RETURN_ERROR(error);
802				moreToCome = reply->moreToCome;
803				ObjectDeleter<Request> replyDeleter(reply);
804				// process the reply
805				error = ProcessReply(reply);
806				if (error != B_OK)
807					return error;
808			}
809			return B_OK;
810		}
811
812		status_t ProcessReply(ReadReply* reply)
813		{
814			if (reply->error != B_OK)
815				RETURN_ERROR(reply->error);
816			// check the fields
817			if (reply->pos != pos)
818				RETURN_ERROR(B_BAD_DATA);
819			int32 bytesRead = reply->data.GetSize();
820			if (bytesRead > (int32)bufferSize)
821				RETURN_ERROR(B_BAD_DATA);
822			// copy the data into the buffer
823			if (bytesRead > 0)
824				memcpy(buffer, reply->data.GetData(), bytesRead);
825			pos += bytesRead;
826			buffer += bytesRead;
827			bufferSize -= bytesRead;
828			this->bytesRead += bytesRead;
829			return B_OK;
830		}
831	} requestHandler(buffer, pos, bufferSize);
832
833	// send the request
834	status_t error = fConnection->SendRequest(&request, &requestHandler);
835	if (error != B_OK)
836		RETURN_ERROR(error);
837	*_bytesRead = requestHandler.bytesRead;
838	return B_OK;
839}
840
841// Write
842status_t
843ShareVolume::Write(Node* _node, void* cookie, off_t pos, const void* _buffer,
844	size_t bufferSize, size_t* bytesWritten)
845{
846	if (!_EnsureShareMounted())
847		return ERROR_NOT_CONNECTED;
848
849	// check permissions
850	if (IsReadOnly())
851		return B_PERMISSION_DENIED;
852
853	*bytesWritten = 0;
854	off_t bytesLeft = bufferSize;
855	const char* buffer = (const char*)_buffer;
856	while (bytesLeft > 0) {
857		off_t toWrite = bytesLeft;
858		if (toWrite > kMaxWriteBufferSize)
859			toWrite = kMaxWriteBufferSize;
860
861		// prepare the request
862		WriteRequest request;
863		request.volumeID = fID;
864		request.cookie = (int32)cookie;
865		request.pos = pos;
866		request.data.SetTo(buffer, toWrite);
867
868		// send the request
869		WriteReply* reply;
870		status_t error = SendRequest(fConnection, &request, &reply);
871		if (error != B_OK)
872			RETURN_ERROR(error);
873		ObjectDeleter<Request> replyDeleter(reply);
874		if (reply->error != B_OK)
875			RETURN_ERROR(reply->error);
876
877		bytesLeft -= toWrite;
878		pos += toWrite;
879		buffer += toWrite;
880
881// TODO: We should probably add an "up to date" flag for ShareNode (just as
882// done for ShareAttrDir) and clear it at this point. Currently continuity
883// inconsistencies could occur (e.g. a stat() after a write() returns
884// obsolete data), depending on when the node monitoring update arrives.
885	}
886
887	*bytesWritten = bufferSize;
888	return B_OK;
889}
890
891
892// #pragma mark -
893// #pragma mark ----- hard links / symlinks -----
894
895// Link
896status_t
897ShareVolume::Link(Node* _dir, const char* name, Node* _node)
898{
899	ShareNode* dir = dynamic_cast<ShareNode*>(_dir);
900	ShareNode* node = dynamic_cast<ShareNode*>(_node);
901
902	if (!node || node->GetVolume() != this)
903		return B_NOT_ALLOWED;
904
905	if (!_EnsureShareMounted())
906		return ERROR_NOT_CONNECTED;
907
908	// check permissions
909	if (IsReadOnly())
910		return B_PERMISSION_DENIED;
911	if (IsVNodeRemoved(dir->GetID()) > 0)
912		RETURN_ERROR(B_NOT_ALLOWED);
913	if (IsVNodeRemoved(node->GetID()) > 0)
914		RETURN_ERROR(B_NOT_ALLOWED);
915	// prepare the request
916	CreateLinkRequest request;
917	request.volumeID = fID;
918	request.directoryID = dir->GetRemoteID();
919	request.name.SetTo(name);
920	request.nodeID = node->GetRemoteID();
921	// send the request
922	CreateLinkReply* reply;
923	status_t error = SendRequest(fConnection, &request, &reply);
924	if (error != B_OK)
925		RETURN_ERROR(error);
926	ObjectDeleter<Request> replyDeleter(reply);
927	RETURN_ERROR(reply->error);
928}
929
930// Unlink
931status_t
932ShareVolume::Unlink(Node* _dir, const char* name)
933{
934	ShareNode* dir = dynamic_cast<ShareNode*>(_dir);
935
936	if (!_EnsureShareMounted())
937		return ERROR_NOT_CONNECTED;
938
939	// check permissions
940	if (IsReadOnly())
941		return B_PERMISSION_DENIED;
942	// prepare the request
943	UnlinkRequest request;
944	request.volumeID = fID;
945	request.directoryID = dir->GetRemoteID();
946	request.name.SetTo(name);
947	// send the request
948	UnlinkReply* reply;
949	status_t error = SendRequest(fConnection, &request, &reply);
950	if (error != B_OK)
951		RETURN_ERROR(error);
952	ObjectDeleter<Request> replyDeleter(reply);
953	RETURN_ERROR(reply->error);
954}
955
956// Symlink
957status_t
958ShareVolume::Symlink(Node* _dir, const char* name, const char* target)
959{
960	ShareNode* dir = dynamic_cast<ShareNode*>(_dir);
961
962	if (!_EnsureShareMounted())
963		return ERROR_NOT_CONNECTED;
964
965	// check permissions
966	if (IsReadOnly())
967		return B_PERMISSION_DENIED;
968	if (IsVNodeRemoved(dir->GetID()) > 0)
969		RETURN_ERROR(B_NOT_ALLOWED);
970	// prepare the request
971	CreateSymlinkRequest request;
972	request.volumeID = fID;
973	request.directoryID = dir->GetRemoteID();
974	request.name.SetTo(name);
975	request.target.SetTo(target);
976	// send the request
977	CreateSymlinkReply* reply;
978	status_t error = SendRequest(fConnection, &request, &reply);
979	if (error != B_OK)
980		RETURN_ERROR(error);
981	ObjectDeleter<Request> replyDeleter(reply);
982	RETURN_ERROR(reply->error);
983}
984
985// ReadLink
986status_t
987ShareVolume::ReadLink(Node* _node, char* buffer, size_t bufferSize,
988	size_t* bytesRead)
989{
990	ShareNode* node = dynamic_cast<ShareNode*>(_node);
991
992	if (!_EnsureShareMounted())
993		return ERROR_NOT_CONNECTED;
994
995	*bytesRead = 0;
996	// prepare the request
997	ReadLinkRequest request;
998	request.volumeID = fID;
999	request.nodeID = node->GetRemoteID();
1000	request.maxSize = bufferSize;
1001	// send the request
1002	ReadLinkReply* reply;
1003	status_t error = SendRequest(fConnection, &request, &reply);
1004	if (error != B_OK)
1005		RETURN_ERROR(error);
1006	ObjectDeleter<Request> replyDeleter(reply);
1007	if (reply->error != B_OK)
1008		RETURN_ERROR(reply->error);
1009	if (reply->data.GetSize() > (int32)bufferSize)
1010		RETURN_ERROR(B_BAD_DATA);
1011	*bytesRead = reply->data.GetSize();
1012	if (*bytesRead > 0)
1013		memcpy(buffer, reply->data.GetData(), *bytesRead);
1014	_UpdateNode(reply->nodeInfo);
1015	return B_OK;
1016}
1017
1018// Rename
1019status_t
1020ShareVolume::Rename(Node* _oldDir, const char* oldName, Node* _newDir,
1021	const char* newName)
1022{
1023	ShareNode* oldDir = dynamic_cast<ShareNode*>(_oldDir);
1024	ShareNode* newDir = dynamic_cast<ShareNode*>(_newDir);
1025
1026	if (!newDir || newDir->GetVolume() != this)
1027		return B_NOT_ALLOWED;
1028
1029	if (!_EnsureShareMounted())
1030		return ERROR_NOT_CONNECTED;
1031
1032	// check permissions
1033	if (IsReadOnly())
1034		return B_PERMISSION_DENIED;
1035	if (IsVNodeRemoved(newDir->GetID()) > 0)
1036		RETURN_ERROR(B_NOT_ALLOWED);
1037	// prepare the request
1038	RenameRequest request;
1039	request.volumeID = fID;
1040	request.oldDirectoryID = oldDir->GetRemoteID();
1041	request.oldName.SetTo(oldName);
1042	request.newDirectoryID = newDir->GetRemoteID();
1043	request.newName.SetTo(newName);
1044	// send the request
1045	RenameReply* reply;
1046	status_t error = SendRequest(fConnection, &request, &reply);
1047	if (error != B_OK)
1048		RETURN_ERROR(error);
1049	ObjectDeleter<Request> replyDeleter(reply);
1050	RETURN_ERROR(reply->error);
1051}
1052
1053
1054// #pragma mark -
1055// #pragma mark ----- directories -----
1056
1057// MkDir
1058status_t
1059ShareVolume::MkDir(Node* _dir, const char* name, int mode)
1060{
1061	ShareNode* dir = dynamic_cast<ShareNode*>(_dir);
1062
1063	if (!_EnsureShareMounted())
1064		return ERROR_NOT_CONNECTED;
1065
1066	// check permissions
1067	if (IsReadOnly())
1068		return B_PERMISSION_DENIED;
1069	if (IsVNodeRemoved(dir->GetID()) > 0)
1070		RETURN_ERROR(B_NOT_ALLOWED);
1071	// prepare the request
1072	MakeDirRequest request;
1073	request.volumeID = fID;
1074	request.directoryID = dir->GetRemoteID();
1075	request.name.SetTo(name);
1076	request.mode = mode;
1077	// send the request
1078	MakeDirReply* reply;
1079	status_t error = SendRequest(fConnection, &request, &reply);
1080	if (error != B_OK)
1081		RETURN_ERROR(error);
1082	ObjectDeleter<Request> replyDeleter(reply);
1083	RETURN_ERROR(reply->error);
1084}
1085
1086// RmDir
1087status_t
1088ShareVolume::RmDir(Node* _dir, const char* name)
1089{
1090	ShareNode* dir = dynamic_cast<ShareNode*>(_dir);
1091
1092	if (!_EnsureShareMounted())
1093		return ERROR_NOT_CONNECTED;
1094
1095	// check permissions
1096	if (IsReadOnly())
1097		return B_PERMISSION_DENIED;
1098	// prepare the request
1099	RemoveDirRequest request;
1100	request.volumeID = fID;
1101	request.directoryID = dir->GetRemoteID();
1102	request.name.SetTo(name);
1103	// send the request
1104	RemoveDirReply* reply;
1105	status_t error = SendRequest(fConnection, &request, &reply);
1106	if (error != B_OK)
1107		RETURN_ERROR(error);
1108	ObjectDeleter<Request> replyDeleter(reply);
1109	RETURN_ERROR(reply->error);
1110}
1111
1112// OpenDir
1113status_t
1114ShareVolume::OpenDir(Node* _node, void** _cookie)
1115{
1116	// we opendir() only directories
1117	ShareDir* node = dynamic_cast<ShareDir*>(_node);
1118	if (!node)
1119		return B_NOT_ALLOWED;
1120
1121// TODO: Allow opening the root node?
1122	if (!_EnsureShareMounted())
1123		return ERROR_NOT_CONNECTED;
1124
1125	// allocate a dir cookie
1126	DirCookie* cookie = new(nothrow) DirCookie;
1127	if (!cookie)
1128		RETURN_ERROR(B_NO_MEMORY);
1129	ObjectDeleter<DirCookie> cookieDeleter(cookie);
1130
1131	// if the directory is fully cached, we allocate a local iterator
1132	{
1133		AutoLocker<Locker> locker(fLock);
1134		if (node->IsComplete()) {
1135			// create a local dir iterator
1136			LocalShareDirIterator* iterator
1137				= new(nothrow) LocalShareDirIterator();
1138			if (!iterator)
1139				RETURN_ERROR(B_NO_MEMORY);
1140			iterator->SetDirectory(node);
1141
1142			// init the cookie
1143			cookie->iterator = iterator;
1144			*_cookie = cookie;
1145			cookieDeleter.Detach();
1146			return B_OK;
1147		}
1148	}
1149
1150	// allocate a remote dir iterator
1151	RemoteShareDirIterator* iterator = new(nothrow) RemoteShareDirIterator;
1152	if (!iterator)
1153		RETURN_ERROR(B_NO_MEMORY);
1154	ObjectDeleter<RemoteShareDirIterator> iteratorDeleter(iterator);
1155
1156	// prepare the request
1157	OpenDirRequest request;
1158	request.volumeID = fID;
1159	request.nodeID = node->GetRemoteID();
1160
1161	// send the request
1162	OpenDirReply* reply;
1163	status_t error = SendRequest(fConnection, &request, &reply);
1164	if (error != B_OK)
1165		RETURN_ERROR(error);
1166	ObjectDeleter<Request> replyDeleter(reply);
1167	if (reply->error != B_OK)
1168{
1169PRINT(("OpenDir() failed: node: %lld, remote: (%ld, %lld)\n",
1170node->GetID(), node->GetRemoteID().volumeID, node->GetRemoteID().nodeID));
1171		RETURN_ERROR(reply->error);
1172}
1173
1174	// update the node
1175	_UpdateNode(reply->nodeInfo);
1176
1177	// init the cookie
1178	iterator->SetCookie(reply->cookie);
1179	cookie->iterator = iterator;
1180
1181	*_cookie = cookie;
1182	cookieDeleter.Detach();
1183	iteratorDeleter.Detach();
1184	return B_OK;
1185}
1186
1187// CloseDir
1188status_t
1189ShareVolume::CloseDir(Node* _node, void* cookie)
1190{
1191	// no-op: FreeDirCookie does the job
1192	return B_OK;
1193}
1194
1195// FreeDirCookie
1196status_t
1197ShareVolume::FreeDirCookie(Node* _node, void* _cookie)
1198{
1199	DirCookie* cookie = (DirCookie*)_cookie;
1200	ObjectDeleter<DirCookie> _(cookie);
1201	ShareDirIterator* iterator = cookie->iterator;
1202
1203	status_t error = B_OK;
1204	if (RemoteShareDirIterator* remoteIterator
1205		= dynamic_cast<RemoteShareDirIterator*>(iterator)) {
1206		// prepare the request
1207		CloseRequest request;
1208		request.volumeID = fID;
1209		request.cookie = remoteIterator->GetCookie();
1210
1211		// send the request
1212		if (!_EnsureShareMounted())
1213			error = ERROR_NOT_CONNECTED;
1214
1215		if (error == B_OK) {
1216			CloseReply* reply;
1217			error = SendRequest(fConnection, &request, &reply);
1218			if (error == B_OK) {
1219				error = reply->error;
1220				delete reply;
1221			}
1222		}
1223	}
1224
1225	// delete the iterator
1226	AutoLocker<Locker> locker(fLock);
1227	delete iterator;
1228
1229	return error;
1230}
1231
1232// ReadDir
1233status_t
1234ShareVolume::ReadDir(Node* _dir, void* _cookie, struct dirent* buffer,
1235	size_t bufferSize, int32 count, int32* countRead)
1236{
1237	ShareDir* directory = dynamic_cast<ShareDir*>(_dir);
1238
1239	if (!_EnsureShareMounted())
1240		return ERROR_NOT_CONNECTED;
1241
1242	*countRead = 0;
1243	if (count <= 0)
1244		return B_OK;
1245
1246	DirCookie* cookie = (DirCookie*)_cookie;
1247	ShareDirIterator* iterator = cookie->iterator;
1248
1249	while (true) {
1250		status_t error;
1251		AutoLocker<Locker> locker(fLock);
1252		while (ShareDirEntry* entry = iterator->GetCurrentEntry()) {
1253			// re-get the entry -- it might already have been removed
1254			const char* name = entry->GetName();
1255			entry = _GetEntryByLocalID(directory->GetID(), name);
1256			if (entry) {
1257				// set the name: this also checks the size of the buffer
1258				error = set_dirent_name(buffer, bufferSize, name,
1259					strlen(name));
1260				if (error != B_OK) {
1261					// if something has been read at all, we're content
1262					if (*countRead > 0)
1263						return B_OK;
1264					RETURN_ERROR(error);
1265				}
1266
1267				// fill in the other fields
1268				buffer->d_pdev = fVolumeManager->GetID();
1269				buffer->d_pino = directory->GetID();
1270				buffer->d_dev = fVolumeManager->GetID();
1271				buffer->d_ino = entry->GetNode()->GetID();
1272
1273				// if the entry is the parent of the share root, we need to
1274				// fix the node ID
1275				if (directory == fRootNode && strcmp(name, "..") == 0) {
1276					if (Volume* parentVolume = GetParentVolume())
1277						buffer->d_ino = parentVolume->GetRootID();
1278				}
1279
1280				iterator->NextEntry();
1281				(*countRead)++;
1282				if (*countRead >= count || !next_dirent(buffer, bufferSize))
1283					return B_OK;
1284			} else
1285				iterator->NextEntry();
1286		}
1287
1288		// no more entries: check, if we're completely through
1289		if (iterator->IsDone())
1290			return B_OK;
1291
1292		// we need to actually get entries from the server
1293		locker.Unlock();
1294		if (RemoteShareDirIterator* remoteIterator
1295				= dynamic_cast<RemoteShareDirIterator*>(iterator)) {
1296			error = _ReadRemoteDir(directory, remoteIterator);
1297			if (error != B_OK)
1298				return error;
1299		}
1300	}
1301}
1302
1303// RewindDir
1304status_t
1305ShareVolume::RewindDir(Node* _node, void* _cookie)
1306{
1307	DirCookie* cookie = (DirCookie*)_cookie;
1308	ShareDirIterator* iterator = cookie->iterator;
1309	AutoLocker<Locker> _(fLock);
1310	iterator->Rewind();
1311	return B_OK;
1312}
1313
1314// Walk
1315status_t
1316ShareVolume::Walk(Node* _dir, const char* entryName, char** resolvedPath,
1317	vnode_id* vnid)
1318{
1319	ShareDir* dir = dynamic_cast<ShareDir*>(_dir);
1320	if (!dir)
1321		return B_BAD_VALUE;
1322
1323	// we always resolve "." and ".." of the root node
1324	if (dir == fRootNode) {
1325		if (strcmp(entryName, ".") == 0 || strcmp(entryName, "..") == 0) {
1326			AutoLocker<Locker> _(fLock);
1327			if (strcmp(entryName, ".") == 0) {
1328				*vnid = fRootNode->GetID();
1329			} else if (Volume* parentVolume = GetParentVolume()) {
1330				*vnid = parentVolume->GetRootID();
1331			} else
1332				*vnid = fRootNode->GetID();
1333			Node* node;
1334			return GetVNode(*vnid, &node);
1335		}
1336	}
1337
1338	if (!_EnsureShareMounted())
1339		return ERROR_NOT_CONNECTED;
1340
1341	// check, if the entry is already known
1342	{
1343		AutoLocker<Locker> _(fLock);
1344		ShareDirEntry* entry = _GetEntryByLocalID(dir->GetID(), entryName);
1345		if (entry) {
1346			*vnid = entry->GetNode()->GetID();
1347			Node* node;
1348			return GetVNode(*vnid, &node);
1349		} else if (dir->IsComplete())
1350			return B_ENTRY_NOT_FOUND;
1351	}
1352
1353	WalkReply* reply;
1354	while (true) {
1355		// send the request
1356		status_t error = _Walk(dir->GetRemoteID(), entryName, resolvedPath,
1357			&reply);
1358		if (error != B_OK)
1359			RETURN_ERROR(error);
1360		ObjectDeleter<Request> replyDeleter(reply);
1361
1362		AutoLocker<Locker> locker(fLock);
1363
1364		// check, if the returned info is obsolete
1365		if (_IsObsoleteEntryInfo(reply->entryInfo))
1366			continue;
1367
1368		// load the entry
1369		ShareDirEntry* entry;
1370		error = _LoadEntry(dir, reply->entryInfo, &entry);
1371		if (error != B_OK)
1372			RETURN_ERROR(error);
1373		*vnid = entry->GetNode()->GetID();
1374
1375		// deal with symlinks
1376		if (reply->linkPath.GetString() && resolvedPath) {
1377			*resolvedPath = strdup(reply->linkPath.GetString());
1378			if (!*resolvedPath)
1379				RETURN_ERROR(B_NO_MEMORY);
1380			return B_OK;
1381		}
1382
1383		break;
1384	}
1385
1386	// no symlink or we shall not resolve it: get the node
1387	Node* _node;
1388	RETURN_ERROR(GetVNode(*vnid, &_node));
1389}
1390
1391
1392// #pragma mark -
1393// #pragma mark ----- attributes -----
1394
1395// OpenAttrDir
1396status_t
1397ShareVolume::OpenAttrDir(Node* _node, void** _cookie)
1398{
1399	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1400
1401// TODO: Allow opening the root node?
1402	if (!_EnsureShareMounted())
1403		return ERROR_NOT_CONNECTED;
1404
1405	// allocate a dir cookie
1406	AttrDirCookie* cookie = new(nothrow) AttrDirCookie;
1407	if (!cookie)
1408		RETURN_ERROR(B_NO_MEMORY);
1409	ObjectDeleter<AttrDirCookie> cookieDeleter(cookie);
1410
1411	AutoLocker<Locker> locker(fLock);
1412
1413	if (!node->GetAttrDir() || !node->GetAttrDir()->IsUpToDate()) {
1414		// prepare the request
1415		OpenAttrDirRequest request;
1416		request.volumeID = fID;
1417		request.nodeID = node->GetRemoteID();
1418
1419		locker.Unlock();
1420
1421		// send the request
1422		OpenAttrDirReply* reply;
1423		status_t error = SendRequest(fConnection, &request, &reply);
1424		if (error != B_OK)
1425			RETURN_ERROR(error);
1426		ObjectDeleter<Request> replyDeleter(reply);
1427		if (reply->error != B_OK)
1428			RETURN_ERROR(reply->error);
1429
1430		// If no AttrDirInfo was supplied, we just save the cookie and be done.
1431		// This usually happens when the attr dir is too big to be cached.
1432		if (!reply->attrDirInfo.isValid) {
1433			cookie->cookie = reply->cookie;
1434			cookie->rewind = false;
1435			*_cookie = cookie;
1436			cookieDeleter.Detach();
1437			return B_OK;
1438		}
1439
1440		locker.SetTo(fLock, false);
1441
1442		// a AttrDirInfo has been supplied: load the attr dir
1443		error = _LoadAttrDir(node, reply->attrDirInfo);
1444		if (error != B_OK)
1445			return error;
1446	}
1447
1448	// we have a valid attr dir: create an attr dir iterator
1449	ShareAttrDirIterator* iterator = new(nothrow) ShareAttrDirIterator;
1450	if (!iterator)
1451		return B_NO_MEMORY;
1452	iterator->SetAttrDir(node->GetAttrDir());
1453
1454	// add the iterator
1455	status_t error = _AddAttrDirIterator(node, iterator);
1456	if (error != B_OK) {
1457		delete iterator;
1458		return error;
1459	}
1460
1461	cookie->iterator = iterator;
1462	*_cookie = cookie;
1463	cookieDeleter.Detach();
1464	return B_OK;
1465}
1466
1467// CloseAttrDir
1468status_t
1469ShareVolume::CloseAttrDir(Node* _node, void* cookie)
1470{
1471	// no-op: FreeAttrDirCookie does the job
1472	return B_OK;
1473}
1474
1475// FreeAttrDirCookie
1476status_t
1477ShareVolume::FreeAttrDirCookie(Node* _node, void* _cookie)
1478{
1479	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1480	AttrDirCookie* cookie = (AttrDirCookie*)_cookie;
1481	ObjectDeleter<AttrDirCookie> _(cookie);
1482
1483	// if this is a local iterator, we just delete it and be done
1484	if (cookie->iterator) {
1485		AutoLocker<Locker> locker(fLock);
1486
1487		// remove and delete the iterator
1488		_RemoveAttrDirIterator(node, cookie->iterator);
1489		delete cookie->iterator;
1490
1491		return B_OK;
1492	}
1493
1494	// prepare the request
1495	CloseRequest request;
1496	request.volumeID = fID;
1497	request.cookie = cookie->cookie;
1498
1499	// send the request
1500	if (!_EnsureShareMounted())
1501		return ERROR_NOT_CONNECTED;
1502	CloseReply* reply;
1503	status_t error = SendRequest(fConnection, &request, &reply);
1504	if (error != B_OK)
1505		RETURN_ERROR(error);
1506	ObjectDeleter<Request> replyDeleter(reply);
1507	if (reply->error != B_OK)
1508		RETURN_ERROR(reply->error);
1509
1510	return B_OK;
1511}
1512
1513// ReadAttrDir
1514status_t
1515ShareVolume::ReadAttrDir(Node* _node, void* _cookie, struct dirent* buffer,
1516	size_t bufferSize, int32 count, int32* countRead)
1517{
1518	if (!_EnsureShareMounted())
1519		return ERROR_NOT_CONNECTED;
1520
1521	*countRead = 0;
1522	AttrDirCookie* cookie = (AttrDirCookie*)_cookie;
1523
1524	// if we have a local iterator, things are easy
1525	if (ShareAttrDirIterator* iterator = cookie->iterator) {
1526		AutoLocker<Locker> locker(fLock);
1527
1528		// get the current attribute
1529		Attribute* attribute = iterator->GetCurrentAttribute();
1530		if (!attribute)
1531			return B_OK;
1532
1533		// set the name: this also checks the size of the buffer
1534		const char* name = attribute->GetName();
1535		status_t error = set_dirent_name(buffer, bufferSize, name,
1536			strlen(name));
1537		if (error != B_OK)
1538			RETURN_ERROR(error);
1539
1540		// fill in the other fields
1541		buffer->d_dev = fVolumeManager->GetID();
1542		buffer->d_ino = -1;
1543		*countRead = 1;
1544
1545		iterator->NextAttribute();
1546		return B_OK;
1547	}
1548
1549	// prepare the request
1550	ReadAttrDirRequest request;
1551	request.volumeID = fID;
1552	request.cookie = cookie->cookie;
1553	request.count = 1;
1554	request.rewind = cookie->rewind;
1555
1556	// send the request
1557	ReadAttrDirReply* reply;
1558	status_t error = SendRequest(fConnection, &request, &reply);
1559	if (error != B_OK)
1560		RETURN_ERROR(error);
1561	ObjectDeleter<Request> replyDeleter(reply);
1562	if (reply->error != B_OK)
1563		RETURN_ERROR(reply->error);
1564	cookie->rewind = false;
1565
1566	// check, if anything has been read at all
1567	if (reply->count == 0) {
1568		*countRead = 0;
1569		return B_OK;
1570	}
1571	const char* name = reply->name.GetString();
1572	int32 nameLen = reply->name.GetSize();
1573	if (!name || nameLen < 2)
1574		return B_BAD_DATA;
1575
1576	// set the name: this also checks the size of the buffer
1577	error = set_dirent_name(buffer, bufferSize, name, nameLen - 1);
1578	if (error != B_OK)
1579		RETURN_ERROR(error);
1580
1581	// fill in the other fields
1582	buffer->d_dev = fVolumeManager->GetID();
1583	buffer->d_ino = -1;
1584	*countRead = 1;
1585	return B_OK;
1586}
1587
1588// RewindAttrDir
1589status_t
1590ShareVolume::RewindAttrDir(Node* _node, void* _cookie)
1591{
1592	AttrDirCookie* cookie = (AttrDirCookie*)_cookie;
1593
1594	// if we have a local iterator, rewind it
1595	if (ShareAttrDirIterator* iterator = cookie->iterator) {
1596		AutoLocker<Locker> locker(fLock);
1597
1598		iterator->Rewind();
1599	} else
1600		cookie->rewind = true;
1601
1602	return B_OK;
1603}
1604
1605// ReadAttr
1606status_t
1607ShareVolume::ReadAttr(Node* _node, const char* name, int type, off_t pos,
1608	void* _buffer, size_t bufferSize, size_t* _bytesRead)
1609{
1610	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1611
1612	if (!_EnsureShareMounted())
1613		return ERROR_NOT_CONNECTED;
1614
1615	*_bytesRead = 0;
1616	if (bufferSize == 0)
1617		return B_OK;
1618	uint8* buffer = (uint8*)_buffer;
1619
1620	// if we have the attribute directory cached, we can first check, if the
1621	// attribute exists at all -- maybe its data are cached, too
1622	{
1623		AutoLocker<Locker> locker(fLock);
1624
1625		ShareAttrDir* attrDir = node->GetAttrDir();
1626		if (attrDir && attrDir->IsUpToDate()) {
1627			// get the attribute
1628			Attribute* attribute = attrDir->GetAttribute(name);
1629			if (!attribute)
1630				return B_ENTRY_NOT_FOUND;
1631
1632			// get the data
1633			if (const void* data = attribute->GetData()) {
1634				// first check, if we can read anything at all
1635				if (pos < 0)
1636					pos = 0;
1637				int32 size = attribute->GetSize();
1638				if (pos >= size)
1639					return B_OK;
1640
1641				// get the data
1642				bufferSize = min(bufferSize, size_t(size - pos));
1643				memcpy(buffer, data, bufferSize);
1644				*_bytesRead = bufferSize;
1645				return B_OK;
1646			}
1647		}
1648	}
1649
1650	// prepare the request
1651	ReadAttrRequest request;
1652	request.volumeID = fID;
1653	request.nodeID = node->GetRemoteID();
1654	request.name.SetTo(name);
1655	request.type = type;
1656	request.pos = pos;
1657	request.size = bufferSize;
1658
1659	struct ReadRequestHandler : public RequestHandler {
1660		uint8*	buffer;
1661		off_t	pos;
1662		int32	bufferSize;
1663		int32	bytesRead;
1664
1665		ReadRequestHandler(uint8* buffer, off_t pos, int32 bufferSize)
1666			: buffer(buffer),
1667			  pos(pos),
1668			  bufferSize(bufferSize),
1669			  bytesRead(0)
1670		{
1671		}
1672
1673		virtual status_t HandleRequest(Request* _reply, RequestChannel* channel)
1674		{
1675			// the passed request is deleted by the request port
1676			ReadAttrReply* reply = dynamic_cast<ReadAttrReply*>(_reply);
1677			if (!reply)
1678				RETURN_ERROR(B_BAD_DATA);
1679			// process the reply
1680			status_t error = ProcessReply(reply);
1681			if (error != B_OK)
1682				return error;
1683			bool moreToCome = reply->moreToCome;
1684			while (moreToCome) {
1685				// receive a reply
1686				error = ReceiveRequest(channel, &reply);
1687				if (error != B_OK)
1688					RETURN_ERROR(error);
1689				moreToCome = reply->moreToCome;
1690				ObjectDeleter<Request> replyDeleter(reply);
1691				// process the reply
1692				error = ProcessReply(reply);
1693				if (error != B_OK)
1694					return error;
1695			}
1696			return B_OK;
1697		}
1698
1699		status_t ProcessReply(ReadAttrReply* reply)
1700		{
1701			if (reply->error != B_OK)
1702				RETURN_ERROR(reply->error);
1703			// check the fields
1704			if (reply->pos != pos)
1705				RETURN_ERROR(B_BAD_DATA);
1706			int32 bytesRead = reply->data.GetSize();
1707			if (bytesRead > (int32)bufferSize)
1708				RETURN_ERROR(B_BAD_DATA);
1709			// copy the data into the buffer
1710			if (bytesRead > 0)
1711				memcpy(buffer, reply->data.GetData(), bytesRead);
1712			pos += bytesRead;
1713			buffer += bytesRead;
1714			bufferSize -= bytesRead;
1715			this->bytesRead += bytesRead;
1716			return B_OK;
1717		}
1718	} requestHandler(buffer, pos, bufferSize);
1719
1720	// send the request
1721	status_t error = fConnection->SendRequest(&request, &requestHandler);
1722	if (error != B_OK)
1723		RETURN_ERROR(error);
1724	*_bytesRead = requestHandler.bytesRead;
1725	return B_OK;
1726}
1727
1728// WriteAttr
1729status_t
1730ShareVolume::WriteAttr(Node* _node, const char* name, int type, off_t pos,
1731	const void* _buffer, size_t bufferSize, size_t* bytesWritten)
1732{
1733	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1734
1735	if (!_EnsureShareMounted())
1736		return ERROR_NOT_CONNECTED;
1737
1738	// check permissions
1739	if (IsReadOnly())
1740		return B_PERMISSION_DENIED;
1741
1742	*bytesWritten = 0;
1743	off_t bytesLeft = bufferSize;
1744	const char* buffer = (const char*)_buffer;
1745	while (bytesLeft > 0) {
1746		// store the current attibute dir revision for reference below
1747		int64 attrDirRevision = -1;
1748		{
1749			AutoLocker<Locker> _(fLock);
1750			if (ShareAttrDir* attrDir = node->GetAttrDir()) {
1751				if (attrDir->IsUpToDate())
1752					attrDirRevision = attrDir->GetRevision();
1753			}
1754		}
1755
1756		off_t toWrite = bytesLeft;
1757		if (toWrite > kMaxWriteBufferSize)
1758			toWrite = kMaxWriteBufferSize;
1759
1760		// prepare the request
1761		WriteAttrRequest request;
1762		request.volumeID = fID;
1763		request.nodeID = node->GetRemoteID();
1764		request.name.SetTo(name);
1765		request.type = type;
1766		request.pos = pos;
1767		request.data.SetTo(buffer, toWrite);
1768
1769		// send the request
1770		WriteAttrReply* reply;
1771		status_t error = SendRequest(fConnection, &request, &reply);
1772		if (error != B_OK)
1773			RETURN_ERROR(error);
1774
1775		ObjectDeleter<Request> replyDeleter(reply);
1776		if (reply->error != B_OK)
1777			RETURN_ERROR(reply->error);
1778
1779		bytesLeft -= toWrite;
1780		pos += toWrite;
1781		buffer += toWrite;
1782
1783		// If the request was successful, we consider the cached attr dir
1784		// no longer up to date.
1785		if (attrDirRevision >= 0) {
1786			AutoLocker<Locker> _(fLock);
1787			ShareAttrDir* attrDir = node->GetAttrDir();
1788			if (attrDir && attrDir->GetRevision() == attrDirRevision)
1789				attrDir->SetUpToDate(false);
1790		}
1791	}
1792
1793	*bytesWritten = bufferSize;
1794	return B_OK;
1795}
1796
1797// RemoveAttr
1798status_t
1799ShareVolume::RemoveAttr(Node* _node, const char* name)
1800{
1801	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1802
1803	if (!_EnsureShareMounted())
1804		return ERROR_NOT_CONNECTED;
1805
1806	// check permissions
1807	if (IsReadOnly())
1808		return B_PERMISSION_DENIED;
1809
1810	// store the current attibute dir revision for reference below
1811	int64 attrDirRevision = -1;
1812	{
1813		AutoLocker<Locker> _(fLock);
1814		if (ShareAttrDir* attrDir = node->GetAttrDir()) {
1815			if (attrDir->IsUpToDate())
1816				attrDirRevision = attrDir->GetRevision();
1817		}
1818	}
1819
1820	// prepare the request
1821	RemoveAttrRequest request;
1822	request.volumeID = fID;
1823	request.nodeID = node->GetRemoteID();
1824	request.name.SetTo(name);
1825
1826	// send the request
1827	RemoveAttrReply* reply;
1828	status_t error = SendRequest(fConnection, &request, &reply);
1829	if (error != B_OK)
1830		RETURN_ERROR(error);
1831	ObjectDeleter<Request> replyDeleter(reply);
1832
1833	// If the request was successful, we consider the cached attr dir
1834	// no longer up to date.
1835	if (reply->error == B_OK && attrDirRevision >= 0) {
1836		AutoLocker<Locker> _(fLock);
1837		ShareAttrDir* attrDir = node->GetAttrDir();
1838		if (attrDir && attrDir->GetRevision() == attrDirRevision)
1839			attrDir->SetUpToDate(false);
1840	}
1841
1842	RETURN_ERROR(reply->error);
1843}
1844
1845// RenameAttr
1846status_t
1847ShareVolume::RenameAttr(Node* _node, const char* oldName, const char* newName)
1848{
1849	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1850
1851	if (!_EnsureShareMounted())
1852		return ERROR_NOT_CONNECTED;
1853
1854	// check permissions
1855	if (IsReadOnly())
1856		return B_PERMISSION_DENIED;
1857
1858	// store the current attibute dir revision for reference below
1859	int64 attrDirRevision = -1;
1860	{
1861		AutoLocker<Locker> _(fLock);
1862		if (ShareAttrDir* attrDir = node->GetAttrDir()) {
1863			if (attrDir->IsUpToDate())
1864				attrDirRevision = attrDir->GetRevision();
1865		}
1866	}
1867
1868	// prepare the request
1869	RenameAttrRequest request;
1870	request.volumeID = fID;
1871	request.nodeID = node->GetRemoteID();
1872	request.oldName.SetTo(oldName);
1873	request.newName.SetTo(newName);
1874
1875	// send the request
1876	RenameAttrReply* reply;
1877	status_t error = SendRequest(fConnection, &request, &reply);
1878	if (error != B_OK)
1879		RETURN_ERROR(error);
1880	ObjectDeleter<Request> replyDeleter(reply);
1881
1882	// If the request was successful, we consider the cached attr dir
1883	// no longer up to date.
1884	if (reply->error == B_OK && attrDirRevision >= 0) {
1885		AutoLocker<Locker> _(fLock);
1886		ShareAttrDir* attrDir = node->GetAttrDir();
1887		if (attrDir && attrDir->GetRevision() == attrDirRevision)
1888			attrDir->SetUpToDate(false);
1889	}
1890
1891	RETURN_ERROR(reply->error);
1892}
1893
1894// StatAttr
1895status_t
1896ShareVolume::StatAttr(Node* _node, const char* name, struct attr_info* attrInfo)
1897{
1898	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1899
1900	if (!_EnsureShareMounted())
1901		return ERROR_NOT_CONNECTED;
1902
1903	// if we have the attribute directory cached, get the info from there
1904	{
1905		AutoLocker<Locker> locker(fLock);
1906
1907		ShareAttrDir* attrDir = node->GetAttrDir();
1908		if (attrDir && attrDir->IsUpToDate()) {
1909			// get the attribute
1910			Attribute* attribute = attrDir->GetAttribute(name);
1911			if (!attribute)
1912				return B_ENTRY_NOT_FOUND;
1913
1914			attribute->GetInfo(attrInfo);
1915			return B_OK;
1916		}
1917	}
1918
1919	// prepare the request
1920	StatAttrRequest request;
1921	request.volumeID = fID;
1922	request.nodeID = node->GetRemoteID();
1923	request.name.SetTo(name);
1924
1925	// send the request
1926	StatAttrReply* reply;
1927	status_t error = SendRequest(fConnection, &request, &reply);
1928	if (error != B_OK)
1929		RETURN_ERROR(error);
1930	ObjectDeleter<Request> replyDeleter(reply);
1931	if (reply->error != B_OK)
1932		RETURN_ERROR(reply->error);
1933
1934	// set the result
1935	*attrInfo = reply->attrInfo.info;
1936	return B_OK;
1937}
1938
1939
1940// #pragma mark -
1941// #pragma mark ----- queries -----
1942
1943// GetQueryEntry
1944status_t
1945ShareVolume::GetQueryEntry(const EntryInfo& entryInfo,
1946	const NodeInfo& dirInfo, struct dirent* buffer, size_t bufferSize,
1947	int32* countRead)
1948{
1949	status_t error = B_OK;
1950
1951	const char* name = entryInfo.name.GetString();
1952	int32 nameLen = entryInfo.name.GetSize();
1953	if (!name || nameLen < 2)
1954		RETURN_ERROR(B_BAD_DATA);
1955
1956	// load the directory
1957	vnode_id localDirID = -1;
1958	{
1959		AutoLocker<Locker> _(fLock);
1960		ShareNode* node;
1961		error = _LoadNode(dirInfo, &node);
1962		if (error != B_OK)
1963			RETURN_ERROR(error);
1964		ShareDir* directory = dynamic_cast<ShareDir*>(node);
1965		if (!directory)
1966			RETURN_ERROR(B_ENTRY_NOT_FOUND);
1967		localDirID = directory->GetID();
1968	}
1969
1970	// add/update the entry
1971	vnode_id localNodeID = -1;
1972	const EntryInfo* resolvedEntryInfo = &entryInfo;
1973	while (error == B_OK) {
1974		// get an up to date entry info
1975		WalkReply* walkReply = NULL;
1976		if (!resolvedEntryInfo) {
1977			error = _Walk(entryInfo.directoryID, name, false,
1978				&walkReply);
1979			if (error != B_OK)
1980				RETURN_ERROR(error);
1981
1982			resolvedEntryInfo = &walkReply->entryInfo;
1983		}
1984		ObjectDeleter<Request> walkReplyDeleter(walkReply);
1985
1986		AutoLocker<Locker> locker(fLock);
1987
1988		// check, if the info is obsolete
1989		if (_IsObsoleteEntryInfo(*resolvedEntryInfo)) {
1990			resolvedEntryInfo = NULL;
1991			continue;
1992		}
1993
1994		// get the directory
1995		ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByLocalID(localDirID));
1996		if (!dir)
1997			RETURN_ERROR(B_ERROR);
1998
1999		// load the entry
2000		ShareDirEntry* entry;
2001		error = _LoadEntry(dir, *resolvedEntryInfo, &entry);
2002		if (error == B_OK)
2003			localNodeID = entry->GetNode()->GetID();
2004
2005		break;
2006	}
2007
2008	// set the name: this also checks the size of the buffer
2009	error = set_dirent_name(buffer, bufferSize, name, nameLen - 1);
2010	if (error != B_OK)
2011		RETURN_ERROR(error);
2012
2013	// fill in the other fields
2014	buffer->d_pdev = fVolumeManager->GetID();
2015	buffer->d_pino = localDirID;
2016	buffer->d_dev = fVolumeManager->GetID();
2017	buffer->d_ino = localNodeID;
2018
2019	*countRead = 1;
2020PRINT(("  entry: d_dev: %ld, d_pdev: %ld, d_ino: %Ld, d_pino: %Ld, "
2021"d_reclen: %hu, d_name: `%s'\n",
2022buffer->d_dev, buffer->d_pdev, buffer->d_ino, buffer->d_pino,
2023buffer->d_reclen, buffer->d_name));
2024	return B_OK;
2025}
2026
2027
2028// #pragma mark -
2029
2030// ProcessNodeMonitoringRequest
2031void
2032ShareVolume::ProcessNodeMonitoringRequest(NodeMonitoringRequest* request)
2033{
2034	switch (request->opcode) {
2035		case B_ENTRY_CREATED:
2036			_HandleEntryCreatedRequest(
2037				dynamic_cast<EntryCreatedRequest*>(request));
2038			break;
2039		case B_ENTRY_REMOVED:
2040			_HandleEntryRemovedRequest(
2041				dynamic_cast<EntryRemovedRequest*>(request));
2042			break;
2043		case B_ENTRY_MOVED:
2044			_HandleEntryMovedRequest(
2045				dynamic_cast<EntryMovedRequest*>(request));
2046			break;
2047		case B_STAT_CHANGED:
2048			_HandleStatChangedRequest(
2049				dynamic_cast<StatChangedRequest*>(request));
2050			break;
2051		case B_ATTR_CHANGED:
2052			_HandleAttributeChangedRequest(
2053				dynamic_cast<AttributeChangedRequest*>(request));
2054			break;
2055	}
2056}
2057
2058// ConnectionClosed
2059void
2060ShareVolume::ConnectionClosed()
2061{
2062	AutoLocker<Locker> _(fMountLock);
2063	fConnectionState = CONNECTION_CLOSED;
2064}
2065
2066
2067// #pragma mark -
2068
2069// _ReadRemoteDir
2070status_t
2071ShareVolume::_ReadRemoteDir(ShareDir* directory,
2072	RemoteShareDirIterator* iterator)
2073{
2074	// prepare the request
2075	fLock.Lock();
2076	ReadDirRequest request;
2077	request.volumeID = fID;
2078	request.cookie = iterator->GetCookie();
2079	request.count = iterator->GetCapacity();
2080	request.rewind = iterator->GetRewind();
2081	fLock.Unlock();
2082
2083	// send the request
2084	ReadDirReply* reply;
2085	status_t error = SendRequest(fConnection, &request, &reply);
2086	if (error != B_OK)
2087		RETURN_ERROR(error);
2088	ObjectDeleter<Request> replyDeleter(reply);
2089	if (reply->error != B_OK)
2090		RETURN_ERROR(reply->error);
2091
2092	RequestMemberArray<EntryInfo>* entryInfos = &reply->entryInfos;
2093	while (true) {
2094		// get up to date entry infos
2095		MultiWalkReply* walkReply = NULL;
2096		if (!entryInfos) {
2097			error = _MultiWalk(reply->entryInfos, &walkReply);
2098			if (error != B_OK)
2099				RETURN_ERROR(error);
2100
2101			entryInfos = &walkReply->entryInfos;
2102		}
2103		ObjectDeleter<Request> walkReplyDeleter(walkReply);
2104
2105		AutoLocker<Locker> locker(fLock);
2106
2107		// check, if any info is obsolete
2108		int32 count = entryInfos->CountElements();
2109		for (int32 i = 0; i < count; i++) {
2110			const EntryInfo& entryInfo = entryInfos->GetElements()[i];
2111			if (_IsObsoleteEntryInfo(entryInfo)) {
2112				entryInfos = NULL;
2113				continue;
2114			}
2115		}
2116
2117		// init the iterator's revision, if it's new or has been rewinded
2118		if (request.rewind || iterator->GetRevision() < 0)
2119			iterator->SetRevision(reply->revision);
2120
2121		iterator->Clear();
2122		iterator->SetDone(reply->done);
2123
2124		// iterate through the entries
2125		for (int32 i = 0; i < count; i++) {
2126			const EntryInfo& entryInfo = entryInfos->GetElements()[i];
2127			const char* name = entryInfo.name.GetString();
2128			int32 nameLen = entryInfo.name.GetSize();
2129			if (!name || nameLen < 2)
2130				return B_BAD_DATA;
2131
2132			// load the node/entry
2133			ShareDirEntry* entry;
2134			error = _LoadEntry(directory, entryInfo, &entry);
2135			if (error != B_OK)
2136				RETURN_ERROR(error);
2137
2138			// add the entry
2139			if (!iterator->AddEntry(entry)) {
2140				ERROR(("ShareVolume::_ReadRemoteDir(): ERROR: Failed to add "
2141					"entry to remote iterator!\n"));
2142			}
2143		}
2144
2145		// directory now complete?
2146		if (reply->done && directory->GetEntryRemovedEventRevision()
2147				< iterator->GetRevision()) {
2148			directory->SetComplete(true);
2149		}
2150
2151		break;
2152	}
2153
2154	return B_OK;
2155}
2156
2157// _HandleEntryCreatedRequest
2158void
2159ShareVolume::_HandleEntryCreatedRequest(EntryCreatedRequest* request)
2160{
2161	if (!request)
2162		return;
2163
2164	nspace_id nsid = fVolumeManager->GetID();
2165	const char* name = request->name.GetString();
2166
2167	// translate the node IDs
2168	vnode_id vnida = 0;
2169	vnode_id vnidb = 0;
2170	vnode_id vnidc = 0;
2171	status_t error = _GetLocalNodeID(request->directoryID, &vnida, true);
2172	if (error == B_OK)
2173		error = _GetLocalNodeID(request->nodeID, &vnidc, true);
2174PRINT(("ShareVolume::_HandleEntryCreatedRequest(): error: 0x%lx, name: \"%s\", dir: %lld (remote: (%ld, %lld)), node: %lld (remote: (%ld, %lld))\n", error, name, vnida, request->directoryID.volumeID, request->directoryID.nodeID, vnidc, request->nodeID.volumeID, request->nodeID.nodeID));
2175
2176	// send notifications / do additional processing
2177	if (request->queryUpdate) {
2178		if (error == B_OK) {
2179			SendNotification(request->port, request->token,
2180				B_QUERY_UPDATE, request->opcode, nsid, 0, vnida, vnidb,
2181				vnidc, name);
2182		}
2183	} else {
2184		_EntryCreated(request->directoryID, name,
2185			(request->entryInfoValid ? &request->entryInfo : NULL),
2186			request->revision);
2187		if (error == B_OK)
2188			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name);
2189	}
2190}
2191
2192// _HandleEntryRemovedRequest
2193void
2194ShareVolume::_HandleEntryRemovedRequest(EntryRemovedRequest* request)
2195{
2196	if (!request)
2197		return;
2198
2199	nspace_id nsid = fVolumeManager->GetID();
2200	const char* name = request->name.GetString();
2201
2202	// translate the node IDs
2203	vnode_id vnida = 0;
2204	vnode_id vnidb = 0;
2205	vnode_id vnidc = 0;
2206	status_t error = _GetLocalNodeID(request->directoryID, &vnida, true);
2207	if (error == B_OK)
2208		error = _GetLocalNodeID(request->nodeID, &vnidc, false);
2209			// TODO: We don't enter a node ID mapping here, which might cause
2210			// undesired behavior in some cases. Queries should usually be
2211			// fine, since, if the entry was in the query set, then the
2212			// respective node ID should definately be known at this point.
2213			// If an entry is removed and the node monitoring event comes
2214			// before a live query event for the same entry, the former one
2215			// will cause the ID to be removed, so that it is already gone
2216			// when the latter one arrives. I haven't observed this yet,
2217			// though. The query events always seem to be sent before the
2218			// node monitoring events (and the server processes them in a
2219			// single-threaded way). I guess, this is FS implementation
2220			// dependent, though.
2221			// A node monitoring event that will always get lost, is when the
2222			// FS user watches a directory that hasn't been read before. Its
2223			// entries will not be known yet and thus "entry removed" events
2224			// will be dropped here. I guess, it's arguable whether this is
2225			// a practical problem (why should the watcher care that an entry
2226			// has been removed, when they didn't know what entries were in
2227			// the directory in the first place?).
2228			// A possible solution would be to never remove node ID mappings.
2229			// We would only need to take care that the cached node info is
2230			// correctly flushed, so that e.g. a subsequent ReadVNode() has to
2231			// ask the server and doesn't work with obsolete data. We would
2232			// also enter a yet unknown ID into the node ID map here. The only
2233			// problem is that the ID maps will keep growing, especially when
2234			// there's a lot of FS activity on the server.
2235
2236	// send notifications / do additional processing
2237	if (request->queryUpdate) {
2238		if (error == B_OK) {
2239			SendNotification(request->port, request->token,
2240				B_QUERY_UPDATE, request->opcode, nsid, 0, vnida, vnidb,
2241				vnidc, name);
2242		}
2243	} else {
2244		_EntryRemoved(request->directoryID, name, request->revision);
2245		_NodeRemoved(request->nodeID);
2246		if (error == B_OK)
2247			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name);
2248	}
2249}
2250
2251// _HandleEntryMovedRequest
2252void
2253ShareVolume::_HandleEntryMovedRequest(EntryMovedRequest* request)
2254{
2255	if (!request)
2256		return;
2257
2258	nspace_id nsid = fVolumeManager->GetID();
2259	const char* oldName = request->fromName.GetString();
2260	const char* name = request->toName.GetString();
2261
2262	// translate the node IDs
2263	vnode_id vnida = 0;
2264	vnode_id vnidb = 0;
2265	vnode_id vnidc = 0;
2266	status_t error = _GetLocalNodeID(request->fromDirectoryID, &vnida, true);
2267	if (error == B_OK)
2268		error = _GetLocalNodeID(request->toDirectoryID, &vnidb, true);
2269	if (error == B_OK)
2270		error = _GetLocalNodeID(request->nodeID, &vnidc, true);
2271
2272	// send notifications / do additional processing
2273	if (!request->queryUpdate) {
2274		_EntryMoved(request->fromDirectoryID, oldName, request->toDirectoryID,
2275			name, (request->entryInfoValid ? &request->entryInfo : NULL),
2276			request->revision);
2277		if (error == B_OK)
2278			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name);
2279	}
2280}
2281
2282// _HandleStatChangedRequest
2283void
2284ShareVolume::_HandleStatChangedRequest(StatChangedRequest* request)
2285{
2286	if (!request)
2287		return;
2288
2289	nspace_id nsid = fVolumeManager->GetID();
2290
2291	// translate the node IDs
2292	vnode_id vnida = 0;
2293	vnode_id vnidb = 0;
2294	vnode_id vnidc = 0;
2295	status_t error = _GetLocalNodeID(request->nodeID, &vnidc, true);
2296
2297	// send notifications / do additional processing
2298	if (!request->queryUpdate) {
2299		_UpdateNode(request->nodeInfo);
2300		if (error == B_OK)
2301			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, NULL);
2302	}
2303}
2304
2305// _HandleAttributeChangedRequest
2306void
2307ShareVolume::_HandleAttributeChangedRequest(AttributeChangedRequest* request)
2308{
2309	if (!request)
2310		return;
2311
2312	nspace_id nsid = fVolumeManager->GetID();
2313	const char* name = request->attrInfo.name.GetString();
2314
2315	// translate the node IDs
2316	vnode_id vnida = 0;
2317	vnode_id vnidb = 0;
2318	vnode_id vnidc = 0;
2319	status_t error = _GetLocalNodeID(request->nodeID, &vnidc, true);
2320
2321	// send notifications / do additional processing
2322	if (!request->queryUpdate) {
2323		_UpdateAttrDir(request->nodeID, request->attrDirInfo);
2324		if (error == B_OK)
2325			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name);
2326	}
2327}
2328
2329// _GetLocalNodeID
2330status_t
2331ShareVolume::_GetLocalNodeID(NodeID remoteID, ino_t* _localID, bool enter)
2332{
2333	AutoLocker<Locker> _(fLock);
2334	// if the ID is already know, just return it
2335	if (fLocalNodeIDs->ContainsKey(remoteID)) {
2336		*_localID = fLocalNodeIDs->Get(remoteID);
2337		return B_OK;
2338	}
2339
2340	// ID not yet known
2341	// enter it? Do this only, if requested and we're not already unmounting.
2342	if (!enter)
2343		return B_ENTRY_NOT_FOUND;
2344	if (fUnmounting)
2345		return ERROR_NOT_CONNECTED;
2346
2347	// get a fresh ID from the volume manager
2348	vnode_id localID = fVolumeManager->NewNodeID(this);
2349	if (localID < 0)
2350		return localID;
2351
2352	// put the IDs into local map
2353	status_t error = fLocalNodeIDs->Put(remoteID, localID);
2354	if (error != B_OK) {
2355		fVolumeManager->RemoveNodeID(localID);
2356		return error;
2357	}
2358
2359	// put the IDs into remote map
2360	error = fRemoteNodeIDs->Put(localID, remoteID);
2361	if (error != B_OK) {
2362		fLocalNodeIDs->Remove(remoteID);
2363		fVolumeManager->RemoveNodeID(localID);
2364		return error;
2365	}
2366PRINT(("ShareVolume(%ld): added node ID mapping: local: %lld -> "
2367"remote: (%ld, %lld)\n", fID, localID, remoteID.volumeID, remoteID.nodeID));
2368
2369	*_localID = localID;
2370	return B_OK;
2371}
2372
2373// _GetRemoteNodeID
2374status_t
2375ShareVolume::_GetRemoteNodeID(ino_t localID, NodeID* remoteID)
2376{
2377	AutoLocker<Locker> _(fLock);
2378
2379	// check, if the ID is known
2380	if (!fRemoteNodeIDs->ContainsKey(localID))
2381		return B_ENTRY_NOT_FOUND;
2382
2383	*remoteID = fRemoteNodeIDs->Get(localID);
2384	return B_OK;
2385}
2386
2387// _RemoveLocalNodeID
2388void
2389ShareVolume::_RemoveLocalNodeID(ino_t localID)
2390{
2391	AutoLocker<Locker> _(fLock);
2392
2393	// check, if the ID is known
2394	if (!fRemoteNodeIDs->ContainsKey(localID))
2395		return;
2396
2397	// remove from ID maps
2398	NodeID remoteID = fRemoteNodeIDs->Get(localID);
2399PRINT(("ShareVolume::_RemoveLocalNodeID(%lld): remote: (%ld, %lld)\n", localID, remoteID.volumeID, remoteID.nodeID));
2400	fRemoteNodeIDs->Remove(localID);
2401	fLocalNodeIDs->Remove(remoteID);
2402
2403	// remove from volume manager
2404	fVolumeManager->RemoveNodeID(localID);
2405}
2406
2407// _GetNodeByLocalID
2408ShareNode*
2409ShareVolume::_GetNodeByLocalID(ino_t localID)
2410{
2411	AutoLocker<Locker> _(fLock);
2412	return fNodes->Get(localID);
2413}
2414
2415// _GetNodeByRemoteID
2416ShareNode*
2417ShareVolume::_GetNodeByRemoteID(NodeID remoteID)
2418{
2419	AutoLocker<Locker> _(fLock);
2420
2421	ino_t localID;
2422	if (_GetLocalNodeID(remoteID, &localID, false) == B_OK)
2423		return fNodes->Get(localID);
2424
2425	return NULL;
2426}
2427
2428// _LoadNode
2429status_t
2430ShareVolume::_LoadNode(const NodeInfo& nodeInfo, ShareNode** _node)
2431{
2432	AutoLocker<Locker> _(fLock);
2433
2434	// check, if the node is already known
2435	ShareNode* node = _GetNodeByRemoteID(nodeInfo.GetID());
2436	if (node) {
2437		node->Update(nodeInfo);
2438	} else {
2439		// don't load the node when already unmounting
2440		if (fUnmounting)
2441			return B_ERROR;
2442
2443		// get a local node ID
2444		vnode_id localID;
2445		status_t error = _GetLocalNodeID(nodeInfo.GetID(), &localID, true);
2446		if (error != B_OK)
2447			return error;
2448
2449		// create a new node
2450		if (S_ISDIR(nodeInfo.st.st_mode))
2451			node = new(nothrow) ShareDir(this, localID, &nodeInfo);
2452		else
2453			node = new(nothrow) ShareNode(this, localID, &nodeInfo);
2454		if (!node) {
2455			_RemoveLocalNodeID(localID);
2456			return B_NO_MEMORY;
2457		}
2458
2459		// add it
2460		error = fNodes->Put(node->GetID(), node);
2461		if (error != B_OK) {
2462			_RemoveLocalNodeID(localID);
2463			delete node;
2464			return error;
2465		}
2466PRINT(("ShareVolume: added node: %lld: remote: (%ld, %lld), localID: %lld\n",
2467node->GetID(), node->GetRemoteID().volumeID, node->GetRemoteID().nodeID,
2468localID));
2469	}
2470
2471	if (_node)
2472		*_node = node;
2473	return B_OK;
2474}
2475
2476// _UpdateNode
2477status_t
2478ShareVolume::_UpdateNode(const NodeInfo& nodeInfo)
2479{
2480	AutoLocker<Locker> _(fLock);
2481
2482	if (fUnmounting)
2483		return ERROR_NOT_CONNECTED;
2484
2485	ShareNode* node = _GetNodeByRemoteID(nodeInfo.GetID());
2486	if (node) {
2487		node->Update(nodeInfo);
2488		return B_OK;
2489	}
2490	return B_ENTRY_NOT_FOUND;
2491}
2492
2493// _GetEntryByLocalID
2494ShareDirEntry*
2495ShareVolume::_GetEntryByLocalID(ino_t localDirID, const char* name)
2496{
2497	if (!name)
2498		return NULL;
2499
2500	AutoLocker<Locker> _(fLock);
2501	return fEntries->Get(EntryKey(localDirID, name));
2502}
2503
2504// _GetEntryByRemoteID
2505ShareDirEntry*
2506ShareVolume::_GetEntryByRemoteID(NodeID remoteDirID, const char* name)
2507{
2508	if (!name)
2509		return NULL;
2510
2511	AutoLocker<Locker> _(fLock);
2512
2513	ino_t localDirID;
2514	if (_GetLocalNodeID(remoteDirID, &localDirID, false) == B_OK)
2515		return fEntries->Get(EntryKey(localDirID, name));
2516
2517	return NULL;
2518}
2519
2520// _LoadEntry
2521//
2522// If _entry is supplied, fLock should be held, otherwise the returned entry
2523// might as well be deleted.
2524status_t
2525ShareVolume::_LoadEntry(ShareDir* directory, const EntryInfo& entryInfo,
2526	ShareDirEntry** _entry)
2527{
2528	const char* name = entryInfo.name.GetString();
2529	if (!directory || !name)
2530		return B_BAD_VALUE;
2531
2532	AutoLocker<Locker> _(fLock);
2533
2534	ShareDirEntry* entry = _GetEntryByLocalID(directory->GetID(), name);
2535	if (entry) {
2536		if (entryInfo.nodeInfo.revision > entry->GetRevision()) {
2537			if (entryInfo.nodeInfo.GetID() != entry->GetNode()->GetRemoteID()) {
2538				// The node the existing entry refers to is not the node it
2539				// should refer to. Remove the old entry and create a new one.
2540				_EntryRemoved(directory->GetRemoteID(), name,
2541					entryInfo.nodeInfo.revision);
2542				_EntryCreated(directory->GetRemoteID(), name, &entryInfo,
2543					entryInfo.nodeInfo.revision);
2544
2545				// re-get the entry and check, if everything is fine
2546				entry = _GetEntryByLocalID(directory->GetID(), name);
2547				if (!entry)
2548					return B_ERROR;
2549				if (entryInfo.nodeInfo.GetID()
2550					!= entry->GetNode()->GetRemoteID()) {
2551					return B_ERROR;
2552				}
2553			} else {
2554				entry->SetRevision(entryInfo.nodeInfo.revision);
2555				_UpdateNode(entryInfo.nodeInfo);
2556			}
2557		}
2558	} else {
2559		// entry not known yet: create it
2560
2561		// don't load the entry when already unmounting
2562		if (fUnmounting)
2563			return B_ERROR;
2564
2565		// load the node
2566		ShareNode* node;
2567		status_t error = _LoadNode(entryInfo.nodeInfo, &node);
2568		if (error != B_OK)
2569			return error;
2570
2571		// if the directory or the node are marked remove, we don't create the
2572		// entry
2573		if (IsVNodeRemoved(directory->GetID()) > 0
2574			|| IsVNodeRemoved(node->GetID()) > 0) {
2575			return B_NOT_ALLOWED;
2576		}
2577
2578		// create the entry
2579		entry = new(nothrow) ShareDirEntry(directory, name, node);
2580		if (!entry)
2581			return B_NO_MEMORY;
2582		ObjectDeleter<ShareDirEntry> entryDeleter(entry);
2583		error = entry->InitCheck();
2584		if (error != B_OK)
2585			return error;
2586
2587		// add the entry
2588		error = fEntries->Put(EntryKey(directory->GetID(), entry->GetName()),
2589			entry);
2590		if (error != B_OK)
2591			return error;
2592
2593		// set the entry revision
2594		entry->SetRevision(entryInfo.nodeInfo.revision);
2595
2596		// add the entry to the directory and the node
2597		directory->AddEntry(entry);
2598		entry->GetNode()->AddReferringEntry(entry);
2599
2600		// everything went fine
2601		entryDeleter.Detach();
2602	}
2603
2604	if (_entry)
2605		*_entry = entry;
2606	return B_OK;
2607}
2608
2609// _RemoveEntry
2610//
2611// fLock must be held.
2612void
2613ShareVolume::_RemoveEntry(ShareDirEntry* entry)
2614{
2615	fEntries->Remove(EntryKey(entry->GetDirectory()->GetID(),
2616		entry->GetName()));
2617	entry->GetDirectory()->RemoveEntry(entry);
2618	entry->GetNode()->RemoveReferringEntry(entry);
2619	entry->RemoveReference();
2620}
2621
2622// _IsObsoleteEntryInfo
2623//
2624// fLock must be held.
2625bool
2626ShareVolume::_IsObsoleteEntryInfo(const EntryInfo& entryInfo)
2627{
2628	// get the directory
2629	ShareDir* dir
2630		= dynamic_cast<ShareDir*>(_GetNodeByRemoteID(entryInfo.directoryID));
2631	if (!dir)
2632		return false;
2633
2634	return (entryInfo.nodeInfo.revision <= dir->GetEntryRemovedEventRevision());
2635}
2636
2637// _LoadAttrDir
2638status_t
2639ShareVolume::_LoadAttrDir(ShareNode* node, const AttrDirInfo& attrDirInfo)
2640{
2641	if (!node || !attrDirInfo.isValid)
2642		return B_BAD_VALUE;
2643
2644	AutoLocker<Locker> _(fLock);
2645
2646	if (fUnmounting)
2647		return ERROR_NOT_CONNECTED;
2648
2649	ShareAttrDir* attrDir = node->GetAttrDir();
2650	if (attrDir) {
2651		if (attrDir->GetRevision() > attrDirInfo.revision)
2652			return B_OK;
2653
2654		// update the attr dir
2655		return attrDir->Update(attrDirInfo,
2656			fAttrDirIterators->Get(node->GetID()));
2657	} else {
2658		// no attribute directory yet: create one
2659		attrDir = new(nothrow) ShareAttrDir;
2660		if (!attrDir)
2661			return B_NO_MEMORY;
2662		ObjectDeleter<ShareAttrDir> attrDirDeleter(attrDir);
2663
2664		// initialize it
2665		status_t error = attrDir->Init(attrDirInfo);
2666		if (error != B_OK)
2667			return error;
2668
2669		// set it
2670		node->SetAttrDir(attrDir);
2671		attrDirDeleter.Detach();
2672		return B_OK;
2673	}
2674}
2675
2676// _UpdateAttrDir
2677status_t
2678ShareVolume::_UpdateAttrDir(NodeID remoteID, const AttrDirInfo& attrDirInfo)
2679{
2680	AutoLocker<Locker> _(fLock);
2681
2682	// get the node
2683	ShareNode* node = _GetNodeByRemoteID(remoteID);
2684	if (!node)
2685		return B_ENTRY_NOT_FOUND;
2686
2687	if (!attrDirInfo.isValid || _LoadAttrDir(node, attrDirInfo) != B_OK) {
2688		// updating/creating the attr dir failed; if existing, we mark it
2689		// obsolete
2690		if (ShareAttrDir* attrDir = node->GetAttrDir())
2691			attrDir->SetUpToDate(false);
2692	}
2693
2694	return B_OK;
2695}
2696
2697// _AddAttrDirIterator
2698status_t
2699ShareVolume::_AddAttrDirIterator(ShareNode* node,
2700	ShareAttrDirIterator* iterator)
2701{
2702	if (!node || !iterator)
2703		return B_BAD_VALUE;
2704
2705	AutoLocker<Locker> locker(fLock);
2706
2707	// get the iterator list
2708	DLList<ShareAttrDirIterator>* iteratorList
2709		= fAttrDirIterators->Get(node->GetID());
2710	if (!iteratorList) {
2711		// no list for the node yet: create one
2712		iteratorList = new(nothrow) DLList<ShareAttrDirIterator>;
2713		if (!iteratorList)
2714			return B_NO_MEMORY;
2715
2716		// add it
2717		status_t error = fAttrDirIterators->Put(node->GetID(), iteratorList);
2718		if (error != B_OK) {
2719			delete iteratorList;
2720			return error;
2721		}
2722	}
2723
2724	// add the iterator
2725	iteratorList->Insert(iterator);
2726
2727	return B_OK;
2728}
2729
2730// _RemoveAttrDirIterator
2731void
2732ShareVolume::_RemoveAttrDirIterator(ShareNode* node,
2733	ShareAttrDirIterator* iterator)
2734{
2735	if (!node || !iterator)
2736		return;
2737
2738	AutoLocker<Locker> locker(fLock);
2739
2740	// get the iterator list
2741	DLList<ShareAttrDirIterator>* iteratorList
2742		= fAttrDirIterators->Get(node->GetID());
2743	if (!iteratorList) {
2744		WARN(("ShareVolume::_RemoveAttrDirIterator(): Iterator list not "
2745			"found: node: %lld\n", node->GetID()));
2746		return;
2747	}
2748
2749	// remove the iterator
2750	iteratorList->Remove(iterator);
2751
2752	// if the list is empty now, discard it
2753	if (!iteratorList->GetFirst()) {
2754		fAttrDirIterators->Remove(node->GetID());
2755		delete iteratorList;
2756	}
2757}
2758
2759// _NodeRemoved
2760void
2761ShareVolume::_NodeRemoved(NodeID remoteID)
2762{
2763	AutoLocker<Locker> locker(fLock);
2764
2765	ShareNode* node = _GetNodeByRemoteID(remoteID);
2766	if (!node)
2767		return;
2768
2769	// if the node still has referring entries, we do nothing
2770	if (node->GetActualReferringEntry())
2771		return;
2772
2773	// if the node is a directory, we remove its entries first
2774	if (ShareDir* dir = dynamic_cast<ShareDir*>(node)) {
2775		while (ShareDirEntry* entry = dir->GetFirstEntry())
2776			_RemoveEntry(entry);
2777	}
2778
2779	// remove all entries still referring to the node
2780	while (ShareDirEntry* entry = node->GetFirstReferringEntry())
2781		_RemoveEntry(entry);
2782
2783	ino_t localID = node->GetID();
2784
2785	// Remove the node ID in all cases -- even, if the node is still
2786	// known to the VFS. Otherwise there could be a race condition, that the
2787	// server re-uses the remote ID and we have it still associated with an
2788	// obsolete local ID.
2789	_RemoveLocalNodeID(localID);
2790
2791	if (node->IsKnownToVFS()) {
2792		Node* _node;
2793		if (GetVNode(localID, &_node) != B_OK)
2794			return;
2795		Volume::RemoveVNode(localID);
2796		locker.Unlock();
2797		PutVNode(localID);
2798
2799	} else {
2800		fNodes->Remove(localID);
2801		delete node;
2802	}
2803}
2804
2805// _EntryCreated
2806void
2807ShareVolume::_EntryCreated(NodeID remoteDirID, const char* name,
2808	const EntryInfo* entryInfo, int64 revision)
2809{
2810	if (!name)
2811		return;
2812
2813	AutoLocker<Locker> locker(fLock);
2814
2815	// get the directory
2816	ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(remoteDirID));
2817	if (!dir)
2818		return;
2819
2820	// load the entry, if possible
2821	ShareDirEntry* entry;
2822	bool entryLoaded = false;
2823	if (entryInfo && _LoadEntry(dir, *entryInfo, &entry) == B_OK)
2824		entryLoaded = true;
2825
2826	// if the entry could not be loaded, we have to mark the dir incomplete
2827	// and update its revision counter
2828	if (!entryLoaded) {
2829		dir->UpdateEntryCreatedEventRevision(revision);
2830		dir->SetComplete(false);
2831	}
2832}
2833
2834// _EntryRemoved
2835void
2836ShareVolume::_EntryRemoved(NodeID remoteDirID, const char* name, int64 revision)
2837{
2838	if (!name)
2839		return;
2840
2841	AutoLocker<Locker> locker(fLock);
2842
2843	// get the directory
2844	ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(remoteDirID));
2845	if (!dir)
2846		return;
2847
2848	// update the directory's "entry removed" event revision
2849	dir->UpdateEntryRemovedEventRevision(revision);
2850
2851	// get the entry
2852	ShareDirEntry* entry = _GetEntryByRemoteID(remoteDirID, name);
2853	if (!entry)
2854		return;
2855
2856	// check the entry revision
2857	if (entry->GetRevision() > revision)
2858		return;
2859
2860	// remove the entry
2861	_RemoveEntry(entry);
2862}
2863
2864// _EntryMoved
2865void
2866ShareVolume::_EntryMoved(NodeID remoteOldDirID, const char* oldName,
2867	NodeID remoteNewDirID, const char* name, const EntryInfo* entryInfo,
2868	int64 revision)
2869{
2870	AutoLocker<Locker> locker(fLock);
2871
2872	_EntryRemoved(remoteOldDirID, oldName, revision);
2873	_EntryCreated(remoteNewDirID, name, entryInfo, revision);
2874}
2875
2876// _Walk
2877status_t
2878ShareVolume::_Walk(NodeID remoteDirID, const char* entryName, bool resolveLink,
2879	WalkReply** _reply)
2880{
2881	// prepare the request
2882	WalkRequest request;
2883	request.volumeID = fID;
2884	request.nodeID = remoteDirID;
2885	request.name.SetTo(entryName);
2886	request.resolveLink = resolveLink;
2887
2888	// send the request
2889	WalkReply* reply;
2890	status_t error = SendRequest(fConnection, &request, &reply);
2891	if (error != B_OK)
2892		RETURN_ERROR(error);
2893	ObjectDeleter<Request> replyDeleter(reply);
2894	if (reply->error != B_OK)
2895		RETURN_ERROR(reply->error);
2896
2897	replyDeleter.Detach();
2898	*_reply = reply;
2899	return B_OK;
2900}
2901
2902// _MultiWalk
2903status_t
2904ShareVolume::_MultiWalk(RequestMemberArray<EntryInfo>& _entryInfos,
2905	MultiWalkReply** _reply)
2906{
2907	int32 count = _entryInfos.CountElements();
2908	if (!_reply || count == 0)
2909		return B_BAD_VALUE;
2910
2911	EntryInfo* entryInfos = _entryInfos.GetElements();
2912
2913	// prepare the request
2914	MultiWalkRequest request;
2915	request.volumeID = fID;
2916	request.nodeID = entryInfos[0].directoryID;
2917
2918	// add the names
2919	for (int32 i = 0; i < count; i++) {
2920		StringData name;
2921		name.SetTo(entryInfos[i].name.GetString());
2922
2923		status_t error = request.names.Append(name);
2924		if (error != B_OK)
2925			return error;
2926	}
2927
2928	// send the request
2929	MultiWalkReply* reply;
2930	status_t error = SendRequest(fConnection, &request, &reply);
2931	if (error != B_OK)
2932		RETURN_ERROR(error);
2933	ObjectDeleter<Request> replyDeleter(reply);
2934	if (reply->error != B_OK)
2935		RETURN_ERROR(reply->error);
2936
2937	replyDeleter.Detach();
2938	*_reply = reply;
2939	return B_OK;
2940}
2941
2942// _Close
2943status_t
2944ShareVolume::_Close(int32 cookie)
2945{
2946	if (!_EnsureShareMounted())
2947		return ERROR_NOT_CONNECTED;
2948
2949	// prepare the request
2950	CloseRequest request;
2951	request.volumeID = fID;
2952	request.cookie = cookie;
2953	// send the request
2954	CloseReply* reply;
2955	status_t error = SendRequest(fConnection, &request, &reply);
2956	if (error != B_OK)
2957		RETURN_ERROR(error);
2958	ObjectDeleter<Request> replyDeleter(reply);
2959	if (reply->error != B_OK)
2960		RETURN_ERROR(reply->error);
2961	return B_OK;
2962}
2963
2964// _GetConnectionState
2965//
2966// Must not be called with fLock being held!
2967uint32
2968ShareVolume::_GetConnectionState()
2969{
2970	AutoLocker<Locker> _(fMountLock);
2971	return fConnectionState;
2972}
2973
2974// _IsConnected
2975//
2976// Must not be called with fLock being held!
2977bool
2978ShareVolume::_IsConnected()
2979{
2980	return (_GetConnectionState() == CONNECTION_READY);
2981}
2982
2983// _EnsureShareMounted
2984//
2985// Must not be called with fLock being held!
2986bool
2987ShareVolume::_EnsureShareMounted()
2988{
2989	AutoLocker<Locker> _(fMountLock);
2990	if (fConnectionState == CONNECTION_NOT_INITIALIZED)
2991		_MountShare();
2992
2993	return (fConnectionState == CONNECTION_READY);
2994}
2995
2996// _MountShare
2997//
2998// fMountLock must be held.
2999status_t
3000ShareVolume::_MountShare()
3001{
3002	// get references to the server and share info
3003	AutoLocker<Locker> locker(fLock);
3004	Reference<ExtendedServerInfo> serverInfoReference(fServerInfo);
3005	Reference<ExtendedShareInfo> shareInfoReference(fShareInfo);
3006	ExtendedServerInfo* serverInfo = fServerInfo;
3007	ExtendedShareInfo* shareInfo = fShareInfo;
3008	locker.Unlock();
3009
3010	// get server address as string
3011	String serverAddressString;
3012	status_t error = serverInfo->GetAddress().GetString(&serverAddressString,
3013		false);
3014	if (error != B_OK)
3015		return error;
3016	const char* server = serverAddressString.GetString();
3017
3018	// get the server name
3019	const char* serverName = serverInfo->GetServerName();
3020	if (serverName && strlen(serverName) == 0)
3021		serverName = NULL;
3022
3023	// get the share name
3024	const char* share = shareInfo->GetShareName();
3025
3026PRINT(("ShareVolume::_MountShare(%s, %s)\n", server, share));
3027	// init a connection to the authentication server
3028	AuthenticationServer authenticationServer;
3029	error = authenticationServer.InitCheck();
3030	if (error != B_OK)
3031		RETURN_ERROR(error);
3032
3033	// get the server connection
3034	fConnectionState = CONNECTION_CLOSED;
3035	if (!fServerConnection) {
3036		status_t error = fServerConnectionProvider->GetServerConnection(
3037			&fServerConnection);
3038		if (error != B_OK)
3039			return error;
3040		fConnection = fServerConnection->GetRequestConnection();
3041	}
3042
3043	// the mount loop
3044	bool badPassword = false;
3045	MountReply* reply = NULL;
3046	do {
3047		// get the user and password from the authentication server
3048		char user[kUserBufferSize];
3049		char password[kPasswordBufferSize];
3050		bool cancelled;
3051		error = authenticationServer.GetAuthentication("netfs",
3052			(serverName ? serverName : server), share,
3053			fVolumeManager->GetMountUID(), badPassword,
3054			&cancelled, user, sizeof(user), password, sizeof(password));
3055		if (cancelled || error != B_OK)
3056			RETURN_ERROR(error);
3057
3058		// prepare the request
3059		MountRequest request;
3060		request.share.SetTo(share);
3061		request.user.SetTo(user);
3062		request.password.SetTo(password);
3063
3064		// send the request
3065		error = SendRequest(fConnection, &request, &reply);
3066		if (error != B_OK)
3067			RETURN_ERROR(error);
3068		ObjectDeleter<Request> replyDeleter(reply);
3069
3070		// if no permission, try again
3071		badPassword = reply->noPermission;
3072		if (!badPassword) {
3073			if (reply->error != B_OK)
3074				RETURN_ERROR(reply->error);
3075			fSharePermissions = reply->sharePermissions;
3076		}
3077	} while (badPassword);
3078
3079	AutoLocker<Locker> _(fLock);
3080
3081	fID = reply->volumeID;
3082
3083	// update the root node and enter its ID
3084	fRootNode->Update(reply->nodeInfo);
3085
3086	// put the IDs into local map
3087	error = fLocalNodeIDs->Put(fRootNode->GetRemoteID(), fRootNode->GetID());
3088	if (error != B_OK)
3089		RETURN_ERROR(error);
3090
3091	// put the IDs into remote map
3092	error = fRemoteNodeIDs->Put(fRootNode->GetID(), fRootNode->GetRemoteID());
3093	if (error != B_OK) {
3094		fLocalNodeIDs->Remove(fRootNode->GetRemoteID());
3095		RETURN_ERROR(error);
3096	}
3097PRINT(("ShareVolume::_MountShare(): root node: local: %lld, remote: (%ld, %lld)\n", fRootNode->GetID(), fRootNode->GetRemoteID().volumeID, fRootNode->GetRemoteID().nodeID));
3098
3099	// Add ourselves to the server connection, so that we can receive
3100	// node monitoring events. There a race condition: We might already
3101	// have missed events for the root node.
3102	error = fServerConnection->AddVolume(this);
3103	if (error != B_OK) {
3104		_RemoveLocalNodeID(fRootNode->GetID());
3105		return error;
3106	}
3107
3108	fConnectionState = CONNECTION_READY;
3109	return B_OK;
3110}
3111
3112