2 * Copyright 2004-2017, Axel Dörfler, axeld@pinc-software.de.
3 * This file may be used under the terms of the MIT License.
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
18 extern void fill_stat_buffer(Inode
* inode
, struct stat
& stat
);
21 Attribute::Attribute(Inode
* inode
)
23 fNodeGetter(inode
->GetVolume()),
32 Attribute::Attribute(Inode
* inode
, attr_cookie
* cookie
)
34 fNodeGetter(inode
->GetVolume()),
44 Attribute::~Attribute()
51 Attribute::InitCheck()
53 return (fSmall
!= NULL
|| fAttribute
!= NULL
) ? B_OK
: B_NO_INIT
;
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));
78 Attribute::Get(const char* 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
)
90 fSmall
= fInode
->FindSmallData(fNodeGetter
.Node(), (const char*)name
);
94 recursive_lock_unlock(&fInode
->SmallDataLock());
98 // then, search in the attribute directory
99 return fInode
->GetAttribute(name
, &fAttribute
);
106 if (fSmall
!= NULL
) {
107 recursive_lock_unlock(&fInode
->SmallDataLock());
112 if (fAttribute
!= NULL
) {
113 fInode
->ReleaseAttribute(fAttribute
);
120 Attribute::Create(const char* name
, type_code type
, int openMode
,
121 attr_cookie
** _cookie
)
123 status_t status
= CheckAccess(name
, openMode
);
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
;
133 RETURN_ERROR(B_NO_MEMORY
);
137 // initialize the cookie
138 strlcpy(cookie
->name
, fName
, B_ATTR_NAME_LENGTH
);
140 cookie
->open_mode
= openMode
;
141 cookie
->create
= true;
143 if (exists
&& (openMode
& O_TRUNC
) != 0)
152 Attribute::Open(const char* name
, int openMode
, attr_cookie
** _cookie
)
154 status_t status
= CheckAccess(name
, openMode
);
162 attr_cookie
* cookie
= new(std::nothrow
) attr_cookie
;
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)
181 Attribute::Stat(struct stat
& stat
)
183 if (fSmall
== NULL
&& fAttribute
== NULL
)
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
);
204 Attribute::Read(attr_cookie
* cookie
, off_t pos
, uint8
* buffer
, size_t* _length
)
206 if (fSmall
== NULL
&& fAttribute
== NULL
)
209 // TODO: move small_data logic from Inode::ReadAttribute() over to here!
210 return fInode
->ReadAttribute(cookie
->name
, 0, pos
, buffer
, _length
);
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
)
221 return fInode
->WriteAttribute(transaction
, cookie
->name
, cookie
->type
,
222 pos
, buffer
, _length
, _created
);
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
235 if (fAttribute
!= NULL
) {
236 Transaction
transaction(fAttribute
->GetVolume(),
237 fAttribute
->BlockNumber());
238 fAttribute
->WriteLockInTransaction(transaction
);
240 status_t status
= fAttribute
->SetFileSize(transaction
, 0);
242 status
= fAttribute
->WriteBack(transaction
);