xref: /haiku/src/add-ons/kernel/file_systems/netfs/client/ShareVolume.cpp (revision 20f046edb99c55b1af0a17340ff8a581d000bc5c)
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ßmus static const int32 kMaxWriteBufferSize	= 64 * 1024;	// 64 KB
395a1d355fSStephan Aßmus static const int32 kUserBufferSize = 256;
405a1d355fSStephan Aßmus static const int32 kPasswordBufferSize = 256;
415a1d355fSStephan Aßmus 
425a1d355fSStephan Aßmus // connection states
435a1d355fSStephan Aßmus enum {
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ßmus struct 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ßmus struct 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ßmus struct ShareVolume::EntryMap : HashMap<EntryKey, ShareDirEntry*> {
1105a1d355fSStephan Aßmus };
1115a1d355fSStephan Aßmus 
1125a1d355fSStephan Aßmus // LocalNodeIDMap
1135a1d355fSStephan Aßmus struct ShareVolume::LocalNodeIDMap : HashMap<NodeID, ino_t> {
1145a1d355fSStephan Aßmus };
1155a1d355fSStephan Aßmus 
1165a1d355fSStephan Aßmus // RemoteNodeIDMap
1175a1d355fSStephan Aßmus struct ShareVolume::RemoteNodeIDMap : HashMap<HashKey64<ino_t>, NodeID> {
1185a1d355fSStephan Aßmus };
1195a1d355fSStephan Aßmus 
1205a1d355fSStephan Aßmus // DirCookie
1215a1d355fSStephan Aßmus struct ShareVolume::DirCookie {
1225a1d355fSStephan Aßmus 	ShareDirIterator*	iterator;
1235a1d355fSStephan Aßmus };
1245a1d355fSStephan Aßmus 
1255a1d355fSStephan Aßmus // AttrDirCookie
1265a1d355fSStephan Aßmus struct 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;
1355a1d355fSStephan Aßmus 	int32					cookie;
1365a1d355fSStephan Aßmus 	bool					rewind;
1375a1d355fSStephan Aßmus };
1385a1d355fSStephan Aßmus 
1395a1d355fSStephan Aßmus // AttrDirIteratorMap
1405a1d355fSStephan Aßmus struct 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ßmus ShareVolume::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ßmus ShareVolume::~ShareVolume()
1795a1d355fSStephan Aßmus {
1805a1d355fSStephan Aßmus PRINT(("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 "
194*20f046edSJé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 "
206*20f046edSJé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ßmus nspace_id
2285a1d355fSStephan Aßmus ShareVolume::GetID() const
2295a1d355fSStephan Aßmus {
2305a1d355fSStephan Aßmus 	return fID;
2315a1d355fSStephan Aßmus }
2325a1d355fSStephan Aßmus 
2335a1d355fSStephan Aßmus // IsReadOnly
2345a1d355fSStephan Aßmus bool
2355a1d355fSStephan Aßmus ShareVolume::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ßmus bool
2425a1d355fSStephan Aßmus ShareVolume::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ßmus status_t
2495a1d355fSStephan Aßmus ShareVolume::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ßmus void
3175a1d355fSStephan Aßmus ShareVolume::Uninit()
3185a1d355fSStephan Aßmus {
3195a1d355fSStephan Aßmus 	Volume::Uninit();
3205a1d355fSStephan Aßmus }
3215a1d355fSStephan Aßmus 
3225a1d355fSStephan Aßmus // GetRootNode
3235a1d355fSStephan Aßmus Node*
3245a1d355fSStephan Aßmus ShareVolume::GetRootNode() const
3255a1d355fSStephan Aßmus {
3265a1d355fSStephan Aßmus 	return fRootNode;
3275a1d355fSStephan Aßmus }
3285a1d355fSStephan Aßmus 
3295a1d355fSStephan Aßmus // PrepareToUnmount
3305a1d355fSStephan Aßmus void
3315a1d355fSStephan Aßmus ShareVolume::PrepareToUnmount()
3325a1d355fSStephan Aßmus {
3335a1d355fSStephan Aßmus PRINT(("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 		it.Remove();
3495a1d355fSStephan Aßmus 		_RemoveEntry(entry);
3505a1d355fSStephan Aßmus 	}
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;
3563c1afd35SPawel Dziepak 	PRINT("  %ld 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) {
3983c1afd35SPawel Dziepak 			PRINT("  removing node %lld\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ßmus PRINT(("ShareVolume::PrepareToUnmount() done\n"));
4115a1d355fSStephan Aßmus }
4125a1d355fSStephan Aßmus 
4135a1d355fSStephan Aßmus // RemoveChildVolume
4145a1d355fSStephan Aßmus void
4155a1d355fSStephan Aßmus ShareVolume::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ßmus status_t
4275a1d355fSStephan Aßmus ShareVolume::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ßmus status_t
4405a1d355fSStephan Aßmus ShareVolume::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ßmus status_t
4575a1d355fSStephan Aßmus ShareVolume::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ßmus status_t
5155a1d355fSStephan Aßmus ShareVolume::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ßmus status_t
5295a1d355fSStephan Aßmus ShareVolume::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
5395a1d355fSStephan Aßmus 	locker.Unlock();
5405a1d355fSStephan Aßmus 	PutVolume();
5415a1d355fSStephan Aßmus 
5425a1d355fSStephan Aßmus 	return B_OK;
5435a1d355fSStephan Aßmus }
5445a1d355fSStephan Aßmus 
5455a1d355fSStephan Aßmus 
5465a1d355fSStephan Aßmus // #pragma mark -
5475a1d355fSStephan Aßmus // #pragma mark ----- nodes -----
5485a1d355fSStephan Aßmus 
5495a1d355fSStephan Aßmus // FSync
5505a1d355fSStephan Aßmus status_t
5515a1d355fSStephan Aßmus ShareVolume::FSync(Node* _node)
5525a1d355fSStephan Aßmus {
5535a1d355fSStephan Aßmus 	// TODO: Implement!
5545a1d355fSStephan Aßmus 	return B_BAD_VALUE;
5555a1d355fSStephan Aßmus }
5565a1d355fSStephan Aßmus 
5575a1d355fSStephan Aßmus // ReadStat
5585a1d355fSStephan Aßmus status_t
5595a1d355fSStephan Aßmus ShareVolume::ReadStat(Node* _node, struct stat* st)
5605a1d355fSStephan Aßmus {
5615a1d355fSStephan Aßmus 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
5625a1d355fSStephan Aßmus 
5635a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fLock);
5645a1d355fSStephan Aßmus 	*st = node->GetNodeInfo().st;
5655a1d355fSStephan Aßmus 	st->st_dev = fVolumeManager->GetID();
5665a1d355fSStephan Aßmus 	st->st_ino = node->GetID();
5675a1d355fSStephan Aßmus 	// we set the UID/GID fields to the one who mounted the FS
5685a1d355fSStephan Aßmus 	st->st_uid = fVolumeManager->GetMountUID();
5695a1d355fSStephan Aßmus 	st->st_gid = fVolumeManager->GetMountGID();
5705a1d355fSStephan Aßmus 	return B_OK;
5715a1d355fSStephan Aßmus }
5725a1d355fSStephan Aßmus 
5735a1d355fSStephan Aßmus // WriteStat
5745a1d355fSStephan Aßmus status_t
5755a1d355fSStephan Aßmus ShareVolume::WriteStat(Node* _node, struct stat *st, uint32 mask)
5765a1d355fSStephan Aßmus {
5775a1d355fSStephan Aßmus 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
5785a1d355fSStephan Aßmus 
5795a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
5805a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
5815a1d355fSStephan Aßmus 
5825a1d355fSStephan Aßmus 	// check read-only
5835a1d355fSStephan Aßmus 	if (IsReadOnly())
5845a1d355fSStephan Aßmus 		return B_PERMISSION_DENIED;
5855a1d355fSStephan Aßmus 	// prepare the request
5865a1d355fSStephan Aßmus 	WriteStatRequest request;
5875a1d355fSStephan Aßmus 	request.volumeID = fID;
5885a1d355fSStephan Aßmus 	request.nodeID = node->GetRemoteID();
5895a1d355fSStephan Aßmus 	request.nodeInfo.st = *st;
5905a1d355fSStephan Aßmus 	request.mask = mask;
5915a1d355fSStephan Aßmus 	// send the request
5925a1d355fSStephan Aßmus 	WriteStatReply* reply;
5935a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
5945a1d355fSStephan Aßmus 	if (error != B_OK)
5955a1d355fSStephan Aßmus 		RETURN_ERROR(error);
5965a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
5975a1d355fSStephan Aßmus 	// update the node
5985a1d355fSStephan Aßmus 	if (reply->nodeInfoValid)
5995a1d355fSStephan Aßmus 		_UpdateNode(reply->nodeInfo);
6005a1d355fSStephan Aßmus 	if (reply->error != B_OK)
6015a1d355fSStephan Aßmus 		RETURN_ERROR(reply->error);
6025a1d355fSStephan Aßmus 	return B_OK;
6035a1d355fSStephan Aßmus }
6045a1d355fSStephan Aßmus 
6055a1d355fSStephan Aßmus // Access
6065a1d355fSStephan Aßmus status_t
6075a1d355fSStephan Aßmus ShareVolume::Access(Node* _node, int mode)
6085a1d355fSStephan Aßmus {
6095a1d355fSStephan Aßmus 	// TODO: Implement.
6105a1d355fSStephan Aßmus 	return B_OK;
6115a1d355fSStephan Aßmus }
6125a1d355fSStephan Aßmus 
6135a1d355fSStephan Aßmus 
6145a1d355fSStephan Aßmus // #pragma mark -
6155a1d355fSStephan Aßmus // #pragma mark ----- files -----
6165a1d355fSStephan Aßmus 
6175a1d355fSStephan Aßmus // Create
6185a1d355fSStephan Aßmus status_t
6195a1d355fSStephan Aßmus ShareVolume::Create(Node* _dir, const char* name, int openMode, int mode,
6205a1d355fSStephan Aßmus 	vnode_id* vnid, void** cookie)
6215a1d355fSStephan Aßmus {
6225a1d355fSStephan Aßmus 	ShareDir* dir = dynamic_cast<ShareDir*>(_dir);
6235a1d355fSStephan Aßmus 	if (!dir)
6245a1d355fSStephan Aßmus 		return B_BAD_VALUE;
6255a1d355fSStephan Aßmus 
6265a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
6275a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
6285a1d355fSStephan Aßmus 
6295a1d355fSStephan Aßmus 	// check permissions
6305a1d355fSStephan Aßmus 	if (IsReadOnly())
6315a1d355fSStephan Aßmus 		return B_PERMISSION_DENIED;
6325a1d355fSStephan Aßmus 	if (IsVNodeRemoved(dir->GetID()) > 0)
6335a1d355fSStephan Aßmus 		RETURN_ERROR(B_NOT_ALLOWED);
6345a1d355fSStephan Aßmus 
6355a1d355fSStephan Aßmus 	// prepare the request
6365a1d355fSStephan Aßmus 	CreateFileRequest request;
6375a1d355fSStephan Aßmus 	request.volumeID = fID;
6385a1d355fSStephan Aßmus 	request.directoryID = dir->GetRemoteID();
6395a1d355fSStephan Aßmus 	request.name.SetTo(name);
6405a1d355fSStephan Aßmus 	request.openMode = openMode;
6415a1d355fSStephan Aßmus 	request.mode = mode;
6425a1d355fSStephan Aßmus 
6435a1d355fSStephan Aßmus 	// send the request
6445a1d355fSStephan Aßmus 	CreateFileReply* reply;
6455a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
6465a1d355fSStephan Aßmus 	if (error != B_OK)
6475a1d355fSStephan Aßmus 		RETURN_ERROR(error);
6485a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
6495a1d355fSStephan Aßmus 	if (reply->error != B_OK)
6505a1d355fSStephan Aßmus 		RETURN_ERROR(reply->error);
6515a1d355fSStephan Aßmus 
6525a1d355fSStephan Aßmus 	// add/update the entry
6535a1d355fSStephan Aßmus 	vnode_id localID = -1;
6545a1d355fSStephan Aßmus 	EntryInfo* entryInfo = &reply->entryInfo;
6555a1d355fSStephan Aßmus 	while (true) {
6565a1d355fSStephan Aßmus 		// get an up to date entry info
6575a1d355fSStephan Aßmus 		WalkReply* walkReply = NULL;
6585a1d355fSStephan Aßmus 		if (!entryInfo) {
6595a1d355fSStephan Aßmus 			error = _Walk(reply->entryInfo.directoryID,
6605a1d355fSStephan Aßmus 				reply->entryInfo.name.GetString(), false, &walkReply);
6615a1d355fSStephan Aßmus 			if (error != B_OK)
6625a1d355fSStephan Aßmus 				break;
6635a1d355fSStephan Aßmus 
6645a1d355fSStephan Aßmus 			entryInfo = &walkReply->entryInfo;
6655a1d355fSStephan Aßmus 		}
6665a1d355fSStephan Aßmus 		ObjectDeleter<Request> walkReplyDeleter(walkReply);
6675a1d355fSStephan Aßmus 
6685a1d355fSStephan Aßmus 		AutoLocker<Locker> locker(fLock);
6695a1d355fSStephan Aßmus 
6705a1d355fSStephan Aßmus 		// check, if the info is obsolete
6715a1d355fSStephan Aßmus 		if (_IsObsoleteEntryInfo(*entryInfo)) {
6725a1d355fSStephan Aßmus 			entryInfo = NULL;
6735a1d355fSStephan Aßmus 			continue;
6745a1d355fSStephan Aßmus 		}
6755a1d355fSStephan Aßmus 
6765a1d355fSStephan Aßmus 		// load the entry
6775a1d355fSStephan Aßmus 		ShareDirEntry* entry;
6785a1d355fSStephan Aßmus 		error = _LoadEntry(dir, *entryInfo, &entry);
6795a1d355fSStephan Aßmus 		if (error == B_OK)
6805a1d355fSStephan Aßmus 			localID = entry->GetNode()->GetID();
6815a1d355fSStephan Aßmus 
6825a1d355fSStephan Aßmus 		break;
6835a1d355fSStephan Aßmus 	}
6845a1d355fSStephan Aßmus 
6855a1d355fSStephan Aßmus 	if (error == B_OK) {
6865a1d355fSStephan Aßmus 		Node* _node;
6875a1d355fSStephan Aßmus 		error = GetVNode(localID, &_node);
6885a1d355fSStephan Aßmus 	}
6895a1d355fSStephan Aßmus 
6905a1d355fSStephan Aßmus 	// set the results / close the handle on error
6915a1d355fSStephan Aßmus 	if (error == B_OK) {
6925a1d355fSStephan Aßmus 		*vnid = localID;
6935a1d355fSStephan Aßmus 		*cookie = (void*)reply->cookie;
6945a1d355fSStephan Aßmus 	} else
6955a1d355fSStephan Aßmus 		_Close(reply->cookie);
6965a1d355fSStephan Aßmus 
6975a1d355fSStephan Aßmus 	RETURN_ERROR(error);
6985a1d355fSStephan Aßmus }
6995a1d355fSStephan Aßmus 
7005a1d355fSStephan Aßmus // Open
7015a1d355fSStephan Aßmus status_t
7025a1d355fSStephan Aßmus ShareVolume::Open(Node* _node, int openMode, void** cookie)
7035a1d355fSStephan Aßmus {
7045a1d355fSStephan Aßmus 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
7055a1d355fSStephan Aßmus 
7065a1d355fSStephan Aßmus // TODO: Allow opening the root node?
7075a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
7085a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
7095a1d355fSStephan Aßmus 
7105a1d355fSStephan Aßmus 	// check the open mode
7115a1d355fSStephan Aßmus 	if (IsReadOnly()) {
7125a1d355fSStephan Aßmus 		if ((openMode & O_RWMASK) == O_WRONLY)
7135a1d355fSStephan Aßmus 			return B_PERMISSION_DENIED;
7145a1d355fSStephan Aßmus 		if (openMode & O_TRUNC)
7155a1d355fSStephan Aßmus 			return B_PERMISSION_DENIED;
7165a1d355fSStephan Aßmus 		if ((openMode & O_RWMASK) == O_RDWR)
7175a1d355fSStephan Aßmus 			openMode = (openMode & ~O_RWMASK) | O_RDONLY;
7185a1d355fSStephan Aßmus 	}
7195a1d355fSStephan Aßmus 	// prepare the request
7205a1d355fSStephan Aßmus 	OpenRequest request;
7215a1d355fSStephan Aßmus 	request.volumeID = fID;
7225a1d355fSStephan Aßmus 	request.nodeID = node->GetRemoteID();
7235a1d355fSStephan Aßmus 	request.openMode = openMode;
7245a1d355fSStephan Aßmus 	// send the request
7255a1d355fSStephan Aßmus 	OpenReply* reply;
7265a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
7275a1d355fSStephan Aßmus 	if (error != B_OK)
7285a1d355fSStephan Aßmus 		RETURN_ERROR(error);
7295a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
7305a1d355fSStephan Aßmus 	if (reply->error != B_OK)
7315a1d355fSStephan Aßmus 		RETURN_ERROR(reply->error);
7325a1d355fSStephan Aßmus 	// update the node
7335a1d355fSStephan Aßmus 	_UpdateNode(reply->nodeInfo);
7345a1d355fSStephan Aßmus 	*cookie = (void*)reply->cookie;
7355a1d355fSStephan Aßmus 	return B_OK;
7365a1d355fSStephan Aßmus }
7375a1d355fSStephan Aßmus 
7385a1d355fSStephan Aßmus // Close
7395a1d355fSStephan Aßmus status_t
7405a1d355fSStephan Aßmus ShareVolume::Close(Node* _node, void* cookie)
7415a1d355fSStephan Aßmus {
7425a1d355fSStephan Aßmus 	// no-op: FreeCookie does the job
7435a1d355fSStephan Aßmus 	return B_OK;
7445a1d355fSStephan Aßmus }
7455a1d355fSStephan Aßmus 
7465a1d355fSStephan Aßmus // FreeCookie
7475a1d355fSStephan Aßmus status_t
7485a1d355fSStephan Aßmus ShareVolume::FreeCookie(Node* _node, void* cookie)
7495a1d355fSStephan Aßmus {
7505a1d355fSStephan Aßmus 	return _Close((int32)cookie);
7515a1d355fSStephan Aßmus }
7525a1d355fSStephan Aßmus 
7535a1d355fSStephan Aßmus // Read
7545a1d355fSStephan Aßmus status_t
7555a1d355fSStephan Aßmus ShareVolume::Read(Node* _node, void* cookie, off_t pos, void* _buffer,
7565a1d355fSStephan Aßmus 	size_t bufferSize, size_t* _bytesRead)
7575a1d355fSStephan Aßmus {
7585a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
7595a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
7605a1d355fSStephan Aßmus 
7615a1d355fSStephan Aßmus 	*_bytesRead = 0;
7625a1d355fSStephan Aßmus 	if (bufferSize == 0)
7635a1d355fSStephan Aßmus 		return B_OK;
7645a1d355fSStephan Aßmus 	uint8* buffer = (uint8*)_buffer;
7655a1d355fSStephan Aßmus 	// prepare the request
7665a1d355fSStephan Aßmus 	ReadRequest request;
7675a1d355fSStephan Aßmus 	request.volumeID = fID;
7685a1d355fSStephan Aßmus 	request.cookie = (int32)cookie;
7695a1d355fSStephan Aßmus 	request.pos = pos;
7705a1d355fSStephan Aßmus 	request.size = bufferSize;
7715a1d355fSStephan Aßmus 
7725a1d355fSStephan Aßmus 	struct ReadRequestHandler : public RequestHandler {
7735a1d355fSStephan Aßmus 		uint8*	buffer;
7745a1d355fSStephan Aßmus 		off_t	pos;
7755a1d355fSStephan Aßmus 		int32	bufferSize;
7765a1d355fSStephan Aßmus 		int32	bytesRead;
7775a1d355fSStephan Aßmus 
7785a1d355fSStephan Aßmus 		ReadRequestHandler(uint8* buffer, off_t pos, int32 bufferSize)
7795a1d355fSStephan Aßmus 			: buffer(buffer),
7805a1d355fSStephan Aßmus 			  pos(pos),
7815a1d355fSStephan Aßmus 			  bufferSize(bufferSize),
7825a1d355fSStephan Aßmus 			  bytesRead(0)
7835a1d355fSStephan Aßmus 		{
7845a1d355fSStephan Aßmus 		}
7855a1d355fSStephan Aßmus 
7865a1d355fSStephan Aßmus 		virtual status_t HandleRequest(Request* _reply, RequestChannel* channel)
7875a1d355fSStephan Aßmus 		{
7885a1d355fSStephan Aßmus 			// the passed request is deleted by the request port
7895a1d355fSStephan Aßmus 			ReadReply* reply = dynamic_cast<ReadReply*>(_reply);
7905a1d355fSStephan Aßmus 			if (!reply)
7915a1d355fSStephan Aßmus 				RETURN_ERROR(B_BAD_DATA);
7925a1d355fSStephan Aßmus 			// process the reply
7935a1d355fSStephan Aßmus 			status_t error = ProcessReply(reply);
7945a1d355fSStephan Aßmus 			if (error != B_OK)
7955a1d355fSStephan Aßmus 				return error;
7965a1d355fSStephan Aßmus 			bool moreToCome = reply->moreToCome;
7975a1d355fSStephan Aßmus 			while (moreToCome) {
7985a1d355fSStephan Aßmus 				// receive a reply
7995a1d355fSStephan Aßmus 				error = ReceiveRequest(channel, &reply);
8005a1d355fSStephan Aßmus 				if (error != B_OK)
8015a1d355fSStephan Aßmus 					RETURN_ERROR(error);
8025a1d355fSStephan Aßmus 				moreToCome = reply->moreToCome;
8035a1d355fSStephan Aßmus 				ObjectDeleter<Request> replyDeleter(reply);
8045a1d355fSStephan Aßmus 				// process the reply
8055a1d355fSStephan Aßmus 				error = ProcessReply(reply);
8065a1d355fSStephan Aßmus 				if (error != B_OK)
8075a1d355fSStephan Aßmus 					return error;
8085a1d355fSStephan Aßmus 			}
8095a1d355fSStephan Aßmus 			return B_OK;
8105a1d355fSStephan Aßmus 		}
8115a1d355fSStephan Aßmus 
8125a1d355fSStephan Aßmus 		status_t ProcessReply(ReadReply* reply)
8135a1d355fSStephan Aßmus 		{
8145a1d355fSStephan Aßmus 			if (reply->error != B_OK)
8155a1d355fSStephan Aßmus 				RETURN_ERROR(reply->error);
8165a1d355fSStephan Aßmus 			// check the fields
8175a1d355fSStephan Aßmus 			if (reply->pos != pos)
8185a1d355fSStephan Aßmus 				RETURN_ERROR(B_BAD_DATA);
8195a1d355fSStephan Aßmus 			int32 bytesRead = reply->data.GetSize();
8205a1d355fSStephan Aßmus 			if (bytesRead > (int32)bufferSize)
8215a1d355fSStephan Aßmus 				RETURN_ERROR(B_BAD_DATA);
8225a1d355fSStephan Aßmus 			// copy the data into the buffer
8235a1d355fSStephan Aßmus 			if (bytesRead > 0)
8245a1d355fSStephan Aßmus 				memcpy(buffer, reply->data.GetData(), bytesRead);
8255a1d355fSStephan Aßmus 			pos += bytesRead;
8265a1d355fSStephan Aßmus 			buffer += bytesRead;
8275a1d355fSStephan Aßmus 			bufferSize -= bytesRead;
8285a1d355fSStephan Aßmus 			this->bytesRead += bytesRead;
8295a1d355fSStephan Aßmus 			return B_OK;
8305a1d355fSStephan Aßmus 		}
8315a1d355fSStephan Aßmus 	} requestHandler(buffer, pos, bufferSize);
8325a1d355fSStephan Aßmus 
8335a1d355fSStephan Aßmus 	// send the request
8345a1d355fSStephan Aßmus 	status_t error = fConnection->SendRequest(&request, &requestHandler);
8355a1d355fSStephan Aßmus 	if (error != B_OK)
8365a1d355fSStephan Aßmus 		RETURN_ERROR(error);
8375a1d355fSStephan Aßmus 	*_bytesRead = requestHandler.bytesRead;
8385a1d355fSStephan Aßmus 	return B_OK;
8395a1d355fSStephan Aßmus }
8405a1d355fSStephan Aßmus 
8415a1d355fSStephan Aßmus // Write
8425a1d355fSStephan Aßmus status_t
8435a1d355fSStephan Aßmus ShareVolume::Write(Node* _node, void* cookie, off_t pos, const void* _buffer,
8445a1d355fSStephan Aßmus 	size_t bufferSize, size_t* bytesWritten)
8455a1d355fSStephan Aßmus {
8465a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
8475a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
8485a1d355fSStephan Aßmus 
8495a1d355fSStephan Aßmus 	// check permissions
8505a1d355fSStephan Aßmus 	if (IsReadOnly())
8515a1d355fSStephan Aßmus 		return B_PERMISSION_DENIED;
8525a1d355fSStephan Aßmus 
8535a1d355fSStephan Aßmus 	*bytesWritten = 0;
8545a1d355fSStephan Aßmus 	off_t bytesLeft = bufferSize;
8555a1d355fSStephan Aßmus 	const char* buffer = (const char*)_buffer;
8565a1d355fSStephan Aßmus 	while (bytesLeft > 0) {
8575a1d355fSStephan Aßmus 		off_t toWrite = bytesLeft;
8585a1d355fSStephan Aßmus 		if (toWrite > kMaxWriteBufferSize)
8595a1d355fSStephan Aßmus 			toWrite = kMaxWriteBufferSize;
8605a1d355fSStephan Aßmus 
8615a1d355fSStephan Aßmus 		// prepare the request
8625a1d355fSStephan Aßmus 		WriteRequest request;
8635a1d355fSStephan Aßmus 		request.volumeID = fID;
8645a1d355fSStephan Aßmus 		request.cookie = (int32)cookie;
8655a1d355fSStephan Aßmus 		request.pos = pos;
8665a1d355fSStephan Aßmus 		request.data.SetTo(buffer, toWrite);
8675a1d355fSStephan Aßmus 
8685a1d355fSStephan Aßmus 		// send the request
8695a1d355fSStephan Aßmus 		WriteReply* reply;
8705a1d355fSStephan Aßmus 		status_t error = SendRequest(fConnection, &request, &reply);
8715a1d355fSStephan Aßmus 		if (error != B_OK)
8725a1d355fSStephan Aßmus 			RETURN_ERROR(error);
8735a1d355fSStephan Aßmus 		ObjectDeleter<Request> replyDeleter(reply);
8745a1d355fSStephan Aßmus 		if (reply->error != B_OK)
8755a1d355fSStephan Aßmus 			RETURN_ERROR(reply->error);
8765a1d355fSStephan Aßmus 
8775a1d355fSStephan Aßmus 		bytesLeft -= toWrite;
8785a1d355fSStephan Aßmus 		pos += toWrite;
8795a1d355fSStephan Aßmus 		buffer += toWrite;
8805a1d355fSStephan Aßmus 
8815a1d355fSStephan Aßmus // TODO: We should probably add an "up to date" flag for ShareNode (just as
8825a1d355fSStephan Aßmus // done for ShareAttrDir) and clear it at this point. Currently continuity
8835a1d355fSStephan Aßmus // inconsistencies could occur (e.g. a stat() after a write() returns
8845a1d355fSStephan Aßmus // obsolete data), depending on when the node monitoring update arrives.
8855a1d355fSStephan Aßmus 	}
8865a1d355fSStephan Aßmus 
8875a1d355fSStephan Aßmus 	*bytesWritten = bufferSize;
8885a1d355fSStephan Aßmus 	return B_OK;
8895a1d355fSStephan Aßmus }
8905a1d355fSStephan Aßmus 
8915a1d355fSStephan Aßmus 
8925a1d355fSStephan Aßmus // #pragma mark -
8935a1d355fSStephan Aßmus // #pragma mark ----- hard links / symlinks -----
8945a1d355fSStephan Aßmus 
8955a1d355fSStephan Aßmus // Link
8965a1d355fSStephan Aßmus status_t
8975a1d355fSStephan Aßmus ShareVolume::Link(Node* _dir, const char* name, Node* _node)
8985a1d355fSStephan Aßmus {
8995a1d355fSStephan Aßmus 	ShareNode* dir = dynamic_cast<ShareNode*>(_dir);
9005a1d355fSStephan Aßmus 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
9015a1d355fSStephan Aßmus 
9025a1d355fSStephan Aßmus 	if (!node || node->GetVolume() != this)
9035a1d355fSStephan Aßmus 		return B_NOT_ALLOWED;
9045a1d355fSStephan Aßmus 
9055a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
9065a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
9075a1d355fSStephan Aßmus 
9085a1d355fSStephan Aßmus 	// check permissions
9095a1d355fSStephan Aßmus 	if (IsReadOnly())
9105a1d355fSStephan Aßmus 		return B_PERMISSION_DENIED;
9115a1d355fSStephan Aßmus 	if (IsVNodeRemoved(dir->GetID()) > 0)
9125a1d355fSStephan Aßmus 		RETURN_ERROR(B_NOT_ALLOWED);
9135a1d355fSStephan Aßmus 	if (IsVNodeRemoved(node->GetID()) > 0)
9145a1d355fSStephan Aßmus 		RETURN_ERROR(B_NOT_ALLOWED);
9155a1d355fSStephan Aßmus 	// prepare the request
9165a1d355fSStephan Aßmus 	CreateLinkRequest request;
9175a1d355fSStephan Aßmus 	request.volumeID = fID;
9185a1d355fSStephan Aßmus 	request.directoryID = dir->GetRemoteID();
9195a1d355fSStephan Aßmus 	request.name.SetTo(name);
9205a1d355fSStephan Aßmus 	request.nodeID = node->GetRemoteID();
9215a1d355fSStephan Aßmus 	// send the request
9225a1d355fSStephan Aßmus 	CreateLinkReply* reply;
9235a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
9245a1d355fSStephan Aßmus 	if (error != B_OK)
9255a1d355fSStephan Aßmus 		RETURN_ERROR(error);
9265a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
9275a1d355fSStephan Aßmus 	RETURN_ERROR(reply->error);
9285a1d355fSStephan Aßmus }
9295a1d355fSStephan Aßmus 
9305a1d355fSStephan Aßmus // Unlink
9315a1d355fSStephan Aßmus status_t
9325a1d355fSStephan Aßmus ShareVolume::Unlink(Node* _dir, const char* name)
9335a1d355fSStephan Aßmus {
9345a1d355fSStephan Aßmus 	ShareNode* dir = dynamic_cast<ShareNode*>(_dir);
9355a1d355fSStephan Aßmus 
9365a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
9375a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
9385a1d355fSStephan Aßmus 
9395a1d355fSStephan Aßmus 	// check permissions
9405a1d355fSStephan Aßmus 	if (IsReadOnly())
9415a1d355fSStephan Aßmus 		return B_PERMISSION_DENIED;
9425a1d355fSStephan Aßmus 	// prepare the request
9435a1d355fSStephan Aßmus 	UnlinkRequest request;
9445a1d355fSStephan Aßmus 	request.volumeID = fID;
9455a1d355fSStephan Aßmus 	request.directoryID = dir->GetRemoteID();
9465a1d355fSStephan Aßmus 	request.name.SetTo(name);
9475a1d355fSStephan Aßmus 	// send the request
9485a1d355fSStephan Aßmus 	UnlinkReply* reply;
9495a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
9505a1d355fSStephan Aßmus 	if (error != B_OK)
9515a1d355fSStephan Aßmus 		RETURN_ERROR(error);
9525a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
9535a1d355fSStephan Aßmus 	RETURN_ERROR(reply->error);
9545a1d355fSStephan Aßmus }
9555a1d355fSStephan Aßmus 
9565a1d355fSStephan Aßmus // Symlink
9575a1d355fSStephan Aßmus status_t
9585a1d355fSStephan Aßmus ShareVolume::Symlink(Node* _dir, const char* name, const char* target)
9595a1d355fSStephan Aßmus {
9605a1d355fSStephan Aßmus 	ShareNode* dir = dynamic_cast<ShareNode*>(_dir);
9615a1d355fSStephan Aßmus 
9625a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
9635a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
9645a1d355fSStephan Aßmus 
9655a1d355fSStephan Aßmus 	// check permissions
9665a1d355fSStephan Aßmus 	if (IsReadOnly())
9675a1d355fSStephan Aßmus 		return B_PERMISSION_DENIED;
9685a1d355fSStephan Aßmus 	if (IsVNodeRemoved(dir->GetID()) > 0)
9695a1d355fSStephan Aßmus 		RETURN_ERROR(B_NOT_ALLOWED);
9705a1d355fSStephan Aßmus 	// prepare the request
9715a1d355fSStephan Aßmus 	CreateSymlinkRequest request;
9725a1d355fSStephan Aßmus 	request.volumeID = fID;
9735a1d355fSStephan Aßmus 	request.directoryID = dir->GetRemoteID();
9745a1d355fSStephan Aßmus 	request.name.SetTo(name);
9755a1d355fSStephan Aßmus 	request.target.SetTo(target);
9765a1d355fSStephan Aßmus 	// send the request
9775a1d355fSStephan Aßmus 	CreateSymlinkReply* reply;
9785a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
9795a1d355fSStephan Aßmus 	if (error != B_OK)
9805a1d355fSStephan Aßmus 		RETURN_ERROR(error);
9815a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
9825a1d355fSStephan Aßmus 	RETURN_ERROR(reply->error);
9835a1d355fSStephan Aßmus }
9845a1d355fSStephan Aßmus 
9855a1d355fSStephan Aßmus // ReadLink
9865a1d355fSStephan Aßmus status_t
9875a1d355fSStephan Aßmus ShareVolume::ReadLink(Node* _node, char* buffer, size_t bufferSize,
9885a1d355fSStephan Aßmus 	size_t* bytesRead)
9895a1d355fSStephan Aßmus {
9905a1d355fSStephan Aßmus 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
9915a1d355fSStephan Aßmus 
9925a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
9935a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
9945a1d355fSStephan Aßmus 
9955a1d355fSStephan Aßmus 	*bytesRead = 0;
9965a1d355fSStephan Aßmus 	// prepare the request
9975a1d355fSStephan Aßmus 	ReadLinkRequest request;
9985a1d355fSStephan Aßmus 	request.volumeID = fID;
9995a1d355fSStephan Aßmus 	request.nodeID = node->GetRemoteID();
10005a1d355fSStephan Aßmus 	request.maxSize = bufferSize;
10015a1d355fSStephan Aßmus 	// send the request
10025a1d355fSStephan Aßmus 	ReadLinkReply* reply;
10035a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
10045a1d355fSStephan Aßmus 	if (error != B_OK)
10055a1d355fSStephan Aßmus 		RETURN_ERROR(error);
10065a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
10075a1d355fSStephan Aßmus 	if (reply->error != B_OK)
10085a1d355fSStephan Aßmus 		RETURN_ERROR(reply->error);
10095a1d355fSStephan Aßmus 	if (reply->data.GetSize() > (int32)bufferSize)
10105a1d355fSStephan Aßmus 		RETURN_ERROR(B_BAD_DATA);
10115a1d355fSStephan Aßmus 	*bytesRead = reply->data.GetSize();
10125a1d355fSStephan Aßmus 	if (*bytesRead > 0)
10135a1d355fSStephan Aßmus 		memcpy(buffer, reply->data.GetData(), *bytesRead);
10145a1d355fSStephan Aßmus 	_UpdateNode(reply->nodeInfo);
10155a1d355fSStephan Aßmus 	return B_OK;
10165a1d355fSStephan Aßmus }
10175a1d355fSStephan Aßmus 
10185a1d355fSStephan Aßmus // Rename
10195a1d355fSStephan Aßmus status_t
10205a1d355fSStephan Aßmus ShareVolume::Rename(Node* _oldDir, const char* oldName, Node* _newDir,
10215a1d355fSStephan Aßmus 	const char* newName)
10225a1d355fSStephan Aßmus {
10235a1d355fSStephan Aßmus 	ShareNode* oldDir = dynamic_cast<ShareNode*>(_oldDir);
10245a1d355fSStephan Aßmus 	ShareNode* newDir = dynamic_cast<ShareNode*>(_newDir);
10255a1d355fSStephan Aßmus 
10265a1d355fSStephan Aßmus 	if (!newDir || newDir->GetVolume() != this)
10275a1d355fSStephan Aßmus 		return B_NOT_ALLOWED;
10285a1d355fSStephan Aßmus 
10295a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
10305a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
10315a1d355fSStephan Aßmus 
10325a1d355fSStephan Aßmus 	// check permissions
10335a1d355fSStephan Aßmus 	if (IsReadOnly())
10345a1d355fSStephan Aßmus 		return B_PERMISSION_DENIED;
10355a1d355fSStephan Aßmus 	if (IsVNodeRemoved(newDir->GetID()) > 0)
10365a1d355fSStephan Aßmus 		RETURN_ERROR(B_NOT_ALLOWED);
10375a1d355fSStephan Aßmus 	// prepare the request
10385a1d355fSStephan Aßmus 	RenameRequest request;
10395a1d355fSStephan Aßmus 	request.volumeID = fID;
10405a1d355fSStephan Aßmus 	request.oldDirectoryID = oldDir->GetRemoteID();
10415a1d355fSStephan Aßmus 	request.oldName.SetTo(oldName);
10425a1d355fSStephan Aßmus 	request.newDirectoryID = newDir->GetRemoteID();
10435a1d355fSStephan Aßmus 	request.newName.SetTo(newName);
10445a1d355fSStephan Aßmus 	// send the request
10455a1d355fSStephan Aßmus 	RenameReply* reply;
10465a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
10475a1d355fSStephan Aßmus 	if (error != B_OK)
10485a1d355fSStephan Aßmus 		RETURN_ERROR(error);
10495a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
10505a1d355fSStephan Aßmus 	RETURN_ERROR(reply->error);
10515a1d355fSStephan Aßmus }
10525a1d355fSStephan Aßmus 
10535a1d355fSStephan Aßmus 
10545a1d355fSStephan Aßmus // #pragma mark -
10555a1d355fSStephan Aßmus // #pragma mark ----- directories -----
10565a1d355fSStephan Aßmus 
10575a1d355fSStephan Aßmus // MkDir
10585a1d355fSStephan Aßmus status_t
10595a1d355fSStephan Aßmus ShareVolume::MkDir(Node* _dir, const char* name, int mode)
10605a1d355fSStephan Aßmus {
10615a1d355fSStephan Aßmus 	ShareNode* dir = dynamic_cast<ShareNode*>(_dir);
10625a1d355fSStephan Aßmus 
10635a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
10645a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
10655a1d355fSStephan Aßmus 
10665a1d355fSStephan Aßmus 	// check permissions
10675a1d355fSStephan Aßmus 	if (IsReadOnly())
10685a1d355fSStephan Aßmus 		return B_PERMISSION_DENIED;
10695a1d355fSStephan Aßmus 	if (IsVNodeRemoved(dir->GetID()) > 0)
10705a1d355fSStephan Aßmus 		RETURN_ERROR(B_NOT_ALLOWED);
10715a1d355fSStephan Aßmus 	// prepare the request
10725a1d355fSStephan Aßmus 	MakeDirRequest request;
10735a1d355fSStephan Aßmus 	request.volumeID = fID;
10745a1d355fSStephan Aßmus 	request.directoryID = dir->GetRemoteID();
10755a1d355fSStephan Aßmus 	request.name.SetTo(name);
10765a1d355fSStephan Aßmus 	request.mode = mode;
10775a1d355fSStephan Aßmus 	// send the request
10785a1d355fSStephan Aßmus 	MakeDirReply* reply;
10795a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
10805a1d355fSStephan Aßmus 	if (error != B_OK)
10815a1d355fSStephan Aßmus 		RETURN_ERROR(error);
10825a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
10835a1d355fSStephan Aßmus 	RETURN_ERROR(reply->error);
10845a1d355fSStephan Aßmus }
10855a1d355fSStephan Aßmus 
10865a1d355fSStephan Aßmus // RmDir
10875a1d355fSStephan Aßmus status_t
10885a1d355fSStephan Aßmus ShareVolume::RmDir(Node* _dir, const char* name)
10895a1d355fSStephan Aßmus {
10905a1d355fSStephan Aßmus 	ShareNode* dir = dynamic_cast<ShareNode*>(_dir);
10915a1d355fSStephan Aßmus 
10925a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
10935a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
10945a1d355fSStephan Aßmus 
10955a1d355fSStephan Aßmus 	// check permissions
10965a1d355fSStephan Aßmus 	if (IsReadOnly())
10975a1d355fSStephan Aßmus 		return B_PERMISSION_DENIED;
10985a1d355fSStephan Aßmus 	// prepare the request
10995a1d355fSStephan Aßmus 	RemoveDirRequest request;
11005a1d355fSStephan Aßmus 	request.volumeID = fID;
11015a1d355fSStephan Aßmus 	request.directoryID = dir->GetRemoteID();
11025a1d355fSStephan Aßmus 	request.name.SetTo(name);
11035a1d355fSStephan Aßmus 	// send the request
11045a1d355fSStephan Aßmus 	RemoveDirReply* reply;
11055a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
11065a1d355fSStephan Aßmus 	if (error != B_OK)
11075a1d355fSStephan Aßmus 		RETURN_ERROR(error);
11085a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
11095a1d355fSStephan Aßmus 	RETURN_ERROR(reply->error);
11105a1d355fSStephan Aßmus }
11115a1d355fSStephan Aßmus 
11125a1d355fSStephan Aßmus // OpenDir
11135a1d355fSStephan Aßmus status_t
11145a1d355fSStephan Aßmus ShareVolume::OpenDir(Node* _node, void** _cookie)
11155a1d355fSStephan Aßmus {
11165a1d355fSStephan Aßmus 	// we opendir() only directories
11175a1d355fSStephan Aßmus 	ShareDir* node = dynamic_cast<ShareDir*>(_node);
11185a1d355fSStephan Aßmus 	if (!node)
11195a1d355fSStephan Aßmus 		return B_NOT_ALLOWED;
11205a1d355fSStephan Aßmus 
11215a1d355fSStephan Aßmus // TODO: Allow opening the root node?
11225a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
11235a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
11245a1d355fSStephan Aßmus 
11255a1d355fSStephan Aßmus 	// allocate a dir cookie
11265a1d355fSStephan Aßmus 	DirCookie* cookie = new(std::nothrow) DirCookie;
11275a1d355fSStephan Aßmus 	if (!cookie)
11285a1d355fSStephan Aßmus 		RETURN_ERROR(B_NO_MEMORY);
11295a1d355fSStephan Aßmus 	ObjectDeleter<DirCookie> cookieDeleter(cookie);
11305a1d355fSStephan Aßmus 
11315a1d355fSStephan Aßmus 	// if the directory is fully cached, we allocate a local iterator
11325a1d355fSStephan Aßmus 	{
11335a1d355fSStephan Aßmus 		AutoLocker<Locker> locker(fLock);
11345a1d355fSStephan Aßmus 		if (node->IsComplete()) {
11355a1d355fSStephan Aßmus 			// create a local dir iterator
11365a1d355fSStephan Aßmus 			LocalShareDirIterator* iterator
11375a1d355fSStephan Aßmus 				= new(std::nothrow) LocalShareDirIterator();
11385a1d355fSStephan Aßmus 			if (!iterator)
11395a1d355fSStephan Aßmus 				RETURN_ERROR(B_NO_MEMORY);
11405a1d355fSStephan Aßmus 			iterator->SetDirectory(node);
11415a1d355fSStephan Aßmus 
11425a1d355fSStephan Aßmus 			// init the cookie
11435a1d355fSStephan Aßmus 			cookie->iterator = iterator;
11445a1d355fSStephan Aßmus 			*_cookie = cookie;
11455a1d355fSStephan Aßmus 			cookieDeleter.Detach();
11465a1d355fSStephan Aßmus 			return B_OK;
11475a1d355fSStephan Aßmus 		}
11485a1d355fSStephan Aßmus 	}
11495a1d355fSStephan Aßmus 
11505a1d355fSStephan Aßmus 	// allocate a remote dir iterator
11515a1d355fSStephan Aßmus 	RemoteShareDirIterator* iterator = new(std::nothrow) RemoteShareDirIterator;
11525a1d355fSStephan Aßmus 	if (!iterator)
11535a1d355fSStephan Aßmus 		RETURN_ERROR(B_NO_MEMORY);
11545a1d355fSStephan Aßmus 	ObjectDeleter<RemoteShareDirIterator> iteratorDeleter(iterator);
11555a1d355fSStephan Aßmus 
11565a1d355fSStephan Aßmus 	// prepare the request
11575a1d355fSStephan Aßmus 	OpenDirRequest request;
11585a1d355fSStephan Aßmus 	request.volumeID = fID;
11595a1d355fSStephan Aßmus 	request.nodeID = node->GetRemoteID();
11605a1d355fSStephan Aßmus 
11615a1d355fSStephan Aßmus 	// send the request
11625a1d355fSStephan Aßmus 	OpenDirReply* reply;
11635a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
11645a1d355fSStephan Aßmus 	if (error != B_OK)
11655a1d355fSStephan Aßmus 		RETURN_ERROR(error);
11665a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
11675a1d355fSStephan Aßmus 	if (reply->error != B_OK)
11685a1d355fSStephan Aßmus {
11693c1afd35SPawel Dziepak 		PRINT("OpenDir() failed: node: %lld, remote: (%ld, %lld)\n",
11703c1afd35SPawel Dziepak 			node->GetID(), node->GetRemoteID().volumeID,
11713c1afd35SPawel Dziepak 			node->GetRemoteID().nodeID);
11725a1d355fSStephan Aßmus 		RETURN_ERROR(reply->error);
11735a1d355fSStephan Aßmus }
11745a1d355fSStephan Aßmus 
11755a1d355fSStephan Aßmus 	// update the node
11765a1d355fSStephan Aßmus 	_UpdateNode(reply->nodeInfo);
11775a1d355fSStephan Aßmus 
11785a1d355fSStephan Aßmus 	// init the cookie
11795a1d355fSStephan Aßmus 	iterator->SetCookie(reply->cookie);
11805a1d355fSStephan Aßmus 	cookie->iterator = iterator;
11815a1d355fSStephan Aßmus 
11825a1d355fSStephan Aßmus 	*_cookie = cookie;
11835a1d355fSStephan Aßmus 	cookieDeleter.Detach();
11845a1d355fSStephan Aßmus 	iteratorDeleter.Detach();
11855a1d355fSStephan Aßmus 	return B_OK;
11865a1d355fSStephan Aßmus }
11875a1d355fSStephan Aßmus 
11885a1d355fSStephan Aßmus // CloseDir
11895a1d355fSStephan Aßmus status_t
11905a1d355fSStephan Aßmus ShareVolume::CloseDir(Node* _node, void* cookie)
11915a1d355fSStephan Aßmus {
11925a1d355fSStephan Aßmus 	// no-op: FreeDirCookie does the job
11935a1d355fSStephan Aßmus 	return B_OK;
11945a1d355fSStephan Aßmus }
11955a1d355fSStephan Aßmus 
11965a1d355fSStephan Aßmus // FreeDirCookie
11975a1d355fSStephan Aßmus status_t
11985a1d355fSStephan Aßmus ShareVolume::FreeDirCookie(Node* _node, void* _cookie)
11995a1d355fSStephan Aßmus {
12005a1d355fSStephan Aßmus 	DirCookie* cookie = (DirCookie*)_cookie;
12015a1d355fSStephan Aßmus 	ObjectDeleter<DirCookie> _(cookie);
12025a1d355fSStephan Aßmus 	ShareDirIterator* iterator = cookie->iterator;
12035a1d355fSStephan Aßmus 
12045a1d355fSStephan Aßmus 	status_t error = B_OK;
12055a1d355fSStephan Aßmus 	if (RemoteShareDirIterator* remoteIterator
12065a1d355fSStephan Aßmus 		= dynamic_cast<RemoteShareDirIterator*>(iterator)) {
12075a1d355fSStephan Aßmus 		// prepare the request
12085a1d355fSStephan Aßmus 		CloseRequest request;
12095a1d355fSStephan Aßmus 		request.volumeID = fID;
12105a1d355fSStephan Aßmus 		request.cookie = remoteIterator->GetCookie();
12115a1d355fSStephan Aßmus 
12125a1d355fSStephan Aßmus 		// send the request
12135a1d355fSStephan Aßmus 		if (!_EnsureShareMounted())
12145a1d355fSStephan Aßmus 			error = ERROR_NOT_CONNECTED;
12155a1d355fSStephan Aßmus 
12165a1d355fSStephan Aßmus 		if (error == B_OK) {
12175a1d355fSStephan Aßmus 			CloseReply* reply;
12185a1d355fSStephan Aßmus 			error = SendRequest(fConnection, &request, &reply);
12195a1d355fSStephan Aßmus 			if (error == B_OK) {
12205a1d355fSStephan Aßmus 				error = reply->error;
12215a1d355fSStephan Aßmus 				delete reply;
12225a1d355fSStephan Aßmus 			}
12235a1d355fSStephan Aßmus 		}
12245a1d355fSStephan Aßmus 	}
12255a1d355fSStephan Aßmus 
12265a1d355fSStephan Aßmus 	// delete the iterator
12275a1d355fSStephan Aßmus 	AutoLocker<Locker> locker(fLock);
12285a1d355fSStephan Aßmus 	delete iterator;
12295a1d355fSStephan Aßmus 
12305a1d355fSStephan Aßmus 	return error;
12315a1d355fSStephan Aßmus }
12325a1d355fSStephan Aßmus 
12335a1d355fSStephan Aßmus // ReadDir
12345a1d355fSStephan Aßmus status_t
12355a1d355fSStephan Aßmus ShareVolume::ReadDir(Node* _dir, void* _cookie, struct dirent* buffer,
12365a1d355fSStephan Aßmus 	size_t bufferSize, int32 count, int32* countRead)
12375a1d355fSStephan Aßmus {
12385a1d355fSStephan Aßmus 	ShareDir* directory = dynamic_cast<ShareDir*>(_dir);
12395a1d355fSStephan Aßmus 
12405a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
12415a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
12425a1d355fSStephan Aßmus 
12435a1d355fSStephan Aßmus 	*countRead = 0;
12445a1d355fSStephan Aßmus 	if (count <= 0)
12455a1d355fSStephan Aßmus 		return B_OK;
12465a1d355fSStephan Aßmus 
12475a1d355fSStephan Aßmus 	DirCookie* cookie = (DirCookie*)_cookie;
12485a1d355fSStephan Aßmus 	ShareDirIterator* iterator = cookie->iterator;
12495a1d355fSStephan Aßmus 
12505a1d355fSStephan Aßmus 	while (true) {
12515a1d355fSStephan Aßmus 		status_t error;
12525a1d355fSStephan Aßmus 		AutoLocker<Locker> locker(fLock);
12535a1d355fSStephan Aßmus 		while (ShareDirEntry* entry = iterator->GetCurrentEntry()) {
12545a1d355fSStephan Aßmus 			// re-get the entry -- it might already have been removed
12555a1d355fSStephan Aßmus 			const char* name = entry->GetName();
12565a1d355fSStephan Aßmus 			entry = _GetEntryByLocalID(directory->GetID(), name);
12575a1d355fSStephan Aßmus 			if (entry) {
12585a1d355fSStephan Aßmus 				// set the name: this also checks the size of the buffer
12595a1d355fSStephan Aßmus 				error = set_dirent_name(buffer, bufferSize, name,
12605a1d355fSStephan Aßmus 					strlen(name));
12615a1d355fSStephan Aßmus 				if (error != B_OK) {
12625a1d355fSStephan Aßmus 					// if something has been read at all, we're content
12635a1d355fSStephan Aßmus 					if (*countRead > 0)
12645a1d355fSStephan Aßmus 						return B_OK;
12655a1d355fSStephan Aßmus 					RETURN_ERROR(error);
12665a1d355fSStephan Aßmus 				}
12675a1d355fSStephan Aßmus 
12685a1d355fSStephan Aßmus 				// fill in the other fields
12695a1d355fSStephan Aßmus 				buffer->d_pdev = fVolumeManager->GetID();
12705a1d355fSStephan Aßmus 				buffer->d_pino = directory->GetID();
12715a1d355fSStephan Aßmus 				buffer->d_dev = fVolumeManager->GetID();
12725a1d355fSStephan Aßmus 				buffer->d_ino = entry->GetNode()->GetID();
12735a1d355fSStephan Aßmus 
12745a1d355fSStephan Aßmus 				// if the entry is the parent of the share root, we need to
12755a1d355fSStephan Aßmus 				// fix the node ID
12765a1d355fSStephan Aßmus 				if (directory == fRootNode && strcmp(name, "..") == 0) {
12775a1d355fSStephan Aßmus 					if (Volume* parentVolume = GetParentVolume())
12785a1d355fSStephan Aßmus 						buffer->d_ino = parentVolume->GetRootID();
12795a1d355fSStephan Aßmus 				}
12805a1d355fSStephan Aßmus 
12815a1d355fSStephan Aßmus 				iterator->NextEntry();
12825a1d355fSStephan Aßmus 				(*countRead)++;
12835a1d355fSStephan Aßmus 				if (*countRead >= count || !next_dirent(buffer, bufferSize))
12845a1d355fSStephan Aßmus 					return B_OK;
12855a1d355fSStephan Aßmus 			} else
12865a1d355fSStephan Aßmus 				iterator->NextEntry();
12875a1d355fSStephan Aßmus 		}
12885a1d355fSStephan Aßmus 
12895a1d355fSStephan Aßmus 		// no more entries: check, if we're completely through
12905a1d355fSStephan Aßmus 		if (iterator->IsDone())
12915a1d355fSStephan Aßmus 			return B_OK;
12925a1d355fSStephan Aßmus 
12935a1d355fSStephan Aßmus 		// we need to actually get entries from the server
12945a1d355fSStephan Aßmus 		locker.Unlock();
12955a1d355fSStephan Aßmus 		if (RemoteShareDirIterator* remoteIterator
12965a1d355fSStephan Aßmus 				= dynamic_cast<RemoteShareDirIterator*>(iterator)) {
12975a1d355fSStephan Aßmus 			error = _ReadRemoteDir(directory, remoteIterator);
12985a1d355fSStephan Aßmus 			if (error != B_OK)
12995a1d355fSStephan Aßmus 				return error;
13005a1d355fSStephan Aßmus 		}
13015a1d355fSStephan Aßmus 	}
13025a1d355fSStephan Aßmus }
13035a1d355fSStephan Aßmus 
13045a1d355fSStephan Aßmus // RewindDir
13055a1d355fSStephan Aßmus status_t
13065a1d355fSStephan Aßmus ShareVolume::RewindDir(Node* _node, void* _cookie)
13075a1d355fSStephan Aßmus {
13085a1d355fSStephan Aßmus 	DirCookie* cookie = (DirCookie*)_cookie;
13095a1d355fSStephan Aßmus 	ShareDirIterator* iterator = cookie->iterator;
13105a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fLock);
13115a1d355fSStephan Aßmus 	iterator->Rewind();
13125a1d355fSStephan Aßmus 	return B_OK;
13135a1d355fSStephan Aßmus }
13145a1d355fSStephan Aßmus 
13155a1d355fSStephan Aßmus // Walk
13165a1d355fSStephan Aßmus status_t
13175a1d355fSStephan Aßmus ShareVolume::Walk(Node* _dir, const char* entryName, char** resolvedPath,
13185a1d355fSStephan Aßmus 	vnode_id* vnid)
13195a1d355fSStephan Aßmus {
13205a1d355fSStephan Aßmus 	ShareDir* dir = dynamic_cast<ShareDir*>(_dir);
13215a1d355fSStephan Aßmus 	if (!dir)
13225a1d355fSStephan Aßmus 		return B_BAD_VALUE;
13235a1d355fSStephan Aßmus 
13245a1d355fSStephan Aßmus 	// we always resolve "." and ".." of the root node
13255a1d355fSStephan Aßmus 	if (dir == fRootNode) {
13265a1d355fSStephan Aßmus 		if (strcmp(entryName, ".") == 0 || strcmp(entryName, "..") == 0) {
13275a1d355fSStephan Aßmus 			AutoLocker<Locker> _(fLock);
13285a1d355fSStephan Aßmus 			if (strcmp(entryName, ".") == 0) {
13295a1d355fSStephan Aßmus 				*vnid = fRootNode->GetID();
13305a1d355fSStephan Aßmus 			} else if (Volume* parentVolume = GetParentVolume()) {
13315a1d355fSStephan Aßmus 				*vnid = parentVolume->GetRootID();
13325a1d355fSStephan Aßmus 			} else
13335a1d355fSStephan Aßmus 				*vnid = fRootNode->GetID();
13345a1d355fSStephan Aßmus 			Node* node;
13355a1d355fSStephan Aßmus 			return GetVNode(*vnid, &node);
13365a1d355fSStephan Aßmus 		}
13375a1d355fSStephan Aßmus 	}
13385a1d355fSStephan Aßmus 
13395a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
13405a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
13415a1d355fSStephan Aßmus 
13425a1d355fSStephan Aßmus 	// check, if the entry is already known
13435a1d355fSStephan Aßmus 	{
13445a1d355fSStephan Aßmus 		AutoLocker<Locker> _(fLock);
13455a1d355fSStephan Aßmus 		ShareDirEntry* entry = _GetEntryByLocalID(dir->GetID(), entryName);
13465a1d355fSStephan Aßmus 		if (entry) {
13475a1d355fSStephan Aßmus 			*vnid = entry->GetNode()->GetID();
13485a1d355fSStephan Aßmus 			Node* node;
13495a1d355fSStephan Aßmus 			return GetVNode(*vnid, &node);
13505a1d355fSStephan Aßmus 		} else if (dir->IsComplete())
13515a1d355fSStephan Aßmus 			return B_ENTRY_NOT_FOUND;
13525a1d355fSStephan Aßmus 	}
13535a1d355fSStephan Aßmus 
13545a1d355fSStephan Aßmus 	WalkReply* reply;
13555a1d355fSStephan Aßmus 	while (true) {
13565a1d355fSStephan Aßmus 		// send the request
13575a1d355fSStephan Aßmus 		status_t error = _Walk(dir->GetRemoteID(), entryName, resolvedPath,
13585a1d355fSStephan Aßmus 			&reply);
13595a1d355fSStephan Aßmus 		if (error != B_OK)
13605a1d355fSStephan Aßmus 			RETURN_ERROR(error);
13615a1d355fSStephan Aßmus 		ObjectDeleter<Request> replyDeleter(reply);
13625a1d355fSStephan Aßmus 
13635a1d355fSStephan Aßmus 		AutoLocker<Locker> locker(fLock);
13645a1d355fSStephan Aßmus 
13655a1d355fSStephan Aßmus 		// check, if the returned info is obsolete
13665a1d355fSStephan Aßmus 		if (_IsObsoleteEntryInfo(reply->entryInfo))
13675a1d355fSStephan Aßmus 			continue;
13685a1d355fSStephan Aßmus 
13695a1d355fSStephan Aßmus 		// load the entry
13705a1d355fSStephan Aßmus 		ShareDirEntry* entry;
13715a1d355fSStephan Aßmus 		error = _LoadEntry(dir, reply->entryInfo, &entry);
13725a1d355fSStephan Aßmus 		if (error != B_OK)
13735a1d355fSStephan Aßmus 			RETURN_ERROR(error);
13745a1d355fSStephan Aßmus 		*vnid = entry->GetNode()->GetID();
13755a1d355fSStephan Aßmus 
13765a1d355fSStephan Aßmus 		// deal with symlinks
13775a1d355fSStephan Aßmus 		if (reply->linkPath.GetString() && resolvedPath) {
13785a1d355fSStephan Aßmus 			*resolvedPath = strdup(reply->linkPath.GetString());
13795a1d355fSStephan Aßmus 			if (!*resolvedPath)
13805a1d355fSStephan Aßmus 				RETURN_ERROR(B_NO_MEMORY);
13815a1d355fSStephan Aßmus 			return B_OK;
13825a1d355fSStephan Aßmus 		}
13835a1d355fSStephan Aßmus 
13845a1d355fSStephan Aßmus 		break;
13855a1d355fSStephan Aßmus 	}
13865a1d355fSStephan Aßmus 
13875a1d355fSStephan Aßmus 	// no symlink or we shall not resolve it: get the node
13885a1d355fSStephan Aßmus 	Node* _node;
13895a1d355fSStephan Aßmus 	RETURN_ERROR(GetVNode(*vnid, &_node));
13905a1d355fSStephan Aßmus }
13915a1d355fSStephan Aßmus 
13925a1d355fSStephan Aßmus 
13935a1d355fSStephan Aßmus // #pragma mark -
13945a1d355fSStephan Aßmus // #pragma mark ----- attributes -----
13955a1d355fSStephan Aßmus 
13965a1d355fSStephan Aßmus // OpenAttrDir
13975a1d355fSStephan Aßmus status_t
13985a1d355fSStephan Aßmus ShareVolume::OpenAttrDir(Node* _node, void** _cookie)
13995a1d355fSStephan Aßmus {
14005a1d355fSStephan Aßmus 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
14015a1d355fSStephan Aßmus 
14025a1d355fSStephan Aßmus // TODO: Allow opening the root node?
14035a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
14045a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
14055a1d355fSStephan Aßmus 
14065a1d355fSStephan Aßmus 	// allocate a dir cookie
14075a1d355fSStephan Aßmus 	AttrDirCookie* cookie = new(std::nothrow) AttrDirCookie;
14085a1d355fSStephan Aßmus 	if (!cookie)
14095a1d355fSStephan Aßmus 		RETURN_ERROR(B_NO_MEMORY);
14105a1d355fSStephan Aßmus 	ObjectDeleter<AttrDirCookie> cookieDeleter(cookie);
14115a1d355fSStephan Aßmus 
14125a1d355fSStephan Aßmus 	AutoLocker<Locker> locker(fLock);
14135a1d355fSStephan Aßmus 
14145a1d355fSStephan Aßmus 	if (!node->GetAttrDir() || !node->GetAttrDir()->IsUpToDate()) {
14155a1d355fSStephan Aßmus 		// prepare the request
14165a1d355fSStephan Aßmus 		OpenAttrDirRequest request;
14175a1d355fSStephan Aßmus 		request.volumeID = fID;
14185a1d355fSStephan Aßmus 		request.nodeID = node->GetRemoteID();
14195a1d355fSStephan Aßmus 
14205a1d355fSStephan Aßmus 		locker.Unlock();
14215a1d355fSStephan Aßmus 
14225a1d355fSStephan Aßmus 		// send the request
14235a1d355fSStephan Aßmus 		OpenAttrDirReply* reply;
14245a1d355fSStephan Aßmus 		status_t error = SendRequest(fConnection, &request, &reply);
14255a1d355fSStephan Aßmus 		if (error != B_OK)
14265a1d355fSStephan Aßmus 			RETURN_ERROR(error);
14275a1d355fSStephan Aßmus 		ObjectDeleter<Request> replyDeleter(reply);
14285a1d355fSStephan Aßmus 		if (reply->error != B_OK)
14295a1d355fSStephan Aßmus 			RETURN_ERROR(reply->error);
14305a1d355fSStephan Aßmus 
14315a1d355fSStephan Aßmus 		// If no AttrDirInfo was supplied, we just save the cookie and be done.
14325a1d355fSStephan Aßmus 		// This usually happens when the attr dir is too big to be cached.
14335a1d355fSStephan Aßmus 		if (!reply->attrDirInfo.isValid) {
14345a1d355fSStephan Aßmus 			cookie->cookie = reply->cookie;
14355a1d355fSStephan Aßmus 			cookie->rewind = false;
14365a1d355fSStephan Aßmus 			*_cookie = cookie;
14375a1d355fSStephan Aßmus 			cookieDeleter.Detach();
14385a1d355fSStephan Aßmus 			return B_OK;
14395a1d355fSStephan Aßmus 		}
14405a1d355fSStephan Aßmus 
14415a1d355fSStephan Aßmus 		locker.SetTo(fLock, false);
14425a1d355fSStephan Aßmus 
14435a1d355fSStephan Aßmus 		// a AttrDirInfo has been supplied: load the attr dir
14445a1d355fSStephan Aßmus 		error = _LoadAttrDir(node, reply->attrDirInfo);
14455a1d355fSStephan Aßmus 		if (error != B_OK)
14465a1d355fSStephan Aßmus 			return error;
14475a1d355fSStephan Aßmus 	}
14485a1d355fSStephan Aßmus 
14495a1d355fSStephan Aßmus 	// we have a valid attr dir: create an attr dir iterator
14505a1d355fSStephan Aßmus 	ShareAttrDirIterator* iterator = new(std::nothrow) ShareAttrDirIterator;
14515a1d355fSStephan Aßmus 	if (!iterator)
14525a1d355fSStephan Aßmus 		return B_NO_MEMORY;
14535a1d355fSStephan Aßmus 	iterator->SetAttrDir(node->GetAttrDir());
14545a1d355fSStephan Aßmus 
14555a1d355fSStephan Aßmus 	// add the iterator
14565a1d355fSStephan Aßmus 	status_t error = _AddAttrDirIterator(node, iterator);
14575a1d355fSStephan Aßmus 	if (error != B_OK) {
14585a1d355fSStephan Aßmus 		delete iterator;
14595a1d355fSStephan Aßmus 		return error;
14605a1d355fSStephan Aßmus 	}
14615a1d355fSStephan Aßmus 
14625a1d355fSStephan Aßmus 	cookie->iterator = iterator;
14635a1d355fSStephan Aßmus 	*_cookie = cookie;
14645a1d355fSStephan Aßmus 	cookieDeleter.Detach();
14655a1d355fSStephan Aßmus 	return B_OK;
14665a1d355fSStephan Aßmus }
14675a1d355fSStephan Aßmus 
14685a1d355fSStephan Aßmus // CloseAttrDir
14695a1d355fSStephan Aßmus status_t
14705a1d355fSStephan Aßmus ShareVolume::CloseAttrDir(Node* _node, void* cookie)
14715a1d355fSStephan Aßmus {
14725a1d355fSStephan Aßmus 	// no-op: FreeAttrDirCookie does the job
14735a1d355fSStephan Aßmus 	return B_OK;
14745a1d355fSStephan Aßmus }
14755a1d355fSStephan Aßmus 
14765a1d355fSStephan Aßmus // FreeAttrDirCookie
14775a1d355fSStephan Aßmus status_t
14785a1d355fSStephan Aßmus ShareVolume::FreeAttrDirCookie(Node* _node, void* _cookie)
14795a1d355fSStephan Aßmus {
14805a1d355fSStephan Aßmus 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
14815a1d355fSStephan Aßmus 	AttrDirCookie* cookie = (AttrDirCookie*)_cookie;
14825a1d355fSStephan Aßmus 	ObjectDeleter<AttrDirCookie> _(cookie);
14835a1d355fSStephan Aßmus 
14845a1d355fSStephan Aßmus 	// if this is a local iterator, we just delete it and be done
14855a1d355fSStephan Aßmus 	if (cookie->iterator) {
14865a1d355fSStephan Aßmus 		AutoLocker<Locker> locker(fLock);
14875a1d355fSStephan Aßmus 
14885a1d355fSStephan Aßmus 		// remove and delete the iterator
14895a1d355fSStephan Aßmus 		_RemoveAttrDirIterator(node, cookie->iterator);
14905a1d355fSStephan Aßmus 		delete cookie->iterator;
14915a1d355fSStephan Aßmus 
14925a1d355fSStephan Aßmus 		return B_OK;
14935a1d355fSStephan Aßmus 	}
14945a1d355fSStephan Aßmus 
14955a1d355fSStephan Aßmus 	// prepare the request
14965a1d355fSStephan Aßmus 	CloseRequest request;
14975a1d355fSStephan Aßmus 	request.volumeID = fID;
14985a1d355fSStephan Aßmus 	request.cookie = cookie->cookie;
14995a1d355fSStephan Aßmus 
15005a1d355fSStephan Aßmus 	// send the request
15015a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
15025a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
15035a1d355fSStephan Aßmus 	CloseReply* reply;
15045a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
15055a1d355fSStephan Aßmus 	if (error != B_OK)
15065a1d355fSStephan Aßmus 		RETURN_ERROR(error);
15075a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
15085a1d355fSStephan Aßmus 	if (reply->error != B_OK)
15095a1d355fSStephan Aßmus 		RETURN_ERROR(reply->error);
15105a1d355fSStephan Aßmus 
15115a1d355fSStephan Aßmus 	return B_OK;
15125a1d355fSStephan Aßmus }
15135a1d355fSStephan Aßmus 
15145a1d355fSStephan Aßmus // ReadAttrDir
15155a1d355fSStephan Aßmus status_t
15165a1d355fSStephan Aßmus ShareVolume::ReadAttrDir(Node* _node, void* _cookie, struct dirent* buffer,
15175a1d355fSStephan Aßmus 	size_t bufferSize, int32 count, int32* countRead)
15185a1d355fSStephan Aßmus {
15195a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
15205a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
15215a1d355fSStephan Aßmus 
15225a1d355fSStephan Aßmus 	*countRead = 0;
15235a1d355fSStephan Aßmus 	AttrDirCookie* cookie = (AttrDirCookie*)_cookie;
15245a1d355fSStephan Aßmus 
15255a1d355fSStephan Aßmus 	// if we have a local iterator, things are easy
15265a1d355fSStephan Aßmus 	if (ShareAttrDirIterator* iterator = cookie->iterator) {
15275a1d355fSStephan Aßmus 		AutoLocker<Locker> locker(fLock);
15285a1d355fSStephan Aßmus 
15295a1d355fSStephan Aßmus 		// get the current attribute
15305a1d355fSStephan Aßmus 		Attribute* attribute = iterator->GetCurrentAttribute();
15315a1d355fSStephan Aßmus 		if (!attribute)
15325a1d355fSStephan Aßmus 			return B_OK;
15335a1d355fSStephan Aßmus 
15345a1d355fSStephan Aßmus 		// set the name: this also checks the size of the buffer
15355a1d355fSStephan Aßmus 		const char* name = attribute->GetName();
15365a1d355fSStephan Aßmus 		status_t error = set_dirent_name(buffer, bufferSize, name,
15375a1d355fSStephan Aßmus 			strlen(name));
15385a1d355fSStephan Aßmus 		if (error != B_OK)
15395a1d355fSStephan Aßmus 			RETURN_ERROR(error);
15405a1d355fSStephan Aßmus 
15415a1d355fSStephan Aßmus 		// fill in the other fields
15425a1d355fSStephan Aßmus 		buffer->d_dev = fVolumeManager->GetID();
15435a1d355fSStephan Aßmus 		buffer->d_ino = -1;
15445a1d355fSStephan Aßmus 		*countRead = 1;
15455a1d355fSStephan Aßmus 
15465a1d355fSStephan Aßmus 		iterator->NextAttribute();
15475a1d355fSStephan Aßmus 		return B_OK;
15485a1d355fSStephan Aßmus 	}
15495a1d355fSStephan Aßmus 
15505a1d355fSStephan Aßmus 	// prepare the request
15515a1d355fSStephan Aßmus 	ReadAttrDirRequest request;
15525a1d355fSStephan Aßmus 	request.volumeID = fID;
15535a1d355fSStephan Aßmus 	request.cookie = cookie->cookie;
15545a1d355fSStephan Aßmus 	request.count = 1;
15555a1d355fSStephan Aßmus 	request.rewind = cookie->rewind;
15565a1d355fSStephan Aßmus 
15575a1d355fSStephan Aßmus 	// send the request
15585a1d355fSStephan Aßmus 	ReadAttrDirReply* reply;
15595a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
15605a1d355fSStephan Aßmus 	if (error != B_OK)
15615a1d355fSStephan Aßmus 		RETURN_ERROR(error);
15625a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
15635a1d355fSStephan Aßmus 	if (reply->error != B_OK)
15645a1d355fSStephan Aßmus 		RETURN_ERROR(reply->error);
15655a1d355fSStephan Aßmus 	cookie->rewind = false;
15665a1d355fSStephan Aßmus 
15675a1d355fSStephan Aßmus 	// check, if anything has been read at all
15685a1d355fSStephan Aßmus 	if (reply->count == 0) {
15695a1d355fSStephan Aßmus 		*countRead = 0;
15705a1d355fSStephan Aßmus 		return B_OK;
15715a1d355fSStephan Aßmus 	}
15725a1d355fSStephan Aßmus 	const char* name = reply->name.GetString();
15735a1d355fSStephan Aßmus 	int32 nameLen = reply->name.GetSize();
15745a1d355fSStephan Aßmus 	if (!name || nameLen < 2)
15755a1d355fSStephan Aßmus 		return B_BAD_DATA;
15765a1d355fSStephan Aßmus 
15775a1d355fSStephan Aßmus 	// set the name: this also checks the size of the buffer
15785a1d355fSStephan Aßmus 	error = set_dirent_name(buffer, bufferSize, name, nameLen - 1);
15795a1d355fSStephan Aßmus 	if (error != B_OK)
15805a1d355fSStephan Aßmus 		RETURN_ERROR(error);
15815a1d355fSStephan Aßmus 
15825a1d355fSStephan Aßmus 	// fill in the other fields
15835a1d355fSStephan Aßmus 	buffer->d_dev = fVolumeManager->GetID();
15845a1d355fSStephan Aßmus 	buffer->d_ino = -1;
15855a1d355fSStephan Aßmus 	*countRead = 1;
15865a1d355fSStephan Aßmus 	return B_OK;
15875a1d355fSStephan Aßmus }
15885a1d355fSStephan Aßmus 
15895a1d355fSStephan Aßmus // RewindAttrDir
15905a1d355fSStephan Aßmus status_t
15915a1d355fSStephan Aßmus ShareVolume::RewindAttrDir(Node* _node, void* _cookie)
15925a1d355fSStephan Aßmus {
15935a1d355fSStephan Aßmus 	AttrDirCookie* cookie = (AttrDirCookie*)_cookie;
15945a1d355fSStephan Aßmus 
15955a1d355fSStephan Aßmus 	// if we have a local iterator, rewind it
15965a1d355fSStephan Aßmus 	if (ShareAttrDirIterator* iterator = cookie->iterator) {
15975a1d355fSStephan Aßmus 		AutoLocker<Locker> locker(fLock);
15985a1d355fSStephan Aßmus 
15995a1d355fSStephan Aßmus 		iterator->Rewind();
16005a1d355fSStephan Aßmus 	} else
16015a1d355fSStephan Aßmus 		cookie->rewind = true;
16025a1d355fSStephan Aßmus 
16035a1d355fSStephan Aßmus 	return B_OK;
16045a1d355fSStephan Aßmus }
16055a1d355fSStephan Aßmus 
16065a1d355fSStephan Aßmus // ReadAttr
16075a1d355fSStephan Aßmus status_t
16085a1d355fSStephan Aßmus ShareVolume::ReadAttr(Node* _node, const char* name, int type, off_t pos,
16095a1d355fSStephan Aßmus 	void* _buffer, size_t bufferSize, size_t* _bytesRead)
16105a1d355fSStephan Aßmus {
16115a1d355fSStephan Aßmus 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
16125a1d355fSStephan Aßmus 
16135a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
16145a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
16155a1d355fSStephan Aßmus 
16165a1d355fSStephan Aßmus 	*_bytesRead = 0;
16175a1d355fSStephan Aßmus 	if (bufferSize == 0)
16185a1d355fSStephan Aßmus 		return B_OK;
16195a1d355fSStephan Aßmus 	uint8* buffer = (uint8*)_buffer;
16205a1d355fSStephan Aßmus 
16215a1d355fSStephan Aßmus 	// if we have the attribute directory cached, we can first check, if the
16225a1d355fSStephan Aßmus 	// attribute exists at all -- maybe its data are cached, too
16235a1d355fSStephan Aßmus 	{
16245a1d355fSStephan Aßmus 		AutoLocker<Locker> locker(fLock);
16255a1d355fSStephan Aßmus 
16265a1d355fSStephan Aßmus 		ShareAttrDir* attrDir = node->GetAttrDir();
16275a1d355fSStephan Aßmus 		if (attrDir && attrDir->IsUpToDate()) {
16285a1d355fSStephan Aßmus 			// get the attribute
16295a1d355fSStephan Aßmus 			Attribute* attribute = attrDir->GetAttribute(name);
16305a1d355fSStephan Aßmus 			if (!attribute)
16315a1d355fSStephan Aßmus 				return B_ENTRY_NOT_FOUND;
16325a1d355fSStephan Aßmus 
16335a1d355fSStephan Aßmus 			// get the data
16345a1d355fSStephan Aßmus 			if (const void* data = attribute->GetData()) {
16355a1d355fSStephan Aßmus 				// first check, if we can read anything at all
16365a1d355fSStephan Aßmus 				if (pos < 0)
16375a1d355fSStephan Aßmus 					pos = 0;
16385a1d355fSStephan Aßmus 				int32 size = attribute->GetSize();
16395a1d355fSStephan Aßmus 				if (pos >= size)
16405a1d355fSStephan Aßmus 					return B_OK;
16415a1d355fSStephan Aßmus 
16425a1d355fSStephan Aßmus 				// get the data
16435a1d355fSStephan Aßmus 				bufferSize = min(bufferSize, size_t(size - pos));
16445a1d355fSStephan Aßmus 				memcpy(buffer, data, bufferSize);
16455a1d355fSStephan Aßmus 				*_bytesRead = bufferSize;
16465a1d355fSStephan Aßmus 				return B_OK;
16475a1d355fSStephan Aßmus 			}
16485a1d355fSStephan Aßmus 		}
16495a1d355fSStephan Aßmus 	}
16505a1d355fSStephan Aßmus 
16515a1d355fSStephan Aßmus 	// prepare the request
16525a1d355fSStephan Aßmus 	ReadAttrRequest request;
16535a1d355fSStephan Aßmus 	request.volumeID = fID;
16545a1d355fSStephan Aßmus 	request.nodeID = node->GetRemoteID();
16555a1d355fSStephan Aßmus 	request.name.SetTo(name);
16565a1d355fSStephan Aßmus 	request.type = type;
16575a1d355fSStephan Aßmus 	request.pos = pos;
16585a1d355fSStephan Aßmus 	request.size = bufferSize;
16595a1d355fSStephan Aßmus 
16605a1d355fSStephan Aßmus 	struct ReadRequestHandler : public RequestHandler {
16615a1d355fSStephan Aßmus 		uint8*	buffer;
16625a1d355fSStephan Aßmus 		off_t	pos;
16635a1d355fSStephan Aßmus 		int32	bufferSize;
16645a1d355fSStephan Aßmus 		int32	bytesRead;
16655a1d355fSStephan Aßmus 
16665a1d355fSStephan Aßmus 		ReadRequestHandler(uint8* buffer, off_t pos, int32 bufferSize)
16675a1d355fSStephan Aßmus 			: buffer(buffer),
16685a1d355fSStephan Aßmus 			  pos(pos),
16695a1d355fSStephan Aßmus 			  bufferSize(bufferSize),
16705a1d355fSStephan Aßmus 			  bytesRead(0)
16715a1d355fSStephan Aßmus 		{
16725a1d355fSStephan Aßmus 		}
16735a1d355fSStephan Aßmus 
16745a1d355fSStephan Aßmus 		virtual status_t HandleRequest(Request* _reply, RequestChannel* channel)
16755a1d355fSStephan Aßmus 		{
16765a1d355fSStephan Aßmus 			// the passed request is deleted by the request port
16775a1d355fSStephan Aßmus 			ReadAttrReply* reply = dynamic_cast<ReadAttrReply*>(_reply);
16785a1d355fSStephan Aßmus 			if (!reply)
16795a1d355fSStephan Aßmus 				RETURN_ERROR(B_BAD_DATA);
16805a1d355fSStephan Aßmus 			// process the reply
16815a1d355fSStephan Aßmus 			status_t error = ProcessReply(reply);
16825a1d355fSStephan Aßmus 			if (error != B_OK)
16835a1d355fSStephan Aßmus 				return error;
16845a1d355fSStephan Aßmus 			bool moreToCome = reply->moreToCome;
16855a1d355fSStephan Aßmus 			while (moreToCome) {
16865a1d355fSStephan Aßmus 				// receive a reply
16875a1d355fSStephan Aßmus 				error = ReceiveRequest(channel, &reply);
16885a1d355fSStephan Aßmus 				if (error != B_OK)
16895a1d355fSStephan Aßmus 					RETURN_ERROR(error);
16905a1d355fSStephan Aßmus 				moreToCome = reply->moreToCome;
16915a1d355fSStephan Aßmus 				ObjectDeleter<Request> replyDeleter(reply);
16925a1d355fSStephan Aßmus 				// process the reply
16935a1d355fSStephan Aßmus 				error = ProcessReply(reply);
16945a1d355fSStephan Aßmus 				if (error != B_OK)
16955a1d355fSStephan Aßmus 					return error;
16965a1d355fSStephan Aßmus 			}
16975a1d355fSStephan Aßmus 			return B_OK;
16985a1d355fSStephan Aßmus 		}
16995a1d355fSStephan Aßmus 
17005a1d355fSStephan Aßmus 		status_t ProcessReply(ReadAttrReply* reply)
17015a1d355fSStephan Aßmus 		{
17025a1d355fSStephan Aßmus 			if (reply->error != B_OK)
17035a1d355fSStephan Aßmus 				RETURN_ERROR(reply->error);
17045a1d355fSStephan Aßmus 			// check the fields
17055a1d355fSStephan Aßmus 			if (reply->pos != pos)
17065a1d355fSStephan Aßmus 				RETURN_ERROR(B_BAD_DATA);
17075a1d355fSStephan Aßmus 			int32 bytesRead = reply->data.GetSize();
17085a1d355fSStephan Aßmus 			if (bytesRead > (int32)bufferSize)
17095a1d355fSStephan Aßmus 				RETURN_ERROR(B_BAD_DATA);
17105a1d355fSStephan Aßmus 			// copy the data into the buffer
17115a1d355fSStephan Aßmus 			if (bytesRead > 0)
17125a1d355fSStephan Aßmus 				memcpy(buffer, reply->data.GetData(), bytesRead);
17135a1d355fSStephan Aßmus 			pos += bytesRead;
17145a1d355fSStephan Aßmus 			buffer += bytesRead;
17155a1d355fSStephan Aßmus 			bufferSize -= bytesRead;
17165a1d355fSStephan Aßmus 			this->bytesRead += bytesRead;
17175a1d355fSStephan Aßmus 			return B_OK;
17185a1d355fSStephan Aßmus 		}
17195a1d355fSStephan Aßmus 	} requestHandler(buffer, pos, bufferSize);
17205a1d355fSStephan Aßmus 
17215a1d355fSStephan Aßmus 	// send the request
17225a1d355fSStephan Aßmus 	status_t error = fConnection->SendRequest(&request, &requestHandler);
17235a1d355fSStephan Aßmus 	if (error != B_OK)
17245a1d355fSStephan Aßmus 		RETURN_ERROR(error);
17255a1d355fSStephan Aßmus 	*_bytesRead = requestHandler.bytesRead;
17265a1d355fSStephan Aßmus 	return B_OK;
17275a1d355fSStephan Aßmus }
17285a1d355fSStephan Aßmus 
17295a1d355fSStephan Aßmus // WriteAttr
17305a1d355fSStephan Aßmus status_t
17315a1d355fSStephan Aßmus ShareVolume::WriteAttr(Node* _node, const char* name, int type, off_t pos,
17325a1d355fSStephan Aßmus 	const void* _buffer, size_t bufferSize, size_t* bytesWritten)
17335a1d355fSStephan Aßmus {
17345a1d355fSStephan Aßmus 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
17355a1d355fSStephan Aßmus 
17365a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
17375a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
17385a1d355fSStephan Aßmus 
17395a1d355fSStephan Aßmus 	// check permissions
17405a1d355fSStephan Aßmus 	if (IsReadOnly())
17415a1d355fSStephan Aßmus 		return B_PERMISSION_DENIED;
17425a1d355fSStephan Aßmus 
17435a1d355fSStephan Aßmus 	*bytesWritten = 0;
17445a1d355fSStephan Aßmus 	off_t bytesLeft = bufferSize;
17455a1d355fSStephan Aßmus 	const char* buffer = (const char*)_buffer;
17465a1d355fSStephan Aßmus 	while (bytesLeft > 0) {
17475a1d355fSStephan Aßmus 		// store the current attibute dir revision for reference below
17485a1d355fSStephan Aßmus 		int64 attrDirRevision = -1;
17495a1d355fSStephan Aßmus 		{
17505a1d355fSStephan Aßmus 			AutoLocker<Locker> _(fLock);
17515a1d355fSStephan Aßmus 			if (ShareAttrDir* attrDir = node->GetAttrDir()) {
17525a1d355fSStephan Aßmus 				if (attrDir->IsUpToDate())
17535a1d355fSStephan Aßmus 					attrDirRevision = attrDir->GetRevision();
17545a1d355fSStephan Aßmus 			}
17555a1d355fSStephan Aßmus 		}
17565a1d355fSStephan Aßmus 
17575a1d355fSStephan Aßmus 		off_t toWrite = bytesLeft;
17585a1d355fSStephan Aßmus 		if (toWrite > kMaxWriteBufferSize)
17595a1d355fSStephan Aßmus 			toWrite = kMaxWriteBufferSize;
17605a1d355fSStephan Aßmus 
17615a1d355fSStephan Aßmus 		// prepare the request
17625a1d355fSStephan Aßmus 		WriteAttrRequest request;
17635a1d355fSStephan Aßmus 		request.volumeID = fID;
17645a1d355fSStephan Aßmus 		request.nodeID = node->GetRemoteID();
17655a1d355fSStephan Aßmus 		request.name.SetTo(name);
17665a1d355fSStephan Aßmus 		request.type = type;
17675a1d355fSStephan Aßmus 		request.pos = pos;
17685a1d355fSStephan Aßmus 		request.data.SetTo(buffer, toWrite);
17695a1d355fSStephan Aßmus 
17705a1d355fSStephan Aßmus 		// send the request
17715a1d355fSStephan Aßmus 		WriteAttrReply* reply;
17725a1d355fSStephan Aßmus 		status_t error = SendRequest(fConnection, &request, &reply);
17735a1d355fSStephan Aßmus 		if (error != B_OK)
17745a1d355fSStephan Aßmus 			RETURN_ERROR(error);
17755a1d355fSStephan Aßmus 
17765a1d355fSStephan Aßmus 		ObjectDeleter<Request> replyDeleter(reply);
17775a1d355fSStephan Aßmus 		if (reply->error != B_OK)
17785a1d355fSStephan Aßmus 			RETURN_ERROR(reply->error);
17795a1d355fSStephan Aßmus 
17805a1d355fSStephan Aßmus 		bytesLeft -= toWrite;
17815a1d355fSStephan Aßmus 		pos += toWrite;
17825a1d355fSStephan Aßmus 		buffer += toWrite;
17835a1d355fSStephan Aßmus 
17845a1d355fSStephan Aßmus 		// If the request was successful, we consider the cached attr dir
17855a1d355fSStephan Aßmus 		// no longer up to date.
17865a1d355fSStephan Aßmus 		if (attrDirRevision >= 0) {
17875a1d355fSStephan Aßmus 			AutoLocker<Locker> _(fLock);
17885a1d355fSStephan Aßmus 			ShareAttrDir* attrDir = node->GetAttrDir();
17895a1d355fSStephan Aßmus 			if (attrDir && attrDir->GetRevision() == attrDirRevision)
17905a1d355fSStephan Aßmus 				attrDir->SetUpToDate(false);
17915a1d355fSStephan Aßmus 		}
17925a1d355fSStephan Aßmus 	}
17935a1d355fSStephan Aßmus 
17945a1d355fSStephan Aßmus 	*bytesWritten = bufferSize;
17955a1d355fSStephan Aßmus 	return B_OK;
17965a1d355fSStephan Aßmus }
17975a1d355fSStephan Aßmus 
17985a1d355fSStephan Aßmus // RemoveAttr
17995a1d355fSStephan Aßmus status_t
18005a1d355fSStephan Aßmus ShareVolume::RemoveAttr(Node* _node, const char* name)
18015a1d355fSStephan Aßmus {
18025a1d355fSStephan Aßmus 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
18035a1d355fSStephan Aßmus 
18045a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
18055a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
18065a1d355fSStephan Aßmus 
18075a1d355fSStephan Aßmus 	// check permissions
18085a1d355fSStephan Aßmus 	if (IsReadOnly())
18095a1d355fSStephan Aßmus 		return B_PERMISSION_DENIED;
18105a1d355fSStephan Aßmus 
18115a1d355fSStephan Aßmus 	// store the current attibute dir revision for reference below
18125a1d355fSStephan Aßmus 	int64 attrDirRevision = -1;
18135a1d355fSStephan Aßmus 	{
18145a1d355fSStephan Aßmus 		AutoLocker<Locker> _(fLock);
18155a1d355fSStephan Aßmus 		if (ShareAttrDir* attrDir = node->GetAttrDir()) {
18165a1d355fSStephan Aßmus 			if (attrDir->IsUpToDate())
18175a1d355fSStephan Aßmus 				attrDirRevision = attrDir->GetRevision();
18185a1d355fSStephan Aßmus 		}
18195a1d355fSStephan Aßmus 	}
18205a1d355fSStephan Aßmus 
18215a1d355fSStephan Aßmus 	// prepare the request
18225a1d355fSStephan Aßmus 	RemoveAttrRequest request;
18235a1d355fSStephan Aßmus 	request.volumeID = fID;
18245a1d355fSStephan Aßmus 	request.nodeID = node->GetRemoteID();
18255a1d355fSStephan Aßmus 	request.name.SetTo(name);
18265a1d355fSStephan Aßmus 
18275a1d355fSStephan Aßmus 	// send the request
18285a1d355fSStephan Aßmus 	RemoveAttrReply* reply;
18295a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
18305a1d355fSStephan Aßmus 	if (error != B_OK)
18315a1d355fSStephan Aßmus 		RETURN_ERROR(error);
18325a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
18335a1d355fSStephan Aßmus 
18345a1d355fSStephan Aßmus 	// If the request was successful, we consider the cached attr dir
18355a1d355fSStephan Aßmus 	// no longer up to date.
18365a1d355fSStephan Aßmus 	if (reply->error == B_OK && attrDirRevision >= 0) {
18375a1d355fSStephan Aßmus 		AutoLocker<Locker> _(fLock);
18385a1d355fSStephan Aßmus 		ShareAttrDir* attrDir = node->GetAttrDir();
18395a1d355fSStephan Aßmus 		if (attrDir && attrDir->GetRevision() == attrDirRevision)
18405a1d355fSStephan Aßmus 			attrDir->SetUpToDate(false);
18415a1d355fSStephan Aßmus 	}
18425a1d355fSStephan Aßmus 
18435a1d355fSStephan Aßmus 	RETURN_ERROR(reply->error);
18445a1d355fSStephan Aßmus }
18455a1d355fSStephan Aßmus 
18465a1d355fSStephan Aßmus // RenameAttr
18475a1d355fSStephan Aßmus status_t
18485a1d355fSStephan Aßmus ShareVolume::RenameAttr(Node* _node, const char* oldName, const char* newName)
18495a1d355fSStephan Aßmus {
18505a1d355fSStephan Aßmus 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
18515a1d355fSStephan Aßmus 
18525a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
18535a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
18545a1d355fSStephan Aßmus 
18555a1d355fSStephan Aßmus 	// check permissions
18565a1d355fSStephan Aßmus 	if (IsReadOnly())
18575a1d355fSStephan Aßmus 		return B_PERMISSION_DENIED;
18585a1d355fSStephan Aßmus 
18595a1d355fSStephan Aßmus 	// store the current attibute dir revision for reference below
18605a1d355fSStephan Aßmus 	int64 attrDirRevision = -1;
18615a1d355fSStephan Aßmus 	{
18625a1d355fSStephan Aßmus 		AutoLocker<Locker> _(fLock);
18635a1d355fSStephan Aßmus 		if (ShareAttrDir* attrDir = node->GetAttrDir()) {
18645a1d355fSStephan Aßmus 			if (attrDir->IsUpToDate())
18655a1d355fSStephan Aßmus 				attrDirRevision = attrDir->GetRevision();
18665a1d355fSStephan Aßmus 		}
18675a1d355fSStephan Aßmus 	}
18685a1d355fSStephan Aßmus 
18695a1d355fSStephan Aßmus 	// prepare the request
18705a1d355fSStephan Aßmus 	RenameAttrRequest request;
18715a1d355fSStephan Aßmus 	request.volumeID = fID;
18725a1d355fSStephan Aßmus 	request.nodeID = node->GetRemoteID();
18735a1d355fSStephan Aßmus 	request.oldName.SetTo(oldName);
18745a1d355fSStephan Aßmus 	request.newName.SetTo(newName);
18755a1d355fSStephan Aßmus 
18765a1d355fSStephan Aßmus 	// send the request
18775a1d355fSStephan Aßmus 	RenameAttrReply* reply;
18785a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
18795a1d355fSStephan Aßmus 	if (error != B_OK)
18805a1d355fSStephan Aßmus 		RETURN_ERROR(error);
18815a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
18825a1d355fSStephan Aßmus 
18835a1d355fSStephan Aßmus 	// If the request was successful, we consider the cached attr dir
18845a1d355fSStephan Aßmus 	// no longer up to date.
18855a1d355fSStephan Aßmus 	if (reply->error == B_OK && attrDirRevision >= 0) {
18865a1d355fSStephan Aßmus 		AutoLocker<Locker> _(fLock);
18875a1d355fSStephan Aßmus 		ShareAttrDir* attrDir = node->GetAttrDir();
18885a1d355fSStephan Aßmus 		if (attrDir && attrDir->GetRevision() == attrDirRevision)
18895a1d355fSStephan Aßmus 			attrDir->SetUpToDate(false);
18905a1d355fSStephan Aßmus 	}
18915a1d355fSStephan Aßmus 
18925a1d355fSStephan Aßmus 	RETURN_ERROR(reply->error);
18935a1d355fSStephan Aßmus }
18945a1d355fSStephan Aßmus 
18955a1d355fSStephan Aßmus // StatAttr
18965a1d355fSStephan Aßmus status_t
18975a1d355fSStephan Aßmus ShareVolume::StatAttr(Node* _node, const char* name, struct attr_info* attrInfo)
18985a1d355fSStephan Aßmus {
18995a1d355fSStephan Aßmus 	ShareNode* node = dynamic_cast<ShareNode*>(_node);
19005a1d355fSStephan Aßmus 
19015a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
19025a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
19035a1d355fSStephan Aßmus 
19045a1d355fSStephan Aßmus 	// if we have the attribute directory cached, get the info from there
19055a1d355fSStephan Aßmus 	{
19065a1d355fSStephan Aßmus 		AutoLocker<Locker> locker(fLock);
19075a1d355fSStephan Aßmus 
19085a1d355fSStephan Aßmus 		ShareAttrDir* attrDir = node->GetAttrDir();
19095a1d355fSStephan Aßmus 		if (attrDir && attrDir->IsUpToDate()) {
19105a1d355fSStephan Aßmus 			// get the attribute
19115a1d355fSStephan Aßmus 			Attribute* attribute = attrDir->GetAttribute(name);
19125a1d355fSStephan Aßmus 			if (!attribute)
19135a1d355fSStephan Aßmus 				return B_ENTRY_NOT_FOUND;
19145a1d355fSStephan Aßmus 
19155a1d355fSStephan Aßmus 			attribute->GetInfo(attrInfo);
19165a1d355fSStephan Aßmus 			return B_OK;
19175a1d355fSStephan Aßmus 		}
19185a1d355fSStephan Aßmus 	}
19195a1d355fSStephan Aßmus 
19205a1d355fSStephan Aßmus 	// prepare the request
19215a1d355fSStephan Aßmus 	StatAttrRequest request;
19225a1d355fSStephan Aßmus 	request.volumeID = fID;
19235a1d355fSStephan Aßmus 	request.nodeID = node->GetRemoteID();
19245a1d355fSStephan Aßmus 	request.name.SetTo(name);
19255a1d355fSStephan Aßmus 
19265a1d355fSStephan Aßmus 	// send the request
19275a1d355fSStephan Aßmus 	StatAttrReply* reply;
19285a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
19295a1d355fSStephan Aßmus 	if (error != B_OK)
19305a1d355fSStephan Aßmus 		RETURN_ERROR(error);
19315a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
19325a1d355fSStephan Aßmus 	if (reply->error != B_OK)
19335a1d355fSStephan Aßmus 		RETURN_ERROR(reply->error);
19345a1d355fSStephan Aßmus 
19355a1d355fSStephan Aßmus 	// set the result
19365a1d355fSStephan Aßmus 	*attrInfo = reply->attrInfo.info;
19375a1d355fSStephan Aßmus 	return B_OK;
19385a1d355fSStephan Aßmus }
19395a1d355fSStephan Aßmus 
19405a1d355fSStephan Aßmus 
19415a1d355fSStephan Aßmus // #pragma mark -
19425a1d355fSStephan Aßmus // #pragma mark ----- queries -----
19435a1d355fSStephan Aßmus 
19445a1d355fSStephan Aßmus // GetQueryEntry
19455a1d355fSStephan Aßmus status_t
19465a1d355fSStephan Aßmus ShareVolume::GetQueryEntry(const EntryInfo& entryInfo,
19475a1d355fSStephan Aßmus 	const NodeInfo& dirInfo, struct dirent* buffer, size_t bufferSize,
19485a1d355fSStephan Aßmus 	int32* countRead)
19495a1d355fSStephan Aßmus {
19505a1d355fSStephan Aßmus 	status_t error = B_OK;
19515a1d355fSStephan Aßmus 
19525a1d355fSStephan Aßmus 	const char* name = entryInfo.name.GetString();
19535a1d355fSStephan Aßmus 	int32 nameLen = entryInfo.name.GetSize();
19545a1d355fSStephan Aßmus 	if (!name || nameLen < 2)
19555a1d355fSStephan Aßmus 		RETURN_ERROR(B_BAD_DATA);
19565a1d355fSStephan Aßmus 
19575a1d355fSStephan Aßmus 	// load the directory
19585a1d355fSStephan Aßmus 	vnode_id localDirID = -1;
19595a1d355fSStephan Aßmus 	{
19605a1d355fSStephan Aßmus 		AutoLocker<Locker> _(fLock);
19615a1d355fSStephan Aßmus 		ShareNode* node;
19625a1d355fSStephan Aßmus 		error = _LoadNode(dirInfo, &node);
19635a1d355fSStephan Aßmus 		if (error != B_OK)
19645a1d355fSStephan Aßmus 			RETURN_ERROR(error);
19655a1d355fSStephan Aßmus 		ShareDir* directory = dynamic_cast<ShareDir*>(node);
19665a1d355fSStephan Aßmus 		if (!directory)
19675a1d355fSStephan Aßmus 			RETURN_ERROR(B_ENTRY_NOT_FOUND);
19685a1d355fSStephan Aßmus 		localDirID = directory->GetID();
19695a1d355fSStephan Aßmus 	}
19705a1d355fSStephan Aßmus 
19715a1d355fSStephan Aßmus 	// add/update the entry
19725a1d355fSStephan Aßmus 	vnode_id localNodeID = -1;
19735a1d355fSStephan Aßmus 	const EntryInfo* resolvedEntryInfo = &entryInfo;
19745a1d355fSStephan Aßmus 	while (error == B_OK) {
19755a1d355fSStephan Aßmus 		// get an up to date entry info
19765a1d355fSStephan Aßmus 		WalkReply* walkReply = NULL;
19775a1d355fSStephan Aßmus 		if (!resolvedEntryInfo) {
19785a1d355fSStephan Aßmus 			error = _Walk(entryInfo.directoryID, name, false,
19795a1d355fSStephan Aßmus 				&walkReply);
19805a1d355fSStephan Aßmus 			if (error != B_OK)
19815a1d355fSStephan Aßmus 				RETURN_ERROR(error);
19825a1d355fSStephan Aßmus 
19835a1d355fSStephan Aßmus 			resolvedEntryInfo = &walkReply->entryInfo;
19845a1d355fSStephan Aßmus 		}
19855a1d355fSStephan Aßmus 		ObjectDeleter<Request> walkReplyDeleter(walkReply);
19865a1d355fSStephan Aßmus 
19875a1d355fSStephan Aßmus 		AutoLocker<Locker> locker(fLock);
19885a1d355fSStephan Aßmus 
19895a1d355fSStephan Aßmus 		// check, if the info is obsolete
19905a1d355fSStephan Aßmus 		if (_IsObsoleteEntryInfo(*resolvedEntryInfo)) {
19915a1d355fSStephan Aßmus 			resolvedEntryInfo = NULL;
19925a1d355fSStephan Aßmus 			continue;
19935a1d355fSStephan Aßmus 		}
19945a1d355fSStephan Aßmus 
19955a1d355fSStephan Aßmus 		// get the directory
19965a1d355fSStephan Aßmus 		ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByLocalID(localDirID));
19975a1d355fSStephan Aßmus 		if (!dir)
19985a1d355fSStephan Aßmus 			RETURN_ERROR(B_ERROR);
19995a1d355fSStephan Aßmus 
20005a1d355fSStephan Aßmus 		// load the entry
20015a1d355fSStephan Aßmus 		ShareDirEntry* entry;
20025a1d355fSStephan Aßmus 		error = _LoadEntry(dir, *resolvedEntryInfo, &entry);
20035a1d355fSStephan Aßmus 		if (error == B_OK)
20045a1d355fSStephan Aßmus 			localNodeID = entry->GetNode()->GetID();
20055a1d355fSStephan Aßmus 
20065a1d355fSStephan Aßmus 		break;
20075a1d355fSStephan Aßmus 	}
20085a1d355fSStephan Aßmus 
20095a1d355fSStephan Aßmus 	// set the name: this also checks the size of the buffer
20105a1d355fSStephan Aßmus 	error = set_dirent_name(buffer, bufferSize, name, nameLen - 1);
20115a1d355fSStephan Aßmus 	if (error != B_OK)
20125a1d355fSStephan Aßmus 		RETURN_ERROR(error);
20135a1d355fSStephan Aßmus 
20145a1d355fSStephan Aßmus 	// fill in the other fields
20155a1d355fSStephan Aßmus 	buffer->d_pdev = fVolumeManager->GetID();
20165a1d355fSStephan Aßmus 	buffer->d_pino = localDirID;
20175a1d355fSStephan Aßmus 	buffer->d_dev = fVolumeManager->GetID();
20185a1d355fSStephan Aßmus 	buffer->d_ino = localNodeID;
20195a1d355fSStephan Aßmus 
20205a1d355fSStephan Aßmus 	*countRead = 1;
20213c1afd35SPawel Dziepak 	PRINT("  entry: d_dev: %ld, d_pdev: %ld, d_ino: %Ld, d_pino: %Ld, "
20223c1afd35SPawel Dziepak 		"d_reclen: %hu, d_name: `%s'\n", buffer->d_dev, buffer->d_pdev,
20233c1afd35SPawel Dziepak 		buffer->d_ino, buffer->d_pino, buffer->d_reclen,
20243c1afd35SPawel Dziepak 		buffer->d_name);
20255a1d355fSStephan Aßmus 	return B_OK;
20265a1d355fSStephan Aßmus }
20275a1d355fSStephan Aßmus 
20285a1d355fSStephan Aßmus 
20295a1d355fSStephan Aßmus // #pragma mark -
20305a1d355fSStephan Aßmus 
20315a1d355fSStephan Aßmus // ProcessNodeMonitoringRequest
20325a1d355fSStephan Aßmus void
20335a1d355fSStephan Aßmus ShareVolume::ProcessNodeMonitoringRequest(NodeMonitoringRequest* request)
20345a1d355fSStephan Aßmus {
20355a1d355fSStephan Aßmus 	switch (request->opcode) {
20365a1d355fSStephan Aßmus 		case B_ENTRY_CREATED:
20375a1d355fSStephan Aßmus 			_HandleEntryCreatedRequest(
20385a1d355fSStephan Aßmus 				dynamic_cast<EntryCreatedRequest*>(request));
20395a1d355fSStephan Aßmus 			break;
20405a1d355fSStephan Aßmus 		case B_ENTRY_REMOVED:
20415a1d355fSStephan Aßmus 			_HandleEntryRemovedRequest(
20425a1d355fSStephan Aßmus 				dynamic_cast<EntryRemovedRequest*>(request));
20435a1d355fSStephan Aßmus 			break;
20445a1d355fSStephan Aßmus 		case B_ENTRY_MOVED:
20455a1d355fSStephan Aßmus 			_HandleEntryMovedRequest(
20465a1d355fSStephan Aßmus 				dynamic_cast<EntryMovedRequest*>(request));
20475a1d355fSStephan Aßmus 			break;
20485a1d355fSStephan Aßmus 		case B_STAT_CHANGED:
20495a1d355fSStephan Aßmus 			_HandleStatChangedRequest(
20505a1d355fSStephan Aßmus 				dynamic_cast<StatChangedRequest*>(request));
20515a1d355fSStephan Aßmus 			break;
20525a1d355fSStephan Aßmus 		case B_ATTR_CHANGED:
20535a1d355fSStephan Aßmus 			_HandleAttributeChangedRequest(
20545a1d355fSStephan Aßmus 				dynamic_cast<AttributeChangedRequest*>(request));
20555a1d355fSStephan Aßmus 			break;
20565a1d355fSStephan Aßmus 	}
20575a1d355fSStephan Aßmus }
20585a1d355fSStephan Aßmus 
20595a1d355fSStephan Aßmus // ConnectionClosed
20605a1d355fSStephan Aßmus void
20615a1d355fSStephan Aßmus ShareVolume::ConnectionClosed()
20625a1d355fSStephan Aßmus {
20635a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fMountLock);
20645a1d355fSStephan Aßmus 	fConnectionState = CONNECTION_CLOSED;
20655a1d355fSStephan Aßmus }
20665a1d355fSStephan Aßmus 
20675a1d355fSStephan Aßmus 
20685a1d355fSStephan Aßmus // #pragma mark -
20695a1d355fSStephan Aßmus 
20705a1d355fSStephan Aßmus // _ReadRemoteDir
20715a1d355fSStephan Aßmus status_t
20725a1d355fSStephan Aßmus ShareVolume::_ReadRemoteDir(ShareDir* directory,
20735a1d355fSStephan Aßmus 	RemoteShareDirIterator* iterator)
20745a1d355fSStephan Aßmus {
20755a1d355fSStephan Aßmus 	// prepare the request
20765a1d355fSStephan Aßmus 	fLock.Lock();
20775a1d355fSStephan Aßmus 	ReadDirRequest request;
20785a1d355fSStephan Aßmus 	request.volumeID = fID;
20795a1d355fSStephan Aßmus 	request.cookie = iterator->GetCookie();
20805a1d355fSStephan Aßmus 	request.count = iterator->GetCapacity();
20815a1d355fSStephan Aßmus 	request.rewind = iterator->GetRewind();
20825a1d355fSStephan Aßmus 	fLock.Unlock();
20835a1d355fSStephan Aßmus 
20845a1d355fSStephan Aßmus 	// send the request
20855a1d355fSStephan Aßmus 	ReadDirReply* reply;
20865a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
20875a1d355fSStephan Aßmus 	if (error != B_OK)
20885a1d355fSStephan Aßmus 		RETURN_ERROR(error);
20895a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
20905a1d355fSStephan Aßmus 	if (reply->error != B_OK)
20915a1d355fSStephan Aßmus 		RETURN_ERROR(reply->error);
20925a1d355fSStephan Aßmus 
20935a1d355fSStephan Aßmus 	RequestMemberArray<EntryInfo>* entryInfos = &reply->entryInfos;
20945a1d355fSStephan Aßmus 	while (true) {
20955a1d355fSStephan Aßmus 		// get up to date entry infos
20965a1d355fSStephan Aßmus 		MultiWalkReply* walkReply = NULL;
20975a1d355fSStephan Aßmus 		if (!entryInfos) {
20985a1d355fSStephan Aßmus 			error = _MultiWalk(reply->entryInfos, &walkReply);
20995a1d355fSStephan Aßmus 			if (error != B_OK)
21005a1d355fSStephan Aßmus 				RETURN_ERROR(error);
21015a1d355fSStephan Aßmus 
21025a1d355fSStephan Aßmus 			entryInfos = &walkReply->entryInfos;
21035a1d355fSStephan Aßmus 		}
21045a1d355fSStephan Aßmus 		ObjectDeleter<Request> walkReplyDeleter(walkReply);
21055a1d355fSStephan Aßmus 
21065a1d355fSStephan Aßmus 		AutoLocker<Locker> locker(fLock);
21075a1d355fSStephan Aßmus 
21085a1d355fSStephan Aßmus 		// check, if any info is obsolete
21095a1d355fSStephan Aßmus 		int32 count = entryInfos->CountElements();
21105a1d355fSStephan Aßmus 		for (int32 i = 0; i < count; i++) {
21115a1d355fSStephan Aßmus 			const EntryInfo& entryInfo = entryInfos->GetElements()[i];
21125a1d355fSStephan Aßmus 			if (_IsObsoleteEntryInfo(entryInfo)) {
21135a1d355fSStephan Aßmus 				entryInfos = NULL;
21145a1d355fSStephan Aßmus 				continue;
21155a1d355fSStephan Aßmus 			}
21165a1d355fSStephan Aßmus 		}
21175a1d355fSStephan Aßmus 
21185a1d355fSStephan Aßmus 		// init the iterator's revision, if it's new or has been rewinded
21195a1d355fSStephan Aßmus 		if (request.rewind || iterator->GetRevision() < 0)
21205a1d355fSStephan Aßmus 			iterator->SetRevision(reply->revision);
21215a1d355fSStephan Aßmus 
21225a1d355fSStephan Aßmus 		iterator->Clear();
21235a1d355fSStephan Aßmus 		iterator->SetDone(reply->done);
21245a1d355fSStephan Aßmus 
21255a1d355fSStephan Aßmus 		// iterate through the entries
21265a1d355fSStephan Aßmus 		for (int32 i = 0; i < count; i++) {
21275a1d355fSStephan Aßmus 			const EntryInfo& entryInfo = entryInfos->GetElements()[i];
21285a1d355fSStephan Aßmus 			const char* name = entryInfo.name.GetString();
21295a1d355fSStephan Aßmus 			int32 nameLen = entryInfo.name.GetSize();
21305a1d355fSStephan Aßmus 			if (!name || nameLen < 2)
21315a1d355fSStephan Aßmus 				return B_BAD_DATA;
21325a1d355fSStephan Aßmus 
21335a1d355fSStephan Aßmus 			// load the node/entry
21345a1d355fSStephan Aßmus 			ShareDirEntry* entry;
21355a1d355fSStephan Aßmus 			error = _LoadEntry(directory, entryInfo, &entry);
21365a1d355fSStephan Aßmus 			if (error != B_OK)
21375a1d355fSStephan Aßmus 				RETURN_ERROR(error);
21385a1d355fSStephan Aßmus 
21395a1d355fSStephan Aßmus 			// add the entry
21405a1d355fSStephan Aßmus 			if (!iterator->AddEntry(entry)) {
21415a1d355fSStephan Aßmus 				ERROR("ShareVolume::_ReadRemoteDir(): ERROR: Failed to add "
21425a1d355fSStephan Aßmus 					"entry to remote iterator!\n");
21435a1d355fSStephan Aßmus 			}
21445a1d355fSStephan Aßmus 		}
21455a1d355fSStephan Aßmus 
21465a1d355fSStephan Aßmus 		// directory now complete?
21475a1d355fSStephan Aßmus 		if (reply->done && directory->GetEntryRemovedEventRevision()
21485a1d355fSStephan Aßmus 				< iterator->GetRevision()) {
21495a1d355fSStephan Aßmus 			directory->SetComplete(true);
21505a1d355fSStephan Aßmus 		}
21515a1d355fSStephan Aßmus 
21525a1d355fSStephan Aßmus 		break;
21535a1d355fSStephan Aßmus 	}
21545a1d355fSStephan Aßmus 
21555a1d355fSStephan Aßmus 	return B_OK;
21565a1d355fSStephan Aßmus }
21575a1d355fSStephan Aßmus 
21585a1d355fSStephan Aßmus // _HandleEntryCreatedRequest
21595a1d355fSStephan Aßmus void
21605a1d355fSStephan Aßmus ShareVolume::_HandleEntryCreatedRequest(EntryCreatedRequest* request)
21615a1d355fSStephan Aßmus {
21625a1d355fSStephan Aßmus 	if (!request)
21635a1d355fSStephan Aßmus 		return;
21645a1d355fSStephan Aßmus 
21655a1d355fSStephan Aßmus 	nspace_id nsid = fVolumeManager->GetID();
21665a1d355fSStephan Aßmus 	const char* name = request->name.GetString();
21675a1d355fSStephan Aßmus 
21685a1d355fSStephan Aßmus 	// translate the node IDs
21695a1d355fSStephan Aßmus 	vnode_id vnida = 0;
21705a1d355fSStephan Aßmus 	vnode_id vnidb = 0;
21715a1d355fSStephan Aßmus 	vnode_id vnidc = 0;
21725a1d355fSStephan Aßmus 	status_t error = _GetLocalNodeID(request->directoryID, &vnida, true);
21735a1d355fSStephan Aßmus 	if (error == B_OK)
21745a1d355fSStephan Aßmus 		error = _GetLocalNodeID(request->nodeID, &vnidc, true);
21753c1afd35SPawel Dziepak 		PRINT("ShareVolume::_HandleEntryCreatedRequest(): error: 0x%lx,"
21763c1afd35SPawel Dziepak 			" name: \"%s\", dir: %lld (remote: (%ld, %lld)), node:"
21773c1afd35SPawel Dziepak 			" %lld (remote: (%ld, %lld))\n", error, name, vnida,
21783c1afd35SPawel Dziepak 			request->directoryID.volumeID,
21793c1afd35SPawel Dziepak 			request->directoryID.nodeID, vnidc,
21803c1afd35SPawel Dziepak 			request->nodeID.volumeID, request->nodeID.nodeID);
21815a1d355fSStephan Aßmus 
21825a1d355fSStephan Aßmus 	// send notifications / do additional processing
21835a1d355fSStephan Aßmus 	if (request->queryUpdate) {
21845a1d355fSStephan Aßmus 		if (error == B_OK) {
21855a1d355fSStephan Aßmus 			SendNotification(request->port, request->token,
21865a1d355fSStephan Aßmus 				B_QUERY_UPDATE, request->opcode, nsid, 0, vnida, vnidb,
21875a1d355fSStephan Aßmus 				vnidc, name);
21885a1d355fSStephan Aßmus 		}
21895a1d355fSStephan Aßmus 	} else {
21905a1d355fSStephan Aßmus 		_EntryCreated(request->directoryID, name,
21915a1d355fSStephan Aßmus 			(request->entryInfoValid ? &request->entryInfo : NULL),
21925a1d355fSStephan Aßmus 			request->revision);
21935a1d355fSStephan Aßmus 		if (error == B_OK)
21945a1d355fSStephan Aßmus 			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name);
21955a1d355fSStephan Aßmus 	}
21965a1d355fSStephan Aßmus }
21975a1d355fSStephan Aßmus 
21985a1d355fSStephan Aßmus // _HandleEntryRemovedRequest
21995a1d355fSStephan Aßmus void
22005a1d355fSStephan Aßmus ShareVolume::_HandleEntryRemovedRequest(EntryRemovedRequest* request)
22015a1d355fSStephan Aßmus {
22025a1d355fSStephan Aßmus 	if (!request)
22035a1d355fSStephan Aßmus 		return;
22045a1d355fSStephan Aßmus 
22055a1d355fSStephan Aßmus 	nspace_id nsid = fVolumeManager->GetID();
22065a1d355fSStephan Aßmus 	const char* name = request->name.GetString();
22075a1d355fSStephan Aßmus 
22085a1d355fSStephan Aßmus 	// translate the node IDs
22095a1d355fSStephan Aßmus 	vnode_id vnida = 0;
22105a1d355fSStephan Aßmus 	vnode_id vnidb = 0;
22115a1d355fSStephan Aßmus 	vnode_id vnidc = 0;
22125a1d355fSStephan Aßmus 	status_t error = _GetLocalNodeID(request->directoryID, &vnida, true);
22135a1d355fSStephan Aßmus 	if (error == B_OK)
22145a1d355fSStephan Aßmus 		error = _GetLocalNodeID(request->nodeID, &vnidc, false);
22155a1d355fSStephan Aßmus 			// TODO: We don't enter a node ID mapping here, which might cause
22165a1d355fSStephan Aßmus 			// undesired behavior in some cases. Queries should usually be
22175a1d355fSStephan Aßmus 			// fine, since, if the entry was in the query set, then the
22185a1d355fSStephan Aßmus 			// respective node ID should definately be known at this point.
22195a1d355fSStephan Aßmus 			// If an entry is removed and the node monitoring event comes
22205a1d355fSStephan Aßmus 			// before a live query event for the same entry, the former one
22215a1d355fSStephan Aßmus 			// will cause the ID to be removed, so that it is already gone
22225a1d355fSStephan Aßmus 			// when the latter one arrives. I haven't observed this yet,
22235a1d355fSStephan Aßmus 			// though. The query events always seem to be sent before the
22245a1d355fSStephan Aßmus 			// node monitoring events (and the server processes them in a
22255a1d355fSStephan Aßmus 			// single-threaded way). I guess, this is FS implementation
22265a1d355fSStephan Aßmus 			// dependent, though.
22275a1d355fSStephan Aßmus 			// A node monitoring event that will always get lost, is when the
22285a1d355fSStephan Aßmus 			// FS user watches a directory that hasn't been read before. Its
22295a1d355fSStephan Aßmus 			// entries will not be known yet and thus "entry removed" events
22305a1d355fSStephan Aßmus 			// will be dropped here. I guess, it's arguable whether this is
22315a1d355fSStephan Aßmus 			// a practical problem (why should the watcher care that an entry
22325a1d355fSStephan Aßmus 			// has been removed, when they didn't know what entries were in
22335a1d355fSStephan Aßmus 			// the directory in the first place?).
22345a1d355fSStephan Aßmus 			// A possible solution would be to never remove node ID mappings.
22355a1d355fSStephan Aßmus 			// We would only need to take care that the cached node info is
22365a1d355fSStephan Aßmus 			// correctly flushed, so that e.g. a subsequent ReadVNode() has to
22375a1d355fSStephan Aßmus 			// ask the server and doesn't work with obsolete data. We would
22385a1d355fSStephan Aßmus 			// also enter a yet unknown ID into the node ID map here. The only
22395a1d355fSStephan Aßmus 			// problem is that the ID maps will keep growing, especially when
22405a1d355fSStephan Aßmus 			// there's a lot of FS activity on the server.
22415a1d355fSStephan Aßmus 
22425a1d355fSStephan Aßmus 	// send notifications / do additional processing
22435a1d355fSStephan Aßmus 	if (request->queryUpdate) {
22445a1d355fSStephan Aßmus 		if (error == B_OK) {
22455a1d355fSStephan Aßmus 			SendNotification(request->port, request->token,
22465a1d355fSStephan Aßmus 				B_QUERY_UPDATE, request->opcode, nsid, 0, vnida, vnidb,
22475a1d355fSStephan Aßmus 				vnidc, name);
22485a1d355fSStephan Aßmus 		}
22495a1d355fSStephan Aßmus 	} else {
22505a1d355fSStephan Aßmus 		_EntryRemoved(request->directoryID, name, request->revision);
22515a1d355fSStephan Aßmus 		_NodeRemoved(request->nodeID);
22525a1d355fSStephan Aßmus 		if (error == B_OK)
22535a1d355fSStephan Aßmus 			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name);
22545a1d355fSStephan Aßmus 	}
22555a1d355fSStephan Aßmus }
22565a1d355fSStephan Aßmus 
22575a1d355fSStephan Aßmus // _HandleEntryMovedRequest
22585a1d355fSStephan Aßmus void
22595a1d355fSStephan Aßmus ShareVolume::_HandleEntryMovedRequest(EntryMovedRequest* request)
22605a1d355fSStephan Aßmus {
22615a1d355fSStephan Aßmus 	if (!request)
22625a1d355fSStephan Aßmus 		return;
22635a1d355fSStephan Aßmus 
22645a1d355fSStephan Aßmus 	nspace_id nsid = fVolumeManager->GetID();
22655a1d355fSStephan Aßmus 	const char* oldName = request->fromName.GetString();
22665a1d355fSStephan Aßmus 	const char* name = request->toName.GetString();
22675a1d355fSStephan Aßmus 
22685a1d355fSStephan Aßmus 	// translate the node IDs
22695a1d355fSStephan Aßmus 	vnode_id vnida = 0;
22705a1d355fSStephan Aßmus 	vnode_id vnidb = 0;
22715a1d355fSStephan Aßmus 	vnode_id vnidc = 0;
22725a1d355fSStephan Aßmus 	status_t error = _GetLocalNodeID(request->fromDirectoryID, &vnida, true);
22735a1d355fSStephan Aßmus 	if (error == B_OK)
22745a1d355fSStephan Aßmus 		error = _GetLocalNodeID(request->toDirectoryID, &vnidb, true);
22755a1d355fSStephan Aßmus 	if (error == B_OK)
22765a1d355fSStephan Aßmus 		error = _GetLocalNodeID(request->nodeID, &vnidc, true);
22775a1d355fSStephan Aßmus 
22785a1d355fSStephan Aßmus 	// send notifications / do additional processing
22795a1d355fSStephan Aßmus 	if (!request->queryUpdate) {
22805a1d355fSStephan Aßmus 		_EntryMoved(request->fromDirectoryID, oldName, request->toDirectoryID,
22815a1d355fSStephan Aßmus 			name, (request->entryInfoValid ? &request->entryInfo : NULL),
22825a1d355fSStephan Aßmus 			request->revision);
22835a1d355fSStephan Aßmus 		if (error == B_OK)
22845a1d355fSStephan Aßmus 			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name);
22855a1d355fSStephan Aßmus 	}
22865a1d355fSStephan Aßmus }
22875a1d355fSStephan Aßmus 
22885a1d355fSStephan Aßmus // _HandleStatChangedRequest
22895a1d355fSStephan Aßmus void
22905a1d355fSStephan Aßmus ShareVolume::_HandleStatChangedRequest(StatChangedRequest* request)
22915a1d355fSStephan Aßmus {
22925a1d355fSStephan Aßmus 	if (!request)
22935a1d355fSStephan Aßmus 		return;
22945a1d355fSStephan Aßmus 
22955a1d355fSStephan Aßmus 	nspace_id nsid = fVolumeManager->GetID();
22965a1d355fSStephan Aßmus 
22975a1d355fSStephan Aßmus 	// translate the node IDs
22985a1d355fSStephan Aßmus 	vnode_id vnida = 0;
22995a1d355fSStephan Aßmus 	vnode_id vnidb = 0;
23005a1d355fSStephan Aßmus 	vnode_id vnidc = 0;
23015a1d355fSStephan Aßmus 	status_t error = _GetLocalNodeID(request->nodeID, &vnidc, true);
23025a1d355fSStephan Aßmus 
23035a1d355fSStephan Aßmus 	// send notifications / do additional processing
23045a1d355fSStephan Aßmus 	if (!request->queryUpdate) {
23055a1d355fSStephan Aßmus 		_UpdateNode(request->nodeInfo);
23065a1d355fSStephan Aßmus 		if (error == B_OK)
23075a1d355fSStephan Aßmus 			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, NULL);
23085a1d355fSStephan Aßmus 	}
23095a1d355fSStephan Aßmus }
23105a1d355fSStephan Aßmus 
23115a1d355fSStephan Aßmus // _HandleAttributeChangedRequest
23125a1d355fSStephan Aßmus void
23135a1d355fSStephan Aßmus ShareVolume::_HandleAttributeChangedRequest(AttributeChangedRequest* request)
23145a1d355fSStephan Aßmus {
23155a1d355fSStephan Aßmus 	if (!request)
23165a1d355fSStephan Aßmus 		return;
23175a1d355fSStephan Aßmus 
23185a1d355fSStephan Aßmus 	nspace_id nsid = fVolumeManager->GetID();
23195a1d355fSStephan Aßmus 	const char* name = request->attrInfo.name.GetString();
23205a1d355fSStephan Aßmus 
23215a1d355fSStephan Aßmus 	// translate the node IDs
23225a1d355fSStephan Aßmus 	vnode_id vnida = 0;
23235a1d355fSStephan Aßmus 	vnode_id vnidb = 0;
23245a1d355fSStephan Aßmus 	vnode_id vnidc = 0;
23255a1d355fSStephan Aßmus 	status_t error = _GetLocalNodeID(request->nodeID, &vnidc, true);
23265a1d355fSStephan Aßmus 
23275a1d355fSStephan Aßmus 	// send notifications / do additional processing
23285a1d355fSStephan Aßmus 	if (!request->queryUpdate) {
23295a1d355fSStephan Aßmus 		_UpdateAttrDir(request->nodeID, request->attrDirInfo);
23305a1d355fSStephan Aßmus 		if (error == B_OK)
23315a1d355fSStephan Aßmus 			NotifyListener(request->opcode, nsid, vnida, vnidb, vnidc, name);
23325a1d355fSStephan Aßmus 	}
23335a1d355fSStephan Aßmus }
23345a1d355fSStephan Aßmus 
23355a1d355fSStephan Aßmus // _GetLocalNodeID
23365a1d355fSStephan Aßmus status_t
23375a1d355fSStephan Aßmus ShareVolume::_GetLocalNodeID(NodeID remoteID, ino_t* _localID, bool enter)
23385a1d355fSStephan Aßmus {
23395a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fLock);
23405a1d355fSStephan Aßmus 	// if the ID is already know, just return it
23415a1d355fSStephan Aßmus 	if (fLocalNodeIDs->ContainsKey(remoteID)) {
23425a1d355fSStephan Aßmus 		*_localID = fLocalNodeIDs->Get(remoteID);
23435a1d355fSStephan Aßmus 		return B_OK;
23445a1d355fSStephan Aßmus 	}
23455a1d355fSStephan Aßmus 
23465a1d355fSStephan Aßmus 	// ID not yet known
23475a1d355fSStephan Aßmus 	// enter it? Do this only, if requested and we're not already unmounting.
23485a1d355fSStephan Aßmus 	if (!enter)
23495a1d355fSStephan Aßmus 		return B_ENTRY_NOT_FOUND;
23505a1d355fSStephan Aßmus 	if (fUnmounting)
23515a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
23525a1d355fSStephan Aßmus 
23535a1d355fSStephan Aßmus 	// get a fresh ID from the volume manager
23545a1d355fSStephan Aßmus 	vnode_id localID = fVolumeManager->NewNodeID(this);
23555a1d355fSStephan Aßmus 	if (localID < 0)
23565a1d355fSStephan Aßmus 		return localID;
23575a1d355fSStephan Aßmus 
23585a1d355fSStephan Aßmus 	// put the IDs into local map
23595a1d355fSStephan Aßmus 	status_t error = fLocalNodeIDs->Put(remoteID, localID);
23605a1d355fSStephan Aßmus 	if (error != B_OK) {
23615a1d355fSStephan Aßmus 		fVolumeManager->RemoveNodeID(localID);
23625a1d355fSStephan Aßmus 		return error;
23635a1d355fSStephan Aßmus 	}
23645a1d355fSStephan Aßmus 
23655a1d355fSStephan Aßmus 	// put the IDs into remote map
23665a1d355fSStephan Aßmus 	error = fRemoteNodeIDs->Put(localID, remoteID);
23675a1d355fSStephan Aßmus 	if (error != B_OK) {
23685a1d355fSStephan Aßmus 		fLocalNodeIDs->Remove(remoteID);
23695a1d355fSStephan Aßmus 		fVolumeManager->RemoveNodeID(localID);
23705a1d355fSStephan Aßmus 		return error;
23715a1d355fSStephan Aßmus 	}
23723c1afd35SPawel Dziepak 	PRINT("ShareVolume(%ld): added node ID mapping: local: %lld -> "
23733c1afd35SPawel Dziepak 		"remote: (%ld, %lld)\n", fID, localID, remoteID.volumeID,
23743c1afd35SPawel Dziepak 		remoteID.nodeID);
23755a1d355fSStephan Aßmus 
23765a1d355fSStephan Aßmus 	*_localID = localID;
23775a1d355fSStephan Aßmus 	return B_OK;
23785a1d355fSStephan Aßmus }
23795a1d355fSStephan Aßmus 
23805a1d355fSStephan Aßmus // _GetRemoteNodeID
23815a1d355fSStephan Aßmus status_t
23825a1d355fSStephan Aßmus ShareVolume::_GetRemoteNodeID(ino_t localID, NodeID* remoteID)
23835a1d355fSStephan Aßmus {
23845a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fLock);
23855a1d355fSStephan Aßmus 
23865a1d355fSStephan Aßmus 	// check, if the ID is known
23875a1d355fSStephan Aßmus 	if (!fRemoteNodeIDs->ContainsKey(localID))
23885a1d355fSStephan Aßmus 		return B_ENTRY_NOT_FOUND;
23895a1d355fSStephan Aßmus 
23905a1d355fSStephan Aßmus 	*remoteID = fRemoteNodeIDs->Get(localID);
23915a1d355fSStephan Aßmus 	return B_OK;
23925a1d355fSStephan Aßmus }
23935a1d355fSStephan Aßmus 
23945a1d355fSStephan Aßmus // _RemoveLocalNodeID
23955a1d355fSStephan Aßmus void
23965a1d355fSStephan Aßmus ShareVolume::_RemoveLocalNodeID(ino_t localID)
23975a1d355fSStephan Aßmus {
23985a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fLock);
23995a1d355fSStephan Aßmus 
24005a1d355fSStephan Aßmus 	// check, if the ID is known
24015a1d355fSStephan Aßmus 	if (!fRemoteNodeIDs->ContainsKey(localID))
24025a1d355fSStephan Aßmus 		return;
24035a1d355fSStephan Aßmus 
24045a1d355fSStephan Aßmus 	// remove from ID maps
24055a1d355fSStephan Aßmus 	NodeID remoteID = fRemoteNodeIDs->Get(localID);
24063c1afd35SPawel Dziepak 	PRINT("ShareVolume::_RemoveLocalNodeID(%lld): remote: (%ld, %lld)\n",
24073c1afd35SPawel Dziepak 		localID, remoteID.volumeID, remoteID.nodeID);
24085a1d355fSStephan Aßmus 	fRemoteNodeIDs->Remove(localID);
24095a1d355fSStephan Aßmus 	fLocalNodeIDs->Remove(remoteID);
24105a1d355fSStephan Aßmus 
24115a1d355fSStephan Aßmus 	// remove from volume manager
24125a1d355fSStephan Aßmus 	fVolumeManager->RemoveNodeID(localID);
24135a1d355fSStephan Aßmus }
24145a1d355fSStephan Aßmus 
24155a1d355fSStephan Aßmus // _GetNodeByLocalID
24165a1d355fSStephan Aßmus ShareNode*
24175a1d355fSStephan Aßmus ShareVolume::_GetNodeByLocalID(ino_t localID)
24185a1d355fSStephan Aßmus {
24195a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fLock);
24205a1d355fSStephan Aßmus 	return fNodes->Get(localID);
24215a1d355fSStephan Aßmus }
24225a1d355fSStephan Aßmus 
24235a1d355fSStephan Aßmus // _GetNodeByRemoteID
24245a1d355fSStephan Aßmus ShareNode*
24255a1d355fSStephan Aßmus ShareVolume::_GetNodeByRemoteID(NodeID remoteID)
24265a1d355fSStephan Aßmus {
24275a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fLock);
24285a1d355fSStephan Aßmus 
24295a1d355fSStephan Aßmus 	ino_t localID;
24305a1d355fSStephan Aßmus 	if (_GetLocalNodeID(remoteID, &localID, false) == B_OK)
24315a1d355fSStephan Aßmus 		return fNodes->Get(localID);
24325a1d355fSStephan Aßmus 
24335a1d355fSStephan Aßmus 	return NULL;
24345a1d355fSStephan Aßmus }
24355a1d355fSStephan Aßmus 
24365a1d355fSStephan Aßmus // _LoadNode
24375a1d355fSStephan Aßmus status_t
24385a1d355fSStephan Aßmus ShareVolume::_LoadNode(const NodeInfo& nodeInfo, ShareNode** _node)
24395a1d355fSStephan Aßmus {
24405a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fLock);
24415a1d355fSStephan Aßmus 
24425a1d355fSStephan Aßmus 	// check, if the node is already known
24435a1d355fSStephan Aßmus 	ShareNode* node = _GetNodeByRemoteID(nodeInfo.GetID());
24445a1d355fSStephan Aßmus 	if (node) {
24455a1d355fSStephan Aßmus 		node->Update(nodeInfo);
24465a1d355fSStephan Aßmus 	} else {
24475a1d355fSStephan Aßmus 		// don't load the node when already unmounting
24485a1d355fSStephan Aßmus 		if (fUnmounting)
24495a1d355fSStephan Aßmus 			return B_ERROR;
24505a1d355fSStephan Aßmus 
24515a1d355fSStephan Aßmus 		// get a local node ID
24525a1d355fSStephan Aßmus 		vnode_id localID;
24535a1d355fSStephan Aßmus 		status_t error = _GetLocalNodeID(nodeInfo.GetID(), &localID, true);
24545a1d355fSStephan Aßmus 		if (error != B_OK)
24555a1d355fSStephan Aßmus 			return error;
24565a1d355fSStephan Aßmus 
24575a1d355fSStephan Aßmus 		// create a new node
24585a1d355fSStephan Aßmus 		if (S_ISDIR(nodeInfo.st.st_mode))
24595a1d355fSStephan Aßmus 			node = new(std::nothrow) ShareDir(this, localID, &nodeInfo);
24605a1d355fSStephan Aßmus 		else
24615a1d355fSStephan Aßmus 			node = new(std::nothrow) ShareNode(this, localID, &nodeInfo);
24625a1d355fSStephan Aßmus 		if (!node) {
24635a1d355fSStephan Aßmus 			_RemoveLocalNodeID(localID);
24645a1d355fSStephan Aßmus 			return B_NO_MEMORY;
24655a1d355fSStephan Aßmus 		}
24665a1d355fSStephan Aßmus 
24675a1d355fSStephan Aßmus 		// add it
24685a1d355fSStephan Aßmus 		error = fNodes->Put(node->GetID(), node);
24695a1d355fSStephan Aßmus 		if (error != B_OK) {
24705a1d355fSStephan Aßmus 			_RemoveLocalNodeID(localID);
24715a1d355fSStephan Aßmus 			delete node;
24725a1d355fSStephan Aßmus 			return error;
24735a1d355fSStephan Aßmus 		}
24743c1afd35SPawel Dziepak 		PRINT("ShareVolume: added node: %lld: remote: (%ld, %lld),"
24753c1afd35SPawel Dziepak 			" localID: %lld\n", node->GetID(),
24763c1afd35SPawel Dziepak 			node->GetRemoteID().volumeID,
24773c1afd35SPawel Dziepak 			node->GetRemoteID().nodeID, localID);
24785a1d355fSStephan Aßmus 	}
24795a1d355fSStephan Aßmus 
24805a1d355fSStephan Aßmus 	if (_node)
24815a1d355fSStephan Aßmus 		*_node = node;
24825a1d355fSStephan Aßmus 	return B_OK;
24835a1d355fSStephan Aßmus }
24845a1d355fSStephan Aßmus 
24855a1d355fSStephan Aßmus // _UpdateNode
24865a1d355fSStephan Aßmus status_t
24875a1d355fSStephan Aßmus ShareVolume::_UpdateNode(const NodeInfo& nodeInfo)
24885a1d355fSStephan Aßmus {
24895a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fLock);
24905a1d355fSStephan Aßmus 
24915a1d355fSStephan Aßmus 	if (fUnmounting)
24925a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
24935a1d355fSStephan Aßmus 
24945a1d355fSStephan Aßmus 	ShareNode* node = _GetNodeByRemoteID(nodeInfo.GetID());
24955a1d355fSStephan Aßmus 	if (node) {
24965a1d355fSStephan Aßmus 		node->Update(nodeInfo);
24975a1d355fSStephan Aßmus 		return B_OK;
24985a1d355fSStephan Aßmus 	}
24995a1d355fSStephan Aßmus 	return B_ENTRY_NOT_FOUND;
25005a1d355fSStephan Aßmus }
25015a1d355fSStephan Aßmus 
25025a1d355fSStephan Aßmus // _GetEntryByLocalID
25035a1d355fSStephan Aßmus ShareDirEntry*
25045a1d355fSStephan Aßmus ShareVolume::_GetEntryByLocalID(ino_t localDirID, const char* name)
25055a1d355fSStephan Aßmus {
25065a1d355fSStephan Aßmus 	if (!name)
25075a1d355fSStephan Aßmus 		return NULL;
25085a1d355fSStephan Aßmus 
25095a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fLock);
25105a1d355fSStephan Aßmus 	return fEntries->Get(EntryKey(localDirID, name));
25115a1d355fSStephan Aßmus }
25125a1d355fSStephan Aßmus 
25135a1d355fSStephan Aßmus // _GetEntryByRemoteID
25145a1d355fSStephan Aßmus ShareDirEntry*
25155a1d355fSStephan Aßmus ShareVolume::_GetEntryByRemoteID(NodeID remoteDirID, const char* name)
25165a1d355fSStephan Aßmus {
25175a1d355fSStephan Aßmus 	if (!name)
25185a1d355fSStephan Aßmus 		return NULL;
25195a1d355fSStephan Aßmus 
25205a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fLock);
25215a1d355fSStephan Aßmus 
25225a1d355fSStephan Aßmus 	ino_t localDirID;
25235a1d355fSStephan Aßmus 	if (_GetLocalNodeID(remoteDirID, &localDirID, false) == B_OK)
25245a1d355fSStephan Aßmus 		return fEntries->Get(EntryKey(localDirID, name));
25255a1d355fSStephan Aßmus 
25265a1d355fSStephan Aßmus 	return NULL;
25275a1d355fSStephan Aßmus }
25285a1d355fSStephan Aßmus 
25295a1d355fSStephan Aßmus // _LoadEntry
25305a1d355fSStephan Aßmus //
25315a1d355fSStephan Aßmus // If _entry is supplied, fLock should be held, otherwise the returned entry
25325a1d355fSStephan Aßmus // might as well be deleted.
25335a1d355fSStephan Aßmus status_t
25345a1d355fSStephan Aßmus ShareVolume::_LoadEntry(ShareDir* directory, const EntryInfo& entryInfo,
25355a1d355fSStephan Aßmus 	ShareDirEntry** _entry)
25365a1d355fSStephan Aßmus {
25375a1d355fSStephan Aßmus 	const char* name = entryInfo.name.GetString();
25385a1d355fSStephan Aßmus 	if (!directory || !name)
25395a1d355fSStephan Aßmus 		return B_BAD_VALUE;
25405a1d355fSStephan Aßmus 
25415a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fLock);
25425a1d355fSStephan Aßmus 
25435a1d355fSStephan Aßmus 	ShareDirEntry* entry = _GetEntryByLocalID(directory->GetID(), name);
25445a1d355fSStephan Aßmus 	if (entry) {
25455a1d355fSStephan Aßmus 		if (entryInfo.nodeInfo.revision > entry->GetRevision()) {
25465a1d355fSStephan Aßmus 			if (entryInfo.nodeInfo.GetID() != entry->GetNode()->GetRemoteID()) {
25475a1d355fSStephan Aßmus 				// The node the existing entry refers to is not the node it
25485a1d355fSStephan Aßmus 				// should refer to. Remove the old entry and create a new one.
25495a1d355fSStephan Aßmus 				_EntryRemoved(directory->GetRemoteID(), name,
25505a1d355fSStephan Aßmus 					entryInfo.nodeInfo.revision);
25515a1d355fSStephan Aßmus 				_EntryCreated(directory->GetRemoteID(), name, &entryInfo,
25525a1d355fSStephan Aßmus 					entryInfo.nodeInfo.revision);
25535a1d355fSStephan Aßmus 
25545a1d355fSStephan Aßmus 				// re-get the entry and check, if everything is fine
25555a1d355fSStephan Aßmus 				entry = _GetEntryByLocalID(directory->GetID(), name);
25565a1d355fSStephan Aßmus 				if (!entry)
25575a1d355fSStephan Aßmus 					return B_ERROR;
25585a1d355fSStephan Aßmus 				if (entryInfo.nodeInfo.GetID()
25595a1d355fSStephan Aßmus 					!= entry->GetNode()->GetRemoteID()) {
25605a1d355fSStephan Aßmus 					return B_ERROR;
25615a1d355fSStephan Aßmus 				}
25625a1d355fSStephan Aßmus 			} else {
25635a1d355fSStephan Aßmus 				entry->SetRevision(entryInfo.nodeInfo.revision);
25645a1d355fSStephan Aßmus 				_UpdateNode(entryInfo.nodeInfo);
25655a1d355fSStephan Aßmus 			}
25665a1d355fSStephan Aßmus 		}
25675a1d355fSStephan Aßmus 	} else {
25685a1d355fSStephan Aßmus 		// entry not known yet: create it
25695a1d355fSStephan Aßmus 
25705a1d355fSStephan Aßmus 		// don't load the entry when already unmounting
25715a1d355fSStephan Aßmus 		if (fUnmounting)
25725a1d355fSStephan Aßmus 			return B_ERROR;
25735a1d355fSStephan Aßmus 
25745a1d355fSStephan Aßmus 		// load the node
25755a1d355fSStephan Aßmus 		ShareNode* node;
25765a1d355fSStephan Aßmus 		status_t error = _LoadNode(entryInfo.nodeInfo, &node);
25775a1d355fSStephan Aßmus 		if (error != B_OK)
25785a1d355fSStephan Aßmus 			return error;
25795a1d355fSStephan Aßmus 
25805a1d355fSStephan Aßmus 		// if the directory or the node are marked remove, we don't create the
25815a1d355fSStephan Aßmus 		// entry
25825a1d355fSStephan Aßmus 		if (IsVNodeRemoved(directory->GetID()) > 0
25835a1d355fSStephan Aßmus 			|| IsVNodeRemoved(node->GetID()) > 0) {
25845a1d355fSStephan Aßmus 			return B_NOT_ALLOWED;
25855a1d355fSStephan Aßmus 		}
25865a1d355fSStephan Aßmus 
25875a1d355fSStephan Aßmus 		// create the entry
25885a1d355fSStephan Aßmus 		entry = new(std::nothrow) ShareDirEntry(directory, name, node);
25895a1d355fSStephan Aßmus 		if (!entry)
25905a1d355fSStephan Aßmus 			return B_NO_MEMORY;
25915a1d355fSStephan Aßmus 		ObjectDeleter<ShareDirEntry> entryDeleter(entry);
25925a1d355fSStephan Aßmus 		error = entry->InitCheck();
25935a1d355fSStephan Aßmus 		if (error != B_OK)
25945a1d355fSStephan Aßmus 			return error;
25955a1d355fSStephan Aßmus 
25965a1d355fSStephan Aßmus 		// add the entry
25975a1d355fSStephan Aßmus 		error = fEntries->Put(EntryKey(directory->GetID(), entry->GetName()),
25985a1d355fSStephan Aßmus 			entry);
25995a1d355fSStephan Aßmus 		if (error != B_OK)
26005a1d355fSStephan Aßmus 			return error;
26015a1d355fSStephan Aßmus 
26025a1d355fSStephan Aßmus 		// set the entry revision
26035a1d355fSStephan Aßmus 		entry->SetRevision(entryInfo.nodeInfo.revision);
26045a1d355fSStephan Aßmus 
26055a1d355fSStephan Aßmus 		// add the entry to the directory and the node
26065a1d355fSStephan Aßmus 		directory->AddEntry(entry);
26075a1d355fSStephan Aßmus 		entry->GetNode()->AddReferringEntry(entry);
26085a1d355fSStephan Aßmus 
26095a1d355fSStephan Aßmus 		// everything went fine
26105a1d355fSStephan Aßmus 		entryDeleter.Detach();
26115a1d355fSStephan Aßmus 	}
26125a1d355fSStephan Aßmus 
26135a1d355fSStephan Aßmus 	if (_entry)
26145a1d355fSStephan Aßmus 		*_entry = entry;
26155a1d355fSStephan Aßmus 	return B_OK;
26165a1d355fSStephan Aßmus }
26175a1d355fSStephan Aßmus 
26185a1d355fSStephan Aßmus // _RemoveEntry
26195a1d355fSStephan Aßmus //
26205a1d355fSStephan Aßmus // fLock must be held.
26215a1d355fSStephan Aßmus void
26225a1d355fSStephan Aßmus ShareVolume::_RemoveEntry(ShareDirEntry* entry)
26235a1d355fSStephan Aßmus {
26245a1d355fSStephan Aßmus 	fEntries->Remove(EntryKey(entry->GetDirectory()->GetID(),
26255a1d355fSStephan Aßmus 		entry->GetName()));
26265a1d355fSStephan Aßmus 	entry->GetDirectory()->RemoveEntry(entry);
26275a1d355fSStephan Aßmus 	entry->GetNode()->RemoveReferringEntry(entry);
262888e38c17SIngo Weinhold 	entry->ReleaseReference();
26295a1d355fSStephan Aßmus }
26305a1d355fSStephan Aßmus 
26315a1d355fSStephan Aßmus // _IsObsoleteEntryInfo
26325a1d355fSStephan Aßmus //
26335a1d355fSStephan Aßmus // fLock must be held.
26345a1d355fSStephan Aßmus bool
26355a1d355fSStephan Aßmus ShareVolume::_IsObsoleteEntryInfo(const EntryInfo& entryInfo)
26365a1d355fSStephan Aßmus {
26375a1d355fSStephan Aßmus 	// get the directory
26385a1d355fSStephan Aßmus 	ShareDir* dir
26395a1d355fSStephan Aßmus 		= dynamic_cast<ShareDir*>(_GetNodeByRemoteID(entryInfo.directoryID));
26405a1d355fSStephan Aßmus 	if (!dir)
26415a1d355fSStephan Aßmus 		return false;
26425a1d355fSStephan Aßmus 
26435a1d355fSStephan Aßmus 	return (entryInfo.nodeInfo.revision <= dir->GetEntryRemovedEventRevision());
26445a1d355fSStephan Aßmus }
26455a1d355fSStephan Aßmus 
26465a1d355fSStephan Aßmus // _LoadAttrDir
26475a1d355fSStephan Aßmus status_t
26485a1d355fSStephan Aßmus ShareVolume::_LoadAttrDir(ShareNode* node, const AttrDirInfo& attrDirInfo)
26495a1d355fSStephan Aßmus {
26505a1d355fSStephan Aßmus 	if (!node || !attrDirInfo.isValid)
26515a1d355fSStephan Aßmus 		return B_BAD_VALUE;
26525a1d355fSStephan Aßmus 
26535a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fLock);
26545a1d355fSStephan Aßmus 
26555a1d355fSStephan Aßmus 	if (fUnmounting)
26565a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
26575a1d355fSStephan Aßmus 
26585a1d355fSStephan Aßmus 	ShareAttrDir* attrDir = node->GetAttrDir();
26595a1d355fSStephan Aßmus 	if (attrDir) {
26605a1d355fSStephan Aßmus 		if (attrDir->GetRevision() > attrDirInfo.revision)
26615a1d355fSStephan Aßmus 			return B_OK;
26625a1d355fSStephan Aßmus 
26635a1d355fSStephan Aßmus 		// update the attr dir
26645a1d355fSStephan Aßmus 		return attrDir->Update(attrDirInfo,
26655a1d355fSStephan Aßmus 			fAttrDirIterators->Get(node->GetID()));
26665a1d355fSStephan Aßmus 	} else {
26675a1d355fSStephan Aßmus 		// no attribute directory yet: create one
26685a1d355fSStephan Aßmus 		attrDir = new(std::nothrow) ShareAttrDir;
26695a1d355fSStephan Aßmus 		if (!attrDir)
26705a1d355fSStephan Aßmus 			return B_NO_MEMORY;
26715a1d355fSStephan Aßmus 		ObjectDeleter<ShareAttrDir> attrDirDeleter(attrDir);
26725a1d355fSStephan Aßmus 
26735a1d355fSStephan Aßmus 		// initialize it
26745a1d355fSStephan Aßmus 		status_t error = attrDir->Init(attrDirInfo);
26755a1d355fSStephan Aßmus 		if (error != B_OK)
26765a1d355fSStephan Aßmus 			return error;
26775a1d355fSStephan Aßmus 
26785a1d355fSStephan Aßmus 		// set it
26795a1d355fSStephan Aßmus 		node->SetAttrDir(attrDir);
26805a1d355fSStephan Aßmus 		attrDirDeleter.Detach();
26815a1d355fSStephan Aßmus 		return B_OK;
26825a1d355fSStephan Aßmus 	}
26835a1d355fSStephan Aßmus }
26845a1d355fSStephan Aßmus 
26855a1d355fSStephan Aßmus // _UpdateAttrDir
26865a1d355fSStephan Aßmus status_t
26875a1d355fSStephan Aßmus ShareVolume::_UpdateAttrDir(NodeID remoteID, const AttrDirInfo& attrDirInfo)
26885a1d355fSStephan Aßmus {
26895a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fLock);
26905a1d355fSStephan Aßmus 
26915a1d355fSStephan Aßmus 	// get the node
26925a1d355fSStephan Aßmus 	ShareNode* node = _GetNodeByRemoteID(remoteID);
26935a1d355fSStephan Aßmus 	if (!node)
26945a1d355fSStephan Aßmus 		return B_ENTRY_NOT_FOUND;
26955a1d355fSStephan Aßmus 
26965a1d355fSStephan Aßmus 	if (!attrDirInfo.isValid || _LoadAttrDir(node, attrDirInfo) != B_OK) {
26975a1d355fSStephan Aßmus 		// updating/creating the attr dir failed; if existing, we mark it
26985a1d355fSStephan Aßmus 		// obsolete
26995a1d355fSStephan Aßmus 		if (ShareAttrDir* attrDir = node->GetAttrDir())
27005a1d355fSStephan Aßmus 			attrDir->SetUpToDate(false);
27015a1d355fSStephan Aßmus 	}
27025a1d355fSStephan Aßmus 
27035a1d355fSStephan Aßmus 	return B_OK;
27045a1d355fSStephan Aßmus }
27055a1d355fSStephan Aßmus 
27065a1d355fSStephan Aßmus // _AddAttrDirIterator
27075a1d355fSStephan Aßmus status_t
27085a1d355fSStephan Aßmus ShareVolume::_AddAttrDirIterator(ShareNode* node,
27095a1d355fSStephan Aßmus 	ShareAttrDirIterator* iterator)
27105a1d355fSStephan Aßmus {
27115a1d355fSStephan Aßmus 	if (!node || !iterator)
27125a1d355fSStephan Aßmus 		return B_BAD_VALUE;
27135a1d355fSStephan Aßmus 
27145a1d355fSStephan Aßmus 	AutoLocker<Locker> locker(fLock);
27155a1d355fSStephan Aßmus 
27165a1d355fSStephan Aßmus 	// get the iterator list
27175a1d355fSStephan Aßmus 	DoublyLinkedList<ShareAttrDirIterator>* iteratorList
27185a1d355fSStephan Aßmus 		= fAttrDirIterators->Get(node->GetID());
27195a1d355fSStephan Aßmus 	if (!iteratorList) {
27205a1d355fSStephan Aßmus 		// no list for the node yet: create one
27215a1d355fSStephan Aßmus 		iteratorList = new(std::nothrow) DoublyLinkedList<ShareAttrDirIterator>;
27225a1d355fSStephan Aßmus 		if (!iteratorList)
27235a1d355fSStephan Aßmus 			return B_NO_MEMORY;
27245a1d355fSStephan Aßmus 
27255a1d355fSStephan Aßmus 		// add it
27265a1d355fSStephan Aßmus 		status_t error = fAttrDirIterators->Put(node->GetID(), iteratorList);
27275a1d355fSStephan Aßmus 		if (error != B_OK) {
27285a1d355fSStephan Aßmus 			delete iteratorList;
27295a1d355fSStephan Aßmus 			return error;
27305a1d355fSStephan Aßmus 		}
27315a1d355fSStephan Aßmus 	}
27325a1d355fSStephan Aßmus 
27335a1d355fSStephan Aßmus 	// add the iterator
27345a1d355fSStephan Aßmus 	iteratorList->Insert(iterator);
27355a1d355fSStephan Aßmus 
27365a1d355fSStephan Aßmus 	return B_OK;
27375a1d355fSStephan Aßmus }
27385a1d355fSStephan Aßmus 
27395a1d355fSStephan Aßmus // _RemoveAttrDirIterator
27405a1d355fSStephan Aßmus void
27415a1d355fSStephan Aßmus ShareVolume::_RemoveAttrDirIterator(ShareNode* node,
27425a1d355fSStephan Aßmus 	ShareAttrDirIterator* iterator)
27435a1d355fSStephan Aßmus {
27445a1d355fSStephan Aßmus 	if (!node || !iterator)
27455a1d355fSStephan Aßmus 		return;
27465a1d355fSStephan Aßmus 
27475a1d355fSStephan Aßmus 	AutoLocker<Locker> locker(fLock);
27485a1d355fSStephan Aßmus 
27495a1d355fSStephan Aßmus 	// get the iterator list
27505a1d355fSStephan Aßmus 	DoublyLinkedList<ShareAttrDirIterator>* iteratorList
27515a1d355fSStephan Aßmus 		= fAttrDirIterators->Get(node->GetID());
27525a1d355fSStephan Aßmus 	if (!iteratorList) {
27535a1d355fSStephan Aßmus 		WARN("ShareVolume::_RemoveAttrDirIterator(): Iterator list not "
2754*20f046edSJérôme Duval 			"found: node: %" B_PRIdINO "\n", node->GetID());
27555a1d355fSStephan Aßmus 		return;
27565a1d355fSStephan Aßmus 	}
27575a1d355fSStephan Aßmus 
27585a1d355fSStephan Aßmus 	// remove the iterator
27595a1d355fSStephan Aßmus 	iteratorList->Remove(iterator);
27605a1d355fSStephan Aßmus 
27615a1d355fSStephan Aßmus 	// if the list is empty now, discard it
27625a1d355fSStephan Aßmus 	if (!iteratorList->First()) {
27635a1d355fSStephan Aßmus 		fAttrDirIterators->Remove(node->GetID());
27645a1d355fSStephan Aßmus 		delete iteratorList;
27655a1d355fSStephan Aßmus 	}
27665a1d355fSStephan Aßmus }
27675a1d355fSStephan Aßmus 
27685a1d355fSStephan Aßmus // _NodeRemoved
27695a1d355fSStephan Aßmus void
27705a1d355fSStephan Aßmus ShareVolume::_NodeRemoved(NodeID remoteID)
27715a1d355fSStephan Aßmus {
27725a1d355fSStephan Aßmus 	AutoLocker<Locker> locker(fLock);
27735a1d355fSStephan Aßmus 
27745a1d355fSStephan Aßmus 	ShareNode* node = _GetNodeByRemoteID(remoteID);
27755a1d355fSStephan Aßmus 	if (!node)
27765a1d355fSStephan Aßmus 		return;
27775a1d355fSStephan Aßmus 
27785a1d355fSStephan Aßmus 	// if the node still has referring entries, we do nothing
27795a1d355fSStephan Aßmus 	if (node->GetActualReferringEntry())
27805a1d355fSStephan Aßmus 		return;
27815a1d355fSStephan Aßmus 
27825a1d355fSStephan Aßmus 	// if the node is a directory, we remove its entries first
27835a1d355fSStephan Aßmus 	if (ShareDir* dir = dynamic_cast<ShareDir*>(node)) {
27845a1d355fSStephan Aßmus 		while (ShareDirEntry* entry = dir->GetFirstEntry())
27855a1d355fSStephan Aßmus 			_RemoveEntry(entry);
27865a1d355fSStephan Aßmus 	}
27875a1d355fSStephan Aßmus 
27885a1d355fSStephan Aßmus 	// remove all entries still referring to the node
27895a1d355fSStephan Aßmus 	while (ShareDirEntry* entry = node->GetFirstReferringEntry())
27905a1d355fSStephan Aßmus 		_RemoveEntry(entry);
27915a1d355fSStephan Aßmus 
27925a1d355fSStephan Aßmus 	ino_t localID = node->GetID();
27935a1d355fSStephan Aßmus 
27945a1d355fSStephan Aßmus 	// Remove the node ID in all cases -- even, if the node is still
27955a1d355fSStephan Aßmus 	// known to the VFS. Otherwise there could be a race condition, that the
27965a1d355fSStephan Aßmus 	// server re-uses the remote ID and we have it still associated with an
27975a1d355fSStephan Aßmus 	// obsolete local ID.
27985a1d355fSStephan Aßmus 	_RemoveLocalNodeID(localID);
27995a1d355fSStephan Aßmus 
28005a1d355fSStephan Aßmus 	if (node->IsKnownToVFS()) {
28015a1d355fSStephan Aßmus 		Node* _node;
28025a1d355fSStephan Aßmus 		if (GetVNode(localID, &_node) != B_OK)
28035a1d355fSStephan Aßmus 			return;
28045a1d355fSStephan Aßmus 		Volume::RemoveVNode(localID);
28055a1d355fSStephan Aßmus 		locker.Unlock();
28065a1d355fSStephan Aßmus 		PutVNode(localID);
28075a1d355fSStephan Aßmus 
28085a1d355fSStephan Aßmus 	} else {
28095a1d355fSStephan Aßmus 		fNodes->Remove(localID);
28105a1d355fSStephan Aßmus 		delete node;
28115a1d355fSStephan Aßmus 	}
28125a1d355fSStephan Aßmus }
28135a1d355fSStephan Aßmus 
28145a1d355fSStephan Aßmus // _EntryCreated
28155a1d355fSStephan Aßmus void
28165a1d355fSStephan Aßmus ShareVolume::_EntryCreated(NodeID remoteDirID, const char* name,
28175a1d355fSStephan Aßmus 	const EntryInfo* entryInfo, int64 revision)
28185a1d355fSStephan Aßmus {
28195a1d355fSStephan Aßmus 	if (!name)
28205a1d355fSStephan Aßmus 		return;
28215a1d355fSStephan Aßmus 
28225a1d355fSStephan Aßmus 	AutoLocker<Locker> locker(fLock);
28235a1d355fSStephan Aßmus 
28245a1d355fSStephan Aßmus 	// get the directory
28255a1d355fSStephan Aßmus 	ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(remoteDirID));
28265a1d355fSStephan Aßmus 	if (!dir)
28275a1d355fSStephan Aßmus 		return;
28285a1d355fSStephan Aßmus 
28295a1d355fSStephan Aßmus 	// load the entry, if possible
28305a1d355fSStephan Aßmus 	ShareDirEntry* entry;
28315a1d355fSStephan Aßmus 	bool entryLoaded = false;
28325a1d355fSStephan Aßmus 	if (entryInfo && _LoadEntry(dir, *entryInfo, &entry) == B_OK)
28335a1d355fSStephan Aßmus 		entryLoaded = true;
28345a1d355fSStephan Aßmus 
28355a1d355fSStephan Aßmus 	// if the entry could not be loaded, we have to mark the dir incomplete
28365a1d355fSStephan Aßmus 	// and update its revision counter
28375a1d355fSStephan Aßmus 	if (!entryLoaded) {
28385a1d355fSStephan Aßmus 		dir->UpdateEntryCreatedEventRevision(revision);
28395a1d355fSStephan Aßmus 		dir->SetComplete(false);
28405a1d355fSStephan Aßmus 	}
28415a1d355fSStephan Aßmus }
28425a1d355fSStephan Aßmus 
28435a1d355fSStephan Aßmus // _EntryRemoved
28445a1d355fSStephan Aßmus void
28455a1d355fSStephan Aßmus ShareVolume::_EntryRemoved(NodeID remoteDirID, const char* name, int64 revision)
28465a1d355fSStephan Aßmus {
28475a1d355fSStephan Aßmus 	if (!name)
28485a1d355fSStephan Aßmus 		return;
28495a1d355fSStephan Aßmus 
28505a1d355fSStephan Aßmus 	AutoLocker<Locker> locker(fLock);
28515a1d355fSStephan Aßmus 
28525a1d355fSStephan Aßmus 	// get the directory
28535a1d355fSStephan Aßmus 	ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(remoteDirID));
28545a1d355fSStephan Aßmus 	if (!dir)
28555a1d355fSStephan Aßmus 		return;
28565a1d355fSStephan Aßmus 
28575a1d355fSStephan Aßmus 	// update the directory's "entry removed" event revision
28585a1d355fSStephan Aßmus 	dir->UpdateEntryRemovedEventRevision(revision);
28595a1d355fSStephan Aßmus 
28605a1d355fSStephan Aßmus 	// get the entry
28615a1d355fSStephan Aßmus 	ShareDirEntry* entry = _GetEntryByRemoteID(remoteDirID, name);
28625a1d355fSStephan Aßmus 	if (!entry)
28635a1d355fSStephan Aßmus 		return;
28645a1d355fSStephan Aßmus 
28655a1d355fSStephan Aßmus 	// check the entry revision
28665a1d355fSStephan Aßmus 	if (entry->GetRevision() > revision)
28675a1d355fSStephan Aßmus 		return;
28685a1d355fSStephan Aßmus 
28695a1d355fSStephan Aßmus 	// remove the entry
28705a1d355fSStephan Aßmus 	_RemoveEntry(entry);
28715a1d355fSStephan Aßmus }
28725a1d355fSStephan Aßmus 
28735a1d355fSStephan Aßmus // _EntryMoved
28745a1d355fSStephan Aßmus void
28755a1d355fSStephan Aßmus ShareVolume::_EntryMoved(NodeID remoteOldDirID, const char* oldName,
28765a1d355fSStephan Aßmus 	NodeID remoteNewDirID, const char* name, const EntryInfo* entryInfo,
28775a1d355fSStephan Aßmus 	int64 revision)
28785a1d355fSStephan Aßmus {
28795a1d355fSStephan Aßmus 	AutoLocker<Locker> locker(fLock);
28805a1d355fSStephan Aßmus 
28815a1d355fSStephan Aßmus 	_EntryRemoved(remoteOldDirID, oldName, revision);
28825a1d355fSStephan Aßmus 	_EntryCreated(remoteNewDirID, name, entryInfo, revision);
28835a1d355fSStephan Aßmus }
28845a1d355fSStephan Aßmus 
28855a1d355fSStephan Aßmus // _Walk
28865a1d355fSStephan Aßmus status_t
28875a1d355fSStephan Aßmus ShareVolume::_Walk(NodeID remoteDirID, const char* entryName, bool resolveLink,
28885a1d355fSStephan Aßmus 	WalkReply** _reply)
28895a1d355fSStephan Aßmus {
28905a1d355fSStephan Aßmus 	// prepare the request
28915a1d355fSStephan Aßmus 	WalkRequest request;
28925a1d355fSStephan Aßmus 	request.volumeID = fID;
28935a1d355fSStephan Aßmus 	request.nodeID = remoteDirID;
28945a1d355fSStephan Aßmus 	request.name.SetTo(entryName);
28955a1d355fSStephan Aßmus 	request.resolveLink = resolveLink;
28965a1d355fSStephan Aßmus 
28975a1d355fSStephan Aßmus 	// send the request
28985a1d355fSStephan Aßmus 	WalkReply* reply;
28995a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
29005a1d355fSStephan Aßmus 	if (error != B_OK)
29015a1d355fSStephan Aßmus 		RETURN_ERROR(error);
29025a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
29035a1d355fSStephan Aßmus 	if (reply->error != B_OK)
29045a1d355fSStephan Aßmus 		RETURN_ERROR(reply->error);
29055a1d355fSStephan Aßmus 
29065a1d355fSStephan Aßmus 	replyDeleter.Detach();
29075a1d355fSStephan Aßmus 	*_reply = reply;
29085a1d355fSStephan Aßmus 	return B_OK;
29095a1d355fSStephan Aßmus }
29105a1d355fSStephan Aßmus 
29115a1d355fSStephan Aßmus // _MultiWalk
29125a1d355fSStephan Aßmus status_t
29135a1d355fSStephan Aßmus ShareVolume::_MultiWalk(RequestMemberArray<EntryInfo>& _entryInfos,
29145a1d355fSStephan Aßmus 	MultiWalkReply** _reply)
29155a1d355fSStephan Aßmus {
29165a1d355fSStephan Aßmus 	int32 count = _entryInfos.CountElements();
29175a1d355fSStephan Aßmus 	if (!_reply || count == 0)
29185a1d355fSStephan Aßmus 		return B_BAD_VALUE;
29195a1d355fSStephan Aßmus 
29205a1d355fSStephan Aßmus 	EntryInfo* entryInfos = _entryInfos.GetElements();
29215a1d355fSStephan Aßmus 
29225a1d355fSStephan Aßmus 	// prepare the request
29235a1d355fSStephan Aßmus 	MultiWalkRequest request;
29245a1d355fSStephan Aßmus 	request.volumeID = fID;
29255a1d355fSStephan Aßmus 	request.nodeID = entryInfos[0].directoryID;
29265a1d355fSStephan Aßmus 
29275a1d355fSStephan Aßmus 	// add the names
29285a1d355fSStephan Aßmus 	for (int32 i = 0; i < count; i++) {
29295a1d355fSStephan Aßmus 		StringData name;
29305a1d355fSStephan Aßmus 		name.SetTo(entryInfos[i].name.GetString());
29315a1d355fSStephan Aßmus 
29325a1d355fSStephan Aßmus 		status_t error = request.names.Append(name);
29335a1d355fSStephan Aßmus 		if (error != B_OK)
29345a1d355fSStephan Aßmus 			return error;
29355a1d355fSStephan Aßmus 	}
29365a1d355fSStephan Aßmus 
29375a1d355fSStephan Aßmus 	// send the request
29385a1d355fSStephan Aßmus 	MultiWalkReply* reply;
29395a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
29405a1d355fSStephan Aßmus 	if (error != B_OK)
29415a1d355fSStephan Aßmus 		RETURN_ERROR(error);
29425a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
29435a1d355fSStephan Aßmus 	if (reply->error != B_OK)
29445a1d355fSStephan Aßmus 		RETURN_ERROR(reply->error);
29455a1d355fSStephan Aßmus 
29465a1d355fSStephan Aßmus 	replyDeleter.Detach();
29475a1d355fSStephan Aßmus 	*_reply = reply;
29485a1d355fSStephan Aßmus 	return B_OK;
29495a1d355fSStephan Aßmus }
29505a1d355fSStephan Aßmus 
29515a1d355fSStephan Aßmus // _Close
29525a1d355fSStephan Aßmus status_t
29535a1d355fSStephan Aßmus ShareVolume::_Close(int32 cookie)
29545a1d355fSStephan Aßmus {
29555a1d355fSStephan Aßmus 	if (!_EnsureShareMounted())
29565a1d355fSStephan Aßmus 		return ERROR_NOT_CONNECTED;
29575a1d355fSStephan Aßmus 
29585a1d355fSStephan Aßmus 	// prepare the request
29595a1d355fSStephan Aßmus 	CloseRequest request;
29605a1d355fSStephan Aßmus 	request.volumeID = fID;
29615a1d355fSStephan Aßmus 	request.cookie = cookie;
29625a1d355fSStephan Aßmus 	// send the request
29635a1d355fSStephan Aßmus 	CloseReply* reply;
29645a1d355fSStephan Aßmus 	status_t error = SendRequest(fConnection, &request, &reply);
29655a1d355fSStephan Aßmus 	if (error != B_OK)
29665a1d355fSStephan Aßmus 		RETURN_ERROR(error);
29675a1d355fSStephan Aßmus 	ObjectDeleter<Request> replyDeleter(reply);
29685a1d355fSStephan Aßmus 	if (reply->error != B_OK)
29695a1d355fSStephan Aßmus 		RETURN_ERROR(reply->error);
29705a1d355fSStephan Aßmus 	return B_OK;
29715a1d355fSStephan Aßmus }
29725a1d355fSStephan Aßmus 
29735a1d355fSStephan Aßmus // _GetConnectionState
29745a1d355fSStephan Aßmus //
29755a1d355fSStephan Aßmus // Must not be called with fLock being held!
29765a1d355fSStephan Aßmus uint32
29775a1d355fSStephan Aßmus ShareVolume::_GetConnectionState()
29785a1d355fSStephan Aßmus {
29795a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fMountLock);
29805a1d355fSStephan Aßmus 	return fConnectionState;
29815a1d355fSStephan Aßmus }
29825a1d355fSStephan Aßmus 
29835a1d355fSStephan Aßmus // _IsConnected
29845a1d355fSStephan Aßmus //
29855a1d355fSStephan Aßmus // Must not be called with fLock being held!
29865a1d355fSStephan Aßmus bool
29875a1d355fSStephan Aßmus ShareVolume::_IsConnected()
29885a1d355fSStephan Aßmus {
29895a1d355fSStephan Aßmus 	return (_GetConnectionState() == CONNECTION_READY);
29905a1d355fSStephan Aßmus }
29915a1d355fSStephan Aßmus 
29925a1d355fSStephan Aßmus // _EnsureShareMounted
29935a1d355fSStephan Aßmus //
29945a1d355fSStephan Aßmus // Must not be called with fLock being held!
29955a1d355fSStephan Aßmus bool
29965a1d355fSStephan Aßmus ShareVolume::_EnsureShareMounted()
29975a1d355fSStephan Aßmus {
29985a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fMountLock);
29995a1d355fSStephan Aßmus 	if (fConnectionState == CONNECTION_NOT_INITIALIZED)
30005a1d355fSStephan Aßmus 		_MountShare();
30015a1d355fSStephan Aßmus 
30025a1d355fSStephan Aßmus 	return (fConnectionState == CONNECTION_READY);
30035a1d355fSStephan Aßmus }
30045a1d355fSStephan Aßmus 
30055a1d355fSStephan Aßmus // _MountShare
30065a1d355fSStephan Aßmus //
30075a1d355fSStephan Aßmus // fMountLock must be held.
30085a1d355fSStephan Aßmus status_t
30095a1d355fSStephan Aßmus ShareVolume::_MountShare()
30105a1d355fSStephan Aßmus {
30115a1d355fSStephan Aßmus 	// get references to the server and share info
30125a1d355fSStephan Aßmus 	AutoLocker<Locker> locker(fLock);
301388e38c17SIngo Weinhold 	BReference<ExtendedServerInfo> serverInfoReference(fServerInfo);
301488e38c17SIngo Weinhold 	BReference<ExtendedShareInfo> shareInfoReference(fShareInfo);
30155a1d355fSStephan Aßmus 	ExtendedServerInfo* serverInfo = fServerInfo;
30165a1d355fSStephan Aßmus 	ExtendedShareInfo* shareInfo = fShareInfo;
30175a1d355fSStephan Aßmus 	locker.Unlock();
30185a1d355fSStephan Aßmus 
30195a1d355fSStephan Aßmus 	// get server address as string
30205a1d355fSStephan Aßmus 	HashString serverAddressString;
30215a1d355fSStephan Aßmus 	status_t error = serverInfo->GetAddress().GetString(&serverAddressString,
30225a1d355fSStephan Aßmus 		false);
30235a1d355fSStephan Aßmus 	if (error != B_OK)
30245a1d355fSStephan Aßmus 		return error;
30255a1d355fSStephan Aßmus 	const char* server = serverAddressString.GetString();
30265a1d355fSStephan Aßmus 
30275a1d355fSStephan Aßmus 	// get the server name
30285a1d355fSStephan Aßmus 	const char* serverName = serverInfo->GetServerName();
30295a1d355fSStephan Aßmus 	if (serverName && strlen(serverName) == 0)
30305a1d355fSStephan Aßmus 		serverName = NULL;
30315a1d355fSStephan Aßmus 
30325a1d355fSStephan Aßmus 	// get the share name
30335a1d355fSStephan Aßmus 	const char* share = shareInfo->GetShareName();
30345a1d355fSStephan Aßmus 
30353c1afd35SPawel Dziepak 	PRINT("ShareVolume::_MountShare(%s, %s)\n", server, share);
30365a1d355fSStephan Aßmus 	// init a connection to the authentication server
30375a1d355fSStephan Aßmus 	AuthenticationServer authenticationServer;
30385a1d355fSStephan Aßmus 	error = authenticationServer.InitCheck();
30395a1d355fSStephan Aßmus 	if (error != B_OK)
30405a1d355fSStephan Aßmus 		RETURN_ERROR(error);
30415a1d355fSStephan Aßmus 
30425a1d355fSStephan Aßmus 	// get the server connection
30435a1d355fSStephan Aßmus 	fConnectionState = CONNECTION_CLOSED;
30445a1d355fSStephan Aßmus 	if (!fServerConnection) {
30455a1d355fSStephan Aßmus 		status_t error = fServerConnectionProvider->GetServerConnection(
30465a1d355fSStephan Aßmus 			&fServerConnection);
30475a1d355fSStephan Aßmus 		if (error != B_OK)
30485a1d355fSStephan Aßmus 			return error;
30495a1d355fSStephan Aßmus 		fConnection = fServerConnection->GetRequestConnection();
30505a1d355fSStephan Aßmus 	}
30515a1d355fSStephan Aßmus 
30525a1d355fSStephan Aßmus 	// the mount loop
30535a1d355fSStephan Aßmus 	bool badPassword = false;
30545a1d355fSStephan Aßmus 	MountReply* reply = NULL;
30555a1d355fSStephan Aßmus 	do {
30565a1d355fSStephan Aßmus 		// get the user and password from the authentication server
30575a1d355fSStephan Aßmus 		char user[kUserBufferSize];
30585a1d355fSStephan Aßmus 		char password[kPasswordBufferSize];
30595a1d355fSStephan Aßmus 		bool cancelled;
30605a1d355fSStephan Aßmus 		error = authenticationServer.GetAuthentication("netfs",
30615a1d355fSStephan Aßmus 			(serverName ? serverName : server), share,
30625a1d355fSStephan Aßmus 			fVolumeManager->GetMountUID(), badPassword,
30635a1d355fSStephan Aßmus 			&cancelled, user, sizeof(user), password, sizeof(password));
30645a1d355fSStephan Aßmus 		if (cancelled || error != B_OK)
30655a1d355fSStephan Aßmus 			RETURN_ERROR(error);
30665a1d355fSStephan Aßmus 
30675a1d355fSStephan Aßmus 		// prepare the request
30685a1d355fSStephan Aßmus 		MountRequest request;
30695a1d355fSStephan Aßmus 		request.share.SetTo(share);
30705a1d355fSStephan Aßmus 		request.user.SetTo(user);
30715a1d355fSStephan Aßmus 		request.password.SetTo(password);
30725a1d355fSStephan Aßmus 
30735a1d355fSStephan Aßmus 		// send the request
30745a1d355fSStephan Aßmus 		error = SendRequest(fConnection, &request, &reply);
30755a1d355fSStephan Aßmus 		if (error != B_OK)
30765a1d355fSStephan Aßmus 			RETURN_ERROR(error);
30775a1d355fSStephan Aßmus 		ObjectDeleter<Request> replyDeleter(reply);
30785a1d355fSStephan Aßmus 
30795a1d355fSStephan Aßmus 		// if no permission, try again
30805a1d355fSStephan Aßmus 		badPassword = reply->noPermission;
30815a1d355fSStephan Aßmus 		if (!badPassword) {
30825a1d355fSStephan Aßmus 			if (reply->error != B_OK)
30835a1d355fSStephan Aßmus 				RETURN_ERROR(reply->error);
30845a1d355fSStephan Aßmus 			fSharePermissions = reply->sharePermissions;
30855a1d355fSStephan Aßmus 		}
30865a1d355fSStephan Aßmus 	} while (badPassword);
30875a1d355fSStephan Aßmus 
30885a1d355fSStephan Aßmus 	AutoLocker<Locker> _(fLock);
30895a1d355fSStephan Aßmus 
30905a1d355fSStephan Aßmus 	fID = reply->volumeID;
30915a1d355fSStephan Aßmus 
30925a1d355fSStephan Aßmus 	// update the root node and enter its ID
30935a1d355fSStephan Aßmus 	fRootNode->Update(reply->nodeInfo);
30945a1d355fSStephan Aßmus 
30955a1d355fSStephan Aßmus 	// put the IDs into local map
30965a1d355fSStephan Aßmus 	error = fLocalNodeIDs->Put(fRootNode->GetRemoteID(), fRootNode->GetID());
30975a1d355fSStephan Aßmus 	if (error != B_OK)
30985a1d355fSStephan Aßmus 		RETURN_ERROR(error);
30995a1d355fSStephan Aßmus 
31005a1d355fSStephan Aßmus 	// put the IDs into remote map
31015a1d355fSStephan Aßmus 	error = fRemoteNodeIDs->Put(fRootNode->GetID(), fRootNode->GetRemoteID());
31025a1d355fSStephan Aßmus 	if (error != B_OK) {
31035a1d355fSStephan Aßmus 		fLocalNodeIDs->Remove(fRootNode->GetRemoteID());
31045a1d355fSStephan Aßmus 		RETURN_ERROR(error);
31055a1d355fSStephan Aßmus 	}
31063c1afd35SPawel Dziepak 	PRINT("ShareVolume::_MountShare(): root node: local: %lld, remote: "
31073c1afd35SPawel Dziepak 		"(%ld, %lld)\n", fRootNode->GetID(),
31083c1afd35SPawel Dziepak 		fRootNode->GetRemoteID().volumeID,
31093c1afd35SPawel Dziepak 		fRootNode->GetRemoteID().nodeID);
31105a1d355fSStephan Aßmus 
31115a1d355fSStephan Aßmus 	// Add ourselves to the server connection, so that we can receive
31125a1d355fSStephan Aßmus 	// node monitoring events. There a race condition: We might already
31135a1d355fSStephan Aßmus 	// have missed events for the root node.
31145a1d355fSStephan Aßmus 	error = fServerConnection->AddVolume(this);
31155a1d355fSStephan Aßmus 	if (error != B_OK) {
31165a1d355fSStephan Aßmus 		_RemoveLocalNodeID(fRootNode->GetID());
31175a1d355fSStephan Aßmus 		return error;
31185a1d355fSStephan Aßmus 	}
31195a1d355fSStephan Aßmus 
31205a1d355fSStephan Aßmus 	fConnectionState = CONNECTION_READY;
31215a1d355fSStephan Aßmus 	return B_OK;
31225a1d355fSStephan Aßmus }
31235a1d355fSStephan Aßmus 
3124