Author: korli Date: 2011-01-31 20:16:14 +0100 (Mon, 31 Jan 2011) New Revision: 40335 Changeset: http://dev.haiku-os.org/changeset/40335 Added: haiku/trunk/src/add-ons/kernel/file_systems/btrfs/Attribute.cpp haiku/trunk/src/add-ons/kernel/file_systems/btrfs/Attribute.h haiku/trunk/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp haiku/trunk/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.h Modified: haiku/trunk/src/add-ons/kernel/file_systems/btrfs/Jamfile haiku/trunk/src/add-ons/kernel/file_systems/btrfs/btrfs.h haiku/trunk/src/add-ons/kernel/file_systems/btrfs/kernel_interface.cpp Log: added read only attribute support for btrfs. Added: haiku/trunk/src/add-ons/kernel/file_systems/btrfs/Attribute.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/btrfs/Attribute.cpp (rev 0) +++ haiku/trunk/src/add-ons/kernel/file_systems/btrfs/Attribute.cpp 2011-01-31 19:16:14 UTC (rev 40335) @@ -0,0 +1,198 @@ +/* + * Copyright 2010-2011, Jérôme Duval, korli@xxxxxxxxxxxxxxxxx + * Copyright 2010, François Revol, <revol@xxxxxxx>. + * Copyright 2004-2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx + * 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; +} + Added: haiku/trunk/src/add-ons/kernel/file_systems/btrfs/Attribute.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/btrfs/Attribute.h (rev 0) +++ haiku/trunk/src/add-ons/kernel/file_systems/btrfs/Attribute.h 2011-01-31 19:16:14 UTC (rev 40335) @@ -0,0 +1,54 @@ +/* + * Copyright 2010-2011, Jérôme Duval, korli@xxxxxxxxxxxxxxxxx + * Copyright 2004-2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx + * 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 + Added: haiku/trunk/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp (rev 0) +++ haiku/trunk/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.cpp 2011-01-31 19:16:14 UTC (rev 40335) @@ -0,0 +1,88 @@ +/* + * Copyright 2011, Jérôme Duval, korli@xxxxxxxxxxxxxxxxx + * 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; +} + Added: haiku/trunk/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.h (rev 0) +++ haiku/trunk/src/add-ons/kernel/file_systems/btrfs/AttributeIterator.h 2011-01-31 19:16:14 UTC (rev 40335) @@ -0,0 +1,29 @@ +/* + * Copyright 2011, Jérôme Duval, korli@xxxxxxxxxxxxxxxxx + * 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 Modified: haiku/trunk/src/add-ons/kernel/file_systems/btrfs/Jamfile =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/btrfs/Jamfile 2011-01-31 18:29:20 UTC (rev 40334) +++ haiku/trunk/src/add-ons/kernel/file_systems/btrfs/Jamfile 2011-01-31 19:16:14 UTC (rev 40335) @@ -6,6 +6,8 @@ KernelAddon btrfs : kernel_interface.cpp + Attribute.cpp + AttributeIterator.cpp BPlusTree.cpp Chunk.cpp CRCTable.cpp Modified: haiku/trunk/src/add-ons/kernel/file_systems/btrfs/btrfs.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/btrfs/btrfs.h 2011-01-31 18:29:20 UTC (rev 40334) +++ haiku/trunk/src/add-ons/kernel/file_systems/btrfs/btrfs.h 2011-01-31 19:16:14 UTC (rev 40335) @@ -308,6 +308,7 @@ #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 Modified: haiku/trunk/src/add-ons/kernel/file_systems/btrfs/kernel_interface.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/btrfs/kernel_interface.cpp 2011-01-31 18:29:20 UTC (rev 40334) +++ haiku/trunk/src/add-ons/kernel/file_systems/btrfs/kernel_interface.cpp 2011-01-31 19:16:14 UTC (rev 40335) @@ -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 @@ 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 @@ } +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 @@ &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, };