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