Author: korli Date: 2010-10-20 23:40:35 +0200 (Wed, 20 Oct 2010) New Revision: 39036 Changeset: http://dev.haiku-os.org/changeset/39036 Added: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Attribute.cpp haiku/trunk/src/add-ons/kernel/file_systems/ext2/Attribute.h Removed: haiku/trunk/src/add-ons/kernel/file_systems/ext2/AttributeIterator.cpp haiku/trunk/src/add-ons/kernel/file_systems/ext2/AttributeIterator.h Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.cpp haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.h haiku/trunk/src/add-ons/kernel/file_systems/ext2/Jamfile haiku/trunk/src/add-ons/kernel/file_systems/ext2/ext2.h haiku/trunk/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp Log: ext3 inodes whose size is at least 256 bytes can also contain attributes (like smalldata for bfs). We now use the Attribute class from bfs (instead of AttributeIterator) to manage small data and block attributes, though it's still readonly. Added: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Attribute.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/Attribute.cpp (rev 0) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/Attribute.cpp 2010-10-20 21:40:35 UTC (rev 39036) @@ -0,0 +1,364 @@ +/* + * Copyright 2010, 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 "Utility.h" + +#include <stdio.h> + + +//#define TRACE_EXT2 +#ifdef TRACE_EXT2 +# define TRACE(x...) dprintf("\33[34mext2:\33[0m " x) +#else +# define TRACE(x...) ; +#endif + + +Attribute::Attribute(Inode* inode) + : + fVolume(inode->GetVolume()), + fBlock(fVolume), + fInode(inode), + fBodyEntry(NULL), + fBlockEntry(NULL), + fName(NULL) +{ + +} + + +Attribute::Attribute(Inode* inode, attr_cookie* cookie) + : + fVolume(inode->GetVolume()), + fBlock(fVolume), + fInode(inode), + fBodyEntry(NULL), + fBlockEntry(NULL), + fName(NULL) +{ + Find(cookie->name); +} + + +Attribute::~Attribute() +{ + Put(); +} + + +status_t +Attribute::InitCheck() +{ + return (fBodyEntry != NULL || fBlockEntry != NULL) ? B_OK : B_NO_INIT; +} + + +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::Find(const char* name) +{ + return _Find(name, -1); +} + + +status_t +Attribute::Find(int32 index) +{ + return _Find(NULL, index); +} + + +status_t +Attribute::GetName(char* name, size_t* _nameLength) +{ + if (fBodyEntry == NULL && fBlockEntry == NULL) + return B_NO_INIT; + if (fBodyEntry != NULL) + return _PrefixedName(fBodyEntry, name, _nameLength); + else + return _PrefixedName(fBlockEntry, name, _nameLength); +} + + +void +Attribute::Put() +{ + if (fBodyEntry != NULL) { + recursive_lock_unlock(&fInode->SmallDataLock()); + fBlock.Unset(); + fBodyEntry = NULL; + } + + if (fBlockEntry != NULL) { + fBlock.Unset(); + fBlockEntry = NULL; + } +} + + +status_t +Attribute::Create(const char* name, type_code type, int openMode, + attr_cookie** _cookie) +{ + status_t status = CheckAccess(name, openMode); + 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->type = type; + cookie->open_mode = openMode; + cookie->create = true; + + if (Find(name) == B_OK) { + // attribute already exists + if ((openMode & O_TRUNC) != 0) + _Truncate(); + } + *_cookie = cookie; + return B_OK; +} + + +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 = Find(name); + if (status < B_OK) + return status; + + attr_cookie* cookie = new(std::nothrow) attr_cookie; + if (cookie == NULL) + return B_NO_MEMORY; + + // initialize the cookie + strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH); + cookie->open_mode = openMode; + cookie->create = false; + + // Should we truncate the attribute? + if ((openMode & O_TRUNC) != 0) + _Truncate(); + + *_cookie = cookie; + return B_OK; +} + + +status_t +Attribute::Stat(struct stat& stat) +{ + TRACE("Stat\n"); + if (fBodyEntry == NULL && fBlockEntry == NULL) + return B_NO_INIT; + + stat.st_type = B_RAW_TYPE; + + if (fBodyEntry != NULL) + stat.st_size = fBodyEntry->ValueSize(); + else if (fBlockEntry != NULL) + stat.st_size = fBlockEntry->ValueSize(); + + return B_OK; +} + + +status_t +Attribute::Read(attr_cookie* cookie, off_t pos, uint8* buffer, size_t* _length) +{ + if (fBodyEntry == NULL && fBlockEntry == NULL) + return B_NO_INIT; + + if (pos < 0LL) + return ERANGE; + + size_t length = *_length; + const uint8* start = (uint8 *)fBlock.Block(); + if (fBlockEntry != NULL) { + pos += fBlockEntry->ValueOffset(); + if (((uint32)pos + length) > fVolume->BlockSize() + || length > fBlockEntry->ValueSize()) + return ERANGE; + } else { + start += fVolume->InodeBlockIndex(fInode->ID()) * fVolume->InodeSize(); + const uint8* end = start + fVolume->InodeSize(); + start += EXT2_INODE_NORMAL_SIZE + fInode->Node().ExtraInodeSize() + + sizeof(uint32); + pos += fBodyEntry->ValueOffset(); + if ((pos + length) > (end - start) || length > fBodyEntry->ValueSize()) + return ERANGE; + } + memcpy(buffer, start + (uint32)pos, length); + + *_length = length; + return B_OK; +} + + +status_t +Attribute::Write(Transaction& transaction, attr_cookie* cookie, off_t pos, + const uint8* buffer, size_t* _length, bool* _created) +{ + if (!cookie->create && fBodyEntry == NULL && fBlockEntry == NULL) + return B_NO_INIT; + + // TODO: Implement + return B_ERROR; +} + + +status_t +Attribute::_Truncate() +{ + // TODO: Implement + return B_ERROR; +} + + +status_t +Attribute::_Find(const char* name, int32 index) +{ + Put(); + + fName = name; + + // try to find it in the small data region + if (fInode->HasExtraAttributes() + && recursive_lock_lock(&fInode->SmallDataLock()) == B_OK) { + uint32 block; + fVolume->GetInodeBlock(fInode->ID(), block); + + if (block != 0) { + fBlock.SetTo(block); + const uint8* start = fBlock.Block() + + fVolume->InodeBlockIndex(fInode->ID()) * fVolume->InodeSize(); + const uint8* end = start + fVolume->InodeSize(); + int32 count = 0; + if (_FindAttributeBody(start + EXT2_INODE_NORMAL_SIZE + + fInode->Node().ExtraInodeSize(), end, name, index, &count, + &fBodyEntry) == B_OK) + return B_OK; + index -= count; + } + + recursive_lock_unlock(&fInode->SmallDataLock()); + fBlock.Unset(); + } + + // then, search in the attribute directory + if (fInode->Node().ExtendedAttributesBlock() != 0) { + fBlock.SetTo(fInode->Node().ExtendedAttributesBlock()); + if (_FindAttributeBlock(fBlock.Block(), + fBlock.Block() + fVolume->BlockSize(), name, index, NULL, + &fBlockEntry) == B_OK) + return B_OK; + fBlock.Unset(); + } + + return B_ENTRY_NOT_FOUND; +} + + +status_t +Attribute::_FindAttributeBody(const uint8* start, const uint8* end, + const char* name, int32 index, int32 *count, ext2_xattr_entry** _entry) +{ + TRACE("_FindAttributeBody %p %p %s\n", start, end, name); + if (*((uint32*)start) != EXT2_XATTR_MAGIC) + return B_BAD_DATA; + return _FindAttribute(start + sizeof(uint32), end, name, index, count, + _entry); +} + + +status_t +Attribute::_FindAttributeBlock(const uint8* start, const uint8* end, const char* name, + int32 index, int32 *count, ext2_xattr_entry** _entry) +{ + TRACE("_FindAttributeBlock %p %p %s\n", start, end, name); + ext2_xattr_header *header = (ext2_xattr_header*)start; + if (!header->IsValid()) + return B_BAD_DATA; + + return _FindAttribute(start + sizeof(ext2_xattr_header), end, name, index, + count, _entry); +} + + +status_t +Attribute::_FindAttribute(const uint8* start, const uint8* end, const char* name, + int32 index, int32 *count, ext2_xattr_entry** _entry) +{ + TRACE("_FindAttribute %p %p %s\n", start, end, name); + char buffer[EXT2_XATTR_NAME_LENGTH]; + + int32 i = 0; + while (start < end) { + ext2_xattr_entry* entry = (ext2_xattr_entry*)start; + if (!entry->IsValid()) + break; + + size_t length = EXT2_XATTR_NAME_LENGTH; + if ((name != NULL && _PrefixedName(entry, buffer, &length) == B_OK + && strncmp(name, buffer, length) == 0) || index == i) { + *_entry = entry; + return B_OK; + } + start += entry->Length(); + i++; + } + + if (count != NULL) + *count = i; + return B_ENTRY_NOT_FOUND; +} + + +status_t +Attribute::_PrefixedName(ext2_xattr_entry* entry, char* _name, size_t* _nameLength) +{ + const char *indexNames[] = { "0", "user" }; + size_t l = 0; + + if (entry->NameIndex() < ((sizeof(indexNames) / sizeof(indexNames[0])))) + l = snprintf(_name, *_nameLength, "%s.%s.%.*s", + "linux", indexNames[entry->NameIndex()], entry->NameLength(), + entry->name); + else + l = snprintf(_name, *_nameLength, "%s.%d.%.*s", + "linux", entry->NameIndex(), entry->NameLength(), entry->name); + if (l < 1 || l > *_nameLength - 1) + return ENOBUFS; + + *_nameLength = l + 1; + _name[l] = '\0'; + + return B_OK; +} + Added: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Attribute.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/Attribute.h (rev 0) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/Attribute.h 2010-10-20 21:40:35 UTC (rev 39036) @@ -0,0 +1,72 @@ +/* + * Copyright 2010, 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 InitCheck(); + status_t CheckAccess(const char* name, int openMode); + + status_t Find(const char* name); + status_t Find(int32 index); + status_t GetName(char* name, size_t* _nameLength); + void Put(); + + 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); + status_t Write(Transaction& transaction, attr_cookie* cookie, + off_t pos, const uint8* buffer, + size_t* _length, bool* _created); + +private: + status_t _Truncate(); + status_t _Find(const char* name, int32 index); + status_t _FindAttributeBody(const uint8* start, const uint8* end, + const char* name, int32 index, int32 *count, + ext2_xattr_entry** entry); + status_t _FindAttributeBlock(const uint8* start, const uint8* end, + const char* name, int32 index, int32 *count, + ext2_xattr_entry** entry); + status_t _FindAttribute(const uint8* start, const uint8* end, + const char* name, int32 index, int32 *count, + ext2_xattr_entry** entry); + status_t _PrefixedName(ext2_xattr_entry* entry, char* _name, + size_t* _nameLength); + + ::Volume* fVolume; + CachedBlock fBlock; + Inode* fInode; + ext2_xattr_entry* fBodyEntry; + ext2_xattr_entry* fBlockEntry; + const char* fName; +}; + +#endif // ATTRIBUTE_H Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.cpp 2010-10-20 21:36:23 UTC (rev 39035) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.cpp 2010-10-20 21:40:35 UTC (rev 39036) @@ -32,9 +32,11 @@ fCache(NULL), fMap(NULL), fCached(false), + fHasExtraAttributes(false), fAttributesBlock(NULL) { rw_lock_init(&fLock, "ext2 inode"); + recursive_lock_init(&fSmallDataLock, "ext2 inode small data"); TRACE("Inode::Inode(): ext2_inode: %lu, disk inode: %lu\n", sizeof(ext2_inode), fVolume->InodeSize()); @@ -70,6 +72,7 @@ fInitStatus(B_NO_INIT) { rw_lock_init(&fLock, "ext2 inode"); + recursive_lock_init(&fSmallDataLock, "ext2 inode small data"); TRACE("Inode::Inode(): ext2_inode: %lu, disk inode: %lu\n", sizeof(ext2_inode), fVolume->InodeSize()); @@ -476,7 +479,7 @@ size_t length = *_length; if (!fAttributesBlock) { - uint32 block = B_LENDIAN_TO_HOST_INT32(Node().file_access_control); + uint32 block = Node().ExtendedAttributesBlock(); if (block == 0) return B_ENTRY_NOT_FOUND; Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.h 2010-10-20 21:36:23 UTC (rev 39035) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/Inode.h 2010-10-20 21:40:35 UTC (rev 39036) @@ -37,6 +37,8 @@ status_t UpdateNodeFromDisk(); status_t WriteBack(Transaction& transaction); + recursive_lock& SmallDataLock() { return fSmallDataLock; } + bool IsDirectory() const { return S_ISDIR(Mode()); } bool IsFile() const @@ -148,6 +150,8 @@ // information is always the same size (except in ext4) ext2_xattr_header* fAttributesBlock; status_t fInitStatus; + + mutable recursive_lock fSmallDataLock; }; Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/Jamfile =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/Jamfile 2010-10-20 21:36:23 UTC (rev 39035) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/Jamfile 2010-10-20 21:40:35 UTC (rev 39036) @@ -15,7 +15,7 @@ Volume.cpp DataStream.cpp Inode.cpp - AttributeIterator.cpp + Attribute.cpp DirectoryIterator.cpp HTree.cpp HTreeEntryIterator.cpp Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/ext2.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/ext2.h 2010-10-20 21:36:23 UTC (rev 39035) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/ext2.h 2010-10-20 21:40:35 UTC (rev 39036) @@ -349,6 +349,9 @@ return B_LENDIAN_TO_HOST_INT32(size); } + uint32 ExtendedAttributesBlock() const + { return B_LENDIAN_TO_HOST_INT32(file_access_control);} + uint16 ExtraInodeSize() const { return B_LENDIAN_TO_HOST_INT16(extra_inode_size); } Modified: haiku/trunk/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp 2010-10-20 21:36:23 UTC (rev 39035) +++ haiku/trunk/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp 2010-10-20 21:40:35 UTC (rev 39036) @@ -1,4 +1,5 @@ /* + * Copyright 2010, Jérôme Duval, korli@xxxxxxxxxxxxxxxxx * Copyright 2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx * This file may be used under the terms of the MIT License. */ @@ -15,7 +16,7 @@ #include <NodeMonitor.h> #include <util/AutoLock.h> -#include "AttributeIterator.h" +#include "Attribute.h" #include "CachedBlock.h" #include "DirectoryIterator.h" #include "ext2.h" @@ -1416,11 +1417,11 @@ if (!inode->IsFile()) return EINVAL; - AttributeIterator* iterator = new(std::nothrow) AttributeIterator(inode); - if (iterator == NULL) + int32 *index = new(std::nothrow) int32; + if (index == NULL) return B_NO_MEMORY; - - *_cookie = iterator; + *index = 0; + *(int32**)_cookie = index; return B_OK; } @@ -1436,7 +1437,7 @@ ext2_free_attr_dir_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie) { TRACE("%s()\n", __FUNCTION__); - delete (AttributeIterator *)_cookie; + delete (int32 *)_cookie; return B_OK; } @@ -1447,17 +1448,22 @@ uint32* _num) { Inode* inode = (Inode*)_node->private_node; - AttributeIterator *iterator = (AttributeIterator *)_cookie; + int32 index = *(int32 *)_cookie; + Attribute attribute(inode); TRACE("%s()\n", __FUNCTION__); size_t length = bufferSize; - status_t status = iterator->GetNext(dirent->d_name, &length); + status_t status = attribute.Find(index); if (status == B_ENTRY_NOT_FOUND) { *_num = 0; return B_OK; } else if (status != B_OK) return status; + status = attribute.GetName(dirent->d_name, &length); + if (status != B_OK) + return B_OK; + Volume* volume = (Volume*)_volume->private_volume; dirent->d_dev = volume->ID(); @@ -1465,6 +1471,7 @@ dirent->d_reclen = sizeof(struct dirent) + length; *_num = 1; + *(int32*)_cookie = index + 1; return B_OK; } @@ -1472,9 +1479,9 @@ static status_t ext2_rewind_attr_dir(fs_volume* _volume, fs_vnode* _node, void* _cookie) { - AttributeIterator *iterator = (AttributeIterator *)_cookie; + *(int32*)_cookie = 0; TRACE("%s()\n", __FUNCTION__); - return iterator->Rewind(); + return B_OK; } @@ -1492,31 +1499,15 @@ 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; + Inode* inode = (Inode*)_node->private_node; + Attribute attribute(inode); 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; + return attribute.Open(name, openMode, (attr_cookie**)_cookie); } @@ -1532,31 +1523,23 @@ ext2_free_attr_cookie(fs_volume* _volume, fs_vnode* _node, void* cookie) { - ext2_xattr_entry *entry = (ext2_xattr_entry *)cookie; - - delete entry; + delete (attr_cookie*)cookie; 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) +ext2_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; - //Volume* volume = (Volume*)_volume->private_volume; - ext2_xattr_entry *entry = (ext2_xattr_entry *)cookie; - if (!entry->IsValid()) - return EINVAL; + Attribute attribute(inode, cookie); - if (pos < 0 || (pos + *length) > entry->ValueSize()) - return ERANGE; - - return inode->AttributeBlockReadAt(entry->ValueOffset() + pos, - (uint8 *)buffer, length); + return attribute.Read(cookie, pos, (uint8*)buffer, _length); } @@ -1571,15 +1554,14 @@ static status_t ext2_read_attr_stat(fs_volume* _volume, fs_vnode* _node, - void* cookie, struct stat* stat) + void* _cookie, struct stat* stat) { - ext2_xattr_entry *entry = (ext2_xattr_entry *)cookie; + attr_cookie* cookie = (attr_cookie*)_cookie; + Inode* inode = (Inode*)_node->private_node; - stat->st_type = B_RAW_TYPE; - stat->st_size = entry->ValueSize(); - TRACE("%s: st_size %d\n", __FUNCTION__, stat->st_size); + Attribute attribute(inode, cookie); - return B_OK; + return attribute.Stat(*stat); }