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