xref: /haiku/src/build/libroot/fs_attr_haiku.cpp (revision 3995592cdf304335132305e27c40cbb0b1ac46e3)
1 /*
2  * Copyright 2017, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 /*!	Shim over the host Haiku fs_attr API */
7 
8 #define BUILDING_FS_ATTR_HAIKU
9 	// so build fs_attr.h will not shadow the fs*attr functions
10 
11 
12 #ifdef BUILDING_FS_SHELL
13 #	include "compat.h"
14 #	define B_OK					0
15 #	define B_BAD_VALUE			EINVAL
16 #	define B_FILE_ERROR			EBADF
17 #	define B_ERROR				EINVAL
18 #	define B_ENTRY_NOT_FOUND	ENOENT
19 #	define B_NO_MEMORY			ENOMEM
20 #else
21 #	include <syscalls.h>
22 
23 #	include "fs_impl.h"
24 #	include "fs_descriptors.h"
25 #endif
26 
27 #include <dirent.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
34 
35 #include <map>
36 #include <string>
37 
38 #include <fs_attr.h>
39 
40 
41 namespace BPrivate {}
42 using namespace BPrivate;
43 
44 
45 namespace {
46 
47 // LocalFD
48 #include "LocalFD.h"
49 
50 } // unnamed namspace
51 
52 
53 // # pragma mark - Public API
54 
55 
56 // fs_open_attr_dir
57 extern "C" DIR *
58 build_fs_open_attr_dir(const char *path)
59 {
60 	return fs_open_attr_dir(path);
61 }
62 
63 // fs_fopen_attr_dir
64 extern "C" DIR* fs_lopen_attr_dir(const char *path);
65 extern "C" DIR*
66 build_fs_fopen_attr_dir(int fd)
67 {
68 	LocalFD localFD;
69 	status_t error = localFD.Init(fd);
70 	if (error != B_OK) {
71 		errno = error;
72 		return NULL;
73 	}
74 
75 	if (localFD.FD() < 0) {
76 		return fs_lopen_attr_dir(localFD.Path());
77 	} else {
78 		return fs_fopen_attr_dir(localFD.FD());
79 	}
80 }
81 
82 // fs_close_attr_dir
83 extern "C" int
84 build_fs_close_attr_dir(DIR *dir)
85 {
86 	return fs_close_attr_dir(dir);
87 }
88 
89 // fs_read_attr_dir
90 extern "C" struct dirent *
91 build_fs_read_attr_dir(DIR *dir)
92 {
93 	return fs_read_attr_dir(dir);
94 }
95 
96 // fs_rewind_attr_dir
97 extern "C" void
98 build_fs_rewind_attr_dir(DIR *dir)
99 {
100 	return fs_rewind_attr_dir(dir);
101 }
102 
103 // fs_fopen_attr
104 extern "C" int
105 build_fs_fopen_attr(int fd, const char *attribute, uint32 type, int openMode)
106 {
107 	if (fd < 0) {
108 		errno = B_BAD_VALUE;
109 		return -1;
110 	}
111 
112 	LocalFD localFD;
113 	status_t error = localFD.Init(fd);
114 	if (error != B_OK) {
115 		errno = error;
116 		return -1;
117 	}
118 
119 	if (localFD.FD() < 0) {
120 		return fs_open_attr(localFD.Path(), attribute, type,
121 			openMode | O_NOTRAVERSE);
122 	} else {
123 		return fs_fopen_attr(localFD.FD(), attribute, type, openMode);
124 	}
125 }
126 
127 // fs_close_attr
128 extern "C" int
129 build_fs_close_attr(int fd)
130 {
131 	return fs_close_attr(fd);
132 }
133 
134 // fs_read_attr
135 extern "C" ssize_t
136 build_fs_read_attr(int fd, const char* attribute, uint32 type, off_t pos,
137 	void *buffer, size_t readBytes)
138 {
139 	LocalFD localFD;
140 	status_t error = localFD.Init(fd);
141 	if (error != B_OK) {
142 		errno = error;
143 		return -1;
144 	}
145 
146 	ssize_t bytesRead;
147 	if (localFD.FD() < 0) {
148 		int fd = open(localFD.Path(), O_RDONLY | O_NOTRAVERSE);
149 		bytesRead = fs_read_attr(fd, attribute, type,
150 			pos, buffer, readBytes);
151 		close(fd);
152 	} else {
153 		bytesRead = fs_read_attr(localFD.FD(), attribute, type,
154 			pos, buffer, readBytes);
155 	}
156 	if (bytesRead < 0) {
157 		// Make sure, the error code is B_ENTRY_NOT_FOUND, if the attribute
158 		// doesn't exist.
159 		if (errno == ENOATTR || errno == ENODATA)
160 			errno = B_ENTRY_NOT_FOUND;
161 		return -1;
162 	}
163 
164 	return bytesRead;
165 }
166 
167 // fs_write_attr
168 extern "C" ssize_t
169 build_fs_write_attr(int fd, const char* attribute, uint32 type, off_t pos,
170 	const void *buffer, size_t writeBytes)
171 {
172 	LocalFD localFD;
173 	status_t error = localFD.Init(fd);
174 	if (error != B_OK) {
175 		errno = error;
176 		return -1;
177 	}
178 
179 	ssize_t written;
180 	if (localFD.FD() < 0) {
181 		int fd = open(localFD.Path(), O_NOTRAVERSE | O_WRONLY);
182 		written = fs_write_attr(fd, attribute, type,
183 			pos, buffer, writeBytes);
184 		close(fd);
185 	} else {
186 		written = fs_write_attr(localFD.FD(), attribute, type,
187 			pos, buffer, writeBytes);
188 	}
189 
190 	return written;
191 }
192 
193 // fs_remove_attr
194 extern "C" int
195 build_fs_remove_attr(int fd, const char* attribute)
196 {
197 	LocalFD localFD;
198 	status_t error = localFD.Init(fd);
199 	if (error != B_OK) {
200 		errno = error;
201 		return -1;
202 	}
203 
204 	// remove attribute
205 	int result;
206 	if (localFD.FD() < 0) {
207 		int fd = open(localFD.Path(), O_NOTRAVERSE | O_WRONLY);
208 		result = fs_remove_attr(fd, attribute);
209 		close(fd);
210 	} else {
211 		result = fs_remove_attr(localFD.FD(), attribute);
212 	}
213 
214 	if (result < 0) {
215 		// Make sure, the error code is B_ENTRY_NOT_FOUND, if the attribute
216 		// doesn't exist.
217 		if (errno == ENOATTR || errno == ENODATA)
218 			errno = B_ENTRY_NOT_FOUND;
219 		return -1;
220 	}
221 	return 0;
222 }
223 
224 // fs_stat_attr
225 extern "C" int
226 build_fs_stat_attr(int fd, const char *attribute, struct attr_info *attrInfo)
227 {
228 	if (!attribute || !attrInfo) {
229 		errno = B_BAD_VALUE;
230 		return -1;
231 	}
232 
233 	LocalFD localFD;
234 	status_t error = localFD.Init(fd);
235 	if (error != B_OK) {
236 		errno = error;
237 		return -1;
238 	}
239 
240 	int result;
241 	if (localFD.FD() < 0) {
242 		int fd = open(localFD.Path(), O_NOTRAVERSE | O_RDONLY);
243 		result = fs_stat_attr(fd, attribute, attrInfo);
244 		close(fd);
245 	} else {
246 		result = fs_stat_attr(localFD.FD(), attribute, attrInfo);
247 	}
248 
249 	return result;
250 }
251 
252 
253 // #pragma mark - Private Syscalls
254 
255 
256 #ifndef BUILDING_FS_SHELL
257 
258 // _kern_open_attr_dir
259 int
260 _kern_open_attr_dir(int fd, const char *path)
261 {
262 	// get node ref for the node
263 	struct stat st;
264 	status_t error = _kern_read_stat(fd, path, false, &st,
265 		sizeof(struct stat));
266 	if (error != B_OK) {
267 		errno = error;
268 		return -1;
269 	}
270 	NodeRef ref(st);
271 
272 	DIR* dir;
273 	if (path) {
274 		// If a path was given, get a usable path.
275 		string realPath;
276 		status_t error = get_path(fd, path, realPath);
277 		if (error != B_OK)
278 			return error;
279 
280 		dir = build_fs_open_attr_dir(realPath.c_str());
281 	} else
282 		dir = build_fs_fopen_attr_dir(fd);
283 
284 	if (!dir)
285 		return errno;
286 
287 	// create descriptor
288 	AttrDirDescriptor *descriptor = new AttrDirDescriptor(dir, ref);
289 	return add_descriptor(descriptor);
290 }
291 
292 // _kern_rename_attr
293 status_t
294 _kern_rename_attr(int fromFile, const char *fromName, int toFile,
295 	const char *toName)
296 {
297 	// not supported ATM
298 	return B_BAD_VALUE;
299 }
300 
301 // _kern_remove_attr
302 status_t
303 _kern_remove_attr(int fd, const char *name)
304 {
305 	if (!name)
306 		return B_BAD_VALUE;
307 
308 	if (build_fs_remove_attr(fd, name) < 0)
309 		return errno;
310 	return B_OK;
311 }
312 
313 #endif	// ! BUILDING_FS_SHELL
314