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