xref: /haiku/src/system/boot/loader/vfs.cpp (revision 002f37b0cca92e4cf72857c72ac95db5a8b09615)
1 /*
2  * Copyright 2003-2013, Axel Dörfler, axeld@pinc-software.de.
3  * Copyright 2014, Ingo Weinhold, ingo_weinhold@gmx.de.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include <boot/vfs.h>
9 
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <string.h>
13 #include <sys/uio.h>
14 #include <unistd.h>
15 
16 #include <StorageDefs.h>
17 
18 #include <AutoDeleter.h>
19 
20 #include <boot/platform.h>
21 #include <boot/partitions.h>
22 #include <boot/stdio.h>
23 #include <boot/stage2.h>
24 #include <syscall_utils.h>
25 
26 #include "package_support.h"
27 #include "RootFileSystem.h"
28 #include "file_systems/packagefs/packagefs.h"
29 
30 
31 using namespace boot;
32 
33 //#define TRACE_VFS
34 #ifdef TRACE_VFS
35 #	define TRACE(x) dprintf x
36 #else
37 #	define TRACE(x) ;
38 #endif
39 
40 
41 struct __DIR {
42 	Directory*	directory;
43 	void*		cookie;
44 	dirent		entry;
45 	char		nameBuffer[B_FILE_NAME_LENGTH - 1];
46 };
47 
48 
49 class Descriptor {
50 	public:
51 		Descriptor(Node *node, void *cookie);
52 		~Descriptor();
53 
54 		ssize_t ReadAt(off_t pos, void *buffer, size_t bufferSize);
55 		ssize_t Read(void *buffer, size_t bufferSize);
56 		ssize_t WriteAt(off_t pos, const void *buffer, size_t bufferSize);
57 		ssize_t Write(const void *buffer, size_t bufferSize);
58 
59 		void Stat(struct stat &stat);
60 
61 		off_t Offset() const { return fOffset; }
62 		int32 RefCount() const { return fRefCount; }
63 
64 		status_t Acquire();
65 		status_t Release();
66 
67 		Node *GetNode() const { return fNode; }
68 
69 	private:
70 		Node	*fNode;
71 		void	*fCookie;
72 		off_t	fOffset;
73 		int32	fRefCount;
74 };
75 
76 #define MAX_VFS_DESCRIPTORS 64
77 
78 NodeList gBootDevices;
79 NodeList gPartitions;
80 RootFileSystem *gRoot;
81 static Descriptor *sDescriptors[MAX_VFS_DESCRIPTORS];
82 static Node *sBootDevice;
83 
84 
85 Node::Node()
86 	:
87 	fRefCount(1)
88 {
89 }
90 
91 
92 Node::~Node()
93 {
94 }
95 
96 
97 status_t
98 Node::Open(void **_cookie, int mode)
99 {
100 	TRACE(("%p::Open()\n", this));
101 	return Acquire();
102 }
103 
104 
105 status_t
106 Node::Close(void *cookie)
107 {
108 	TRACE(("%p::Close()\n", this));
109 	return Release();
110 }
111 
112 
113 status_t
114 Node::ReadLink(char* buffer, size_t bufferSize)
115 {
116 	return B_BAD_VALUE;
117 }
118 
119 
120 status_t
121 Node::GetName(char *nameBuffer, size_t bufferSize) const
122 {
123 	return B_ERROR;
124 }
125 
126 
127 status_t
128 Node::GetFileMap(struct file_map_run *runs, int32 *count)
129 {
130 	return B_ERROR;
131 }
132 
133 
134 int32
135 Node::Type() const
136 {
137 	return 0;
138 }
139 
140 
141 off_t
142 Node::Size() const
143 {
144 	return 0LL;
145 }
146 
147 
148 ino_t
149 Node::Inode() const
150 {
151 	return 0;
152 }
153 
154 
155 void
156 Node::Stat(struct stat& stat)
157 {
158 	stat.st_mode = Type();
159 	stat.st_size = Size();
160 	stat.st_ino = Inode();
161 }
162 
163 
164 status_t
165 Node::Acquire()
166 {
167 	fRefCount++;
168 	TRACE(("%p::Acquire(), fRefCount = %ld\n", this, fRefCount));
169 	return B_OK;
170 }
171 
172 
173 status_t
174 Node::Release()
175 {
176 	TRACE(("%p::Release(), fRefCount = %ld\n", this, fRefCount));
177 	if (--fRefCount == 0) {
178 		TRACE(("delete node: %p\n", this));
179 		delete this;
180 		return 1;
181 	}
182 
183 	return B_OK;
184 }
185 
186 
187 //	#pragma mark -
188 
189 
190 ConsoleNode::ConsoleNode()
191 	: Node()
192 {
193 }
194 
195 
196 ssize_t
197 ConsoleNode::Read(void *buffer, size_t bufferSize)
198 {
199 	return ReadAt(NULL, -1, buffer, bufferSize);
200 }
201 
202 
203 ssize_t
204 ConsoleNode::Write(const void *buffer, size_t bufferSize)
205 {
206 	return WriteAt(NULL, -1, buffer, bufferSize);
207 }
208 
209 
210 //	#pragma mark -
211 
212 
213 Directory::Directory()
214 	: Node()
215 {
216 }
217 
218 
219 ssize_t
220 Directory::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
221 {
222 	return B_ERROR;
223 }
224 
225 
226 ssize_t
227 Directory::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
228 {
229 	return B_ERROR;
230 }
231 
232 
233 int32
234 Directory::Type() const
235 {
236 	return S_IFDIR;
237 }
238 
239 
240 Node*
241 Directory::Lookup(const char* name, bool traverseLinks)
242 {
243 	Node* node = LookupDontTraverse(name);
244 	if (node == NULL)
245 		return NULL;
246 
247 	if (!traverseLinks || !S_ISLNK(node->Type()))
248 		return node;
249 
250 	// the node is a symbolic link, so we have to resolve the path
251 	char linkPath[B_PATH_NAME_LENGTH];
252 	status_t error = node->ReadLink(linkPath, sizeof(linkPath));
253 
254 	node->Release();
255 		// we don't need this one anymore
256 
257 	if (error != B_OK)
258 		return NULL;
259 
260 	// let open_from() do the real work
261 	int fd = open_from(this, linkPath, O_RDONLY);
262 	if (fd < 0)
263 		return NULL;
264 
265 	node = get_node_from(fd);
266 	if (node != NULL)
267 		node->Acquire();
268 
269 	close(fd);
270 	return node;
271 }
272 
273 
274 status_t
275 Directory::CreateFile(const char *name, mode_t permissions, Node **_node)
276 {
277 	return EROFS;
278 }
279 
280 
281 //	#pragma mark -
282 
283 
284 MemoryDisk::MemoryDisk(const uint8* data, size_t size, const char* name)
285 	: Node(),
286 	  fData(data),
287 	  fSize(size)
288 {
289 	strlcpy(fName, name, sizeof(fName));
290 }
291 
292 
293 ssize_t
294 MemoryDisk::ReadAt(void* cookie, off_t pos, void* buffer, size_t bufferSize)
295 {
296 	if (pos >= fSize)
297 		return 0;
298 
299 	if (pos + bufferSize > fSize)
300 		bufferSize = fSize - pos;
301 
302 	memcpy(buffer, fData + pos, bufferSize);
303 	return bufferSize;
304 }
305 
306 
307 ssize_t
308 MemoryDisk::WriteAt(void* cookie, off_t pos, const void* buffer,
309 	size_t bufferSize)
310 {
311 	return B_NOT_ALLOWED;
312 }
313 
314 
315 off_t
316 MemoryDisk::Size() const
317 {
318 	return fSize;
319 }
320 
321 
322 status_t
323 MemoryDisk::GetName(char *nameBuffer, size_t bufferSize) const
324 {
325 	if (!nameBuffer)
326 		return B_BAD_VALUE;
327 
328 	strlcpy(nameBuffer, fName, bufferSize);
329 	return B_OK;
330 }
331 
332 
333 //	#pragma mark -
334 
335 
336 Descriptor::Descriptor(Node *node, void *cookie)
337 	:
338 	fNode(node),
339 	fCookie(cookie),
340 	fOffset(0),
341 	fRefCount(1)
342 {
343 }
344 
345 
346 Descriptor::~Descriptor()
347 {
348 }
349 
350 
351 ssize_t
352 Descriptor::Read(void *buffer, size_t bufferSize)
353 {
354 	ssize_t bytesRead = fNode->ReadAt(fCookie, fOffset, buffer, bufferSize);
355 	if (bytesRead > B_OK)
356 		fOffset += bytesRead;
357 
358 	return bytesRead;
359 }
360 
361 
362 ssize_t
363 Descriptor::ReadAt(off_t pos, void *buffer, size_t bufferSize)
364 {
365 	return fNode->ReadAt(fCookie, pos, buffer, bufferSize);
366 }
367 
368 
369 ssize_t
370 Descriptor::Write(const void *buffer, size_t bufferSize)
371 {
372 	ssize_t bytesWritten = fNode->WriteAt(fCookie, fOffset, buffer, bufferSize);
373 	if (bytesWritten > B_OK)
374 		fOffset += bytesWritten;
375 
376 	return bytesWritten;
377 }
378 
379 
380 ssize_t
381 Descriptor::WriteAt(off_t pos, const void *buffer, size_t bufferSize)
382 {
383 	return fNode->WriteAt(fCookie, pos, buffer, bufferSize);
384 }
385 
386 
387 void
388 Descriptor::Stat(struct stat &stat)
389 {
390 	fNode->Stat(stat);
391 }
392 
393 
394 status_t
395 Descriptor::Acquire()
396 {
397 	fRefCount++;
398 	return B_OK;
399 }
400 
401 
402 status_t
403 Descriptor::Release()
404 {
405 	if (--fRefCount == 0) {
406 		status_t status = fNode->Close(fCookie);
407 		if (status != B_OK)
408 			return status;
409 	}
410 
411 	return B_OK;
412 }
413 
414 
415 //	#pragma mark -
416 
417 
418 BootVolume::BootVolume()
419 	:
420 	fRootDirectory(NULL),
421 	fSystemDirectory(NULL),
422 	fPackageVolumeInfo(NULL),
423 	fPackageVolumeState(NULL)
424 {
425 }
426 
427 
428 BootVolume::~BootVolume()
429 {
430 	Unset();
431 }
432 
433 
434 status_t
435 BootVolume::SetTo(Directory* rootDirectory,
436 	PackageVolumeInfo* packageVolumeInfo,
437 	PackageVolumeState* packageVolumeState)
438 {
439 	Unset();
440 
441 	status_t error = _SetTo(rootDirectory, packageVolumeInfo,
442 		packageVolumeState);
443 	if (error != B_OK)
444 		Unset();
445 
446 	return error;
447 }
448 
449 
450 void
451 BootVolume::Unset()
452 {
453 	if (fRootDirectory != NULL) {
454 		fRootDirectory->Release();
455 		fRootDirectory = NULL;
456 	}
457 
458 	if (fSystemDirectory != NULL) {
459 		fSystemDirectory->Release();
460 		fSystemDirectory = NULL;
461 	}
462 
463 	if (fPackageVolumeInfo != NULL) {
464 		fPackageVolumeInfo->ReleaseReference();
465 		fPackageVolumeInfo = NULL;
466 		fPackageVolumeState = NULL;
467 	}
468 }
469 
470 
471 status_t
472 BootVolume::_SetTo(Directory* rootDirectory,
473 	PackageVolumeInfo* packageVolumeInfo,
474 	PackageVolumeState* packageVolumeState)
475 {
476 	Unset();
477 
478 	if (rootDirectory == NULL)
479 		return B_BAD_VALUE;
480 
481 	fRootDirectory = rootDirectory;
482 	fRootDirectory->Acquire();
483 
484 	// find the system directory
485 	Node* systemNode = fRootDirectory->Lookup("system", true);
486 	if (systemNode == NULL || !S_ISDIR(systemNode->Type())) {
487 		if (systemNode != NULL)
488 			systemNode->Release();
489 		Unset();
490 		return B_ENTRY_NOT_FOUND;
491 	}
492 
493 	fSystemDirectory = static_cast<Directory*>(systemNode);
494 
495 	if (packageVolumeInfo == NULL) {
496 		// get a package volume info
497 		BReference<PackageVolumeInfo> packageVolumeInfoReference(
498 			new(std::nothrow) PackageVolumeInfo);
499 		status_t error = packageVolumeInfoReference->SetTo(fSystemDirectory,
500 			"packages");
501 		if (error != B_OK) {
502 			// apparently not packaged
503 			return B_OK;
504 		}
505 
506 		fPackageVolumeInfo = packageVolumeInfoReference.Detach();
507 	} else {
508 		fPackageVolumeInfo = packageVolumeInfo;
509 		fPackageVolumeInfo->AcquireReference();
510 	}
511 
512 	fPackageVolumeState = packageVolumeState != NULL
513 		? packageVolumeState : fPackageVolumeInfo->States().Head();
514 
515 	// try opening the system package
516 	int packageFD = _OpenSystemPackage();
517 	if (packageFD < 0)
518 		return packageFD;
519 
520 	// mount packagefs
521 	Directory* packageRootDirectory;
522 	status_t error = packagefs_mount_file(packageFD, fSystemDirectory,
523 		packageRootDirectory);
524 	close(packageFD);
525 	if (error != B_OK) {
526 		Unset();
527 		return error;
528 	}
529 
530 	fSystemDirectory->Release();
531 	fSystemDirectory = packageRootDirectory;
532 
533 	return B_OK;
534 }
535 
536 
537 int
538 BootVolume::_OpenSystemPackage()
539 {
540 	// open the packages directory
541 	Node* packagesNode = fSystemDirectory->Lookup("packages", false);
542 	if (packagesNode == NULL)
543 		return -1;
544 	MethodDeleter<Node, status_t> packagesNodeReleaser(packagesNode,
545 		&Node::Release);
546 
547 	if (!S_ISDIR(packagesNode->Type()))
548 		return -1;
549 	Directory* packageDirectory = (Directory*)packagesNode;
550 
551 	// open the system package
552 	return open_from(packageDirectory, fPackageVolumeState->SystemPackage(),
553 		O_RDONLY);
554 }
555 
556 
557 //	#pragma mark -
558 
559 
560 status_t
561 vfs_init(stage2_args *args)
562 {
563 	gRoot = new(nothrow) RootFileSystem();
564 	if (gRoot == NULL)
565 		return B_NO_MEMORY;
566 
567 	return B_OK;
568 }
569 
570 
571 status_t
572 register_boot_file_system(BootVolume& bootVolume)
573 {
574 	Directory* rootDirectory = bootVolume.RootDirectory();
575 	gRoot->AddLink("boot", rootDirectory);
576 
577 	Partition *partition;
578 	status_t status = gRoot->GetPartitionFor(rootDirectory, &partition);
579 	if (status != B_OK) {
580 		dprintf("register_boot_file_system(): could not locate boot volume in "
581 			"root!\n");
582 		return status;
583 	}
584 
585 	gBootVolume.SetInt64(BOOT_VOLUME_PARTITION_OFFSET,
586 		partition->offset);
587 
588 	if (bootVolume.IsPackaged()) {
589 		gBootVolume.SetBool(BOOT_VOLUME_PACKAGED, true);
590 		PackageVolumeState* state = bootVolume.GetPackageVolumeState();
591 		if (state->Name() != NULL)
592 			gBootVolume.AddString(BOOT_VOLUME_PACKAGES_STATE, state->Name());
593 	}
594 
595 	Node *device = get_node_from(partition->FD());
596 	if (device == NULL) {
597 		dprintf("register_boot_file_system(): could not get boot device!\n");
598 		return B_ERROR;
599 	}
600 
601 	return platform_register_boot_device(device);
602 }
603 
604 
605 /*! Gets the boot device, scans all of its partitions, gets the
606 	boot partition, and mounts its file system.
607 
608 	\param args The stage 2 arguments.
609 	\param _bootVolume On success set to the boot volume.
610 	\return \c B_OK on success, another error code otherwise.
611 */
612 status_t
613 get_boot_file_system(stage2_args* args, BootVolume& _bootVolume)
614 {
615 	Node *device;
616 	status_t error = platform_add_boot_device(args, &gBootDevices);
617 	if (error != B_OK)
618 		return error;
619 
620 	// the boot device must be the first device in the list
621 	device = gBootDevices.First();
622 
623 	error = add_partitions_for(device, false, true);
624 	if (error != B_OK)
625 		return error;
626 
627 	Partition *partition;
628 	error = platform_get_boot_partition(args, device, &gPartitions, &partition);
629 	if (error != B_OK)
630 		return error;
631 
632 	Directory *fileSystem;
633 	error = partition->Mount(&fileSystem, true);
634 	if (error != B_OK) {
635 		// this partition doesn't contain any known file system; we
636 		// don't need it anymore
637 		gPartitions.Remove(partition);
638 		delete partition;
639 		return error;
640 	}
641 
642 	// init the BootVolume
643 	error = _bootVolume.SetTo(fileSystem);
644 	if (error != B_OK)
645 		return error;
646 
647 	sBootDevice = device;
648 	return B_OK;
649 }
650 
651 
652 /** Mounts all file systems recognized on the given device by
653  *	calling the add_partitions_for() function on them.
654  */
655 
656 status_t
657 mount_file_systems(stage2_args *args)
658 {
659 	// mount other partitions on boot device (if any)
660 	NodeIterator iterator = gPartitions.GetIterator();
661 
662 	Partition *partition = NULL;
663 	while ((partition = (Partition *)iterator.Next()) != NULL) {
664 		// don't scan known partitions again
665 		if (partition->IsFileSystem())
666 			continue;
667 
668 		// remove the partition if it doesn't contain a (known) file system
669 		if (partition->Scan(true) != B_OK && !partition->IsFileSystem()) {
670 			gPartitions.Remove(partition);
671 			delete partition;
672 		}
673 	}
674 
675 	// add all block devices the platform has for us
676 
677 	status_t status = platform_add_block_devices(args, &gBootDevices);
678 	if (status < B_OK)
679 		return status;
680 
681 	iterator = gBootDevices.GetIterator();
682 	Node *device = NULL, *last = NULL;
683 	while ((device = iterator.Next()) != NULL) {
684 		// don't scan former boot device again
685 		if (device == sBootDevice)
686 			continue;
687 
688 		if (add_partitions_for(device, true) == B_OK) {
689 			// ToDo: we can't delete the object here, because it must
690 			//	be removed from the list before we know that it was
691 			//	deleted.
692 
693 /*			// if the Release() deletes the object, we need to skip it
694 			if (device->Release() > 0) {
695 				list_remove_item(&gBootDevices, device);
696 				device = last;
697 			}
698 */
699 (void)last;
700 		}
701 		last = device;
702 	}
703 
704 	if (gPartitions.IsEmpty())
705 		return B_ENTRY_NOT_FOUND;
706 
707 #if 0
708 	void *cookie;
709 	if (gRoot->Open(&cookie, O_RDONLY) == B_OK) {
710 		Directory *directory;
711 		while (gRoot->GetNextNode(cookie, (Node **)&directory) == B_OK) {
712 			char name[256];
713 			if (directory->GetName(name, sizeof(name)) == B_OK)
714 				printf(":: %s (%p)\n", name, directory);
715 
716 			void *subCookie;
717 			if (directory->Open(&subCookie, O_RDONLY) == B_OK) {
718 				while (directory->GetNextEntry(subCookie, name, sizeof(name)) == B_OK) {
719 					printf("\t%s\n", name);
720 				}
721 				directory->Close(subCookie);
722 			}
723 		}
724 		gRoot->Close(cookie);
725 	}
726 #endif
727 
728 	return B_OK;
729 }
730 
731 
732 /*!	Resolves \a directory + \a path to a node.
733 	Note that \a path will be modified by the function.
734 */
735 static status_t
736 get_node_for_path(Directory *directory, char *path, Node **_node)
737 {
738 	directory->Acquire();
739 		// balance Acquire()/Release() calls
740 
741 	while (true) {
742 		Node *nextNode;
743 		char *nextPath;
744 
745 		// walk to find the next path component ("path" will point to a single
746 		// path component), and filter out multiple slashes
747 		for (nextPath = path + 1; nextPath[0] != '\0' && nextPath[0] != '/'; nextPath++);
748 
749 		if (*nextPath == '/') {
750 			*nextPath = '\0';
751 			do
752 				nextPath++;
753 			while (*nextPath == '/');
754 		}
755 
756 		nextNode = directory->Lookup(path, true);
757 		directory->Release();
758 
759 		if (nextNode == NULL)
760 			return B_ENTRY_NOT_FOUND;
761 
762 		path = nextPath;
763 		if (S_ISDIR(nextNode->Type()))
764 			directory = (Directory *)nextNode;
765 		else if (path[0])
766 			return B_NOT_ALLOWED;
767 
768 		// are we done?
769 		if (path[0] == '\0') {
770 			*_node = nextNode;
771 			return B_OK;
772 		}
773 	}
774 
775 	return B_ENTRY_NOT_FOUND;
776 }
777 
778 
779 /*!	Version of get_node_for_path() not modifying \a path.
780  */
781 static status_t
782 get_node_for_path(Directory* directory, const char* path, Node** _node)
783 {
784 	char* mutablePath = strdup(path);
785 	if (mutablePath == NULL)
786 		return B_NO_MEMORY;
787 	MemoryDeleter mutablePathDeleter(mutablePath);
788 
789 	return get_node_for_path(directory, mutablePath, _node);
790 }
791 
792 //	#pragma mark -
793 
794 
795 static Descriptor *
796 get_descriptor(int fd)
797 {
798 	if (fd < 0 || fd >= MAX_VFS_DESCRIPTORS)
799 		return NULL;
800 
801 	return sDescriptors[fd];
802 }
803 
804 
805 static void
806 free_descriptor(int fd)
807 {
808 	if (fd >= MAX_VFS_DESCRIPTORS)
809 		return;
810 
811 	delete sDescriptors[fd];
812 	sDescriptors[fd] = NULL;
813 }
814 
815 
816 /**	Reserves an entry of the descriptor table and
817  *	assigns the given node to it.
818  */
819 
820 int
821 open_node(Node *node, int mode)
822 {
823 	if (node == NULL)
824 		return B_ERROR;
825 
826 	// get free descriptor
827 
828 	int fd = 0;
829 	for (; fd < MAX_VFS_DESCRIPTORS; fd++) {
830 		if (sDescriptors[fd] == NULL)
831 			break;
832 	}
833 	if (fd == MAX_VFS_DESCRIPTORS)
834 		return B_ERROR;
835 
836 	TRACE(("got descriptor %d for node %p\n", fd, node));
837 
838 	// we got a free descriptor entry, now try to open the node
839 
840 	void *cookie;
841 	status_t status = node->Open(&cookie, mode);
842 	if (status < B_OK)
843 		return status;
844 
845 	TRACE(("could open node at %p\n", node));
846 
847 	Descriptor *descriptor = new(nothrow) Descriptor(node, cookie);
848 	if (descriptor == NULL)
849 		return B_NO_MEMORY;
850 
851 	sDescriptors[fd] = descriptor;
852 
853 	return fd;
854 }
855 
856 
857 int
858 dup(int fd)
859 {
860 	Descriptor *descriptor = get_descriptor(fd);
861 	if (descriptor == NULL)
862 		RETURN_AND_SET_ERRNO(B_FILE_ERROR);
863 
864 	descriptor->Acquire();
865 	RETURN_AND_SET_ERRNO(fd);
866 }
867 
868 
869 ssize_t
870 read_pos(int fd, off_t offset, void *buffer, size_t bufferSize)
871 {
872 	Descriptor *descriptor = get_descriptor(fd);
873 	if (descriptor == NULL)
874 		RETURN_AND_SET_ERRNO(B_FILE_ERROR);
875 
876 	RETURN_AND_SET_ERRNO(descriptor->ReadAt(offset, buffer, bufferSize));
877 }
878 
879 
880 ssize_t
881 pread(int fd, void* buffer, size_t bufferSize, off_t offset)
882 {
883 	return read_pos(fd, offset, buffer, bufferSize);
884 }
885 
886 
887 ssize_t
888 read(int fd, void *buffer, size_t bufferSize)
889 {
890 	Descriptor *descriptor = get_descriptor(fd);
891 	if (descriptor == NULL)
892 		RETURN_AND_SET_ERRNO(B_FILE_ERROR);
893 
894 	RETURN_AND_SET_ERRNO(descriptor->Read(buffer, bufferSize));
895 }
896 
897 
898 ssize_t
899 write_pos(int fd, off_t offset, const void *buffer, size_t bufferSize)
900 {
901 	Descriptor *descriptor = get_descriptor(fd);
902 	if (descriptor == NULL)
903 		RETURN_AND_SET_ERRNO(B_FILE_ERROR);
904 
905 	RETURN_AND_SET_ERRNO(descriptor->WriteAt(offset, buffer, bufferSize));
906 }
907 
908 
909 ssize_t
910 write(int fd, const void *buffer, size_t bufferSize)
911 {
912 	Descriptor *descriptor = get_descriptor(fd);
913 	if (descriptor == NULL)
914 		RETURN_AND_SET_ERRNO(B_FILE_ERROR);
915 
916 	RETURN_AND_SET_ERRNO(descriptor->Write(buffer, bufferSize));
917 }
918 
919 
920 ssize_t
921 writev(int fd, const struct iovec* vecs, size_t count)
922 {
923 	size_t totalWritten = 0;
924 
925 	for (size_t i = 0; i < count; i++) {
926 		ssize_t written = write(fd, vecs[i].iov_base, vecs[i].iov_len);
927 		if (written < 0)
928 			return totalWritten == 0 ? written : totalWritten;
929 
930 		totalWritten += written;
931 
932 		if ((size_t)written != vecs[i].iov_len)
933 			break;
934 	}
935 
936 	return totalWritten;
937 }
938 
939 
940 int
941 open(const char *name, int mode, ...)
942 {
943 	mode_t permissions = 0;
944 	if ((mode & O_CREAT) != 0) {
945         va_list args;
946         va_start(args, mode);
947         permissions = va_arg(args, int) /*& ~__gUmask*/;
948             // adapt the permissions as required by POSIX
949         va_end(args);
950 	}
951 
952 	// we always start at the top (there is no notion of a current directory (yet?))
953 	RETURN_AND_SET_ERRNO(open_from(gRoot, name, mode, permissions));
954 }
955 
956 
957 int
958 open_from(Directory *directory, const char *name, int mode, mode_t permissions)
959 {
960 	if (name[0] == '/') {
961 		// ignore the directory and start from root if we are asked to do that
962 		directory = gRoot;
963 		name++;
964 	}
965 
966 	char path[B_PATH_NAME_LENGTH];
967 	if (strlcpy(path, name, sizeof(path)) >= sizeof(path))
968 		return B_NAME_TOO_LONG;
969 
970 	Node *node;
971 	status_t error = get_node_for_path(directory, path, &node);
972 	if (error != B_OK) {
973 		if (error != B_ENTRY_NOT_FOUND)
974 			return error;
975 
976 		if ((mode & O_CREAT) == 0)
977 			return B_ENTRY_NOT_FOUND;
978 
979 		// try to resolve the parent directory
980 		strlcpy(path, name, sizeof(path));
981 		if (char* lastSlash = strrchr(path, '/')) {
982 			if (lastSlash[1] == '\0')
983 				return B_ENTRY_NOT_FOUND;
984 
985 			lastSlash = '\0';
986 			name = lastSlash + 1;
987 
988 			// resolve the directory
989 			if (get_node_for_path(directory, path, &node) != B_OK)
990 				return B_ENTRY_NOT_FOUND;
991 
992 			if (node->Type() != S_IFDIR) {
993 				node->Release();
994 				return B_NOT_A_DIRECTORY;
995 			}
996 
997 			directory = static_cast<Directory*>(node);
998 		} else
999 			directory->Acquire();
1000 
1001 		// create the file
1002 		error = directory->CreateFile(name, permissions, &node);
1003 		directory->Release();
1004 
1005 		if (error != B_OK)
1006 			return error;
1007 	} else if ((mode & O_EXCL) != 0) {
1008 		node->Release();
1009 		return B_FILE_EXISTS;
1010 	}
1011 
1012 	int fd = open_node(node, mode);
1013 
1014 	node->Release();
1015 	return fd;
1016 }
1017 
1018 
1019 /** Since we don't have directory functions yet, this
1020  *	function is needed to get the contents of a directory.
1021  *	It should be removed once readdir() & co. are in place.
1022  */
1023 
1024 Node *
1025 get_node_from(int fd)
1026 {
1027 	Descriptor *descriptor = get_descriptor(fd);
1028 	if (descriptor == NULL)
1029 		return NULL;
1030 
1031 	return descriptor->GetNode();
1032 }
1033 
1034 
1035 status_t
1036 get_stat(Directory* directory, const char* path, struct stat& st)
1037 {
1038 	Node* node;
1039 	status_t error = get_node_for_path(directory, path, &node);
1040 	if (error != B_OK)
1041 		return error;
1042 
1043 	node->Stat(st);
1044 	node->Release();
1045 	return B_OK;
1046 }
1047 
1048 
1049 Directory*
1050 directory_from(DIR* dir)
1051 {
1052 	return dir != NULL ? dir->directory : NULL;
1053 }
1054 
1055 
1056 int
1057 close(int fd)
1058 {
1059 	Descriptor *descriptor = get_descriptor(fd);
1060 	if (descriptor == NULL)
1061 		RETURN_AND_SET_ERRNO(B_FILE_ERROR);
1062 
1063 	status_t status = descriptor->Release();
1064 	if (!descriptor->RefCount())
1065 		free_descriptor(fd);
1066 
1067 	RETURN_AND_SET_ERRNO(status);
1068 }
1069 
1070 
1071 // ToDo: remove this kludge when possible
1072 int
1073 #if defined(fstat) && !defined(main)
1074 _fstat(int fd, struct stat *stat, size_t /*statSize*/)
1075 #else
1076 fstat(int fd, struct stat *stat)
1077 #endif
1078 {
1079 	if (stat == NULL)
1080 		RETURN_AND_SET_ERRNO(B_BAD_VALUE);
1081 
1082 	Descriptor *descriptor = get_descriptor(fd);
1083 	if (descriptor == NULL)
1084 		RETURN_AND_SET_ERRNO(B_FILE_ERROR);
1085 
1086 	descriptor->Stat(*stat);
1087 	return 0;
1088 }
1089 
1090 
1091 DIR*
1092 open_directory(Directory* baseDirectory, const char* path)
1093 {
1094 	DIR* dir = new(std::nothrow) DIR;
1095 	if (dir == NULL) {
1096 		errno = B_NO_MEMORY;
1097 		return NULL;
1098 	}
1099 	ObjectDeleter<DIR> dirDeleter(dir);
1100 
1101 	Node* node;
1102 	status_t error = get_node_for_path(baseDirectory, path, &node);
1103 	if (error != B_OK) {
1104 		errno = error;
1105 		return NULL;
1106 	}
1107 	MethodDeleter<Node, status_t> nodeReleaser(node, &Node::Release);
1108 
1109 	if (!S_ISDIR(node->Type())) {
1110 		errno = error;
1111 		return NULL;
1112 	}
1113 
1114 	dir->directory = static_cast<Directory*>(node);
1115 
1116 	error = dir->directory->Open(&dir->cookie, O_RDONLY);
1117 	if (error != B_OK) {
1118 		errno = error;
1119 		return NULL;
1120 	}
1121 
1122 	nodeReleaser.Detach();
1123 	return dirDeleter.Detach();
1124 }
1125 
1126 
1127 DIR*
1128 opendir(const char* dirName)
1129 {
1130 	return open_directory(gRoot, dirName);
1131 }
1132 
1133 
1134 int
1135 closedir(DIR* dir)
1136 {
1137 	if (dir != NULL) {
1138 		dir->directory->Close(dir->cookie);
1139 		dir->directory->Release();
1140 		delete dir;
1141 	}
1142 
1143 	return 0;
1144 }
1145 
1146 
1147 struct dirent*
1148 readdir(DIR* dir)
1149 {
1150 	if (dir == NULL) {
1151 		errno = B_BAD_VALUE;
1152 		return NULL;
1153 	}
1154 
1155 	for (;;) {
1156 		status_t error = dir->directory->GetNextEntry(dir->cookie,
1157 			dir->entry.d_name, B_FILE_NAME_LENGTH);
1158 		if (error != B_OK) {
1159 			errno = error;
1160 			return NULL;
1161 		}
1162 
1163 		dir->entry.d_pdev = 0;
1164 			// not supported
1165 		dir->entry.d_pino = dir->directory->Inode();
1166 		dir->entry.d_dev = dir->entry.d_pdev;
1167 			// not supported
1168 
1169 		if (strcmp(dir->entry.d_name, ".") == 0
1170 				|| strcmp(dir->entry.d_name, "..") == 0) {
1171 			// Note: That's obviously not correct for "..", but we can't
1172 			// retrieve that information.
1173 			dir->entry.d_ino = dir->entry.d_pino;
1174 		} else {
1175 			Node* node = dir->directory->Lookup(dir->entry.d_name, false);
1176 			if (node == NULL)
1177 				continue;
1178 
1179 			dir->entry.d_ino = node->Inode();
1180 			node->Release();
1181 		}
1182 
1183 		return &dir->entry;
1184 	}
1185 }
1186 
1187 
1188 void
1189 rewinddir(DIR* dir)
1190 {
1191 	if (dir == NULL) {
1192 		errno = B_BAD_VALUE;
1193 		return;
1194 	}
1195 
1196 	status_t error = dir->directory->Rewind(dir->cookie);
1197 	if (error != B_OK)
1198 		errno = error;
1199 }
1200