BTRFS: Node now holding Volume instead of cache to retrieve more values
[haiku.git] / src / add-ons / kernel / file_systems / btrfs / Attribute.cpp
blobddda28dfc5cf9c2e29d05a92b987d83d4ebecc0b
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 */
8 //! connection between pure inode and kernel_interface attributes
11 #include "Attribute.h"
12 #include "BTree.h"
13 #include "CRCTable.h"
14 #include "Utility.h"
17 //#define TRACE_BTRFS
18 #ifdef TRACE_BTRFS
19 # define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x)
20 #else
21 # define TRACE(x...) ;
22 #endif
25 Attribute::Attribute(Inode* inode)
27 fVolume(inode->GetVolume()),
28 fInode(inode),
29 fName(NULL)
34 Attribute::Attribute(Inode* inode, attr_cookie* cookie)
36 fVolume(inode->GetVolume()),
37 fInode(inode),
38 fName(cookie->name)
43 Attribute::~Attribute()
48 status_t
49 Attribute::CheckAccess(const char* name, int openMode)
51 return fInode->CheckPermissions(open_mode_to_access(openMode)
52 | (openMode & O_TRUNC ? W_OK : 0));
56 status_t
57 Attribute::Open(const char* name, int openMode, attr_cookie** _cookie)
59 TRACE("Open\n");
60 status_t status = CheckAccess(name, openMode);
61 if (status < B_OK)
62 return status;
64 status = _Lookup(name, strlen(name));
65 if (status < B_OK)
66 return status;
68 attr_cookie* cookie = new(std::nothrow) attr_cookie;
69 if (cookie == NULL)
70 return B_NO_MEMORY;
72 fName = name;
74 // initialize the cookie
75 strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
76 cookie->open_mode = openMode;
77 cookie->create = false;
79 *_cookie = cookie;
80 return B_OK;
84 status_t
85 Attribute::Stat(struct stat& stat)
87 TRACE("Stat\n");
89 size_t nameLength = strlen(fName);
90 btrfs_dir_entry* entries;
91 uint32 length;
92 status_t status = _Lookup(fName, nameLength, &entries, &length);
93 if (status < B_OK)
94 return status;
96 btrfs_dir_entry* entry;
97 status = _FindEntry(entries, length, fName, nameLength, &entry);
98 if (status != B_OK) {
99 free(entries);
100 return status;
103 // found an entry to stat
104 stat.st_type = B_XATTR_TYPE;
105 stat.st_size = entry->DataLength();
106 free(entries);
107 return B_OK;
111 status_t
112 Attribute::Read(attr_cookie* cookie, off_t pos, uint8* buffer, size_t* _length)
114 if (pos < 0LL)
115 return ERANGE;
117 size_t nameLength = strlen(fName);
118 btrfs_dir_entry* entries;
119 uint32 length;
120 status_t status = _Lookup(fName, nameLength, &entries, &length);
121 if (status < B_OK)
122 return status;
124 btrfs_dir_entry* entry;
125 status = _FindEntry(entries, length, fName, nameLength, &entry);
126 if (status != B_OK) {
127 free(entries);
128 return status;
131 // found an entry to read
132 if (pos + *_length > entry->DataLength())
133 length = entry->DataLength() - pos;
134 else
135 length = *_length - pos;
136 memcpy(buffer, (uint8*)entry + entry->NameLength()
137 + sizeof(btrfs_dir_entry) + (uint32)pos, length);
138 *_length = length;
140 free(entries);
141 return B_OK;
145 status_t
146 Attribute::_Lookup(const char* name, size_t nameLength,
147 btrfs_dir_entry** _entries, uint32* _length)
149 uint32 hash = calculate_crc((uint32)~1, (uint8*)name, nameLength);
150 struct btrfs_key key;
151 key.SetType(BTRFS_KEY_TYPE_XATTR_ITEM);
152 key.SetObjectID(fInode->ID());
153 key.SetOffset(hash);
155 btrfs_dir_entry* entries;
156 uint32 length;
157 status_t status = fInode->GetVolume()->FSTree()->FindExact(key,
158 (void**)&entries, &length);
159 if (status != B_OK) {
160 TRACE("AttributeIterator::Lookup(): Couldn't find entry with hash %"
161 B_PRIu32 " \"%s\"\n", hash, name);
162 return status;
165 if (_entries == NULL)
166 free(entries);
167 else
168 *_entries = entries;
170 if (_length != NULL)
171 *_length = length;
173 return B_OK;
177 status_t
178 Attribute::_FindEntry(btrfs_dir_entry* entries, size_t length,
179 const char* name, size_t nameLength, btrfs_dir_entry** _entry)
181 btrfs_dir_entry* entry = entries;
182 uint16 current = 0;
183 while (current < length) {
184 current += entry->Length();
185 break;
186 // TODO there could be several entries with the same name hash
187 entry = (btrfs_dir_entry*)((uint8*)entry + entry->Length());
190 *_entry = entry;
191 return B_OK;