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:
parent
af6693471d
commit
b026d219fc
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -13,6 +13,7 @@ UsePrivateKernelHeaders ;
|
||||
KernelAddon ext2 :
|
||||
Volume.cpp
|
||||
Inode.cpp
|
||||
AttributeIterator.cpp
|
||||
DirectoryIterator.cpp
|
||||
|
||||
kernel_interface.cpp
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 = {
|
||||
|
Loading…
Reference in New Issue
Block a user