15a1d355fSStephan Aßmus// ShareVolume.cpp
25a1d355fSStephan Aßmus
35a1d355fSStephan Aßmus#include "ShareVolume.h"
45a1d355fSStephan Aßmus
55a1d355fSStephan Aßmus#include <new>
65a1d355fSStephan Aßmus#include <unistd.h>
75a1d355fSStephan Aßmus
85a1d355fSStephan Aßmus#include <AppDefs.h>	// for B_QUERY_UPDATE
95a1d355fSStephan Aßmus#include <AutoDeleter.h>
105a1d355fSStephan Aßmus#include <AutoLocker.h>
115a1d355fSStephan Aßmus#include <HashMap.h>
125a1d355fSStephan Aßmus
135a1d355fSStephan Aßmus#include "AuthenticationServer.h"
145a1d355fSStephan Aßmus#include "Compatibility.h"
155a1d355fSStephan Aßmus#include "Connection.h"
165a1d355fSStephan Aßmus#include "ConnectionFactory.h"
175a1d355fSStephan Aßmus#include "DebugSupport.h"
185a1d355fSStephan Aßmus#include "ExtendedServerInfo.h"
195a1d355fSStephan Aßmus#include "Permissions.h"
205a1d355fSStephan Aßmus#include "Node.h"
215a1d355fSStephan Aßmus#include "QueryManager.h"
225a1d355fSStephan Aßmus#include "RequestChannel.h"
235a1d355fSStephan Aßmus#include "RequestConnection.h"
245a1d355fSStephan Aßmus#include "Requests.h"
255a1d355fSStephan Aßmus#include "RootVolume.h"
265a1d355fSStephan Aßmus#include "SendReceiveRequest.h"
275a1d355fSStephan Aßmus#include "ServerConnection.h"
285a1d355fSStephan Aßmus#include "ServerConnectionProvider.h"
295a1d355fSStephan Aßmus#include "ShareAttrDir.h"
305a1d355fSStephan Aßmus#include "ShareAttrDirIterator.h"
315a1d355fSStephan Aßmus#include "ShareNode.h"
325a1d355fSStephan Aßmus#include "Utils.h"
335a1d355fSStephan Aßmus#include "VolumeManager.h"
345a1d355fSStephan Aßmus#include "VolumeSupport.h"
355a1d355fSStephan Aßmus
365a1d355fSStephan Aßmus// TODO: Request timeouts!
375a1d355fSStephan Aßmus
385a1d355fSStephan Aßmusstatic const int32 kMaxWriteBufferSize	= 64 * 1024;	// 64 KB
395a1d355fSStephan Aßmusstatic const int32 kUserBufferSize = 256;
405a1d355fSStephan Aßmusstatic const int32 kPasswordBufferSize = 256;
415a1d355fSStephan Aßmus
425a1d355fSStephan Aßmus// connection states
435a1d355fSStephan Aßmusenum {
445a1d355fSStephan Aßmus	CONNECTION_NOT_INITIALIZED,
455a1d355fSStephan Aßmus	CONNECTION_READY,
465a1d355fSStephan Aßmus	CONNECTION_CLOSED,
475a1d355fSStephan Aßmus};
485a1d355fSStephan Aßmus
495a1d355fSStephan Aßmus// NodeMap
505a1d355fSStephan Aßmusstruct ShareVolume::NodeMap : HashMap<HashKey64<ino_t>, ShareNode*> {
515a1d355fSStephan Aßmus};
525a1d355fSStephan Aßmus
535a1d355fSStephan Aßmus// EntryKey
545a1d355fSStephan Aßmus//
555a1d355fSStephan Aßmus// NOTE: This class doesn't make a copy of the name string it is constructed
565a1d355fSStephan Aßmus// with. So, when entering the key in a map, one must make sure, that the
575a1d355fSStephan Aßmus// string stays valid as long as the entry is in the map.
585a1d355fSStephan Aßmusstruct ShareVolume::EntryKey {
595a1d355fSStephan Aßmus	EntryKey() {}
605a1d355fSStephan Aßmus
615a1d355fSStephan Aßmus	EntryKey(ino_t directoryID, const char* name)
625a1d355fSStephan Aßmus		: directoryID(directoryID),
635a1d355fSStephan Aßmus		  name(name)
645a1d355fSStephan Aßmus	{
655a1d355fSStephan Aßmus	}
665a1d355fSStephan Aßmus
675a1d355fSStephan Aßmus	EntryKey(const EntryKey& other)
685a1d355fSStephan Aßmus		: directoryID(other.directoryID),
695a1d355fSStephan Aßmus		  name(other.name)
705a1d355fSStephan Aßmus	{
715a1d355fSStephan Aßmus	}
725a1d355fSStephan Aßmus
735a1d355fSStephan Aßmus	uint32 GetHashCode() const
745a1d355fSStephan Aßmus	{
755a1d355fSStephan Aßmus		uint32 hash = (uint32)directoryID;
765a1d355fSStephan Aßmus		hash = 31 * hash + (uint32)(directoryID >> 32);
775a1d355fSStephan Aßmus		hash = 31 * hash + string_hash(name);
785a1d355fSStephan Aßmus		return hash;
795a1d355fSStephan Aßmus	}
805a1d355fSStephan Aßmus
815a1d355fSStephan Aßmus	EntryKey& operator=(const EntryKey& other)
825a1d355fSStephan Aßmus	{
835a1d355fSStephan Aßmus		directoryID = other.directoryID;
845a1d355fSStephan Aßmus		name = other.name;
855a1d355fSStephan Aßmus		return *this;
865a1d355fSStephan Aßmus	}
875a1d355fSStephan Aßmus
885a1d355fSStephan Aßmus	bool operator==(const EntryKey& other) const
895a1d355fSStephan Aßmus	{
905a1d355fSStephan Aßmus		if (directoryID != other.directoryID)
915a1d355fSStephan Aßmus			return false;
925a1d355fSStephan Aßmus
935a1d355fSStephan Aßmus		if (name)
945a1d355fSStephan Aßmus			return (other.name && strcmp(name, other.name) == 0);
955a1d355fSStephan Aßmus
965a1d355fSStephan Aßmus		return !other.name;
975a1d355fSStephan Aßmus	}
985a1d355fSStephan Aßmus
995a1d355fSStephan Aßmus	bool operator!=(const EntryKey& other) const
1005a1d355fSStephan Aßmus	{
1015a1d355fSStephan Aßmus		return !(*this == other);
1025a1d355fSStephan Aßmus	}
1035a1d355fSStephan Aßmus
1045a1d355fSStephan Aßmus	ino_t		directoryID;
1055a1d355fSStephan Aßmus	const char*	name;
1065a1d355fSStephan Aßmus};
1075a1d355fSStephan Aßmus
1085a1d355fSStephan Aßmus// EntryMap
1095a1d355fSStephan Aßmusstruct ShareVolume::EntryMap : HashMap<EntryKey, ShareDirEntry*> {
1105a1d355fSStephan Aßmus};
1115a1d355fSStephan Aßmus
1125a1d355fSStephan Aßmus// LocalNodeIDMap
1135a1d355fSStephan Aßmusstruct ShareVolume::LocalNodeIDMap : HashMap<NodeID, ino_t> {
1145a1d355fSStephan Aßmus};
1155a1d355fSStephan Aßmus
1165a1d355fSStephan Aßmus// RemoteNodeIDMap
1175a1d355fSStephan Aßmusstruct ShareVolume::RemoteNodeIDMap : HashMap<HashKey64<ino_t>, NodeID> {
1185a1d355fSStephan Aßmus};
1195a1d355fSStephan Aßmus
1205a1d355fSStephan Aßmus// DirCookie
1215a1d355fSStephan Aßmusstruct ShareVolume::DirCookie {
1225a1d355fSStephan Aßmus	ShareDirIterator*	iterator;
1235a1d355fSStephan Aßmus};
1245a1d355fSStephan Aßmus
1255a1d355fSStephan Aßmus// AttrDirCookie
1265a1d355fSStephan Aßmusstruct ShareVolume::AttrDirCookie {
1275a1d355fSStephan Aßmus	AttrDirCookie()
1285a1d355fSStephan Aßmus		: iterator(NULL),
1295a1d355fSStephan Aßmus		  cookie(-1),
1305a1d355fSStephan Aßmus		  rewind(false)
1315a1d355fSStephan Aßmus	{
1325a1d355fSStephan Aßmus	}
1335a1d355fSStephan Aßmus
1345a1d355fSStephan Aßmus	ShareAttrDirIterator*	iterator;
13559ecfa6cSAugustin Cavalier	intptr_t				cookie;
1365a1d355fSStephan Aßmus	bool					rewind;
1375a1d355fSStephan Aßmus};
1385a1d355fSStephan Aßmus
1395a1d355fSStephan Aßmus// AttrDirIteratorMap
1405a1d355fSStephan Aßmusstruct ShareVolume::AttrDirIteratorMap
1415a1d355fSStephan Aßmus	: HashMap<HashKey64<ino_t>, DoublyLinkedList<ShareAttrDirIterator>*> {
1425a1d355fSStephan Aßmus};
1435a1d355fSStephan Aßmus
1445a1d355fSStephan Aßmus
1455a1d355fSStephan Aßmus// #pragma mark -
1465a1d355fSStephan Aßmus
1475a1d355fSStephan Aßmus// constructor
1485a1d355fSStephan AßmusShareVolume::ShareVolume(VolumeManager* volumeManager,
1495a1d355fSStephan Aßmus	ServerConnectionProvider* connectionProvider,
1505a1d355fSStephan Aßmus	ExtendedServerInfo* serverInfo, ExtendedShareInfo* shareInfo)
1515a1d355fSStephan Aßmus	: Volume(volumeManager),
1525a1d355fSStephan Aßmus	  fID(-1),
1535a1d355fSStephan Aßmus	  fFlags(0),
1545a1d355fSStephan Aßmus	  fMountLock("share mount lock"),
1555a1d355fSStephan Aßmus	  fNodes(NULL),
1565a1d355fSStephan Aßmus	  fEntries(NULL),
1575a1d355fSStephan Aßmus	  fAttrDirIterators(NULL),
1585a1d355fSStephan Aßmus	  fLocalNodeIDs(NULL),
1595a1d355fSStephan Aßmus	  fRemoteNodeIDs(NULL),
1605a1d355fSStephan Aßmus	  fServerConnectionProvider(connectionProvider),
1615a1d355fSStephan Aßmus	  fServerInfo(serverInfo),
1625a1d355fSStephan Aßmus	  fShareInfo(shareInfo),
1635a1d355fSStephan Aßmus	  fServerConnection(NULL),
1645a1d355fSStephan Aßmus	  fConnection(NULL),
1655a1d355fSStephan Aßmus	  fSharePermissions(0),
1665a1d355fSStephan Aßmus	  fConnectionState(CONNECTION_NOT_INITIALIZED)
1675a1d355fSStephan Aßmus{
1685a1d355fSStephan Aßmus	fFlags = fVolumeManager->GetMountFlags();
1695a1d355fSStephan Aßmus	if (fServerConnectionProvider)
17088e38c17SIngo Weinhold		fServerConnectionProvider->AcquireReference();
1715a1d355fSStephan Aßmus	if (fServerInfo)
17288e38c17SIngo Weinhold		fServerInfo->AcquireReference();
1735a1d355fSStephan Aßmus	if (fShareInfo)
17488e38c17SIngo Weinhold		fShareInfo->AcquireReference();
1755a1d355fSStephan Aßmus}
1765a1d355fSStephan Aßmus
1775a1d355fSStephan Aßmus// destructor
1785a1d355fSStephan AßmusShareVolume::~ShareVolume()
1795a1d355fSStephan Aßmus{
1805a1d355fSStephan AßmusPRINT(("ShareVolume::~ShareVolume()\n"));
1815a1d355fSStephan Aßmus	// delete the root node
1825a1d355fSStephan Aßmus	if (fRootNode) {
1835a1d355fSStephan Aßmus		if (fNodes)
1845a1d355fSStephan Aßmus			fNodes->Remove(fRootNode->GetID());
1855a1d355fSStephan Aßmus		delete fRootNode;
1865a1d355fSStephan Aßmus		fRootNode = NULL;
1875a1d355fSStephan Aßmus	}
1885a1d355fSStephan Aßmus
1895a1d355fSStephan Aßmus	// delete the nodes
1905a1d355fSStephan Aßmus	if (fNodes) {
1915a1d355fSStephan Aßmus		// there shouldn't be any more nodes
1925a1d355fSStephan Aßmus		if (fNodes->Size() > 0) {
1935a1d355fSStephan Aßmus			WARN("ShareVolume::~ShareVolume(): WARNING: There are still "
19420f046edSJérôme Duval				"%" B_PRId32 " nodes\n", fNodes->Size());
1955a1d355fSStephan Aßmus		}
1965a1d355fSStephan Aßmus		for (NodeMap::Iterator it = fNodes->GetIterator(); it.HasNext();)
1975a1d355fSStephan Aßmus			delete it.Next().value;
1985a1d355fSStephan Aßmus		delete fNodes;
1995a1d355fSStephan Aßmus	}
2005a1d355fSStephan Aßmus
2015a1d355fSStephan Aßmus	// delete the entries
2025a1d355fSStephan Aßmus	if (fEntries) {
2035a1d355fSStephan Aßmus		// there shouldn't be any more entries
2045a1d355fSStephan Aßmus		if (fEntries->Size() > 0) {
2055a1d355fSStephan Aßmus			WARN("ShareVolume::~ShareVolume(): WARNING: There are still "
20620f046edSJérôme Duval				"%" B_PRId32 " entries\n", fEntries->Size());
2075a1d355fSStephan Aßmus		}
2085a1d355fSStephan Aßmus		for (EntryMap::Iterator it = fEntries->GetIterator(); it.HasNext();)
2095a1d355fSStephan Aßmus			delete it.Next().value;
2105a1d355fSStephan Aßmus		delete fEntries;
2115a1d355fSStephan Aßmus	}
2125a1d355fSStephan Aßmus
2135a1d355fSStephan Aßmus	delete fLocalNodeIDs;
2145a1d355fSStephan Aßmus	delete fRemoteNodeIDs;
2155a1d355fSStephan Aßmus
2165a1d355fSStephan Aßmus	if (fShareInfo)
21788e38c17SIngo Weinhold		fShareInfo->ReleaseReference();
2185a1d355fSStephan Aßmus	if (fServerInfo)
21988e38c17SIngo Weinhold		fServerInfo->ReleaseReference();
2205a1d355fSStephan Aßmus	if (fServerConnection)
22188e38c17SIngo Weinhold		fServerConnection->ReleaseReference();
2225a1d355fSStephan Aßmus	if (fServerConnectionProvider)
22388e38c17SIngo Weinhold		fServerConnectionProvider->ReleaseReference();
2245a1d355fSStephan Aßmus}
2255a1d355fSStephan Aßmus
2265a1d355fSStephan Aßmus// GetID
2275a1d355fSStephan Aßmusnspace_id
2285a1d355fSStephan AßmusShareVolume::GetID() const
2295a1d355fSStephan Aßmus{
2305a1d355fSStephan Aßmus	return fID;
2315a1d355fSStephan Aßmus}
2325a1d355fSStephan Aßmus
2335a1d355fSStephan Aßmus// IsReadOnly
2345a1d355fSStephan Aßmusbool
2355a1d355fSStephan AßmusShareVolume::IsReadOnly() const
2365a1d355fSStephan Aßmus{
2375a1d355fSStephan Aßmus	return (fFlags & B_MOUNT_READ_ONLY);
2385a1d355fSStephan Aßmus}
2395a1d355fSStephan Aßmus
2405a1d355fSStephan Aßmus// SupportsQueries
2415a1d355fSStephan Aßmusbool
2425a1d355fSStephan AßmusShareVolume::SupportsQueries() const
2435a1d355fSStephan Aßmus{
2445a1d355fSStephan Aßmus	return (fSharePermissions & QUERY_SHARE_PERMISSION);
2455a1d355fSStephan Aßmus}
2465a1d355fSStephan Aßmus
2475a1d355fSStephan Aßmus// Init
2485a1d355fSStephan Aßmusstatus_t
2495a1d355fSStephan AßmusShareVolume::Init(const char* name)
2505a1d355fSStephan Aßmus{
2515a1d355fSStephan Aßmus	status_t error = Volume::Init(name);
2525a1d355fSStephan Aßmus	if (error != B_OK)
2535a1d355fSStephan Aßmus		return error;
2545a1d355fSStephan Aßmus
2555a1d355fSStephan Aßmus	// create node map
2565a1d355fSStephan Aßmus	fNodes = new(std::nothrow) NodeMap;
2575a1d355fSStephan Aßmus	if (!fNodes)
2585a1d355fSStephan Aßmus		RETURN_ERROR(B_NO_MEMORY);
2595a1d355fSStephan Aßmus	error = fNodes->InitCheck();
2605a1d355fSStephan Aßmus	if (error != B_OK)
2615a1d355fSStephan Aßmus		return error;
2625a1d355fSStephan Aßmus
2635a1d355fSStephan Aßmus	// create entry map
2645a1d355fSStephan Aßmus	fEntries = new(std::nothrow) EntryMap;
2655a1d355fSStephan Aßmus	if (!fEntries)
2665a1d355fSStephan Aßmus		RETURN_ERROR(B_NO_MEMORY);
2675a1d355fSStephan Aßmus	error = fEntries->InitCheck();
2685a1d355fSStephan Aßmus	if (error != B_OK)
2695a1d355fSStephan Aßmus		return error;
2705a1d355fSStephan Aßmus
2715a1d355fSStephan Aßmus	// create attribute iterator map
2725a1d355fSStephan Aßmus	fAttrDirIterators = new(std::nothrow) AttrDirIteratorMap;
2735a1d355fSStephan Aßmus	if (!fAttrDirIterators)
2745a1d355fSStephan Aßmus		RETURN_ERROR(B_NO_MEMORY);
2755a1d355fSStephan Aßmus	error = fAttrDirIterators->InitCheck();
2765a1d355fSStephan Aßmus	if (error != B_OK)
2775a1d355fSStephan Aßmus		return error;
2785a1d355fSStephan Aßmus
2795a1d355fSStephan Aßmus	// create local node ID map
2805a1d355fSStephan Aßmus	fLocalNodeIDs = new(std::nothrow) LocalNodeIDMap;
2815a1d355fSStephan Aßmus	if (!fLocalNodeIDs)
2825a1d355fSStephan Aßmus		RETURN_ERROR(B_NO_MEMORY);
2835a1d355fSStephan Aßmus	error = fLocalNodeIDs->InitCheck();
2845a1d355fSStephan Aßmus	if (error != B_OK)
2855a1d355fSStephan Aßmus		return error;
2865a1d355fSStephan Aßmus
2875a1d355fSStephan Aßmus	// create remote node ID map
2885a1d355fSStephan Aßmus	fRemoteNodeIDs = new(std::nothrow) RemoteNodeIDMap;
2895a1d355fSStephan Aßmus	if (!fRemoteNodeIDs)
2905a1d355fSStephan Aßmus		RETURN_ERROR(B_NO_MEMORY);
2915a1d355fSStephan Aßmus	error = fRemoteNodeIDs->InitCheck();
2925a1d355fSStephan Aßmus	if (error != B_OK)
2935a1d355fSStephan Aßmus		return error;
2945a1d355fSStephan Aßmus
2955a1d355fSStephan Aßmus	// get a local node ID for our root node
2965a1d355fSStephan Aßmus	vnode_id localID = fVolumeManager->NewNodeID(this);
2975a1d355fSStephan Aßmus	if (localID < 0)
2985a1d355fSStephan Aßmus		return localID;
2995a1d355fSStephan Aßmus
3005a1d355fSStephan Aßmus	// create the root node
3015a1d355fSStephan Aßmus	fRootNode = new(std::nothrow) ShareDir(this, localID, NULL);
3025a1d355fSStephan Aßmus	if (!fRootNode) {
3035a1d355fSStephan Aßmus		fVolumeManager->RemoveNodeID(localID);
3045a1d355fSStephan Aßmus		return B_NO_MEMORY;
3055a1d355fSStephan Aßmus	}
3065a1d355fSStephan Aßmus
3075a1d355fSStephan Aßmus	// add the root node to the node map
3085a1d355fSStephan Aßmus	error = fNodes->Put(localID, fRootNode);
3095a1d355fSStephan Aßmus	if (error != B_OK)
3105a1d355fSStephan Aßmus		return error;
3115a1d355fSStephan Aßmus
3125a1d355fSStephan Aßmus	return B_OK;
3135a1d355fSStephan Aßmus}
3145a1d355fSStephan Aßmus
3155a1d355fSStephan Aßmus// Uninit
3165a1d355fSStephan Aßmusvoid
3175a1d355fSStephan AßmusShareVolume::Uninit()
3185a1d355fSStephan Aßmus{
3195a1d355fSStephan Aßmus	Volume::Uninit();
3205a1d355fSStephan Aßmus}
3215a1d355fSStephan Aßmus
3225a1d355fSStephan Aßmus// GetRootNode
3235a1d355fSStephan AßmusNode*
3245a1d355fSStephan AßmusShareVolume::GetRootNode() const
3255a1d355fSStephan Aßmus{
3265a1d355fSStephan Aßmus	return fRootNode;
3275a1d355fSStephan Aßmus}
3285a1d355fSStephan Aßmus
3295a1d355fSStephan Aßmus// PrepareToUnmount
3305a1d355fSStephan Aßmusvoid
3315a1d355fSStephan AßmusShareVolume::PrepareToUnmount()
3325a1d355fSStephan Aßmus{
3335a1d355fSStephan AßmusPRINT(("ShareVolume::PrepareToUnmount()\n"));
3345a1d355fSStephan Aßmus	Volume::PrepareToUnmount();
3355a1d355fSStephan Aßmus
3365a1d355fSStephan Aßmus	ConnectionClosed();
3375a1d355fSStephan Aßmus
3385a1d355fSStephan Aßmus	AutoLocker<Locker> locker(fLock);
3395a1d355fSStephan Aßmus
3405a1d355fSStephan Aßmus	// remove all entries and send respective "entry removed" events
3415a1d355fSStephan Aßmus	for (EntryMap::Iterator it = fEntries->GetIterator(); it.HasNext();) {
3425a1d355fSStephan Aßmus		ShareDirEntry* entry = it.Next().value;
3435a1d355fSStephan Aßmus
3445a1d355fSStephan Aßmus		NotifyListener(B_ENTRY_REMOVED, fVolumeManager->GetID(),
3455a1d355fSStephan Aßmus			entry->GetDirectory()->GetID(), 0, entry->GetNode()->GetID(),
3465a1d355fSStephan Aßmus			entry->GetName());
3475a1d355fSStephan Aßmus
3485a1d355fSStephan Aßmus		_RemoveEntry(entry);
3495a1d355fSStephan Aßmus	}
350de48af7aSAugustin Cavalier	fEntries->Clear();
3515a1d355fSStephan Aßmus
3525a1d355fSStephan Aßmus	// get all IDs
3535a1d355fSStephan Aßmus	int32 count = fNodes->Size();
3545a1d355fSStephan Aßmus	if (count == 0)
3555a1d355fSStephan Aßmus		return;
3564cfa5b2dSJérôme Duval	PRINT("  %" B_PRId32 " nodes to remove\n", count);
3575a1d355fSStephan Aßmus	vnode_id* ids = new(std::nothrow) vnode_id[count];
3585a1d355fSStephan Aßmus	if (!ids) {
3595a1d355fSStephan Aßmus		ERROR("ShareVolume::PrepareToUnmount(): ERROR: Insufficient memory to "
3605a1d355fSStephan Aßmus			"allocate the node ID array!\n");
3615a1d355fSStephan Aßmus		return;
3625a1d355fSStephan Aßmus	}
3635a1d355fSStephan Aßmus	ArrayDeleter<vnode_id> _(ids);
3645a1d355fSStephan Aßmus	count = 0;
3655a1d355fSStephan Aßmus	for (NodeMap::Iterator it = fNodes->GetIterator(); it.HasNext();) {
3665a1d355fSStephan Aßmus		ShareNode* node = it.Next().value;
3675a1d355fSStephan Aßmus		ids[count++] = node->GetID();
3685a1d355fSStephan Aßmus	}
3695a1d355fSStephan Aßmus
3705a1d355fSStephan Aßmus	// Remove all nodes that are not known to the VFS right away.
3715a1d355fSStephan Aßmus	// If the netfs is already in the process of being unmounted, GetVNode()
3725a1d355fSStephan Aßmus	// will fail and the GetVNode(), RemoveVNode(), PutVNode() method won't
3735a1d355fSStephan Aßmus	// work for removing them.
3745a1d355fSStephan Aßmus	int32 remainingCount = 0;
3755a1d355fSStephan Aßmus	for (int32 i = 0; i < count; i++) {
3765a1d355fSStephan Aßmus		if (Node* node = fNodes->Get(ids[i])) {
3775a1d355fSStephan Aßmus			if (node->IsKnownToVFS()) {
3785a1d355fSStephan Aßmus				// node is known to VFS; we need to use the GetVNode(),
3795a1d355fSStephan Aßmus				// RemoveVNode(), PutVNode() method
3805a1d355fSStephan Aßmus				ids[remainingCount++] = ids[i];
3815a1d355fSStephan Aßmus			} else {
3825a1d355fSStephan Aßmus				// node is not known to VFS; just remove and delete it
3835a1d355fSStephan Aßmus				fNodes->Remove(node->GetID());
3845a1d355fSStephan Aßmus				_RemoveLocalNodeID(node->GetID());
3855a1d355fSStephan Aßmus				if (node != fRootNode)
3865a1d355fSStephan Aßmus					delete node;
3875a1d355fSStephan Aßmus			}
3885a1d355fSStephan Aßmus		}
3895a1d355fSStephan Aßmus	}
3905a1d355fSStephan Aßmus	count = remainingCount;
3915a1d355fSStephan Aßmus
3925a1d355fSStephan Aßmus	locker.Unlock();
3935a1d355fSStephan Aßmus
3945a1d355fSStephan Aßmus	// remove the nodes
3955a1d355fSStephan Aßmus	for (int32 i = 0; i < count; i++) {
3965a1d355fSStephan Aßmus		Node* node;
3975a1d355fSStephan Aßmus		if (GetVNode(ids[i], &node) == B_OK) {
3984cfa5b2dSJérôme Duval			PRINT("  removing node %" B_PRIdINO "\n", ids[i]);
3995a1d355fSStephan Aßmus			Volume::RemoveVNode(ids[i]);
4005a1d355fSStephan Aßmus			PutVNode(ids[i]);
4015a1d355fSStephan Aßmus		}
4025a1d355fSStephan Aßmus	}
4035a1d355fSStephan Aßmus
4045a1d355fSStephan Aßmus	// remove ourselves for the server connection
4055a1d355fSStephan Aßmus	if (fServerConnection)
4065a1d355fSStephan Aßmus		fServerConnection->RemoveVolume(this);
4075a1d355fSStephan Aßmus
4085a1d355fSStephan Aßmus	// delete all entries
4095a1d355fSStephan Aßmus
4105a1d355fSStephan AßmusPRINT(("ShareVolume::PrepareToUnmount() done\n"));
4115a1d355fSStephan Aßmus}
4125a1d355fSStephan Aßmus
4135a1d355fSStephan Aßmus// RemoveChildVolume
4145a1d355fSStephan Aßmusvoid
4155a1d355fSStephan AßmusShareVolume::RemoveChildVolume(Volume* volume)
4165a1d355fSStephan Aßmus{
4175a1d355fSStephan Aßmus	// should never be called
4185a1d355fSStephan Aßmus	WARN("WARNING: ShareVolume::RemoveChildVolume(%p) invoked!\n", volume);
4195a1d355fSStephan Aßmus}
4205a1d355fSStephan Aßmus
4215a1d355fSStephan Aßmus
4225a1d355fSStephan Aßmus// #pragma mark -
4235a1d355fSStephan Aßmus// #pragma mark ----- FS -----
4245a1d355fSStephan Aßmus
4255a1d355fSStephan Aßmus// Unmount
4265a1d355fSStephan Aßmusstatus_t
4275a1d355fSStephan AßmusShareVolume::Unmount()
4285a1d355fSStephan Aßmus{
4295a1d355fSStephan Aßmus	if (_IsConnected()) {
4305a1d355fSStephan Aßmus		// send the request
4315a1d355fSStephan Aßmus		UnmountRequest request;
4325a1d355fSStephan Aßmus		request.volumeID = fID;
4335a1d355fSStephan Aßmus		fConnection->SendRequest(&request);
4345a1d355fSStephan Aßmus	}
4355a1d355fSStephan Aßmus	return B_OK;
4365a1d355fSStephan Aßmus}
4375a1d355fSStephan Aßmus
4385a1d355fSStephan Aßmus// Sync
4395a1d355fSStephan Aßmusstatus_t
4405a1d355fSStephan AßmusShareVolume::Sync()
4415a1d355fSStephan Aßmus{
4425a1d355fSStephan Aßmus	// TODO: Implement?
4435a1d355fSStephan Aßmus	// We can't implement this without risking an endless recursion. The server
4445a1d355fSStephan Aßmus	// could only invoke sync(), which would sync all FSs, including a NetFS
4455a1d355fSStephan Aßmus	// which might be connected with a server running alongside this client.
4465a1d355fSStephan Aßmus	// We could introduce a sync flag to break the recursion. This might be
4475a1d355fSStephan Aßmus	// risky though.
4485a1d355fSStephan Aßmus	return B_OK;
4495a1d355fSStephan Aßmus}
4505a1d355fSStephan Aßmus
4515a1d355fSStephan Aßmus
4525a1d355fSStephan Aßmus// #pragma mark -
4535a1d355fSStephan Aßmus// #pragma mark ----- vnodes -----
4545a1d355fSStephan Aßmus
4555a1d355fSStephan Aßmus// ReadVNode
4565a1d355fSStephan Aßmusstatus_t
4575a1d355fSStephan AßmusShareVolume::ReadVNode(vnode_id vnid, char reenter, Node** _node)
4585a1d355fSStephan Aßmus{
4595a1d355fSStephan Aßmus	// check the map, maybe it's already loaded
4605a1d355fSStephan Aßmus	ShareNode* node = NULL;
4615a1d355fSStephan Aßmus	{
4625a1d355fSStephan Aßmus		AutoLocker<Locker> _(fLock);
4635a1d355fSStephan Aßmus		node = _GetNodeByLocalID(vnid);
4645a1d355fSStephan Aßmus		if (node) {
4655a1d355fSStephan Aßmus			node->SetKnownToVFS(true);
4665a1d355fSStephan Aßmus			*_node = node;
4675a1d355fSStephan Aßmus
4685a1d355fSStephan Aßmus			// add a volume reference for the node
46988e38c17SIngo Weinhold			AcquireReference();
4705a1d355fSStephan Aßmus
4715a1d355fSStephan Aßmus			return B_OK;
4725a1d355fSStephan Aßmus		}
4735a1d355fSStephan Aßmus	}
4745a1d355fSStephan Aßmus
4755a1d355fSStephan Aßmus	// not yet loaded: send a request to the server
4765a1d355fSStephan Aßmus	if (!_EnsureShareMounted())
4775a1d355fSStephan Aßmus		return ERROR_NOT_CONNECTED;
4785a1d355fSStephan Aßmus
4795a1d355fSStephan Aßmus	// get the remote ID
4805a1d355fSStephan Aßmus	NodeID remoteID;
4815a1d355fSStephan Aßmus	status_t error = _GetRemoteNodeID(vnid, &remoteID);
4825a1d355fSStephan Aßmus	if (error != B_OK)
4835a1d355fSStephan Aßmus		return error;
4845a1d355fSStephan Aßmus
4855a1d355fSStephan Aßmus	// prepare the request
4865a1d355fSStephan Aßmus	ReadVNodeRequest request;
4875a1d355fSStephan Aßmus	request.volumeID = fID;
4885a1d355fSStephan Aßmus	request.nodeID = remoteID;
4895a1d355fSStephan Aßmus
4905a1d355fSStephan Aßmus	// send the request
4915a1d355fSStephan Aßmus	ReadVNodeReply* reply;
4925a1d355fSStephan Aßmus	error = SendRequest(fConnection, &request, &reply);
4935a1d355fSStephan Aßmus	if (error != B_OK)
4945a1d355fSStephan Aßmus		RETURN_ERROR(error);
4955a1d355fSStephan Aßmus	ObjectDeleter<Request> replyDeleter(reply);
4965a1d355fSStephan Aßmus	if (reply->error != B_OK)
4975a1d355fSStephan Aßmus		RETURN_ERROR(reply->error);
4985a1d355fSStephan Aßmus
4995a1d355fSStephan Aßmus	// add the node
5005a1d355fSStephan Aßmus	AutoLocker<Locker> _(fLock);
5015a1d355fSStephan Aßmus	error = _LoadNode(reply->nodeInfo, &node);
5025a1d355fSStephan Aßmus	if (error != B_OK)
5035a1d355fSStephan Aßmus		RETURN_ERROR(error);
5045a1d355fSStephan Aßmus	node->SetKnownToVFS(true);
5055a1d355fSStephan Aßmus	*_node = node;
5065a1d355fSStephan Aßmus
5075a1d355fSStephan Aßmus	// add a volume reference for the node
50888e38c17SIngo Weinhold	AcquireReference();
5095a1d355fSStephan Aßmus
5105a1d355fSStephan Aßmus	return B_OK;
5115a1d355fSStephan Aßmus}
5125a1d355fSStephan Aßmus
5135a1d355fSStephan Aßmus// WriteVNode
5145a1d355fSStephan Aßmusstatus_t
5155a1d355fSStephan AßmusShareVolume::WriteVNode(Node* node, char reenter)
5165a1d355fSStephan Aßmus{
5175a1d355fSStephan Aßmus	AutoLocker<Locker> locker(fLock);
5185a1d355fSStephan Aßmus	node->SetKnownToVFS(false);
5195a1d355fSStephan Aßmus
5205a1d355fSStephan Aßmus	// surrender the node's volume reference
5215a1d355fSStephan Aßmus	locker.Unlock();
5225a1d355fSStephan Aßmus	PutVolume();
5235a1d355fSStephan Aßmus
5245a1d355fSStephan Aßmus	return B_OK;
5255a1d355fSStephan Aßmus}
5265a1d355fSStephan Aßmus
5275a1d355fSStephan Aßmus// RemoveVNode
5285a1d355fSStephan Aßmusstatus_t
5295a1d355fSStephan AßmusShareVolume::RemoveVNode(Node* node, char reenter)
5305a1d355fSStephan Aßmus{
5315a1d355fSStephan Aßmus	AutoLocker<Locker> locker(fLock);
5325a1d355fSStephan Aßmus	node->SetKnownToVFS(false);
5335a1d355fSStephan Aßmus	fNodes->Remove(node->GetID());
5345a1d355fSStephan Aßmus	_RemoveLocalNodeID(node->GetID());
5355a1d355fSStephan Aßmus	if (node != fRootNode)
5365a1d355fSStephan Aßmus		delete node;
5375a1d355fSStephan Aßmus
5385a1d355fSStephan Aßmus	// surrender the node's volume reference
539