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:
@@ -7,11 +7,12 @@
|
|||||||
#include "Inode.h"
|
#include "Inode.h"
|
||||||
|
|
||||||
#include <fs_cache.h>
|
#include <fs_cache.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "CachedBlock.h"
|
#include "CachedBlock.h"
|
||||||
|
|
||||||
|
|
||||||
//#define TRACE_EXT2
|
#define TRACE_EXT2
|
||||||
#ifdef TRACE_EXT2
|
#ifdef TRACE_EXT2
|
||||||
# define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
|
# define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
|
||||||
#else
|
#else
|
||||||
@@ -25,7 +26,8 @@ Inode::Inode(Volume* volume, ino_t id)
|
|||||||
fID(id),
|
fID(id),
|
||||||
fCache(NULL),
|
fCache(NULL),
|
||||||
fMap(NULL),
|
fMap(NULL),
|
||||||
fNode(NULL)
|
fNode(NULL),
|
||||||
|
fAttributesBlock(NULL)
|
||||||
{
|
{
|
||||||
rw_lock_init(&fLock, "ext2 inode");
|
rw_lock_init(&fLock, "ext2 inode");
|
||||||
|
|
||||||
@@ -53,6 +55,11 @@ Inode::~Inode()
|
|||||||
file_cache_delete(FileCache());
|
file_cache_delete(FileCache());
|
||||||
file_map_delete(Map());
|
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) {
|
if (fNode != NULL) {
|
||||||
uint32 block;
|
uint32 block;
|
||||||
if (fVolume->GetInodeBlock(ID(), block) == B_OK)
|
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);
|
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 FindBlock(off_t offset, uint32& block);
|
||||||
status_t ReadAt(off_t pos, uint8 *buffer, size_t *length);
|
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; }
|
ext2_inode& Node() { return *fNode; }
|
||||||
|
|
||||||
void* FileCache() const { return fCache; }
|
void* FileCache() const { return fCache; }
|
||||||
@@ -66,6 +69,7 @@ private:
|
|||||||
void* fCache;
|
void* fCache;
|
||||||
void* fMap;
|
void* fMap;
|
||||||
ext2_inode* fNode;
|
ext2_inode* fNode;
|
||||||
|
ext2_xattr_header* fAttributesBlock;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INODE_H
|
#endif // INODE_H
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ UsePrivateKernelHeaders ;
|
|||||||
KernelAddon ext2 :
|
KernelAddon ext2 :
|
||||||
Volume.cpp
|
Volume.cpp
|
||||||
Inode.cpp
|
Inode.cpp
|
||||||
|
AttributeIterator.cpp
|
||||||
DirectoryIterator.cpp
|
DirectoryIterator.cpp
|
||||||
|
|
||||||
kernel_interface.cpp
|
kernel_interface.cpp
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <ByteOrder.h>
|
#include <ByteOrder.h>
|
||||||
#include <fs_interface.h>
|
#include <fs_interface.h>
|
||||||
|
#include <KernelExport.h>
|
||||||
|
|
||||||
|
|
||||||
#define EXT2_SUPER_BLOCK_OFFSET 1024
|
#define EXT2_SUPER_BLOCK_OFFSET 1024
|
||||||
@@ -286,6 +287,78 @@ struct ext2_dir_entry {
|
|||||||
#define EXT2_TYPE_SOCKET 6
|
#define EXT2_TYPE_SOCKET 6
|
||||||
#define EXT2_TYPE_SYMLINK 7
|
#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_volume_ops gExt2VolumeOps;
|
||||||
extern fs_vnode_ops gExt2VnodeOps;
|
extern fs_vnode_ops gExt2VnodeOps;
|
||||||
|
|
||||||
|
|||||||
@@ -11,11 +11,20 @@
|
|||||||
#include <fs_cache.h>
|
#include <fs_cache.h>
|
||||||
#include <fs_info.h>
|
#include <fs_info.h>
|
||||||
|
|
||||||
|
#include "AttributeIterator.h"
|
||||||
#include "DirectoryIterator.h"
|
#include "DirectoryIterator.h"
|
||||||
#include "ext2.h"
|
#include "ext2.h"
|
||||||
#include "Inode.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
|
#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 = {
|
fs_volume_ops gExt2VolumeOps = {
|
||||||
&ext2_unmount,
|
&ext2_unmount,
|
||||||
&ext2_read_fs_info,
|
&ext2_read_fs_info,
|
||||||
@@ -556,7 +757,25 @@ fs_vnode_ops gExt2VnodeOps = {
|
|||||||
&ext2_read_dir,
|
&ext2_read_dir,
|
||||||
&ext2_rewind_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 = {
|
static file_system_module_info sExt2FileSystem = {
|
||||||
|
|||||||
Reference in New Issue
Block a user