xref: /haiku/src/build/libroot/fs.cpp (revision abba71575e34f84c3d75be9d29d6e6caa6c033db)
1 /*
2  * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <BeOSBuildCompatibility.h>
8 
9 #include "fs_impl.h"
10 
11 #include <dirent.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <utime.h>
18 #include <sys/stat.h>
19 #include <sys/time.h>
20 
21 #include <map>
22 #include <string>
23 
24 #include <fs_attr.h>
25 #include <NodeMonitor.h>	// for B_STAT_* flags
26 #include <syscalls.h>
27 
28 #include "fs_descriptors.h"
29 #include "NodeRef.h"
30 #include "remapped_functions.h"
31 
32 #if defined(HAIKU_HOST_PLATFORM_FREEBSD)
33 #	include "fs_freebsd.h"
34 #endif
35 
36 
37 using namespace std;
38 using namespace BPrivate;
39 
40 
41 #if defined(HAIKU_HOST_PLATFORM_FREEBSD)
42 #	define haiku_host_platform_read		haiku_freebsd_read
43 #	define haiku_host_platform_write	haiku_freebsd_write
44 #	define haiku_host_platform_readv	haiku_freebsd_readv
45 #	define haiku_host_platform_writev	haiku_freebsd_writev
46 #	define HAIKU_HOST_STAT_ATIM(x)		((x).st_atimespec)
47 #	define HAIKU_HOST_STAT_MTIM(x)		((x).st_mtimespec)
48 #elif defined(HAIKU_HOST_PLATFORM_DARWIN)
49 #	define haiku_host_platform_read		read
50 #	define haiku_host_platform_write	write
51 #	define haiku_host_platform_readv	readv
52 #	define haiku_host_platform_writev	writev
53 #	define HAIKU_HOST_STAT_ATIM(x)		((x).st_atimespec)
54 #	define HAIKU_HOST_STAT_MTIM(x)		((x).st_mtimespec)
55 #else
56 #	define haiku_host_platform_read		read
57 #	define haiku_host_platform_write	write
58 #	define haiku_host_platform_readv	readv
59 #	define haiku_host_platform_writev	writev
60 #	define HAIKU_HOST_STAT_ATIM(x)		((x).st_atim)
61 #	define HAIKU_HOST_STAT_MTIM(x)		((x).st_mtim)
62 #endif
63 
64 #define RETURN_AND_SET_ERRNO(err)			\
65 	do {									\
66 		__typeof(err) __result = (err);		\
67 		if (__result < 0) {					\
68 			errno = __result;				\
69 			return -1;						\
70 		}									\
71 		return __result;					\
72 	} while (0)
73 
74 
75 #if defined(_HAIKU_BUILD_NO_FUTIMENS) || defined(_HAIKU_BUILD_NO_FUTIMENS)
76 
77 template<typename File>
78 static int
79 utimes_helper(File& file, const struct timespec times[2])
80 {
81 	if (times == NULL)
82 		return file.SetTimes(NULL);
83 
84 	timeval timeBuffer[2];
85 	timeBuffer[0].tv_sec = times[0].tv_sec;
86 	timeBuffer[0].tv_usec = times[0].tv_nsec / 1000;
87 	timeBuffer[1].tv_sec = times[1].tv_sec;
88 	timeBuffer[1].tv_usec = times[1].tv_nsec / 1000;
89 
90 	if (times[0].tv_nsec == UTIME_OMIT || times[1].tv_nsec == UTIME_OMIT) {
91 		struct stat st;
92 		if (file.GetStat(st) != 0)
93 			return -1;
94 
95 		if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT)
96 			return 0;
97 
98 		if (times[0].tv_nsec == UTIME_OMIT) {
99 			timeBuffer[0].tv_sec = st.st_atimespec.tv_sec;
100 			timeBuffer[0].tv_usec = st.st_atimespec.tv_nsec / 1000;
101 		}
102 
103 		if (times[1].tv_nsec == UTIME_OMIT) {
104 			timeBuffer[1].tv_sec = st.st_mtimespec.tv_sec;
105 			timeBuffer[1].tv_usec = st.st_mtimespec.tv_nsec / 1000;
106 		}
107 	}
108 
109 	if (times[0].tv_nsec == UTIME_NOW || times[1].tv_nsec == UTIME_NOW) {
110 		timeval now;
111 		gettimeofday(&now, NULL);
112 
113 		if (times[0].tv_nsec == UTIME_NOW)
114 			timeBuffer[0] = now;
115 
116 		if (times[1].tv_nsec == UTIME_NOW)
117 			timeBuffer[1] = now;
118 	}
119 
120 	return file.SetTimes(timeBuffer);
121 }
122 
123 #endif	// _HAIKU_BUILD_NO_FUTIMENS || _HAIKU_BUILD_NO_FUTIMENS
124 
125 
126 #ifdef _HAIKU_BUILD_NO_FUTIMENS
127 
128 struct FDFile {
129 	FDFile(int fd)
130 		:
131 		fFD(fd)
132 	{
133 	}
134 
135 	int GetStat(struct stat& _st)
136 	{
137 		return fstat(fFD, &_st);
138 	}
139 
140 	int SetTimes(const timeval times[2])
141 	{
142 		return futimes(fFD, times);
143 	}
144 
145 private:
146 	int fFD;
147 };
148 
149 
150 int
151 futimens(int fd, const struct timespec times[2])
152 {
153 	FDFile file(fd);
154 	return utimes_helper(file, times);
155 }
156 
157 #endif	// _HAIKU_BUILD_NO_FUTIMENS
158 
159 #ifdef _HAIKU_BUILD_NO_UTIMENSAT
160 
161 struct FDPathFile {
162 	FDPathFile(int fd, const char* path, int flag)
163 		:
164 		fFD(fd),
165 		fPath(path),
166 		fFlag(flag)
167 	{
168 	}
169 
170 	int GetStat(struct stat& _st)
171 	{
172 		return fstatat(fFD, fPath, &_st, fFlag);
173 	}
174 
175 	int SetTimes(const timeval times[2])
176 	{
177 		// TODO: fFlag (AT_SYMLINK_NOFOLLOW) is not supported here!
178 		return futimesat(fFD, fPath, times);
179 	}
180 
181 private:
182 	int			fFD;
183 	const char*	fPath;
184 	int			fFlag;
185 };
186 
187 
188 int
189 utimensat(int fd, const char* path, const struct timespec times[2], int flag)
190 {
191 	FDPathFile file(fd, path, flag);
192 	return utimes_helper(file, times);
193 }
194 
195 #endif	// _HAIKU_BUILD_NO_UTIMENSAT
196 
197 
198 static status_t get_path(dev_t device, ino_t node, const char *name,
199 	string &path);
200 
201 
202 // find_dir_entry
203 static status_t
204 find_dir_entry(DIR *dir, const char *path, NodeRef ref, string &name,
205 	bool skipDot)
206 {
207 	// find the entry
208 	bool found = false;
209 	while (dirent *entry = readdir(dir)) {
210 		if ((strcmp(entry->d_name, ".") == 0 && skipDot)
211 			|| strcmp(entry->d_name, "..") == 0) {
212 			// skip "." and ".."
213 		} else /*if (entry->d_ino == ref.node)*/ {
214 				// Note: Linux doesn't seem to translate dirent::d_ino of
215 				// mount points. Thus we always have to lstat().
216 			// We also need to compare the device, which is generally not
217 			// included in the dirent structure. Hence we lstat().
218 			string entryPath(path);
219 			entryPath += '/';
220 			entryPath += entry->d_name;
221 			struct stat st;
222 			if (lstat(entryPath.c_str(), &st) == 0) {
223 				if (NodeRef(st) == ref) {
224 					name = entry->d_name;
225 					found = true;
226 					break;
227 				}
228 			}
229 		}
230 	}
231 
232 	if (!found)
233 		return B_ENTRY_NOT_FOUND;
234 
235 	return B_OK;
236 }
237 
238 // find_dir_entry
239 static status_t
240 find_dir_entry(const char *path, NodeRef ref, string &name, bool skipDot)
241 {
242 	// open dir
243 	DIR *dir = opendir(path);
244 	if (!dir)
245 		return errno;
246 
247 	status_t error = find_dir_entry(dir, path, ref, name, skipDot);
248 
249 	// close dir
250 	closedir(dir);
251 
252 	return error;
253 }
254 
255 
256 static bool
257 guess_normalized_dir_path(string path, NodeRef ref, string& _normalizedPath)
258 {
259 	// We assume the CWD is normalized and hope that the directory is an
260 	// ancestor of it. We just chop off path components until we find a match or
261 	// hit root.
262 	char cwd[B_PATH_NAME_LENGTH];
263 	if (getcwd(cwd, sizeof(cwd)) == NULL)
264 		return false;
265 
266 	while (cwd[0] == '/') {
267 		struct stat st;
268 		if (stat(cwd, &st) == 0) {
269 			if (st.st_dev == ref.device && st.st_ino == ref.node) {
270 				_normalizedPath = cwd;
271 				return true;
272 			}
273 		}
274 
275 		*strrchr(cwd, '/') = '\0';
276 	}
277 
278 	// TODO: If path is absolute, we could also try to work with that, though
279 	// the other way around -- trying prefixes until we hit a "." or ".."
280 	// component.
281 
282 	return false;
283 }
284 
285 
286 // normalize_dir_path
287 static status_t
288 normalize_dir_path(string path, NodeRef ref, string &normalizedPath)
289 {
290 	// get parent path
291 	path += "/..";
292 
293 	// stat the parent dir
294 	struct stat st;
295 	if (lstat(path.c_str(), &st) < 0)
296 		return errno;
297 
298 	// root dir?
299 	NodeRef parentRef(st);
300 	if (parentRef == ref) {
301 		normalizedPath = "/";
302 		return 0;
303 	}
304 
305 	// find the entry
306 	string name;
307 	status_t error = find_dir_entry(path.c_str(), ref, name, true)				;
308 	if (error != B_OK) {
309 		if (error != B_ENTRY_NOT_FOUND) {
310 			// We couldn't open the directory. This might be because we don't
311 			// have read permission. We're OK with not fully normalizing the
312 			// path and try to guess the path in this case. Note: We don't check
313 			// error for B_PERMISSION_DENIED, since opendir() may clobber the
314 			// actual kernel error code with something not helpful.
315 			if (guess_normalized_dir_path(path, ref, normalizedPath))
316 				return B_OK;
317 		}
318 
319 		return error;
320 	}
321 
322 	// recurse to get the parent dir path, if found
323 	error = normalize_dir_path(path, parentRef, normalizedPath);
324 	if (error != 0)
325 		return error;
326 
327 	// construct the normalizedPath
328 	if (normalizedPath.length() > 1) // don't append "/", if parent is root
329 		normalizedPath += '/';
330 	normalizedPath += name;
331 
332 	return 0;
333 }
334 
335 // normalize_dir_path
336 static status_t
337 normalize_dir_path(const char *path, string &normalizedPath)
338 {
339 	// stat() the dir
340 	struct stat st;
341 	if (stat(path, &st) < 0)
342 		return errno;
343 
344 	return normalize_dir_path(path, NodeRef(st), normalizedPath);
345 }
346 
347 // normalize_entry_path
348 static status_t
349 normalize_entry_path(const char *path, string &normalizedPath)
350 {
351 	const char *dirPath = NULL;
352 	const char *leafName = NULL;
353 
354 	string dirPathString;
355 	if (const char *lastSlash = strrchr(path, '/')) {
356 		// found a slash: decompose into dir path and leaf name
357 		leafName = lastSlash + 1;
358 		if (leafName[0] == '\0') {
359 			// slash is at the end: the whole path is a dir name
360 			leafName = NULL;
361 		} else {
362 			dirPathString = string(path, leafName - path);
363 			dirPath = dirPathString.c_str();
364 		}
365 
366 	} else {
367 		// path contains no slash, so it is a path relative to the current dir
368 		dirPath = ".";
369 		leafName = path;
370 	}
371 
372 	// catch special case: no leaf, or leaf is a directory
373 	if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0)
374 		return normalize_dir_path(path, normalizedPath);
375 
376 	// normalize the dir path
377 	status_t error = normalize_dir_path(dirPath, normalizedPath);
378 	if (error != B_OK)
379 		return error;
380 
381 	// append the leaf name
382 	if (normalizedPath.length() > 1) // don't append "/", if parent is root
383 		normalizedPath += '/';
384 	normalizedPath += leafName;
385 
386 	return B_OK;
387 }
388 
389 
390 // #pragma mark -
391 
392 typedef map<NodeRef, string> DirPathMap;
393 static DirPathMap sDirPathMap;
394 
395 // get_path
396 static status_t
397 get_path(const NodeRef *ref, const char *name, string &path)
398 {
399 	if (!ref && !name)
400 		return B_BAD_VALUE;
401 
402 	// no ref or absolute path
403 	if (!ref || (name && name[0] == '/')) {
404 		path = name;
405 		return B_OK;
406 	}
407 
408 	// get the dir path
409 	if (ref) {
410 		DirPathMap::iterator it = sDirPathMap.find(*ref);
411 		if (it == sDirPathMap.end())
412 			return B_ENTRY_NOT_FOUND;
413 
414 		path = it->second;
415 
416 		// stat the path to check, if it is still valid
417 		struct stat st;
418 		if (lstat(path.c_str(), &st) < 0) {
419 			sDirPathMap.erase(it);
420 			return errno;
421 		}
422 
423 		// compare the NodeRef
424 		if (NodeRef(st) != *ref) {
425 			sDirPathMap.erase(it);
426 			return B_ENTRY_NOT_FOUND;
427 		}
428 
429 		// still a directory?
430 		if (!S_ISDIR(st.st_mode)) {
431 			sDirPathMap.erase(it);
432 			return B_NOT_A_DIRECTORY;
433 		}
434 	}
435 
436 	// if there's a name, append it
437 	if (name) {
438 		path += '/';
439 		path += name;
440 	}
441 
442 	return B_OK;
443 }
444 
445 // get_path
446 status_t
447 BPrivate::get_path(int fd, const char *name, string &path)
448 {
449 	// get the node ref for the fd, if any, and the path part is not absolute
450 	if (fd >= 0 && !(name && name[0] == '/')) {
451 		// get descriptor
452 		Descriptor *descriptor = get_descriptor(fd);
453 		if (!descriptor)
454 			return B_FILE_ERROR;
455 
456 		// Handle symlink descriptors here explicitly, so this function can be
457 		// used more flexibly.
458 		if (SymlinkDescriptor* symlinkDescriptor
459 				= dynamic_cast<SymlinkDescriptor*>(descriptor)) {
460 			path = symlinkDescriptor->path;
461 			if (name == NULL)
462 				return B_OK;
463 			path += '/';
464 			path += name;
465 			return B_OK;
466 		}
467 
468 		// get node ref for the descriptor
469 		NodeRef ref;
470 		status_t error = descriptor->GetNodeRef(ref);
471 		if (error != B_OK)
472 			return error;
473 
474 		return ::get_path(&ref, name, path);
475 
476 	} else	// no descriptor or absolute path
477 		return ::get_path((NodeRef*)NULL, name, path);
478 }
479 
480 // get_path
481 static status_t
482 get_path(dev_t device, ino_t directory, const char *name, string &path)
483 {
484 	NodeRef ref;
485 	ref.device = device;
486 	ref.node = directory;
487 
488 	return get_path(&ref, name, path);
489 }
490 
491 // add_dir_path
492 static void
493 add_dir_path(const char *path, const NodeRef &ref)
494 {
495 	// add the normalized path
496 	string normalizedPath;
497 	if (normalize_dir_path(path, normalizedPath) == B_OK)
498 		sDirPathMap[ref] = normalizedPath;
499 }
500 
501 
502 // #pragma mark -
503 
504 // _kern_entry_ref_to_path
505 status_t
506 _kern_entry_ref_to_path(dev_t device, ino_t node, const char *leaf,
507 	char *userPath, size_t pathLength)
508 {
509 	// get the path
510 	string path;
511 	status_t error = get_path(device, node, leaf, path);
512 	if (error != B_OK)
513 		return error;
514 
515 	// copy it back to the user buffer
516 	if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength)
517 		return B_BUFFER_OVERFLOW;
518 
519 	return B_OK;
520 }
521 
522 
523 // #pragma mark -
524 
525 // _kern_create_dir
526 status_t
527 _kern_create_dir(int fd, const char *path, int perms)
528 {
529 	// get a usable path
530 	string realPath;
531 	status_t error = get_path(fd, path, realPath);
532 	if (error != B_OK)
533 		return error;
534 
535 	// mkdir
536 	if (mkdir(realPath.c_str(), perms) < 0)
537 		return errno;
538 
539 	return B_OK;
540 }
541 
542 // _kern_create_dir_entry_ref
543 status_t
544 _kern_create_dir_entry_ref(dev_t device, ino_t node, const char *name,
545 	int perms)
546 {
547 	// get a usable path
548 	string realPath;
549 	status_t error = get_path(device, node, name, realPath);
550 	if (error != B_OK)
551 		return error;
552 
553 	// mkdir
554 	if (mkdir(realPath.c_str(), perms) < 0)
555 		return errno;
556 
557 	return B_OK;
558 }
559 
560 // open_dir
561 static int
562 open_dir(const char *path)
563 {
564 	// open the dir
565 	DIR *dir = opendir(path);
566 	if (!dir)
567 		return errno;
568 
569 	// stat the entry
570 	struct stat st;
571 	if (stat(path, &st) < 0) {
572 		closedir(dir);
573 		return errno;
574 	}
575 
576 	if (!S_ISDIR(st.st_mode)) {
577 		closedir(dir);
578 		return B_NOT_A_DIRECTORY;
579 	}
580 
581 	// cache dir path
582 	NodeRef ref(st);
583 	add_dir_path(path, ref);
584 
585 	// create descriptor
586 	DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref);
587 	return add_descriptor(descriptor);
588 }
589 
590 // _kern_open_dir
591 int
592 _kern_open_dir(int fd, const char *path)
593 {
594 	// get a usable path
595 	string realPath;
596 	status_t error = get_path(fd, path, realPath);
597 	if (error != B_OK)
598 		return error;
599 
600 	return open_dir(realPath.c_str());
601 }
602 
603 // _kern_open_dir_entry_ref
604 int
605 _kern_open_dir_entry_ref(dev_t device, ino_t node, const char *name)
606 {
607 	// get a usable path
608 	string realPath;
609 	status_t error = get_path(device, node, name, realPath);
610 	if (error != B_OK)
611 		return error;
612 
613 	return open_dir(realPath.c_str());
614 }
615 
616 // _kern_open_parent_dir
617 int
618 _kern_open_parent_dir(int fd, char *name, size_t nameLength)
619 {
620 	// get a usable path
621 	string realPath;
622 	status_t error = get_path(fd, NULL, realPath);
623 	if (error != B_OK)
624 		return error;
625 
626 	// stat the entry
627 	struct stat st;
628 	if (stat(realPath.c_str(), &st) < 0)
629 		return errno;
630 
631 	if (!S_ISDIR(st.st_mode))
632 		return B_NOT_A_DIRECTORY;
633 
634 	// get the entry name
635 	realPath += "/..";
636 	string entryName;
637 	error = find_dir_entry(realPath.c_str(), NodeRef(st),
638 		entryName, false);
639 	if (error != B_OK)
640 		return error;
641 
642 	if (strlcpy(name, entryName.c_str(), nameLength) >= nameLength)
643 		return B_BUFFER_OVERFLOW;
644 
645 	// open the parent directory
646 
647 	return open_dir(realPath.c_str());
648 }
649 
650 // _kern_read_dir
651 ssize_t
652 _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize,
653 	uint32 maxCount)
654 {
655 	if (maxCount <= 0)
656 		return B_BAD_VALUE;
657 
658 	// get the descriptor
659 	DirectoryDescriptor *descriptor
660 		= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
661 	if (!descriptor)
662 		return B_FILE_ERROR;
663 
664 	// get the next entry
665 	dirent *entry;
666 	errno = 0;
667 	if (dynamic_cast<AttrDirDescriptor*>(descriptor))
668 		entry = fs_read_attr_dir(descriptor->dir);
669 	else
670 		entry = readdir(descriptor->dir);
671 	if (!entry)
672 		return errno;
673 
674 	// copy the entry
675 	int entryLen = &entry->d_name[strlen(entry->d_name) + 1] - (char*)entry;
676 	if (entryLen > (int)bufferSize)
677 		return B_BUFFER_OVERFLOW;
678 
679 	memcpy(buffer, entry, entryLen);
680 
681 	return 1;
682 }
683 
684 // _kern_rewind_dir
685 status_t
686 _kern_rewind_dir(int fd)
687 {
688 	// get the descriptor
689 	DirectoryDescriptor *descriptor
690 		= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
691 	if (!descriptor)
692 		return B_FILE_ERROR;
693 
694 	// rewind
695 	if (dynamic_cast<AttrDirDescriptor*>(descriptor))
696 		fs_rewind_attr_dir(descriptor->dir);
697 	else
698 		rewinddir(descriptor->dir);
699 
700 	return B_OK;
701 }
702 
703 
704 // #pragma mark -
705 
706 // open_file
707 static int
708 open_file(const char *path, int openMode, int perms)
709 {
710 	// stat the node
711 	bool exists = true;
712 	struct stat st;
713 	if (lstat(path, &st) < 0) {
714 		exists = false;
715 		if (!(openMode & O_CREAT))
716 			return errno;
717 	}
718 
719 	Descriptor *descriptor;
720 	if (exists && S_ISLNK(st.st_mode) && (openMode & O_NOTRAVERSE) != 0) {
721 		// a symlink not to be followed: create a special descriptor
722 		// normalize path first
723 		string normalizedPath;
724 		status_t error = normalize_entry_path(path, normalizedPath);
725 		if (error != B_OK)
726 			return error;
727 
728 		descriptor = new SymlinkDescriptor(normalizedPath.c_str());
729 	} else {
730 		// open the file
731 		openMode &= ~O_NOTRAVERSE;
732 		int newFD = open(path, openMode, perms);
733 		if (newFD < 0)
734 			return errno;
735 
736 		descriptor = new FileDescriptor(newFD);
737 	}
738 
739 	// cache path, if this is a directory
740 	if (exists && S_ISDIR(st.st_mode))
741 		add_dir_path(path, NodeRef(st));
742 
743 	return add_descriptor(descriptor);
744 }
745 
746 // _kern_open
747 int
748 _kern_open(int fd, const char *path, int openMode, int perms)
749 {
750 	// get a usable path
751 	string realPath;
752 	status_t error = get_path(fd, path, realPath);
753 	if (error != B_OK)
754 		return error;
755 
756 	return open_file(realPath.c_str(), openMode, perms);
757 }
758 
759 // _kern_open_entry_ref
760 int
761 _kern_open_entry_ref(dev_t device, ino_t node, const char *name,
762 	int openMode, int perms)
763 {
764 	// get a usable path
765 	string realPath;
766 	status_t error = get_path(device, node, name, realPath);
767 	if (error != B_OK)
768 		return error;
769 
770 	return open_file(realPath.c_str(), openMode, perms);
771 }
772 
773 // _kern_seek
774 off_t
775 _kern_seek(int fd, off_t pos, int seekType)
776 {
777 	// get the descriptor
778 	FileDescriptor *descriptor
779 		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
780 	if (!descriptor)
781 		return B_FILE_ERROR;
782 
783 	// seek
784 	off_t result = lseek(descriptor->fd, pos, seekType);
785 	if (result < 0)
786 		return errno;
787 
788 	return result;
789 }
790 
791 // _kern_read
792 ssize_t
793 _kern_read(int fd, off_t pos, void *buffer, size_t bufferSize)
794 {
795 	// get the descriptor
796 	FileDescriptor *descriptor
797 		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
798 	if (!descriptor)
799 		return B_FILE_ERROR;
800 
801 	// seek
802 	if (pos != -1) {
803 		off_t result = lseek(descriptor->fd, pos, SEEK_SET);
804 		if (result < 0)
805 			return errno;
806 	}
807 
808 	// read
809 	ssize_t bytesRead = haiku_host_platform_read(descriptor->fd, buffer,
810 		bufferSize);
811 	if (bytesRead < 0)
812 		return errno;
813 
814 	return bytesRead;
815 }
816 
817 // _kern_write
818 ssize_t
819 _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize)
820 {
821 	// get the descriptor
822 	FileDescriptor *descriptor
823 		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
824 	if (!descriptor)
825 		return B_FILE_ERROR;
826 
827 	// seek
828 	if (pos != -1) {
829 		off_t result = lseek(descriptor->fd, pos, SEEK_SET);
830 		if (result < 0)
831 			return errno;
832 	}
833 
834 	// read
835 	ssize_t bytesWritten = haiku_host_platform_write(descriptor->fd, buffer,
836 		bufferSize);
837 	if (bytesWritten < 0)
838 		return errno;
839 
840 	return bytesWritten;
841 }
842 
843 // _kern_close
844 status_t
845 _kern_close(int fd)
846 {
847 	return delete_descriptor(fd);
848 }
849 
850 // _kern_dup
851 int
852 _kern_dup(int fd)
853 {
854 	// get the descriptor
855 	Descriptor *descriptor = get_descriptor(fd);
856 	if (!descriptor)
857 		return B_FILE_ERROR;
858 
859 	// clone it
860 	Descriptor *clone;
861 	status_t error = descriptor->Dup(clone);
862 	if (error != B_OK)
863 		return error;
864 
865 	return add_descriptor(clone);
866 }
867 
868 // _kern_fsync
869 status_t
870 _kern_fsync(int fd)
871 {
872 	// get the descriptor
873 	FileDescriptor *descriptor
874 		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
875 	if (!descriptor)
876 		return B_FILE_ERROR;
877 
878 	// sync
879 	if (fsync(descriptor->fd) < 0)
880 		return errno;
881 
882 	return B_OK;
883 }
884 
885 // _kern_read_stat
886 status_t
887 _kern_read_stat(int fd, const char *path, bool traverseLink,
888 	struct stat *st, size_t statSize)
889 {
890 	if (path) {
891 		// get a usable path
892 		string realPath;
893 		status_t error = get_path(fd, path, realPath);
894 		if (error != B_OK)
895 			return error;
896 
897 		// stat
898 		int result;
899 		if (traverseLink)
900 			result = stat(realPath.c_str(), st);
901 		else
902 			result = lstat(realPath.c_str(), st);
903 
904 		if (result < 0)
905 			return errno;
906 	} else {
907 		Descriptor *descriptor = get_descriptor(fd);
908 		if (!descriptor)
909 			return B_FILE_ERROR;
910 
911 		return descriptor->GetStat(traverseLink, st);
912 	}
913 
914 	return B_OK;
915 }
916 
917 // _kern_write_stat
918 status_t
919 _kern_write_stat(int fd, const char *path, bool traverseLink,
920 	const struct stat *st, size_t statSize, int statMask)
921 {
922 	// get a usable path
923 	int realFD = -1;
924 	string realPath;
925 	status_t error;
926 	bool isSymlink = false;
927 	if (path) {
928 		error = get_path(fd, path, realPath);
929 		if (error != B_OK)
930 			return error;
931 
932 		// stat it to see, if it is a symlink
933 		struct stat tmpStat;
934 		if (lstat(realPath.c_str(), &tmpStat) < 0)
935 			return errno;
936 
937 		isSymlink = S_ISLNK(tmpStat.st_mode);
938 
939 	} else {
940 		Descriptor *descriptor = get_descriptor(fd);
941 		if (!descriptor)
942 			return B_FILE_ERROR;
943 
944 		if (FileDescriptor *fileFD
945 				= dynamic_cast<FileDescriptor*>(descriptor)) {
946 			realFD = fileFD->fd;
947 
948 		} else if (dynamic_cast<DirectoryDescriptor*>(descriptor)) {
949 			error = get_path(fd, NULL, realPath);
950 			if (error != B_OK)
951 				return error;
952 
953 		} else if (SymlinkDescriptor *linkFD
954 				= dynamic_cast<SymlinkDescriptor*>(descriptor)) {
955 			realPath = linkFD->path;
956 			isSymlink = true;
957 
958 		} else
959 			return B_FILE_ERROR;
960 	}
961 
962 	// We're screwed, if the node to manipulate is a symlink. All the
963 	// available functions traverse symlinks.
964 	if (isSymlink && !traverseLink)
965 		return B_ERROR;
966 
967 	if (realFD >= 0) {
968 		if (statMask & B_STAT_MODE) {
969 			if (fchmod(realFD, st->st_mode) < 0)
970 				return errno;
971 		}
972 
973 		if (statMask & B_STAT_UID) {
974 			if (fchown(realFD, st->st_uid, (gid_t)-1) < 0)
975 				return errno;
976 		}
977 
978 		if (statMask & B_STAT_GID) {
979 			if (fchown(realFD, (uid_t)-1, st->st_gid) < 0)
980 				return errno;
981 		}
982 
983 		if (statMask & B_STAT_SIZE) {
984 			if (ftruncate(realFD, st->st_size) < 0)
985 				return errno;
986 		}
987 
988 		// The timestamps can only be set via utime(), but that requires a
989 		// path we don't have.
990 		if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME
991 				| B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) {
992 			return B_ERROR;
993 		}
994 
995 		return 0;
996 
997 	} else {
998 		if (statMask & B_STAT_MODE) {
999 			if (chmod(realPath.c_str(), st->st_mode) < 0)
1000 				return errno;
1001 		}
1002 
1003 		if (statMask & B_STAT_UID) {
1004 			if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0)
1005 				return errno;
1006 		}
1007 
1008 		if (statMask & B_STAT_GID) {
1009 			if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0)
1010 				return errno;
1011 		}
1012 
1013 		if (statMask & B_STAT_SIZE) {
1014 			if (truncate(realPath.c_str(), st->st_size) < 0)
1015 				return errno;
1016 		}
1017 
1018 		if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
1019 			// Grab the previous mod and access times so we only overwrite
1020 			// the specified time and not both
1021 			struct stat oldStat;
1022 			if (~statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
1023 				if (stat(realPath.c_str(), &oldStat) < 0)
1024 					return errno;
1025 			}
1026 
1027 			utimbuf buffer;
1028 			buffer.actime = (statMask & B_STAT_ACCESS_TIME) ? st->st_atime : oldStat.st_atime;
1029 			buffer.modtime = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtime : oldStat.st_mtime;
1030 			if (utime(realPath.c_str(), &buffer) < 0)
1031 				return errno;
1032 		}
1033 
1034 		// not supported
1035 		if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME))
1036 			return B_ERROR;
1037 	}
1038 
1039 	return B_OK;
1040 }
1041 
1042 
1043 // #pragma mark -
1044 
1045 // _kern_create_symlink
1046 status_t
1047 _kern_create_symlink(int fd, const char *path, const char *toPath, int mode)
1048 {
1049 	// Note: path must not be NULL, so this will always work.
1050 	// get a usable path
1051 	string realPath;
1052 	status_t error = get_path(fd, path, realPath);
1053 	if (error != B_OK)
1054 		return error;
1055 
1056 	// symlink
1057 	if (symlink(toPath, realPath.c_str()) < 0)
1058 		return errno;
1059 
1060 	return B_OK;
1061 }
1062 
1063 // _kern_read_link
1064 status_t
1065 _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize)
1066 {
1067 	// get the path
1068 	string realPath;
1069 	status_t error = get_path(fd, path, realPath);
1070 	if (error != B_OK)
1071 		return error;
1072 
1073 	ssize_t bytesRead = readlink(realPath.c_str(), buffer, *_bufferSize);
1074 	if (bytesRead < 0)
1075 		return errno;
1076 
1077 	// On Haiku _kern_read_link will return the length of the link, *not*
1078 	// the number of bytes written to the buffer parameter. To emulate that
1079 	// here, we use readlink() to read the links contents, and then if it is
1080 	// possible that the link contents didn't fit in buffer, we'll fall back
1081 	// to lstat() to get the full length of the link.
1082 	if (static_cast<size_t>(bytesRead) < *_bufferSize) {
1083 		buffer[bytesRead] = '\0';
1084 		*_bufferSize = bytesRead;
1085 	} else {
1086 		// The number of bytes copied by readlink() tells us that the entire
1087 		// link might not have fit into buffer. Fall back to getting the full
1088 		// length of the link using lstat.
1089 		struct stat linkStat;
1090 		if (lstat(realPath.c_str(), &linkStat) != 0)
1091 			return errno;
1092 
1093 		*_bufferSize = linkStat.st_size;
1094 	}
1095 
1096 	return B_OK;
1097 }
1098 
1099 // _kern_unlink
1100 status_t
1101 _kern_unlink(int fd, const char *path)
1102 {
1103 	// get a usable path
1104 	string realPath;
1105 	status_t error = get_path(fd, path, realPath);
1106 	if (error != B_OK)
1107 		return error;
1108 
1109 	// unlink
1110 	if (unlink(realPath.c_str()) < 0)
1111 		return errno;
1112 
1113 	return B_OK;
1114 }
1115 
1116 // _kern_rename
1117 status_t
1118 _kern_rename(int oldDir, const char *oldPath, int newDir, const char *newPath)
1119 {
1120 	// get usable paths
1121 	string realOldPath;
1122 	status_t error = get_path(oldDir, oldPath, realOldPath);
1123 	if (error != B_OK)
1124 		return error;
1125 
1126 	string realNewPath;
1127 	error = get_path(newDir, newPath, realNewPath);
1128 	if (error != B_OK)
1129 		return error;
1130 
1131 	// rename
1132 	if (rename(realOldPath.c_str(), realNewPath.c_str()) < 0)
1133 		return errno;
1134 
1135 	return B_OK;
1136 }
1137 
1138 
1139 // #pragma mark -
1140 
1141 // _kern_lock_node
1142 status_t
1143 _kern_lock_node(int fd)
1144 {
1145 	return B_ERROR;
1146 }
1147 
1148 // _kern_unlock_node
1149 status_t
1150 _kern_unlock_node(int fd)
1151 {
1152 	return B_ERROR;
1153 }
1154 
1155 
1156 // #pragma mark -
1157 
1158 #if !defined(HAIKU_HOST_PLATFORM_HAIKU)
1159 // read_pos
1160 ssize_t
1161 read_pos(int fd, off_t pos, void *buffer, size_t bufferSize)
1162 {
1163 	// seek
1164 	off_t result = lseek(fd, pos, SEEK_SET);
1165 	if (result < 0)
1166 		return errno;
1167 
1168 	// read
1169 	ssize_t bytesRead = haiku_host_platform_read(fd, buffer, bufferSize);
1170 	if (bytesRead < 0) {
1171 		errno = bytesRead;
1172 		return -1;
1173 	}
1174 
1175 	return bytesRead;
1176 }
1177 
1178 // write_pos
1179 ssize_t
1180 write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize)
1181 {
1182 	// If this is an attribute descriptor, let it do the job.
1183 	AttributeDescriptor* descriptor
1184 		= dynamic_cast<AttributeDescriptor*>(get_descriptor(fd));
1185 	if (descriptor != NULL) {
1186 		status_t error = descriptor->Write(pos, buffer, bufferSize);
1187 		if (error != B_OK) {
1188 			errno = error;
1189 			return -1;
1190 		}
1191 
1192 		return bufferSize;
1193 	}
1194 
1195 	// seek
1196 	off_t result = lseek(fd, pos, SEEK_SET);
1197 	if (result < 0)
1198 		return errno;
1199 
1200 	// write
1201 	ssize_t bytesWritten = haiku_host_platform_write(fd, buffer, bufferSize);
1202 	if (bytesWritten < 0) {
1203 		errno = bytesWritten;
1204 		return -1;
1205 	}
1206 
1207 	return bytesWritten;
1208 }
1209 
1210 // readv_pos
1211 ssize_t
1212 readv_pos(int fd, off_t pos, const struct iovec *vec, int count)
1213 {
1214 	// seek
1215 	off_t result = lseek(fd, pos, SEEK_SET);
1216 	if (result < 0)
1217 		return errno;
1218 
1219 	// read
1220 	ssize_t bytesRead = haiku_host_platform_readv(fd, vec, count);
1221 	if (bytesRead < 0) {
1222 		errno = bytesRead;
1223 		return -1;
1224 	}
1225 
1226 	return bytesRead;
1227 }
1228 
1229 // writev_pos
1230 ssize_t
1231 writev_pos(int fd, off_t pos, const struct iovec *vec, int count)
1232 {
1233 	// seek
1234 	off_t result = lseek(fd, pos, SEEK_SET);
1235 	if (result < 0)
1236 		return errno;
1237 
1238 	// read
1239 	ssize_t bytesWritten = haiku_host_platform_writev(fd, vec, count);
1240 	if (bytesWritten < 0) {
1241 		errno = bytesWritten;
1242 		return -1;
1243 	}
1244 
1245 	return bytesWritten;
1246 }
1247 #endif
1248 
1249 
1250 // #pragma mark -
1251 
1252 
1253 int
1254 _haiku_build_fchmod(int fd, mode_t mode)
1255 {
1256 	return _haiku_build_fchmodat(fd, NULL, mode, AT_SYMLINK_NOFOLLOW);
1257 }
1258 
1259 
1260 int
1261 _haiku_build_fchmodat(int fd, const char* path, mode_t mode, int flag)
1262 {
1263 	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1264 		return fchmodat(fd, path, mode, flag);
1265 
1266 	struct stat st;
1267 	st.st_mode = mode;
1268 
1269 	RETURN_AND_SET_ERRNO(_kern_write_stat(fd, path,
1270 		(flag & AT_SYMLINK_NOFOLLOW) == 0, &st, sizeof(st), B_STAT_MODE));
1271 }
1272 
1273 
1274 int
1275 _haiku_build_fstat(int fd, struct stat* st)
1276 {
1277 	return _haiku_build_fstatat(fd, NULL, st, AT_SYMLINK_NOFOLLOW);
1278 }
1279 
1280 
1281 int
1282 _haiku_build_fstatat(int fd, const char* path, struct stat* st, int flag)
1283 {
1284 	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1285 		return fstatat(fd, path, st, flag);
1286 
1287 	RETURN_AND_SET_ERRNO(_kern_read_stat(fd, path,
1288 		(flag & AT_SYMLINK_NOFOLLOW) == 0, st, sizeof(*st)));
1289 }
1290 
1291 
1292 int
1293 _haiku_build_mkdirat(int fd, const char* path, mode_t mode)
1294 {
1295 	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1296 		return mkdirat(fd, path, mode);
1297 
1298 	RETURN_AND_SET_ERRNO(_kern_create_dir(fd, path, mode));
1299 }
1300 
1301 
1302 int
1303 _haiku_build_mkfifoat(int fd, const char* path, mode_t mode)
1304 {
1305 	return mkfifoat(fd, path, mode);
1306 
1307 	// TODO: Handle non-system FDs.
1308 }
1309 
1310 
1311 int
1312 _haiku_build_utimensat(int fd, const char* path, const struct timespec times[2],
1313 	int flag)
1314 {
1315 	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1316 		return utimensat(fd, path, times, flag);
1317 
1318 	struct stat stat;
1319 	status_t status;
1320 	uint32 mask = 0;
1321 
1322 	// Init the stat time fields to the current time, if at least one time is
1323 	// supposed to be set to it.
1324 	if (times == NULL || times[0].tv_nsec == UTIME_NOW
1325 		|| times[1].tv_nsec == UTIME_NOW) {
1326 		timeval now;
1327 		gettimeofday(&now, NULL);
1328 		HAIKU_HOST_STAT_ATIM(stat).tv_sec
1329 			= HAIKU_HOST_STAT_MTIM(stat).tv_sec = now.tv_sec;
1330 		HAIKU_HOST_STAT_ATIM(stat).tv_nsec
1331 			= HAIKU_HOST_STAT_MTIM(stat).tv_nsec = now.tv_usec * 1000;
1332 	}
1333 
1334 	if (times != NULL) {
1335 		// access time
1336 		if (times[0].tv_nsec != UTIME_OMIT) {
1337 			mask |= B_STAT_ACCESS_TIME;
1338 
1339 			if (times[0].tv_nsec != UTIME_NOW) {
1340 				if (times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999)
1341 					RETURN_AND_SET_ERRNO(EINVAL);
1342 			}
1343 
1344 			HAIKU_HOST_STAT_ATIM(stat) = times[0];
1345 		}
1346 
1347 		// modified time
1348 		if (times[1].tv_nsec != UTIME_OMIT) {
1349 			mask |= B_STAT_MODIFICATION_TIME;
1350 
1351 			if (times[1].tv_nsec != UTIME_NOW) {
1352 				if (times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999)
1353 					RETURN_AND_SET_ERRNO(EINVAL);
1354 			}
1355 
1356 			HAIKU_HOST_STAT_MTIM(stat) = times[1];
1357 		}
1358 	} else
1359 		mask |= B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME;
1360 
1361 	// set the times -- as per spec we even need to do this, if both have
1362 	// UTIME_OMIT set
1363 	status = _kern_write_stat(fd, path, (flag & AT_SYMLINK_NOFOLLOW) == 0,
1364 		&stat, sizeof(struct stat), mask);
1365 
1366 	RETURN_AND_SET_ERRNO(status);
1367 }
1368 
1369 
1370 int
1371 _haiku_build_futimens(int fd, const struct timespec times[2])
1372 {
1373 	return _haiku_build_utimensat(fd, NULL, times, AT_SYMLINK_NOFOLLOW);
1374 }
1375 
1376 
1377 int
1378 _haiku_build_faccessat(int fd, const char* path, int accessMode, int flag)
1379 {
1380 	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1381 		return faccessat(fd, path, accessMode, flag);
1382 
1383 	// stat the file
1384 	struct stat st;
1385 	status_t error = _kern_read_stat(fd, path, false, &st, sizeof(st));
1386 	if (error != B_OK)
1387 		RETURN_AND_SET_ERRNO(error);
1388 
1389 	// get the current user
1390 	uid_t uid = (flag & AT_EACCESS) != 0 ? geteuid() : getuid();
1391 
1392 	int fileMode = 0;
1393 
1394 	if (uid == 0) {
1395 		// user is root
1396 		// root has always read/write permission, but at least one of the
1397 		// X bits must be set for execute permission
1398 		fileMode = R_OK | W_OK;
1399 		if ((st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)
1400 			fileMode |= X_OK;
1401 	} else if (st.st_uid == uid) {
1402 		// user is node owner
1403 		if ((st.st_mode & S_IRUSR) != 0)
1404 			fileMode |= R_OK;
1405 		if ((st.st_mode & S_IWUSR) != 0)
1406 			fileMode |= W_OK;
1407 		if ((st.st_mode & S_IXUSR) != 0)
1408 			fileMode |= X_OK;
1409 	} else if (st.st_gid == ((flag & AT_EACCESS) != 0 ? getegid() : getgid())) {
1410 		// user is in owning group
1411 		if ((st.st_mode & S_IRGRP) != 0)
1412 			fileMode |= R_OK;
1413 		if ((st.st_mode & S_IWGRP) != 0)
1414 			fileMode |= W_OK;
1415 		if ((st.st_mode & S_IXGRP) != 0)
1416 			fileMode |= X_OK;
1417 	} else {
1418 		// user is one of the others
1419 		if ((st.st_mode & S_IROTH) != 0)
1420 			fileMode |= R_OK;
1421 		if ((st.st_mode & S_IWOTH) != 0)
1422 			fileMode |= W_OK;
1423 		if ((st.st_mode & S_IXOTH) != 0)
1424 			fileMode |= X_OK;
1425 	}
1426 
1427 	if ((accessMode & ~fileMode) != 0)
1428 		RETURN_AND_SET_ERRNO(EACCES);
1429 
1430 	return 0;
1431 }
1432 
1433 
1434 int
1435 _haiku_build_fchdir(int fd)
1436 {
1437 	if (is_unknown_or_system_descriptor(fd))
1438 		return fchdir(fd);
1439 
1440 	RETURN_AND_SET_ERRNO(B_FILE_ERROR);
1441 }
1442 
1443 
1444 int
1445 _haiku_build_close(int fd)
1446 {
1447 	if (get_descriptor(fd) == NULL)
1448 		return close(fd);
1449 
1450 	RETURN_AND_SET_ERRNO(_kern_close(fd));
1451 }
1452 
1453 
1454 int
1455 _haiku_build_dup(int fd)
1456 {
1457 	if (get_descriptor(fd) == NULL)
1458 		return close(fd);
1459 
1460 	RETURN_AND_SET_ERRNO(_kern_dup(fd));
1461 }
1462 
1463 
1464 int
1465 _haiku_build_dup2(int fd1, int fd2)
1466 {
1467 	if (is_unknown_or_system_descriptor(fd1))
1468 		return dup2(fd1, fd2);
1469 
1470 	// TODO: Handle non-system FDs.
1471 	RETURN_AND_SET_ERRNO(B_NOT_SUPPORTED);
1472 }
1473 
1474 
1475 int
1476 _haiku_build_linkat(int toFD, const char* toPath, int pathFD, const char* path,
1477 	int flag)
1478 {
1479 	return linkat(toFD, toPath, pathFD, path, flag);
1480 
1481 	// TODO: Handle non-system FDs.
1482 }
1483 
1484 
1485 int
1486 _haiku_build_unlinkat(int fd, const char* path, int flag)
1487 {
1488 	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1489 		return unlinkat(fd, path, flag);
1490 
1491 	RETURN_AND_SET_ERRNO(_kern_unlink(fd, path));
1492 }
1493 
1494 
1495 ssize_t
1496 _haiku_build_readlinkat(int fd, const char* path, char* buffer,
1497 	size_t bufferSize)
1498 {
1499 	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1500 		return readlinkat(fd, path, buffer, bufferSize);
1501 
1502 	status_t error = _kern_read_link(fd, path, buffer, &bufferSize);
1503 	if (error != B_OK)
1504 		RETURN_AND_SET_ERRNO(error);
1505 
1506 	return bufferSize;
1507 }
1508 
1509 
1510 int
1511 _haiku_build_symlinkat(const char* toPath, int fd, const char* symlinkPath)
1512 {
1513 	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1514 		return symlinkat(toPath, fd, symlinkPath);
1515 
1516 	RETURN_AND_SET_ERRNO(_kern_create_symlink(fd, symlinkPath, toPath,
1517 		S_IRWXU | S_IRWXG | S_IRWXO));
1518 }
1519 
1520 
1521 int
1522 _haiku_build_ftruncate(int fd, off_t newSize)
1523 {
1524 	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1525 		return ftruncate(fd, newSize);
1526 
1527 	struct stat st;
1528 	st.st_size = newSize;
1529 
1530 	RETURN_AND_SET_ERRNO(_kern_write_stat(fd, NULL, false, &st, sizeof(st),
1531 		B_STAT_SIZE));
1532 }
1533 
1534 
1535 int
1536 _haiku_build_fchown(int fd, uid_t owner, gid_t group)
1537 {
1538 	return _haiku_build_fchownat(fd, NULL, owner, group, AT_SYMLINK_NOFOLLOW);
1539 }
1540 
1541 
1542 int
1543 _haiku_build_fchownat(int fd, const char* path, uid_t owner, gid_t group,
1544 	int flag)
1545 {
1546 	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
1547 		return fchownat(fd, path, owner, group, flag);
1548 
1549 	struct stat st;
1550 	st.st_uid = owner;
1551 	st.st_gid = group;
1552 
1553 	RETURN_AND_SET_ERRNO(_kern_write_stat(fd, path,
1554 		(flag & AT_SYMLINK_NOFOLLOW) == 0, &st, sizeof(st),
1555 		B_STAT_UID | B_STAT_GID));
1556 }
1557 
1558 
1559 int
1560 _haiku_build_mknodat(int fd, const char* name, mode_t mode, dev_t dev)
1561 {
1562 	return mknodat(fd, name, mode, dev);
1563 
1564 	// TODO: Handle non-system FDs.
1565 }
1566 
1567 
1568 int
1569 _haiku_build_creat(const char* path, mode_t mode)
1570 {
1571 	return _haiku_build_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
1572 }
1573 
1574 
1575 int
1576 _haiku_build_open(const char* path, int openMode, mode_t permissions)
1577 {
1578 	return _haiku_build_openat(AT_FDCWD, path, openMode, permissions);
1579 }
1580 
1581 
1582 int
1583 _haiku_build_openat(int fd, const char* path, int openMode, mode_t permissions)
1584 {
1585 	// adapt the permissions as required by POSIX
1586 	mode_t mask = umask(0);
1587 	umask(mask);
1588 	permissions &= ~mask;
1589 
1590 	RETURN_AND_SET_ERRNO(_kern_open(fd, path, openMode, permissions));
1591 }
1592 
1593 
1594 int
1595 _haiku_build_fcntl(int fd, int op, int argument)
1596 {
1597 	if (is_unknown_or_system_descriptor(fd))
1598 		return fcntl(fd, op, argument);
1599 
1600 	RETURN_AND_SET_ERRNO(B_NOT_SUPPORTED);
1601 }
1602 
1603 
1604 int
1605 _haiku_build_renameat(int fromFD, const char* from, int toFD, const char* to)
1606 {
1607 	if ((fromFD >= 0 && fromFD != AT_FDCWD && get_descriptor(fromFD) == NULL)
1608 		|| (toFD >= 0 && toFD != AT_FDCWD && get_descriptor(toFD) == NULL)) {
1609 		return renameat(fromFD, from, toFD, to);
1610 	}
1611 
1612 	RETURN_AND_SET_ERRNO(_kern_rename(fromFD, from, toFD, to));
1613 }
1614