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