boot loader: Implement subset of <dirent.h> API
* Add opendir(), closedir(), readdir(), rewinddir(). * Add open_directory(), similar to opendir(), but basing the path off a specified directory.
This commit is contained in:
parent
09c07e4c5c
commit
2f019bd6ca
@ -6,6 +6,8 @@
|
||||
#define KERNEL_BOOT_VFS_H
|
||||
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include <util/DoublyLinkedList.h>
|
||||
@ -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);
|
||||
|
||||
|
@ -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<DIR> dirDeleter(dir);
|
||||
|
||||
Node* node;
|
||||
status_t error = get_node_for_path(baseDirectory, path, &node);
|
||||
if (error != B_OK) {
|
||||
errno = error;
|
||||
return NULL;
|
||||
}
|
||||
MethodDeleter<Node, status_t> nodeReleaser(node, &Node::Release);
|
||||
|
||||
if (!S_ISDIR(node->Type())) {
|
||||
errno = error;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dir->directory = static_cast<Directory*>(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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user