#include <Node.h>
#include <errno.h>
#include <fcntl.h>
#include <new>
#include <string.h>
#include <unistd.h>
#include <Directory.h>
#include <Entry.h>
#include <fs_attr.h>
#include <String.h>
#include <TypeConstants.h>
#include <syscalls.h>
#include "storage_support.h"
node_ref::node_ref()
:
device((dev_t)-1),
node((ino_t)-1)
{
}
node_ref::node_ref(const node_ref& other)
:
device((dev_t)-1),
node((ino_t)-1)
{
*this = other;
}
bool
node_ref::operator==(const node_ref& other) const
{
return (device == other.device && node == other.node);
}
bool
node_ref::operator!=(const node_ref& other) const
{
return !(*this == other);
}
bool
node_ref::operator<(const node_ref& other) const
{
if (this->device != other.device)
return this->device < other.device;
return this->node < other.node;
}
node_ref&
node_ref::operator=(const node_ref& other)
{
device = other.device;
node = other.node;
return *this;
}
BNode::BNode()
:
fFd(-1),
fAttrFd(-1),
fCStatus(B_NO_INIT)
{
}
BNode::BNode(const entry_ref* ref)
:
fFd(-1),
fAttrFd(-1),
fCStatus(B_NO_INIT)
{
(void)SetTo(ref);
}
BNode::BNode(const BEntry* entry)
:
fFd(-1),
fAttrFd(-1),
fCStatus(B_NO_INIT)
{
(void)SetTo(entry);
}
BNode::BNode(const char* path)
:
fFd(-1),
fAttrFd(-1),
fCStatus(B_NO_INIT)
{
(void)SetTo(path);
}
BNode::BNode(const BDirectory* dir, const char* path)
:
fFd(-1),
fAttrFd(-1),
fCStatus(B_NO_INIT)
{
(void)SetTo(dir, path);
}
BNode::BNode(const BNode& node)
:
fFd(-1),
fAttrFd(-1),
fCStatus(B_NO_INIT)
{
*this = node;
}
BNode::~BNode()
{
Unset();
}
status_t
BNode::InitCheck() const
{
return fCStatus;
}
status_t
BNode::SetTo(const entry_ref* ref)
{
return _SetTo(ref, false);
}
status_t
BNode::SetTo(const BEntry* entry)
{
if (entry == NULL) {
Unset();
return (fCStatus = B_BAD_VALUE);
}
return _SetTo(entry->fDirFd, entry->fName, false);
}
status_t
BNode::SetTo(const char* path)
{
return _SetTo(-1, path, false);
}
status_t
BNode::SetTo(const BDirectory* dir, const char* path)
{
if (dir == NULL || path == NULL
|| BPrivate::Storage::is_absolute_path(path)) {
Unset();
return (fCStatus = B_BAD_VALUE);
}
return _SetTo(dir->fDirFd, path, false);
}
void
BNode::Unset()
{
close_fd();
fCStatus = B_NO_INIT;
}
status_t
BNode::Lock()
{
if (fCStatus != B_OK)
return fCStatus;
return _kern_lock_node(fFd);
}
status_t
BNode::Unlock()
{
if (fCStatus != B_OK)
return fCStatus;
return _kern_unlock_node(fFd);
}
status_t
BNode::Sync()
{
return (fCStatus != B_OK) ? B_FILE_ERROR : _kern_fsync(fFd, false);
}
ssize_t
BNode::WriteAttr(const char* attr, type_code type, off_t offset,
const void* buffer, size_t length)
{
if (fCStatus != B_OK)
return B_FILE_ERROR;
if (attr == NULL || buffer == NULL)
return B_BAD_VALUE;
ssize_t result = fs_write_attr(fFd, attr, type, offset, buffer, length);
return result < 0 ? errno : result;
}
ssize_t
BNode::ReadAttr(const char* attr, type_code type, off_t offset,
void* buffer, size_t length) const
{
if (fCStatus != B_OK)
return B_FILE_ERROR;
if (attr == NULL || buffer == NULL)
return B_BAD_VALUE;
ssize_t result = fs_read_attr(fFd, attr, type, offset, buffer, length);
return result == -1 ? errno : result;
}
status_t
BNode::RemoveAttr(const char* name)
{
return fCStatus != B_OK ? B_FILE_ERROR : _kern_remove_attr(fFd, name);
}
status_t
BNode::RenameAttr(const char* oldName, const char* newName)
{
if (fCStatus != B_OK)
return B_FILE_ERROR;
return _kern_rename_attr(fFd, oldName, fFd, newName);
}
status_t
BNode::GetAttrInfo(const char* name, struct attr_info* info) const
{
if (fCStatus != B_OK)
return B_FILE_ERROR;
if (name == NULL || info == NULL)
return B_BAD_VALUE;
return fs_stat_attr(fFd, name, info) < 0 ? errno : B_OK ;
}
status_t
BNode::GetNextAttrName(char* buffer)
{
if (buffer == NULL)
return B_BAD_VALUE;
if (InitAttrDir() != B_OK)
return B_FILE_ERROR;
BPrivate::Storage::LongDirEntry longEntry;
struct dirent* entry = longEntry.dirent();
ssize_t result = _kern_read_dir(fAttrFd, entry, sizeof(longEntry), 1);
if (result < 0)
return result;
if (result == 0)
return B_ENTRY_NOT_FOUND;
strlcpy(buffer, entry->d_name, B_ATTR_NAME_LENGTH);
return B_OK;
}
status_t
BNode::RewindAttrs()
{
if (InitAttrDir() != B_OK)
return B_FILE_ERROR;
return _kern_rewind_dir(fAttrFd);
}
status_t
BNode::WriteAttrString(const char* name, const BString* data)
{
status_t error = (!name || !data) ? B_BAD_VALUE : B_OK;
if (error == B_OK) {
int32 length = data->Length() + 1;
ssize_t sizeWritten = WriteAttr(name, B_STRING_TYPE, 0, data->String(),
length);
if (sizeWritten != length)
error = sizeWritten;
}
return error;
}
status_t
BNode::ReadAttrString(const char* name, BString* result) const
{
if (name == NULL || result == NULL)
return B_BAD_VALUE;
attr_info info;
status_t error;
error = GetAttrInfo(name, &info);
if (error != B_OK)
return error;
char* data = result->LockBuffer(info.size + 1);
if (data == NULL)
return B_NO_MEMORY;
ssize_t bytes = ReadAttr(name, B_STRING_TYPE, 0, data, info.size);
if (bytes < 0) {
error = bytes;
bytes = 0;
} else
error = B_OK;
data[bytes] = 0;
result->UnlockBuffer();
return error;
}
BNode&
BNode::operator=(const BNode& node)
{
if (*this == node)
return *this;
Unset();
fFd = _kern_dup(node.fFd);
fCStatus = (fFd < 0) ? B_NO_INIT : B_OK ;
return *this;
}
bool
BNode::operator==(const BNode& node) const
{
if (fCStatus == B_NO_INIT && node.InitCheck() == B_NO_INIT)
return true;
if (fCStatus == B_OK && node.InitCheck() == B_OK) {
node_ref ref1, ref2;
if (GetNodeRef(&ref1) != B_OK)
return false;
if (node.GetNodeRef(&ref2) != B_OK)
return false;
return (ref1 == ref2);
}
return false;
}
bool
BNode::operator!=(const BNode& node) const
{
return !(*this == node);
}
int
BNode::Dup()
{
int fd = _kern_dup(fFd);
return (fd >= 0 ? fd : -1);
}
void BNode::_RudeNode1() { }
void BNode::_RudeNode2() { }
void BNode::_RudeNode3() { }
void BNode::_RudeNode4() { }
void BNode::_RudeNode5() { }
void BNode::_RudeNode6() { }
status_t
BNode::set_fd(int fd)
{
if (fFd != -1)
close_fd();
fFd = fd;
return B_OK;
}
void
BNode::close_fd()
{
if (fAttrFd >= 0) {
_kern_close(fAttrFd);
fAttrFd = -1;
}
if (fFd >= 0) {
_kern_close(fFd);
fFd = -1;
}
}
void
BNode::set_status(status_t newStatus)
{
fCStatus = newStatus;
}
status_t
BNode::_SetTo(int fd, const char* path, bool traverse)
{
Unset();
status_t error = (fd >= 0 || path ? B_OK : B_BAD_VALUE);
if (error == B_OK) {
int traverseFlag = (traverse ? 0 : O_NOTRAVERSE);
fFd = _kern_open(fd, path, O_RDWR | O_CLOEXEC | traverseFlag, 0);
if (fFd < B_OK && fFd != B_ENTRY_NOT_FOUND) {
fFd = _kern_open(fd, path, O_RDONLY | O_CLOEXEC | traverseFlag, 0);
}
if (fFd < 0)
error = fFd;
}
return fCStatus = error;
}
status_t
BNode::_SetTo(const entry_ref* ref, bool traverse)
{
Unset();
status_t result = (ref ? B_OK : B_BAD_VALUE);
if (result == B_OK) {
int traverseFlag = (traverse ? 0 : O_NOTRAVERSE);
fFd = _kern_open_entry_ref(ref->device, ref->directory, ref->name,
O_RDWR | O_CLOEXEC | traverseFlag, 0);
if (fFd < B_OK && fFd != B_ENTRY_NOT_FOUND) {
fFd = _kern_open_entry_ref(ref->device, ref->directory, ref->name,
O_RDONLY | O_CLOEXEC | traverseFlag, 0);
}
if (fFd < 0)
result = fFd;
}
return fCStatus = result;
}
status_t
BNode::set_stat(struct stat& stat, uint32 what)
{
if (fCStatus != B_OK)
return B_FILE_ERROR;
return _kern_write_stat(fFd, NULL, false, &stat, sizeof(struct stat),
what);
}
status_t
BNode::InitAttrDir()
{
if (fCStatus == B_OK && fAttrFd < 0) {
fAttrFd = _kern_open_attr_dir(fFd, NULL);
if (fAttrFd < 0)
return fAttrFd;
fcntl(fAttrFd, F_SETFD, FD_CLOEXEC);
}
return fCStatus;
}
status_t
BNode::GetStat(struct stat* stat) const
{
return fCStatus != B_OK
? fCStatus
: _kern_read_stat(fFd, NULL, false, stat, sizeof(struct stat));
}