ext3 inodes whose size is at least 256 bytes can also contain attributes (like smalldata for bfs).
We now use the Attribute class from bfs (instead of AttributeIterator) to manage small data and block attributes, though it's still readonly. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39036 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
* Copyright 2010, Jérôme Duval, [email protected].
|
||||
* Copyright 2010, François Revol, <[email protected]>.
|
||||
* Copyright 2004-2008, Axel Dörfler, [email protected].
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
//! connection between pure inode and kernel_interface attributes
|
||||
|
||||
|
||||
#include "Attribute.h"
|
||||
#include "Utility.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
//#define TRACE_EXT2
|
||||
#ifdef TRACE_EXT2
|
||||
# define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
|
||||
#else
|
||||
# define TRACE(x...) ;
|
||||
#endif
|
||||
|
||||
|
||||
Attribute::Attribute(Inode* inode)
|
||||
:
|
||||
fVolume(inode->GetVolume()),
|
||||
fBlock(fVolume),
|
||||
fInode(inode),
|
||||
fBodyEntry(NULL),
|
||||
fBlockEntry(NULL),
|
||||
fName(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
Attribute::Attribute(Inode* inode, attr_cookie* cookie)
|
||||
:
|
||||
fVolume(inode->GetVolume()),
|
||||
fBlock(fVolume),
|
||||
fInode(inode),
|
||||
fBodyEntry(NULL),
|
||||
fBlockEntry(NULL),
|
||||
fName(NULL)
|
||||
{
|
||||
Find(cookie->name);
|
||||
}
|
||||
|
||||
|
||||
Attribute::~Attribute()
|
||||
{
|
||||
Put();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Attribute::InitCheck()
|
||||
{
|
||||
return (fBodyEntry != NULL || fBlockEntry != NULL) ? B_OK : B_NO_INIT;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Attribute::CheckAccess(const char* name, int openMode)
|
||||
{
|
||||
return fInode->CheckPermissions(open_mode_to_access(openMode)
|
||||
| (openMode & O_TRUNC ? W_OK : 0));
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Attribute::Find(const char* name)
|
||||
{
|
||||
return _Find(name, -1);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Attribute::Find(int32 index)
|
||||
{
|
||||
return _Find(NULL, index);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Attribute::GetName(char* name, size_t* _nameLength)
|
||||
{
|
||||
if (fBodyEntry == NULL && fBlockEntry == NULL)
|
||||
return B_NO_INIT;
|
||||
if (fBodyEntry != NULL)
|
||||
return _PrefixedName(fBodyEntry, name, _nameLength);
|
||||
else
|
||||
return _PrefixedName(fBlockEntry, name, _nameLength);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Attribute::Put()
|
||||
{
|
||||
if (fBodyEntry != NULL) {
|
||||
recursive_lock_unlock(&fInode->SmallDataLock());
|
||||
fBlock.Unset();
|
||||
fBodyEntry = NULL;
|
||||
}
|
||||
|
||||
if (fBlockEntry != NULL) {
|
||||
fBlock.Unset();
|
||||
fBlockEntry = 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;
|
||||
|
||||
attr_cookie* cookie = new(std::nothrow) attr_cookie;
|
||||
if (cookie == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
fName = name;
|
||||
|
||||
// initialize the cookie
|
||||
strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
|
||||
cookie->type = type;
|
||||
cookie->open_mode = openMode;
|
||||
cookie->create = true;
|
||||
|
||||
if (Find(name) == B_OK) {
|
||||
// attribute already exists
|
||||
if ((openMode & O_TRUNC) != 0)
|
||||
_Truncate();
|
||||
}
|
||||
*_cookie = cookie;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Attribute::Open(const char* name, int openMode, attr_cookie** _cookie)
|
||||
{
|
||||
TRACE("Open\n");
|
||||
status_t status = CheckAccess(name, openMode);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
status = Find(name);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
attr_cookie* cookie = new(std::nothrow) attr_cookie;
|
||||
if (cookie == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// initialize the cookie
|
||||
strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
|
||||
cookie->open_mode = openMode;
|
||||
cookie->create = false;
|
||||
|
||||
// Should we truncate the attribute?
|
||||
if ((openMode & O_TRUNC) != 0)
|
||||
_Truncate();
|
||||
|
||||
*_cookie = cookie;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Attribute::Stat(struct stat& stat)
|
||||
{
|
||||
TRACE("Stat\n");
|
||||
if (fBodyEntry == NULL && fBlockEntry == NULL)
|
||||
return B_NO_INIT;
|
||||
|
||||
stat.st_type = B_RAW_TYPE;
|
||||
|
||||
if (fBodyEntry != NULL)
|
||||
stat.st_size = fBodyEntry->ValueSize();
|
||||
else if (fBlockEntry != NULL)
|
||||
stat.st_size = fBlockEntry->ValueSize();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Attribute::Read(attr_cookie* cookie, off_t pos, uint8* buffer, size_t* _length)
|
||||
{
|
||||
if (fBodyEntry == NULL && fBlockEntry == NULL)
|
||||
return B_NO_INIT;
|
||||
|
||||
if (pos < 0LL)
|
||||
return ERANGE;
|
||||
|
||||
size_t length = *_length;
|
||||
const uint8* start = (uint8 *)fBlock.Block();
|
||||
if (fBlockEntry != NULL) {
|
||||
pos += fBlockEntry->ValueOffset();
|
||||
if (((uint32)pos + length) > fVolume->BlockSize()
|
||||
|| length > fBlockEntry->ValueSize())
|
||||
return ERANGE;
|
||||
} else {
|
||||
start += fVolume->InodeBlockIndex(fInode->ID()) * fVolume->InodeSize();
|
||||
const uint8* end = start + fVolume->InodeSize();
|
||||
start += EXT2_INODE_NORMAL_SIZE + fInode->Node().ExtraInodeSize()
|
||||
+ sizeof(uint32);
|
||||
pos += fBodyEntry->ValueOffset();
|
||||
if ((pos + length) > (end - start) || length > fBodyEntry->ValueSize())
|
||||
return ERANGE;
|
||||
}
|
||||
memcpy(buffer, start + (uint32)pos, length);
|
||||
|
||||
*_length = length;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Attribute::Write(Transaction& transaction, attr_cookie* cookie, off_t pos,
|
||||
const uint8* buffer, size_t* _length, bool* _created)
|
||||
{
|
||||
if (!cookie->create && fBodyEntry == NULL && fBlockEntry == NULL)
|
||||
return B_NO_INIT;
|
||||
|
||||
// TODO: Implement
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Attribute::_Truncate()
|
||||
{
|
||||
// TODO: Implement
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Attribute::_Find(const char* name, int32 index)
|
||||
{
|
||||
Put();
|
||||
|
||||
fName = name;
|
||||
|
||||
// try to find it in the small data region
|
||||
if (fInode->HasExtraAttributes()
|
||||
&& recursive_lock_lock(&fInode->SmallDataLock()) == B_OK) {
|
||||
uint32 block;
|
||||
fVolume->GetInodeBlock(fInode->ID(), block);
|
||||
|
||||
if (block != 0) {
|
||||
fBlock.SetTo(block);
|
||||
const uint8* start = fBlock.Block()
|
||||
+ fVolume->InodeBlockIndex(fInode->ID()) * fVolume->InodeSize();
|
||||
const uint8* end = start + fVolume->InodeSize();
|
||||
int32 count = 0;
|
||||
if (_FindAttributeBody(start + EXT2_INODE_NORMAL_SIZE
|
||||
+ fInode->Node().ExtraInodeSize(), end, name, index, &count,
|
||||
&fBodyEntry) == B_OK)
|
||||
return B_OK;
|
||||
index -= count;
|
||||
}
|
||||
|
||||
recursive_lock_unlock(&fInode->SmallDataLock());
|
||||
fBlock.Unset();
|
||||
}
|
||||
|
||||
// then, search in the attribute directory
|
||||
if (fInode->Node().ExtendedAttributesBlock() != 0) {
|
||||
fBlock.SetTo(fInode->Node().ExtendedAttributesBlock());
|
||||
if (_FindAttributeBlock(fBlock.Block(),
|
||||
fBlock.Block() + fVolume->BlockSize(), name, index, NULL,
|
||||
&fBlockEntry) == B_OK)
|
||||
return B_OK;
|
||||
fBlock.Unset();
|
||||
}
|
||||
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Attribute::_FindAttributeBody(const uint8* start, const uint8* end,
|
||||
const char* name, int32 index, int32 *count, ext2_xattr_entry** _entry)
|
||||
{
|
||||
TRACE("_FindAttributeBody %p %p %s\n", start, end, name);
|
||||
if (*((uint32*)start) != EXT2_XATTR_MAGIC)
|
||||
return B_BAD_DATA;
|
||||
return _FindAttribute(start + sizeof(uint32), end, name, index, count,
|
||||
_entry);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Attribute::_FindAttributeBlock(const uint8* start, const uint8* end, const char* name,
|
||||
int32 index, int32 *count, ext2_xattr_entry** _entry)
|
||||
{
|
||||
TRACE("_FindAttributeBlock %p %p %s\n", start, end, name);
|
||||
ext2_xattr_header *header = (ext2_xattr_header*)start;
|
||||
if (!header->IsValid())
|
||||
return B_BAD_DATA;
|
||||
|
||||
return _FindAttribute(start + sizeof(ext2_xattr_header), end, name, index,
|
||||
count, _entry);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Attribute::_FindAttribute(const uint8* start, const uint8* end, const char* name,
|
||||
int32 index, int32 *count, ext2_xattr_entry** _entry)
|
||||
{
|
||||
TRACE("_FindAttribute %p %p %s\n", start, end, name);
|
||||
char buffer[EXT2_XATTR_NAME_LENGTH];
|
||||
|
||||
int32 i = 0;
|
||||
while (start < end) {
|
||||
ext2_xattr_entry* entry = (ext2_xattr_entry*)start;
|
||||
if (!entry->IsValid())
|
||||
break;
|
||||
|
||||
size_t length = EXT2_XATTR_NAME_LENGTH;
|
||||
if ((name != NULL && _PrefixedName(entry, buffer, &length) == B_OK
|
||||
&& strncmp(name, buffer, length) == 0) || index == i) {
|
||||
*_entry = entry;
|
||||
return B_OK;
|
||||
}
|
||||
start += entry->Length();
|
||||
i++;
|
||||
}
|
||||
|
||||
if (count != NULL)
|
||||
*count = i;
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Attribute::_PrefixedName(ext2_xattr_entry* entry, char* _name, size_t* _nameLength)
|
||||
{
|
||||
const char *indexNames[] = { "0", "user" };
|
||||
size_t l = 0;
|
||||
|
||||
if (entry->NameIndex() < ((sizeof(indexNames) / sizeof(indexNames[0]))))
|
||||
l = snprintf(_name, *_nameLength, "%s.%s.%.*s",
|
||||
"linux", indexNames[entry->NameIndex()], entry->NameLength(),
|
||||
entry->name);
|
||||
else
|
||||
l = snprintf(_name, *_nameLength, "%s.%d.%.*s",
|
||||
"linux", entry->NameIndex(), entry->NameLength(), entry->name);
|
||||
if (l < 1 || l > *_nameLength - 1)
|
||||
return ENOBUFS;
|
||||
|
||||
*_nameLength = l + 1;
|
||||
_name[l] = '\0';
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2010, Jérôme Duval, [email protected].
|
||||
* Copyright 2004-2008, Axel Dörfler, [email protected].
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef ATTRIBUTE_H
|
||||
#define ATTRIBUTE_H
|
||||
|
||||
|
||||
#include "CachedBlock.h"
|
||||
#include "Inode.h"
|
||||
|
||||
|
||||
struct attr_cookie {
|
||||
char name[B_ATTR_NAME_LENGTH];
|
||||
uint32 type;
|
||||
int open_mode;
|
||||
bool create;
|
||||
};
|
||||
|
||||
|
||||
class Attribute {
|
||||
public:
|
||||
Attribute(Inode* inode);
|
||||
Attribute(Inode* inode, attr_cookie* cookie);
|
||||
~Attribute();
|
||||
|
||||
status_t InitCheck();
|
||||
status_t CheckAccess(const char* name, int openMode);
|
||||
|
||||
status_t Find(const char* name);
|
||||
status_t Find(int32 index);
|
||||
status_t GetName(char* name, size_t* _nameLength);
|
||||
void Put();
|
||||
|
||||
status_t Create(const char* name, type_code type,
|
||||
int openMode, attr_cookie** _cookie);
|
||||
status_t Open(const char* name, int openMode,
|
||||
attr_cookie** _cookie);
|
||||
|
||||
status_t Stat(struct stat& stat);
|
||||
|
||||
status_t Read(attr_cookie* cookie, off_t pos, uint8* buffer,
|
||||
size_t* _length);
|
||||
status_t Write(Transaction& transaction, attr_cookie* cookie,
|
||||
off_t pos, const uint8* buffer,
|
||||
size_t* _length, bool* _created);
|
||||
|
||||
private:
|
||||
status_t _Truncate();
|
||||
status_t _Find(const char* name, int32 index);
|
||||
status_t _FindAttributeBody(const uint8* start, const uint8* end,
|
||||
const char* name, int32 index, int32 *count,
|
||||
ext2_xattr_entry** entry);
|
||||
status_t _FindAttributeBlock(const uint8* start, const uint8* end,
|
||||
const char* name, int32 index, int32 *count,
|
||||
ext2_xattr_entry** entry);
|
||||
status_t _FindAttribute(const uint8* start, const uint8* end,
|
||||
const char* name, int32 index, int32 *count,
|
||||
ext2_xattr_entry** entry);
|
||||
status_t _PrefixedName(ext2_xattr_entry* entry, char* _name,
|
||||
size_t* _nameLength);
|
||||
|
||||
::Volume* fVolume;
|
||||
CachedBlock fBlock;
|
||||
Inode* fInode;
|
||||
ext2_xattr_entry* fBodyEntry;
|
||||
ext2_xattr_entry* fBlockEntry;
|
||||
const char* fName;
|
||||
};
|
||||
|
||||
#endif // ATTRIBUTE_H
|
||||
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, François Revol, <[email protected]>.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "AttributeIterator.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "Inode.h"
|
||||
|
||||
|
||||
//#define TRACE_EXT2
|
||||
#ifdef TRACE_EXT2
|
||||
# define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
|
||||
#else
|
||||
# define TRACE(x...) ;
|
||||
#endif
|
||||
|
||||
|
||||
AttributeIterator::AttributeIterator(Inode* inode)
|
||||
:
|
||||
fInode(inode),
|
||||
fOffset(0)
|
||||
{
|
||||
TRACE("AttributeIterator::%s()\n", __FUNCTION__);
|
||||
ext2_xattr_header header;
|
||||
size_t length = sizeof(header);
|
||||
if (fInode->AttributeBlockReadAt(fOffset, (uint8*)&header, &length) == B_OK
|
||||
&& length == sizeof(header)) {
|
||||
//header.Dump();
|
||||
if (header.IsValid()) {
|
||||
fOffset = sizeof(header);
|
||||
TRACE("AttributeIterator::%s: header valid\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AttributeIterator::~AttributeIterator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AttributeIterator::GetNext(char* name, size_t* _nameLength, ext2_xattr_entry *_entry)
|
||||
{
|
||||
TRACE("AttributeIterator::%s()\n", __FUNCTION__);
|
||||
ext2_xattr_entry internalEntry;
|
||||
if (_entry == NULL)
|
||||
_entry = &internalEntry;
|
||||
|
||||
TRACE("AttributeIterator::%s: fOffset %Ld e.MinSize %d BlockSize %d\n",
|
||||
__FUNCTION__, fOffset, _entry->MinimumSize(), fInode->GetVolume()->BlockSize());
|
||||
|
||||
if (fOffset + _entry->MinimumSize() >= fInode->GetVolume()->BlockSize())
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
size_t length = ext2_xattr_entry::MinimumSize();
|
||||
status_t status = fInode->AttributeBlockReadAt(fOffset, (uint8*)_entry, &length);
|
||||
TRACE("AttributeIterator::%s:AttributeBlockReadAt(%Ld): 0x%08lx len %d\n",
|
||||
__FUNCTION__, fOffset, status, length);
|
||||
//_entry->Dump();
|
||||
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
if (length < ext2_xattr_entry::MinimumSize())
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
TRACE("AttributeIterator::%s:AttributeBlockReadAt(%Ld): namelen %d %cvalid\n",
|
||||
__FUNCTION__, fOffset, _entry->NameLength(), _entry->IsValid() ? ' ' : '!');
|
||||
if (!_entry->IsValid())
|
||||
return B_BAD_DATA;
|
||||
|
||||
TRACE("xattr block offset %Ld: entry ino %Lu, length %u, name length %u,"
|
||||
" index %d\n",
|
||||
fOffset, fInode->ID(), _entry->Length(), _entry->NameLength(),
|
||||
_entry->NameIndex());
|
||||
|
||||
// read name
|
||||
|
||||
length = _entry->NameLength();
|
||||
status = fInode->AttributeBlockReadAt(fOffset + ext2_xattr_entry::MinimumSize(),
|
||||
(uint8*)_entry->name, &length);
|
||||
TRACE("AttributeIterator::%s:AttributeBlockReadAt(%Ld): 0x%08lx len %d\n",
|
||||
__FUNCTION__, fOffset + ext2_xattr_entry::MinimumSize(),
|
||||
status, length);
|
||||
|
||||
if (length < 1)
|
||||
status = ENOENT;
|
||||
|
||||
if (status == B_OK) {
|
||||
const char *indexNames[] = { "0", "user" };
|
||||
|
||||
size_t l;
|
||||
|
||||
TRACE("AttributeIterator::%s: len %d nlen %d\n",
|
||||
__FUNCTION__, length, *_nameLength);
|
||||
if (_entry->NameIndex() < ((sizeof(indexNames) / sizeof(indexNames[0]))))
|
||||
l = snprintf(name, *_nameLength, "%s.%s.%.*s",
|
||||
"linux", indexNames[_entry->NameIndex()], length, _entry->name);
|
||||
else
|
||||
l = snprintf(name, *_nameLength, "%s.%d.%.*s",
|
||||
"linux", _entry->NameIndex(), length, _entry->name);
|
||||
if (l < 1 || l > *_nameLength - 1)
|
||||
status = ENOBUFS;
|
||||
else {
|
||||
*_nameLength = l + 1;
|
||||
name[l] = '\0';
|
||||
}
|
||||
|
||||
TRACE("AttributeIterator::%s: name %.*s len %d nlen %d\n",
|
||||
__FUNCTION__, *_nameLength, name, length, *_nameLength);
|
||||
|
||||
fOffset += _entry->Length();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AttributeIterator::Rewind()
|
||||
{
|
||||
TRACE("AttributeIterator::%s()\n", __FUNCTION__);
|
||||
fOffset = sizeof(ext2_xattr_header);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AttributeIterator::Find(const char* name, ext2_xattr_entry *_entry)
|
||||
{
|
||||
char buffer[EXT2_XATTR_NAME_LENGTH];
|
||||
size_t length = sizeof(buffer);
|
||||
status_t err;
|
||||
while ((err = GetNext(buffer, &length, _entry)) == B_OK) {
|
||||
TRACE("AttributeIterator::%s: next is '%.*s'\n", __FUNCTION__, length > 0 ? length : 0, buffer);
|
||||
_entry->Dump();
|
||||
if (strncmp(name, buffer, length) == 0)
|
||||
return B_OK;
|
||||
length = sizeof(buffer);
|
||||
}
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AttributeIterator::PrefixForNameIndex(uint8 index, char* prefix, size_t *length)
|
||||
{
|
||||
const char *indexNames[] = { "user" };
|
||||
if (index < (sizeof(indexNames) / sizeof(indexNames[0])))
|
||||
*length = strlcpy(prefix, indexNames[index], *length);
|
||||
else {
|
||||
*length = strlcpy(prefix, "unknown", *length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AttributeIterator::NameBufferAppend(const char* str, char *&buffer, size_t *length)
|
||||
{
|
||||
size_t done;
|
||||
done = strlcpy(buffer, str, *length);
|
||||
*length = done > 0 ? done - 1 : 0;
|
||||
buffer += done;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, François Revol, <[email protected]>.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef ATTRIBUTE_ITERATOR_H
|
||||
#define ATTRIBUTE_ITERATOR_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include "ext2.h"
|
||||
|
||||
class Inode;
|
||||
|
||||
class AttributeIterator {
|
||||
public:
|
||||
AttributeIterator(Inode* inode);
|
||||
~AttributeIterator();
|
||||
|
||||
status_t InitCheck() const { return (fOffset
|
||||
>= sizeof(ext2_xattr_header)) ? B_OK : B_ENTRY_NOT_FOUND; }
|
||||
|
||||
status_t GetNext(char* name, size_t* _nameLength, ext2_xattr_entry *_entry=NULL);
|
||||
|
||||
status_t Rewind();
|
||||
|
||||
status_t Find(const char* name, ext2_xattr_entry *_entry);
|
||||
|
||||
private:
|
||||
AttributeIterator(const AttributeIterator&);
|
||||
AttributeIterator &operator=(const AttributeIterator&);
|
||||
// no implementation
|
||||
|
||||
void PrefixForNameIndex(uint8 index, char* prefix, size_t *length);
|
||||
status_t NameBufferAppend(const char* str, char *&buffer, size_t *length);
|
||||
|
||||
private:
|
||||
Inode* fInode;
|
||||
off_t fOffset;
|
||||
};
|
||||
|
||||
#endif // ATTRIBUTE_ITERATOR_H
|
||||
@@ -32,9 +32,11 @@ Inode::Inode(Volume* volume, ino_t id)
|
||||
fCache(NULL),
|
||||
fMap(NULL),
|
||||
fCached(false),
|
||||
fHasExtraAttributes(false),
|
||||
fAttributesBlock(NULL)
|
||||
{
|
||||
rw_lock_init(&fLock, "ext2 inode");
|
||||
recursive_lock_init(&fSmallDataLock, "ext2 inode small data");
|
||||
|
||||
TRACE("Inode::Inode(): ext2_inode: %lu, disk inode: %lu\n",
|
||||
sizeof(ext2_inode), fVolume->InodeSize());
|
||||
@@ -70,6 +72,7 @@ Inode::Inode(Volume* volume)
|
||||
fInitStatus(B_NO_INIT)
|
||||
{
|
||||
rw_lock_init(&fLock, "ext2 inode");
|
||||
recursive_lock_init(&fSmallDataLock, "ext2 inode small data");
|
||||
|
||||
TRACE("Inode::Inode(): ext2_inode: %lu, disk inode: %lu\n",
|
||||
sizeof(ext2_inode), fVolume->InodeSize());
|
||||
@@ -476,7 +479,7 @@ Inode::AttributeBlockReadAt(off_t pos, uint8* buffer, size_t* _length)
|
||||
size_t length = *_length;
|
||||
|
||||
if (!fAttributesBlock) {
|
||||
uint32 block = B_LENDIAN_TO_HOST_INT32(Node().file_access_control);
|
||||
uint32 block = Node().ExtendedAttributesBlock();
|
||||
|
||||
if (block == 0)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
@@ -37,6 +37,8 @@ public:
|
||||
status_t UpdateNodeFromDisk();
|
||||
status_t WriteBack(Transaction& transaction);
|
||||
|
||||
recursive_lock& SmallDataLock() { return fSmallDataLock; }
|
||||
|
||||
bool IsDirectory() const
|
||||
{ return S_ISDIR(Mode()); }
|
||||
bool IsFile() const
|
||||
@@ -148,6 +150,8 @@ private:
|
||||
// information is always the same size (except in ext4)
|
||||
ext2_xattr_header* fAttributesBlock;
|
||||
status_t fInitStatus;
|
||||
|
||||
mutable recursive_lock fSmallDataLock;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ KernelAddon ext2 :
|
||||
Volume.cpp
|
||||
DataStream.cpp
|
||||
Inode.cpp
|
||||
AttributeIterator.cpp
|
||||
Attribute.cpp
|
||||
DirectoryIterator.cpp
|
||||
HTree.cpp
|
||||
HTreeEntryIterator.cpp
|
||||
|
||||
@@ -349,6 +349,9 @@ struct ext2_inode {
|
||||
return B_LENDIAN_TO_HOST_INT32(size);
|
||||
}
|
||||
|
||||
uint32 ExtendedAttributesBlock() const
|
||||
{ return B_LENDIAN_TO_HOST_INT32(file_access_control);}
|
||||
|
||||
uint16 ExtraInodeSize() const
|
||||
{ return B_LENDIAN_TO_HOST_INT16(extra_inode_size); }
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010, Jérôme Duval, korli@users.berlios.de.
|
||||
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
@@ -15,7 +16,7 @@
|
||||
#include <NodeMonitor.h>
|
||||
#include <util/AutoLock.h>
|
||||
|
||||
#include "AttributeIterator.h"
|
||||
#include "Attribute.h"
|
||||
#include "CachedBlock.h"
|
||||
#include "DirectoryIterator.h"
|
||||
#include "ext2.h"
|
||||
@@ -1416,11 +1417,11 @@ ext2_open_attr_dir(fs_volume *_volume, fs_vnode *_node, void **_cookie)
|
||||
if (!inode->IsFile())
|
||||
return EINVAL;
|
||||
|
||||
AttributeIterator* iterator = new(std::nothrow) AttributeIterator(inode);
|
||||
if (iterator == NULL)
|
||||
int32 *index = new(std::nothrow) int32;
|
||||
if (index == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
*_cookie = iterator;
|
||||
*index = 0;
|
||||
*(int32**)_cookie = index;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -1436,7 +1437,7 @@ static status_t
|
||||
ext2_free_attr_dir_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie)
|
||||
{
|
||||
TRACE("%s()\n", __FUNCTION__);
|
||||
delete (AttributeIterator *)_cookie;
|
||||
delete (int32 *)_cookie;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -1447,17 +1448,22 @@ ext2_read_attr_dir(fs_volume* _volume, fs_vnode* _node,
|
||||
uint32* _num)
|
||||
{
|
||||
Inode* inode = (Inode*)_node->private_node;
|
||||
AttributeIterator *iterator = (AttributeIterator *)_cookie;
|
||||
int32 index = *(int32 *)_cookie;
|
||||
Attribute attribute(inode);
|
||||
TRACE("%s()\n", __FUNCTION__);
|
||||
|
||||
size_t length = bufferSize;
|
||||
status_t status = iterator->GetNext(dirent->d_name, &length);
|
||||
status_t status = attribute.Find(index);
|
||||
if (status == B_ENTRY_NOT_FOUND) {
|
||||
*_num = 0;
|
||||
return B_OK;
|
||||
} else if (status != B_OK)
|
||||
return status;
|
||||
|
||||
status = attribute.GetName(dirent->d_name, &length);
|
||||
if (status != B_OK)
|
||||
return B_OK;
|
||||
|
||||
Volume* volume = (Volume*)_volume->private_volume;
|
||||
|
||||
dirent->d_dev = volume->ID();
|
||||
@@ -1465,6 +1471,7 @@ ext2_read_attr_dir(fs_volume* _volume, fs_vnode* _node,
|
||||
dirent->d_reclen = sizeof(struct dirent) + length;
|
||||
|
||||
*_num = 1;
|
||||
*(int32*)_cookie = index + 1;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -1472,9 +1479,9 @@ ext2_read_attr_dir(fs_volume* _volume, fs_vnode* _node,
|
||||
static status_t
|
||||
ext2_rewind_attr_dir(fs_volume* _volume, fs_vnode* _node, void* _cookie)
|
||||
{
|
||||
AttributeIterator *iterator = (AttributeIterator *)_cookie;
|
||||
*(int32*)_cookie = 0;
|
||||
TRACE("%s()\n", __FUNCTION__);
|
||||
return iterator->Rewind();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -1492,31 +1499,15 @@ ext2_open_attr(fs_volume* _volume, fs_vnode* _node, const char* name,
|
||||
int openMode, void** _cookie)
|
||||
{
|
||||
TRACE("%s()\n", __FUNCTION__);
|
||||
if ((openMode & O_RWMASK) != O_RDONLY)
|
||||
return EROFS;
|
||||
|
||||
Inode* inode = (Inode*)_node->private_node;
|
||||
|
||||
Volume* volume = (Volume*)_volume->private_volume;
|
||||
Inode* inode = (Inode*)_node->private_node;
|
||||
Attribute attribute(inode);
|
||||
|
||||
if (!(volume->SuperBlock().CompatibleFeatures() & EXT2_FEATURE_EXT_ATTR))
|
||||
return ENOSYS;
|
||||
|
||||
// on directories too ?
|
||||
if (!inode->IsFile())
|
||||
return EINVAL;
|
||||
|
||||
ext2_xattr_entry *entry = new ext2_xattr_entry;
|
||||
|
||||
AttributeIterator i(inode);
|
||||
status_t status = i.Find(name, entry);
|
||||
if (status == B_OK) {
|
||||
//entry->Dump();
|
||||
*_cookie = entry;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
delete entry;
|
||||
return status;
|
||||
return attribute.Open(name, openMode, (attr_cookie**)_cookie);
|
||||
}
|
||||
|
||||
|
||||
@@ -1532,31 +1523,23 @@ static status_t
|
||||
ext2_free_attr_cookie(fs_volume* _volume, fs_vnode* _node,
|
||||
void* cookie)
|
||||
{
|
||||
ext2_xattr_entry *entry = (ext2_xattr_entry *)cookie;
|
||||
|
||||
delete entry;
|
||||
delete (attr_cookie*)cookie;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
ext2_read_attr(fs_volume* _volume, fs_vnode* _node, void* cookie,
|
||||
off_t pos, void* buffer, size_t* length)
|
||||
ext2_read_attr(fs_volume* _volume, fs_vnode* _node, void* _cookie,
|
||||
off_t pos, void* buffer, size_t* _length)
|
||||
{
|
||||
TRACE("%s()\n", __FUNCTION__);
|
||||
|
||||
attr_cookie* cookie = (attr_cookie*)_cookie;
|
||||
Inode* inode = (Inode*)_node->private_node;
|
||||
//Volume* volume = (Volume*)_volume->private_volume;
|
||||
ext2_xattr_entry *entry = (ext2_xattr_entry *)cookie;
|
||||
|
||||
if (!entry->IsValid())
|
||||
return EINVAL;
|
||||
Attribute attribute(inode, cookie);
|
||||
|
||||
if (pos < 0 || (pos + *length) > entry->ValueSize())
|
||||
return ERANGE;
|
||||
|
||||
return inode->AttributeBlockReadAt(entry->ValueOffset() + pos,
|
||||
(uint8 *)buffer, length);
|
||||
return attribute.Read(cookie, pos, (uint8*)buffer, _length);
|
||||
}
|
||||
|
||||
|
||||
@@ -1571,15 +1554,14 @@ ext2_write_attr(fs_volume* _volume, fs_vnode* _node, void* cookie,
|
||||
|
||||
static status_t
|
||||
ext2_read_attr_stat(fs_volume* _volume, fs_vnode* _node,
|
||||
void* cookie, struct stat* stat)
|
||||
void* _cookie, struct stat* stat)
|
||||
{
|
||||
ext2_xattr_entry *entry = (ext2_xattr_entry *)cookie;
|
||||
attr_cookie* cookie = (attr_cookie*)_cookie;
|
||||
Inode* inode = (Inode*)_node->private_node;
|
||||
|
||||
stat->st_type = B_RAW_TYPE;
|
||||
stat->st_size = entry->ValueSize();
|
||||
TRACE("%s: st_size %d\n", __FUNCTION__, stat->st_size);
|
||||
Attribute attribute(inode, cookie);
|
||||
|
||||
return B_OK;
|
||||
return attribute.Stat(*stat);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user