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
38namespace BPrivate {}
39using namespace BPrivate;
40
41
42namespace {
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
54extern "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
61extern "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
68extern "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
86extern "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
93extern "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
100extern "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
107extern "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
131extern "C" int
132_haiku_build_fs_close_attr(int fd)
133{
134	return fs_close_attr(fd);
135}
136
137// fs_read_attr
138extern "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
171extern "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
197extern "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
228extern "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
262int
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
296status_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
305status_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