1 /* 2 * Copyright 2024 Google LLC 3 * SPDX-License-Identifier: MIT 4 */ 5 6 #include <lib/zxio/zxio.h> 7 #include <services/service_connector.h> 8 #include <string.h> 9 10 #include "os_dirent.h" 11 #include "util/log.h" 12 13 struct os_dir { ~os_diros_dir14 ~os_dir() { 15 if (dir_iterator_init_) { 16 zxio_dirent_iterator_destroy(&iterator_); 17 } 18 if (zxio_init_) { 19 zxio_close(&io_storage_.io, /*should_wait=*/true); 20 } 21 } 22 23 // Always consumes |dir_channel| Initos_dir24 bool Init(zx_handle_t dir_channel) { 25 zx_status_t status = zxio_create(dir_channel, &io_storage_); 26 if (status != ZX_OK) { 27 mesa_loge("zxio_create failed: %d", status); 28 return false; 29 } 30 31 zxio_init_ = true; 32 33 status = zxio_dirent_iterator_init(&iterator_, &io_storage_.io); 34 if (status != ZX_OK) { 35 mesa_loge("zxio_dirent_iterator_init failed: %d", status); 36 return false; 37 } 38 39 dir_iterator_init_ = true; 40 return true; 41 } 42 Nextos_dir43 bool Next(struct os_dirent* entry) { 44 // dirent is an in-out parameter. 45 // name must be initialized to point to a buffer of at least ZXIO_MAX_FILENAME bytes. 46 static_assert(sizeof(entry->d_name) >= ZXIO_MAX_FILENAME); 47 zxio_dirent_t dirent = {.name = entry->d_name}; 48 49 zx_status_t status = zxio_dirent_iterator_next(&iterator_, &dirent); 50 if (status != ZX_OK) { 51 if (status != ZX_ERR_NOT_FOUND) 52 mesa_loge("zxio_dirent_iterator_next failed: %d", status); 53 return false; 54 } 55 56 entry->d_ino = dirent.has.id ? dirent.id : OS_INO_UNKNOWN; 57 entry->d_name[dirent.name_length] = '\0'; 58 59 return true; 60 } 61 62 private: 63 bool zxio_init_ = false; 64 bool dir_iterator_init_ = false; 65 zxio_storage_t io_storage_; 66 zxio_dirent_iterator_t iterator_; 67 }; 68 os_opendir(const char * path)69os_dir_t* os_opendir(const char* path) { 70 zx_handle_t dir_channel = GetConnectToServiceFunction()(path); 71 if (dir_channel == ZX_HANDLE_INVALID) { 72 mesa_loge("fuchsia_open(%s) failed", path); 73 return nullptr; 74 } 75 76 auto dir = new os_dir(); 77 78 if (!dir->Init(dir_channel)) { 79 delete dir; 80 return nullptr; 81 } 82 83 return dir; 84 } 85 os_closedir(os_dir_t * dir)86int os_closedir(os_dir_t* dir) { 87 delete dir; 88 return 0; 89 } 90 os_readdir(os_dir_t * dir)91struct os_dirent* os_readdir(os_dir_t* dir) { 92 static struct os_dirent dirent = {}; 93 return reinterpret_cast<os_dirent*>(dir->Next(&dirent)) ? &dirent : nullptr; 94 } 95