added read only attribute support for btrfs.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40335 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval 2011-01-31 19:16:14 +00:00
parent a72d0f2439
commit 956f541d96
7 changed files with 560 additions and 16 deletions

View File

@ -0,0 +1,198 @@
/*
* Copyright 2010-2011, Jérôme Duval, korli@users.berlios.de.
* Copyright 2010, François Revol, <revol@free.fr>.
* Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License.
*/
//! connection between pure inode and kernel_interface attributes
#include "Attribute.h"
#include <new>
#include <stdio.h>
#include <stdlib.h>
#include "BPlusTree.h"
#include "CRCTable.h"
#include "Utility.h"
//#define TRACE_BTRFS
#ifdef TRACE_BTRFS
# define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x)
#else
# define TRACE(x...) ;
#endif
Attribute::Attribute(Inode* inode)
:
fVolume(inode->GetVolume()),
fInode(inode),
fName(NULL)
{
}
Attribute::Attribute(Inode* inode, attr_cookie* cookie)
:
fVolume(inode->GetVolume()),
fInode(inode),
fName(cookie->name)
{
}
Attribute::~Attribute()
{
}
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::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 = _Lookup(name, strlen(name));
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->open_mode = openMode;
cookie->create = false;
*_cookie = cookie;
return B_OK;
}
status_t
Attribute::Stat(struct stat& stat)
{
TRACE("Stat\n");
size_t nameLength = strlen(fName);
btrfs_dir_entry *entries;
size_t length;
status_t status = _Lookup(fName, nameLength, &entries, &length);
if (status < B_OK)
return status;
btrfs_dir_entry *entry;
status = _FindEntry(entries, length, fName, nameLength, &entry);
if (status != B_OK) {
free(entries);
return status;
}
// found an entry to stat
stat.st_type = B_RAW_TYPE;
stat.st_size = entry->DataLength();
free(entries);
return B_OK;
}
status_t
Attribute::Read(attr_cookie* cookie, off_t pos, uint8* buffer, size_t* _length)
{
if (pos < 0LL)
return ERANGE;
size_t nameLength = strlen(fName);
btrfs_dir_entry *entries;
size_t length;
status_t status = _Lookup(fName, nameLength, &entries, &length);
if (status < B_OK)
return status;
btrfs_dir_entry *entry;
status = _FindEntry(entries, length, fName, nameLength, &entry);
if (status != B_OK) {
free(entries);
return status;
}
// found an entry to read
if (pos + *_length > entry->DataLength())
length = entry->DataLength() - pos;
else
length = *_length - pos;
memcpy(buffer, (uint8*)entry + entry->NameLength()
+ sizeof(btrfs_dir_entry) + (uint32)pos, length);
*_length = length;
free(entries);
return B_OK;
}
status_t
Attribute::_Lookup(const char* name, size_t nameLength,
btrfs_dir_entry **_entries, size_t *_length)
{
uint32 hash = calculate_crc((uint32)~1, (uint8*)name, nameLength);
struct btrfs_key key;
key.SetType(BTRFS_KEY_TYPE_XATTR_ITEM);
key.SetObjectID(fInode->ID());
key.SetOffset(hash);
btrfs_dir_entry *entries;
size_t length;
status_t status = fInode->GetVolume()->FSTree()->FindExact(key,
(void**)&entries, &length);
if (status != B_OK) {
TRACE("AttributeIterator::Lookup(): Couldn't find entry with hash %lu "
"\"%s\"\n", hash, name);
return status;
}
if (_entries == NULL)
free(entries);
else
*_entries = entries;
if (_length != NULL)
*_length = length;
return B_OK;
}
status_t
Attribute::_FindEntry(btrfs_dir_entry *entries, size_t length,
const char* name, size_t nameLength, btrfs_dir_entry **_entry)
{
btrfs_dir_entry *entry = entries;
uint16 current = 0;
while (current < length) {
current += entry->Length();
break;
// TODO there could be several entries with the same name hash
entry = (btrfs_dir_entry *)((uint8*)entry + entry->Length());
}
*_entry = entry;
return B_OK;
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2010-2011, Jérôme Duval, korli@users.berlios.de.
* Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
* 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 CheckAccess(const char* name, int openMode);
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);
private:
status_t _Lookup(const char* name, size_t nameLength,
btrfs_dir_entry **entries = NULL,
size_t *length = NULL);
status_t _FindEntry(btrfs_dir_entry *entries,
size_t length, const char* name,
size_t nameLength,
btrfs_dir_entry **_entry);
::Volume* fVolume;
Inode* fInode;
const char* fName;
};
#endif // ATTRIBUTE_H

View File

@ -0,0 +1,88 @@
/*
* Copyright 2011, Jérôme Duval, korli@users.berlios.de.
* This file may be used under the terms of the MIT License.
*/
#include "AttributeIterator.h"
#include <new>
#include <stdlib.h>
//#define TRACE_BTRFS
#ifdef TRACE_BTRFS
# define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x)
#else
# define TRACE(x...) ;
#endif
# define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x)
AttributeIterator::AttributeIterator(Inode* inode)
:
fOffset(-1ULL),
fInode(inode),
fIterator(NULL)
{
struct btrfs_key key;
key.SetType(BTRFS_KEY_TYPE_XATTR_ITEM);
key.SetObjectID(inode->ID());
fIterator = new(std::nothrow) TreeIterator(inode->GetVolume()->FSTree(),
key);
}
AttributeIterator::~AttributeIterator()
{
delete fIterator;
}
status_t
AttributeIterator::InitCheck()
{
return fIterator != NULL ? B_OK : B_NO_MEMORY;
}
status_t
AttributeIterator::GetNext(char* name, size_t* _nameLength)
{
btrfs_key key;
btrfs_dir_entry *entries;
size_t entries_length;
status_t status = fIterator->GetPreviousEntry(key, (void**)&entries,
&entries_length);
if (status != B_OK)
return status;
btrfs_dir_entry *entry = entries;
uint16 current = 0;
while (current < entries_length) {
current += entry->Length();
break;
// TODO there could be several entries with the same name hash
entry = (btrfs_dir_entry *)((uint8*)entry + entry->Length());
}
TRACE("DirectoryIterator::GetNext() entries_length %ld name_length %d\n",
entries_length, entry->NameLength());
memcpy(name, entry + 1, entry->NameLength());
name[entry->NameLength()] = '\0';
*_nameLength = entry->NameLength();
free(entries);
return B_OK;
}
status_t
AttributeIterator::Rewind()
{
fIterator->Rewind();
fOffset = -1ULL;
return B_OK;
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2011, Jérôme Duval, korli@users.berlios.de.
* This file may be used under the terms of the MIT License.
*/
#ifndef ATTRIBUTEITERATOR_H
#define ATTRIBUTEITERATOR_H
#include "BPlusTree.h"
#include "Inode.h"
class AttributeIterator {
public:
AttributeIterator(Inode* inode);
~AttributeIterator();
status_t InitCheck();
status_t GetNext(char* name, size_t* _nameLength);
status_t Rewind();
private:
uint64 fOffset;
Inode* fInode;
TreeIterator* fIterator;
};
#endif // ATTRIBUTEITERATOR_H

View File

@ -6,6 +6,8 @@ UsePrivateKernelHeaders ;
KernelAddon btrfs :
kernel_interface.cpp
Attribute.cpp
AttributeIterator.cpp
BPlusTree.cpp
Chunk.cpp
CRCTable.cpp

View File

@ -308,6 +308,7 @@ struct btrfs_extent_data {
#define BTRFS_KEY_TYPE_INODE_ITEM 1
#define BTRFS_KEY_TYPE_INODE_REF 12
#define BTRFS_KEY_TYPE_ROOT_ITEM 132
#define BTRFS_KEY_TYPE_XATTR_ITEM 24
#define BTRFS_EXTENT_DATA_INLINE 0
#define BTRFS_EXTENT_DATA_REGULAR 1

View File

@ -16,6 +16,8 @@
#include <NodeMonitor.h>
#include <util/AutoLock.h>
#include "Attribute.h"
#include "AttributeIterator.h"
#include "btrfs.h"
#include "DirectoryIterator.h"
#include "Inode.h"
@ -291,7 +293,6 @@ btrfs_get_file_map(fs_volume* _volume, fs_vnode* _node, off_t offset,
size_t size, struct file_io_vec* vecs, size_t* _count)
{
TRACE("btrfs_get_file_map()\n");
Volume* volume = (Volume*)_volume->private_volume;
Inode* inode = (Inode*)_node->private_node;
size_t index = 0, max = *_count;
@ -563,6 +564,177 @@ btrfs_free_dir_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie)
}
static status_t
btrfs_open_attr_dir(fs_volume *_volume, fs_vnode *_node, void **_cookie)
{
Inode* inode = (Inode*)_node->private_node;
TRACE("%s()\n", __FUNCTION__);
// on directories too ?
if (!inode->IsFile())
return EINVAL;
AttributeIterator* iterator = new(std::nothrow) AttributeIterator(inode);
if (iterator == NULL || iterator->InitCheck() != B_OK) {
delete iterator;
return B_NO_MEMORY;
}
*_cookie = iterator;
return B_OK;
}
static status_t
btrfs_close_attr_dir(fs_volume* _volume, fs_vnode* _node, void* cookie)
{
TRACE("%s()\n", __FUNCTION__);
return B_OK;
}
static status_t
btrfs_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
btrfs_read_attr_dir(fs_volume* _volume, fs_vnode* _node,
void* _cookie, struct dirent* dirent, size_t bufferSize,
uint32* _num)
{
TRACE("%s()\n", __FUNCTION__);
AttributeIterator* iterator = (AttributeIterator*)_cookie;
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_reclen = sizeof(struct dirent) + length;
*_num = 1;
return B_OK;
}
static status_t
btrfs_rewind_attr_dir(fs_volume* _volume, fs_vnode* _node, void* _cookie)
{
DirectoryIterator* iterator = (DirectoryIterator*)_cookie;
return iterator->Rewind();
}
/* attribute operations */
static status_t
btrfs_create_attr(fs_volume* _volume, fs_vnode* _node,
const char* name, uint32 type, int openMode, void** _cookie)
{
return EROFS;
}
static status_t
btrfs_open_attr(fs_volume* _volume, fs_vnode* _node, const char* name,
int openMode, void** _cookie)
{
TRACE("%s()\n", __FUNCTION__);
Inode* inode = (Inode*)_node->private_node;
Attribute attribute(inode);
return attribute.Open(name, openMode, (attr_cookie**)_cookie);
}
static status_t
btrfs_close_attr(fs_volume* _volume, fs_vnode* _node,
void* cookie)
{
return B_OK;
}
static status_t
btrfs_free_attr_cookie(fs_volume* _volume, fs_vnode* _node,
void* cookie)
{
delete (attr_cookie*)cookie;
return B_OK;
}
static status_t
btrfs_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;
Attribute attribute(inode, cookie);
return attribute.Read(cookie, pos, (uint8*)buffer, _length);
}
static status_t
btrfs_write_attr(fs_volume* _volume, fs_vnode* _node, void* cookie,
off_t pos, const void* buffer, size_t* length)
{
return EROFS;
}
static status_t
btrfs_read_attr_stat(fs_volume* _volume, fs_vnode* _node,
void* _cookie, struct stat* stat)
{
attr_cookie* cookie = (attr_cookie*)_cookie;
Inode* inode = (Inode*)_node->private_node;
Attribute attribute(inode, cookie);
return attribute.Stat(*stat);
}
static status_t
btrfs_write_attr_stat(fs_volume* _volume, fs_vnode* _node,
void* cookie, const struct stat* stat, int statMask)
{
return EROFS;
}
static status_t
btrfs_rename_attr(fs_volume* _volume, fs_vnode* fromVnode,
const char* fromName, fs_vnode* toVnode, const char* toName)
{
return EROFS;
}
static status_t
btrfs_remove_attr(fs_volume* _volume, fs_vnode* vnode,
const char* name)
{
return EROFS;
}
fs_volume_ops gBtrfsVolumeOps = {
&btrfs_unmount,
&btrfs_read_fs_info,
@ -625,23 +797,23 @@ fs_vnode_ops gBtrfsVnodeOps = {
&btrfs_rewind_dir,
/* attribute directory operations */
NULL, // fs_open_attr_dir,
NULL, // fs_close_attr_dir,
NULL, // fs_free_attr_dir_cookie,
NULL, // fs_read_attr_dir,
NULL, // fs_rewind_attr_dir,
&btrfs_open_attr_dir,
&btrfs_close_attr_dir,
&btrfs_free_attr_dir_cookie,
&btrfs_read_attr_dir,
&btrfs_rewind_attr_dir,
/* attribute operations */
NULL, // fs_create_attr,
NULL, // fs_open_attr,
NULL, // fs_close_attr,
NULL, // fs_free_attr_cookie,
NULL, // fs_read_attr,
NULL, // fs_write_attr,
NULL, // fs_read_attr_stat,
NULL, // fs_write_attr_stat,
NULL, // fs_rename_attr,
NULL, // fs_remove_attr,
&btrfs_create_attr,
&btrfs_open_attr,
&btrfs_close_attr,
&btrfs_free_attr_cookie,
&btrfs_read_attr,
&btrfs_write_attr,
&btrfs_read_attr_stat,
&btrfs_write_attr_stat,
&btrfs_rename_attr,
&btrfs_remove_attr,
};