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