Partial implementation for attribute support. Currently listattr successfully lists attributes on files.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36148 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
François Revol 2010-04-11 13:18:05 +00:00
parent af6693471d
commit b026d219fc
5 changed files with 334 additions and 3 deletions

View File

@ -7,11 +7,12 @@
#include "Inode.h"
#include <fs_cache.h>
#include <string.h>
#include "CachedBlock.h"
//#define TRACE_EXT2
#define TRACE_EXT2
#ifdef TRACE_EXT2
# define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
#else
@ -25,7 +26,8 @@ Inode::Inode(Volume* volume, ino_t id)
fID(id),
fCache(NULL),
fMap(NULL),
fNode(NULL)
fNode(NULL),
fAttributesBlock(NULL)
{
rw_lock_init(&fLock, "ext2 inode");
@ -53,6 +55,11 @@ Inode::~Inode()
file_cache_delete(FileCache());
file_map_delete(Map());
if (fAttributesBlock) {
uint32 block = B_LENDIAN_TO_HOST_INT32(Node().file_access_control);
block_cache_put(fVolume->BlockCache(), block);
}
if (fNode != NULL) {
uint32 block;
if (fVolume->GetInodeBlock(ID(), block) == B_OK)
@ -206,3 +213,30 @@ Inode::ReadAt(off_t pos, uint8* buffer, size_t* _length)
return file_cache_read(FileCache(), NULL, pos, buffer, _length);
}
status_t
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);
if (block == 0)
return B_ENTRY_NOT_FOUND;
TRACE("inode %Ld attributes at block %lu\n", ID(), block);
fAttributesBlock = (ext2_xattr_header*)block_cache_get(
GetVolume()->BlockCache(), block);
}
if (!fAttributesBlock)
return B_ENTRY_NOT_FOUND;
if (pos < 0LL || ((uint32)pos + length) > GetVolume()->BlockSize())
return ERANGE;
memcpy(buffer, ((uint8 *)fAttributesBlock) + (uint32)pos, length);
*_length = length;
return B_NO_ERROR;
}

View File

@ -49,6 +49,9 @@ public:
status_t FindBlock(off_t offset, uint32& block);
status_t ReadAt(off_t pos, uint8 *buffer, size_t *length);
status_t AttributeBlockReadAt(off_t pos, uint8 *buffer,
size_t *length);
ext2_inode& Node() { return *fNode; }
void* FileCache() const { return fCache; }
@ -66,6 +69,7 @@ private:
void* fCache;
void* fMap;
ext2_inode* fNode;
ext2_xattr_header* fAttributesBlock;
};
#endif // INODE_H

View File

@ -13,6 +13,7 @@ UsePrivateKernelHeaders ;
KernelAddon ext2 :
Volume.cpp
Inode.cpp
AttributeIterator.cpp
DirectoryIterator.cpp
kernel_interface.cpp

View File

@ -10,6 +10,7 @@
#include <ByteOrder.h>
#include <fs_interface.h>
#include <KernelExport.h>
#define EXT2_SUPER_BLOCK_OFFSET 1024
@ -286,6 +287,78 @@ struct ext2_dir_entry {
#define EXT2_TYPE_SOCKET 6
#define EXT2_TYPE_SYMLINK 7
#define EXT2_XATTR_MAGIC 0xea020000
#define EXT2_XATTR_ROUND ((1 << 2) - 1)
#define EXT2_XATTR_NAME_LENGTH 255
#define EXT2_XATTR_INDEX_USER 1
struct ext2_xattr_header {
uint32 magic;
uint32 refcount;
uint32 blocks; // must be 1 for ext2
uint32 hash;
uint32 reserved[4]; // zero
bool IsValid() const
{
return B_LENDIAN_TO_HOST_INT32(magic) == EXT2_XATTR_MAGIC
&& B_LENDIAN_TO_HOST_INT32(blocks) == 1
&& refcount <= 1024;
}
void Dump() const {
for (int i = 0; i < Length(); i++)
dprintf("%02x ", ((uint8 *)this)[i]);
dprintf("\n");
}
static size_t Length()
{
return sizeof(ext2_xattr_header);
}
};
struct ext2_xattr_entry {
uint8 name_length;
uint8 name_index;
uint16 value_offset;
uint32 value_block; // must be zero for ext2
uint32 value_size;
uint32 hash;
char name[EXT2_XATTR_NAME_LENGTH];
uint8 NameLength() const { return name_length; }
uint8 NameIndex() const { return name_index; }
uint16 ValueOffset() const { return
B_LENDIAN_TO_HOST_INT16(value_offset); }
uint32 ValueSize() const { return
B_LENDIAN_TO_HOST_INT32(value_size); }
// padded sizes
uint32 Length() const { return (MinimumSize() + NameLength()
+ EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND; }
bool IsValid() const
{
return NameLength() > 0 && value_block == 0;
// There is no maximum size, as the last entry spans until the
// end of the block
}
void Dump(bool full=false) const {
for (int i = 0; i < (full ? sizeof(this) : MinimumSize()); i++)
dprintf("%02x ", ((uint8 *)this)[i]);
dprintf("\n");
}
static size_t MinimumSize()
{
return sizeof(ext2_xattr_entry) - EXT2_XATTR_NAME_LENGTH;
}
} _PACKED;
extern fs_volume_ops gExt2VolumeOps;
extern fs_vnode_ops gExt2VnodeOps;

View File

@ -11,11 +11,20 @@
#include <fs_cache.h>
#include <fs_info.h>
#include "AttributeIterator.h"
#include "DirectoryIterator.h"
#include "ext2.h"
#include "Inode.h"
//#define TRACE_EXT2
#ifdef TRACE_EXT2
# define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
#else
# define TRACE(x...) ;
#endif
#define EXT2_IO_SIZE 65536
@ -497,6 +506,198 @@ ext2_free_dir_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie)
}
static status_t
ext2_open_attr_dir(fs_volume *_volume, fs_vnode *_node, void **_cookie)
{
Inode* inode = (Inode*)_node->private_node;
Volume* volume = (Volume*)_volume->private_volume;
TRACE("%s()\n", __FUNCTION__);
if (!(volume->SuperBlock().CompatibleFeatures() & EXT2_FEATURE_EXT_ATTR))
return ENOSYS;
// on directories too ?
if (!inode->IsFile())
return EINVAL;
AttributeIterator* iterator = new(std::nothrow) AttributeIterator(inode);
if (iterator == NULL)
return B_NO_MEMORY;
*_cookie = iterator;
return B_OK;
}
static status_t
ext2_close_attr_dir(fs_volume* _volume, fs_vnode* _node, void* cookie)
{
TRACE("%s()\n", __FUNCTION__);
return B_OK;
}
static status_t
ext2_free_attr_dir_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie)
{
TRACE("%s()\n", __FUNCTION__);
delete (AttributeIterator *)_cookie;
return B_OK;
}
static status_t
ext2_read_attr_dir(fs_volume* _volume, fs_vnode* _node,
void* _cookie, struct dirent* dirent, size_t bufferSize,
uint32* _num)
{
Inode* inode = (Inode*)_node->private_node;
AttributeIterator *iterator = (AttributeIterator *)_cookie;
TRACE("%s()\n", __FUNCTION__);
size_t length = bufferSize;
status_t status = iterator->GetNext(dirent->d_name, &length);
if (status == B_ENTRY_NOT_FOUND) {
*_num = 0;
return B_OK;
} else if (status != B_OK)
return status;
Volume* volume = (Volume*)_volume->private_volume;
dirent->d_dev = volume->ID();
dirent->d_ino = inode->ID();
dirent->d_reclen = sizeof(struct dirent) + length;
*_num = 1;
return B_OK;
}
static status_t
ext2_rewind_attr_dir(fs_volume* _volume, fs_vnode* _node, void* _cookie)
{
AttributeIterator *iterator = (AttributeIterator *)_cookie;
TRACE("%s()\n", __FUNCTION__);
return iterator->Rewind();
}
/* attribute operations */
static status_t
ext2_create_attr(fs_volume* _volume, fs_vnode* _node,
const char* name, uint32 type, int openMode, void** _cookie)
{
return EROFS;
}
static status_t
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;
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;
}
static status_t
ext2_close_attr(fs_volume* _volume, fs_vnode* _node,
void* cookie)
{
return B_OK;
}
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;
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)
{
return ENOSYS;
}
static status_t
ext2_write_attr(fs_volume* _volume, fs_vnode* _node, void* cookie,
off_t pos, const void* buffer, size_t* length)
{
return EROFS;
}
static status_t
ext2_read_attr_stat(fs_volume* _volume, fs_vnode* _node,
void* cookie, struct stat* stat)
{
ext2_xattr_entry *entry = (ext2_xattr_entry *)cookie;
stat->st_type = B_RAW_TYPE;
stat->st_size = entry->ValueSize();
TRACE("%s: st_size %d\n", __FUNCTION__, stat->st_size);
return B_OK;
}
static status_t
ext2_write_attr_stat(fs_volume* _volume, fs_vnode* _node,
void* cookie, const struct stat* stat, int statMask)
{
return EROFS;
}
static status_t
ext2_rename_attr(fs_volume* _volume, fs_vnode* fromVnode,
const char* fromName, fs_vnode* toVnode, const char* toName)
{
return ENOSYS;
}
static status_t
ext2_remove_attr(fs_volume* _volume, fs_vnode* vnode,
const char* name)
{
return ENOSYS;
}
fs_volume_ops gExt2VolumeOps = {
&ext2_unmount,
&ext2_read_fs_info,
@ -556,7 +757,25 @@ fs_vnode_ops gExt2VnodeOps = {
&ext2_read_dir,
&ext2_rewind_dir,
NULL,
/* attribute directory operations */
&ext2_open_attr_dir,
&ext2_close_attr_dir,
&ext2_free_attr_dir_cookie,
&ext2_read_attr_dir,
&ext2_rewind_attr_dir,
/* attribute operations */
NULL, //&ext2_create_attr,
&ext2_open_attr,
&ext2_close_attr,
&ext2_free_attr_cookie,
NULL, //&ext2_read_attr,
NULL, //&ext2_write_attr,
&ext2_read_attr_stat,
NULL, //&ext2_write_attr_stat,
NULL, //&ext2_rename_attr,
NULL, //&ext2_remove_attr,
};
static file_system_module_info sExt2FileSystem = {