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