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