1065e3184SAxel Dörfler/*
239f437f7SAxel Dörfler * Copyright 2004-2017, Axel D��rfler, axeld@pinc-software.de.
3d48f7182SAxel Dörfler * This file may be used under the terms of the MIT License.
4d48f7182SAxel Dörfler */
5d48f7182SAxel Dörfler
6a90df70aSAxel Dörfler
7a90df70aSAxel Dörfler//!	Connection between pure inode and kernel_interface attributes.
8065e3184SAxel Dörfler
9d48f7182SAxel Dörfler
10d48f7182SAxel Dörfler#include "Attribute.h"
11d48f7182SAxel Dörfler
12d48f7182SAxel Dörfler
13082bae1aSAxel Dörfler// TODO: clean this up, find a better separation between Inode and this class
1402c8f6c8SAxel Dörfler// TODO: even after Create(), the attribute cannot be stat() for until the
1502c8f6c8SAxel Dörfler// first write
16d48f7182SAxel Dörfler
17d48f7182SAxel Dörfler
1802c8f6c8SAxel Dörflerextern void fill_stat_buffer(Inode* inode, struct stat& stat);
19d48f7182SAxel Dörfler
20d48f7182SAxel Dörfler
2102c8f6c8SAxel DörflerAttribute::Attribute(Inode* inode)
22d48f7182SAxel Dörfler	:
23d48f7182SAxel Dörfler	fNodeGetter(inode->GetVolume()),
24d48f7182SAxel Dörfler	fInode(inode),
25d48f7182SAxel Dörfler	fSmall(NULL),
26d48f7182SAxel Dörfler	fAttribute(NULL),
27d48f7182SAxel Dörfler	fName(NULL)
28d48f7182SAxel Dörfler{
29d48f7182SAxel Dörfler}
30d48f7182SAxel Dörfler
31d48f7182SAxel Dörfler
3202c8f6c8SAxel DörflerAttribute::Attribute(Inode* inode, attr_cookie* cookie)
33d48f7182SAxel Dörfler	:
34d48f7182SAxel Dörfler	fNodeGetter(inode->GetVolume()),
35d48f7182SAxel Dörfler	fInode(inode),
36d48f7182SAxel Dörfler	fSmall(NULL),
37d48f7182SAxel Dörfler	fAttribute(NULL),
38d48f7182SAxel Dörfler	fName(NULL)
39d48f7182SAxel Dörfler{
40d48f7182SAxel Dörfler	Get(cookie->name);
41d48f7182SAxel Dörfler}
42d48f7182SAxel Dörfler
43d48f7182SAxel Dörfler
44d48f7182SAxel DörflerAttribute::~Attribute()
45d48f7182SAxel Dörfler{
46d48f7182SAxel Dörfler	Put();
47d48f7182SAxel Dörfler}
48d48f7182SAxel Dörfler
49d48f7182SAxel Dörfler
50d48f7182SAxel Dörflerstatus_t
51d48f7182SAxel DörflerAttribute::InitCheck()
52d48f7182SAxel Dörfler{
53d48f7182SAxel Dörfler	return (fSmall != NULL || fAttribute != NULL) ? B_OK : B_NO_INIT;
54d48f7182SAxel Dörfler}
55d48f7182SAxel Dörfler
56d48f7182SAxel Dörfler
57d48f7182SAxel Dörflerstatus_t
5802c8f6c8SAxel DörflerAttribute::CheckAccess(const char* name, int openMode)
59d48f7182SAxel Dörfler{
60d48f7182SAxel Dörfler	// Opening the name attribute using this function is not allowed,
61d48f7182SAxel Dörfler	// also using the reserved indices name, last_modified, and size
62d48f7182SAxel Dörfler	// shouldn't be allowed.
632e3477e3SAxel Dörfler	// TODO: we might think about allowing to update those values, but
64d48f7182SAxel Dörfler	//	really change their corresponding values in the bfs_inode structure
65d48f7182SAxel Dörfler	if (name[0] == FILE_NAME_NAME && name[1] == '\0'
662e3477e3SAxel Dörfler// TODO: reenable this check -- some WonderBrush locale files used them
6797d5bb2bSIngo Weinhold/*		|| !strcmp(name, "name")
68d48f7182SAxel Dörfler		|| !strcmp(name, "last_modified")
6997d5bb2bSIngo Weinhold		|| !strcmp(name, "size")*/)
70d48f7182SAxel Dörfler		RETURN_ERROR(B_NOT_ALLOWED);
71d48f7182SAxel Dörfler
722accd07bSAxel Dörfler	return fInode->CheckPermissions(open_mode_to_access(openMode)
73d48f7182SAxel Dörfler		| (openMode & O_TRUNC ? W_OK : 0));
74d48f7182SAxel Dörfler}
75d48f7182SAxel Dörfler
76d48f7182SAxel Dörfler
771bde8b03SAxel Dörflerstatus_t
7802c8f6c8SAxel DörflerAttribute::Get(const char* name)
79d48f7182SAxel Dörfler{
80d48f7182SAxel Dörfler	Put();
81d48f7182SAxel Dörfler
82d48f7182SAxel Dörfler	fName = name;
83d48f7182SAxel Dörfler
84d48f7182SAxel Dörfler	// try to find it in the small data region
8503fa417bSAxel Dörfler	if (recursive_lock_lock(&fInode->SmallDataLock()) == B_OK) {
86d48f7182SAxel Dörfler		fNodeGetter.SetToNode(fInode);
8739f437f7SAxel Dörfler		if (fNodeGetter.Node() == NULL)
8839f437f7SAxel Dörfler			return B_IO_ERROR;
8939f437f7SAxel Dörfler
9002c8f6c8SAxel Dörfler		fSmall = fInode->FindSmallData(fNodeGetter.Node(), (const char*)name);
91d48f7182SAxel Dörfler		if (fSmall != NULL)
92d48f7182SAxel Dörfler			return B_OK;
93d48f7182SAxel Dörfler
9403fa417bSAxel Dörfler		recursive_lock_unlock(&fInode->SmallDataLock());
95d48f7182SAxel Dörfler		fNodeGetter.Unset();
96d48f7182SAxel Dörfler	}
97d48f7182SAxel Dörfler
98d48f7182SAxel Dörfler	// then, search in the attribute directory
99d48f7182SAxel Dörfler	return fInode->GetAttribute(name, &fAttribute);
100d48f7182SAxel Dörfler}
101d48f7182SAxel Dörfler
102d48f7182SAxel Dörfler
103d48f7182SAxel Dörflervoid
104d48f7182SAxel DörflerAttribute::Put()
105d48f7182SAxel Dörfler{
106d48f7182SAxel Dörfler	if (fSmall != NULL) {
10703fa417bSAxel Dörfler		recursive_lock_unlock(&fInode->SmallDataLock());
108d48f7182SAxel Dörfler		fNodeGetter.Unset();
109d48f7182SAxel Dörfler		fSmall = NULL;
110d48f7182SAxel Dörfler	}
111d48f7182SAxel Dörfler
112d48f7182SAxel Dörfler	if (fAttribute != NULL) {
113d48f7182SAxel Dörfler		fInode->ReleaseAttribute(fAttribute);
114d48f7182SAxel Dörfler		fAttribute = NULL;
115d48f7182SAxel Dörfler	}
116d48f7182SAxel Dörfler}
117d48f7182SAxel Dörfler
118d48f7182SAxel Dörfler
119d48f7182SAxel Dörflerstatus_t
12002c8f6c8SAxel DörflerAttribute::Create(const char* name, type_code type, int openMode,
12102c8f6c8SAxel Dörfler	attr_cookie** _cookie)
122d48f7182SAxel Dörfler{
123d48f7182SAxel Dörfler	status_t status = CheckAccess(name, openMode);
124a90df70aSAxel Dörfler	if (status != B_OK)
125d48f7182SAxel Dörfler		return status;
126d48f7182SAxel Dörfler
12783b4b893SAxel Dörfler	bool exists = Get(name) == B_OK;
12883b4b893SAxel Dörfler	if (exists && (openMode & O_EXCL) != 0)
12983b4b893SAxel Dörfler		return B_FILE_EXISTS;
13083b4b893SAxel Dörfler
131a90df70aSAxel Dörfler	attr_cookie* cookie = new(std::nothrow) attr_cookie;
132a90df70aSAxel Dörfler	if (cookie == NULL)
133a90df70aSAxel Dörfler		RETURN_ERROR(B_NO_MEMORY);
134a90df70aSAxel Dörfler
135d48f7182SAxel Dörfler	fName = name;
136d48f7182SAxel Dörfler
137d48f7182SAxel Dörfler	// initialize the cookie
138d48f7182SAxel Dörfler	strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
139d48f7182SAxel Dörfler	cookie->type = type;
140d48f7182SAxel Dörfler	cookie->open_mode = openMode;
141d48f7182SAxel Dörfler	cookie->create = true;
142d48f7182SAxel Dörfler
14383b4b893SAxel Dörfler	if (exists && (openMode & O_TRUNC) != 0)
14483b4b893SAxel Dörfler		_Truncate();
14583b4b893SAxel Dörfler
146d48f7182SAxel Dörfler	*_cookie = cookie;
147d48f7182SAxel Dörfler	return B_OK;
148d48f7182SAxel Dörfler}
149d48f7182SAxel Dörfler
150d48f7182SAxel Dörfler
151d48f7182SAxel Dörflerstatus_t
15202c8f6c8SAxel DörflerAttribute::Open(const char* name, int openMode, attr_cookie** _cookie)
153d48f7182SAxel Dörfler{
154d48f7182SAxel Dörfler	status_t status = CheckAccess(name, openMode);
155d48f7182SAxel Dörfler	if (status < B_OK)
156d48f7182SAxel Dörfler		return status;
157d48f7182SAxel Dörfler
158d48f7182SAxel Dörfler	status = Get(name);
159d48f7182SAxel Dörfler	if (status < B_OK)
160d48f7182SAxel Dörfler		return status;
161d48f7182SAxel Dörfler
16202c8f6c8SAxel Dörfler	attr_cookie* cookie = new(std::nothrow) attr_cookie;
163d48f7182SAxel Dörfler	if (cookie == NULL)
1641bde8b03SAxel Dörfler		RETURN_ERROR(B_NO_MEMORY);
165d48f7182SAxel Dörfler
166d48f7182SAxel Dörfler	// initialize the cookie
167d48f7182SAxel Dörfler	strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
168d48f7182SAxel Dörfler	cookie->open_mode = openMode;
169d48f7182SAxel Dörfler	cookie->create = false;
170d48f7182SAxel Dörfler
171d48f7182SAxel Dörfler	// Should we truncate the attribute?
172065e3184SAxel Dörfler	if ((openMode & O_TRUNC) != 0)
173065e3184SAxel Dörfler		_Truncate();
174d48f7182SAxel Dörfler
175d48f7182SAxel Dörfler	*_cookie = cookie;
176d48f7182SAxel Dörfler	return B_OK;
177d48f7182SAxel Dörfler}
178d48f7182SAxel Dörfler
179d48f7182SAxel Dörfler
180d48f7182SAxel Dörflerstatus_t
18102c8f6c8SAxel DörflerAttribute::Stat(struct stat& stat)
182d48f7182SAxel Dörfler{
183d48f7182SAxel Dörfler	if (fSmall == NULL && fAttribute == NULL)
184d48f7182SAxel Dörfler		return B_NO_INIT;
185d48f7182SAxel Dörfler
186d48f7182SAxel Dörfler	if (fSmall != NULL) {
187d48f7182SAxel Dörfler		fill_stat_buffer(fInode, stat);
188d48f7182SAxel Dörfler
189d48f7182SAxel Dörfler		// overwrite some data to suit our needs
190d48f7182SAxel Dörfler		stat.st_type = fSmall->Type();
191d48f7182SAxel Dörfler		stat.st_size = fSmall->DataSize();
19256ae953fSAxel Dörfler		stat.st_mtim = stat.st_ctim;
19356ae953fSAxel Dörfler			// attribute changes cause status_change updates
194d48f7182SAxel Dörfler	}
195d48f7182SAxel Dörfler
196d48f7182SAxel Dörfler	if (fAttribute != NULL)
197d48f7182SAxel Dörfler		fill_stat_buffer(fAttribute, stat);
198d48f7182SAxel Dörfler
199d48f7182SAxel Dörfler	return B_OK;
200d48f7182SAxel Dörfler}
201d48f7182SAxel Dörfler
202d48f7182SAxel Dörfler
203d48f7182SAxel Dörflerstatus_t
20402c8f6c8SAxel DörflerAttribute::Read(attr_cookie* cookie, off_t pos, uint8* buffer, size_t* _length)
205d48f7182SAxel Dörfler{
206d48f7182SAxel Dörfler	if (fSmall == NULL && fAttribute == NULL)
207d48f7182SAxel Dörfler		return B_NO_INIT;
208d48f7182SAxel Dörfler
20903fa417bSAxel Dörfler	// TODO: move small_data logic from Inode::ReadAttribute() over to here!
210d48f7182SAxel Dörfler	return fInode->ReadAttribute(cookie->name, 0, pos, buffer, _length);
211d48f7182SAxel Dörfler}
212d48f7182SAxel Dörfler
213d48f7182SAxel Dörfler
214d48f7182SAxel Dörflerstatus_t
21502c8f6c8SAxel DörflerAttribute::Write(Transaction& transaction, attr_cookie* cookie, off_t pos,
2161b944eecSAxel Dörfler	const uint8* buffer, size_t* _length, bool* _created)
217d48f7182SAxel Dörfler{
218d48f7182SAxel Dörfler	if (!cookie->create && fSmall == NULL && fAttribute == NULL)
219d48f7182SAxel Dörfler		return B_NO_INIT;
220d48f7182SAxel Dörfler
221d48f7182SAxel Dörfler	return fInode->WriteAttribute(transaction, cookie->name, cookie->type,
2221b944eecSAxel Dörfler		pos, buffer, _length, _created);
223d48f7182SAxel Dörfler}
224d48f7182SAxel Dörfler
225065e3184SAxel Dörfler
226065e3184SAxel Dörflerstatus_t
227065e3184SAxel DörflerAttribute::_Truncate()
228065e3184SAxel Dörfler{
229065e3184SAxel Dörfler	if (fSmall != NULL) {
230065e3184SAxel Dörfler		// TODO: as long as Inode::_AddSmallData() works like it does,
231065e3184SAxel Dörfler		// we've got nothing to do here
232065e3184SAxel Dörfler		return B_OK;
233065e3184SAxel Dörfler	}
234065e3184SAxel Dörfler
235065e3184SAxel Dörfler	if (fAttribute != NULL) {
236082bae1aSAxel Dörfler		Transaction transaction(fAttribute->GetVolume(),
237082bae1aSAxel Dörfler			fAttribute->BlockNumber());
2382e3477e3SAxel Dörfler		fAttribute->WriteLockInTransaction(transaction);
239065e3184SAxel Dörfler
240065e3184SAxel Dörfler		status_t status = fAttribute->SetFileSize(transaction, 0);
241065e3184SAxel Dörfler		if (status >= B_OK)
242065e3184SAxel Dörfler			status = fAttribute->WriteBack(transaction);
243065e3184SAxel Dörfler
244065e3184SAxel Dörfler		if (status < B_OK)
245065e3184SAxel Dörfler			return status;
246065e3184SAxel Dörfler
247065e3184SAxel Dörfler		transaction.Done();
248065e3184SAxel Dörfler	}
249065e3184SAxel Dörfler
250065e3184SAxel Dörfler	return B_OK;
251065e3184SAxel Dörfler}
252065e3184SAxel Dörfler