btrfs: [] on the end of a struct field is a variable length array.
[haiku.git] / src / add-ons / kernel / file_systems / bfs / Attribute.cpp
blob3347e6414e0b807fe550ec54e49323d76b80ea36
1 /*
2 * Copyright 2004-2017, Axel Dörfler, axeld@pinc-software.de.
3 * This file may be used under the terms of the MIT License.
4 */
7 //! Connection between pure inode and kernel_interface attributes.
10 #include "Attribute.h"
13 // TODO: clean this up, find a better separation between Inode and this class
14 // TODO: even after Create(), the attribute cannot be stat() for until the
15 // first write
18 extern void fill_stat_buffer(Inode* inode, struct stat& stat);
21 Attribute::Attribute(Inode* inode)
23 fNodeGetter(inode->GetVolume()),
24 fInode(inode),
25 fSmall(NULL),
26 fAttribute(NULL),
27 fName(NULL)
32 Attribute::Attribute(Inode* inode, attr_cookie* cookie)
34 fNodeGetter(inode->GetVolume()),
35 fInode(inode),
36 fSmall(NULL),
37 fAttribute(NULL),
38 fName(NULL)
40 Get(cookie->name);
44 Attribute::~Attribute()
46 Put();
50 status_t
51 Attribute::InitCheck()
53 return (fSmall != NULL || fAttribute != NULL) ? B_OK : B_NO_INIT;
57 status_t
58 Attribute::CheckAccess(const char* name, int openMode)
60 // Opening the name attribute using this function is not allowed,
61 // also using the reserved indices name, last_modified, and size
62 // shouldn't be allowed.
63 // TODO: we might think about allowing to update those values, but
64 // really change their corresponding values in the bfs_inode structure
65 if (name[0] == FILE_NAME_NAME && name[1] == '\0'
66 // TODO: reenable this check -- some WonderBrush locale files used them
67 /* || !strcmp(name, "name")
68 || !strcmp(name, "last_modified")
69 || !strcmp(name, "size")*/)
70 RETURN_ERROR(B_NOT_ALLOWED);
72 return fInode->CheckPermissions(open_mode_to_access(openMode)
73 | (openMode & O_TRUNC ? W_OK : 0));
77 status_t
78 Attribute::Get(const char* name)
80 Put();
82 fName = name;
84 // try to find it in the small data region
85 if (recursive_lock_lock(&fInode->SmallDataLock()) == B_OK) {
86 fNodeGetter.SetToNode(fInode);
87 if (fNodeGetter.Node() == NULL)
88 return B_IO_ERROR;
90 fSmall = fInode->FindSmallData(fNodeGetter.Node(), (const char*)name);
91 if (fSmall != NULL)
92 return B_OK;
94 recursive_lock_unlock(&fInode->SmallDataLock());
95 fNodeGetter.Unset();
98 // then, search in the attribute directory
99 return fInode->GetAttribute(name, &fAttribute);
103 void
104 Attribute::Put()
106 if (fSmall != NULL) {
107 recursive_lock_unlock(&fInode->SmallDataLock());
108 fNodeGetter.Unset();
109 fSmall = NULL;
112 if (fAttribute != NULL) {
113 fInode->ReleaseAttribute(fAttribute);
114 fAttribute = NULL;
119 status_t
120 Attribute::Create(const char* name, type_code type, int openMode,
121 attr_cookie** _cookie)
123 status_t status = CheckAccess(name, openMode);
124 if (status != B_OK)
125 return status;
127 bool exists = Get(name) == B_OK;
128 if (exists && (openMode & O_EXCL) != 0)
129 return B_FILE_EXISTS;
131 attr_cookie* cookie = new(std::nothrow) attr_cookie;
132 if (cookie == NULL)
133 RETURN_ERROR(B_NO_MEMORY);
135 fName = name;
137 // initialize the cookie
138 strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
139 cookie->type = type;
140 cookie->open_mode = openMode;
141 cookie->create = true;
143 if (exists && (openMode & O_TRUNC) != 0)
144 _Truncate();
146 *_cookie = cookie;
147 return B_OK;
151 status_t
152 Attribute::Open(const char* name, int openMode, attr_cookie** _cookie)
154 status_t status = CheckAccess(name, openMode);
155 if (status < B_OK)
156 return status;
158 status = Get(name);
159 if (status < B_OK)
160 return status;
162 attr_cookie* cookie = new(std::nothrow) attr_cookie;
163 if (cookie == NULL)
164 RETURN_ERROR(B_NO_MEMORY);
166 // initialize the cookie
167 strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
168 cookie->open_mode = openMode;
169 cookie->create = false;
171 // Should we truncate the attribute?
172 if ((openMode & O_TRUNC) != 0)
173 _Truncate();
175 *_cookie = cookie;
176 return B_OK;
180 status_t
181 Attribute::Stat(struct stat& stat)
183 if (fSmall == NULL && fAttribute == NULL)
184 return B_NO_INIT;
186 if (fSmall != NULL) {
187 fill_stat_buffer(fInode, stat);
189 // overwrite some data to suit our needs
190 stat.st_type = fSmall->Type();
191 stat.st_size = fSmall->DataSize();
192 stat.st_mtim = stat.st_ctim;
193 // attribute changes cause status_change updates
196 if (fAttribute != NULL)
197 fill_stat_buffer(fAttribute, stat);
199 return B_OK;
203 status_t
204 Attribute::Read(attr_cookie* cookie, off_t pos, uint8* buffer, size_t* _length)
206 if (fSmall == NULL && fAttribute == NULL)
207 return B_NO_INIT;
209 // TODO: move small_data logic from Inode::ReadAttribute() over to here!
210 return fInode->ReadAttribute(cookie->name, 0, pos, buffer, _length);
214 status_t
215 Attribute::Write(Transaction& transaction, attr_cookie* cookie, off_t pos,
216 const uint8* buffer, size_t* _length, bool* _created)
218 if (!cookie->create && fSmall == NULL && fAttribute == NULL)
219 return B_NO_INIT;
221 return fInode->WriteAttribute(transaction, cookie->name, cookie->type,
222 pos, buffer, _length, _created);
226 status_t
227 Attribute::_Truncate()
229 if (fSmall != NULL) {
230 // TODO: as long as Inode::_AddSmallData() works like it does,
231 // we've got nothing to do here
232 return B_OK;
235 if (fAttribute != NULL) {
236 Transaction transaction(fAttribute->GetVolume(),
237 fAttribute->BlockNumber());
238 fAttribute->WriteLockInTransaction(transaction);
240 status_t status = fAttribute->SetFileSize(transaction, 0);
241 if (status >= B_OK)
242 status = fAttribute->WriteBack(transaction);
244 if (status < B_OK)
245 return status;
247 transaction.Done();
250 return B_OK;