120253Sjoerg// ShareVolume.cpp
220302Sjoerg
320302Sjoerg#include "ShareVolume.h"
420253Sjoerg
520253Sjoerg#include <new>
620253Sjoerg#include <unistd.h>
720253Sjoerg
820253Sjoerg#include <AppDefs.h>	// for B_QUERY_UPDATE
920302Sjoerg#include <AutoDeleter.h>
1020253Sjoerg#include <AutoLocker.h>
1120253Sjoerg#include <HashMap.h>
1220253Sjoerg
1320253Sjoerg#include "AuthenticationServer.h"
1420302Sjoerg#include "Compatibility.h"
1520253Sjoerg#include "Connection.h"
1620253Sjoerg#include "ConnectionFactory.h"
1720302Sjoerg#include "DebugSupport.h"
1820253Sjoerg#include "ExtendedServerInfo.h"
1920253Sjoerg#include "Permissions.h"
2020253Sjoerg#include "Node.h"
2120253Sjoerg#include "QueryManager.h"
2220253Sjoerg#include "RequestChannel.h"
2320253Sjoerg#include "RequestConnection.h"
2420253Sjoerg#include "Requests.h"
2520253Sjoerg#include "RootVolume.h"
2620747Sdavidn#include "SendReceiveRequest.h"
2720253Sjoerg#include "ServerConnection.h"
2820253Sjoerg#include "ServerConnectionProvider.h"
2920253Sjoerg#include "ShareAttrDir.h"
3020253Sjoerg#include "ShareAttrDirIterator.h"
3120253Sjoerg#include "ShareNode.h"
3220253Sjoerg#include "Utils.h"
3320253Sjoerg#include "VolumeManager.h"
3420747Sdavidn#include "VolumeSupport.h"
3520253Sjoerg
3620253Sjoerg// TODO: Request timeouts!
3720253Sjoerg
3820253Sjoergstatic const int32 kMaxWriteBufferSize	= 64 * 1024;	// 64 KB
3920253Sjoergstatic const int32 kUserBufferSize = 256;
4020253Sjoergstatic const int32 kPasswordBufferSize = 256;
4120253Sjoerg
4220253Sjoerg// connection states
4320253Sjoergenum {
4420253Sjoerg	CONNECTION_NOT_INITIALIZED,
4520253Sjoerg	CONNECTION_READY,
4620253Sjoerg	CONNECTION_CLOSED,
4720253Sjoerg};
4820253Sjoerg
4920253Sjoerg// NodeMap
5020253Sjoergstruct ShareVolume::NodeMap : HashMap<HashKey64<ino_t>, ShareNode*> {
5120253Sjoerg};
5220253Sjoerg
5320253Sjoerg// EntryKey
5420253Sjoerg//
5520253Sjoerg// NOTE: This class doesn't make a copy of the name string it is constructed
5620253Sjoerg// with. So, when entering the key in a map, one must make sure, that the
5720253Sjoerg// string stays valid as long as the entry is in the map.
5820253Sjoergstruct ShareVolume::EntryKey {
5920253Sjoerg	EntryKey() {}
6020253Sjoerg
6120253Sjoerg	EntryKey(ino_t directoryID, const char* name)
6220253Sjoerg		: directoryID(directoryID),
6320253Sjoerg		  name(name)
6420253Sjoerg	{
6520253Sjoerg	}
6620253Sjoerg
6720253Sjoerg	EntryKey(const EntryKey& other)
6820253Sjoerg		: directoryID(other.directoryID),
6920253Sjoerg		  name(other.name)
7020253Sjoerg	{
7120253Sjoerg	}
7220253Sjoerg
7320253Sjoerg	uint32 GetHashCode() const
7420253Sjoerg	{
7520253Sjoerg		uint32 hash = (uint32)directoryID;
7620253Sjoerg		hash = 31 * hash + (uint32)(directoryID >> 32);
7720253Sjoerg		hash = 31 * hash + string_hash(name);
7820253Sjoerg		return hash;
7920253Sjoerg	}
8020253Sjoerg
8120253Sjoerg	EntryKey& operator=(const EntryKey& other)
8220253Sjoerg	{
8320253Sjoerg		directoryID = other.directoryID;
8420253Sjoerg		name = other.name;
8520253Sjoerg		return *this;
8620253Sjoerg	}
8720253Sjoerg
8820253Sjoerg	bool operator==(const EntryKey& other) const
8920253Sjoerg	{
9020253Sjoerg		if (directoryID != other.directoryID)
9120253Sjoerg			return false;
9220747Sdavidn
9320253Sjoerg		if (name)
9420253Sjoerg			return (other.name && strcmp(name, other.name) == 0);
9520253Sjoerg
9620253Sjoerg		return !other.name;
9720253Sjoerg	}
9820253Sjoerg
9920253Sjoerg	bool operator!=(const EntryKey& other) const
10020253Sjoerg	{
10120253Sjoerg		return !(*this == other);
10220253Sjoerg	}
10320253Sjoerg
10420253Sjoerg	ino_t		directoryID;
10520253Sjoerg	const char*	name;
10620253Sjoerg};
10720253Sjoerg
10820253Sjoerg// EntryMap
10920253Sjoergstruct ShareVolume::EntryMap : HashMap<EntryKey, ShareDirEntry*> {
11020253Sjoerg};
11120253Sjoerg
11220253Sjoerg// LocalNodeIDMap
11320253Sjoergstruct ShareVolume::LocalNodeIDMap : HashMap<NodeID, ino_t> {
11420253Sjoerg};
11520253Sjoerg
11620253Sjoerg// RemoteNodeIDMap
11720253Sjoergstruct ShareVolume::RemoteNodeIDMap : HashMap<HashKey64<ino_t>, NodeID> {
11820253Sjoerg};
11920253Sjoerg
12020253Sjoerg// DirCookie
12120253Sjoergstruct ShareVolume::DirCookie {
12220253Sjoerg	ShareDirIterator*	iterator;
12320253Sjoerg};
12420253Sjoerg
12520253Sjoerg// AttrDirCookie
12620253Sjoergstruct ShareVolume::AttrDirCookie {
12720253Sjoerg	AttrDirCookie()
12820253Sjoerg		: iterator(NULL),
12920253Sjoerg		  cookie(-1),
13020253Sjoerg		  rewind(false)
13120253Sjoerg	{
13220253Sjoerg	}
13320253Sjoerg
13420253Sjoerg	ShareAttrDirIterator*	iterator;
13520253Sjoerg	int32					cookie;
13620253Sjoerg	bool					rewind;
13720253Sjoerg};
13820253Sjoerg
13920253Sjoerg// AttrDirIteratorMap
14020253Sjoergstruct ShareVolume::AttrDirIteratorMap
14120253Sjoerg	: HashMap<HashKey64<ino_t>, DoublyLinkedList<ShareAttrDirIterator>*> {
14220253Sjoerg};
14320253Sjoerg
14420253Sjoerg
14520253Sjoerg// #pragma mark -
14620253Sjoerg
14720253Sjoerg// constructor
14820253SjoergShareVolume::ShareVolume(VolumeManager* volumeManager,
14920253Sjoerg	ServerConnectionProvider* connectionProvider,
15020253Sjoerg	ExtendedServerInfo* serverInfo, ExtendedShareInfo* shareInfo)
15120253Sjoerg	: Volume(volumeManager),
15220253Sjoerg	  fID(-1),
15320253Sjoerg	  fFlags(0),
15420253Sjoerg	  fMountLock("share mount lock"),
15520253Sjoerg	  fNodes(NULL),
15620253Sjoerg	  fEntries(NULL),
15720253Sjoerg	  fAttrDirIterators(NULL),
15820253Sjoerg	  fLocalNodeIDs(NULL),
15920253Sjoerg	  fRemoteNodeIDs(NULL),
16020253Sjoerg	  fServerConnectionProvider(connectionProvider),
16120253Sjoerg	  fServerInfo(serverInfo),
16220253Sjoerg	  fShareInfo(shareInfo),
16320253Sjoerg	  fServerConnection(NULL),
16420253Sjoerg	  fConnection(NULL),
16520253Sjoerg	  fSharePermissions(0),
16620253Sjoerg	  fConnectionState(CONNECTION_NOT_INITIALIZED)
16720253Sjoerg{
16820253Sjoerg	fFlags = fVolumeManager->GetMountFlags();
16920253Sjoerg	if (fServerConnectionProvider)
17020253Sjoerg		fServerConnectionProvider->AcquireReference();
17120253Sjoerg	if (fServerInfo)
17220253Sjoerg		fServerInfo->AcquireReference();
17320253Sjoerg	if (fShareInfo)
17420253Sjoerg		fShareInfo->AcquireReference();
17520253Sjoerg}
17620253Sjoerg
17720253Sjoerg// destructor
17820253SjoergShareVolume::~ShareVolume()
17920253Sjoerg{
18020253SjoergPRINT(("ShareVolume::~ShareVolume()\n"));
18120253Sjoerg	// delete the root node
18220253Sjoerg	if (fRootNode) {
18320253Sjoerg		if (fNodes)
18420253Sjoerg			fNodes->Remove(fRootNode->GetID());
18520253Sjoerg		delete fRootNode;
18620253Sjoerg		fRootNode = NULL;
18720253Sjoerg	}
18820253Sjoerg
18920253Sjoerg	// delete the nodes
19020253Sjoerg	if (fNodes) {
19120253Sjoerg		// there shouldn't be any more nodes
19220253Sjoerg		if (fNodes->Size() > 0) {
19320253Sjoerg			WARN("ShareVolume::~ShareVolume(): WARNING: There are still "
19420253Sjoerg				"%ld nodes\n", fNodes->Size());
19520253Sjoerg		}
19620253Sjoerg		for (NodeMap::Iterator it = fNodes->GetIterator(); it.HasNext();)
19720253Sjoerg			delete it.Next().value;
19820253Sjoerg		delete fNodes;
19920253Sjoerg	}
20020253Sjoerg
20120253Sjoerg	// delete the entries
20220253Sjoerg	if (fEntries) {
20320253Sjoerg		// there shouldn't be any more entries
20420253Sjoerg		if (fEntries->Size() > 0) {
20520253Sjoerg			WARN("ShareVolume::~ShareVolume(): WARNING: There are still "
20620253Sjoerg				"%ld entries\n", fEntries->Size());
20720253Sjoerg		}
20820253Sjoerg		for (EntryMap::Iterator it = fEntries->GetIterator(); it.HasNext();)
20920253Sjoerg			delete it.Next().value;
21020253Sjoerg		delete fEntries;
21120747Sdavidn	}
21220253Sjoerg
21320747Sdavidn	delete fLocalNodeIDs;
21420253Sjoerg	delete fRemoteNodeIDs;
21520253Sjoerg
21620253Sjoerg	if (fShareInfo)
21720253Sjoerg		fShareInfo->ReleaseReference();
21820253Sjoerg	if (fServerInfo)
21920747Sdavidn		fServerInfo->ReleaseReference();
22020747Sdavidn	if (fServerConnection)
22120253Sjoerg		fServerConnection->ReleaseReference();
22220253Sjoerg	if (fServerConnectionProvider)
22320253Sjoerg		fServerConnectionProvider->ReleaseReference();
22420747Sdavidn}
22520747Sdavidn
22620253Sjoerg// GetID
22720747Sdavidnnspace_id
22820747SdavidnShareVolume::GetID() const
22920747Sdavidn{
23020253Sjoerg	return fID;
23120747Sdavidn}
23220747Sdavidn
23320747Sdavidn// IsReadOnly
23420747Sdavidnbool
23520747SdavidnShareVolume::IsReadOnly() const
23620747Sdavidn{
23720747Sdavidn	return (fFlags & B_MOUNT_READ_ONLY);
23820747Sdavidn}
23920747Sdavidn
24020747Sdavidn// SupportsQueries
24120747Sdavidnbool
24220253SjoergShareVolume::SupportsQueries() const
24320747Sdavidn{
24420253Sjoerg	return (fSharePermissions & QUERY_SHARE_PERMISSION);
24520253Sjoerg}
24620747Sdavidn
24720747Sdavidn// Init
24820747Sdavidnstatus_t
24920747SdavidnShareVolume::Init(const char* name)
25020747Sdavidn{
25120747Sdavidn	status_t error = Volume::Init(name);
25220747Sdavidn	if (error != B_OK)
25320253Sjoerg		return error;
25420747Sdavidn
25520747Sdavidn	// create node map
25620747Sdavidn	fNodes = new(std::nothrow) NodeMap;
25720747Sdavidn	if (!fNodes)
25820253Sjoerg		RETURN_ERROR(B_NO_MEMORY);
25920747Sdavidn	error = fNodes->InitCheck();
26020747Sdavidn	if (error != B_OK)
26120747Sdavidn		return error;
26220747Sdavidn
26320747Sdavidn	// create entry map
26420747Sdavidn	fEntries = new(std::nothrow) EntryMap;
26520747Sdavidn	if (!fEntries)
26620747Sdavidn		RETURN_ERROR(B_NO_MEMORY);
26720747Sdavidn	error = fEntries->InitCheck();
26820747Sdavidn	if (error != B_OK)
26920747Sdavidn		return error;
27020747Sdavidn
27120747Sdavidn	// create attribute iterator map
27220747Sdavidn	fAttrDirIterators = new(std::nothrow) AttrDirIteratorMap;
27320747Sdavidn	if (!fAttrDirIterators)
27420747Sdavidn		RETURN_ERROR(B_NO_MEMORY);
27520747Sdavidn	error = fAttrDirIterators->InitCheck();
27620747Sdavidn	if (error != B_OK)
27720747Sdavidn		return error;
27820747Sdavidn
27920747Sdavidn	// create local node ID map
28020747Sdavidn	fLocalNodeIDs = new(std::nothrow) LocalNodeIDMap;
28120747Sdavidn	if (!fLocalNodeIDs)
28220747Sdavidn		RETURN_ERROR(B_NO_MEMORY);
28320747Sdavidn	error = fLocalNodeIDs->InitCheck();
28420747Sdavidn	if (error != B_OK)
28520747Sdavidn		return error;
28620747Sdavidn
28720747Sdavidn	// create remote node ID map
28820747Sdavidn	fRemoteNodeIDs = new(std::nothrow) RemoteNodeIDMap;
28920747Sdavidn	if (!fRemoteNodeIDs)
29020747Sdavidn		RETURN_ERROR(B_NO_MEMORY);
29120747Sdavidn	error = fRemoteNodeIDs->InitCheck();
29220747Sdavidn	if (error != B_OK)
29320747Sdavidn		return error;
29420747Sdavidn
29520747Sdavidn	// get a local node ID for our root node
29620747Sdavidn	vnode_id localID = fVolumeManager->NewNodeID(this);
29720747Sdavidn	if (localID < 0)
29820747Sdavidn		return localID;
29920747Sdavidn
30020747Sdavidn	// create the root node
30120747Sdavidn	fRootNode = new(std::nothrow) ShareDir(this, localID, NULL);
30220747Sdavidn	if (!fRootNode) {
30320747Sdavidn		fVolumeManager->RemoveNodeID(localID);
30420747Sdavidn		return B_NO_MEMORY;
30520747Sdavidn	}
30620747Sdavidn
30720747Sdavidn	// add the root node to the node map
30820253Sjoerg	error = fNodes->Put(localID, fRootNode);
30920747Sdavidn	if (error != B_OK)
31020747Sdavidn		return error;
31120747Sdavidn
31220747Sdavidn	return B_OK;
31320747Sdavidn}
31420747Sdavidn
31520747Sdavidn// Uninit
31620747Sdavidnvoid
31720747SdavidnShareVolume::Uninit()
31820747Sdavidn{
31920747Sdavidn	Volume::Uninit();
32020747Sdavidn}
32120747Sdavidn
32220747Sdavidn// GetRootNode
32320747SdavidnNode*
32420747SdavidnShareVolume::GetRootNode() const
32520747Sdavidn{
32620747Sdavidn	return fRootNode;
32720747Sdavidn}
32820747Sdavidn
32920747Sdavidn// PrepareToUnmount
33020747Sdavidnvoid
33120747SdavidnShareVolume::PrepareToUnmount()
33220747Sdavidn{
33320747SdavidnPRINT(("ShareVolume::PrepareToUnmount()\n"));
33420747Sdavidn	Volume::PrepareToUnmount();
33520747Sdavidn
33620747Sdavidn	ConnectionClosed();
33720747Sdavidn
33820747Sdavidn	AutoLocker<Locker> locker(fLock);
33920747Sdavidn
34020747Sdavidn	// remove all entries and send respective "entry removed" events
34120747Sdavidn	for (EntryMap::Iterator it = fEntries->GetIterator(); it.HasNext();) {
34220747Sdavidn		ShareDirEntry* entry = it.Next().value;
34320747Sdavidn
34420253Sjoerg		NotifyListener(B_ENTRY_REMOVED, fVolumeManager->GetID(),
34520253Sjoerg			entry->GetDirectory()->GetID(), 0, entry->GetNode()->GetID(),
34620253Sjoerg			entry->GetName());
34720747Sdavidn
34820253Sjoerg		it.Remove();
34920253Sjoerg		_RemoveEntry(entry);
35020253Sjoerg	}
35120253Sjoerg
35220253Sjoerg	// get all IDs
35320253Sjoerg	int32 count = fNodes->Size();
35420253Sjoerg	if (count == 0)
35520253Sjoerg		return;
35620253Sjoerg	PRINT("  %ld nodes to remove\n", count);
35720253Sjoerg	vnode_id* ids = new(std::nothrow) vnode_id[count];
35820253Sjoerg	if (!ids) {
35920253Sjoerg		ERROR("ShareVolume::PrepareToUnmount(): ERROR: Insufficient memory to "
36020253Sjoerg			"allocate the node ID array!\n");
36120253Sjoerg		return;
36220253Sjoerg	}
36320253Sjoerg	ArrayDeleter<vnode_id> _(ids);
36420253Sjoerg	count = 0;
36520253Sjoerg	for (NodeMap::Iterator it = fNodes->GetIterator(); it.HasNext();) {
36620253Sjoerg		ShareNode* node = it.Next().value;
36720253Sjoerg		ids[count++] = node->GetID();
36820253Sjoerg	}
36920747Sdavidn
37020747Sdavidn	// Remove all nodes that are not known to the VFS right away.
37120253Sjoerg	// If the netfs is already in the process of being unmounted, GetVNode()
37220253Sjoerg	// will fail and the GetVNode(), RemoveVNode(), PutVNode() method won't
37320253Sjoerg	// work for removing them.
37420253Sjoerg	int32 remainingCount = 0;
37520253Sjoerg	for (int32 i = 0; i < count; i++) {
37620253Sjoerg		if (Node* node = fNodes->Get(ids[i])) {
37720253Sjoerg			if (node->IsKnownToVFS()) {
37820253Sjoerg				// node is known to VFS; we need to use the GetVNode(),
37920253Sjoerg				// RemoveVNode(), PutVNode() method
38020253Sjoerg				ids[remainingCount++] = ids[i];
38120253Sjoerg			} else {
38220253Sjoerg				// node is not known to VFS; just remove and delete it
38320253Sjoerg				fNodes->Remove(node->GetID());
38420253Sjoerg				_RemoveLocalNodeID(node->GetID());
38520253Sjoerg				if (node != fRootNode)
38620253Sjoerg					delete node;
38720253Sjoerg			}
38820253Sjoerg		}
38920253Sjoerg	}
39020253Sjoerg	count = remainingCount;
39120253Sjoerg
39220253Sjoerg	locker.Unlock();
39320253Sjoerg
39420253Sjoerg	// remove the nodes
39520253Sjoerg	for (int32 i = 0; i < count; i++) {
39620253Sjoerg		Node* node;
39720253Sjoerg		if (GetVNode(ids[i], &node) == B_OK) {
39820253Sjoerg			PRINT("  removing node %lld\n", ids[i]);
39920253Sjoerg			Volume::RemoveVNode(ids[i]);
40020253Sjoerg			PutVNode(ids[i]);
40120253Sjoerg		}
40220253Sjoerg	}
40320747Sdavidn
40420747Sdavidn	// remove ourselves for the server connection
40520747Sdavidn	if (fServerConnection)
40620747Sdavidn		fServerConnection->RemoveVolume(this);
40720747Sdavidn
40820747Sdavidn	// delete all entries
40920747Sdavidn
41020747SdavidnPRINT(("ShareVolume::PrepareToUnmount() done\n"));
41120253Sjoerg}
41220253Sjoerg
41320253Sjoerg// RemoveChildVolume
41420253Sjoergvoid
41520253SjoergShareVolume::RemoveChildVolume(Volume* volume)
41620253Sjoerg{
41720253Sjoerg	// should never be called
41820253Sjoerg	WARN("WARNING: ShareVolume::RemoveChildVolume(%p) invoked!\n", volume);
41920253Sjoerg}
42020747Sdavidn
42120747Sdavidn
42220747Sdavidn// #pragma mark -
42320747Sdavidn// #pragma mark ----- FS -----
42420747Sdavidn
42520747Sdavidn// Unmount
42620747Sdavidnstatus_t
42720747SdavidnShareVolume::Unmount()
42820747Sdavidn{
42920253Sjoerg	if (_IsConnected()) {
43020253Sjoerg		// send the request
43120253Sjoerg		UnmountRequest request;
43220253Sjoerg		request.volumeID = fID;
43320253Sjoerg		fConnection->SendRequest(&request);
43420253Sjoerg	}
43520253Sjoerg	return B_OK;
43620253Sjoerg}
43720253Sjoerg
43820253Sjoerg// Sync
43920253Sjoergstatus_t
44020253SjoergShareVolume::Sync()
44120253Sjoerg{
44220253Sjoerg	// TODO: Implement?
44320253Sjoerg	// We can't implement this without risking an endless recursion. The server
44420253Sjoerg	// could only invoke sync(), which would sync all FSs, including a NetFS
44520253Sjoerg	// which might be connected with a server running alongside this client.
44620253Sjoerg	// We could introduce a sync flag to break the recursion. This might be
44720253Sjoerg	// risky though.
44820253Sjoerg	return B_OK;
44920253Sjoerg}
45020253Sjoerg
45120253Sjoerg
45220253Sjoerg// #pragma mark -
45320253Sjoerg// #pragma mark ----- vnodes -----
45420253Sjoerg
45520253Sjoerg// ReadVNode
45620253Sjoergstatus_t
45720253SjoergShareVolume::ReadVNode(vnode_id vnid, char reenter, Node** _node)
45820253Sjoerg{
45920253Sjoerg	// check the map, maybe it's already loaded
46020253Sjoerg	ShareNode* node = NULL;
46120253Sjoerg	{
46220253Sjoerg		AutoLocker<Locker> _(fLock);
46320253Sjoerg		node = _GetNodeByLocalID(vnid);
46420253Sjoerg		if (node) {
46520253Sjoerg			node->SetKnownToVFS(true);
46620253Sjoerg			*_node = node;
46720253Sjoerg
46820253Sjoerg			// add a volume reference for the node
46920253Sjoerg			AcquireReference();
47020253Sjoerg
47120253Sjoerg			return B_OK;
47220253Sjoerg		}
47320253Sjoerg	}
47420253Sjoerg
47520747Sdavidn	// not yet loaded: send a request to the server
47620253Sjoerg	if (!_EnsureShareMounted())
47720253Sjoerg		return ERROR_NOT_CONNECTED;
47820253Sjoerg
47920253Sjoerg	// get the remote ID
48020253Sjoerg	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	AcquireReference();
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(std::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(std::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(std::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{
1169		PRINT("OpenDir() failed: node: %lld, remote: (%ld, %lld)\n",
1170			node->GetID(), node->GetRemoteID().volumeID,
1171			node->GetRemoteID().nodeID);
1172		RETURN_ERROR(reply->error);
1173}
1174
1175	// update the node
1176	_UpdateNode(reply->nodeInfo);
1177
1178	// init the cookie
1179	iterator->SetCookie(reply->cookie);
1180	cookie->iterator = iterator;
1181
1182	*_cookie = cookie;
1183	cookieDeleter.Detach();
1184	iteratorDeleter.Detach();
1185	return B_OK;
1186}
1187
1188// CloseDir
1189status_t
1190ShareVolume::CloseDir(Node* _node, void* cookie)
1191{
1192	// no-op: FreeDirCookie does the job
1193	return B_OK;
1194}
1195
1196// FreeDirCookie
1197status_t
1198ShareVolume::FreeDirCookie(Node* _node, void* _cookie)
1199{
1200	DirCookie* cookie = (DirCookie*)_cookie;
1201	ObjectDeleter<DirCookie> _(cookie);
1202	ShareDirIterator* iterator = cookie->iterator;
1203
1204	status_t error = B_OK;
1205	if (RemoteShareDirIterator* remoteIterator
1206		= dynamic_cast<RemoteShareDirIterator*>(iterator)) {
1207		// prepare the request
1208		CloseRequest request;
1209		request.volumeID = fID;
1210		request.cookie = remoteIterator->GetCookie();
1211
1212		// send the request
1213		if (!_EnsureShareMounted())
1214			error = ERROR_NOT_CONNECTED;
1215
1216		if (error == B_OK) {
1217			CloseReply* reply;
1218			error = SendRequest(fConnection, &request, &reply);
1219			if (error == B_OK) {
1220				error = reply->error;
1221				delete reply;
1222			}
1223		}
1224	}
1225
1226	// delete the iterator
1227	AutoLocker<Locker> locker(fLock);
1228	delete iterator;
1229
1230	return error;
1231}
1232
1233// ReadDir
1234status_t
1235ShareVolume::ReadDir(Node* _dir, void* _cookie, struct dirent* buffer,
1236	size_t bufferSize, int32 count, int32* countRead)
1237{
1238	ShareDir* directory = dynamic_cast<ShareDir*>(_dir);
1239
1240	if (!_EnsureShareMounted())
1241		return ERROR_NOT_CONNECTED;
1242
1243	*countRead = 0;
1244	if (count <= 0)
1245		return B_OK;
1246
1247	DirCookie* cookie = (DirCookie*)_cookie;
1248	ShareDirIterator* iterator = cookie->iterator;
1249
1250	while (true) {
1251		status_t error;
1252		AutoLocker<Locker> locker(fLock);
1253		while (ShareDirEntry* entry = iterator->GetCurrentEntry()) {
1254			// re-get the entry -- it might already have been removed
1255			const char* name = entry->GetName();
1256			entry = _GetEntryByLocalID(directory->GetID(), name);
1257			if (entry) {
1258				// set the name: this also checks the size of the buffer
1259				error = set_dirent_name(buffer, bufferSize, name,
1260					strlen(name));
1261				if (error != B_OK) {
1262					// if something has been read at all, we're content
1263					if (*countRead > 0)
1264						return B_OK;
1265					RETURN_ERROR(error);
1266				}
1267
1268				// fill in the other fields
1269				buffer->d_pdev = fVolumeManager->GetID();
1270				buffer->d_pino = directory->GetID();
1271				buffer->d_dev = fVolumeManager->GetID();
1272				buffer->d_ino = entry->GetNode()->GetID();
1273
1274				// if the entry is the parent of the share root, we need to
1275				// fix the node ID
1276				if (directory == fRootNode && strcmp(name, "..") == 0) {
1277					if (Volume* parentVolume = GetParentVolume())
1278						buffer->d_ino = parentVolume->GetRootID();
1279				}
1280
1281				iterator->NextEntry();
1282				(*countRead)++;
1283				if (*countRead >= count || !next_dirent(buffer, bufferSize))
1284					return B_OK;
1285			} else
1286				iterator->NextEntry();
1287		}
1288
1289		// no more entries: check, if we're completely through
1290		if (iterator->IsDone())
1291			return B_OK;
1292
1293		// we need to actually get entries from the server
1294		locker.Unlock();
1295		if (RemoteShareDirIterator* remoteIterator
1296				= dynamic_cast<RemoteShareDirIterator*>(iterator)) {
1297			error = _ReadRemoteDir(directory, remoteIterator);
1298			if (error != B_OK)
1299				return error;
1300		}
1301	}
1302}
1303
1304// RewindDir
1305status_t
1306ShareVolume::RewindDir(Node* _node, void* _cookie)
1307{
1308	DirCookie* cookie = (DirCookie*)_cookie;
1309	ShareDirIterator* iterator = cookie->iterator;
1310	AutoLocker<Locker> _(fLock);
1311	iterator->Rewind();
1312	return B_OK;
1313}
1314
1315// Walk
1316status_t
1317ShareVolume::Walk(Node* _dir, const char* entryName, char** resolvedPath,
1318	vnode_id* vnid)
1319{
1320	ShareDir* dir = dynamic_cast<ShareDir*>(_dir);
1321	if (!dir)
1322		return B_BAD_VALUE;
1323
1324	// we always resolve "." and ".." of the root node
1325	if (dir == fRootNode) {
1326		if (strcmp(entryName, ".") == 0 || strcmp(entryName, "..") == 0) {
1327			AutoLocker<Locker> _(fLock);
1328			if (strcmp(entryName, ".") == 0) {
1329				*vnid = fRootNode->GetID();
1330			} else if (Volume* parentVolume = GetParentVolume()) {
1331				*vnid = parentVolume->GetRootID();
1332			} else
1333				*vnid = fRootNode->GetID();
1334			Node* node;
1335			return GetVNode(*vnid, &node);
1336		}
1337	}
1338
1339	if (!_EnsureShareMounted())
1340		return ERROR_NOT_CONNECTED;
1341
1342	// check, if the entry is already known
1343	{
1344		AutoLocker<Locker> _(fLock);
1345		ShareDirEntry* entry = _GetEntryByLocalID(dir->GetID(), entryName);
1346		if (entry) {
1347			*vnid = entry->GetNode()->GetID();
1348			Node* node;
1349			return GetVNode(*vnid, &node);
1350		} else if (dir->IsComplete())
1351			return B_ENTRY_NOT_FOUND;
1352	}
1353
1354	WalkReply* reply;
1355	while (true) {
1356		// send the request
1357		status_t error = _Walk(dir->GetRemoteID(), entryName, resolvedPath,
1358			&reply);
1359		if (error != B_OK)
1360			RETURN_ERROR(error);
1361		ObjectDeleter<Request> replyDeleter(reply);
1362
1363		AutoLocker<Locker> locker(fLock);
1364
1365		// check, if the returned info is obsolete
1366		if (_IsObsoleteEntryInfo(reply->entryInfo))
1367			continue;
1368
1369		// load the entry
1370		ShareDirEntry* entry;
1371		error = _LoadEntry(dir, reply->entryInfo, &entry);
1372		if (error != B_OK)
1373			RETURN_ERROR(error);
1374		*vnid = entry->GetNode()->GetID();
1375
1376		// deal with symlinks
1377		if (reply->linkPath.GetString() && resolvedPath) {
1378			*resolvedPath = strdup(reply->linkPath.GetString());
1379			if (!*resolvedPath)
1380				RETURN_ERROR(B_NO_MEMORY);
1381			return B_OK;
1382		}
1383
1384		break;
1385	}
1386
1387	// no symlink or we shall not resolve it: get the node
1388	Node* _node;
1389	RETURN_ERROR(GetVNode(*vnid, &_node));
1390}
1391
1392
1393// #pragma mark -
1394// #pragma mark ----- attributes -----
1395
1396// OpenAttrDir
1397status_t
1398ShareVolume::OpenAttrDir(Node* _node, void** _cookie)
1399{
1400	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1401
1402// TODO: Allow opening the root node?
1403	if (!_EnsureShareMounted())
1404		return ERROR_NOT_CONNECTED;
1405
1406	// allocate a dir cookie
1407	AttrDirCookie* cookie = new(std::nothrow) AttrDirCookie;
1408	if (!cookie)
1409		RETURN_ERROR(B_NO_MEMORY);
1410	ObjectDeleter<AttrDirCookie> cookieDeleter(cookie);
1411
1412	AutoLocker<Locker> locker(fLock);
1413
1414	if (!node->GetAttrDir() || !node->GetAttrDir()->IsUpToDate()) {
1415		// prepare the request
1416		OpenAttrDirRequest request;
1417		request.volumeID = fID;
1418		request.nodeID = node->GetRemoteID();
1419
1420		locker.Unlock();
1421
1422		// send the request
1423		OpenAttrDirReply* reply;
1424		status_t error = SendRequest(fConnection, &request, &reply);
1425		if (error != B_OK)
1426			RETURN_ERROR(error);
1427		ObjectDeleter<Request> replyDeleter(reply);
1428		if (reply->error != B_OK)
1429			RETURN_ERROR(reply->error);
1430
1431		// If no AttrDirInfo was supplied, we just save the cookie and be done.
1432		// This usually happens when the attr dir is too big to be cached.
1433		if (!reply->attrDirInfo.isValid) {
1434			cookie->cookie = reply->cookie;
1435			cookie->rewind = false;
1436			*_cookie = cookie;
1437			cookieDeleter.Detach();
1438			return B_OK;
1439		}
1440
1441		locker.SetTo(fLock, false);
1442
1443		// a AttrDirInfo has been supplied: load the attr dir
1444		error = _LoadAttrDir(node, reply->attrDirInfo);
1445		if (error != B_OK)
1446			return error;
1447	}
1448
1449	// we have a valid attr dir: create an attr dir iterator
1450	ShareAttrDirIterator* iterator = new(std::nothrow) ShareAttrDirIterator;
1451	if (!iterator)
1452		return B_NO_MEMORY;
1453	iterator->SetAttrDir(node->GetAttrDir());
1454
1455	// add the iterator
1456	status_t error = _AddAttrDirIterator(node, iterator);
1457	if (error != B_OK) {
1458		delete iterator;
1459		return error;
1460	}
1461
1462	cookie->iterator = iterator;
1463	*_cookie = cookie;
1464	cookieDeleter.Detach();
1465	return B_OK;
1466}
1467
1468// CloseAttrDir
1469status_t
1470ShareVolume::CloseAttrDir(Node* _node, void* cookie)
1471{
1472	// no-op: FreeAttrDirCookie does the job
1473	return B_OK;
1474}
1475
1476// FreeAttrDirCookie
1477status_t
1478ShareVolume::FreeAttrDirCookie(Node* _node, void* _cookie)
1479{
1480	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1481	AttrDirCookie* cookie = (AttrDirCookie*)_cookie;
1482	ObjectDeleter<AttrDirCookie> _(cookie);
1483
1484	// if this is a local iterator, we just delete it and be done
1485	if (cookie->iterator) {
1486		AutoLocker<Locker> locker(fLock);
1487
1488		// remove and delete the iterator
1489		_RemoveAttrDirIterator(node, cookie->iterator);
1490		delete cookie->iterator;
1491
1492		return B_OK;
1493	}
1494
1495	// prepare the request
1496	CloseRequest request;
1497	request.volumeID = fID;
1498	request.cookie = cookie->cookie;
1499
1500	// send the request
1501	if (!_EnsureShareMounted())
1502		return ERROR_NOT_CONNECTED;
1503	CloseReply* reply;
1504	status_t error = SendRequest(fConnection, &request, &reply);
1505	if (error != B_OK)
1506		RETURN_ERROR(error);
1507	ObjectDeleter<Request> replyDeleter(reply);
1508	if (reply->error != B_OK)
1509		RETURN_ERROR(reply->error);
1510
1511	return B_OK;
1512}
1513
1514// ReadAttrDir
1515status_t
1516ShareVolume::ReadAttrDir(Node* _node, void* _cookie, struct dirent* buffer,
1517	size_t bufferSize, int32 count, int32* countRead)
1518{
1519	if (!_EnsureShareMounted())
1520		return ERROR_NOT_CONNECTED;
1521
1522	*countRead = 0;
1523	AttrDirCookie* cookie = (AttrDirCookie*)_cookie;
1524
1525	// if we have a local iterator, things are easy
1526	if (ShareAttrDirIterator* iterator = cookie->iterator) {
1527		AutoLocker<Locker> locker(fLock);
1528
1529		// get the current attribute
1530		Attribute* attribute = iterator->GetCurrentAttribute();
1531		if (!attribute)
1532			return B_OK;
1533
1534		// set the name: this also checks the size of the buffer
1535		const char* name = attribute->GetName();
1536		status_t error = set_dirent_name(buffer, bufferSize, name,
1537			strlen(name));
1538		if (error != B_OK)
1539			RETURN_ERROR(error);
1540
1541		// fill in the other fields
1542		buffer->d_dev = fVolumeManager->GetID();
1543		buffer->d_ino = -1;
1544		*countRead = 1;
1545
1546		iterator->NextAttribute();
1547		return B_OK;
1548	}
1549
1550	// prepare the request
1551	ReadAttrDirRequest request;
1552	request.volumeID = fID;
1553	request.cookie = cookie->cookie;
1554	request.count = 1;
1555	request.rewind = cookie->rewind;
1556
1557	// send the request
1558	ReadAttrDirReply* reply;
1559	status_t error = SendRequest(fConnection, &request, &reply);
1560	if (error != B_OK)
1561		RETURN_ERROR(error);
1562	ObjectDeleter<Request> replyDeleter(reply);
1563	if (reply->error != B_OK)
1564		RETURN_ERROR(reply->error);
1565	cookie->rewind = false;
1566
1567	// check, if anything has been read at all
1568	if (reply->count == 0) {
1569		*countRead = 0;
1570		return B_OK;
1571	}
1572	const char* name = reply->name.GetString();
1573	int32 nameLen = reply->name.GetSize();
1574	if (!name || nameLen < 2)
1575		return B_BAD_DATA;
1576
1577	// set the name: this also checks the size of the buffer
1578	error = set_dirent_name(buffer, bufferSize, name, nameLen - 1);
1579	if (error != B_OK)
1580		RETURN_ERROR(error);
1581
1582	// fill in the other fields
1583	buffer->d_dev = fVolumeManager->GetID();
1584	buffer->d_ino = -1;
1585	*countRead = 1;
1586	return B_OK;
1587}
1588
1589// RewindAttrDir
1590status_t
1591ShareVolume::RewindAttrDir(Node* _node, void* _cookie)
1592{
1593	AttrDirCookie* cookie = (AttrDirCookie*)_cookie;
1594
1595	// if we have a local iterator, rewind it
1596	if (ShareAttrDirIterator* iterator = cookie->iterator) {
1597		AutoLocker<Locker> locker(fLock);
1598
1599		iterator->Rewind();
1600	} else
1601		cookie->rewind = true;
1602
1603	return B_OK;
1604}
1605
1606// ReadAttr
1607status_t
1608ShareVolume::ReadAttr(Node* _node, const char* name, int type, off_t pos,
1609	void* _buffer, size_t bufferSize, size_t* _bytesRead)
1610{
1611	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1612
1613	if (!_EnsureShareMounted())
1614		return ERROR_NOT_CONNECTED;
1615
1616	*_bytesRead = 0;
1617	if (bufferSize == 0)
1618		return B_OK;
1619	uint8* buffer = (uint8*)_buffer;
1620
1621	// if we have the attribute directory cached, we can first check, if the
1622	// attribute exists at all -- maybe its data are cached, too
1623	{
1624		AutoLocker<Locker> locker(fLock);
1625
1626		ShareAttrDir* attrDir = node->GetAttrDir();
1627		if (attrDir && attrDir->IsUpToDate()) {
1628			// get the attribute
1629			Attribute* attribute = attrDir->GetAttribute(name);
1630			if (!attribute)
1631				return B_ENTRY_NOT_FOUND;
1632
1633			// get the data
1634			if (const void* data = attribute->GetData()) {
1635				// first check, if we can read anything at all
1636				if (pos < 0)
1637					pos = 0;
1638				int32 size = attribute->GetSize();
1639				if (pos >= size)
1640					return B_OK;
1641
1642				// get the data
1643				bufferSize = min(bufferSize, size_t(size - pos));
1644				memcpy(buffer, data, bufferSize);
1645				*_bytesRead = bufferSize;
1646				return B_OK;
1647			}
1648		}
1649	}
1650
1651	// prepare the request
1652	ReadAttrRequest request;
1653	request.volumeID = fID;
1654	request.nodeID = node->GetRemoteID();
1655	request.name.SetTo(name);
1656	request.type = type;
1657	request.pos = pos;
1658	request.size = bufferSize;
1659
1660	struct ReadRequestHandler : public RequestHandler {
1661		uint8*	buffer;
1662		off_t	pos;
1663		int32	bufferSize;
1664		int32	bytesRead;
1665
1666		ReadRequestHandler(uint8* buffer, off_t pos, int32 bufferSize)
1667			: buffer(buffer),
1668			  pos(pos),
1669			  bufferSize(bufferSize),
1670			  bytesRead(0)
1671		{
1672		}
1673
1674		virtual status_t HandleRequest(Request* _reply, RequestChannel* channel)
1675		{
1676			// the passed request is deleted by the request port
1677			ReadAttrReply* reply = dynamic_cast<ReadAttrReply*>(_reply);
1678			if (!reply)
1679				RETURN_ERROR(B_BAD_DATA);
1680			// process the reply
1681			status_t error = ProcessReply(reply);
1682			if (error != B_OK)
1683				return error;
1684			bool moreToCome = reply->moreToCome;
1685			while (moreToCome) {
1686				// receive a reply
1687				error = ReceiveRequest(channel, &reply);
1688				if (error != B_OK)
1689					RETURN_ERROR(error);
1690				moreToCome = reply->moreToCome;
1691				ObjectDeleter<Request> replyDeleter(reply);
1692				// process the reply
1693				error = ProcessReply(reply);
1694				if (error != B_OK)
1695					return error;
1696			}
1697			return B_OK;
1698		}
1699
1700		status_t ProcessReply(ReadAttrReply* reply)
1701		{
1702			if (reply->error != B_OK)
1703				RETURN_ERROR(reply->error);
1704			// check the fields
1705			if (reply->pos != pos)
1706				RETURN_ERROR(B_BAD_DATA);
1707			int32 bytesRead = reply->data.GetSize();
1708			if (bytesRead > (int32)bufferSize)
1709				RETURN_ERROR(B_BAD_DATA);
1710			// copy the data into the buffer
1711			if (bytesRead > 0)
1712				memcpy(buffer, reply->data.GetData(), bytesRead);
1713			pos += bytesRead;
1714			buffer += bytesRead;
1715			bufferSize -= bytesRead;
1716			this->bytesRead += bytesRead;
1717			return B_OK;
1718		}
1719	} requestHandler(buffer, pos, bufferSize);
1720
1721	// send the request
1722	status_t error = fConnection->SendRequest(&request, &requestHandler);
1723	if (error != B_OK)
1724		RETURN_ERROR(error);
1725	*_bytesRead = requestHandler.bytesRead;
1726	return B_OK;
1727}
1728
1729// WriteAttr
1730status_t
1731ShareVolume::WriteAttr(Node* _node, const char* name, int type, off_t pos,
1732	const void* _buffer, size_t bufferSize, size_t* bytesWritten)
1733{
1734	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1735
1736	if (!_EnsureShareMounted())
1737		return ERROR_NOT_CONNECTED;
1738
1739	// check permissions
1740	if (IsReadOnly())
1741		return B_PERMISSION_DENIED;
1742
1743	*bytesWritten = 0;
1744	off_t bytesLeft = bufferSize;
1745	const char* buffer = (const char*)_buffer;
1746	while (bytesLeft > 0) {
1747		// store the current attibute dir revision for reference below
1748		int64 attrDirRevision = -1;
1749		{
1750			AutoLocker<Locker> _(fLock);
1751			if (ShareAttrDir* attrDir = node->GetAttrDir()) {
1752				if (attrDir->IsUpToDate())
1753					attrDirRevision = attrDir->GetRevision();
1754			}
1755		}
1756
1757		off_t toWrite = bytesLeft;
1758		if (toWrite > kMaxWriteBufferSize)
1759			toWrite = kMaxWriteBufferSize;
1760
1761		// prepare the request
1762		WriteAttrRequest request;
1763		request.volumeID = fID;
1764		request.nodeID = node->GetRemoteID();
1765		request.name.SetTo(name);
1766		request.type = type;
1767		request.pos = pos;
1768		request.data.SetTo(buffer, toWrite);
1769
1770		// send the request
1771		WriteAttrReply* reply;
1772		status_t error = SendRequest(fConnection, &request, &reply);
1773		if (error != B_OK)
1774			RETURN_ERROR(error);
1775
1776		ObjectDeleter<Request> replyDeleter(reply);
1777		if (reply->error != B_OK)
1778			RETURN_ERROR(reply->error);
1779
1780		bytesLeft -= toWrite;
1781		pos += toWrite;
1782		buffer += toWrite;
1783
1784		// If the request was successful, we consider the cached attr dir
1785		// no longer up to date.
1786		if (attrDirRevision >= 0) {
1787			AutoLocker<Locker> _(fLock);
1788			ShareAttrDir* attrDir = node->GetAttrDir();
1789			if (attrDir && attrDir->GetRevision() == attrDirRevision)
1790				attrDir->SetUpToDate(false);
1791		}
1792	}
1793
1794	*bytesWritten = bufferSize;
1795	return B_OK;
1796}
1797
1798// RemoveAttr
1799status_t
1800ShareVolume::RemoveAttr(Node* _node, const char* name)
1801{
1802	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1803
1804	if (!_EnsureShareMounted())
1805		return ERROR_NOT_CONNECTED;
1806
1807	// check permissions
1808	if (IsReadOnly())
1809		return B_PERMISSION_DENIED;
1810
1811	// store the current attibute dir revision for reference below
1812	int64 attrDirRevision = -1;
1813	{
1814		AutoLocker<Locker> _(fLock);
1815		if (ShareAttrDir* attrDir = node->GetAttrDir()) {
1816			if (attrDir->IsUpToDate())
1817				attrDirRevision = attrDir->GetRevision();
1818		}
1819	}
1820
1821	// prepare the request
1822	RemoveAttrRequest request;
1823	request.volumeID = fID;
1824	request.nodeID = node->GetRemoteID();
1825	request.name.SetTo(name);
1826
1827	// send the request
1828	RemoveAttrReply* reply;
1829	status_t error = SendRequest(fConnection, &request, &reply);
1830	if (error != B_OK)
1831		RETURN_ERROR(error);
1832	ObjectDeleter<Request> replyDeleter(reply);
1833
1834	// If the request was successful, we consider the cached attr dir
1835	// no longer up to date.
1836	if (reply->error == B_OK && attrDirRevision >= 0) {
1837		AutoLocker<Locker> _(fLock);
1838		ShareAttrDir* attrDir = node->GetAttrDir();
1839		if (attrDir && attrDir->GetRevision() == attrDirRevision)
1840			attrDir->SetUpToDate(false);
1841	}
1842
1843	RETURN_ERROR(reply->error);
1844}
1845
1846// RenameAttr
1847status_t
1848ShareVolume::RenameAttr(Node* _node, const char* oldName, const char* newName)
1849{
1850	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1851
1852	if (!_EnsureShareMounted())
1853		return ERROR_NOT_CONNECTED;
1854
1855	// check permissions
1856	if (IsReadOnly())
1857		return B_PERMISSION_DENIED;
1858
1859	// store the current attibute dir revision for reference below
1860	int64 attrDirRevision = -1;
1861	{
1862		AutoLocker<Locker> _(fLock);
1863		if (ShareAttrDir* attrDir = node->GetAttrDir()) {
1864			if (attrDir->IsUpToDate())
1865				attrDirRevision = attrDir->GetRevision();
1866		}
1867	}
1868
1869	// prepare the request
1870	RenameAttrRequest request;
1871	request.volumeID = fID;
1872	request.nodeID = node->GetRemoteID();
1873	request.oldName.SetTo(oldName);
1874	request.newName.SetTo(newName);
1875
1876	// send the request
1877	RenameAttrReply* reply;
1878	status_t error = SendRequest(fConnection, &request, &reply);
1879	if (error != B_OK)
1880		RETURN_ERROR(error);
1881	ObjectDeleter<Request> replyDeleter(reply);
1882
1883	// If the request was successful, we consider the cached attr dir
1884	// no longer up to date.
1885	if (reply->error == B_OK && attrDirRevision >= 0) {
1886		AutoLocker<Locker> _(fLock);
1887		ShareAttrDir* attrDir = node->GetAttrDir();
1888		if (attrDir && attrDir->GetRevision() == attrDirRevision)
1889			attrDir->SetUpToDate(false);
1890	}
1891
1892	RETURN_ERROR(reply->error);
1893}
1894
1895// StatAttr
1896status_t
1897ShareVolume::StatAttr(Node* _node, const char* name, struct attr_info* attrInfo)
1898{
1899	ShareNode* node = dynamic_cast<ShareNode*>(_node);
1900
1901	if (!_EnsureShareMounted())
1902		return ERROR_NOT_CONNECTED;
1903
1904	// if we have the attribute directory cached, get the info from there
1905	{
1906		AutoLocker<Locker> locker(fLock);
1907
1908		ShareAttrDir* attrDir = node->GetAttrDir();
1909		if (attrDir && attrDir->IsUpToDate()) {
1910			// get the attribute
1911			Attribute* attribute = attrDir->GetAttribute(name);
1912			if (!attribute)
1913				return B_ENTRY_NOT_FOUND;
1914
1915			attribute->GetInfo(attrInfo);
1916			return B_OK;
1917		}
1918	}
1919
1920	// prepare the request
1921	StatAttrRequest request;
1922	request.volumeID = fID;
1923	request.nodeID = node->GetRemoteID();
1924	request.name.SetTo(name);
1925
1926	// send the request
1927	StatAttrReply* reply;
1928	status_t error = SendRequest(fConnection, &request, &reply);
1929	if (error != B_OK)
1930		RETURN_ERROR(error);
1931	ObjectDeleter<Request> replyDeleter(reply);
1932	if (reply->error != B_OK)
1933		RETURN_ERROR(reply->error);
1934
1935	// set the result
1936	*attrInfo = reply->attrInfo.info;
1937	return B_OK;
1938}
1939
1940
1941// #pragma mark -
1942// #pragma mark ----- queries -----
1943
1944// GetQueryEntry
1945status_t
1946ShareVolume::GetQueryEntry(const EntryInfo& entryInfo,
1947	const NodeInfo& dirInfo, struct dirent* buffer, size_t bufferSize,
1948	int32* countRead)
1949{
1950	status_t error = B_OK;
1951
1952	const char* name = entryInfo.name.GetString();
1953	int32 nameLen = entryInfo.name.GetSize();
1954	if (!name || nameLen < 2)
1955		RETURN_ERROR(B_BAD_DATA);
1956
1957	// load the directory
1958	vnode_id localDirID = -1;
1959	{
1960		AutoLocker<Locker> _(fLock);
1961		ShareNode* node;
1962		error = _LoadNode(dirInfo, &node);
1963		if (error != B_OK)
1964			RETURN_ERROR(error);
1965		ShareDir* directory = dynamic_cast<ShareDir*>(node);
1966		if (!directory)
1967			RETURN_ERROR(B_ENTRY_NOT_FOUND);
1968		localDirID = directory->GetID();
1969	}
1970
1971	// add/update the entry
1972	vnode_id localNodeID = -1;
1973	const EntryInfo* resolvedEntryInfo = &entryInfo;
1974	while (error == B_OK) {
1975		// get an up to date entry info
1976		WalkReply* walkReply = NULL;
1977		if (!resolvedEntryInfo) {
1978			error = _Walk(entryInfo.directoryID, name, false,
1979				&walkReply);
1980			if (error != B_OK)
1981				RETURN_ERROR(error);
1982
1983			resolvedEntryInfo = &walkReply->entryInfo;
1984		}
1985		ObjectDeleter<Request> walkReplyDeleter(walkReply);
1986
1987		AutoLocker<Locker> locker(fLock);
1988
1989		// check, if the info is obsolete
1990		if (_IsObsoleteEntryInfo(*resolvedEntryInfo)) {
1991			resolvedEntryInfo = NULL;
1992			continue;
1993		}
1994
1995		// get the directory
1996		ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByLocalID(localDirID));
1997		if (!dir)
1998			RETURN_ERROR(B_ERROR);
1999
2000		// load the entry
2001		ShareDirEntry* entry;
2002		error = _LoadEntry(dir, *resolvedEntryInfo, &entry);
2003		if (error == B_OK)
2004			localNodeID = entry->GetNode()->GetID();
2005
2006		break;
2007	}
2008
2009	// set the name: this also checks the size of the buffer
2010	error = set_dirent_name(buffer, bufferSize, name, nameLen - 1);
2011	if (error != B_OK)
2012		RETURN_ERROR(error);
2013
2014	// fill in the other fields
2015	buffer->d_pdev = fVolumeManager->GetID();
2016	buffer->d_pino = localDirID;
2017	buffer->d_dev = fVolumeManager->GetID();
2018	buffer->d_ino = localNodeID;
2019
2020	*countRead = 1;
2021	PRINT("  entry: d_dev: %ld, d_pdev: %ld, d_ino: %Ld, d_pino: %Ld, "
2022		"d_reclen: %hu, d_name: `%s'\n", buffer->d_dev, buffer->d_pdev,
2023		buffer->d_ino, buffer->d_pino, buffer->d_reclen,
2024		buffer->d_name);
2025	return B_OK;
2026}
2027
2028
2029// #pragma mark -
2030
2031// ProcessNodeMonitoringRequest
2032void
2033ShareVolume::ProcessNodeMonitoringRequest(NodeMonitoringRequest* request)
2034{
2035	switch (request->opcode) {
2036		case B_ENTRY_CREATED:
2037			_HandleEntryCreatedRequest(
2038				dynamic_cast<EntryCreatedRequest*>(request));
2039			break;
2040		case B_ENTRY_REMOVED:
2041			_HandleEntryRemovedRequest(
2042				dynamic_cast<EntryRemovedRequest*>(request));
2043			break;
2044		case B_ENTRY_MOVED:
2045			_HandleEntryMovedRequest(
2046				dynamic_cast<EntryMovedRequest*>(request));
2047			break;
2048		case B_STAT_CHANGED:
2049			_HandleStatChangedRequest(
2050				dynamic_cast<StatChangedRequest*>(request));
2051			break;
2052		case B_ATTR_CHANGED:
2053			_HandleAttributeChangedRequest(
2054				dynamic_cast<AttributeChangedRequest*>(request));
2055			break;
2056	}
2057}
2058
2059// ConnectionClosed
2060void
2061ShareVolume::ConnectionClosed()
2062{
2063	AutoLocker<Locker> _(fMountLock);
2064	fConnectionState = CONNECTION_CLOSED;
2065}
2066
2067
2068// #pragma mark -
2069
2070// _ReadRemoteDir
2071status_t
2072ShareVolume::_ReadRemoteDir(ShareDir* directory,
2073	RemoteShareDirIterator* iterator)
2074{
2075	// prepare the request
2076	fLock.Lock();
2077	ReadDirRequest request;
2078	request.volumeID = fID;
2079	request.cookie = iterator->GetCookie();
2080	request.count = iterator->GetCapacity();
2081	request.rewind = iterator->GetRewind();
2082	fLock.Unlock();
2083
2084	// send the request
2085	ReadDirReply* reply;
2086	status_t error = SendRequest(fConnection, &request, &reply);
2087	if (error != B_OK)
2088		RETURN_ERROR(error);
2089	ObjectDeleter<Request> replyDeleter(reply);
2090	if (reply->error != B_OK)
2091		RETURN_ERROR(reply->error);
2092
2093	RequestMemberArray<EntryInfo>* entryInfos = &reply->entryInfos;
2094	while (true) {
2095		// get up to date entry infos
2096		MultiWalkReply* walkReply = NULL;
2097		if (!entryInfos) {
2098			error = _MultiWalk(reply->entryInfos, &walkReply);
2099			if (error != B_OK)
2100				RETURN_ERROR(error);
2101
2102			entryInfos = &walkReply->entryInfos;
2103		}
2104		ObjectDeleter<Request> walkReplyDeleter(walkReply);
2105
2106		AutoLocker<Locker> locker(fLock);
2107
2108		// check, if any info is obsolete
2109		int32 count = entryInfos->CountElements();
2110		for (int32 i = 0; i < count; i++) {
2111			const EntryInfo& entryInfo = entryInfos->GetElements()[i];
2112			if (_IsObsoleteEntryInfo(entryInfo)) {
2113				entryInfos = NULL;
2114				continue;
2115			}
2116		}
2117
2118		// init the iterator's revision, if it's new or has been rewinded
2119		if (request.rewind || iterator->GetRevision() < 0)
2120			iterator->SetRevision(reply->revision);
2121
2122		iterator->Clear();
2123		iterator->SetDone(reply->done);
2124
2125		// iterate through the entries
2126		for (int32 i = 0; i < count; i++) {
2127			const EntryInfo& entryInfo = entryInfos->GetElements()[i];
2128			const char* name = entryInfo.name.GetString();
2129			int32 nameLen = entryInfo.name.GetSize();
2130			if (!name || nameLen < 2)
2131				return B_BAD_DATA;
2132
2133			// load the node/entry
2134			ShareDirEntry* entry;
2135			error = _LoadEntry(directory, entryInfo, &entry);
2136			if (error != B_OK)
2137				RETURN_ERROR(error);
2138
2139			// add the entry
2140			if (!iterator->AddEntry(entry)) {
2141				ERROR("ShareVolume::_ReadRemoteDir(): ERROR: Failed to add "
2142					"entry to remote iterator!\n");
2143			}
2144		}
2145
2146		// directory now complete?
2147		if (reply->done && directory->GetEntryRemovedEventRevision()
2148				< iterator->GetRevision()) {
2149			directory->SetComplete(true);
2150		}
2151
2152		break;
2153	}
2154
2155	return B_OK;
2156}
2157
2158// _HandleEntryCreatedRequest
2159void
2160ShareVolume::_HandleEntryCreatedRequest(EntryCreatedRequest* request)
2161{
2162	if (!request)
2163		return;
2164
2165	nspace_id nsid = fVolumeManager->GetID();
2166	const char* name = request->name.GetString();
2167
2168	// translate the node IDs
2169	vnode_id vnida = 0;
2170	vnode_id vnidb = 0;
2171	vnode_id vnidc = 0;
2172	status_t error = _GetLocalNodeID(request->directoryID, &vnida, true);
2173	if (error == B_OK)
2174		error = _GetLocalNodeID(request->nodeID, &vnidc, true);
2175		PRINT("ShareVolume::_HandleEntryCreatedRequest(): error: 0x%lx,"
2176			" name: \"%s\", dir: %lld (remote: (%ld, %lld)), node:"
2177			" %lld (remote: (%ld, %lld))\n", error, name, vnida,
2178			request->directoryID.volumeID,
2179			request->directoryID.nodeID, vnidc,
2180			request->nodeID.volumeID, request->nodeID.nodeID);
2181
2182	// send notifications / do additional processing
2183	if (request->queryUpdate) {
2184		if (error == B_OK) {
2185			SendNotification(request->port, request->token,
2186				B_QUERY_UPDATE, request->opcode, nsid, 0, vnida, vnidb,
2187				vnidc, name);
2188		}
2189	} else {
2190		_EntryCreated(request->directoryID, name,
2191			(request->entryInfoValid ? &request->entryInfo : NULL),
2192			request->revision);
2193		if (error == B_OK)
2194			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name);
2195	}
2196}
2197
2198// _HandleEntryRemovedRequest
2199void
2200ShareVolume::_HandleEntryRemovedRequest(EntryRemovedRequest* request)
2201{
2202	if (!request)
2203		return;
2204
2205	nspace_id nsid = fVolumeManager->GetID();
2206	const char* name = request->name.GetString();
2207
2208	// translate the node IDs
2209	vnode_id vnida = 0;
2210	vnode_id vnidb = 0;
2211	vnode_id vnidc = 0;
2212	status_t error = _GetLocalNodeID(request->directoryID, &vnida, true);
2213	if (error == B_OK)
2214		error = _GetLocalNodeID(request->nodeID, &vnidc, false);
2215			// TODO: We don't enter a node ID mapping here, which might cause
2216			// undesired behavior in some cases. Queries should usually be
2217			// fine, since, if the entry was in the query set, then the
2218			// respective node ID should definately be known at this point.
2219			// If an entry is removed and the node monitoring event comes
2220			// before a live query event for the same entry, the former one
2221			// will cause the ID to be removed, so that it is already gone
2222			// when the latter one arrives. I haven't observed this yet,
2223			// though. The query events always seem to be sent before the
2224			// node monitoring events (and the server processes them in a
2225			// single-threaded way). I guess, this is FS implementation
2226			// dependent, though.
2227			// A node monitoring event that will always get lost, is when the
2228			// FS user watches a directory that hasn't been read before. Its
2229			// entries will not be known yet and thus "entry removed" events
2230			// will be dropped here. I guess, it's arguable whether this is
2231			// a practical problem (why should the watcher care that an entry
2232			// has been removed, when they didn't know what entries were in
2233			// the directory in the first place?).
2234			// A possible solution would be to never remove node ID mappings.
2235			// We would only need to take care that the cached node info is
2236			// correctly flushed, so that e.g. a subsequent ReadVNode() has to
2237			// ask the server and doesn't work with obsolete data. We would
2238			// also enter a yet unknown ID into the node ID map here. The only
2239			// problem is that the ID maps will keep growing, especially when
2240			// there's a lot of FS activity on the server.
2241
2242	// send notifications / do additional processing
2243	if (request->queryUpdate) {
2244		if (error == B_OK) {
2245			SendNotification(request->port, request->token,
2246				B_QUERY_UPDATE, request->opcode, nsid, 0, vnida, vnidb,
2247				vnidc, name);
2248		}
2249	} else {
2250		_EntryRemoved(request->directoryID, name, request->revision);
2251		_NodeRemoved(request->nodeID);
2252		if (error == B_OK)
2253			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name);
2254	}
2255}
2256
2257// _HandleEntryMovedRequest
2258void
2259ShareVolume::_HandleEntryMovedRequest(EntryMovedRequest* request)
2260{
2261	if (!request)
2262		return;
2263
2264	nspace_id nsid = fVolumeManager->GetID();
2265	const char* oldName = request->fromName.GetString();
2266	const char* name = request->toName.GetString();
2267
2268	// translate the node IDs
2269	vnode_id vnida = 0;
2270	vnode_id vnidb = 0;
2271	vnode_id vnidc = 0;
2272	status_t error = _GetLocalNodeID(request->fromDirectoryID, &vnida, true);
2273	if (error == B_OK)
2274		error = _GetLocalNodeID(request->toDirectoryID, &vnidb, true);
2275	if (error == B_OK)
2276		error = _GetLocalNodeID(request->nodeID, &vnidc, true);
2277
2278	// send notifications / do additional processing
2279	if (!request->queryUpdate) {
2280		_EntryMoved(request->fromDirectoryID, oldName, request->toDirectoryID,
2281			name, (request->entryInfoValid ? &request->entryInfo : NULL),
2282			request->revision);
2283		if (error == B_OK)
2284			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name);
2285	}
2286}
2287
2288// _HandleStatChangedRequest
2289void
2290ShareVolume::_HandleStatChangedRequest(StatChangedRequest* request)
2291{
2292	if (!request)
2293		return;
2294
2295	nspace_id nsid = fVolumeManager->GetID();
2296
2297	// translate the node IDs
2298	vnode_id vnida = 0;
2299	vnode_id vnidb = 0;
2300	vnode_id vnidc = 0;
2301	status_t error = _GetLocalNodeID(request->nodeID, &vnidc, true);
2302
2303	// send notifications / do additional processing
2304	if (!request->queryUpdate) {
2305		_UpdateNode(request->nodeInfo);
2306		if (error == B_OK)
2307			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, NULL);
2308	}
2309}
2310
2311// _HandleAttributeChangedRequest
2312void
2313ShareVolume::_HandleAttributeChangedRequest(AttributeChangedRequest* request)
2314{
2315	if (!request)
2316		return;
2317
2318	nspace_id nsid = fVolumeManager->GetID();
2319	const char* name = request->attrInfo.name.GetString();
2320
2321	// translate the node IDs
2322	vnode_id vnida = 0;
2323	vnode_id vnidb = 0;
2324	vnode_id vnidc = 0;
2325	status_t error = _GetLocalNodeID(request->nodeID, &vnidc, true);
2326
2327	// send notifications / do additional processing
2328	if (!request->queryUpdate) {
2329		_UpdateAttrDir(request->nodeID, request->attrDirInfo);
2330		if (error == B_OK)
2331			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name);
2332	}
2333}
2334
2335// _GetLocalNodeID
2336status_t
2337ShareVolume::_GetLocalNodeID(NodeID remoteID, ino_t* _localID, bool enter)
2338{
2339	AutoLocker<Locker> _(fLock);
2340	// if the ID is already know, just return it
2341	if (fLocalNodeIDs->ContainsKey(remoteID)) {
2342		*_localID = fLocalNodeIDs->Get(remoteID);
2343		return B_OK;
2344	}
2345
2346	// ID not yet known
2347	// enter it? Do this only, if requested and we're not already unmounting.
2348	if (!enter)
2349		return B_ENTRY_NOT_FOUND;
2350	if (fUnmounting)
2351		return ERROR_NOT_CONNECTED;
2352
2353	// get a fresh ID from the volume manager
2354	vnode_id localID = fVolumeManager->NewNodeID(this);
2355	if (localID < 0)
2356		return localID;
2357
2358	// put the IDs into local map
2359	status_t error = fLocalNodeIDs->Put(remoteID, localID);
2360	if (error != B_OK) {
2361		fVolumeManager->RemoveNodeID(localID);
2362		return error;
2363	}
2364
2365	// put the IDs into remote map
2366	error = fRemoteNodeIDs->Put(localID, remoteID);
2367	if (error != B_OK) {
2368		fLocalNodeIDs->Remove(remoteID);
2369		fVolumeManager->RemoveNodeID(localID);
2370		return error;
2371	}
2372	PRINT("ShareVolume(%ld): added node ID mapping: local: %lld -> "
2373		"remote: (%ld, %lld)\n", fID, localID, remoteID.volumeID,
2374		remoteID.nodeID);
2375
2376	*_localID = localID;
2377	return B_OK;
2378}
2379
2380// _GetRemoteNodeID
2381status_t
2382ShareVolume::_GetRemoteNodeID(ino_t localID, NodeID* remoteID)
2383{
2384	AutoLocker<Locker> _(fLock);
2385
2386	// check, if the ID is known
2387	if (!fRemoteNodeIDs->ContainsKey(localID))
2388		return B_ENTRY_NOT_FOUND;
2389
2390	*remoteID = fRemoteNodeIDs->Get(localID);
2391	return B_OK;
2392}
2393
2394// _RemoveLocalNodeID
2395void
2396ShareVolume::_RemoveLocalNodeID(ino_t localID)
2397{
2398	AutoLocker<Locker> _(fLock);
2399
2400	// check, if the ID is known
2401	if (!fRemoteNodeIDs->ContainsKey(localID))
2402		return;
2403
2404	// remove from ID maps
2405	NodeID remoteID = fRemoteNodeIDs->Get(localID);
2406	PRINT("ShareVolume::_RemoveLocalNodeID(%lld): remote: (%ld, %lld)\n",
2407		localID, remoteID.volumeID, remoteID.nodeID);
2408	fRemoteNodeIDs->Remove(localID);
2409	fLocalNodeIDs->Remove(remoteID);
2410
2411	// remove from volume manager
2412	fVolumeManager->RemoveNodeID(localID);
2413}
2414
2415// _GetNodeByLocalID
2416ShareNode*
2417ShareVolume::_GetNodeByLocalID(ino_t localID)
2418{
2419	AutoLocker<Locker> _(fLock);
2420	return fNodes->Get(localID);
2421}
2422
2423// _GetNodeByRemoteID
2424ShareNode*
2425ShareVolume::_GetNodeByRemoteID(NodeID remoteID)
2426{
2427	AutoLocker<Locker> _(fLock);
2428
2429	ino_t localID;
2430	if (_GetLocalNodeID(remoteID, &localID, false) == B_OK)
2431		return fNodes->Get(localID);
2432
2433	return NULL;
2434}
2435
2436// _LoadNode
2437status_t
2438ShareVolume::_LoadNode(const NodeInfo& nodeInfo, ShareNode** _node)
2439{
2440	AutoLocker<Locker> _(fLock);
2441
2442	// check, if the node is already known
2443	ShareNode* node = _GetNodeByRemoteID(nodeInfo.GetID());
2444	if (node) {
2445		node->Update(nodeInfo);
2446	} else {
2447		// don't load the node when already unmounting
2448		if (fUnmounting)
2449			return B_ERROR;
2450
2451		// get a local node ID
2452		vnode_id localID;
2453		status_t error = _GetLocalNodeID(nodeInfo.GetID(), &localID, true);
2454		if (error != B_OK)
2455			return error;
2456
2457		// create a new node
2458		if (S_ISDIR(nodeInfo.st.st_mode))
2459			node = new(std::nothrow) ShareDir(this, localID, &nodeInfo);
2460		else
2461			node = new(std::nothrow) ShareNode(this, localID, &nodeInfo);
2462		if (!node) {
2463			_RemoveLocalNodeID(localID);
2464			return B_NO_MEMORY;
2465		}
2466
2467		// add it
2468		error = fNodes->Put(node->GetID(), node);
2469		if (error != B_OK) {
2470			_RemoveLocalNodeID(localID);
2471			delete node;
2472			return error;
2473		}
2474		PRINT("ShareVolume: added node: %lld: remote: (%ld, %lld),"
2475			" localID: %lld\n", node->GetID(),
2476			node->GetRemoteID().volumeID,
2477			node->GetRemoteID().nodeID, localID);
2478	}
2479
2480	if (_node)
2481		*_node = node;
2482	return B_OK;
2483}
2484
2485// _UpdateNode
2486status_t
2487ShareVolume::_UpdateNode(const NodeInfo& nodeInfo)
2488{
2489	AutoLocker<Locker> _(fLock);
2490
2491	if (fUnmounting)
2492		return ERROR_NOT_CONNECTED;
2493
2494	ShareNode* node = _GetNodeByRemoteID(nodeInfo.GetID());
2495	if (node) {
2496		node->Update(nodeInfo);
2497		return B_OK;
2498	}
2499	return B_ENTRY_NOT_FOUND;
2500}
2501
2502// _GetEntryByLocalID
2503ShareDirEntry*
2504ShareVolume::_GetEntryByLocalID(ino_t localDirID, const char* name)
2505{
2506	if (!name)
2507		return NULL;
2508
2509	AutoLocker<Locker> _(fLock);
2510	return fEntries->Get(EntryKey(localDirID, name));
2511}
2512
2513// _GetEntryByRemoteID
2514ShareDirEntry*
2515ShareVolume::_GetEntryByRemoteID(NodeID remoteDirID, const char* name)
2516{
2517	if (!name)
2518		return NULL;
2519
2520	AutoLocker<Locker> _(fLock);
2521
2522	ino_t localDirID;
2523	if (_GetLocalNodeID(remoteDirID, &localDirID, false) == B_OK)
2524		return fEntries->Get(EntryKey(localDirID, name));
2525
2526	return NULL;
2527}
2528
2529// _LoadEntry
2530//
2531// If _entry is supplied, fLock should be held, otherwise the returned entry
2532// might as well be deleted.
2533status_t
2534ShareVolume::_LoadEntry(ShareDir* directory, const EntryInfo& entryInfo,
2535	ShareDirEntry** _entry)
2536{
2537	const char* name = entryInfo.name.GetString();
2538	if (!directory || !name)
2539		return B_BAD_VALUE;
2540
2541	AutoLocker<Locker> _(fLock);
2542
2543	ShareDirEntry* entry = _GetEntryByLocalID(directory->GetID(), name);
2544	if (entry) {
2545		if (entryInfo.nodeInfo.revision > entry->GetRevision()) {
2546			if (entryInfo.nodeInfo.GetID() != entry->GetNode()->GetRemoteID()) {
2547				// The node the existing entry refers to is not the node it
2548				// should refer to. Remove the old entry and create a new one.
2549				_EntryRemoved(directory->GetRemoteID(), name,
2550					entryInfo.nodeInfo.revision);
2551				_EntryCreated(directory->GetRemoteID(), name, &entryInfo,
2552					entryInfo.nodeInfo.revision);
2553
2554				// re-get the entry and check, if everything is fine
2555				entry = _GetEntryByLocalID(directory->GetID(), name);
2556				if (!entry)
2557					return B_ERROR;
2558				if (entryInfo.nodeInfo.GetID()
2559					!= entry->GetNode()->GetRemoteID()) {
2560					return B_ERROR;
2561				}
2562			} else {
2563				entry->SetRevision(entryInfo.nodeInfo.revision);
2564				_UpdateNode(entryInfo.nodeInfo);
2565			}
2566		}
2567	} else {
2568		// entry not known yet: create it
2569
2570		// don't load the entry when already unmounting
2571		if (fUnmounting)
2572			return B_ERROR;
2573
2574		// load the node
2575		ShareNode* node;
2576		status_t error = _LoadNode(entryInfo.nodeInfo, &node);
2577		if (error != B_OK)
2578			return error;
2579
2580		// if the directory or the node are marked remove, we don't create the
2581		// entry
2582		if (IsVNodeRemoved(directory->GetID()) > 0
2583			|| IsVNodeRemoved(node->GetID()) > 0) {
2584			return B_NOT_ALLOWED;
2585		}
2586
2587		// create the entry
2588		entry = new(std::nothrow) ShareDirEntry(directory, name, node);
2589		if (!entry)
2590			return B_NO_MEMORY;
2591		ObjectDeleter<ShareDirEntry> entryDeleter(entry);
2592		error = entry->InitCheck();
2593		if (error != B_OK)
2594			return error;
2595
2596		// add the entry
2597		error = fEntries->Put(EntryKey(directory->GetID(), entry->GetName()),
2598			entry);
2599		if (error != B_OK)
2600			return error;
2601
2602		// set the entry revision
2603		entry->SetRevision(entryInfo.nodeInfo.revision);
2604
2605		// add the entry to the directory and the node
2606		directory->AddEntry(entry);
2607		entry->GetNode()->AddReferringEntry(entry);
2608
2609		// everything went fine
2610		entryDeleter.Detach();
2611	}
2612
2613	if (_entry)
2614		*_entry = entry;
2615	return B_OK;
2616}
2617
2618// _RemoveEntry
2619//
2620// fLock must be held.
2621void
2622ShareVolume::_RemoveEntry(ShareDirEntry* entry)
2623{
2624	fEntries->Remove(EntryKey(entry->GetDirectory()->GetID(),
2625		entry->GetName()));
2626	entry->GetDirectory()->RemoveEntry(entry);
2627	entry->GetNode()->RemoveReferringEntry(entry);
2628	entry->ReleaseReference();
2629}
2630
2631// _IsObsoleteEntryInfo
2632//
2633// fLock must be held.
2634bool
2635ShareVolume::_IsObsoleteEntryInfo(const EntryInfo& entryInfo)
2636{
2637	// get the directory
2638	ShareDir* dir
2639		= dynamic_cast<ShareDir*>(_GetNodeByRemoteID(entryInfo.directoryID));
2640	if (!dir)
2641		return false;
2642
2643	return (entryInfo.nodeInfo.revision <= dir->GetEntryRemovedEventRevision());
2644}
2645
2646// _LoadAttrDir
2647status_t
2648ShareVolume::_LoadAttrDir(ShareNode* node, const AttrDirInfo& attrDirInfo)
2649{
2650	if (!node || !attrDirInfo.isValid)
2651		return B_BAD_VALUE;
2652
2653	AutoLocker<Locker> _(fLock);
2654
2655	if (fUnmounting)
2656		return ERROR_NOT_CONNECTED;
2657
2658	ShareAttrDir* attrDir = node->GetAttrDir();
2659	if (attrDir) {
2660		if (attrDir->GetRevision() > attrDirInfo.revision)
2661			return B_OK;
2662
2663		// update the attr dir
2664		return attrDir->Update(attrDirInfo,
2665			fAttrDirIterators->Get(node->GetID()));
2666	} else {
2667		// no attribute directory yet: create one
2668		attrDir = new(std::nothrow) ShareAttrDir;
2669		if (!attrDir)
2670			return B_NO_MEMORY;
2671		ObjectDeleter<ShareAttrDir> attrDirDeleter(attrDir);
2672
2673		// initialize it
2674		status_t error = attrDir->Init(attrDirInfo);
2675		if (error != B_OK)
2676			return error;
2677
2678		// set it
2679		node->SetAttrDir(attrDir);
2680		attrDirDeleter.Detach();
2681		return B_OK;
2682	}
2683}
2684
2685// _UpdateAttrDir
2686status_t
2687ShareVolume::_UpdateAttrDir(NodeID remoteID, const AttrDirInfo& attrDirInfo)
2688{
2689	AutoLocker<Locker> _(fLock);
2690
2691	// get the node
2692	ShareNode* node = _GetNodeByRemoteID(remoteID);
2693	if (!node)
2694		return B_ENTRY_NOT_FOUND;
2695
2696	if (!attrDirInfo.isValid || _LoadAttrDir(node, attrDirInfo) != B_OK) {
2697		// updating/creating the attr dir failed; if existing, we mark it
2698		// obsolete
2699		if (ShareAttrDir* attrDir = node->GetAttrDir())
2700			attrDir->SetUpToDate(false);
2701	}
2702
2703	return B_OK;
2704}
2705
2706// _AddAttrDirIterator
2707status_t
2708ShareVolume::_AddAttrDirIterator(ShareNode* node,
2709	ShareAttrDirIterator* iterator)
2710{
2711	if (!node || !iterator)
2712		return B_BAD_VALUE;
2713
2714	AutoLocker<Locker> locker(fLock);
2715
2716	// get the iterator list
2717	DoublyLinkedList<ShareAttrDirIterator>* iteratorList
2718		= fAttrDirIterators->Get(node->GetID());
2719	if (!iteratorList) {
2720		// no list for the node yet: create one
2721		iteratorList = new(std::nothrow) DoublyLinkedList<ShareAttrDirIterator>;
2722		if (!iteratorList)
2723			return B_NO_MEMORY;
2724
2725		// add it
2726		status_t error = fAttrDirIterators->Put(node->GetID(), iteratorList);
2727		if (error != B_OK) {
2728			delete iteratorList;
2729			return error;
2730		}
2731	}
2732
2733	// add the iterator
2734	iteratorList->Insert(iterator);
2735
2736	return B_OK;
2737}
2738
2739// _RemoveAttrDirIterator
2740void
2741ShareVolume::_RemoveAttrDirIterator(ShareNode* node,
2742	ShareAttrDirIterator* iterator)
2743{
2744	if (!node || !iterator)
2745		return;
2746
2747	AutoLocker<Locker> locker(fLock);
2748
2749	// get the iterator list
2750	DoublyLinkedList<ShareAttrDirIterator>* iteratorList
2751		= fAttrDirIterators->Get(node->GetID());
2752	if (!iteratorList) {
2753		WARN("ShareVolume::_RemoveAttrDirIterator(): Iterator list not "
2754			"found: node: %lld\n", node->GetID());
2755		return;
2756	}
2757
2758	// remove the iterator
2759	iteratorList->Remove(iterator);
2760
2761	// if the list is empty now, discard it
2762	if (!iteratorList->First()) {
2763		fAttrDirIterators->Remove(node->GetID());
2764		delete iteratorList;
2765	}
2766}
2767
2768// _NodeRemoved
2769void
2770ShareVolume::_NodeRemoved(NodeID remoteID)
2771{
2772	AutoLocker<Locker> locker(fLock);
2773
2774	ShareNode* node = _GetNodeByRemoteID(remoteID);
2775	if (!node)
2776		return;
2777
2778	// if the node still has referring entries, we do nothing
2779	if (node->GetActualReferringEntry())
2780		return;
2781
2782	// if the node is a directory, we remove its entries first
2783	if (ShareDir* dir = dynamic_cast<ShareDir*>(node)) {
2784		while (ShareDirEntry* entry = dir->GetFirstEntry())
2785			_RemoveEntry(entry);
2786	}
2787
2788	// remove all entries still referring to the node
2789	while (ShareDirEntry* entry = node->GetFirstReferringEntry())
2790		_RemoveEntry(entry);
2791
2792	ino_t localID = node->GetID();
2793
2794	// Remove the node ID in all cases -- even, if the node is still
2795	// known to the VFS. Otherwise there could be a race condition, that the
2796	// server re-uses the remote ID and we have it still associated with an
2797	// obsolete local ID.
2798	_RemoveLocalNodeID(localID);
2799
2800	if (node->IsKnownToVFS()) {
2801		Node* _node;
2802		if (GetVNode(localID, &_node) != B_OK)
2803			return;
2804		Volume::RemoveVNode(localID);
2805		locker.Unlock();
2806		PutVNode(localID);
2807
2808	} else {
2809		fNodes->Remove(localID);
2810		delete node;
2811	}
2812}
2813
2814// _EntryCreated
2815void
2816ShareVolume::_EntryCreated(NodeID remoteDirID, const char* name,
2817	const EntryInfo* entryInfo, int64 revision)
2818{
2819	if (!name)
2820		return;
2821
2822	AutoLocker<Locker> locker(fLock);
2823
2824	// get the directory
2825	ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(remoteDirID));
2826	if (!dir)
2827		return;
2828
2829	// load the entry, if possible
2830	ShareDirEntry* entry;
2831	bool entryLoaded = false;
2832	if (entryInfo && _LoadEntry(dir, *entryInfo, &entry) == B_OK)
2833		entryLoaded = true;
2834
2835	// if the entry could not be loaded, we have to mark the dir incomplete
2836	// and update its revision counter
2837	if (!entryLoaded) {
2838		dir->UpdateEntryCreatedEventRevision(revision);
2839		dir->SetComplete(false);
2840	}
2841}
2842
2843// _EntryRemoved
2844void
2845ShareVolume::_EntryRemoved(NodeID remoteDirID, const char* name, int64 revision)
2846{
2847	if (!name)
2848		return;
2849
2850	AutoLocker<Locker> locker(fLock);
2851
2852	// get the directory
2853	ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(remoteDirID));
2854	if (!dir)
2855		return;
2856
2857	// update the directory's "entry removed" event revision
2858	dir->UpdateEntryRemovedEventRevision(revision);
2859
2860	// get the entry
2861	ShareDirEntry* entry = _GetEntryByRemoteID(remoteDirID, name);
2862	if (!entry)
2863		return;
2864
2865	// check the entry revision
2866	if (entry->GetRevision() > revision)
2867		return;
2868
2869	// remove the entry
2870	_RemoveEntry(entry);
2871}
2872
2873// _EntryMoved
2874void
2875ShareVolume::_EntryMoved(NodeID remoteOldDirID, const char* oldName,
2876	NodeID remoteNewDirID, const char* name, const EntryInfo* entryInfo,
2877	int64 revision)
2878{
2879	AutoLocker<Locker> locker(fLock);
2880
2881	_EntryRemoved(remoteOldDirID, oldName, revision);
2882	_EntryCreated(remoteNewDirID, name, entryInfo, revision);
2883}
2884
2885// _Walk
2886status_t
2887ShareVolume::_Walk(NodeID remoteDirID, const char* entryName, bool resolveLink,
2888	WalkReply** _reply)
2889{
2890	// prepare the request
2891	WalkRequest request;
2892	request.volumeID = fID;
2893	request.nodeID = remoteDirID;
2894	request.name.SetTo(entryName);
2895	request.resolveLink = resolveLink;
2896
2897	// send the request
2898	WalkReply* reply;
2899	status_t error = SendRequest(fConnection, &request, &reply);
2900	if (error != B_OK)
2901		RETURN_ERROR(error);
2902	ObjectDeleter<Request> replyDeleter(reply);
2903	if (reply->error != B_OK)
2904		RETURN_ERROR(reply->error);
2905
2906	replyDeleter.Detach();
2907	*_reply = reply;
2908	return B_OK;
2909}
2910
2911// _MultiWalk
2912status_t
2913ShareVolume::_MultiWalk(RequestMemberArray<EntryInfo>& _entryInfos,
2914	MultiWalkReply** _reply)
2915{
2916	int32 count = _entryInfos.CountElements();
2917	if (!_reply || count == 0)
2918		return B_BAD_VALUE;
2919
2920	EntryInfo* entryInfos = _entryInfos.GetElements();
2921
2922	// prepare the request
2923	MultiWalkRequest request;
2924	request.volumeID = fID;
2925	request.nodeID = entryInfos[0].directoryID;
2926
2927	// add the names
2928	for (int32 i = 0; i < count; i++) {
2929		StringData name;
2930		name.SetTo(entryInfos[i].name.GetString());
2931
2932		status_t error = request.names.Append(name);
2933		if (error != B_OK)
2934			return error;
2935	}
2936
2937	// send the request
2938	MultiWalkReply* reply;
2939	status_t error = SendRequest(fConnection, &request, &reply);
2940	if (error != B_OK)
2941		RETURN_ERROR(error);
2942	ObjectDeleter<Request> replyDeleter(reply);
2943	if (reply->error != B_OK)
2944		RETURN_ERROR(reply->error);
2945
2946	replyDeleter.Detach();
2947	*_reply = reply;
2948	return B_OK;
2949}
2950
2951// _Close
2952status_t
2953ShareVolume::_Close(int32 cookie)
2954{
2955	if (!_EnsureShareMounted())
2956		return ERROR_NOT_CONNECTED;
2957
2958	// prepare the request
2959	CloseRequest request;
2960	request.volumeID = fID;
2961	request.cookie = cookie;
2962	// send the request
2963	CloseReply* reply;
2964	status_t error = SendRequest(fConnection, &request, &reply);
2965	if (error != B_OK)
2966		RETURN_ERROR(error);
2967	ObjectDeleter<Request> replyDeleter(reply);
2968	if (reply->error != B_OK)
2969		RETURN_ERROR(reply->error);
2970	return B_OK;
2971}
2972
2973// _GetConnectionState
2974//
2975// Must not be called with fLock being held!
2976uint32
2977ShareVolume::_GetConnectionState()
2978{
2979	AutoLocker<Locker> _(fMountLock);
2980	return fConnectionState;
2981}
2982
2983// _IsConnected
2984//
2985// Must not be called with fLock being held!
2986bool
2987ShareVolume::_IsConnected()
2988{
2989	return (_GetConnectionState() == CONNECTION_READY);
2990}
2991
2992// _EnsureShareMounted
2993//
2994// Must not be called with fLock being held!
2995bool
2996ShareVolume::_EnsureShareMounted()
2997{
2998	AutoLocker<Locker> _(fMountLock);
2999	if (fConnectionState == CONNECTION_NOT_INITIALIZED)
3000		_MountShare();
3001
3002	return (fConnectionState == CONNECTION_READY);
3003}
3004
3005// _MountShare
3006//
3007// fMountLock must be held.
3008status_t
3009ShareVolume::_MountShare()
3010{
3011	// get references to the server and share info
3012	AutoLocker<Locker> locker(fLock);
3013	BReference<ExtendedServerInfo> serverInfoReference(fServerInfo);
3014	BReference<ExtendedShareInfo> shareInfoReference(fShareInfo);
3015	ExtendedServerInfo* serverInfo = fServerInfo;
3016	ExtendedShareInfo* shareInfo = fShareInfo;
3017	locker.Unlock();
3018
3019	// get server address as string
3020	HashString serverAddressString;
3021	status_t error = serverInfo->GetAddress().GetString(&serverAddressString,
3022		false);
3023	if (error != B_OK)
3024		return error;
3025	const char* server = serverAddressString.GetString();
3026
3027	// get the server name
3028	const char* serverName = serverInfo->GetServerName();
3029	if (serverName && strlen(serverName) == 0)
3030		serverName = NULL;
3031
3032	// get the share name
3033	const char* share = shareInfo->GetShareName();
3034
3035	PRINT("ShareVolume::_MountShare(%s, %s)\n", server, share);
3036	// init a connection to the authentication server
3037	AuthenticationServer authenticationServer;
3038	error = authenticationServer.InitCheck();
3039	if (error != B_OK)
3040		RETURN_ERROR(error);
3041
3042	// get the server connection
3043	fConnectionState = CONNECTION_CLOSED;
3044	if (!fServerConnection) {
3045		status_t error = fServerConnectionProvider->GetServerConnection(
3046			&fServerConnection);
3047		if (error != B_OK)
3048			return error;
3049		fConnection = fServerConnection->GetRequestConnection();
3050	}
3051
3052	// the mount loop
3053	bool badPassword = false;
3054	MountReply* reply = NULL;
3055	do {
3056		// get the user and password from the authentication server
3057		char user[kUserBufferSize];
3058		char password[kPasswordBufferSize];
3059		bool cancelled;
3060		error = authenticationServer.GetAuthentication("netfs",
3061			(serverName ? serverName : server), share,
3062			fVolumeManager->GetMountUID(), badPassword,
3063			&cancelled, user, sizeof(user), password, sizeof(password));
3064		if (cancelled || error != B_OK)
3065			RETURN_ERROR(error);
3066
3067		// prepare the request
3068		MountRequest request;
3069		request.share.SetTo(share);
3070		request.user.SetTo(user);
3071		request.password.SetTo(password);
3072
3073		// send the request
3074		error = SendRequest(fConnection, &request, &reply);
3075		if (error != B_OK)
3076			RETURN_ERROR(error);
3077		ObjectDeleter<Request> replyDeleter(reply);
3078
3079		// if no permission, try again
3080		badPassword = reply->noPermission;
3081		if (!badPassword) {
3082			if (reply->error != B_OK)
3083				RETURN_ERROR(reply->error);
3084			fSharePermissions = reply->sharePermissions;
3085		}
3086	} while (badPassword);
3087
3088	AutoLocker<Locker> _(fLock);
3089
3090	fID = reply->volumeID;
3091
3092	// update the root node and enter its ID
3093	fRootNode->Update(reply->nodeInfo);
3094
3095	// put the IDs into local map
3096	error = fLocalNodeIDs->Put(fRootNode->GetRemoteID(), fRootNode->GetID());
3097	if (error != B_OK)
3098		RETURN_ERROR(error);
3099
3100	// put the IDs into remote map
3101	error = fRemoteNodeIDs->Put(fRootNode->GetID(), fRootNode->GetRemoteID());
3102	if (error != B_OK) {
3103		fLocalNodeIDs->Remove(fRootNode->GetRemoteID());
3104		RETURN_ERROR(error);
3105	}
3106	PRINT("ShareVolume::_MountShare(): root node: local: %lld, remote: "
3107		"(%ld, %lld)\n", fRootNode->GetID(),
3108		fRootNode->GetRemoteID().volumeID,
3109		fRootNode->GetRemoteID().nodeID);
3110
3111	// Add ourselves to the server connection, so that we can receive
3112	// node monitoring events. There a race condition: We might already
3113	// have missed events for the root node.
3114	error = fServerConnection->AddVolume(this);
3115	if (error != B_OK) {
3116		_RemoveLocalNodeID(fRootNode->GetID());
3117		return error;
3118	}
3119
3120	fConnectionState = CONNECTION_READY;
3121	return B_OK;
3122}
3123
3124