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