xref: /haiku/src/add-ons/kernel/file_systems/btrfs/Attribute.cpp (revision 6aff37d1c79e20748c683ae224bd629f88a5b0be)
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 #include "BTree.h"
13 #include "CRCTable.h"
14 #include "Utility.h"
15 
16 
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
23 
24 
25 Attribute::Attribute(Inode* inode)
26 	:
27 	fVolume(inode->GetVolume()),
28 	fInode(inode),
29 	fName(NULL)
30 {
31 }
32 
33 
34 Attribute::Attribute(Inode* inode, attr_cookie* cookie)
35 	:
36 	fVolume(inode->GetVolume()),
37 	fInode(inode),
38 	fName(cookie->name)
39 {
40 }
41 
42 
43 Attribute::~Attribute()
44 {
45 }
46 
47 
48 status_t
49 Attribute::CheckAccess(const char* name, int openMode)
50 {
51 	return fInode->CheckPermissions(open_mode_to_access(openMode)
52 		| (openMode & O_TRUNC ? W_OK : 0));
53 }
54 
55 
56 status_t
57 Attribute::Open(const char* name, int openMode, attr_cookie** _cookie)
58 {
59 	TRACE("Open\n");
60 	status_t status = CheckAccess(name, openMode);
61 	if (status < B_OK)
62 		return status;
63 
64 	status = _Lookup(name, strlen(name));
65 	if (status < B_OK)
66 		return status;
67 
68 	attr_cookie* cookie = new(std::nothrow) attr_cookie;
69 	if (cookie == NULL)
70 		return B_NO_MEMORY;
71 
72 	fName = name;
73 
74 	// initialize the cookie
75 	strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
76 	cookie->open_mode = openMode;
77 	cookie->create = false;
78 
79 	*_cookie = cookie;
80 	return B_OK;
81 }
82 
83 
84 status_t
85 Attribute::Stat(struct stat& stat)
86 {
87 	TRACE("Stat\n");
88 
89 	size_t nameLength = strlen(fName);
90 	btrfs_dir_entry* entries;
91 	size_t length;
92 	status_t status = _Lookup(fName, nameLength, &entries, &length);
93 	if (status < B_OK)
94 		return status;
95 
96 	btrfs_dir_entry* entry;
97 	status = _FindEntry(entries, length, fName, nameLength, &entry);
98 	if (status != B_OK) {
99 		free(entries);
100 		return status;
101 	}
102 
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;
108 }
109 
110 
111 status_t
112 Attribute::Read(attr_cookie* cookie, off_t pos, uint8* buffer, size_t* _length)
113 {
114 	if (pos < 0LL)
115 		return ERANGE;
116 
117 	size_t nameLength = strlen(fName);
118 	btrfs_dir_entry* entries;
119 	size_t length;
120 	status_t status = _Lookup(fName, nameLength, &entries, &length);
121 	if (status < B_OK)
122 		return status;
123 
124 	btrfs_dir_entry* entry;
125 	status = _FindEntry(entries, length, fName, nameLength, &entry);
126 	if (status != B_OK) {
127 		free(entries);
128 		return status;
129 	}
130 
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;
139 
140 	free(entries);
141 	return B_OK;
142 }
143 
144 
145 status_t
146 Attribute::_Lookup(const char* name, size_t nameLength,
147 	btrfs_dir_entry** _entries, size_t* _length)
148 {
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);
154 
155 	btrfs_dir_entry* entries;
156 	size_t 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;
163 	}
164 
165 	if (_entries == NULL)
166 		free(entries);
167 	else
168 		*_entries = entries;
169 
170 	if (_length != NULL)
171 		*_length = length;
172 
173 	return B_OK;
174 }
175 
176 
177 status_t
178 Attribute::_FindEntry(btrfs_dir_entry* entries, size_t length,
179 	const char* name, size_t nameLength, btrfs_dir_entry** _entry)
180 {
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());
188 	}
189 
190 	*_entry = entry;
191 	return B_OK;
192 }
193