blob: 8fdcf7d4edefa9150d74518a60cb823295c95cf6 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "os_dirent.h"
#include "list.h"
#include "os/fuchsia.h"
#include <lib/zxio/inception.h>
#include <lib/zxio/zxio.h>
#include <magma_util/dlog.h>
// Offsets must match struct os_dirent, static_asserts below.
struct os_dirent_impl {
ino_t d_ino;
char d_name[NAME_MAX];
};
static_assert(offsetof(struct os_dirent_impl, d_ino) == offsetof(struct os_dirent, d_ino),
"d_ino offset mismatch");
static_assert(offsetof(struct os_dirent_impl, d_name) == offsetof(struct os_dirent, d_name),
"d_ino offset mismatch");
class os_dir {
public:
os_dir() { buffer = new char[buffer_size()]; }
~os_dir()
{
if (dir_init) {
zxio_close(&io_storage.io);
}
delete[] buffer;
}
static size_t buffer_size() { return ZXIO_DIRENT_ITERATOR_DEFAULT_BUFFER_SIZE; }
// Always consumes |dir_channel|
bool Init(zx_handle_t dir_channel)
{
zx_status_t status = zxio_dir_init(&io_storage, dir_channel);
if (status != ZX_OK) {
DLOG("zxio_dir_init failed: %d", status);
return false;
}
dir_init = true;
status = zxio_dirent_iterator_init(&iterator, &io_storage.io, buffer, buffer_size());
if (status != ZX_OK) {
DLOG("zxio_dirent_iterator_init failed: %d", status);
return false;
}
return true;
}
struct os_dirent_impl* Next()
{
zxio_dirent_t* dirent;
zx_status_t status = zxio_dirent_iterator_next(&iterator, &dirent);
if (status != ZX_OK) {
DLOG("zxio_dirent_iterator_next failed: %d", status);
return nullptr;
}
entry.d_ino = dirent->inode;
strncpy(entry.d_name, dirent->name, dirent->size);
entry.d_name[dirent->size] = 0;
return &entry;
}
private:
bool dir_init = false;
zxio_storage_t io_storage;
zxio_dirent_iterator_t iterator;
struct os_dirent_impl entry;
char* buffer = nullptr;
};
os_dir_t* os_opendir(const char* path)
{
zx_handle_t dir_channel;
if (!fuchsia_open(path, &dir_channel)) {
DLOG("fuchsia_open(%s) failed\n", path);
return nullptr;
}
auto dir = new os_dir();
if (!dir->Init(dir_channel)) {
delete dir;
return nullptr;
}
return dir;
}
int os_closedir(os_dir_t* dir)
{
// Assume param is valid.
delete dir;
return 0;
}
struct os_dirent* os_readdir(os_dir_t* dir) { return reinterpret_cast<os_dirent*>(dir->Next()); }