1/* 2 * Copyright 2017, Ch��� V�� Gia Hy, cvghy116@gmail.com. 3 * Copyright 2010-2011, J��r��me Duval, korli@users.berlios.de. 4 * Copyright 2010, Fran��ois Revol, <revol@free.fr>. 5 * Copyright 2004-2008, Axel D��rfler, axeld@pinc-software.de. 6 * This file may be used under the terms of the MIT License. 7 */ 8 9//! connection between pure inode and kernel_interface attributes 10 11 12#include "Attribute.h" 13#include "BTree.h" 14#include "CRCTable.h" 15#include "Utility.h" 16 17 18//#define TRACE_BTRFS 19#ifdef TRACE_BTRFS 20# define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x) 21#else 22# define TRACE(x...) ; 23#endif 24 25 26Attribute::Attribute(Inode* inode) 27 : 28 fVolume(inode->GetVolume()), 29 fInode(inode), 30 fName(NULL) 31{ 32} 33 34 35Attribute::Attribute(Inode* inode, attr_cookie* cookie) 36 : 37 fVolume(inode->GetVolume()), 38 fInode(inode), 39 fName(cookie->name) 40{ 41} 42 43 44Attribute::~Attribute() 45{ 46} 47 48 49status_t 50Attribute::CheckAccess(const char* name, int openMode) 51{ 52 return fInode->CheckPermissions(open_mode_to_access(openMode) 53 | (openMode & O_TRUNC ? W_OK : 0)); 54} 55 56 57status_t 58Attribute::Open(const char* name, int openMode, attr_cookie** _cookie) 59{ 60 TRACE("Open\n"); 61 status_t status = CheckAccess(name, openMode); 62 if (status < B_OK) 63 return status; 64 65 status = _Lookup(name, strlen(name)); 66 if (status < B_OK) 67 return status; 68 69 attr_cookie* cookie = new(std::nothrow) attr_cookie; 70 if (cookie == NULL) 71 return B_NO_MEMORY; 72 73 fName = name; 74 75 // initialize the cookie 76 strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH); 77 cookie->open_mode = openMode; 78 cookie->create = false; 79 80 *_cookie = cookie; 81 return B_OK; 82} 83 84 85status_t 86Attribute::Stat(struct stat& stat) 87{ 88 TRACE("Stat\n"); 89 90 size_t nameLength = strlen(fName); 91 btrfs_dir_entry* entries; 92 uint32 length; 93 status_t status = _Lookup(fName, nameLength, &entries, &length); 94 if (status < B_OK) 95 return status; 96 97 btrfs_dir_entry* entry; 98 status = _FindEntry(entries, length, fName, nameLength, &entry); 99 if (status != B_OK) { 100 free(entries); 101 return status; 102 } 103 104 // found an entry to stat 105 stat.st_type = B_XATTR_TYPE; 106 stat.st_size = entry->DataLength(); 107 free(entries); 108 return B_OK; 109} 110 111 112status_t 113Attribute::Read(attr_cookie* cookie, off_t pos, uint8* buffer, size_t* _length) 114{ 115 if (pos < 0LL) 116 return ERANGE; 117 118 size_t nameLength = strlen(fName); 119 btrfs_dir_entry* entries; 120 uint32 length; 121 status_t status = _Lookup(fName, nameLength, &entries, &length); 122 if (status < B_OK) 123 return status; 124 125 btrfs_dir_entry* entry; 126 status = _FindEntry(entries, length, fName, nameLength, &entry); 127 if (status != B_OK) { 128 free(entries); 129 return status; 130 } 131 132 // found an entry to read 133 if (pos + *_length > entry->DataLength()) 134 length = entry->DataLength() - pos; 135 else 136 length = *_length - pos; 137 memcpy(buffer, (uint8*)entry + entry->NameLength() 138 + sizeof(btrfs_dir_entry) + (uint32)pos, length); 139 *_length = length; 140 141 free(entries); 142 return B_OK; 143} 144 145 146status_t 147Attribute::_Lookup(const char* name, size_t nameLength, 148 btrfs_dir_entry** _entries, uint32* _length) 149{ 150 uint32 hash = calculate_crc((uint32)~1, (uint8*)name, nameLength); 151 struct btrfs_key key; 152 key.SetType(BTRFS_KEY_TYPE_XATTR_ITEM); 153 key.SetObjectID(fInode->ID()); 154 key.SetOffset(hash); 155 BTree::Path path(fInode->GetVolume()->FSTree()); 156 157 btrfs_dir_entry* entries; 158 uint32 length; 159 status_t status = fInode->GetVolume()->FSTree()->FindExact(&path, key, 160 (void**)&entries, &length); 161 if (status != B_OK) { 162 TRACE("AttributeIterator::Lookup(): Couldn't find entry with hash %" 163 B_PRIu32 " \"%s\"\n", hash, name); 164 return status; 165 } 166 167 if (_entries == NULL) 168 free(entries); 169 else 170 *_entries = entries; 171 172 if (_length != NULL) 173 *_length = length; 174 175 return B_OK; 176} 177 178 179status_t 180Attribute::_FindEntry(btrfs_dir_entry* entries, size_t length, 181 const char* name, size_t nameLength, btrfs_dir_entry** _entry) 182{ 183 btrfs_dir_entry* entry = entries; 184 uint16 current = 0; 185 while (current < length) { 186 current += entry->Length(); 187 break; 188 // TODO there could be several entries with the same name hash 189 entry = (btrfs_dir_entry*)((uint8*)entry + entry->Length()); 190 } 191 192 *_entry = entry; 193 return B_OK; 194} 195