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