HaikuDepot: notify work status from main window
[haiku.git] / src / libs / gnu / xattr.cpp
blob9873018ac645ebbe2dca5606c898b351aaa35bdb
1 /*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
6 #include <sys/xattr.h>
8 #include <ctype.h>
9 #include <errno.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
14 #include <algorithm>
16 #include <fs_attr.h>
17 #include <TypeConstants.h>
19 #include <syscall_utils.h>
22 static const char* const kXattrNamespace = "user.haiku.";
23 static const size_t kXattrNamespaceLength = 11;
26 namespace {
29 struct AttributeName {
30 char name[B_ATTR_NAME_LENGTH + 32];
31 uint32 type;
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));
38 this->type = type;
39 } else {
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
44 // to hex
45 char typeString[9];
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];
55 typeString[4] = '\0';
56 } else
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))
71 return;
74 // a simple xattr
75 strlcpy(name, xattrName, sizeof(name));
76 this->type = B_XATTR_TYPE;
79 private:
81 bool _DecodeNameAndType(const char* xattrName)
83 const char* typeString = strrchr(xattrName, '#');
84 if (typeString == NULL || typeString == xattrName)
85 return false;
86 typeString++;
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
95 char* numberEnd;
96 type = strtoul(typeString, &numberEnd, 16);
97 if (numberEnd != typeString + 8)
98 return false;
99 } else
100 return false;
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
106 return true;
111 struct Node {
112 Node(const char* path, bool traverseSymlinks)
114 fFileFD = open(path, O_RDONLY | (traverseSymlinks ? 0 : O_NOTRAVERSE));
115 fOwnsFileFD = true;
118 Node(int fileFD)
120 fFileFD = fileFD;
121 fOwnsFileFD = false;
123 if (fileFD < 0)
124 errno = B_FILE_ERROR;
127 ~Node()
129 if (fFileFD >= 0 && fOwnsFileFD)
130 close(fFileFD);
133 int Set(const char* attribute, int flags, const void* buffer, size_t size)
135 if (fFileFD < 0)
136 return -1;
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
144 } else
145 openMode |= O_CREAT;
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)
155 errno = ENOATTR;
157 return -1;
160 ssize_t written = write(attributeFD, buffer, size);
162 fs_close_attr(attributeFD);
164 if (written < 0)
165 return -1;
166 if ((size_t)written != size)
167 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
169 return 0;
172 ssize_t Get(const char* attribute, void* buffer, size_t size)
174 if (fFileFD < 0)
175 return -1;
177 AttributeName attributeName;
178 attributeName.Init(attribute);
180 // get the attribute size -- we read all or nothing
181 attr_info info;
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)
185 errno = ENOATTR;
186 return -1;
189 // if an empty buffer is given, return the attribute size
190 if (size == 0)
191 return info.size;
193 // if the buffer is too small, fail
194 if (size < info.size) {
195 errno = ERANGE;
196 return -1;
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)
204 errno = ENOATTR;
206 return bytesRead;
209 int Remove(const char* attribute)
211 if (fFileFD < 0)
212 return -1;
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)
221 errno = ENOATTR;
223 return result;
226 ssize_t GetList(void* _buffer, size_t size)
228 char* buffer = (char*)_buffer;
230 if (fFileFD < 0)
231 return -1;
233 // open attribute directory
234 DIR* dir = fs_fopen_attr_dir(fFileFD);
235 if (dir == NULL)
236 return -1;
238 // read the attributes
239 size_t remainingSize = size;
240 size_t totalSize = 0;
241 while (struct dirent* entry = readdir(dir)) {
242 attr_info info;
243 if (fs_stat_attr(fFileFD, entry->d_name, &info) != 0)
244 continue;
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;
256 } else
257 remainingSize = 0;
260 closedir(dir);
262 // If the buffer was too small, fail.
263 if (size != 0 && totalSize > size) {
264 errno = ERANGE;
265 return -1;
268 return totalSize;
271 private:
272 int fFileFD;
273 bool fOwnsFileFD;
277 } // namespace
280 // #pragma mark -
283 ssize_t
284 getxattr(const char* path, const char* attribute, void* buffer, size_t size)
286 return Node(path, true).Get(attribute, buffer, size);
290 ssize_t
291 lgetxattr(const char* path, const char* attribute, void* buffer, size_t size)
293 return Node(path, false).Get(attribute, buffer, size);
297 ssize_t
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,
322 int flags)
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);
349 ssize_t
350 listxattr(const char* path, char* buffer, size_t size)
352 return Node(path, true).GetList(buffer, size);
356 ssize_t
357 llistxattr(const char* path, char* buffer, size_t size)
359 return Node(path, false).GetList(buffer, size);
363 ssize_t
364 flistxattr(int fd, char* buffer, size_t size)
366 return Node(fd).GetList(buffer, size);