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