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