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