xref: /haiku/src/add-ons/kernel/file_systems/btrfs/Attribute.cpp (revision f2b4344867e97c3f4e742a1b4a15e6879644601a)
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