⛏️ index : haiku.git

// NodeHandle.cpp

#include "NodeHandle.h"

#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

#include <fs_attr.h>

#include "Compatibility.h"
#include "Directory.h"
#include "FDManager.h"
#include "Path.h"

// TODO: Do the FD creation via the FDManager.

// NodeHandle

// constructor
NodeHandle::NodeHandle()
	: BReferenceable(),
	  Lockable(),
	  fCookie(-1),
	  fNodeRef()
{
}

// destructor
NodeHandle::~NodeHandle()
{
}

// GetStat
status_t
NodeHandle::GetStat(struct stat* st)
{
	int fd = GetFD();
	if (fd < 0)
		return B_ENTRY_NOT_FOUND;

	if (fstat(fd, st) < 0)
		return errno;

	return B_OK;
}

// SetCookie
void
NodeHandle::SetCookie(int32 cookie)
{
	fCookie = cookie;
}

// GetCookie
int32
NodeHandle::GetCookie() const
{
	return fCookie;
}

// GetNodeRef
const NodeRef&
NodeHandle::GetNodeRef() const
{
	return fNodeRef;
}

// GetFD
int
NodeHandle::GetFD() const
{
	return -1;
}


// #pragma mark -

// FileHandle

// constructor
FileHandle::FileHandle()
	: fFD(-1)
{
}

// destructor
FileHandle::~FileHandle()
{
	Close();
}

// Open
status_t
FileHandle::Open(Node* node, int openMode)
{
	if (!node)
		return B_BAD_VALUE;

	openMode &= O_RWMASK | O_TRUNC | O_APPEND;

	// get a path
	Path path;
	status_t error = node->GetPath(&path);
	if (error != B_OK)
		return error;

	// open the file
	error = FDManager::Open(path.GetPath(), openMode | O_NOTRAVERSE, 0, fFD);
	if (error != B_OK)
		return error;

	fNodeRef = node->GetNodeRef();

	return B_OK;
}

// Close
status_t
FileHandle::Close()
{
	if (fFD < 0)
		return B_BAD_VALUE;

	status_t error = B_OK;
	if (close(fFD) < 0)
		error = errno;
	fFD = -1;

	return error;
}

// Read
status_t
FileHandle::Read(off_t pos, void* buffer, size_t size, size_t* _bytesRead)
{
	if (fFD < 0)
		return B_BAD_VALUE;

	ssize_t bytesRead = read_pos(fFD, pos, buffer, size);
	if (bytesRead < 0)
		return errno;

	*_bytesRead = bytesRead;
	return B_OK;
}

// Write
status_t
FileHandle::Write(off_t pos, const void* buffer, size_t size,
	size_t* _bytesWritten)
{
	if (fFD < 0)
		return B_BAD_VALUE;

	ssize_t bytesWritten = write_pos(fFD, pos, buffer, size);
	if (bytesWritten < 0)
		return errno;

	*_bytesWritten = bytesWritten;
	return B_OK;
}

// ReadAttr
status_t
FileHandle::ReadAttr(const char* name, uint32 type, off_t pos, void* buffer,
	size_t size, size_t* _bytesRead)
{
	if (fFD < 0)
		return B_BAD_VALUE;

	ssize_t bytesRead = fs_read_attr(fFD, name, type, pos, buffer, size);
	if (bytesRead < 0)
		return errno;

	*_bytesRead = bytesRead;
	return B_OK;
}

// WriteAttr
status_t
FileHandle::WriteAttr(const char* name, uint32 type, off_t pos,
	const void* buffer, size_t size, size_t* _bytesWritten)
{
	if (fFD < 0)
		return B_BAD_VALUE;

	ssize_t bytesWritten = fs_write_attr(fFD, name, type, pos, buffer, size);
	if (bytesWritten < 0)
		return errno;

	*_bytesWritten = bytesWritten;
	return B_OK;
}

// RemoveAttr
status_t
FileHandle::RemoveAttr(const char* name)
{
	if (fFD < 0)
		return B_BAD_VALUE;

	return (fs_remove_attr(fFD, name) == 0 ? B_OK : errno);
}

// StatAttr
status_t
FileHandle::StatAttr(const char* name, attr_info* info)
{
	if (fFD < 0)
		return B_BAD_VALUE;

	return (fs_stat_attr(fFD, name, info) == 0 ? B_OK : errno);
}

// GetFD
int
FileHandle::GetFD() const
{
	return fFD;
}


// #pragma mark -

// DirIterator

// constructor
DirIterator::DirIterator()
	: fDirectory(NULL)
{
}

// destructor
DirIterator::~DirIterator()
{
	if (fDirectory)
		fDirectory->RemoveDirIterator(this);
}

// IsValid
bool
DirIterator::IsValid() const
{
	return fDirectory;
}


// #pragma mark -

// AttrDirIterator

// constructor
AttrDirIterator::AttrDirIterator()
	: NodeHandle(),
	  fDir(NULL)
{
}

// destructor
AttrDirIterator::~AttrDirIterator()
{
	Close();
}

// Open
status_t
AttrDirIterator::Open(Node* node)
{
	if (!node)
		return B_BAD_VALUE;

	// get a path
	Path path;
	status_t error = node->GetPath(&path);
	if (error != B_OK)
		return error;

	// open the attribute directory
	error = FDManager::OpenAttrDir(path.GetPath(), fDir);
	if (error != B_OK)
		return errno;

	fNodeRef = node->GetNodeRef();

	return B_OK;
}

// Close
status_t
AttrDirIterator::Close()
{
	if (!fDir)
		return B_BAD_VALUE;

	status_t error = B_OK;
	if (fs_close_attr_dir(fDir) < 0)
		error = errno;

	fDir = NULL;
	return error;
}

// ReadDir
status_t
AttrDirIterator::ReadDir(dirent* _entry, int32 bufferSize,
	int32 count, int32* countRead, bool* done)
{
// TODO: Burst read.
	if (!fDir)
		return B_ENTRY_NOT_FOUND;

	*countRead = 0;
	*done = false;

	if (count == 0)
		return B_OK;

	if (struct dirent* entry = fs_read_attr_dir(fDir)) {
		size_t entryLen = entry->d_name + strlen(entry->d_name) + 1
			- (char*)entry;
		memcpy(_entry, entry, entryLen);
		*countRead = 1;
	} else {
		*countRead = 0;
		*done = true;
	}
	return B_OK;
}

// RewindDir
status_t
AttrDirIterator::RewindDir()
{
	if (!fDir)
		return B_ENTRY_NOT_FOUND;

	fs_rewind_attr_dir(fDir);

	return B_OK;
}

// GetFD
int
AttrDirIterator::GetFD() const
{
	return dirfd(fDir);
}


// #pragma mark -

// QueryListener

// constructor
QueryListener::QueryListener()
{
}

// destructor
QueryListener::~QueryListener()
{
}


// #pragma mark -

// QueryHandle

// constructor
QueryHandle::QueryHandle(port_id remotePort, int32 remoteToken)
	: NodeHandle(),
	  fRemotePort(remotePort),
	  fRemoteToken(remoteToken),
	  fQueries(),
	  fCurrentQuery(NULL),
	  fListener(NULL),
	  fClosed(false)
{
}

// destructor
QueryHandle::~QueryHandle()
{
	Close();
}

// SetQueryListener
void
QueryHandle::SetQueryListener(QueryListener* listener)
{
	fListener = listener;
}

// GetQueryListener
QueryListener*
QueryHandle::GetQueryListener() const
{
	return fListener;
}

// AddQuery
void
QueryHandle::AddQuery(Query* query)
{
	if (query) {
		fQueries.Insert(query);
		if (!fCurrentQuery)
			fCurrentQuery = query;
	}
}

// RemoveQuery
void
QueryHandle::RemoveQuery(Query* query)
{
	if (query) {
		if (query == fCurrentQuery)
			fCurrentQuery = fQueries.GetNext(query);
		fQueries.Remove(query);
	}
}

// GetRemotePort
port_id
QueryHandle::GetRemotePort() const
{
	return fRemotePort;
}

// GetRemoteToken
int32
QueryHandle::GetRemoteToken() const
{
	return fRemoteToken;
}

// Close
status_t
QueryHandle::Close()
{
	if (fClosed)
		return B_OK;

	fCurrentQuery = NULL;

	// delete all queries
	for (DoublyLinkedList<Query>::Iterator it = fQueries.GetIterator();
			it.HasNext();) {
		Query* query = it.Next();
		it.Remove();
		delete query;
	}

	fClosed = true;

	if (fListener)
		fListener->QueryHandleClosed(this);

	return B_OK;
}

// ReadDir
status_t
QueryHandle::ReadDir(dirent* entry, int32 count, int32* countRead)
{
	if (count == 0) {
		*countRead = 0;
		return B_OK;
	}
	while (fCurrentQuery) {
		int32 readEntries = fCurrentQuery->GetNextDirents(entry,
			offsetof(struct dirent, d_name) + B_FILE_NAME_LENGTH, 1);
		if (readEntries < 0)
			return readEntries;
		if (readEntries > 0) {
			*countRead = 1;
			return B_OK;
		}
		fCurrentQuery = fQueries.GetNext(fCurrentQuery);
	}
	*countRead = 0;
	return B_OK;
}