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:
parent
a72d0f2439
commit
956f541d96
198
src/add-ons/kernel/file_systems/btrfs/Attribute.cpp
Normal file
198
src/add-ons/kernel/file_systems/btrfs/Attribute.cpp
Normal 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;
|
||||
}
|
||||
|
54
src/add-ons/kernel/file_systems/btrfs/Attribute.h
Normal file
54
src/add-ons/kernel/file_systems/btrfs/Attribute.h
Normal 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
|
||||
|
88
src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp
Normal file
88
src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp
Normal 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;
|
||||
}
|
||||
|
29
src/add-ons/kernel/file_systems/btrfs/AttributeIterator.h
Normal file
29
src/add-ons/kernel/file_systems/btrfs/AttributeIterator.h
Normal 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
|
@ -6,6 +6,8 @@ UsePrivateKernelHeaders ;
|
||||
|
||||
KernelAddon btrfs :
|
||||
kernel_interface.cpp
|
||||
Attribute.cpp
|
||||
AttributeIterator.cpp
|
||||
BPlusTree.cpp
|
||||
Chunk.cpp
|
||||
CRCTable.cpp
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user