headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / boot / loader / vfs.cpp
blob88a3ba6a07bf81d20f940f5e2f567de88ba3a5ee
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 */
9 #include <boot/vfs.h>
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <string.h>
14 #include <sys/uio.h>
15 #include <unistd.h>
17 #include <StorageDefs.h>
19 #include <AutoDeleter.h>
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>
27 #include "package_support.h"
28 #include "RootFileSystem.h"
29 #include "file_systems/packagefs/packagefs.h"
32 using namespace boot;
34 //#define TRACE_VFS
35 #ifdef TRACE_VFS
36 # define TRACE(x) dprintf x
37 #else
38 # define TRACE(x) ;
39 #endif
42 struct __DIR {
43 Directory* directory;
44 void* cookie;
45 dirent entry;
46 char nameBuffer[B_FILE_NAME_LENGTH - 1];
50 class Descriptor {
51 public:
52 Descriptor(Node *node, void *cookie);
53 ~Descriptor();
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);
60 void Stat(struct stat &stat);
61 status_t Seek(off_t position, int mode);
63 off_t Offset() const { return fOffset; }
64 int32 RefCount() const { return fRefCount; }
66 status_t Acquire();
67 status_t Release();
69 Node *GetNode() const { return fNode; }
71 private:
72 Node *fNode;
73 void *fCookie;
74 off_t fOffset;
75 int32 fRefCount;
78 #define MAX_VFS_DESCRIPTORS 64
80 NodeList gBootDevices;
81 NodeList gPartitions;
82 RootFileSystem *gRoot;
83 static Descriptor *sDescriptors[MAX_VFS_DESCRIPTORS];
84 static Node *sBootDevice;
87 Node::Node()
89 fRefCount(1)
94 Node::~Node()
99 status_t
100 Node::Open(void **_cookie, int mode)
102 TRACE(("%p::Open()\n", this));
103 return Acquire();
107 status_t
108 Node::Close(void *cookie)
110 TRACE(("%p::Close()\n", this));
111 return Release();
115 status_t
116 Node::ReadLink(char* buffer, size_t bufferSize)
118 return B_BAD_VALUE;
122 status_t
123 Node::GetName(char *nameBuffer, size_t bufferSize) const
125 return B_ERROR;
129 status_t
130 Node::GetFileMap(struct file_map_run *runs, int32 *count)
132 return B_ERROR;
136 int32
137 Node::Type() const
139 return 0;
143 off_t
144 Node::Size() const
146 return 0LL;
150 ino_t
151 Node::Inode() const
153 return 0;
157 void
158 Node::Stat(struct stat& stat)
160 stat.st_mode = Type();
161 stat.st_size = Size();
162 stat.st_ino = Inode();
166 status_t
167 Node::Acquire()
169 fRefCount++;
170 TRACE(("%p::Acquire(), fRefCount = %ld\n", this, fRefCount));
171 return B_OK;
175 status_t
176 Node::Release()
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;
185 return B_OK;
189 // #pragma mark -
192 ConsoleNode::ConsoleNode()
193 : Node()
198 ssize_t
199 ConsoleNode::Read(void *buffer, size_t bufferSize)
201 return ReadAt(NULL, -1, buffer, bufferSize);
205 ssize_t
206 ConsoleNode::Write(const void *buffer, size_t bufferSize)
208 return WriteAt(NULL, -1, buffer, bufferSize);
212 // #pragma mark -
215 Directory::Directory()
216 : Node()
221 ssize_t
222 Directory::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
224 return B_ERROR;
228 ssize_t
229 Directory::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize)
231 return B_ERROR;
235 int32
236 Directory::Type() const
238 return S_IFDIR;
242 Node*
243 Directory::Lookup(const char* name, bool traverseLinks)
245 Node* node = LookupDontTraverse(name);
246 if (node == NULL)
247 return NULL;
249 if (!traverseLinks || !S_ISLNK(node->Type()))
250 return node;
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));
256 node->Release();
257 // we don't need this one anymore
259 if (error != B_OK)
260 return NULL;
262 // let open_from() do the real work
263 int fd = open_from(this, linkPath, O_RDONLY);
264 if (fd < 0)
265 return NULL;
267 node = get_node_from(fd);
268 if (node != NULL)
269 node->Acquire();
271 close(fd);
272 return node;
276 status_t
277 Directory::CreateFile(const char *name, mode_t permissions, Node **_node)
279 return EROFS;
283 // #pragma mark -
286 MemoryDisk::MemoryDisk(const uint8* data, size_t size, const char* name)
287 : Node(),
288 fData(data),
289 fSize(size)
291 strlcpy(fName, name, sizeof(fName));
295 ssize_t
296 MemoryDisk::ReadAt(void* cookie, off_t pos, void* buffer, size_t bufferSize)
298 if (pos < 0)
299 return B_BAD_VALUE;
300 if ((size_t)pos >= fSize)
301 return 0;
303 if (pos + bufferSize > fSize)
304 bufferSize = fSize - pos;
306 memcpy(buffer, fData + pos, bufferSize);
307 return bufferSize;
311 ssize_t
312 MemoryDisk::WriteAt(void* cookie, off_t pos, const void* buffer,
313 size_t bufferSize)
315 return B_NOT_ALLOWED;
319 off_t
320 MemoryDisk::Size() const
322 return fSize;
326 status_t
327 MemoryDisk::GetName(char *nameBuffer, size_t bufferSize) const
329 if (!nameBuffer)
330 return B_BAD_VALUE;
332 strlcpy(nameBuffer, fName, bufferSize);
333 return B_OK;
337 // #pragma mark -
340 Descriptor::Descriptor(Node *node, void *cookie)
342 fNode(node),
343 fCookie(cookie),
344 fOffset(0),
345 fRefCount(1)
350 Descriptor::~Descriptor()
355 ssize_t
356 Descriptor::Read(void *buffer, size_t bufferSize)
358 ssize_t bytesRead = fNode->ReadAt(fCookie, fOffset, buffer, bufferSize);
359 if (bytesRead > B_OK)
360 fOffset += bytesRead;
362 return bytesRead;
366 ssize_t
367 Descriptor::ReadAt(off_t pos, void *buffer, size_t bufferSize)
369 return fNode->ReadAt(fCookie, pos, buffer, bufferSize);
373 ssize_t
374 Descriptor::Write(const void *buffer, size_t bufferSize)
376 ssize_t bytesWritten = fNode->WriteAt(fCookie, fOffset, buffer, bufferSize);
377 if (bytesWritten > B_OK)
378 fOffset += bytesWritten;
380 return bytesWritten;
384 ssize_t
385 Descriptor::WriteAt(off_t pos, const void *buffer, size_t bufferSize)
387 return fNode->WriteAt(fCookie, pos, buffer, bufferSize);
391 void
392 Descriptor::Stat(struct stat &stat)
394 fNode->Stat(stat);
398 status_t
399 Descriptor::Seek(off_t position, int mode)
401 off_t newPosition;
402 switch (mode)
404 case SEEK_SET:
405 newPosition = position;
406 break;
407 case SEEK_CUR:
408 newPosition = fOffset + position;
409 break;
410 case SEEK_END:
412 struct stat st;
413 Stat(st);
414 newPosition = st.st_size + position;
415 break;
417 default:
418 return B_BAD_VALUE;
421 if (newPosition < 0)
422 return B_BAD_VALUE;
424 fOffset = newPosition;
425 return B_OK;
429 status_t
430 Descriptor::Acquire()
432 fRefCount++;
433 return B_OK;
437 status_t
438 Descriptor::Release()
440 if (--fRefCount == 0) {
441 status_t status = fNode->Close(fCookie);
442 if (status != B_OK)
443 return status;
446 return B_OK;
450 // #pragma mark -
453 BootVolume::BootVolume()
455 fRootDirectory(NULL),
456 fSystemDirectory(NULL),
457 fPackageVolumeInfo(NULL),
458 fPackageVolumeState(NULL)
463 BootVolume::~BootVolume()
465 Unset();
469 status_t
470 BootVolume::SetTo(Directory* rootDirectory,
471 PackageVolumeInfo* packageVolumeInfo,
472 PackageVolumeState* packageVolumeState)
474 Unset();
476 status_t error = _SetTo(rootDirectory, packageVolumeInfo,
477 packageVolumeState);
478 if (error != B_OK)
479 Unset();
481 return error;
485 void
486 BootVolume::Unset()
488 if (fRootDirectory != NULL) {
489 fRootDirectory->Release();
490 fRootDirectory = NULL;
493 if (fSystemDirectory != NULL) {
494 fSystemDirectory->Release();
495 fSystemDirectory = NULL;
498 if (fPackageVolumeInfo != NULL) {
499 fPackageVolumeInfo->ReleaseReference();
500 fPackageVolumeInfo = NULL;
501 fPackageVolumeState = NULL;
506 status_t
507 BootVolume::_SetTo(Directory* rootDirectory,
508 PackageVolumeInfo* packageVolumeInfo,
509 PackageVolumeState* packageVolumeState)
511 Unset();
513 if (rootDirectory == NULL)
514 return B_BAD_VALUE;
516 fRootDirectory = rootDirectory;
517 fRootDirectory->Acquire();
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;
528 fSystemDirectory = static_cast<Directory*>(systemNode);
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;
541 fPackageVolumeInfo = packageVolumeInfoReference.Detach();
542 } else {
543 fPackageVolumeInfo = packageVolumeInfo;
544 fPackageVolumeInfo->AcquireReference();
547 fPackageVolumeState = packageVolumeState != NULL
548 ? packageVolumeState : fPackageVolumeInfo->States().Head();
550 // try opening the system package
551 int packageFD = _OpenSystemPackage();
552 if (packageFD < 0)
553 return packageFD;
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;
565 fSystemDirectory->Release();
566 fSystemDirectory = packageRootDirectory;
568 return B_OK;
573 BootVolume::_OpenSystemPackage()
575 // open the packages directory
576 Node* packagesNode = fSystemDirectory->Lookup("packages", false);
577 if (packagesNode == NULL)
578 return -1;
579 MethodDeleter<Node, status_t> packagesNodeReleaser(packagesNode,
580 &Node::Release);
582 if (!S_ISDIR(packagesNode->Type()))
583 return -1;
584 Directory* packageDirectory = (Directory*)packagesNode;
586 // open the system package
587 return open_from(packageDirectory, fPackageVolumeState->SystemPackage(),
588 O_RDONLY);
592 // #pragma mark -
595 status_t
596 vfs_init(stage2_args *args)
598 gRoot = new(nothrow) RootFileSystem();
599 if (gRoot == NULL)
600 return B_NO_MEMORY;
602 return B_OK;
606 status_t
607 register_boot_file_system(BootVolume& bootVolume)
609 Directory* rootDirectory = bootVolume.RootDirectory();
610 gRoot->AddLink("boot", rootDirectory);
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;
620 gBootVolume.SetInt64(BOOT_VOLUME_PARTITION_OFFSET,
621 partition->offset);
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());
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;
636 return platform_register_boot_device(device);
640 /*! Gets the boot device, scans all of its partitions, gets the
641 boot partition, and mounts its file system.
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.
647 status_t
648 get_boot_file_system(stage2_args* args, BootVolume& _bootVolume)
650 status_t error = platform_add_boot_device(args, &gBootDevices);
651 if (error != B_OK)
652 return error;
654 NodeIterator iterator = gBootDevices.GetIterator();
655 while (iterator.HasNext()) {
656 Node *device = iterator.Next();
658 error = add_partitions_for(device, false, true);
659 if (error != B_OK)
660 continue;
662 NodeList bootPartitions;
663 error = platform_get_boot_partitions(args, device, &gPartitions, &bootPartitions);
664 if (error != B_OK)
665 continue;
667 NodeIterator partitionIterator = bootPartitions.GetIterator();
668 while (partitionIterator.HasNext()) {
669 Partition *partition = (Partition*)partitionIterator.Next();
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;
681 // init the BootVolume
682 error = _bootVolume.SetTo(fileSystem);
683 if (error != B_OK)
684 continue;
686 sBootDevice = device;
687 return B_OK;
691 return B_ERROR;
695 /** Mounts all file systems recognized on the given device by
696 * calling the add_partitions_for() function on them.
699 status_t
700 mount_file_systems(stage2_args *args)
702 // mount other partitions on boot device (if any)
703 NodeIterator iterator = gPartitions.GetIterator();
705 Partition *partition = NULL;
706 while ((partition = (Partition *)iterator.Next()) != NULL) {
707 // don't scan known partitions again
708 if (partition->IsFileSystem())
709 continue;
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;
718 // add all block devices the platform has for us
720 status_t status = platform_add_block_devices(args, &gBootDevices);
721 if (status < B_OK)
722 return status;
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;
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.
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;
742 (void)last;
744 last = device;
747 if (gPartitions.IsEmpty())
748 return B_ENTRY_NOT_FOUND;
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);
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);
764 directory->Close(subCookie);
767 gRoot->Close(cookie);
769 #endif
771 return B_OK;
775 /*! Resolves \a directory + \a path to a node.
776 Note that \a path will be modified by the function.
778 static status_t
779 get_node_for_path(Directory *directory, char *path, Node **_node)
781 directory->Acquire();
782 // balance Acquire()/Release() calls
784 while (true) {
785 Node *nextNode;
786 char *nextPath;
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++);
792 if (*nextPath == '/') {
793 *nextPath = '\0';
795 nextPath++;
796 while (*nextPath == '/');
799 nextNode = directory->Lookup(path, true);
800 directory->Release();
802 if (nextNode == NULL)
803 return B_ENTRY_NOT_FOUND;
805 path = nextPath;
806 if (S_ISDIR(nextNode->Type()))
807 directory = (Directory *)nextNode;
808 else if (path[0])
809 return B_NOT_ALLOWED;
811 // are we done?
812 if (path[0] == '\0') {
813 *_node = nextNode;
814 return B_OK;
818 return B_ENTRY_NOT_FOUND;
822 /*! Version of get_node_for_path() not modifying \a path.
824 static status_t
825 get_node_for_path(Directory* directory, const char* path, Node** _node)
827 char* mutablePath = strdup(path);
828 if (mutablePath == NULL)
829 return B_NO_MEMORY;
830 MemoryDeleter mutablePathDeleter(mutablePath);
832 return get_node_for_path(directory, mutablePath, _node);
835 // #pragma mark -
838 static Descriptor *
839 get_descriptor(int fd)
841 if (fd < 0 || fd >= MAX_VFS_DESCRIPTORS)
842 return NULL;
844 return sDescriptors[fd];
848 static void
849 free_descriptor(int fd)
851 if (fd >= MAX_VFS_DESCRIPTORS)
852 return;
854 delete sDescriptors[fd];
855 sDescriptors[fd] = NULL;
859 /** Reserves an entry of the descriptor table and
860 * assigns the given node to it.
864 open_node(Node *node, int mode)
866 if (node == NULL)
867 return B_ERROR;
869 // get free descriptor
871 int fd = 0;
872 for (; fd < MAX_VFS_DESCRIPTORS; fd++) {
873 if (sDescriptors[fd] == NULL)
874 break;
876 if (fd == MAX_VFS_DESCRIPTORS)
877 return B_ERROR;
879 TRACE(("got descriptor %d for node %p\n", fd, node));
881 // we got a free descriptor entry, now try to open the node
883 void *cookie;
884 status_t status = node->Open(&cookie, mode);
885 if (status < B_OK)
886 return status;
888 TRACE(("could open node at %p\n", node));
890 Descriptor *descriptor = new(nothrow) Descriptor(node, cookie);
891 if (descriptor == NULL)
892 return B_NO_MEMORY;
894 sDescriptors[fd] = descriptor;
896 return fd;
901 dup(int fd)
903 Descriptor *descriptor = get_descriptor(fd);
904 if (descriptor == NULL)
905 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
907 descriptor->Acquire();
908 RETURN_AND_SET_ERRNO(fd);
912 off_t
913 lseek(int fd, off_t offset, int whence)
915 Descriptor* descriptor = get_descriptor(fd);
916 if (descriptor == NULL)
917 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
919 status_t error = descriptor->Seek(offset, whence);
920 if (error != B_OK)
921 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
923 return descriptor->Offset();
928 ftruncate(int fd, off_t newSize)
930 dprintf("ftruncate() not implemented!\n");
931 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
935 ssize_t
936 read_pos(int fd, off_t offset, void *buffer, size_t bufferSize)
938 Descriptor *descriptor = get_descriptor(fd);
939 if (descriptor == NULL)
940 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
942 RETURN_AND_SET_ERRNO(descriptor->ReadAt(offset, buffer, bufferSize));
946 ssize_t
947 pread(int fd, void* buffer, size_t bufferSize, off_t offset)
949 return read_pos(fd, offset, buffer, bufferSize);
953 ssize_t
954 read(int fd, void *buffer, size_t bufferSize)
956 Descriptor *descriptor = get_descriptor(fd);
957 if (descriptor == NULL)
958 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
960 RETURN_AND_SET_ERRNO(descriptor->Read(buffer, bufferSize));
964 ssize_t
965 write_pos(int fd, off_t offset, const void *buffer, size_t bufferSize)
967 Descriptor *descriptor = get_descriptor(fd);
968 if (descriptor == NULL)
969 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
971 RETURN_AND_SET_ERRNO(descriptor->WriteAt(offset, buffer, bufferSize));
975 ssize_t
976 pwrite(int fd, const void* buffer, size_t bufferSize, off_t offset)
978 return write_pos(fd, offset, buffer, bufferSize);
982 ssize_t
983 write(int fd, const void *buffer, size_t bufferSize)
985 Descriptor *descriptor = get_descriptor(fd);
986 if (descriptor == NULL)
987 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
989 RETURN_AND_SET_ERRNO(descriptor->Write(buffer, bufferSize));
993 ssize_t
994 writev(int fd, const struct iovec* vecs, size_t count)
996 size_t totalWritten = 0;
998 for (size_t i = 0; i < count; i++) {
999 ssize_t written = write(fd, vecs[i].iov_base, vecs[i].iov_len);
1000 if (written < 0)
1001 return totalWritten == 0 ? written : totalWritten;
1003 totalWritten += written;
1005 if ((size_t)written != vecs[i].iov_len)
1006 break;
1009 return totalWritten;
1014 open(const char *name, int mode, ...)
1016 mode_t permissions = 0;
1017 if ((mode & O_CREAT) != 0) {
1018 va_list args;
1019 va_start(args, mode);
1020 permissions = va_arg(args, int) /*& ~__gUmask*/;
1021 // adapt the permissions as required by POSIX
1022 va_end(args);
1025 // we always start at the top (there is no notion of a current directory (yet?))
1026 RETURN_AND_SET_ERRNO(open_from(gRoot, name, mode, permissions));
1031 open_from(Directory *directory, const char *name, int mode, mode_t permissions)
1033 if (name[0] == '/') {
1034 // ignore the directory and start from root if we are asked to do that
1035 directory = gRoot;
1036 name++;
1039 char path[B_PATH_NAME_LENGTH];
1040 if (strlcpy(path, name, sizeof(path)) >= sizeof(path))
1041 return B_NAME_TOO_LONG;
1043 Node *node;
1044 status_t error = get_node_for_path(directory, path, &node);
1045 if (error != B_OK) {
1046 if (error != B_ENTRY_NOT_FOUND)
1047 return error;
1049 if ((mode & O_CREAT) == 0)
1050 return B_ENTRY_NOT_FOUND;
1052 // try to resolve the parent directory
1053 strlcpy(path, name, sizeof(path));
1054 if (char* lastSlash = strrchr(path, '/')) {
1055 if (lastSlash[1] == '\0')
1056 return B_ENTRY_NOT_FOUND;
1058 *lastSlash = '\0';
1059 name = lastSlash + 1;
1061 // resolve the directory
1062 if (get_node_for_path(directory, path, &node) != B_OK)
1063 return B_ENTRY_NOT_FOUND;
1065 if (node->Type() != S_IFDIR) {
1066 node->Release();
1067 return B_NOT_A_DIRECTORY;
1070 directory = static_cast<Directory*>(node);
1071 } else
1072 directory->Acquire();
1074 // create the file
1075 error = directory->CreateFile(name, permissions, &node);
1076 directory->Release();
1078 if (error != B_OK)
1079 return error;
1080 } else if ((mode & O_EXCL) != 0) {
1081 node->Release();
1082 return B_FILE_EXISTS;
1085 int fd = open_node(node, mode);
1087 node->Release();
1088 return fd;
1092 /** Since we don't have directory functions yet, this
1093 * function is needed to get the contents of a directory.
1094 * It should be removed once readdir() & co. are in place.
1097 Node *
1098 get_node_from(int fd)
1100 Descriptor *descriptor = get_descriptor(fd);
1101 if (descriptor == NULL)
1102 return NULL;
1104 return descriptor->GetNode();
1108 status_t
1109 get_stat(Directory* directory, const char* path, struct stat& st)
1111 Node* node;
1112 status_t error = get_node_for_path(directory, path, &node);
1113 if (error != B_OK)
1114 return error;
1116 node->Stat(st);
1117 node->Release();
1118 return B_OK;
1122 Directory*
1123 directory_from(DIR* dir)
1125 return dir != NULL ? dir->directory : NULL;
1130 close(int fd)
1132 Descriptor *descriptor = get_descriptor(fd);
1133 if (descriptor == NULL)
1134 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
1136 status_t status = descriptor->Release();
1137 if (!descriptor->RefCount())
1138 free_descriptor(fd);
1140 RETURN_AND_SET_ERRNO(status);
1144 // ToDo: remove this kludge when possible
1146 #if defined(fstat) && !defined(main)
1147 _fstat(int fd, struct stat *stat, size_t /*statSize*/)
1148 #else
1149 fstat(int fd, struct stat *stat)
1150 #endif
1152 if (stat == NULL)
1153 RETURN_AND_SET_ERRNO(B_BAD_VALUE);
1155 Descriptor *descriptor = get_descriptor(fd);
1156 if (descriptor == NULL)
1157 RETURN_AND_SET_ERRNO(B_FILE_ERROR);
1159 descriptor->Stat(*stat);
1160 return 0;
1164 DIR*
1165 open_directory(Directory* baseDirectory, const char* path)
1167 DIR* dir = new(std::nothrow) DIR;
1168 if (dir == NULL) {
1169 errno = B_NO_MEMORY;
1170 return NULL;
1172 ObjectDeleter<DIR> dirDeleter(dir);
1174 Node* node;
1175 status_t error = get_node_for_path(baseDirectory, path, &node);
1176 if (error != B_OK) {
1177 errno = error;
1178 return NULL;
1180 MethodDeleter<Node, status_t> nodeReleaser(node, &Node::Release);
1182 if (!S_ISDIR(node->Type())) {
1183 errno = error;
1184 return NULL;
1187 dir->directory = static_cast<Directory*>(node);
1189 error = dir->directory->Open(&dir->cookie, O_RDONLY);
1190 if (error != B_OK) {
1191 errno = error;
1192 return NULL;
1195 nodeReleaser.Detach();
1196 return dirDeleter.Detach();
1200 DIR*
1201 opendir(const char* dirName)
1203 return open_directory(gRoot, dirName);
1208 closedir(DIR* dir)
1210 if (dir != NULL) {
1211 dir->directory->Close(dir->cookie);
1212 dir->directory->Release();
1213 delete dir;
1216 return 0;
1220 struct dirent*
1221 readdir(DIR* dir)
1223 if (dir == NULL) {
1224 errno = B_BAD_VALUE;
1225 return NULL;
1228 for (;;) {
1229 status_t error = dir->directory->GetNextEntry(dir->cookie,
1230 dir->entry.d_name, B_FILE_NAME_LENGTH);
1231 if (error != B_OK) {
1232 errno = error;
1233 return NULL;
1236 dir->entry.d_pdev = 0;
1237 // not supported
1238 dir->entry.d_pino = dir->directory->Inode();
1239 dir->entry.d_dev = dir->entry.d_pdev;
1240 // not supported
1242 if (strcmp(dir->entry.d_name, ".") == 0
1243 || strcmp(dir->entry.d_name, "..") == 0) {
1244 // Note: That's obviously not correct for "..", but we can't
1245 // retrieve that information.
1246 dir->entry.d_ino = dir->entry.d_pino;
1247 } else {
1248 Node* node = dir->directory->Lookup(dir->entry.d_name, false);
1249 if (node == NULL)
1250 continue;
1252 dir->entry.d_ino = node->Inode();
1253 node->Release();
1256 return &dir->entry;
1261 void
1262 rewinddir(DIR* dir)
1264 if (dir == NULL) {
1265 errno = B_BAD_VALUE;
1266 return;
1269 status_t error = dir->directory->Rewind(dir->cookie);
1270 if (error != B_OK)
1271 errno = error;