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:
@@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2011, Jérôme Duval, [email protected].
|
||||||
|
* Copyright 2010, François Revol, <[email protected]>.
|
||||||
|
* Copyright 2004-2008, Axel Dörfler, [email protected].
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2011, Jérôme Duval, [email protected].
|
||||||
|
* Copyright 2004-2008, Axel Dörfler, [email protected].
|
||||||
|
* 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
|
||||||
|
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Jérôme Duval, [email protected].
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Jérôme Duval, [email protected].
|
||||||
|
* 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 :
|
KernelAddon btrfs :
|
||||||
kernel_interface.cpp
|
kernel_interface.cpp
|
||||||
|
Attribute.cpp
|
||||||
|
AttributeIterator.cpp
|
||||||
BPlusTree.cpp
|
BPlusTree.cpp
|
||||||
Chunk.cpp
|
Chunk.cpp
|
||||||
CRCTable.cpp
|
CRCTable.cpp
|
||||||
|
|||||||
@@ -308,6 +308,7 @@ struct btrfs_extent_data {
|
|||||||
#define BTRFS_KEY_TYPE_INODE_ITEM 1
|
#define BTRFS_KEY_TYPE_INODE_ITEM 1
|
||||||
#define BTRFS_KEY_TYPE_INODE_REF 12
|
#define BTRFS_KEY_TYPE_INODE_REF 12
|
||||||
#define BTRFS_KEY_TYPE_ROOT_ITEM 132
|
#define BTRFS_KEY_TYPE_ROOT_ITEM 132
|
||||||
|
#define BTRFS_KEY_TYPE_XATTR_ITEM 24
|
||||||
|
|
||||||
#define BTRFS_EXTENT_DATA_INLINE 0
|
#define BTRFS_EXTENT_DATA_INLINE 0
|
||||||
#define BTRFS_EXTENT_DATA_REGULAR 1
|
#define BTRFS_EXTENT_DATA_REGULAR 1
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
#include <NodeMonitor.h>
|
#include <NodeMonitor.h>
|
||||||
#include <util/AutoLock.h>
|
#include <util/AutoLock.h>
|
||||||
|
|
||||||
|
#include "Attribute.h"
|
||||||
|
#include "AttributeIterator.h"
|
||||||
#include "btrfs.h"
|
#include "btrfs.h"
|
||||||
#include "DirectoryIterator.h"
|
#include "DirectoryIterator.h"
|
||||||
#include "Inode.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)
|
size_t size, struct file_io_vec* vecs, size_t* _count)
|
||||||
{
|
{
|
||||||
TRACE("btrfs_get_file_map()\n");
|
TRACE("btrfs_get_file_map()\n");
|
||||||
Volume* volume = (Volume*)_volume->private_volume;
|
|
||||||
Inode* inode = (Inode*)_node->private_node;
|
Inode* inode = (Inode*)_node->private_node;
|
||||||
size_t index = 0, max = *_count;
|
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 = {
|
fs_volume_ops gBtrfsVolumeOps = {
|
||||||
&btrfs_unmount,
|
&btrfs_unmount,
|
||||||
&btrfs_read_fs_info,
|
&btrfs_read_fs_info,
|
||||||
@@ -625,23 +797,23 @@ fs_vnode_ops gBtrfsVnodeOps = {
|
|||||||
&btrfs_rewind_dir,
|
&btrfs_rewind_dir,
|
||||||
|
|
||||||
/* attribute directory operations */
|
/* attribute directory operations */
|
||||||
NULL, // fs_open_attr_dir,
|
&btrfs_open_attr_dir,
|
||||||
NULL, // fs_close_attr_dir,
|
&btrfs_close_attr_dir,
|
||||||
NULL, // fs_free_attr_dir_cookie,
|
&btrfs_free_attr_dir_cookie,
|
||||||
NULL, // fs_read_attr_dir,
|
&btrfs_read_attr_dir,
|
||||||
NULL, // fs_rewind_attr_dir,
|
&btrfs_rewind_attr_dir,
|
||||||
|
|
||||||
/* attribute operations */
|
/* attribute operations */
|
||||||
NULL, // fs_create_attr,
|
&btrfs_create_attr,
|
||||||
NULL, // fs_open_attr,
|
&btrfs_open_attr,
|
||||||
NULL, // fs_close_attr,
|
&btrfs_close_attr,
|
||||||
NULL, // fs_free_attr_cookie,
|
&btrfs_free_attr_cookie,
|
||||||
NULL, // fs_read_attr,
|
&btrfs_read_attr,
|
||||||
NULL, // fs_write_attr,
|
&btrfs_write_attr,
|
||||||
NULL, // fs_read_attr_stat,
|
&btrfs_read_attr_stat,
|
||||||
NULL, // fs_write_attr_stat,
|
&btrfs_write_attr_stat,
|
||||||
NULL, // fs_rename_attr,
|
&btrfs_rename_attr,
|
||||||
NULL, // fs_remove_attr,
|
&btrfs_remove_attr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user