xref: /haiku/src/add-ons/kernel/file_systems/btrfs/Attribute.cpp (revision 5ac9b506412b11afb993bb52d161efe7666958a5)
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 
26 Attribute::Attribute(Inode* inode)
27 	:
28 	fVolume(inode->GetVolume()),
29 	fInode(inode),
30 	fName(NULL)
31 {
32 }
33 
34 
35 Attribute::Attribute(Inode* inode, attr_cookie* cookie)
36 	:
37 	fVolume(inode->GetVolume()),
38 	fInode(inode),
39 	fName(cookie->name)
40 {
41 }
42 
43 
44 Attribute::~Attribute()
45 {
46 }
47 
48 
49 status_t
50 Attribute::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 
57 status_t
58 Attribute::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 
85 status_t
86 Attribute::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 
112 status_t
113 Attribute::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 
146 status_t
147 Attribute::_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 
179 status_t
180 Attribute::_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