readdir(dir_fd:i32, entry_ptr) -> i32 Returns: 0 = entry written, 1 = end of directory, -errno = error.
| 294 | // readdir(dir_fd:i32, entry_ptr) -> i32 |
| 295 | // Returns: 0 = entry written, 1 = end of directory, -errno = error. |
| 296 | static std::vector<Value> fs_readdir(Stack& stack) { |
| 297 | Frame& frame = stack.frames.top(); |
| 298 | i32_t dir_fd = std::get<i32_t>(frame.locals[0]); |
| 299 | i64_t entry_ptr = get_ptr(frame.locals[1]); |
| 300 | FdEntry* e = fd_table.get(dir_fd); |
| 301 | if(!e || !e->is_dir || !e->dir) return {Value(i32_t(-EBADF))}; |
| 302 | DirIter& di = *e->dir; |
| 303 | if(di.it == di.end) return {Value(i32_t(1))}; |
| 304 | |
| 305 | try { |
| 306 | const fs::directory_entry& entry = *di.it; |
| 307 | uint8_t buf[WASM_DIRENT_SIZE] = {}; |
| 308 | // std::filesystem doesn't expose a stable inode number cross-platform; |
| 309 | // hash the path so each entry has a distinct, deterministic id. |
| 310 | uint32_t ino = (uint32_t)fs::hash_value(entry.path()); |
| 311 | uint8_t type = dt_from_entry(entry); |
| 312 | std::string name = entry.path().filename().string(); |
| 313 | std::memcpy(buf + 0, &ino, 4); |
| 314 | std::memcpy(buf + 4, &type, 1); |
| 315 | std::strncpy(reinterpret_cast<char*>(buf + 5), name.c_str(), 254); |
| 316 | buf[5 + 254] = '\0'; |
| 317 | mem_write(stack, entry_ptr, buf, WASM_DIRENT_SIZE); |
| 318 | |
| 319 | std::error_code ec; |
| 320 | di.it.increment(ec); |
| 321 | if(ec) { |
| 322 | errno = ec.value(); |
| 323 | return {Value(err_code())}; |
| 324 | } |
| 325 | return {Value(i32_t(0))}; |
| 326 | } catch(...) { |
| 327 | return {Value(i32_t(-EFAULT))}; |
| 328 | } |
| 329 | } |
| 330 | |
| 331 | // closedir(dir_fd:i32) -> i32 |
| 332 | static std::vector<Value> fs_closedir(Stack& stack) { |