xref: /haiku/src/build/libroot/fs.cpp (revision 0562493379cd52eb7103531f895f10bb8e77c085)
1 /*
2  * Copyright 2005-2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include <BeOSBuildCompatibility.h>
7 
8 #include "fs_impl.h"
9 
10 #include <dirent.h>
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <utime.h>
17 #include <sys/stat.h>
18 
19 #include <map>
20 #include <string>
21 
22 #include <fs_attr.h>
23 #include <NodeMonitor.h>	// for B_STAT_* flags
24 #include <syscalls.h>
25 
26 #include "fs_descriptors.h"
27 #include "NodeRef.h"
28 
29 #if defined(HAIKU_HOST_PLATFORM_FREEBSD)
30 #	include "fs_freebsd.h"
31 #endif
32 
33 
34 using namespace std;
35 using namespace BPrivate;
36 
37 
38 #if defined(HAIKU_HOST_PLATFORM_FREEBSD)
39 #	define haiku_host_platform_read		haiku_freebsd_read
40 #	define haiku_host_platform_write	haiku_freebsd_write
41 #	define haiku_host_platform_readv	haiku_freebsd_readv
42 #	define haiku_host_platform_writev	haiku_freebsd_writev
43 #else
44 #	define haiku_host_platform_read		read
45 #	define haiku_host_platform_write	write
46 #	define haiku_host_platform_readv	readv
47 #	define haiku_host_platform_writev	writev
48 #endif
49 
50 
51 static status_t get_path(dev_t device, ino_t node, const char *name,
52 	string &path);
53 
54 
55 // find_dir_entry
56 static status_t
57 find_dir_entry(DIR *dir, const char *path, NodeRef ref, string &name,
58 	bool skipDot)
59 {
60 	// find the entry
61 	bool found = false;
62 	while (dirent *entry = readdir(dir)) {
63 		if ((!skipDot && strcmp(entry->d_name, ".") == 0)
64 			|| strcmp(entry->d_name, "..") == 0) {
65 			// skip "." and ".."
66 		} else /*if (entry->d_ino == ref.node)*/ {
67 				// Note: Linux doesn't seem to translate dirent::d_ino of
68 				// mount points. Thus we always have to lstat().
69 			// We also need to compare the device, which is generally not
70 			// included in the dirent structure. Hence we lstat().
71 			string entryPath(path);
72 			entryPath += '/';
73 			entryPath += entry->d_name;
74 			struct stat st;
75 			if (lstat(entryPath.c_str(), &st) == 0) {
76 				if (NodeRef(st) == ref) {
77 					name = entry->d_name;
78 					found = true;
79 					break;
80 				}
81 			}
82 		}
83 	}
84 
85 	if (!found)
86 		return B_ENTRY_NOT_FOUND;
87 
88 	return B_OK;
89 }
90 
91 // find_dir_entry
92 static status_t
93 find_dir_entry(const char *path, NodeRef ref, string &name, bool skipDot)
94 {
95 	// open dir
96 	DIR *dir = opendir(path);
97 	if (!dir)
98 		return errno;
99 
100 	status_t error = find_dir_entry(dir, path, ref, name, skipDot);
101 
102 	// close dir
103 	closedir(dir);
104 
105 	return error;
106 }
107 
108 // normalize_dir_path
109 static status_t
110 normalize_dir_path(string path, NodeRef ref, string &normalizedPath)
111 {
112 	// get parent path
113 	path += "/..";
114 
115 	// stat the parent dir
116 	struct stat st;
117 	if (lstat(path.c_str(), &st) < 0)
118 		return errno;
119 
120 	// root dir?
121 	NodeRef parentRef(st);
122 	if (parentRef == ref) {
123 		normalizedPath = "/";
124 		return 0;
125 	}
126 
127 	// find the entry
128 	string name;
129 	status_t error = find_dir_entry(path.c_str(), ref, name, true)				;
130 	if (error != B_OK)
131 		return error;
132 
133 	// recurse to get the parent dir path, if found
134 	error = normalize_dir_path(path, parentRef, normalizedPath);
135 	if (error != 0)
136 		return error;
137 
138 	// construct the normalizedPath
139 	if (normalizedPath.length() > 1) // don't append "/", if parent is root
140 		normalizedPath += '/';
141 	normalizedPath += name;
142 
143 	return 0;
144 }
145 
146 // normalize_dir_path
147 static status_t
148 normalize_dir_path(const char *path, string &normalizedPath)
149 {
150 	// stat() the dir
151 	struct stat st;
152 	if (stat(path, &st) < 0)
153 		return errno;
154 
155 	return normalize_dir_path(path, NodeRef(st), normalizedPath);
156 }
157 
158 // normalize_entry_path
159 static status_t
160 normalize_entry_path(const char *path, string &normalizedPath)
161 {
162 	const char *dirPath = NULL;
163 	const char *leafName = NULL;
164 
165 	string dirPathString;
166 	if (char *lastSlash = strrchr(path, '/')) {
167 		// found a slash: decompose into dir path and leaf name
168 		leafName = lastSlash + 1;
169 		if (leafName[0] == '\0') {
170 			// slash is at the end: the whole path is a dir name
171 			leafName = NULL;
172 		} else {
173 			dirPathString = string(path, leafName - path);
174 			dirPath = dirPathString.c_str();
175 		}
176 
177 	} else {
178 		// path contains no slash, so it is a path relative to the current dir
179 		dirPath = ".";
180 		leafName = path;
181 	}
182 
183 	// catch special case: no leaf, or leaf is a directory
184 	if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0)
185 		return normalize_dir_path(path, normalizedPath);
186 
187 	// normalize the dir path
188 	status_t error = normalize_dir_path(dirPath, normalizedPath);
189 	if (error != B_OK)
190 		return error;
191 
192 	// append the leaf name
193 	if (normalizedPath.length() > 1) // don't append "/", if parent is root
194 		normalizedPath += '/';
195 	normalizedPath += leafName;
196 
197 	return B_OK;
198 }
199 
200 
201 // #pragma mark -
202 
203 typedef map<NodeRef, string> DirPathMap;
204 static DirPathMap sDirPathMap;
205 
206 // get_path
207 static status_t
208 get_path(const NodeRef *ref, const char *name, string &path)
209 {
210 	if (!ref && !name)
211 		return B_BAD_VALUE;
212 
213 	// no ref or absolute path
214 	if (!ref || (name && name[0] == '/')) {
215 		path = name;
216 		return B_OK;
217 	}
218 
219 	// get the dir path
220 	if (ref) {
221 		DirPathMap::iterator it = sDirPathMap.find(*ref);
222 		if (it == sDirPathMap.end())
223 			return B_ENTRY_NOT_FOUND;
224 
225 		path = it->second;
226 
227 		// stat the path to check, if it is still valid
228 		struct stat st;
229 		if (lstat(path.c_str(), &st) < 0) {
230 			sDirPathMap.erase(it);
231 			return errno;
232 		}
233 
234 		// compare the NodeRef
235 		if (NodeRef(st) != *ref) {
236 			sDirPathMap.erase(it);
237 			return B_ENTRY_NOT_FOUND;
238 		}
239 
240 		// still a directory?
241 		if (!S_ISDIR(st.st_mode)) {
242 			sDirPathMap.erase(it);
243 			return B_NOT_A_DIRECTORY;
244 		}
245 	}
246 
247 	// if there's a name, append it
248 	if (name) {
249 		path += '/';
250 		path += name;
251 	}
252 
253 	return B_OK;
254 }
255 
256 // get_path
257 status_t
258 BPrivate::get_path(int fd, const char *name, string &path)
259 {
260 	// get the node ref for the fd, if any, and the path part is not absolute
261 	if (fd >= 0 && !(name && name[0] == '/')) {
262 		// get descriptor
263 		Descriptor *descriptor = get_descriptor(fd);
264 		if (!descriptor)
265 			return B_FILE_ERROR;
266 
267 		// get node ref for the descriptor
268 		NodeRef ref;
269 		status_t error = descriptor->GetNodeRef(ref);
270 		if (error != B_OK)
271 			return error;
272 
273 		return ::get_path(&ref, name, path);
274 
275 	} else	// no descriptor or absolute path
276 		return ::get_path((NodeRef*)NULL, name, path);
277 }
278 
279 // get_path
280 static status_t
281 get_path(dev_t device, ino_t directory, const char *name, string &path)
282 {
283 	NodeRef ref;
284 	ref.device = device;
285 	ref.node = directory;
286 
287 	return get_path(&ref, name, path);
288 }
289 
290 // add_dir_path
291 static void
292 add_dir_path(const char *path, const NodeRef &ref)
293 {
294 	// add the normalized path
295 	string normalizedPath;
296 	if (normalize_dir_path(path, normalizedPath) == B_OK)
297 		sDirPathMap[ref] = normalizedPath;
298 }
299 
300 
301 // #pragma mark -
302 
303 // _kern_entry_ref_to_path
304 status_t
305 _kern_entry_ref_to_path(dev_t device, ino_t node, const char *leaf,
306 	char *userPath, size_t pathLength)
307 {
308 	// get the path
309 	string path;
310 	status_t error = get_path(device, node, leaf, path);
311 	if (error != B_OK)
312 		return error;
313 
314 	// copy it back to the user buffer
315 	if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength)
316 		return B_BUFFER_OVERFLOW;
317 
318 	return B_OK;
319 }
320 
321 
322 // #pragma mark -
323 
324 // _kern_create_dir
325 status_t
326 _kern_create_dir(int fd, const char *path, int perms)
327 {
328 	// get a usable path
329 	string realPath;
330 	status_t error = get_path(fd, path, realPath);
331 	if (error != B_OK)
332 		return error;
333 
334 	// mkdir
335 	if (mkdir(realPath.c_str(), perms) < 0)
336 		return errno;
337 
338 	return B_OK;
339 }
340 
341 // _kern_create_dir_entry_ref
342 status_t
343 _kern_create_dir_entry_ref(dev_t device, ino_t node, const char *name,
344 	int perms)
345 {
346 	// get a usable path
347 	string realPath;
348 	status_t error = get_path(device, node, name, realPath);
349 	if (error != B_OK)
350 		return error;
351 
352 	// mkdir
353 	if (mkdir(realPath.c_str(), perms) < 0)
354 		return errno;
355 
356 	return B_OK;
357 }
358 
359 // open_dir
360 static int
361 open_dir(const char *path)
362 {
363 	// open the dir
364 	DIR *dir = opendir(path);
365 	if (!dir)
366 		return errno;
367 
368 	// stat the entry
369 	struct stat st;
370 	if (stat(path, &st) < 0) {
371 		closedir(dir);
372 		return errno;
373 	}
374 
375 	if (!S_ISDIR(st.st_mode)) {
376 		closedir(dir);
377 		return B_NOT_A_DIRECTORY;
378 	}
379 
380 	// cache dir path
381 	NodeRef ref(st);
382 	add_dir_path(path, ref);
383 
384 	// create descriptor
385 	DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref);
386 	return add_descriptor(descriptor);
387 }
388 
389 // _kern_open_dir
390 int
391 _kern_open_dir(int fd, const char *path)
392 {
393 	// get a usable path
394 	string realPath;
395 	status_t error = get_path(fd, path, realPath);
396 	if (error != B_OK)
397 		return error;
398 
399 	return open_dir(realPath.c_str());
400 }
401 
402 // _kern_open_dir_entry_ref
403 int
404 _kern_open_dir_entry_ref(dev_t device, ino_t node, const char *name)
405 {
406 	// get a usable path
407 	string realPath;
408 	status_t error = get_path(device, node, name, realPath);
409 	if (error != B_OK)
410 		return error;
411 
412 	return open_dir(realPath.c_str());
413 }
414 
415 // _kern_open_parent_dir
416 int
417 _kern_open_parent_dir(int fd, char *name, size_t nameLength)
418 {
419 	// get a usable path
420 	string realPath;
421 	status_t error = get_path(fd, NULL, realPath);
422 	if (error != B_OK)
423 		return error;
424 
425 	// stat the entry
426 	struct stat st;
427 	if (stat(realPath.c_str(), &st) < 0)
428 		return errno;
429 
430 	if (!S_ISDIR(st.st_mode))
431 		return B_NOT_A_DIRECTORY;
432 
433 	// get the entry name
434 	realPath += "/..";
435 	string entryName;
436 	error = find_dir_entry(realPath.c_str(), NodeRef(st),
437 		entryName, false);
438 	if (error != B_OK)
439 		return error;
440 
441 	if (strlcpy(name, entryName.c_str(), nameLength) >= nameLength)
442 		return B_BUFFER_OVERFLOW;
443 
444 	// open the parent directory
445 
446 	return open_dir(realPath.c_str());
447 }
448 
449 // _kern_read_dir
450 ssize_t
451 _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize,
452 	uint32 maxCount)
453 {
454 	if (maxCount <= 0)
455 		return B_BAD_VALUE;
456 
457 	// get the descriptor
458 	DirectoryDescriptor *descriptor
459 		= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
460 	if (!descriptor)
461 		return B_FILE_ERROR;
462 
463 	// get the next entry
464 	dirent *entry;
465 	if (dynamic_cast<AttrDirDescriptor*>(descriptor))
466 		entry = fs_read_attr_dir(descriptor->dir);
467 	else
468 		entry = readdir(descriptor->dir);
469 	if (!entry)
470 		return errno;
471 
472 	// copy the entry
473 	int entryLen = &entry->d_name[strlen(entry->d_name) + 1] - (char*)entry;
474 	if (entryLen > (int)bufferSize)
475 		return B_BUFFER_OVERFLOW;
476 
477 	memcpy(buffer, entry, entryLen);
478 
479 	return 1;
480 }
481 
482 // _kern_rewind_dir
483 status_t
484 _kern_rewind_dir(int fd)
485 {
486 	// get the descriptor
487 	DirectoryDescriptor *descriptor
488 		= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
489 	if (!descriptor)
490 		return B_FILE_ERROR;
491 
492 	// rewind
493 	if (dynamic_cast<AttrDirDescriptor*>(descriptor))
494 		fs_rewind_attr_dir(descriptor->dir);
495 	else
496 		rewinddir(descriptor->dir);
497 
498 	return B_OK;
499 }
500 
501 
502 // #pragma mark -
503 
504 // open_file
505 static int
506 open_file(const char *path, int openMode, int perms)
507 {
508 	// stat the node
509 	bool exists = true;
510 	struct stat st;
511 	if (lstat(path, &st) < 0) {
512 		exists = false;
513 		if (!(openMode & O_CREAT))
514 			return errno;
515 	}
516 
517 	Descriptor *descriptor;
518 	if (exists && S_ISLNK(st.st_mode) && (openMode & O_NOTRAVERSE)) {
519 		// a symlink not to be followed: create a special descriptor
520 		// normalize path first
521 		string normalizedPath;
522 		status_t error = normalize_entry_path(path, normalizedPath);
523 		if (error != B_OK)
524 			return error;
525 
526 		descriptor = new SymlinkDescriptor(normalizedPath.c_str());
527 
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