diff --git a/headers/private/kernel/boot/vfs.h b/headers/private/kernel/boot/vfs.h index cf6411945a..3b8e076225 100644 --- a/headers/private/kernel/boot/vfs.h +++ b/headers/private/kernel/boot/vfs.h @@ -6,6 +6,8 @@ #define KERNEL_BOOT_VFS_H +#include + #include #include @@ -146,6 +148,7 @@ extern status_t mount_file_systems(stage2_args *args); extern int open_node(Node *node, int mode); extern int open_from(Directory *directory, const char *path, int mode, mode_t permissions = 0); +extern DIR* open_directory(Directory* baseDirectory, const char* path); extern Node *get_node_from(int fd); diff --git a/src/system/boot/loader/vfs.cpp b/src/system/boot/loader/vfs.cpp index bb7d5e037d..46ca5d6ab6 100644 --- a/src/system/boot/loader/vfs.cpp +++ b/src/system/boot/loader/vfs.cpp @@ -1,5 +1,6 @@ /* * Copyright 2003-2013, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2014, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -36,6 +37,14 @@ using namespace boot; #endif +struct __DIR { + Directory* directory; + void* cookie; + dirent entry; + char nameBuffer[B_FILE_NAME_LENGTH - 1]; +}; + + class Descriptor { public: Descriptor(Node *node, void *cookie); @@ -734,6 +743,19 @@ get_node_for_path(Directory *directory, char *path, Node **_node) } +/*! Version of get_node_for_path() not modifying \a path. + */ +static status_t +get_node_for_path(Directory* directory, const char* path, Node** _node) +{ + char* mutablePath = strdup(path); + if (mutablePath == NULL) + return B_NO_MEMORY; + MemoryDeleter mutablePathDeleter(mutablePath); + + return get_node_for_path(directory, mutablePath, _node); +} + // #pragma mark - @@ -1009,3 +1031,114 @@ fstat(int fd, struct stat *stat) RETURN_AND_SET_ERRNO(descriptor->Stat(*stat)); } + + +DIR* +open_directory(Directory* baseDirectory, const char* path) +{ + DIR* dir = new(std::nothrow) DIR; + if (dir == NULL) { + errno = B_NO_MEMORY; + return NULL; + } + ObjectDeleter dirDeleter(dir); + + Node* node; + status_t error = get_node_for_path(baseDirectory, path, &node); + if (error != B_OK) { + errno = error; + return NULL; + } + MethodDeleter nodeReleaser(node, &Node::Release); + + if (!S_ISDIR(node->Type())) { + errno = error; + return NULL; + } + + dir->directory = static_cast(node); + + error = dir->directory->Open(&dir->cookie, O_RDONLY); + if (error != B_OK) { + errno = error; + return NULL; + } + + nodeReleaser.Detach(); + return dirDeleter.Detach(); +} + + +DIR* +opendir(const char* dirName) +{ + return open_directory(gRoot, dirName); +} + + +int +closedir(DIR* dir) +{ + if (dir != NULL) { + dir->directory->Close(dir->cookie); + dir->directory->Release(); + delete dir; + } + + return 0; +} + + +struct dirent* +readdir(DIR* dir) +{ + if (dir == NULL) { + errno = B_BAD_VALUE; + return NULL; + } + + for (;;) { + status_t error = dir->directory->GetNextEntry(dir->cookie, + dir->entry.d_name, B_FILE_NAME_LENGTH); + if (error != B_OK) { + errno = error; + return NULL; + } + + dir->entry.d_pdev = 0; + // not supported + dir->entry.d_pino = dir->directory->Inode(); + dir->entry.d_dev = dir->entry.d_pdev; + // not supported + + if (strcmp(dir->entry.d_name, ".") == 0 + || strcmp(dir->entry.d_name, "..") == 0) { + // Note: That's obviously not correct for "..", but we can't + // retrieve that information. + dir->entry.d_ino = dir->entry.d_pino; + } else { + Node* node = dir->directory->Lookup(dir->entry.d_name, false); + if (node == NULL) + continue; + + dir->entry.d_ino = node->Inode(); + node->Release(); + } + + return &dir->entry; + } +} + + +void +rewinddir(DIR* dir) +{ + if (dir == NULL) { + errno = B_BAD_VALUE; + return; + } + + status_t error = dir->directory->Rewind(dir->cookie); + if (error != B_OK) + errno = error; +}