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 {
EntryKeyShareVolume::EntryKey595a1d355fSStephan Aßmus EntryKey() {}
605a1d355fSStephan Aßmus
EntryKeyShareVolume::EntryKey615a1d355fSStephan 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
EntryKeyShareVolume::EntryKey675a1d355fSStephan 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
GetHashCodeShareVolume::EntryKey735a1d355fSStephan 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
operator =ShareVolume::EntryKey815a1d355fSStephan 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
operator ==ShareVolume::EntryKey885a1d355fSStephan 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
operator !=ShareVolume::EntryKey995a1d355fSStephan 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 {
AttrDirCookieShareVolume::AttrDirCookie1275a1d355fSStephan Aßmus AttrDirCookie()
1285a1d355fSStephan Aßmus : iterator(NULL),
1295a1d355fSStephan Aßmus cookie(-1),
1305a1d355fSStephan Aßmus rewind(false)
1315a1d355fSStephan Aßmus {
1325a1d355fSStephan Aßmus }
1335a1d355fSStephan Aßmus
1345a1d355fSStephan Aßmus ShareAttrDirIterator* iterator;
13559ecfa6cSAugustin Cavalier intptr_t cookie;
1365a1d355fSStephan Aßmus bool rewind;
1375a1d355fSStephan Aßmus };
1385a1d355fSStephan Aßmus
1395a1d355fSStephan Aßmus // AttrDirIteratorMap
1405a1d355fSStephan Aß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
ShareVolume(VolumeManager * volumeManager,ServerConnectionProvider * connectionProvider,ExtendedServerInfo * serverInfo,ExtendedShareInfo * shareInfo)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
~ShareVolume()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 "
19420f046edSJérôme Duval "%" B_PRId32 " nodes\n", fNodes->Size());
1955a1d355fSStephan Aßmus }
1965a1d355fSStephan Aßmus for (NodeMap::Iterator it = fNodes->GetIterator(); it.HasNext();)
1975a1d355fSStephan Aßmus delete it.Next().value;
1985a1d355fSStephan Aßmus delete fNodes;
1995a1d355fSStephan Aßmus }
2005a1d355fSStephan Aßmus
2015a1d355fSStephan Aßmus // delete the entries
2025a1d355fSStephan Aßmus if (fEntries) {
2035a1d355fSStephan Aßmus // there shouldn't be any more entries
2045a1d355fSStephan Aßmus if (fEntries->Size() > 0) {
2055a1d355fSStephan Aßmus WARN("ShareVolume::~ShareVolume(): WARNING: There are still "
20620f046edSJérôme Duval "%" B_PRId32 " entries\n", fEntries->Size());
2075a1d355fSStephan Aßmus }
2085a1d355fSStephan Aßmus for (EntryMap::Iterator it = fEntries->GetIterator(); it.HasNext();)
2095a1d355fSStephan Aßmus delete it.Next().value;
2105a1d355fSStephan Aßmus delete fEntries;
2115a1d355fSStephan Aßmus }
2125a1d355fSStephan Aßmus
2135a1d355fSStephan Aßmus delete fLocalNodeIDs;
2145a1d355fSStephan Aßmus delete fRemoteNodeIDs;
2155a1d355fSStephan Aßmus
2165a1d355fSStephan Aßmus if (fShareInfo)
21788e38c17SIngo Weinhold fShareInfo->ReleaseReference();
2185a1d355fSStephan Aßmus if (fServerInfo)
21988e38c17SIngo Weinhold fServerInfo->ReleaseReference();
2205a1d355fSStephan Aßmus if (fServerConnection)
22188e38c17SIngo Weinhold fServerConnection->ReleaseReference();
2225a1d355fSStephan Aßmus if (fServerConnectionProvider)
22388e38c17SIngo Weinhold fServerConnectionProvider->ReleaseReference();
2245a1d355fSStephan Aßmus }
2255a1d355fSStephan Aßmus
2265a1d355fSStephan Aßmus // GetID
2275a1d355fSStephan Aßmus nspace_id
GetID() const2285a1d355fSStephan 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
IsReadOnly() const2355a1d355fSStephan 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
SupportsQueries() const2425a1d355fSStephan 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
Init(const char * name)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
Uninit()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*
GetRootNode() const3245a1d355fSStephan 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
PrepareToUnmount()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 _RemoveEntry(entry);
3495a1d355fSStephan Aßmus }
350*de48af7aSAugustin Cavalier fEntries->Clear();
3515a1d355fSStephan Aßmus
3525a1d355fSStephan Aßmus // get all IDs
3535a1d355fSStephan Aßmus int32 count = fNodes->Size();
3545a1d355fSStephan Aßmus if (count == 0)
3555a1d355fSStephan Aßmus return;
3564cfa5b2dSJérôme Duval PRINT(" %" B_PRId32 " nodes to remove\n", count);
3575a1d355fSStephan Aßmus vnode_id* ids = new(std::nothrow) vnode_id[count];
3585a1d355fSStephan Aßmus if (!ids) {
3595a1d355fSStephan Aßmus ERROR("ShareVolume::PrepareToUnmount(): ERROR: Insufficient memory to "
3605a1d355fSStephan Aßmus "allocate the node ID array!\n");
3615a1d355fSStephan Aßmus return;
3625a1d355fSStephan Aßmus }
3635a1d355fSStephan Aßmus ArrayDeleter<vnode_id> _(ids);
3645a1d355fSStephan Aßmus count = 0;
3655a1d355fSStephan Aßmus for (NodeMap::Iterator it = fNodes->GetIterator(); it.HasNext();) {
3665a1d355fSStephan Aßmus ShareNode* node = it.Next().value;
3675a1d355fSStephan Aßmus ids[count++] = node->GetID();
3685a1d355fSStephan Aßmus }
3695a1d355fSStephan Aßmus
3705a1d355fSStephan Aßmus // Remove all nodes that are not known to the VFS right away.
3715a1d355fSStephan Aßmus // If the netfs is already in the process of being unmounted, GetVNode()
3725a1d355fSStephan Aßmus // will fail and the GetVNode(), RemoveVNode(), PutVNode() method won't
3735a1d355fSStephan Aßmus // work for removing them.
3745a1d355fSStephan Aßmus int32 remainingCount = 0;
3755a1d355fSStephan Aßmus for (int32 i = 0; i < count; i++) {
3765a1d355fSStephan Aßmus if (Node* node = fNodes->Get(ids[i])) {
3775a1d355fSStephan Aßmus if (node->IsKnownToVFS()) {
3785a1d355fSStephan Aßmus // node is known to VFS; we need to use the GetVNode(),
3795a1d355fSStephan Aßmus // RemoveVNode(), PutVNode() method
3805a1d355fSStephan Aßmus ids[remainingCount++] = ids[i];
3815a1d355fSStephan Aßmus } else {
3825a1d355fSStephan Aßmus // node is not known to VFS; just remove and delete it
3835a1d355fSStephan Aßmus fNodes->Remove(node->GetID());
3845a1d355fSStephan Aßmus _RemoveLocalNodeID(node->GetID());
3855a1d355fSStephan Aßmus if (node != fRootNode)
3865a1d355fSStephan Aßmus delete node;
3875a1d355fSStephan Aßmus }
3885a1d355fSStephan Aßmus }
3895a1d355fSStephan Aßmus }
3905a1d355fSStephan Aßmus count = remainingCount;
3915a1d355fSStephan Aßmus
3925a1d355fSStephan Aßmus locker.Unlock();
3935a1d355fSStephan Aßmus
3945a1d355fSStephan Aßmus // remove the nodes
3955a1d355fSStephan Aßmus for (int32 i = 0; i < count; i++) {
3965a1d355fSStephan Aßmus Node* node;
3975a1d355fSStephan Aßmus if (GetVNode(ids[i], &node) == B_OK) {
3984cfa5b2dSJérôme Duval PRINT(" removing node %" B_PRIdINO "\n", ids[i]);
3995a1d355fSStephan Aßmus Volume::RemoveVNode(ids[i]);
4005a1d355fSStephan Aßmus PutVNode(ids[i]);
4015a1d355fSStephan Aßmus }
4025a1d355fSStephan Aßmus }
4035a1d355fSStephan Aßmus
4045a1d355fSStephan Aßmus // remove ourselves for the server connection
4055a1d355fSStephan Aßmus if (fServerConnection)
4065a1d355fSStephan Aßmus fServerConnection->RemoveVolume(this);
4075a1d355fSStephan Aßmus
4085a1d355fSStephan Aßmus // delete all entries
4095a1d355fSStephan Aßmus
4105a1d355fSStephan Aßmus PRINT(("ShareVolume::PrepareToUnmount() done\n"));
4115a1d355fSStephan Aßmus }
4125a1d355fSStephan Aßmus
4135a1d355fSStephan Aßmus // RemoveChildVolume
4145a1d355fSStephan Aßmus void
RemoveChildVolume(Volume * volume)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
Unmount()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
Sync()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
ReadVNode(vnode_id vnid,char reenter,Node ** _node)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
WriteVNode(Node * node,char reenter)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
RemoveVNode(Node * node,char reenter)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
FSync(Node * _node)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
ReadStat(Node * _node,struct stat * st)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
WriteStat(Node * _node,struct stat * st,uint32 mask)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
Access(Node * _node,int mode)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
Create(Node * _dir,const char * name,int openMode,int mode,vnode_id * vnid,void ** cookie)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
Open(Node * _node,int openMode,void ** cookie)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
Close(Node * _node,void * cookie)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
FreeCookie(Node * _node,void * cookie)7485a1d355fSStephan Aßmus ShareVolume::FreeCookie(Node* _node, void* cookie)
7495a1d355fSStephan Aßmus {
75059ecfa6cSAugustin Cavalier return _Close((intptr_t)cookie);
7515a1d355fSStephan Aßmus }
7525a1d355fSStephan Aßmus
7535a1d355fSStephan Aßmus // Read
7545a1d355fSStephan Aßmus status_t
Read(Node * _node,void * cookie,off_t pos,void * _buffer,size_t bufferSize,size_t * _bytesRead)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;
76859ecfa6cSAugustin Cavalier request.cookie = (intptr_t)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
Write(Node * _node,void * cookie,off_t pos,const void * _buffer,size_t bufferSize,size_t * bytesWritten)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;
86459ecfa6cSAugustin Cavalier request.cookie = (intptr_t)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
Link(Node * _dir,const char * name,Node * _node)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
Unlink(Node * _dir,const char * name)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
Symlink(Node * _dir,const char * name,const char * target)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
ReadLink(Node * _node,char * buffer,size_t bufferSize,size_t * bytesRead)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
Rename(Node * _oldDir,const char * oldName,Node * _newDir,const char * newName)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
MkDir(Node * _dir,const char * name,int mode)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
RmDir(Node * _dir,const char * name)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
OpenDir(Node * _node,void ** _cookie)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 {
11694cfa5b2dSJérôme Duval PRINT("OpenDir() failed: node: %" B_PRIdINO ", remote: (%" B_PRIdDEV
11704cfa5b2dSJérôme Duval ", %" B_PRIdINO ")\n", 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
CloseDir(Node * _node,void * cookie)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
FreeDirCookie(Node * _node,void * _cookie)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
ReadDir(Node * _dir,void * _cookie,struct dirent * buffer,size_t bufferSize,int32 count,int32 * countRead)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
RewindDir(Node * _node,void * _cookie)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
Walk(Node * _dir,const char * entryName,char ** resolvedPath,vnode_id * vnid)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
OpenAttrDir(Node * _node,void ** _cookie)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
CloseAttrDir(Node * _node,void * cookie)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
FreeAttrDirCookie(Node * _node,void * _cookie)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
ReadAttrDir(Node * _node,void * _cookie,struct dirent * buffer,size_t bufferSize,int32 count,int32 * countRead)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
RewindAttrDir(Node * _node,void * _cookie)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
ReadAttr(Node * _node,const char * name,int type,off_t pos,void * _buffer,size_t bufferSize,size_t * _bytesRead)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
WriteAttr(Node * _node,const char * name,int type,off_t pos,const void * _buffer,size_t bufferSize,size_t * bytesWritten)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
RemoveAttr(Node * _node,const char * name)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
RenameAttr(Node * _node,const char * oldName,const char * newName)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
StatAttr(Node * _node,const char * name,struct attr_info * attrInfo)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
GetQueryEntry(const EntryInfo & entryInfo,const NodeInfo & dirInfo,struct dirent * buffer,size_t bufferSize,int32 * countRead)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;
20214cfa5b2dSJérôme Duval PRINT(" entry: d_dev: %" B_PRIdDEV ", d_pdev: %" B_PRIdDEV ", d_ino: %"
20224cfa5b2dSJérôme Duval B_PRIdINO ", d_pino: %" B_PRIdINO ", d_reclen: %hu, d_name: `%s'\n",
20234cfa5b2dSJérôme Duval buffer->d_dev, buffer->d_pdev, buffer->d_ino, buffer->d_pino,
20244cfa5b2dSJérôme Duval buffer->d_reclen, 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
ProcessNodeMonitoringRequest(NodeMonitoringRequest * request)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
ConnectionClosed()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
_ReadRemoteDir(ShareDir * directory,RemoteShareDirIterator * iterator)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
_HandleEntryCreatedRequest(EntryCreatedRequest * request)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);
21754cfa5b2dSJérôme Duval PRINT("ShareVolume::_HandleEntryCreatedRequest(): error: 0x%" B_PRIx32
21764cfa5b2dSJérôme Duval ", name: \"%s\", dir: %" B_PRIdINO " (remote: (%" B_PRIdDEV ", %"
21774cfa5b2dSJérôme Duval B_PRIdINO ")), node: %" B_PRIdINO " (remote: (%" B_PRIdDEV ", %"
21784cfa5b2dSJérôme Duval B_PRIdINO "))\n", error, name, vnida,
21794cfa5b2dSJérôme Duval request->directoryID.volumeID, 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
_HandleEntryRemovedRequest(EntryRemovedRequest * request)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
_HandleEntryMovedRequest(EntryMovedRequest * request)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
_HandleStatChangedRequest(StatChangedRequest * request)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
_HandleAttributeChangedRequest(AttributeChangedRequest * request)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
_GetLocalNodeID(NodeID remoteID,ino_t * _localID,bool enter)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 }
23724cfa5b2dSJérôme Duval PRINT("ShareVolume(%" B_PRId32 "): added node ID mapping: local: %"
23734cfa5b2dSJérôme Duval B_PRIdINO " -> remote: (%" B_PRIdDEV ", %" B_PRIdINO ")\n", fID,
23744cfa5b2dSJérôme Duval localID, remoteID.volumeID, 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
_GetRemoteNodeID(ino_t localID,NodeID * remoteID)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
_RemoveLocalNodeID(ino_t localID)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);
24064cfa5b2dSJérôme Duval PRINT("ShareVolume::_RemoveLocalNodeID(%" B_PRIdINO "): remote: (%"
24074cfa5b2dSJérôme Duval B_PRIdDEV ", %" B_PRIdINO ")\n", localID, remoteID.volumeID,
24084cfa5b2dSJérôme Duval remoteID.nodeID);
24095a1d355fSStephan Aßmus fRemoteNodeIDs->Remove(localID);
24105a1d355fSStephan Aßmus fLocalNodeIDs->Remove(remoteID);
24115a1d355fSStephan Aßmus
24125a1d355fSStephan Aßmus // remove from volume manager
24135a1d355fSStephan Aßmus fVolumeManager->RemoveNodeID(localID);
24145a1d355fSStephan Aßmus }
24155a1d355fSStephan Aßmus
24165a1d355fSStephan Aßmus // _GetNodeByLocalID
24175a1d355fSStephan Aßmus ShareNode*
_GetNodeByLocalID(ino_t localID)24185a1d355fSStephan Aßmus ShareVolume::_GetNodeByLocalID(ino_t localID)
24195a1d355fSStephan Aßmus {
24205a1d355fSStephan Aßmus AutoLocker<Locker> _(fLock);
24215a1d355fSStephan Aßmus return fNodes->Get(localID);
24225a1d355fSStephan Aßmus }
24235a1d355fSStephan Aßmus
24245a1d355fSStephan Aßmus // _GetNodeByRemoteID
24255a1d355fSStephan Aßmus ShareNode*
_GetNodeByRemoteID(NodeID remoteID)24265a1d355fSStephan Aßmus ShareVolume::_GetNodeByRemoteID(NodeID remoteID)
24275a1d355fSStephan Aßmus {
24285a1d355fSStephan Aßmus AutoLocker<Locker> _(fLock);
24295a1d355fSStephan Aßmus
24305a1d355fSStephan Aßmus ino_t localID;
24315a1d355fSStephan Aßmus if (_GetLocalNodeID(remoteID, &localID, false) == B_OK)
24325a1d355fSStephan Aßmus return fNodes->Get(localID);
24335a1d355fSStephan Aßmus
24345a1d355fSStephan Aßmus return NULL;
24355a1d355fSStephan Aßmus }
24365a1d355fSStephan Aßmus
24375a1d355fSStephan Aßmus // _LoadNode
24385a1d355fSStephan Aßmus status_t
_LoadNode(const NodeInfo & nodeInfo,ShareNode ** _node)24395a1d355fSStephan Aßmus ShareVolume::_LoadNode(const NodeInfo& nodeInfo, ShareNode** _node)
24405a1d355fSStephan Aßmus {
24415a1d355fSStephan Aßmus AutoLocker<Locker> _(fLock);
24425a1d355fSStephan Aßmus
24435a1d355fSStephan Aßmus // check, if the node is already known
24445a1d355fSStephan Aßmus ShareNode* node = _GetNodeByRemoteID(nodeInfo.GetID());
24455a1d355fSStephan Aßmus if (node) {
24465a1d355fSStephan Aßmus node->Update(nodeInfo);
24475a1d355fSStephan Aßmus } else {
24485a1d355fSStephan Aßmus // don't load the node when already unmounting
24495a1d355fSStephan Aßmus if (fUnmounting)
24505a1d355fSStephan Aßmus return B_ERROR;
24515a1d355fSStephan Aßmus
24525a1d355fSStephan Aßmus // get a local node ID
24535a1d355fSStephan Aßmus vnode_id localID;
24545a1d355fSStephan Aßmus status_t error = _GetLocalNodeID(nodeInfo.GetID(), &localID, true);
24555a1d355fSStephan Aßmus if (error != B_OK)
24565a1d355fSStephan Aßmus return error;
24575a1d355fSStephan Aßmus
24585a1d355fSStephan Aßmus // create a new node
24595a1d355fSStephan Aßmus if (S_ISDIR(nodeInfo.st.st_mode))
24605a1d355fSStephan Aßmus node = new(std::nothrow) ShareDir(this, localID, &nodeInfo);
24615a1d355fSStephan Aßmus else
24625a1d355fSStephan Aßmus node = new(std::nothrow) ShareNode(this, localID, &nodeInfo);
24635a1d355fSStephan Aßmus if (!node) {
24645a1d355fSStephan Aßmus _RemoveLocalNodeID(localID);
24655a1d355fSStephan Aßmus return B_NO_MEMORY;
24665a1d355fSStephan Aßmus }
24675a1d355fSStephan Aßmus
24685a1d355fSStephan Aßmus // add it
24695a1d355fSStephan Aßmus error = fNodes->Put(node->GetID(), node);
24705a1d355fSStephan Aßmus if (error != B_OK) {
24715a1d355fSStephan Aßmus _RemoveLocalNodeID(localID);
24725a1d355fSStephan Aßmus delete node;
24735a1d355fSStephan Aßmus return error;
24745a1d355fSStephan Aßmus }
24754cfa5b2dSJérôme Duval PRINT("ShareVolume: added node: %" B_PRIdINO ": remote: (%" B_PRIdDEV
24764cfa5b2dSJérôme Duval ", %" B_PRIdINO "), localID: %" B_PRIdINO "\n", node->GetID(),
24773c1afd35SPawel Dziepak node->GetRemoteID().volumeID,
24783c1afd35SPawel Dziepak node->GetRemoteID().nodeID, localID);
24795a1d355fSStephan Aßmus }
24805a1d355fSStephan Aßmus
24815a1d355fSStephan Aßmus if (_node)
24825a1d355fSStephan Aßmus *_node = node;
24835a1d355fSStephan Aßmus return B_OK;
24845a1d355fSStephan Aßmus }
24855a1d355fSStephan Aßmus
24865a1d355fSStephan Aßmus // _UpdateNode
24875a1d355fSStephan Aßmus status_t
_UpdateNode(const NodeInfo & nodeInfo)24885a1d355fSStephan Aßmus ShareVolume::_UpdateNode(const NodeInfo& nodeInfo)
24895a1d355fSStephan Aßmus {
24905a1d355fSStephan Aßmus AutoLocker<Locker> _(fLock);
24915a1d355fSStephan Aßmus
24925a1d355fSStephan Aßmus if (fUnmounting)
24935a1d355fSStephan Aßmus return ERROR_NOT_CONNECTED;
24945a1d355fSStephan Aßmus
24955a1d355fSStephan Aßmus ShareNode* node = _GetNodeByRemoteID(nodeInfo.GetID());
24965a1d355fSStephan Aßmus if (node) {
24975a1d355fSStephan Aßmus node->Update(nodeInfo);
24985a1d355fSStephan Aßmus return B_OK;
24995a1d355fSStephan Aßmus }
25005a1d355fSStephan Aßmus return B_ENTRY_NOT_FOUND;
25015a1d355fSStephan Aßmus }
25025a1d355fSStephan Aßmus
25035a1d355fSStephan Aßmus // _GetEntryByLocalID
25045a1d355fSStephan Aßmus ShareDirEntry*
_GetEntryByLocalID(ino_t localDirID,const char * name)25055a1d355fSStephan Aßmus ShareVolume::_GetEntryByLocalID(ino_t localDirID, const char* name)
25065a1d355fSStephan Aßmus {
25075a1d355fSStephan Aßmus if (!name)
25085a1d355fSStephan Aßmus return NULL;
25095a1d355fSStephan Aßmus
25105a1d355fSStephan Aßmus AutoLocker<Locker> _(fLock);
25115a1d355fSStephan Aßmus return fEntries->Get(EntryKey(localDirID, name));
25125a1d355fSStephan Aßmus }
25135a1d355fSStephan Aßmus
25145a1d355fSStephan Aßmus // _GetEntryByRemoteID
25155a1d355fSStephan Aßmus ShareDirEntry*
_GetEntryByRemoteID(NodeID remoteDirID,const char * name)25165a1d355fSStephan Aßmus ShareVolume::_GetEntryByRemoteID(NodeID remoteDirID, const char* name)
25175a1d355fSStephan Aßmus {
25185a1d355fSStephan Aßmus if (!name)
25195a1d355fSStephan Aßmus return NULL;
25205a1d355fSStephan Aßmus
25215a1d355fSStephan Aßmus AutoLocker<Locker> _(fLock);
25225a1d355fSStephan Aßmus
25235a1d355fSStephan Aßmus ino_t localDirID;
25245a1d355fSStephan Aßmus if (_GetLocalNodeID(remoteDirID, &localDirID, false) == B_OK)
25255a1d355fSStephan Aßmus return fEntries->Get(EntryKey(localDirID, name));
25265a1d355fSStephan Aßmus
25275a1d355fSStephan Aßmus return NULL;
25285a1d355fSStephan Aßmus }
25295a1d355fSStephan Aßmus
25305a1d355fSStephan Aßmus // _LoadEntry
25315a1d355fSStephan Aßmus //
25325a1d355fSStephan Aßmus // If _entry is supplied, fLock should be held, otherwise the returned entry
25335a1d355fSStephan Aßmus // might as well be deleted.
25345a1d355fSStephan Aßmus status_t
_LoadEntry(ShareDir * directory,const EntryInfo & entryInfo,ShareDirEntry ** _entry)25355a1d355fSStephan Aßmus ShareVolume::_LoadEntry(ShareDir* directory, const EntryInfo& entryInfo,
25365a1d355fSStephan Aßmus ShareDirEntry** _entry)
25375a1d355fSStephan Aßmus {
25385a1d355fSStephan Aßmus const char* name = entryInfo.name.GetString();
25395a1d355fSStephan Aßmus if (!directory || !name)
25405a1d355fSStephan Aßmus return B_BAD_VALUE;
25415a1d355fSStephan Aßmus
25425a1d355fSStephan Aßmus AutoLocker<Locker> _(fLock);
25435a1d355fSStephan Aßmus
25445a1d355fSStephan Aßmus ShareDirEntry* entry = _GetEntryByLocalID(directory->GetID(), name);
25455a1d355fSStephan Aßmus if (entry) {
25465a1d355fSStephan Aßmus if (entryInfo.nodeInfo.revision > entry->GetRevision()) {
25475a1d355fSStephan Aßmus if (entryInfo.nodeInfo.GetID() != entry->GetNode()->GetRemoteID()) {
25485a1d355fSStephan Aßmus // The node the existing entry refers to is not the node it
25495a1d355fSStephan Aßmus // should refer to. Remove the old entry and create a new one.
25505a1d355fSStephan Aßmus _EntryRemoved(directory->GetRemoteID(), name,
25515a1d355fSStephan Aßmus entryInfo.nodeInfo.revision);
25525a1d355fSStephan Aßmus _EntryCreated(directory->GetRemoteID(), name, &entryInfo,
25535a1d355fSStephan Aßmus entryInfo.nodeInfo.revision);
25545a1d355fSStephan Aßmus
25555a1d355fSStephan Aßmus // re-get the entry and check, if everything is fine
25565a1d355fSStephan Aßmus entry = _GetEntryByLocalID(directory->GetID(), name);
25575a1d355fSStephan Aßmus if (!entry)
25585a1d355fSStephan Aßmus return B_ERROR;
25595a1d355fSStephan Aßmus if (entryInfo.nodeInfo.GetID()
25605a1d355fSStephan Aßmus != entry->GetNode()->GetRemoteID()) {
25615a1d355fSStephan Aßmus return B_ERROR;
25625a1d355fSStephan Aßmus }
25635a1d355fSStephan Aßmus } else {
25645a1d355fSStephan Aßmus entry->SetRevision(entryInfo.nodeInfo.revision);
25655a1d355fSStephan Aßmus _UpdateNode(entryInfo.nodeInfo);
25665a1d355fSStephan Aßmus }
25675a1d355fSStephan Aßmus }
25685a1d355fSStephan Aßmus } else {
25695a1d355fSStephan Aßmus // entry not known yet: create it
25705a1d355fSStephan Aßmus
25715a1d355fSStephan Aßmus // don't load the entry when already unmounting
25725a1d355fSStephan Aßmus if (fUnmounting)
25735a1d355fSStephan Aßmus return B_ERROR;
25745a1d355fSStephan Aßmus
25755a1d355fSStephan Aßmus // load the node
25765a1d355fSStephan Aßmus ShareNode* node;
25775a1d355fSStephan Aßmus status_t error = _LoadNode(entryInfo.nodeInfo, &node);
25785a1d355fSStephan Aßmus if (error != B_OK)
25795a1d355fSStephan Aßmus return error;
25805a1d355fSStephan Aßmus
25815a1d355fSStephan Aßmus // if the directory or the node are marked remove, we don't create the
25825a1d355fSStephan Aßmus // entry
25835a1d355fSStephan Aßmus if (IsVNodeRemoved(directory->GetID()) > 0
25845a1d355fSStephan Aßmus || IsVNodeRemoved(node->GetID()) > 0) {
25855a1d355fSStephan Aßmus return B_NOT_ALLOWED;
25865a1d355fSStephan Aßmus }
25875a1d355fSStephan Aßmus
25885a1d355fSStephan Aßmus // create the entry
25895a1d355fSStephan Aßmus entry = new(std::nothrow) ShareDirEntry(directory, name, node);
25905a1d355fSStephan Aßmus if (!entry)
25915a1d355fSStephan Aßmus return B_NO_MEMORY;
25925a1d355fSStephan Aßmus ObjectDeleter<ShareDirEntry> entryDeleter(entry);
25935a1d355fSStephan Aßmus error = entry->InitCheck();
25945a1d355fSStephan Aßmus if (error != B_OK)
25955a1d355fSStephan Aßmus return error;
25965a1d355fSStephan Aßmus
25975a1d355fSStephan Aßmus // add the entry
25985a1d355fSStephan Aßmus error = fEntries->Put(EntryKey(directory->GetID(), entry->GetName()),
25995a1d355fSStephan Aßmus entry);
26005a1d355fSStephan Aßmus if (error != B_OK)
26015a1d355fSStephan Aßmus return error;
26025a1d355fSStephan Aßmus
26035a1d355fSStephan Aßmus // set the entry revision
26045a1d355fSStephan Aßmus entry->SetRevision(entryInfo.nodeInfo.revision);
26055a1d355fSStephan Aßmus
26065a1d355fSStephan Aßmus // add the entry to the directory and the node
26075a1d355fSStephan Aßmus directory->AddEntry(entry);
26085a1d355fSStephan Aßmus entry->GetNode()->AddReferringEntry(entry);
26095a1d355fSStephan Aßmus
26105a1d355fSStephan Aßmus // everything went fine
26115a1d355fSStephan Aßmus entryDeleter.Detach();
26125a1d355fSStephan Aßmus }
26135a1d355fSStephan Aßmus
26145a1d355fSStephan Aßmus if (_entry)
26155a1d355fSStephan Aßmus *_entry = entry;
26165a1d355fSStephan Aßmus return B_OK;
26175a1d355fSStephan Aßmus }
26185a1d355fSStephan Aßmus
26195a1d355fSStephan Aßmus // _RemoveEntry
26205a1d355fSStephan Aßmus //
26215a1d355fSStephan Aßmus // fLock must be held.
26225a1d355fSStephan Aßmus void
_RemoveEntry(ShareDirEntry * entry)26235a1d355fSStephan Aßmus ShareVolume::_RemoveEntry(ShareDirEntry* entry)
26245a1d355fSStephan Aßmus {
26255a1d355fSStephan Aßmus fEntries->Remove(EntryKey(entry->GetDirectory()->GetID(),
26265a1d355fSStephan Aßmus entry->GetName()));
26275a1d355fSStephan Aßmus entry->GetDirectory()->RemoveEntry(entry);
26285a1d355fSStephan Aßmus entry->GetNode()->RemoveReferringEntry(entry);
262988e38c17SIngo Weinhold entry->ReleaseReference();
26305a1d355fSStephan Aßmus }
26315a1d355fSStephan Aßmus
26325a1d355fSStephan Aßmus // _IsObsoleteEntryInfo
26335a1d355fSStephan Aßmus //
26345a1d355fSStephan Aßmus // fLock must be held.
26355a1d355fSStephan Aßmus bool
_IsObsoleteEntryInfo(const EntryInfo & entryInfo)26365a1d355fSStephan Aßmus ShareVolume::_IsObsoleteEntryInfo(const EntryInfo& entryInfo)
26375a1d355fSStephan Aßmus {
26385a1d355fSStephan Aßmus // get the directory
26395a1d355fSStephan Aßmus ShareDir* dir
26405a1d355fSStephan Aßmus = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(entryInfo.directoryID));
26415a1d355fSStephan Aßmus if (!dir)
26425a1d355fSStephan Aßmus return false;
26435a1d355fSStephan Aßmus
26445a1d355fSStephan Aßmus return (entryInfo.nodeInfo.revision <= dir->GetEntryRemovedEventRevision());
26455a1d355fSStephan Aßmus }
26465a1d355fSStephan Aßmus
26475a1d355fSStephan Aßmus // _LoadAttrDir
26485a1d355fSStephan Aßmus status_t
_LoadAttrDir(ShareNode * node,const AttrDirInfo & attrDirInfo)26495a1d355fSStephan Aßmus ShareVolume::_LoadAttrDir(ShareNode* node, const AttrDirInfo& attrDirInfo)
26505a1d355fSStephan Aßmus {
26515a1d355fSStephan Aßmus if (!node || !attrDirInfo.isValid)
26525a1d355fSStephan Aßmus return B_BAD_VALUE;
26535a1d355fSStephan Aßmus
26545a1d355fSStephan Aßmus AutoLocker<Locker> _(fLock);
26555a1d355fSStephan Aßmus
26565a1d355fSStephan Aßmus if (fUnmounting)
26575a1d355fSStephan Aßmus return ERROR_NOT_CONNECTED;
26585a1d355fSStephan Aßmus
26595a1d355fSStephan Aßmus ShareAttrDir* attrDir = node->GetAttrDir();
26605a1d355fSStephan Aßmus if (attrDir) {
26615a1d355fSStephan Aßmus if (attrDir->GetRevision() > attrDirInfo.revision)
26625a1d355fSStephan Aßmus return B_OK;
26635a1d355fSStephan Aßmus
26645a1d355fSStephan Aßmus // update the attr dir
26655a1d355fSStephan Aßmus return attrDir->Update(attrDirInfo,
26665a1d355fSStephan Aßmus fAttrDirIterators->Get(node->GetID()));
26675a1d355fSStephan Aßmus } else {
26685a1d355fSStephan Aßmus // no attribute directory yet: create one
26695a1d355fSStephan Aßmus attrDir = new(std::nothrow) ShareAttrDir;
26705a1d355fSStephan Aßmus if (!attrDir)
26715a1d355fSStephan Aßmus return B_NO_MEMORY;
26725a1d355fSStephan Aßmus ObjectDeleter<ShareAttrDir> attrDirDeleter(attrDir);
26735a1d355fSStephan Aßmus
26745a1d355fSStephan Aßmus // initialize it
26755a1d355fSStephan Aßmus status_t error = attrDir->Init(attrDirInfo);
26765a1d355fSStephan Aßmus if (error != B_OK)
26775a1d355fSStephan Aßmus return error;
26785a1d355fSStephan Aßmus
26795a1d355fSStephan Aßmus // set it
26805a1d355fSStephan Aßmus node->SetAttrDir(attrDir);
26815a1d355fSStephan Aßmus attrDirDeleter.Detach();
26825a1d355fSStephan Aßmus return B_OK;
26835a1d355fSStephan Aßmus }
26845a1d355fSStephan Aßmus }
26855a1d355fSStephan Aßmus
26865a1d355fSStephan Aßmus // _UpdateAttrDir
26875a1d355fSStephan Aßmus status_t
_UpdateAttrDir(NodeID remoteID,const AttrDirInfo & attrDirInfo)26885a1d355fSStephan Aßmus ShareVolume::_UpdateAttrDir(NodeID remoteID, const AttrDirInfo& attrDirInfo)
26895a1d355fSStephan Aßmus {
26905a1d355fSStephan Aßmus AutoLocker<Locker> _(fLock);
26915a1d355fSStephan Aßmus
26925a1d355fSStephan Aßmus // get the node
26935a1d355fSStephan Aßmus ShareNode* node = _GetNodeByRemoteID(remoteID);
26945a1d355fSStephan Aßmus if (!node)
26955a1d355fSStephan Aßmus return B_ENTRY_NOT_FOUND;
26965a1d355fSStephan Aßmus
26975a1d355fSStephan Aßmus if (!attrDirInfo.isValid || _LoadAttrDir(node, attrDirInfo) != B_OK) {
26985a1d355fSStephan Aßmus // updating/creating the attr dir failed; if existing, we mark it
26995a1d355fSStephan Aßmus // obsolete
27005a1d355fSStephan Aßmus if (ShareAttrDir* attrDir = node->GetAttrDir())
27015a1d355fSStephan Aßmus attrDir->SetUpToDate(false);
27025a1d355fSStephan Aßmus }
27035a1d355fSStephan Aßmus
27045a1d355fSStephan Aßmus return B_OK;
27055a1d355fSStephan Aßmus }
27065a1d355fSStephan Aßmus
27075a1d355fSStephan Aßmus // _AddAttrDirIterator
27085a1d355fSStephan Aßmus status_t
_AddAttrDirIterator(ShareNode * node,ShareAttrDirIterator * iterator)27095a1d355fSStephan Aßmus ShareVolume::_AddAttrDirIterator(ShareNode* node,
27105a1d355fSStephan Aßmus ShareAttrDirIterator* iterator)
27115a1d355fSStephan Aßmus {
27125a1d355fSStephan Aßmus if (!node || !iterator)
27135a1d355fSStephan Aßmus return B_BAD_VALUE;
27145a1d355fSStephan Aßmus
27155a1d355fSStephan Aßmus AutoLocker<Locker> locker(fLock);
27165a1d355fSStephan Aßmus
27175a1d355fSStephan Aßmus // get the iterator list
27185a1d355fSStephan Aßmus DoublyLinkedList<ShareAttrDirIterator>* iteratorList
27195a1d355fSStephan Aßmus = fAttrDirIterators->Get(node->GetID());
27205a1d355fSStephan Aßmus if (!iteratorList) {
27215a1d355fSStephan Aßmus // no list for the node yet: create one
27225a1d355fSStephan Aßmus iteratorList = new(std::nothrow) DoublyLinkedList<ShareAttrDirIterator>;
27235a1d355fSStephan Aßmus if (!iteratorList)
27245a1d355fSStephan Aßmus return B_NO_MEMORY;
27255a1d355fSStephan Aßmus
27265a1d355fSStephan Aßmus // add it
27275a1d355fSStephan Aßmus status_t error = fAttrDirIterators->Put(node->GetID(), iteratorList);
27285a1d355fSStephan Aßmus if (error != B_OK) {
27295a1d355fSStephan Aßmus delete iteratorList;
27305a1d355fSStephan Aßmus return error;
27315a1d355fSStephan Aßmus }
27325a1d355fSStephan Aßmus }
27335a1d355fSStephan Aßmus
27345a1d355fSStephan Aßmus // add the iterator
27355a1d355fSStephan Aßmus iteratorList->Insert(iterator);
27365a1d355fSStephan Aßmus
27375a1d355fSStephan Aßmus return B_OK;
27385a1d355fSStephan Aßmus }
27395a1d355fSStephan Aßmus
27405a1d355fSStephan Aßmus // _RemoveAttrDirIterator
27415a1d355fSStephan Aßmus void
_RemoveAttrDirIterator(ShareNode * node,ShareAttrDirIterator * iterator)27425a1d355fSStephan Aßmus ShareVolume::_RemoveAttrDirIterator(ShareNode* node,
27435a1d355fSStephan Aßmus ShareAttrDirIterator* iterator)
27445a1d355fSStephan Aßmus {
27455a1d355fSStephan Aßmus if (!node || !iterator)
27465a1d355fSStephan Aßmus return;
27475a1d355fSStephan Aßmus
27485a1d355fSStephan Aßmus AutoLocker<Locker> locker(fLock);
27495a1d355fSStephan Aßmus
27505a1d355fSStephan Aßmus // get the iterator list
27515a1d355fSStephan Aßmus DoublyLinkedList<ShareAttrDirIterator>* iteratorList
27525a1d355fSStephan Aßmus = fAttrDirIterators->Get(node->GetID());
27535a1d355fSStephan Aßmus if (!iteratorList) {
27545a1d355fSStephan Aßmus WARN("ShareVolume::_RemoveAttrDirIterator(): Iterator list not "
275520f046edSJérôme Duval "found: node: %" B_PRIdINO "\n", node->GetID());
27565a1d355fSStephan Aßmus return;
27575a1d355fSStephan Aßmus }
27585a1d355fSStephan Aßmus
27595a1d355fSStephan Aßmus // remove the iterator
27605a1d355fSStephan Aßmus iteratorList->Remove(iterator);
27615a1d355fSStephan Aßmus
27625a1d355fSStephan Aßmus // if the list is empty now, discard it
27635a1d355fSStephan Aßmus if (!iteratorList->First()) {
27645a1d355fSStephan Aßmus fAttrDirIterators->Remove(node->GetID());
27655a1d355fSStephan Aßmus delete iteratorList;
27665a1d355fSStephan Aßmus }
27675a1d355fSStephan Aßmus }
27685a1d355fSStephan Aßmus
27695a1d355fSStephan Aßmus // _NodeRemoved
27705a1d355fSStephan Aßmus void
_NodeRemoved(NodeID remoteID)27715a1d355fSStephan Aßmus ShareVolume::_NodeRemoved(NodeID remoteID)
27725a1d355fSStephan Aßmus {
27735a1d355fSStephan Aßmus AutoLocker<Locker> locker(fLock);
27745a1d355fSStephan Aßmus
27755a1d355fSStephan Aßmus ShareNode* node = _GetNodeByRemoteID(remoteID);
27765a1d355fSStephan Aßmus if (!node)
27775a1d355fSStephan Aßmus return;
27785a1d355fSStephan Aßmus
27795a1d355fSStephan Aßmus // if the node still has referring entries, we do nothing
27805a1d355fSStephan Aßmus if (node->GetActualReferringEntry())
27815a1d355fSStephan Aßmus return;
27825a1d355fSStephan Aßmus
27835a1d355fSStephan Aßmus // if the node is a directory, we remove its entries first
27845a1d355fSStephan Aßmus if (ShareDir* dir = dynamic_cast<ShareDir*>(node)) {
27855a1d355fSStephan Aßmus while (ShareDirEntry* entry = dir->GetFirstEntry())
27865a1d355fSStephan Aßmus _RemoveEntry(entry);
27875a1d355fSStephan Aßmus }
27885a1d355fSStephan Aßmus
27895a1d355fSStephan Aßmus // remove all entries still referring to the node
27905a1d355fSStephan Aßmus while (ShareDirEntry* entry = node->GetFirstReferringEntry())
27915a1d355fSStephan Aßmus _RemoveEntry(entry);
27925a1d355fSStephan Aßmus
27935a1d355fSStephan Aßmus ino_t localID = node->GetID();
27945a1d355fSStephan Aßmus
27955a1d355fSStephan Aßmus // Remove the node ID in all cases -- even, if the node is still
27965a1d355fSStephan Aßmus // known to the VFS. Otherwise there could be a race condition, that the
27975a1d355fSStephan Aßmus // server re-uses the remote ID and we have it still associated with an
27985a1d355fSStephan Aßmus // obsolete local ID.
27995a1d355fSStephan Aßmus _RemoveLocalNodeID(localID);
28005a1d355fSStephan Aßmus
28015a1d355fSStephan Aßmus if (node->IsKnownToVFS()) {
28025a1d355fSStephan Aßmus Node* _node;
28035a1d355fSStephan Aßmus if (GetVNode(localID, &_node) != B_OK)
28045a1d355fSStephan Aßmus return;
28055a1d355fSStephan Aßmus Volume::RemoveVNode(localID);
28065a1d355fSStephan Aßmus locker.Unlock();
28075a1d355fSStephan Aßmus PutVNode(localID);
28085a1d355fSStephan Aßmus
28095a1d355fSStephan Aßmus } else {
28105a1d355fSStephan Aßmus fNodes->Remove(localID);
28115a1d355fSStephan Aßmus delete node;
28125a1d355fSStephan Aßmus }
28135a1d355fSStephan Aßmus }
28145a1d355fSStephan Aßmus
28155a1d355fSStephan Aßmus // _EntryCreated
28165a1d355fSStephan Aßmus void
_EntryCreated(NodeID remoteDirID,const char * name,const EntryInfo * entryInfo,int64 revision)28175a1d355fSStephan Aßmus ShareVolume::_EntryCreated(NodeID remoteDirID, const char* name,
28185a1d355fSStephan Aßmus const EntryInfo* entryInfo, int64 revision)
28195a1d355fSStephan Aßmus {
28205a1d355fSStephan Aßmus if (!name)
28215a1d355fSStephan Aßmus return;
28225a1d355fSStephan Aßmus
28235a1d355fSStephan Aßmus AutoLocker<Locker> locker(fLock);
28245a1d355fSStephan Aßmus
28255a1d355fSStephan Aßmus // get the directory
28265a1d355fSStephan Aßmus ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(remoteDirID));
28275a1d355fSStephan Aßmus if (!dir)
28285a1d355fSStephan Aßmus return;
28295a1d355fSStephan Aßmus
28305a1d355fSStephan Aßmus // load the entry, if possible
28315a1d355fSStephan Aßmus ShareDirEntry* entry;
28325a1d355fSStephan Aßmus bool entryLoaded = false;
28335a1d355fSStephan Aßmus if (entryInfo && _LoadEntry(dir, *entryInfo, &entry) == B_OK)
28345a1d355fSStephan Aßmus entryLoaded = true;
28355a1d355fSStephan Aßmus
28365a1d355fSStephan Aßmus // if the entry could not be loaded, we have to mark the dir incomplete
28375a1d355fSStephan Aßmus // and update its revision counter
28385a1d355fSStephan Aßmus if (!entryLoaded) {
28395a1d355fSStephan Aßmus dir->UpdateEntryCreatedEventRevision(revision);
28405a1d355fSStephan Aßmus dir->SetComplete(false);
28415a1d355fSStephan Aßmus }
28425a1d355fSStephan Aßmus }
28435a1d355fSStephan Aßmus
28445a1d355fSStephan Aßmus // _EntryRemoved
28455a1d355fSStephan Aßmus void
_EntryRemoved(NodeID remoteDirID,const char * name,int64 revision)28465a1d355fSStephan Aßmus ShareVolume::_EntryRemoved(NodeID remoteDirID, const char* name, int64 revision)
28475a1d355fSStephan Aßmus {
28485a1d355fSStephan Aßmus if (!name)
28495a1d355fSStephan Aßmus return;
28505a1d355fSStephan Aßmus
28515a1d355fSStephan Aßmus AutoLocker<Locker> locker(fLock);
28525a1d355fSStephan Aßmus
28535a1d355fSStephan Aßmus // get the directory
28545a1d355fSStephan Aßmus ShareDir* dir = dynamic_cast<ShareDir*>(_GetNodeByRemoteID(remoteDirID));
28555a1d355fSStephan Aßmus if (!dir)
28565a1d355fSStephan Aßmus return;
28575a1d355fSStephan Aßmus
28585a1d355fSStephan Aßmus // update the directory's "entry removed" event revision
28595a1d355fSStephan Aßmus dir->UpdateEntryRemovedEventRevision(revision);
28605a1d355fSStephan Aßmus
28615a1d355fSStephan Aßmus // get the entry
28625a1d355fSStephan Aßmus ShareDirEntry* entry = _GetEntryByRemoteID(remoteDirID, name);
28635a1d355fSStephan Aßmus if (!entry)
28645a1d355fSStephan Aßmus return;
28655a1d355fSStephan Aßmus
28665a1d355fSStephan Aßmus // check the entry revision
28675a1d355fSStephan Aßmus if (entry->GetRevision() > revision)
28685a1d355fSStephan Aßmus return;
28695a1d355fSStephan Aßmus
28705a1d355fSStephan Aßmus // remove the entry
28715a1d355fSStephan Aßmus _RemoveEntry(entry);
28725a1d355fSStephan Aßmus }
28735a1d355fSStephan Aßmus
28745a1d355fSStephan Aßmus // _EntryMoved
28755a1d355fSStephan Aßmus void
_EntryMoved(NodeID remoteOldDirID,const char * oldName,NodeID remoteNewDirID,const char * name,const EntryInfo * entryInfo,int64 revision)28765a1d355fSStephan Aßmus ShareVolume::_EntryMoved(NodeID remoteOldDirID, const char* oldName,
28775a1d355fSStephan Aßmus NodeID remoteNewDirID, const char* name, const EntryInfo* entryInfo,
28785a1d355fSStephan Aßmus int64 revision)
28795a1d355fSStephan Aßmus {
28805a1d355fSStephan Aßmus AutoLocker<Locker> locker(fLock);
28815a1d355fSStephan Aßmus
28825a1d355fSStephan Aßmus _EntryRemoved(remoteOldDirID, oldName, revision);
28835a1d355fSStephan Aßmus _EntryCreated(remoteNewDirID, name, entryInfo, revision);
28845a1d355fSStephan Aßmus }
28855a1d355fSStephan Aßmus
28865a1d355fSStephan Aßmus // _Walk
28875a1d355fSStephan Aßmus status_t
_Walk(NodeID remoteDirID,const char * entryName,bool resolveLink,WalkReply ** _reply)28885a1d355fSStephan Aßmus ShareVolume::_Walk(NodeID remoteDirID, const char* entryName, bool resolveLink,
28895a1d355fSStephan Aßmus WalkReply** _reply)
28905a1d355fSStephan Aßmus {
28915a1d355fSStephan Aßmus // prepare the request
28925a1d355fSStephan Aßmus WalkRequest request;
28935a1d355fSStephan Aßmus request.volumeID = fID;
28945a1d355fSStephan Aßmus request.nodeID = remoteDirID;
28955a1d355fSStephan Aßmus request.name.SetTo(entryName);
28965a1d355fSStephan Aßmus request.resolveLink = resolveLink;
28975a1d355fSStephan Aßmus
28985a1d355fSStephan Aßmus // send the request
28995a1d355fSStephan Aßmus WalkReply* reply;
29005a1d355fSStephan Aßmus status_t error = SendRequest(fConnection, &request, &reply);
29015a1d355fSStephan Aßmus if (error != B_OK)
29025a1d355fSStephan Aßmus RETURN_ERROR(error);
29035a1d355fSStephan Aßmus ObjectDeleter<Request> replyDeleter(reply);
29045a1d355fSStephan Aßmus if (reply->error != B_OK)
29055a1d355fSStephan Aßmus RETURN_ERROR(reply->error);
29065a1d355fSStephan Aßmus
29075a1d355fSStephan Aßmus replyDeleter.Detach();
29085a1d355fSStephan Aßmus *_reply = reply;
29095a1d355fSStephan Aßmus return B_OK;
29105a1d355fSStephan Aßmus }
29115a1d355fSStephan Aßmus
29125a1d355fSStephan Aßmus // _MultiWalk
29135a1d355fSStephan Aßmus status_t
_MultiWalk(RequestMemberArray<EntryInfo> & _entryInfos,MultiWalkReply ** _reply)29145a1d355fSStephan Aßmus ShareVolume::_MultiWalk(RequestMemberArray<EntryInfo>& _entryInfos,
29155a1d355fSStephan Aßmus MultiWalkReply** _reply)
29165a1d355fSStephan Aßmus {
29175a1d355fSStephan Aßmus int32 count = _entryInfos.CountElements();
29185a1d355fSStephan Aßmus if (!_reply || count == 0)
29195a1d355fSStephan Aßmus return B_BAD_VALUE;
29205a1d355fSStephan Aßmus
29215a1d355fSStephan Aßmus EntryInfo* entryInfos = _entryInfos.GetElements();
29225a1d355fSStephan Aßmus
29235a1d355fSStephan Aßmus // prepare the request
29245a1d355fSStephan Aßmus MultiWalkRequest request;
29255a1d355fSStephan Aßmus request.volumeID = fID;
29265a1d355fSStephan Aßmus request.nodeID = entryInfos[0].directoryID;
29275a1d355fSStephan Aßmus
29285a1d355fSStephan Aßmus // add the names
29295a1d355fSStephan Aßmus for (int32 i = 0; i < count; i++) {
29305a1d355fSStephan Aßmus StringData name;
29315a1d355fSStephan Aßmus name.SetTo(entryInfos[i].name.GetString());
29325a1d355fSStephan Aßmus
29335a1d355fSStephan Aßmus status_t error = request.names.Append(name);
29345a1d355fSStephan Aßmus if (error != B_OK)
29355a1d355fSStephan Aßmus return error;
29365a1d355fSStephan Aßmus }
29375a1d355fSStephan Aßmus
29385a1d355fSStephan Aßmus // send the request
29395a1d355fSStephan Aßmus MultiWalkReply* reply;
29405a1d355fSStephan Aßmus status_t error = SendRequest(fConnection, &request, &reply);
29415a1d355fSStephan Aßmus if (error != B_OK)
29425a1d355fSStephan Aßmus RETURN_ERROR(error);
29435a1d355fSStephan Aßmus ObjectDeleter<Request> replyDeleter(reply);
29445a1d355fSStephan Aßmus if (reply->error != B_OK)
29455a1d355fSStephan Aßmus RETURN_ERROR(reply->error);
29465a1d355fSStephan Aßmus
29475a1d355fSStephan Aßmus replyDeleter.Detach();
29485a1d355fSStephan Aßmus *_reply = reply;
29495a1d355fSStephan Aßmus return B_OK;
29505a1d355fSStephan Aßmus }
29515a1d355fSStephan Aßmus
29525a1d355fSStephan Aßmus // _Close
29535a1d355fSStephan Aßmus status_t
_Close(intptr_t cookie)295459ecfa6cSAugustin Cavalier ShareVolume::_Close(intptr_t cookie)
29555a1d355fSStephan Aßmus {
29565a1d355fSStephan Aßmus if (!_EnsureShareMounted())
29575a1d355fSStephan Aßmus return ERROR_NOT_CONNECTED;
29585a1d355fSStephan Aßmus
29595a1d355fSStephan Aßmus // prepare the request
29605a1d355fSStephan Aßmus CloseRequest request;
29615a1d355fSStephan Aßmus request.volumeID = fID;
29625a1d355fSStephan Aßmus request.cookie = cookie;
29635a1d355fSStephan Aßmus // send the request
29645a1d355fSStephan Aßmus CloseReply* reply;
29655a1d355fSStephan Aßmus status_t error = SendRequest(fConnection, &request, &reply);
29665a1d355fSStephan Aßmus if (error != B_OK)
29675a1d355fSStephan Aßmus RETURN_ERROR(error);
29685a1d355fSStephan Aßmus ObjectDeleter<Request> replyDeleter(reply);
29695a1d355fSStephan Aßmus if (reply->error != B_OK)
29705a1d355fSStephan Aßmus RETURN_ERROR(reply->error);
29715a1d355fSStephan Aßmus return B_OK;
29725a1d355fSStephan Aßmus }
29735a1d355fSStephan Aßmus
29745a1d355fSStephan Aßmus // _GetConnectionState
29755a1d355fSStephan Aßmus //
29765a1d355fSStephan Aßmus // Must not be called with fLock being held!
29775a1d355fSStephan Aßmus uint32
_GetConnectionState()29785a1d355fSStephan Aßmus ShareVolume::_GetConnectionState()
29795a1d355fSStephan Aßmus {
29805a1d355fSStephan Aßmus AutoLocker<Locker> _(fMountLock);
29815a1d355fSStephan Aßmus return fConnectionState;
29825a1d355fSStephan Aßmus }
29835a1d355fSStephan Aßmus
29845a1d355fSStephan Aßmus // _IsConnected
29855a1d355fSStephan Aßmus //
29865a1d355fSStephan Aßmus // Must not be called with fLock being held!
29875a1d355fSStephan Aßmus bool
_IsConnected()29885a1d355fSStephan Aßmus ShareVolume::_IsConnected()
29895a1d355fSStephan Aßmus {
29905a1d355fSStephan Aßmus return (_GetConnectionState() == CONNECTION_READY);
29915a1d355fSStephan Aßmus }
29925a1d355fSStephan Aßmus
29935a1d355fSStephan Aßmus // _EnsureShareMounted
29945a1d355fSStephan Aßmus //
29955a1d355fSStephan Aßmus // Must not be called with fLock being held!
29965a1d355fSStephan Aßmus bool
_EnsureShareMounted()29975a1d355fSStephan Aßmus ShareVolume::_EnsureShareMounted()
29985a1d355fSStephan Aßmus {
29995a1d355fSStephan Aßmus AutoLocker<Locker> _(fMountLock);
30005a1d355fSStephan Aßmus if (fConnectionState == CONNECTION_NOT_INITIALIZED)
30015a1d355fSStephan Aßmus _MountShare();
30025a1d355fSStephan Aßmus
30035a1d355fSStephan Aßmus return (fConnectionState == CONNECTION_READY);
30045a1d355fSStephan Aßmus }
30055a1d355fSStephan Aßmus
30065a1d355fSStephan Aßmus // _MountShare
30075a1d355fSStephan Aßmus //
30085a1d355fSStephan Aßmus // fMountLock must be held.
30095a1d355fSStephan Aßmus status_t
_MountShare()30105a1d355fSStephan Aßmus ShareVolume::_MountShare()
30115a1d355fSStephan Aßmus {
30125a1d355fSStephan Aßmus // get references to the server and share info
30135a1d355fSStephan Aßmus AutoLocker<Locker> locker(fLock);
301488e38c17SIngo Weinhold BReference<ExtendedServerInfo> serverInfoReference(fServerInfo);
301588e38c17SIngo Weinhold BReference<ExtendedShareInfo> shareInfoReference(fShareInfo);
30165a1d355fSStephan Aßmus ExtendedServerInfo* serverInfo = fServerInfo;
30175a1d355fSStephan Aßmus ExtendedShareInfo* shareInfo = fShareInfo;
30185a1d355fSStephan Aßmus locker.Unlock();
30195a1d355fSStephan Aßmus
30205a1d355fSStephan Aßmus // get server address as string
30215a1d355fSStephan Aßmus HashString serverAddressString;
30225a1d355fSStephan Aßmus status_t error = serverInfo->GetAddress().GetString(&serverAddressString,
30235a1d355fSStephan Aßmus false);
30245a1d355fSStephan Aßmus if (error != B_OK)
30255a1d355fSStephan Aßmus return error;
30265a1d355fSStephan Aßmus const char* server = serverAddressString.GetString();
30275a1d355fSStephan Aßmus
30285a1d355fSStephan Aßmus // get the server name
30295a1d355fSStephan Aßmus const char* serverName = serverInfo->GetServerName();
30305a1d355fSStephan Aßmus if (serverName && strlen(serverName) == 0)
30315a1d355fSStephan Aßmus serverName = NULL;
30325a1d355fSStephan Aßmus
30335a1d355fSStephan Aßmus // get the share name
30345a1d355fSStephan Aßmus const char* share = shareInfo->GetShareName();
30355a1d355fSStephan Aßmus
30363c1afd35SPawel Dziepak PRINT("ShareVolume::_MountShare(%s, %s)\n", server, share);
30375a1d355fSStephan Aßmus // init a connection to the authentication server
30385a1d355fSStephan Aßmus AuthenticationServer authenticationServer;
30395a1d355fSStephan Aßmus error = authenticationServer.InitCheck();
30405a1d355fSStephan Aßmus if (error != B_OK)
30415a1d355fSStephan Aßmus RETURN_ERROR(error);
30425a1d355fSStephan Aßmus
30435a1d355fSStephan Aßmus // get the server connection
30445a1d355fSStephan Aßmus fConnectionState = CONNECTION_CLOSED;
30455a1d355fSStephan Aßmus if (!fServerConnection) {
30465a1d355fSStephan Aßmus status_t error = fServerConnectionProvider->GetServerConnection(
30475a1d355fSStephan Aßmus &fServerConnection);
30485a1d355fSStephan Aßmus if (error != B_OK)
30495a1d355fSStephan Aßmus return error;
30505a1d355fSStephan Aßmus fConnection = fServerConnection->GetRequestConnection();
30515a1d355fSStephan Aßmus }
30525a1d355fSStephan Aßmus
30535a1d355fSStephan Aßmus // the mount loop
30545a1d355fSStephan Aßmus bool badPassword = false;
30555a1d355fSStephan Aßmus MountReply* reply = NULL;
30565a1d355fSStephan Aßmus do {
30575a1d355fSStephan Aßmus // get the user and password from the authentication server
30585a1d355fSStephan Aßmus char user[kUserBufferSize];
30595a1d355fSStephan Aßmus char password[kPasswordBufferSize];
30605a1d355fSStephan Aßmus bool cancelled;
30615a1d355fSStephan Aßmus error = authenticationServer.GetAuthentication("netfs",
30625a1d355fSStephan Aßmus (serverName ? serverName : server), share,
30635a1d355fSStephan Aßmus fVolumeManager->GetMountUID(), badPassword,
30645a1d355fSStephan Aßmus &cancelled, user, sizeof(user), password, sizeof(password));
30655a1d355fSStephan Aßmus if (cancelled || error != B_OK)
30665a1d355fSStephan Aßmus RETURN_ERROR(error);
30675a1d355fSStephan Aßmus
30685a1d355fSStephan Aßmus // prepare the request
30695a1d355fSStephan Aßmus MountRequest request;
30705a1d355fSStephan Aßmus request.share.SetTo(share);
30715a1d355fSStephan Aßmus request.user.SetTo(user);
30725a1d355fSStephan Aßmus request.password.SetTo(password);
30735a1d355fSStephan Aßmus
30745a1d355fSStephan Aßmus // send the request
30755a1d355fSStephan Aßmus error = SendRequest(fConnection, &request, &reply);
30765a1d355fSStephan Aßmus if (error != B_OK)
30775a1d355fSStephan Aßmus RETURN_ERROR(error);
30785a1d355fSStephan Aßmus ObjectDeleter<Request> replyDeleter(reply);
30795a1d355fSStephan Aßmus
30805a1d355fSStephan Aßmus // if no permission, try again
30815a1d355fSStephan Aßmus badPassword = reply->noPermission;
30825a1d355fSStephan Aßmus if (!badPassword) {
30835a1d355fSStephan Aßmus if (reply->error != B_OK)
30845a1d355fSStephan Aßmus RETURN_ERROR(reply->error);
30855a1d355fSStephan Aßmus fSharePermissions = reply->sharePermissions;
30865a1d355fSStephan Aßmus }
30875a1d355fSStephan Aßmus } while (badPassword);
30885a1d355fSStephan Aßmus
30895a1d355fSStephan Aßmus AutoLocker<Locker> _(fLock);
30905a1d355fSStephan Aßmus
30915a1d355fSStephan Aßmus fID = reply->volumeID;
30925a1d355fSStephan Aßmus
30935a1d355fSStephan Aßmus // update the root node and enter its ID
30945a1d355fSStephan Aßmus fRootNode->Update(reply->nodeInfo);
30955a1d355fSStephan Aßmus
30965a1d355fSStephan Aßmus // put the IDs into local map
30975a1d355fSStephan Aßmus error = fLocalNodeIDs->Put(fRootNode->GetRemoteID(), fRootNode->GetID());
30985a1d355fSStephan Aßmus if (error != B_OK)
30995a1d355fSStephan Aßmus RETURN_ERROR(error);
31005a1d355fSStephan Aßmus
31015a1d355fSStephan Aßmus // put the IDs into remote map
31025a1d355fSStephan Aßmus error = fRemoteNodeIDs->Put(fRootNode->GetID(), fRootNode->GetRemoteID());
31035a1d355fSStephan Aßmus if (error != B_OK) {
31045a1d355fSStephan Aßmus fLocalNodeIDs->Remove(fRootNode->GetRemoteID());
31055a1d355fSStephan Aßmus RETURN_ERROR(error);
31065a1d355fSStephan Aßmus }
31074cfa5b2dSJérôme Duval PRINT("ShareVolume::_MountShare(): root node: local: %" B_PRIdINO
31084cfa5b2dSJérôme Duval ", remote: (%" B_PRIdDEV ", %" B_PRIdINO ")\n", fRootNode->GetID(),
31093c1afd35SPawel Dziepak fRootNode->GetRemoteID().volumeID,
31103c1afd35SPawel Dziepak fRootNode->GetRemoteID().nodeID);
31115a1d355fSStephan Aßmus
31125a1d355fSStephan Aßmus // Add ourselves to the server connection, so that we can receive
31135a1d355fSStephan Aßmus // node monitoring events. There a race condition: We might already
31145a1d355fSStephan Aßmus // have missed events for the root node.
31155a1d355fSStephan Aßmus error = fServerConnection->AddVolume(this);
31165a1d355fSStephan Aßmus if (error != B_OK) {
31175a1d355fSStephan Aßmus _RemoveLocalNodeID(fRootNode->GetID());
31185a1d355fSStephan Aßmus return error;
31195a1d355fSStephan Aßmus }
31205a1d355fSStephan Aßmus
31215a1d355fSStephan Aßmus fConnectionState = CONNECTION_READY;
31225a1d355fSStephan Aßmus return B_OK;
31235a1d355fSStephan Aßmus }
31245a1d355fSStephan Aßmus
3125