xref: /haiku/src/build/libroot/fs.cpp (revision 4f00613311d0bd6b70fa82ce19931c41f071ea4e)
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 (stat(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 (stat(path, &st) < 0) {
621 		closedir(dir);
622 		return errno;
623 	}
624 
625 	if (!S_ISDIR(st.st_mode)) {
626 		closedir(dir);
627 		return B_NOT_A_DIRECTORY;
628 	}
629 
630 	// cache dir path
631 	NodeRef ref(st);
632 	add_dir_path(path, ref);
633 
634 	// create descriptor
635 	DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref);
636 	return add_descriptor(descriptor);
637 }
638 
639 // _kern_open_dir
640 int
641 _kern_open_dir(int fd, const char *path)
642 {
643 	// get a usable path
644 	string realPath;
645 	status_t error = get_path(fd, path, realPath);
646 	if (error != B_OK)
647 		return error;
648 
649 	return open_dir(realPath.c_str());
650 }
651 
652 // _kern_open_dir_entry_ref
653 int
654 _kern_open_dir_entry_ref(dev_t device, ino_t node, const char *name)
655 {
656 	// get a usable path
657 	string realPath;
658 	status_t error = get_path(device, node, name, realPath);
659 	if (error != B_OK)
660 		return error;
661 
662 	return open_dir(realPath.c_str());
663 }
664 
665 // _kern_open_parent_dir
666 int
667 _kern_open_parent_dir(int fd, char *name, size_t nameLength)
668 {
669 	// get a usable path
670 	string realPath;
671 	status_t error = get_path(fd, name, realPath);
672 	if (error != B_OK)
673 		return error;
674 
675 	// stat the entry
676 	struct stat st;
677 	if (stat(realPath.c_str(), &st) < 0)
678 		return errno;
679 
680 	if (!S_ISDIR(st.st_mode))
681 		return B_NOT_A_DIRECTORY;
682 
683 	// get the entry name
684 	realPath += "/..";
685 	string entryName;
686 	error = find_dir_entry(realPath.c_str(), NodeRef(st),
687 		entryName, false);
688 	if (error != B_OK)
689 		return error;
690 
691 	if (strlcpy(name, entryName.c_str(), nameLength) >= nameLength)
692 		return B_BUFFER_OVERFLOW;
693 
694 	// open the parent directory
695 
696 	return open_dir(realPath.c_str());
697 }
698 
699 // _kern_read_dir
700 ssize_t
701 _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize,
702 	uint32 maxCount)
703 {
704 	if (maxCount <= 0)
705 		return B_BAD_VALUE;
706 
707 	// get the descriptor
708 	DirectoryDescriptor *descriptor
709 		= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
710 	if (!descriptor)
711 		return B_FILE_ERROR;
712 
713 	// get the next entry
714 	dirent *entry;
715 	if (dynamic_cast<AttrDirDescriptor*>(descriptor))
716 		entry = fs_read_attr_dir(descriptor->dir);
717 	else
718 		entry = readdir(descriptor->dir);
719 	if (!entry)
720 		return errno;
721 
722 	// copy the entry
723 	int entryLen = &entry->d_name[strlen(entry->d_name) + 1] - (char*)entry;
724 	if (entryLen > (int)bufferSize)
725 		return B_BUFFER_OVERFLOW;
726 
727 	memcpy(buffer, entry, entryLen);
728 
729 	return 1;
730 }
731 
732 // _kern_rewind_dir
733 status_t
734 _kern_rewind_dir(int fd)
735 {
736 	// get the descriptor
737 	DirectoryDescriptor *descriptor
738 		= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
739 	if (!descriptor)
740 		return B_FILE_ERROR;
741 
742 	// rewind
743 	if (dynamic_cast<AttrDirDescriptor*>(descriptor))
744 		fs_rewind_attr_dir(descriptor->dir);
745 	else
746 		rewinddir(descriptor->dir);
747 
748 	return B_OK;
749 }
750 
751 
752 // #pragma mark -
753 
754 // open_file
755 static int
756 open_file(const char *path, int openMode, int perms)
757 {
758 	// stat the node
759 	bool exists = true;
760 	struct stat st;
761 	if (lstat(path, &st) < 0) {
762 		exists = false;
763 		if (!(openMode & O_CREAT))
764 			return errno;
765 	}
766 
767 	Descriptor *descriptor;
768 	if (exists && S_ISLNK(st.st_mode) && (openMode & O_NOTRAVERSE)) {
769 		// a symlink not to be followed: create a special descriptor
770 		// normalize path first
771 		string normalizedPath;
772 		status_t error = normalize_entry_path(path, normalizedPath);
773 		if (error != B_OK)
774 			return error;
775 
776 		descriptor = new SymlinkDescriptor(normalizedPath.c_str());
777 
778 	} else {
779 		// open the file
780 		openMode &= ~O_NOTRAVERSE;
781 		int newFD = open(path, openMode, perms);
782 		if (newFD < 0)
783 			return errno;
784 
785 		descriptor = new FileDescriptor(newFD);
786 	}
787 
788 	// cache path, if this is a directory
789 	if (S_ISDIR(st.st_mode))
790 		add_dir_path(path, NodeRef(st));
791 
792 	return add_descriptor(descriptor);
793 }
794 
795 // _kern_open
796 int
797 _kern_open(int fd, const char *path, int openMode, int perms)
798 {
799 	// get a usable path
800 	string realPath;
801 	status_t error = get_path(fd, path, realPath);
802 	if (error != B_OK)
803 		return error;
804 
805 	return open_file(realPath.c_str(), openMode, perms);
806 }
807 
808 // _kern_open_entry_ref
809 int
810 _kern_open_entry_ref(dev_t device, ino_t node, const char *name,
811 	int openMode, int perms)
812 {
813 	// get a usable path
814 	string realPath;
815 	status_t error = get_path(device, node, name, realPath);
816 	if (error != B_OK)
817 		return error;
818 
819 	return open_file(realPath.c_str(), openMode, perms);
820 }
821 
822 // _kern_seek
823 off_t
824 _kern_seek(int fd, off_t pos, int seekType)
825 {
826 	// get the descriptor
827 	FileDescriptor *descriptor
828 		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
829 	if (!descriptor)
830 		return B_FILE_ERROR;
831 
832 	// seek
833 	off_t result = lseek(descriptor->fd, pos, seekType);
834 	if (result < 0)
835 		return errno;
836 
837 	return result;
838 }
839 
840 // _kern_read
841 ssize_t
842 _kern_read(int fd, off_t pos, void *buffer, size_t bufferSize)
843 {
844 	// get the descriptor
845 	FileDescriptor *descriptor
846 		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
847 	if (!descriptor)
848 		return B_FILE_ERROR;
849 
850 	// seek
851 	if (pos != -1) {
852 		off_t result = lseek(descriptor->fd, pos, SEEK_SET);
853 		if (result < 0)
854 			return errno;
855 	}
856 
857 	// read
858 	ssize_t bytesRead = read(descriptor->fd, buffer, bufferSize);
859 	if (bytesRead < 0)
860 		return errno;
861 
862 	return bytesRead;
863 }
864 
865 // _kern_write
866 ssize_t
867 _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize)
868 {
869 	// get the descriptor
870 	FileDescriptor *descriptor
871 		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
872 	if (!descriptor)
873 		return B_FILE_ERROR;
874 
875 	// seek
876 	if (pos != -1) {
877 		off_t result = lseek(descriptor->fd, pos, SEEK_SET);
878 		if (result < 0)
879 			return errno;
880 	}
881 
882 	// read
883 	ssize_t bytesWritten = write(descriptor->fd, buffer, bufferSize);
884 	if (bytesWritten < 0)
885 		return errno;
886 
887 	return bytesWritten;
888 }
889 
890 // _kern_close
891 status_t
892 _kern_close(int fd)
893 {
894 	return delete_descriptor(fd);
895 }
896 
897 // _kern_dup
898 int
899 _kern_dup(int fd)
900 {
901 	// get the descriptor
902 	Descriptor *descriptor = get_descriptor(fd);
903 	if (!descriptor)
904 		return B_FILE_ERROR;
905 
906 	// clone it
907 	Descriptor *clone;
908 	status_t error = descriptor->Dup(clone);
909 	if (error != B_OK)
910 		return error;
911 
912 	return add_descriptor(clone);
913 }
914 
915 // _kern_fsync
916 status_t
917 _kern_fsync(int fd)
918 {
919 	// get the descriptor
920 	FileDescriptor *descriptor
921 		= dynamic_cast<FileDescriptor*>(get_descriptor(fd));
922 	if (!descriptor)
923 		return B_FILE_ERROR;
924 
925 	// sync
926 	if (fsync(descriptor->fd) < 0)
927 		return errno;
928 
929 	return B_OK;
930 }
931 
932 // _kern_read_stat
933 status_t
934 _kern_read_stat(int fd, const char *path, bool traverseLink,
935 	struct stat *st, size_t statSize)
936 {
937 	if (path) {
938 		// get a usable path
939 		string realPath;
940 		status_t error = get_path(fd, path, realPath);
941 		if (error != B_OK)
942 			return error;
943 
944 		// stat
945 		int result;
946 		if (traverseLink)
947 			result = stat(realPath.c_str(), st);
948 		else
949 			result = lstat(realPath.c_str(), st);
950 
951 		if (result < 0)
952 			return errno;
953 	} else {
954 		Descriptor *descriptor = get_descriptor(fd);
955 		if (!descriptor)
956 			return B_FILE_ERROR;
957 
958 		return descriptor->GetStat(traverseLink, st);
959 	}
960 
961 	return B_OK;
962 }
963 
964 // _kern_write_stat
965 status_t
966 _kern_write_stat(int fd, const char *path, bool traverseLink,
967 	const struct stat *st, size_t statSize, int statMask)
968 {
969 	// get a usable path
970 	int realFD = -1;
971 	string realPath;
972 	status_t error;
973 	bool isSymlink = false;
974 	if (path) {
975 		error = get_path(fd, path, realPath);
976 		if (error != B_OK)
977 			return error;
978 
979 		// stat it to see, if it is a symlink
980 		struct stat tmpStat;
981 		if (lstat(realPath.c_str(), &tmpStat) < 0)
982 			return errno;
983 
984 		isSymlink = S_ISLNK(tmpStat.st_mode);
985 
986 	} else {
987 		Descriptor *descriptor = get_descriptor(fd);
988 		if (!descriptor)
989 			return B_FILE_ERROR;
990 
991 		if (FileDescriptor *fileFD
992 				= dynamic_cast<FileDescriptor*>(descriptor)) {
993 			realFD = fileFD->fd;
994 
995 		} else if (dynamic_cast<DirectoryDescriptor*>(descriptor)) {
996 			error = get_path(fd, NULL, realPath);
997 			if (error != B_OK)
998 				return error;
999 
1000 		} else if (SymlinkDescriptor *linkFD
1001 				= dynamic_cast<SymlinkDescriptor*>(descriptor)) {
1002 			realPath = linkFD->path;
1003 			isSymlink = true;
1004 
1005 		} else
1006 			return B_FILE_ERROR;
1007 	}
1008 
1009 	// We're screwed, if the node to manipulate is a symlink. All the
1010 	// available functions traverse symlinks.
1011 	if (isSymlink && !traverseLink)
1012 		return B_ERROR;
1013 
1014 	if (realFD >= 0) {
1015 		if (statMask & B_STAT_MODE) {
1016 			if (fchmod(realFD, st->st_mode) < 0)
1017 				return errno;
1018 		}
1019 
1020 		if (statMask & B_STAT_UID) {
1021 			if (fchown(realFD, st->st_uid, (gid_t)-1) < 0)
1022 				return errno;
1023 		}
1024 
1025 		if (statMask & B_STAT_GID) {
1026 			if (fchown(realFD, (uid_t)-1, st->st_gid) < 0)
1027 				return errno;
1028 		}
1029 
1030 		if (statMask & B_STAT_SIZE) {
1031 			if (ftruncate(realFD, st->st_size) < 0)
1032 				return errno;
1033 		}
1034 
1035 		// The timestamps can only be set via utime(), but that requires a
1036 		// path we don't have.
1037 		if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME
1038 				| B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) {
1039 			return B_ERROR;
1040 		}
1041 
1042 		return 0;
1043 
1044 	} else {
1045 		if (statMask & B_STAT_MODE) {
1046 			if (chmod(realPath.c_str(), st->st_mode) < 0)
1047 				return errno;
1048 		}
1049 
1050 		if (statMask & B_STAT_UID) {
1051 			if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0)
1052 				return errno;
1053 		}
1054 
1055 		if (statMask & B_STAT_GID) {
1056 			if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0)
1057 				return errno;
1058 		}
1059 
1060 		if (statMask & B_STAT_SIZE) {
1061 			if (truncate(realPath.c_str(), st->st_size) < 0)
1062 				return errno;
1063 		}
1064 
1065 		if (statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
1066 			// Grab the previous mod and access times so we only overwrite
1067 			// the specified time and not both
1068 			struct stat oldStat;
1069 			if (~statMask & (B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME)) {
1070 				if (stat(realPath.c_str(), &oldStat) < 0)
1071 					return errno;
1072 			}
1073 
1074 			utimbuf buffer;
1075 			buffer.actime = (statMask & B_STAT_ACCESS_TIME) ? st->st_atime : oldStat.st_atime;
1076 			buffer.modtime = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtime : oldStat.st_mtime;
1077 			if (utime(realPath.c_str(), &buffer) < 0)
1078 				return errno;
1079 		}
1080 
1081 		// not supported
1082 		if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME))
1083 			return B_ERROR;
1084 	}
1085 
1086 	return B_OK;
1087 }
1088 
1089 
1090 // #pragma mark -
1091 
1092 // _kern_create_symlink
1093 status_t
1094 _kern_create_symlink(int fd, const char *path, const char *toPath, int mode)
1095 {
1096 	// Note: path must not be NULL, so this will always work.
1097 	// get a usable path
1098 	string realPath;
1099 	status_t error = get_path(fd, path, realPath);
1100 	if (error != B_OK)
1101 		return error;
1102 
1103 	// symlink
1104 	if (symlink(toPath, realPath.c_str()) < 0)
1105 		return errno;
1106 
1107 	return B_OK;
1108 }
1109 
1110 // _kern_read_link
1111 status_t
1112 _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize)
1113 {
1114 	// get the descriptor
1115 	SymlinkDescriptor *descriptor
1116 		= dynamic_cast<SymlinkDescriptor*>(get_descriptor(fd));
1117 	if (!descriptor)
1118 		return B_FILE_ERROR;
1119 
1120 	// readlink
1121 	ssize_t bytesRead = readlink(descriptor->path.c_str(), buffer,
1122 		*_bufferSize);
1123 	if (bytesRead < 0)
1124 		return errno;
1125 
1126 	if (*_bufferSize > 0) {
1127 		if ((size_t)bytesRead == *_bufferSize)
1128 			bytesRead--;
1129 
1130 		buffer[bytesRead] = '\0';
1131 	}
1132 
1133 	*_bufferSize = bytesRead;
1134 
1135 	return B_OK;
1136 }
1137 
1138 // _kern_unlink
1139 status_t
1140 _kern_unlink(int fd, const char *path)
1141 {
1142 	// get a usable path
1143 	string realPath;
1144 	status_t error = get_path(fd, path, realPath);
1145 	if (error != B_OK)
1146 		return error;
1147 
1148 	// unlink
1149 	if (unlink(realPath.c_str()) < 0)
1150 		return errno;
1151 
1152 	return B_OK;
1153 }
1154 
1155 // _kern_rename
1156 status_t
1157 _kern_rename(int oldDir, const char *oldPath, int newDir, const char *newPath)
1158 {
1159 	// get usable paths
1160 	string realOldPath;
1161 	status_t error = get_path(oldDir, oldPath, realOldPath);
1162 	if (error != B_OK)
1163 		return error;
1164 
1165 	string realNewPath;
1166 	error = get_path(newDir, newPath, realNewPath);
1167 	if (error != B_OK)
1168 		return error;
1169 
1170 	// rename
1171 	if (rename(realOldPath.c_str(), realNewPath.c_str()) < 0)
1172 		return errno;
1173 
1174 	return B_OK;
1175 }
1176 
1177 
1178 // #pragma mark -
1179 
1180 // _kern_lock_node
1181 status_t
1182 _kern_lock_node(int fd)
1183 {
1184 	return B_ERROR;
1185 }
1186 
1187 // _kern_unlock_node
1188 status_t
1189 _kern_unlock_node(int fd)
1190 {
1191 	return B_ERROR;
1192 }
1193 
1194 
1195 // #pragma mark -
1196 
1197 // _kern_open_attr_dir
1198 int
1199 _kern_open_attr_dir(int fd, const char *path)
1200 {
1201 	// get node ref for the node
1202 	struct stat st;
1203 	status_t error = _kern_read_stat(fd, path, false, &st,
1204 		sizeof(struct stat));
1205 	if (error != B_OK) {
1206 		errno = error;
1207 		return -1;
1208 	}
1209 	NodeRef ref(st);
1210 
1211 	// open the attr dir
1212 	DIR *dir = open_attr_dir(ref);
1213 	if (!dir)
1214 		return errno;
1215 
1216 	// create descriptor
1217 	AttrDirDescriptor *descriptor = new AttrDirDescriptor(dir, ref);
1218 	return add_descriptor(descriptor);
1219 }
1220 
1221 // get_attribute_path
1222 static status_t
1223 get_attribute_path(int fd, const char *attribute, string &attrPath,
1224 	string &typePath)
1225 {
1226 	// stat the file to get a NodeRef
1227 	struct stat st;
1228 	status_t error = _kern_read_stat(fd, NULL, false, &st, sizeof(st));
1229 	if (error != B_OK)
1230 		return error;
1231 	NodeRef ref(st);
1232 
1233 	// get the attribute path
1234 	return get_attribute_path(ref, attribute, attrPath, typePath);
1235 }
1236 
1237 // _kern_rename_attr
1238 status_t
1239 _kern_rename_attr(int fromFile, const char *fromName, int toFile,
1240 	const char *toName)
1241 {
1242 	if (!fromName || !toName)
1243 		return B_BAD_VALUE;
1244 
1245 	// get the attribute paths
1246 	string fromAttrPath;
1247 	string fromTypePath;
1248 	status_t error = get_attribute_path(fromFile, fromName, fromAttrPath,
1249 		fromTypePath);
1250 	if (error != B_OK)
1251 		return error;
1252 
1253 	string toAttrPath;
1254 	string toTypePath;
1255 	error = get_attribute_path(toFile, toName, toAttrPath, toTypePath);
1256 	if (error != B_OK)
1257 		return error;
1258 
1259 	// rename the attribute and type files
1260 	if (rename(fromAttrPath.c_str(), toAttrPath.c_str()) < 0)
1261 		return errno;
1262 
1263 	if (rename(fromTypePath.c_str(), toTypePath.c_str()) < 0) {
1264 		// renaming the type file failed: try to rename back the attribute file
1265 		error = errno;
1266 
1267 		rename(toAttrPath.c_str(), fromAttrPath.c_str());
1268 
1269 		return error;
1270 	}
1271 
1272 	return B_OK;
1273 }
1274 
1275 // _kern_remove_attr
1276 status_t
1277 _kern_remove_attr(int fd, const char *name)
1278 {
1279 	if (!name)
1280 		return B_BAD_VALUE;
1281 
1282 	// get the attribute path
1283 	string attrPath;
1284 	string typePath;
1285 	status_t error = get_attribute_path(fd, name, attrPath, typePath);
1286 	if (error != B_OK)
1287 		return error;
1288 
1289 	// remove the attribute
1290 	if (unlink(attrPath.c_str()) < 0)
1291 		return errno;
1292 
1293 	unlink(typePath.c_str());
1294 
1295 	return B_OK;
1296 }
1297 
1298 
1299 // #pragma mark -
1300 
1301 // read_pos
1302 ssize_t
1303 read_pos(int fd, off_t pos, void *buffer, size_t bufferSize)
1304 {
1305 	// seek
1306 	off_t result = lseek(fd, pos, SEEK_SET);
1307 	if (result < 0)
1308 		return errno;
1309 
1310 	// read
1311 	ssize_t bytesRead = read(fd, buffer, bufferSize);
1312 	if (bytesRead < 0) {
1313 		errno = bytesRead;
1314 		return -1;
1315 	}
1316 
1317 	return bytesRead;
1318 }
1319 
1320 // write_pos
1321 ssize_t
1322 write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize)
1323 {
1324 	// seek
1325 	off_t result = lseek(fd, pos, SEEK_SET);
1326 	if (result < 0)
1327 		return errno;
1328 
1329 	// read
1330 	ssize_t bytesWritten = write(fd, buffer, bufferSize);
1331 	if (bytesWritten < 0) {
1332 		errno = bytesWritten;
1333 		return -1;
1334 	}
1335 
1336 	return bytesWritten;
1337 }
1338