xref: /haiku/src/build/libroot/fs.cpp (revision 9760dcae2038d47442f4658c2575844c6cf92c40)
1 /*
2  * Copyright 2005-2008, 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 
20 #include <map>
21 #include <string>
22 
23 #include <fs_attr.h>
24 #include <NodeMonitor.h>	// for B_STAT_* flags
25 #include <syscalls.h>
26 
27 #include "fs_descriptors.h"
28 #include "NodeRef.h"
29 
30 #if defined(HAIKU_HOST_PLATFORM_FREEBSD)
31 #	include "fs_freebsd.h"
32 #endif
33 
34 
35 using namespace std;
36 using namespace BPrivate;
37 
38 
39 #if defined(HAIKU_HOST_PLATFORM_FREEBSD)
40 #	define haiku_host_platform_read		haiku_freebsd_read
41 #	define haiku_host_platform_write	haiku_freebsd_write
42 #	define haiku_host_platform_readv	haiku_freebsd_readv
43 #	define haiku_host_platform_writev	haiku_freebsd_writev
44 #else
45 #	define haiku_host_platform_read		read
46 #	define haiku_host_platform_write	write
47 #	define haiku_host_platform_readv	readv
48 #	define haiku_host_platform_writev	writev
49 #endif
50 
51 
52 static status_t get_path(dev_t device, ino_t node, const char *name,
53 	string &path);
54 
55 
56 // find_dir_entry
57 static status_t
58 find_dir_entry(DIR *dir, const char *path, NodeRef ref, string &name,
59 	bool skipDot)
60 {
61 	// find the entry
62 	bool found = false;
63 	while (dirent *entry = readdir(dir)) {
64 		if ((!skipDot && strcmp(entry->d_name, ".") == 0)
65 			|| strcmp(entry->d_name, "..") == 0) {
66 			// skip "." and ".."
67 		} else /*if (entry->d_ino == ref.node)*/ {
68 				// Note: Linux doesn't seem to translate dirent::d_ino of
69 				// mount points. Thus we always have to lstat().
70 			// We also need to compare the device, which is generally not
71 			// included in the dirent structure. Hence we lstat().
72 			string entryPath(path);
73 			entryPath += '/';
74 			entryPath += entry->d_name;
75 			struct stat st;
76 			if (lstat(entryPath.c_str(), &st) == 0) {
77 				if (NodeRef(st) == ref) {
78 					name = entry->d_name;
79 					found = true;
80 					break;
81 				}
82 			}
83 		}
84 	}
85 
86 	if (!found)
87 		return B_ENTRY_NOT_FOUND;
88 
89 	return B_OK;
90 }
91 
92 // find_dir_entry
93 static status_t
94 find_dir_entry(const char *path, NodeRef ref, string &name, bool skipDot)
95 {
96 	// open dir
97 	DIR *dir = opendir(path);
98 	if (!dir)
99 		return errno;
100 
101 	status_t error = find_dir_entry(dir, path, ref, name, skipDot);
102 
103 	// close dir
104 	closedir(dir);
105 
106 	return error;
107 }
108 
109 // normalize_dir_path
110 static status_t
111 normalize_dir_path(string path, NodeRef ref, string &normalizedPath)
112 {
113 	// get parent path
114 	path += "/..";
115 
116 	// stat the parent dir
117 	struct stat st;
118 	if (lstat(path.c_str(), &st) < 0)
119 		return errno;
120 
121 	// root dir?
122 	NodeRef parentRef(st);
123 	if (parentRef == ref) {
124 		normalizedPath = "/";
125 		return 0;
126 	}
127 
128 	// find the entry
129 	string name;
130 	status_t error = find_dir_entry(path.c_str(), ref, name, true)				;
131 	if (error != B_OK)
132 		return error;
133 
134 	// recurse to get the parent dir path, if found
135 	error = normalize_dir_path(path, parentRef, normalizedPath);
136 	if (error != 0)
137 		return error;
138 
139 	// construct the normalizedPath
140 	if (normalizedPath.length() > 1) // don't append "/", if parent is root
141 		normalizedPath += '/';
142 	normalizedPath += name;
143 
144 	return 0;
145 }
146 
147 // normalize_dir_path
148 static status_t
149 normalize_dir_path(const char *path, string &normalizedPath)
150 {
151 	// stat() the dir
152 	struct stat st;
153 	if (stat(path, &st) < 0)
154 		return errno;
155 
156 	return normalize_dir_path(path, NodeRef(st), normalizedPath);
157 }
158 
159 // normalize_entry_path
160 static status_t
161 normalize_entry_path(const char *path, string &normalizedPath)
162 {
163 	const char *dirPath = NULL;
164 	const char *leafName = NULL;
165 
166 	string dirPathString;
167 	if (const char *lastSlash = strrchr(path, '/')) {
168 		// found a slash: decompose into dir path and leaf name
169 		leafName = lastSlash + 1;
170 		if (leafName[0] == '\0') {
171 			// slash is at the end: the whole path is a dir name
172 			leafName = NULL;
173 		} else {
174 			dirPathString = string(path, leafName - path);
175 			dirPath = dirPathString.c_str();
176 		}
177 
178 	} else {
179 		// path contains no slash, so it is a path relative to the current dir
180 		dirPath = ".";
181 		leafName = path;
182 	}
183 
184 	// catch special case: no leaf, or leaf is a directory
185 	if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0)
186 		return normalize_dir_path(path, normalizedPath);
187 
188 	// normalize the dir path
189 	status_t error = normalize_dir_path(dirPath, normalizedPath);
190 	if (error != B_OK)
191 		return error;
192 
193 	// append the leaf name
194 	if (normalizedPath.length() > 1) // don't append "/", if parent is root
195 		normalizedPath += '/';
196 	normalizedPath += leafName;
197 
198 	return B_OK;
199 }
200 
201 
202 // #pragma mark -
203 
204 typedef map<NodeRef, string> DirPathMap;
205 static DirPathMap sDirPathMap;
206 
207 // get_path
208 static status_t
209 get_path(const NodeRef *ref, const char *name, string &path)
210 {
211 	if (!ref && !name)
212 		return B_BAD_VALUE;
213 
214 	// no ref or absolute path
215 	if (!ref || (name && name[0] == '/')) {
216 		path = name;
217 		return B_OK;
218 	}
219 
220 	// get the dir path
221 	if (ref) {
222 		DirPathMap::iterator it = sDirPathMap.find(*ref);
223 		if (it == sDirPathMap.end())
224 			return B_ENTRY_NOT_FOUND;
225 
226 		path = it->second;
227 
228 		// stat the path to check, if it is still valid
229 		struct stat st;
230 		if (lstat(path.c_str(), &st) < 0) {
231 			sDirPathMap.erase(it);
232 			return errno;
233 		}
234 
235 		// compare the NodeRef
236 		if (NodeRef(st) != *ref) {
237 			sDirPathMap.erase(it);
238 			return B_ENTRY_NOT_FOUND;
239 		}
240 
241 		// still a directory?
242 		if (!S_ISDIR(st.st_mode)) {
243 			sDirPathMap.erase(it);
244 			return B_NOT_A_DIRECTORY;
245 		}
246 	}
247 
248 	// if there's a name, append it
249 	if (name) {
250 		path += '/';
251 		path += name;
252 	}
253 
254 	return B_OK;
255 }
256 
257 // get_path
258 status_t
259 BPrivate::get_path(int fd, const char *name, string &path)
260 {
261 	// get the node ref for the fd, if any, and the path part is not absolute
262 	if (fd >= 0 && !(name && name[0] == '/')) {
263 		// get descriptor
264 		Descriptor *descriptor = get_descriptor(fd);
265 		if (!descriptor)
266 			return B_FILE_ERROR;
267 
268 		// get node ref for the descriptor
269 		NodeRef ref;
270 		status_t error = descriptor->GetNodeRef(ref);
271 		if (error != B_OK)
272 			return error;
273 
274 		return ::get_path(&ref, name, path);
275 
276 	} else	// no descriptor or absolute path
277 		return ::get_path((NodeRef*)NULL, name, path);
278 }
279 
280 // get_path
281 static status_t
282 get_path(dev_t device, ino_t directory, const char *name, string &path)
283 {
284 	NodeRef ref;
285 	ref.device = device;
286 	ref.node = directory;
287 
288 	return get_path(&ref, name, path);
289 }
290 
291 // add_dir_path
292 static void
293 add_dir_path(const char *path, const NodeRef &ref)
294 {
295 	// add the normalized path
296 	string normalizedPath;
297 	if (normalize_dir_path(path, normalizedPath) == B_OK)
298 		sDirPathMap[ref] = normalizedPath;
299 }
300 
301 
302 // #pragma mark -
303 
304 // _kern_entry_ref_to_path
305 status_t
306 _kern_entry_ref_to_path(dev_t device, ino_t node, const char *leaf,
307 	char *userPath, size_t pathLength)
308 {
309 	// get the path
310 	string path;
311 	status_t error = get_path(device, node, leaf, path);
312 	if (error != B_OK)
313 		return error;
314 
315 	// copy it back to the user buffer
316 	if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength)
317 		return B_BUFFER_OVERFLOW;
318 
319 	return B_OK;
320 }
321 
322 
323 // #pragma mark -
324 
325 // _kern_create_dir
326 status_t
327 _kern_create_dir(int fd, const char *path, int perms)
328 {
329 	// get a usable path
330 	string realPath;
331 	status_t error = get_path(fd, path, realPath);
332 	if (error != B_OK)
333 		return error;
334 
335 	// mkdir
336 	if (mkdir(realPath.c_str(), perms) < 0)
337 		return errno;
338 
339 	return B_OK;
340 }
341 
342 // _kern_create_dir_entry_ref
343 status_t
344 _kern_create_dir_entry_ref(dev_t device, ino_t node, const char *name,
345 	int perms)
346 {
347 	// get a usable path
348 	string realPath;
349 	status_t error = get_path(device, node, name, realPath);
350 	if (error != B_OK)
351 		return error;
352 
353 	// mkdir
354 	if (mkdir(realPath.c_str(), perms) < 0)
355 		return errno;
356 
357 	return B_OK;
358 }
359 
360 // open_dir
361 static int
362 open_dir(const char *path)
363 {
364 	// open the dir
365 	DIR *dir = opendir(path);
366 	if (!dir)
367 		return errno;
368 
369 	// stat the entry
370 	struct stat st;
371 	if (stat(path, &st) < 0) {
372 		closedir(dir);
373 		return errno;
374 	}
375 
376 	if (!S_ISDIR(st.st_mode)) {
377 		closedir(dir);
378 		return B_NOT_A_DIRECTORY;
379 	}
380 
381 	// cache dir path
382 	NodeRef ref(st);
383 	add_dir_path(path, ref);
384 
385 	// create descriptor
386 	DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref);
387 	return add_descriptor(descriptor);
388 }
389 
390 // _kern_open_dir
391 int
392 _kern_open_dir(int fd, const char *path)
393 {
394 	// get a usable path
395 	string realPath;
396 	status_t error = get_path(fd, path, realPath);
397 	if (error != B_OK)
398 		return error;
399 
400 	return open_dir(realPath.c_str());
401 }
402 
403 // _kern_open_dir_entry_ref
404 int
405 _kern_open_dir_entry_ref(dev_t device, ino_t node, const char *name)
406 {
407 	// get a usable path
408 	string realPath;
409 	status_t error = get_path(device, node, name, realPath);
410 	if (error != B_OK)
411 		return error;
412 
413 	return open_dir(realPath.c_str());
414 }
415 
416 // _kern_open_parent_dir
417 int
418 _kern_open_parent_dir(int fd, char *name, size_t nameLength)
419 {
420 	// get a usable path
421 	string realPath;
422 	status_t error = get_path(fd, NULL, realPath);
423 	if (error != B_OK)
424 		return error;
425 
426 	// stat the entry
427 	struct stat st;
428 	if (stat(realPath.c_str(), &st) < 0)
429 		return errno;
430 
431 	if (!S_ISDIR(st.st_mode))
432 		return B_NOT_A_DIRECTORY;
433 
434 	// get the entry name
435 	realPath += "/..";
436 	string entryName;
437 	error = find_dir_entry(realPath.c_str(), NodeRef(st),
438 		entryName, false);
439 	if (error != B_OK)
440 		return error;
441 
442 	if (strlcpy(name, entryName.c_str(), nameLength) >= nameLength)
443 		return B_BUFFER_OVERFLOW;
444 
445 	// open the parent directory
446 
447 	return open_dir(realPath.c_str());
448 }
449 
450 // _kern_read_dir
451 ssize_t
452 _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize,
453 	uint32 maxCount)
454 {
455 	if (maxCount <= 0)
456 		return B_BAD_VALUE;
457 
458 	// get the descriptor
459 	DirectoryDescriptor *descriptor
460 		= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
461 	if (!descriptor)
462 		return B_FILE_ERROR;
463 
464 	// get the next entry
465 	dirent *entry;
466 	if (dynamic_cast<AttrDirDescriptor*>(descriptor))
467 		entry = fs_read_attr_dir(descriptor->dir);
468 	else
469 		entry = readdir(descriptor->dir);
470 	if (!entry)
471 		return errno;
472 
473 	// copy the entry
474 	int entryLen = &entry->d_name[strlen(entry->d_name) + 1] - (char*)entry;
475 	if (entryLen > (int)bufferSize)
476 		return B_BUFFER_OVERFLOW;
477 
478 	memcpy(buffer, entry, entryLen);
479 
480 	return 1;
481 }
482 
483 // _kern_rewind_dir
484 status_t
485 _kern_rewind_dir(int fd)
486 {
487 	// get the descriptor
488 	DirectoryDescriptor *descriptor
489 		= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
490 	if (!descriptor)
491 		return B_FILE_ERROR;
492 
493 	// rewind
494 	if (dynamic_cast<AttrDirDescriptor*>(descriptor))
495 		fs_rewind_attr_dir(descriptor->dir);
496 	else
497 		rewinddir(descriptor->dir);
498 
499 	return B_OK;
500 }
501 
502 
503 // #pragma mark -
504 
505 // open_file
506 static int
507 open_file(const char *path, int openMode, int perms)
508 {
509 	// stat the node
510 	bool exists = true;
511 	struct stat st;
512 	if (lstat(path, &st) < 0) {
513 		exists = false;
514 		if (!(openMode & O_CREAT))
515 			return errno;
516 	}
517 
518 	Descriptor *descriptor;
519 	if (exists && S_ISLNK(st.st_mode) && (openMode & O_NOTRAVERSE) != 0) {
520 		// a symlink not to be followed: create a special descriptor
521 		// normalize path first
522 		string normalizedPath;
523 		status_t error = normalize_entry_path(path, normalizedPath);
524 		if (error != B_OK)
525 			return error;
526 
527 		descriptor = new SymlinkDescriptor(normalizedPath.c_str());
528 	} else {
529 		// open the file
530 		openMode &= ~O_NOTRAVERSE;
531 		int newFD = open(path, openMode, perms);
532 		if (newFD < 0)
533 			return errno;
534 
535 		descriptor = new FileDescriptor(newFD);
536 	}
537 
538 	// cache path, if this is a directory
539 	if (exists && S_ISDIR(st.st_mode))
540 		add_dir_path(path, NodeRef(st));
541 
542 	return add_descriptor(descriptor);
543 }
544 
545 // _kern_open
546 int
547 _kern_open(int fd, const char *path, int openMode, int perms)
548 {
549 	// get a usable path
550 	string realPath;
551 	status_t error = get_path(fd, path, realPath);
552 	if (error != B_OK)
553 		return error;
554 
555 	return open_file(realPath.c_str(), openMode, perms);
556 }
557 
558 // _kern_open_entry_ref
559 int
560 _kern_open_entry_ref(dev_t device, ino_t node, const char *name,
561 	int openMode, int perms)
562 {
563 	// get a usable path
564 	string realPath;
565 	status_t error = get_path(device, node, name, realPath);
566 	if (error != B_OK)
567 		return error;
568 
569 	return open_file(realPath.c_str(), openMode, perms);
570 }
571 
572 // _kern_seek
573 off_t
574 _kern_seek(int fd, off_t pos, int seekType)
575 {
576 	// get the descriptor
577 	FileDescriptor *descriptor
578 		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
579 	if (!descriptor)
580 		return B_FILE_ERROR;
581 
582 	// seek
583 	off_t result = lseek(descriptor->fd, pos, seekType);
584 	if (result < 0)
585 		return errno;
586 
587 	return result;
588 }
589 
590 // _kern_read
591 ssize_t
592 _kern_read(int fd, off_t pos, void *buffer, size_t bufferSize)
593 {
594 	// get the descriptor
595 	FileDescriptor *descriptor
596 		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
597 	if (!descriptor)
598 		return B_FILE_ERROR;
599 
600 	// seek
601 	if (pos != -1) {
602 		off_t result = lseek(descriptor->fd, pos, SEEK_SET);
603 		if (result < 0)
604 			return errno;
605 	}
606 
607 	// read
608 	ssize_t bytesRead = haiku_host_platform_read(descriptor->fd, buffer,
609 		bufferSize);
610 	if (bytesRead < 0)
611 		return errno;
612 
613 	return bytesRead;
614 }
615 
616 // _kern_write
617 ssize_t
618 _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize)
619 {
620 	// get the descriptor
621 	FileDescriptor *descriptor
622 		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
623 	if (!descriptor)
624 		return B_FILE_ERROR;
625 
626 	// seek
627 	if (pos != -1) {
628 		off_t result = lseek(descriptor->fd, pos, SEEK_SET);
629 		if (result < 0)
630 			return errno;
631 	}
632 
633 	// read
634 	ssize_t bytesWritten = haiku_host_platform_write(descriptor->fd, buffer,
635 		bufferSize);
636 	if (bytesWritten < 0)
637 		return errno;
638 
639 	return bytesWritten;
640 }
641 
642 // _kern_close
643 status_t
644 _kern_close(int fd)
645 {
646 	return delete_descriptor(fd);
647 }
648 
649 // _kern_dup
650 int
651 _kern_dup(int fd)
652 {
653 	// get the descriptor
654 	Descriptor *descriptor = get_descriptor(fd);
655 	if (!descriptor)
656 		return B_FILE_ERROR;
657 
658 	// clone it
659 	Descriptor *clone;
660 	status_t error = descriptor->Dup(clone);
661 	if (error != B_OK)
662 		return error;
663 
664 	return add_descriptor(clone);
665 }
666 
667 // _kern_fsync
668 status_t
669 _kern_fsync(int fd)
670 {
671 	// get the descriptor
672 	FileDescriptor *descriptor
673 		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
674 	if (!descriptor)
675 		return B_FILE_ERROR;
676 
677 	// sync
678 	if (fsync(descriptor->fd) < 0)
679 		return errno;
680 
681 	return B_OK;
682 }
683 
684 // _kern_read_stat
685 status_t
686 _kern_read_stat(int fd, const char *path, bool traverseLink,
687 	struct stat *st, size_t statSize)
688 {
689 	if (path) {
690 		// get a usable path
691 		string realPath;
692 		status_t error = get_path(fd, path, realPath);
693 		if (error != B_OK)
694 			return error;
695 
696 		// stat
697 		int result;
698 		if (traverseLink)
699 			result = stat(realPath.c_str(), st);
700 		else
701 			result = lstat(realPath.c_str(), st);
702 
703 		if (result < 0)
704 			return errno;
705 	} else {
706 		Descriptor *descriptor = get_descriptor(fd);
707 		if (!descriptor)
708 			return B_FILE_ERROR;
709 
710 		return descriptor->GetStat(traverseLink, st);
711 	}
712 
713 	return B_OK;
714 }
715 
716 // _kern_write_stat
717 status_t
718 _kern_write_stat(int fd, const char *path, bool traverseLink,
719 	const struct stat *st, size_t statSize, int statMask)
720 {
721 	// get a usable path
722 	int realFD = -1;
723 	string realPath;
724 	status_t error;
725 	bool isSymlink = false;
726 	if (path) {
727 		error = get_path(fd, path, realPath);
728 		if (error != B_OK)
729 			return error;
730 
731 		// stat it to see, if it is a symlink
732 		struct stat tmpStat;
733 		if (lstat(realPath.c_str(), &tmpStat) < 0)
734 			return errno;
735 
736 		isSymlink = S_ISLNK(tmpStat.st_mode);
737 
738 	} else {
739 		Descriptor *descriptor = get_descriptor(fd);
740 		if (!descriptor)
741 			return B_FILE_ERROR;
742 
743 		if (FileDescriptor *fileFD
744 				= dynamic_cast<FileDescriptor*>(descriptor)) {
745 			realFD = fileFD->fd;
746 
747 		} else if (dynamic_cast<DirectoryDescriptor*>(descriptor)) {
748 			error = get_path(fd, NULL, realPath);
749 			if (error != B_OK)
750 				return error;
751 
752 		} else if (SymlinkDescriptor *linkFD
753 				= dynamic_cast<SymlinkDescriptor*>(descriptor)) {
754 			realPath = linkFD->path;
755 			isSymlink = true;
756 
757 		} else
758 			return B_FILE_ERROR;
759 	}
760 
761 	// We're screwed, if the node to manipulate is a symlink. All the
762 	// available functions traverse symlinks.
763 	if (isSymlink && !traverseLink)
764 		return B_ERROR;
765 
766 	if (realFD >= 0) {
767 		if (statMask & B_STAT_MODE) {
768 			if (fchmod(realFD, st->st_mode) < 0)
769 				return errno;
770 		}
771 
772 		if (statMask & B_STAT_UID) {
773 			if (fchown(realFD, st->st_uid, (gid_t)-1) < 0)
774 				return errno;
775 		}
776 
777 		if (statMask & B_STAT_GID) {
778 			if (fchown(realFD, (uid_t)-1, st->st_gid) < 0)
779 				return errno;
780 		}
781 
782 		if (statMask & B_STAT_SIZE) {
783 			if (ftruncate(realFD, st->st_size) < 0)
784 				return errno;
785 		}
786 
787 		// The timestamps can only be set via utime(), but that requires a
788 		// path we don't have.
789 		if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME
790 				| B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) {
791 			return B_ERROR;
792 		}
793 
794 		return 0;
795 
796 	} else {
797 		if (statMask & B_STAT_MODE) {
798 			if (chmod(realPath.c_str(), st->st_mode) < 0)
799 				return errno;
800 		}
801 
802 		if (statMask & B_STAT_UID) {
803 			if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0)
804 				return errno;
805 		}
806 
807 		if (statMask & B_STAT_GID) {
808 			if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0)
809 				return errno;
810 		}
811 
812 		if (statMask & B_STAT_SIZE) {
813 			if (truncate(realPath.c_str(), st->st_size) < 0)
814 				return errno;
815 		}
816 
817 		if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
818 			// Grab the previous mod and access times so we only overwrite
819 			// the specified time and not both
820 			struct stat oldStat;
821 			if (~statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
822 				if (stat(realPath.c_str(), &oldStat) < 0)
823 					return errno;
824 			}
825 
826 			utimbuf buffer;
827 			buffer.actime = (statMask & B_STAT_ACCESS_TIME) ? st->st_atime : oldStat.st_atime;
828 			buffer.modtime = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtime : oldStat.st_mtime;
829 			if (utime(realPath.c_str(), &buffer) < 0)
830 				return errno;
831 		}
832 
833 		// not supported
834 		if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME))
835 			return B_ERROR;
836 	}
837 
838 	return B_OK;
839 }
840 
841 
842 // #pragma mark -
843 
844 // _kern_create_symlink
845 status_t
846 _kern_create_symlink(int fd, const char *path, const char *toPath, int mode)
847 {
848 	// Note: path must not be NULL, so this will always work.
849 	// get a usable path
850 	string realPath;
851 	status_t error = get_path(fd, path, realPath);
852 	if (error != B_OK)
853 		return error;
854 
855 	// symlink
856 	if (symlink(toPath, realPath.c_str()) < 0)
857 		return errno;
858 
859 	return B_OK;
860 }
861 
862 // _kern_read_link
863 status_t
864 _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize)
865 {
866 	// get the descriptor
867 	SymlinkDescriptor *descriptor
868 		= dynamic_cast<SymlinkDescriptor*>(get_descriptor(fd));
869 	if (!descriptor)
870 		return B_FILE_ERROR;
871 
872 	// readlink
873 	ssize_t bytesRead = readlink(descriptor->path.c_str(), buffer,
874 		*_bufferSize);
875 	if (bytesRead < 0)
876 		return errno;
877 
878 	if (*_bufferSize > 0) {
879 		if ((size_t)bytesRead == *_bufferSize)
880 			bytesRead--;
881 
882 		buffer[bytesRead] = '\0';
883 	}
884 
885 	*_bufferSize = bytesRead;
886 
887 	return B_OK;
888 }
889 
890 // _kern_unlink
891 status_t
892 _kern_unlink(int fd, const char *path)
893 {
894 	// get a usable path
895 	string realPath;
896 	status_t error = get_path(fd, path, realPath);
897 	if (error != B_OK)
898 		return error;
899 
900 	// unlink
901 	if (unlink(realPath.c_str()) < 0)
902 		return errno;
903 
904 	return B_OK;
905 }
906 
907 // _kern_rename
908 status_t
909 _kern_rename(int oldDir, const char *oldPath, int newDir, const char *newPath)
910 {
911 	// get usable paths
912 	string realOldPath;
913 	status_t error = get_path(oldDir, oldPath, realOldPath);
914 	if (error != B_OK)
915 		return error;
916 
917 	string realNewPath;
918 	error = get_path(newDir, newPath, realNewPath);
919 	if (error != B_OK)
920 		return error;
921 
922 	// rename
923 	if (rename(realOldPath.c_str(), realNewPath.c_str()) < 0)
924 		return errno;
925 
926 	return B_OK;
927 }
928 
929 
930 // #pragma mark -
931 
932 // _kern_lock_node
933 status_t
934 _kern_lock_node(int fd)
935 {
936 	return B_ERROR;
937 }
938 
939 // _kern_unlock_node
940 status_t
941 _kern_unlock_node(int fd)
942 {
943 	return B_ERROR;
944 }
945 
946 
947 // #pragma mark -
948 
949 // read_pos
950 ssize_t
951 read_pos(int fd, off_t pos, void *buffer, size_t bufferSize)
952 {
953 	// seek
954 	off_t result = lseek(fd, pos, SEEK_SET);
955 	if (result < 0)
956 		return errno;
957 
958 	// read
959 	ssize_t bytesRead = haiku_host_platform_read(fd, buffer, bufferSize);
960 	if (bytesRead < 0) {
961 		errno = bytesRead;
962 		return -1;
963 	}
964 
965 	return bytesRead;
966 }
967 
968 // write_pos
969 ssize_t
970 write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize)
971 {
972 	// seek
973 	off_t result = lseek(fd, pos, SEEK_SET);
974 	if (result < 0)
975 		return errno;
976 
977 	// read
978 	ssize_t bytesWritten = haiku_host_platform_write(fd, buffer, bufferSize);
979 	if (bytesWritten < 0) {
980 		errno = bytesWritten;
981 		return -1;
982 	}
983 
984 	return bytesWritten;
985 }
986 
987 // readv_pos
988 ssize_t
989 readv_pos(int fd, off_t pos, const struct iovec *vec, size_t count)
990 {
991 	// seek
992 	off_t result = lseek(fd, pos, SEEK_SET);
993 	if (result < 0)
994 		return errno;
995 
996 	// read
997 	ssize_t bytesRead = haiku_host_platform_readv(fd, vec, count);
998 	if (bytesRead < 0) {
999 		errno = bytesRead;
1000 		return -1;
1001 	}
1002 
1003 	return bytesRead;
1004 }
1005 
1006 // writev_pos
1007 ssize_t
1008 writev_pos(int fd, off_t pos, const struct iovec *vec, size_t count)
1009 {
1010 	// seek
1011 	off_t result = lseek(fd, pos, SEEK_SET);
1012 	if (result < 0)
1013 		return errno;
1014 
1015 	// read
1016 	ssize_t bytesWritten = haiku_host_platform_writev(fd, vec, count);
1017 	if (bytesWritten < 0) {
1018 		errno = bytesWritten;
1019 		return -1;
1020 	}
1021 
1022 	return bytesWritten;
1023 }
1024