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 *
_haiku_build_fs_open_attr_dir(const char * path)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*
_haiku_build_fs_lopen_attr_dir(const char * path)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*
_haiku_build_fs_fopen_attr_dir(int fd)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
_haiku_build_fs_close_attr_dir(DIR * dir)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 *
_haiku_build_fs_read_attr_dir(DIR * dir)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
_haiku_build_fs_rewind_attr_dir(DIR * dir)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
_haiku_build_fs_fopen_attr(int fd,const char * attribute,uint32 type,int openMode)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
_haiku_build_fs_close_attr(int fd)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
_haiku_build_fs_read_attr(int fd,const char * attribute,uint32 type,off_t pos,void * buffer,size_t readBytes)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
_haiku_build_fs_write_attr(int fd,const char * attribute,uint32 type,off_t pos,const void * buffer,size_t writeBytes)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
_haiku_build_fs_remove_attr(int fd,const char * attribute)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
_haiku_build_fs_stat_attr(int fd,const char * attribute,struct attr_info * attrInfo)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
_kern_open_attr_dir(int fd,const char * path)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
_kern_rename_attr(int fromFile,const char * fromName,int toFile,const char * toName)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
_kern_remove_attr(int fd,const char * name)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