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