xref: /haiku/src/add-ons/kernel/file_systems/bfs/Attribute.cpp (revision 93aeb8c3bc3f13cb1f282e3e749258a23790d947)
1 /* Attribute - connection between pure inode and kernel_interface attributes
2  *
3  * Copyright 2004, Axel Dörfler, axeld@pinc-software.de.
4  * This file may be used under the terms of the MIT License.
5  */
6 
7 
8 #include "Attribute.h"
9 #include <stdlib.h>
10 
11 
12 // ToDo: clean this up, find a better separation between Inode and this class
13 // ToDo: even after Create(), the attribute cannot be stat() for until the first write
14 
15 
16 extern void fill_stat_buffer(Inode *inode, struct stat &stat);
17 
18 
19 Attribute::Attribute(Inode *inode)
20 	:
21 	fNodeGetter(inode->GetVolume()),
22 	fInode(inode),
23 	fSmall(NULL),
24 	fAttribute(NULL),
25 	fName(NULL)
26 {
27 }
28 
29 
30 Attribute::Attribute(Inode *inode, attr_cookie *cookie)
31 	:
32 	fNodeGetter(inode->GetVolume()),
33 	fInode(inode),
34 	fSmall(NULL),
35 	fAttribute(NULL),
36 	fName(NULL)
37 {
38 	Get(cookie->name);
39 }
40 
41 
42 Attribute::~Attribute()
43 {
44 	Put();
45 }
46 
47 
48 status_t
49 Attribute::InitCheck()
50 {
51 	return (fSmall != NULL || fAttribute != NULL) ? B_OK : B_NO_INIT;
52 }
53 
54 
55 status_t
56 Attribute::CheckAccess(const char *name, int openMode)
57 {
58 	// Opening the name attribute using this function is not allowed,
59 	// also using the reserved indices name, last_modified, and size
60 	// shouldn't be allowed.
61 	// ToDo: we might think about allowing to update those values, but
62 	//	really change their corresponding values in the bfs_inode structure
63 	if (name[0] == FILE_NAME_NAME && name[1] == '\0'
64 		|| !strcmp(name, "name")
65 		|| !strcmp(name, "last_modified")
66 		|| !strcmp(name, "size"))
67 		RETURN_ERROR(B_NOT_ALLOWED);
68 
69 	return fInode->CheckPermissions(openModeToAccess(openMode)
70 		| (openMode & O_TRUNC ? W_OK : 0));
71 }
72 
73 
74 status_t
75 Attribute::Get(const char *name)
76 {
77 	Put();
78 
79 	fName = name;
80 
81 	// try to find it in the small data region
82 	if (fInode->SmallDataLock().Lock() == B_OK) {
83 		fNodeGetter.SetToNode(fInode);
84 		fSmall = fInode->FindSmallData(fNodeGetter.Node(), (const char *)name);
85 		if (fSmall != NULL)
86 			return B_OK;
87 
88 		fInode->SmallDataLock().Unlock();
89 		fNodeGetter.Unset();
90 	}
91 
92 	// then, search in the attribute directory
93 	return fInode->GetAttribute(name, &fAttribute);
94 }
95 
96 
97 void
98 Attribute::Put()
99 {
100 	if (fSmall != NULL) {
101 		fInode->SmallDataLock().Unlock();
102 		fNodeGetter.Unset();
103 		fSmall = NULL;
104 	}
105 
106 	if (fAttribute != NULL) {
107 		fInode->ReleaseAttribute(fAttribute);
108 		fAttribute = NULL;
109 	}
110 }
111 
112 
113 status_t
114 Attribute::Create(const char *name, type_code type, int openMode, attr_cookie **_cookie)
115 {
116 	status_t status = CheckAccess(name, openMode);
117 	if (status < B_OK)
118 		return status;
119 
120 	attr_cookie *cookie = (attr_cookie *)malloc(sizeof(attr_cookie));
121 	if (cookie == NULL)
122 		RETURN_ERROR(B_NO_MEMORY);
123 
124 	fName = name;
125 
126 	// initialize the cookie
127 	strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
128 	cookie->type = type;
129 	cookie->open_mode = openMode;
130 	cookie->create = true;
131 
132 	*_cookie = cookie;
133 	return B_OK;
134 }
135 
136 
137 status_t
138 Attribute::Open(const char *name, int openMode, attr_cookie **_cookie)
139 {
140 	status_t status = CheckAccess(name, openMode);
141 	if (status < B_OK)
142 		return status;
143 
144 	status = Get(name);
145 	if (status < B_OK)
146 		return status;
147 
148 	attr_cookie *cookie = (attr_cookie *)malloc(sizeof(attr_cookie));
149 	if (cookie == NULL)
150 		RETURN_ERROR(B_NO_MEMORY);
151 
152 	// initialize the cookie
153 	strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
154 	cookie->open_mode = openMode;
155 	cookie->create = false;
156 
157 	// Should we truncate the attribute?
158 	if (openMode & O_TRUNC) {
159 		// ToDo!
160 	}
161 
162 	*_cookie = cookie;
163 	return B_OK;
164 }
165 
166 
167 status_t
168 Attribute::Stat(struct stat &stat)
169 {
170 	if (fSmall == NULL && fAttribute == NULL)
171 		return B_NO_INIT;
172 
173 	if (fSmall != NULL) {
174 		fill_stat_buffer(fInode, stat);
175 
176 		// overwrite some data to suit our needs
177 		stat.st_type = fSmall->Type();
178 		stat.st_size = fSmall->DataSize();
179 	}
180 
181 	if (fAttribute != NULL)
182 		fill_stat_buffer(fAttribute, stat);
183 
184 	return B_OK;
185 }
186 
187 
188 status_t
189 Attribute::Read(attr_cookie *cookie, off_t pos, uint8 *buffer, size_t *_length)
190 {
191 	if (fSmall == NULL && fAttribute == NULL)
192 		return B_NO_INIT;
193 
194 	// ToDo: move small_data logic from Inode::ReadAttribute() over to here!
195 	return fInode->ReadAttribute(cookie->name, 0, pos, buffer, _length);
196 }
197 
198 
199 status_t
200 Attribute::Write(Transaction &transaction, attr_cookie *cookie,
201 	off_t pos, const uint8 *buffer, size_t *_length)
202 {
203 	if (!cookie->create && fSmall == NULL && fAttribute == NULL)
204 		return B_NO_INIT;
205 
206 	return fInode->WriteAttribute(transaction, cookie->name, cookie->type,
207 		pos, buffer, _length);
208 }
209 
210