* Copyright 2004-2020, Axel DΓΆrfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License.
*/
#include "Attribute.h"
extern void fill_stat_buffer(Inode* inode, struct stat& stat);
Attribute::Attribute(Inode* inode)
:
fNodeGetter(inode->GetVolume()),
fInode(inode),
fSmall(NULL),
fAttribute(NULL),
fName(NULL)
{
}
Attribute::Attribute(Inode* inode, attr_cookie* cookie)
:
fNodeGetter(inode->GetVolume()),
fInode(inode),
fSmall(NULL),
fAttribute(NULL),
fName(NULL)
{
Get(cookie->name);
}
Attribute::~Attribute()
{
Put();
}
status_t
Attribute::InitCheck()
{
return (fSmall != NULL || fAttribute != NULL) ? B_OK : B_NO_INIT;
}
status_t
Attribute::CheckAccess(const char* name, int openMode)
{
if (name[0] == FILE_NAME_NAME && name[1] == '\0'
|| !strcmp(name, "last_modified")
|| !strcmp(name, "size")*/)
RETURN_ERROR(B_NOT_ALLOWED);
return fInode->CheckPermissions(open_mode_to_access(openMode)
| (openMode & O_TRUNC ? W_OK : 0));
}
status_t
Attribute::Get(const char* name)
{
Put();
fName = name;
if (recursive_lock_lock(&fInode->SmallDataLock()) == B_OK) {
status_t status = fNodeGetter.SetTo(fInode);
if (status != B_OK)
return status;
fSmall = fInode->FindSmallData(fNodeGetter.Node(), (const char*)name);
if (fSmall != NULL)
return B_OK;
recursive_lock_unlock(&fInode->SmallDataLock());
fNodeGetter.Unset();
}
return fInode->GetAttribute(name, &fAttribute);
}
void
Attribute::Put()
{
if (fSmall != NULL) {
recursive_lock_unlock(&fInode->SmallDataLock());
fNodeGetter.Unset();
fSmall = NULL;
}
if (fAttribute != NULL) {
fInode->ReleaseAttribute(fAttribute);
fAttribute = NULL;
}
}
status_t
Attribute::Create(const char* name, type_code type, int openMode,
attr_cookie** _cookie)
{
status_t status = CheckAccess(name, openMode);
if (status != B_OK)
return status;
bool exists = Get(name) == B_OK;
if (exists && (openMode & O_EXCL) != 0)
return B_FILE_EXISTS;
attr_cookie* cookie = new(std::nothrow) attr_cookie;
if (cookie == NULL)
RETURN_ERROR(B_NO_MEMORY);
fName = name;
strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
cookie->type = type;
cookie->open_mode = openMode;
cookie->create = true;
if (exists && (openMode & O_TRUNC) != 0)
_Truncate();
*_cookie = cookie;
return B_OK;
}
status_t
Attribute::Open(const char* name, int openMode, attr_cookie** _cookie)
{
status_t status = CheckAccess(name, openMode);
if (status < B_OK)
return status;
status = Get(name);
if (status < B_OK)
return status;
attr_cookie* cookie = new(std::nothrow) attr_cookie;
if (cookie == NULL)
RETURN_ERROR(B_NO_MEMORY);
strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
cookie->open_mode = openMode;
cookie->create = false;
if ((openMode & O_TRUNC) != 0)
_Truncate();
*_cookie = cookie;
return B_OK;
}
status_t
Attribute::Stat(struct stat& stat)
{
if (fSmall == NULL && fAttribute == NULL)
return B_NO_INIT;
if (fSmall != NULL) {
fill_stat_buffer(fInode, stat);
stat.st_type = fSmall->Type();
stat.st_size = fSmall->DataSize();
stat.st_mtim = stat.st_ctim;
}
if (fAttribute != NULL)
fill_stat_buffer(fAttribute, stat);
return B_OK;
}
status_t
Attribute::Read(attr_cookie* cookie, off_t pos, uint8* buffer, size_t* _length)
{
if (fSmall == NULL && fAttribute == NULL)
return B_NO_INIT;
return fInode->ReadAttribute(cookie->name, 0, pos, buffer, _length);
}
status_t
Attribute::Write(Transaction& transaction, attr_cookie* cookie, off_t pos,
const uint8* buffer, size_t* _length, bool* _created)
{
if (!cookie->create && fSmall == NULL && fAttribute == NULL)
return B_NO_INIT;
return fInode->WriteAttribute(transaction, cookie->name, cookie->type,
pos, buffer, _length, _created);
}
status_t
Attribute::_Truncate()
{
if (fSmall != NULL) {
return B_OK;
}
if (fAttribute != NULL) {
Transaction transaction(fAttribute->GetVolume(),
fAttribute->BlockNumber());
fAttribute->WriteLockInTransaction(transaction);
status_t status = fAttribute->SetFileSize(transaction, 0);
if (status >= B_OK)
status = fAttribute->WriteBack(transaction);
if (status < B_OK)
return status;
transaction.Done();
}
return B_OK;
}