#include <new>
#include <AutoDeleter.h>
#include <AutoLocker.h>
#include <HashMap.h>
#include <Path.h>
#include "ClientVolume.h"
#include "DebugSupport.h"
#include "Directory.h"
#include "Entry.h"
#include "GlobalBlockerPool.h"
#include "NodeHandle.h"
#include "NodeHandleMap.h"
#include "NodeMonitoringEvent.h"
#include "SecurityContext.h"
#include "StatisticsManager.h"
#include "UserSecurityContext.h"
#include "Volume.h"
#include "VolumeManager.h"
ClientVolume::ClientVolume(Locker& securityContextLocker,
NodeMonitoringProcessor* nodeMonitoringProcessor)
: FSObject(),
fID(_NextVolumeID()),
fSecurityContext(NULL),
fSecurityContextLock(securityContextLocker),
fNodeMonitoringProcessor(nodeMonitoringProcessor),
fNodeHandles(NULL),
fShare(NULL),
fRootNodeRef(),
fSharePermissions(),
fMounted(false)
{
}
ClientVolume::~ClientVolume()
{
Unmount();
if (fShare)
fShare->ReleaseReference();
delete fNodeHandles;
delete fSecurityContext;
}
status_t
ClientVolume::Init()
{
fNodeHandles = new(std::nothrow) NodeHandleMap("node handles");
if (!fNodeHandles)
return B_NO_MEMORY;
status_t error = fNodeHandles->Init();
if (error != B_OK)
return error;
return B_OK;
}
int32
ClientVolume::GetID() const
{
return fID;
}
status_t
ClientVolume::Mount(UserSecurityContext* securityContext, Share* share)
{
if (!securityContext || !share)
return B_BAD_VALUE;
ObjectDeleter<UserSecurityContext> securityContextDeleter(securityContext);
if (IsMounted())
return B_BAD_VALUE;
fSecurityContext = securityContext;
securityContextDeleter.Detach();
fShare = share;
fShare->AcquireReference();
dev_t volumeID = share->GetVolumeID();
ino_t nodeID = share->GetNodeID();
fRootNodeRef.device = volumeID;
fRootNodeRef.node = nodeID;
fSharePermissions = securityContext->GetNodePermissions(volumeID, nodeID);
VolumeManager* volumeManager = VolumeManager::GetDefault();
Directory* rootDir;
status_t error = volumeManager->LoadDirectory(volumeID, nodeID, &rootDir);
if (error != B_OK)
return error;
error = volumeManager->AddClientVolume(this);
if (error != B_OK) {
Unmount();
return error;
}
fMounted = true;
StatisticsManager::GetDefault()->ShareMounted(fShare,
fSecurityContext->GetUser());
return B_OK;
}
void
ClientVolume::Unmount()
{
PRINT(("ClientVolume::Unmount()\n"));
if (fMounted) {
fMounted = false;
StatisticsManager::GetDefault()->ShareUnmounted(fShare,
fSecurityContext->GetUser());
}
VolumeManager::GetDefault()->RemoveClientVolume(this);
}
bool
ClientVolume::IsMounted() const
{
return fMounted;
}
UserSecurityContext*
ClientVolume::GetSecurityContext() const
{
return fSecurityContext;
}
void
ClientVolume::SetSecurityContext(UserSecurityContext* securityContext)
{
AutoLocker<Locker> locker(fSecurityContextLock);
delete fSecurityContext;
fSecurityContext = securityContext;
fSharePermissions = fSecurityContext->GetNodePermissions(fRootNodeRef);
}
Share*
ClientVolume::GetShare() const
{
return fShare;
}
Directory*
ClientVolume::GetRootDirectory() const
{
return VolumeManager::GetDefault()->GetDirectory(
fRootNodeRef.device, fRootNodeRef.node);
}
const NodeRef&
ClientVolume::GetRootNodeRef() const
{
return fRootNodeRef;
}
Permissions
ClientVolume::GetSharePermissions() const
{
return fSharePermissions;
}
Permissions
ClientVolume::GetNodePermissions(dev_t volumeID, ino_t nodeID)
{
return fSharePermissions;
}
Permissions
ClientVolume::GetNodePermissions(Node* node)
{
return fSharePermissions;
}
Node*
ClientVolume::GetNode(dev_t volumeID, ino_t nodeID)
{
VolumeManager* volumeManager = VolumeManager::GetDefault();
Node* node = volumeManager->GetNode(volumeID, nodeID);
if (!node)
return NULL;
if (volumeManager->DirectoryContains(GetRootDirectory(), node, true))
return node;
return NULL;
}
Node*
ClientVolume::GetNode(NodeID nodeID)
{
return GetNode(nodeID.volumeID, nodeID.nodeID);
}
Node*
ClientVolume::GetNode(const node_ref& nodeRef)
{
return GetNode(nodeRef.device, nodeRef.node);
}
Directory*
ClientVolume::GetDirectory(dev_t volumeID, ino_t nodeID)
{
VolumeManager* volumeManager = VolumeManager::GetDefault();
Directory* dir = GetDirectory(volumeID, nodeID);
if (!dir)
return NULL;
if (volumeManager->DirectoryContains(GetRootDirectory(), dir, true))
return dir;
return NULL;
}
Directory*
ClientVolume::GetDirectory(NodeID nodeID)
{
return GetDirectory(nodeID.volumeID, nodeID.nodeID);
}
status_t
ClientVolume::LoadDirectory(dev_t volumeID, ino_t nodeID,
Directory** _directory)
{
if (!_directory)
return B_BAD_VALUE;
VolumeManager* volumeManager = VolumeManager::GetDefault();
Directory* dir;
status_t error = volumeManager->LoadDirectory(volumeID, nodeID, &dir);
if (error != B_OK)
return error;
if (!volumeManager->DirectoryContains(GetRootDirectory(), dir, true))
return B_ENTRY_NOT_FOUND;
*_directory = dir;
return B_OK;
}
Entry*
ClientVolume::GetEntry(dev_t volumeID, ino_t dirID, const char* name)
{
VolumeManager* volumeManager = VolumeManager::GetDefault();
Entry* entry = volumeManager->GetEntry(volumeID, dirID, name);
if (!entry)
return NULL;
if (volumeManager->DirectoryContains(GetRootDirectory(), entry))
return entry;
return NULL;
}
Entry*
ClientVolume::GetEntry(Directory* directory, const char* name)
{
if (!directory)
return NULL;
return GetEntry(directory->GetVolumeID(), directory->GetID(), name);
}
status_t
ClientVolume::LoadEntry(dev_t volumeID, ino_t dirID, const char* name,
Entry** _entry)
{
if (!name || !_entry)
return B_BAD_VALUE;
VolumeManager* volumeManager = VolumeManager::GetDefault();
Entry* entry;
status_t error = VolumeManager::GetDefault()->LoadEntry(volumeID, dirID,
name, true, &entry);
if (error != B_OK)
return error;
if (!volumeManager->DirectoryContains(GetRootDirectory(), entry))
return B_ENTRY_NOT_FOUND;
*_entry = entry;
return B_OK;
}
status_t
ClientVolume::LoadEntry(Directory* directory, const char* name, Entry** entry)
{
if (!directory)
return B_BAD_VALUE;
return LoadEntry(directory->GetVolumeID(), directory->GetID(), name, entry);
}
status_t
ClientVolume::Open(Node* node, int openMode, FileHandle** _handle)
{
if (!node || !_handle)
return B_BAD_VALUE;
FileHandle* handle = NULL;
status_t error = node->Open(openMode, &handle);
if (error != B_OK)
return error;
BReference<NodeHandle> handleReference(handle, true);
handle->Lock();
error = fNodeHandles->AddNodeHandle(handle);
if (error != B_OK)
return error;
handleReference.Detach();
*_handle = handle;
return B_OK;
}
status_t
ClientVolume::OpenDir(Directory* directory, DirIterator** _iterator)
{
if (!directory || !_iterator)
return B_BAD_VALUE;
DirIterator* iterator = NULL;
status_t error = directory->OpenDir(&iterator);
if (error != B_OK)
return error;
BReference<NodeHandle> handleReference(iterator, true);
iterator->Lock();
error = fNodeHandles->AddNodeHandle(iterator);
if (error != B_OK)
return error;
handleReference.Detach();
*_iterator = iterator;
return B_OK;
}
status_t
ClientVolume::OpenAttrDir(Node* node, AttrDirIterator** _iterator)
{
if (!node || !_iterator)
return B_BAD_VALUE;
AttrDirIterator* iterator = NULL;
status_t error = node->OpenAttrDir(&iterator);
if (error != B_OK)
return error;
BReference<NodeHandle> handleReference(iterator, true);
iterator->Lock();
error = fNodeHandles->AddNodeHandle(iterator);
if (error != B_OK)
return error;
handleReference.Detach();
*_iterator = iterator;
return B_OK;
}
status_t
ClientVolume::Close(NodeHandle* handle)
{
if (!handle || !fNodeHandles->RemoveNodeHandle(handle))
return B_BAD_VALUE;
return B_OK;
}
status_t
ClientVolume::LockNodeHandle(int32 cookie, NodeHandle** _handle)
{
return fNodeHandles->LockNodeHandle(cookie, _handle);
}
void
ClientVolume::UnlockNodeHandle(NodeHandle* nodeHandle)
{
fNodeHandles->UnlockNodeHandle(nodeHandle);
}
void
ClientVolume::ProcessNodeMonitoringEvent(NodeMonitoringEvent* event)
{
if (fNodeMonitoringProcessor)
fNodeMonitoringProcessor->ProcessNodeMonitoringEvent(fID, event);
}
int32
ClientVolume::_NextVolumeID()
{
return atomic_add(&sNextVolumeID, 1);
}
int32 ClientVolume::sNextVolumeID = 0;
ClientVolume::NodeMonitoringProcessor::~NodeMonitoringProcessor()
{
}