2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
17 #include <TypeConstants.h>
19 #include <syscall_utils.h>
22 static const char* const kXattrNamespace
= "user.haiku.";
23 static const size_t kXattrNamespaceLength
= 11;
29 struct AttributeName
{
30 char name
[B_ATTR_NAME_LENGTH
+ 32];
33 void Init(const char* haikuName
, uint32 type
)
35 if (type
== B_XATTR_TYPE
) {
36 // a simple xattr -- copy the name verbatim
37 strlcpy(name
, haikuName
, sizeof(name
));
40 // a Haiku attribute -- map the name
42 // create a type string -- if the four bytes of the type are
43 // printable, just use them as the type string, otherwise convert
46 uint8 typeBytes
[4] = { (uint8
)((type
>> 24) & 0xff),
47 (uint8
)((type
>> 16) & 0xff), (uint8
)((type
>> 8) & 0xff),
48 (uint8
)(type
& 0xff) };
49 if (isprint(typeBytes
[0]) && isprint(typeBytes
[1])
50 && isprint(typeBytes
[2]) && isprint(typeBytes
[3])) {
51 typeString
[0] = typeBytes
[0];
52 typeString
[1] = typeBytes
[1];
53 typeString
[2] = typeBytes
[2];
54 typeString
[3] = typeBytes
[3];
57 sprintf(typeString
, "%08lx", type
);
59 snprintf(name
, sizeof(name
), "%s%s#%s", kXattrNamespace
,
60 haikuName
, typeString
);
64 void Init(const char* xattrName
)
66 if (strncmp(xattrName
, kXattrNamespace
, kXattrNamespaceLength
) == 0) {
67 // a Haiku attribute -- extract the actual name and type
68 xattrName
+= kXattrNamespaceLength
;
70 if (_DecodeNameAndType(xattrName
))
75 strlcpy(name
, xattrName
, sizeof(name
));
76 this->type
= B_XATTR_TYPE
;
81 bool _DecodeNameAndType(const char* xattrName
)
83 const char* typeString
= strrchr(xattrName
, '#');
84 if (typeString
== NULL
|| typeString
== xattrName
)
88 size_t typeStringLength
= strlen(typeString
);
89 if (typeStringLength
== 4) {
90 // the type string consists of the literal type bytes
91 type
= ((uint32
)typeString
[0] << 24) | ((uint32
)typeString
[1] << 16)
92 | ((uint32
)typeString
[2] << 8) | (uint32
)typeString
[3];
93 } else if (typeStringLength
== 8) {
94 // must be hex-encoded
96 type
= strtoul(typeString
, &numberEnd
, 16);
97 if (numberEnd
!= typeString
+ 8)
102 strlcpy(name
, xattrName
,
103 std::min(sizeof(name
), (size_t)(typeString
- xattrName
)));
104 // typeString - xattrName - 1 is the name length, but we need to
105 // specify one more for the terminating null
112 Node(const char* path
, bool traverseSymlinks
)
114 fFileFD
= open(path
, O_RDONLY
| (traverseSymlinks
? 0 : O_NOTRAVERSE
));
124 errno
= B_FILE_ERROR
;
129 if (fFileFD
>= 0 && fOwnsFileFD
)
133 int Set(const char* attribute
, int flags
, const void* buffer
, size_t size
)
138 // flags to open mode
139 int openMode
= O_WRONLY
| O_TRUNC
;
140 if (flags
== XATTR_CREATE
) {
141 openMode
|= O_CREAT
| O_EXCL
;
142 } else if (flags
== XATTR_REPLACE
) {
143 // pure open -- attribute must exist
147 AttributeName attributeName
;
148 attributeName
.Init(attribute
);
150 int attributeFD
= fs_fopen_attr(fFileFD
, attributeName
.name
,
151 attributeName
.type
, openMode
);
152 if (attributeFD
< 0) {
153 // translate B_ENTRY_NOT_FOUND to ENOATTR
154 if (errno
== B_ENTRY_NOT_FOUND
)
160 ssize_t written
= write(attributeFD
, buffer
, size
);
162 fs_close_attr(attributeFD
);
166 if ((size_t)written
!= size
)
167 RETURN_AND_SET_ERRNO(B_FILE_ERROR
);
172 ssize_t
Get(const char* attribute
, void* buffer
, size_t size
)
177 AttributeName attributeName
;
178 attributeName
.Init(attribute
);
180 // get the attribute size -- we read all or nothing
182 if (fs_stat_attr(fFileFD
, attributeName
.name
, &info
) != 0) {
183 // translate B_ENTRY_NOT_FOUND to ENOATTR
184 if (errno
== B_ENTRY_NOT_FOUND
)
189 // if an empty buffer is given, return the attribute size
193 // if the buffer is too small, fail
194 if (size
< info
.size
) {
199 ssize_t bytesRead
= fs_read_attr(fFileFD
, attributeName
.name
,
200 info
.type
, 0, buffer
, info
.size
);
202 // translate B_ENTRY_NOT_FOUND to ENOATTR
203 if (bytesRead
< 0 && errno
== B_ENTRY_NOT_FOUND
)
209 int Remove(const char* attribute
)
214 AttributeName attributeName
;
215 attributeName
.Init(attribute
);
217 int result
= fs_remove_attr(fFileFD
, attributeName
.name
);
219 // translate B_ENTRY_NOT_FOUND to ENOATTR
220 if (result
!= 0 && errno
== B_ENTRY_NOT_FOUND
)
226 ssize_t
GetList(void* _buffer
, size_t size
)
228 char* buffer
= (char*)_buffer
;
233 // open attribute directory
234 DIR* dir
= fs_fopen_attr_dir(fFileFD
);
238 // read the attributes
239 size_t remainingSize
= size
;
240 size_t totalSize
= 0;
241 while (struct dirent
* entry
= readdir(dir
)) {
243 if (fs_stat_attr(fFileFD
, entry
->d_name
, &info
) != 0)
246 AttributeName attributeName
;
247 attributeName
.Init(entry
->d_name
, info
.type
);
249 size_t nameLength
= strlen(attributeName
.name
);
250 totalSize
+= nameLength
+ 1;
252 if (remainingSize
> nameLength
) {
253 strcpy((char*)buffer
, attributeName
.name
);
254 buffer
+= nameLength
+ 1;
255 remainingSize
-= nameLength
+ 1;
262 // If the buffer was too small, fail.
263 if (size
!= 0 && totalSize
> size
) {
284 getxattr(const char* path
, const char* attribute
, void* buffer
, size_t size
)
286 return Node(path
, true).Get(attribute
, buffer
, size
);
291 lgetxattr(const char* path
, const char* attribute
, void* buffer
, size_t size
)
293 return Node(path
, false).Get(attribute
, buffer
, size
);
298 fgetxattr(int fd
, const char* attribute
, void* buffer
, size_t size
)
300 return Node(fd
).Get(attribute
, buffer
, size
);
305 setxattr(const char* path
, const char* attribute
, const void* buffer
,
306 size_t size
, int flags
)
308 return Node(path
, true).Set(attribute
, flags
, buffer
, size
);
313 lsetxattr(const char* path
, const char* attribute
, const void* buffer
,
314 size_t size
, int flags
)
316 return Node(path
, false).Set(attribute
, flags
, buffer
, size
);
321 fsetxattr(int fd
, const char* attribute
, const void* buffer
, size_t size
,
324 return Node(fd
).Set(attribute
, flags
, buffer
, size
);
329 removexattr (const char* path
, const char* attribute
)
331 return Node(path
, true).Remove(attribute
);
336 lremovexattr (const char* path
, const char* attribute
)
338 return Node(path
, false).Remove(attribute
);
343 fremovexattr (int fd
, const char* attribute
)
345 return Node(fd
).Remove(attribute
);
350 listxattr(const char* path
, char* buffer
, size_t size
)
352 return Node(path
, true).GetList(buffer
, size
);
357 llistxattr(const char* path
, char* buffer
, size_t size
)
359 return Node(path
, false).GetList(buffer
, size
);
364 flistxattr(int fd
, char* buffer
, size_t size
)
366 return Node(fd
).GetList(buffer
, size
);