// POSIX compatibility support for posix dir. #include #include #include #include "posix.h" #include "posix_fd.h" #include "posix_path.h" typedef SYS_DIR_ENTRY KDIR_ENTRY; #define KATTR_DIR 0x10 // Implements the chdir operation. __declspec(dllexport) int chdir(const char* path) { char native[512]; PosixTranslatePath(path, native, sizeof(native)); SYS_PATH_REQUEST req = { SysSvFromCstr(native) }; uint32_t s = SysSetCwd(&req); if (s != 0) { errno = ENOENT; return -1; } return 0; } // Implements the getcwd operation. __declspec(dllexport) char* getcwd(char* buf, size_t size) { if (!buf || size == 0) { errno = EINVAL; return (char*)0; } SYS_STRING_VIEW cwd = SysGetCurrentDirectoryView(); if ((cwd.Length && !cwd.Data) || cwd.Length > SYS_CWD_MAX) { errno = ERANGE; return (char*)0; } char native[SYS_CWD_MAX + 1]; if (cwd.Length) memcpy(native, cwd.Data, cwd.Length); native[cwd.Length] = '\0'; char posix[SYS_CWD_MAX + 1]; NativeToPosix(native, posix, sizeof(posix)); size_t needed = strlen(posix) + 1; if (needed > size) { errno = ERANGE; return (char*)0; } memcpy(buf, posix, needed); return buf; } // Copies one path string into either caller storage or a new allocation. static char* PosixCopyResolvedPath(const char* value, char* resolvedPath) { if (!value) { errno = EINVAL; return (char*)0; } size_t needed = strlen(value) + 1; char* out = resolvedPath; if (!out) { out = (char*)malloc(needed); if (!out) { errno = ENOMEM; return (char*)0; } } memcpy(out, value, needed); return out; } // Implements the realpath operation over the kernel lexical resolver. __declspec(dllexport) char* realpath(const char* path, char* resolved_path) { if (!path) { errno = EINVAL; return (char*)0; } char native[SYS_PATH_MAX + 1]; const char* translated = PosixTranslatePath(path, native, sizeof(native)); if (strcmp(translated, SYNTH_DEVNULL) == 0 || strcmp(translated, SYNTH_DEVZERO) == 0) return PosixCopyResolvedPath(path, resolved_path); size_t required = 0; SYS_REAL_PATH_REQUEST query = { sizeof(query), SYS_REAL_PATH_FLAG_NONE, SysSvFromCstr(translated), (char*)0, 0, &required, }; uint32_t status = SysRealPath(&query); if (status != STATUS_SUCCESS) { errno = PosixStatusToErrno(status); return (char*)0; } if (required == 0 || required > SYS_CWD_MAX) { errno = ERANGE; return (char*)0; } char nativeResolved[SYS_CWD_MAX]; SYS_REAL_PATH_REQUEST request = { sizeof(request), SYS_REAL_PATH_FLAG_NONE, SysSvFromCstr(translated), nativeResolved, sizeof(nativeResolved), &required, }; status = SysRealPath(&request); if (status != STATUS_SUCCESS) { errno = PosixStatusToErrno(status); return (char*)0; } char posix[SYS_CWD_MAX]; NativeToPosix(nativeResolved, posix, sizeof(posix)); return PosixCopyResolvedPath(posix, resolved_path); } // Implements the opendir operation. __declspec(dllexport) DIR* opendir(const char* path) { char native[512]; PosixTranslatePath(path, native, sizeof(native)); uint32_t kh; SYS_PATH_HANDLE_REQUEST req = { SysSvFromCstr(native), &kh }; uint32_t s = SysOpenDir(&req); if (s != 0) { errno = ENOENT; return (DIR*)0; } // Allocate DIR on the kernel heap (malloc) so it outlives the stack. DIR* d = (DIR*)malloc(sizeof(DIR)); if (!d) { SysCloseHandle(kh); errno = ENOMEM; return (DIR*)0; } d->KHandle = kh; d->Valid = false; return d; } // Implements the readdir operation. __declspec(dllexport) struct dirent* readdir(DIR* d) { if (!d) { errno = EBADF; return (struct dirent*)0; } KDIR_ENTRY ke; uint32_t s = SysReadDir(d->KHandle, &ke); if (s != 0) return (struct dirent*)0; // end of directory or error size_t len = strlen(ke.Name); if (len > NAME_MAX) len = NAME_MAX; memcpy(d->Current.d_name, ke.Name, len); d->Current.d_name[len] = '\0'; d->Current.d_type = (ke.Attr & KATTR_DIR) ? DT_DIR : DT_REG; d->Valid = true; return &d->Current; } // Implements the closedir operation. __declspec(dllexport) int closedir(DIR* d) { if (!d) { errno = EBADF; return -1; } SysCloseHandle(d->KHandle); free(d); return 0; } // Converts native file metadata to a POSIX stat structure. static int PosixFillStat(const SYS_FILE_STAT* native, struct stat* out) { if (!native || !out) { errno = EINVAL; return -1; } if (native->FileSize > 0x7FFFFFFFULL) { errno = EINVAL; return -1; } memset(out, 0, sizeof(*out)); out->st_dev = native->VolumeId; out->st_ino = native->FileId; out->st_nlink = native->LinkCount ? native->LinkCount : 1; out->st_size = (off_t)native->FileSize; out->st_atime = (int64_t)native->LastAccessTime.EpochSeconds; out->st_mtime = (int64_t)native->LastWriteTime.EpochSeconds; out->st_ctime = (int64_t)native->ChangeTime.EpochSeconds; if (native->Type == SYS_FILE_TYPE_DIRECTORY) { out->st_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; } else { out->st_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; } if (native->Attributes & SYS_FILE_ATTR_READ_ONLY) out->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); return 0; } // Fills stat for one synthetic descriptor. static int PosixFillSyntheticStat(mode_t type, struct stat* out) { if (!out) { errno = EINVAL; return -1; } memset(out, 0, sizeof(*out)); out->st_mode = type | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; out->st_nlink = 1; return 0; } // Implements the stat operation. __declspec(dllexport) int stat(const char* path, struct stat* out) { if (!path || !out) { errno = EINVAL; return -1; } char native[512]; const char* p = PosixTranslatePath(path, native, sizeof(native)); if (strcmp(p, SYNTH_DEVNULL) == 0 || strcmp(p, SYNTH_DEVZERO) == 0) return PosixFillSyntheticStat(S_IFCHR, out); SYS_FILE_STAT nativeStat; SYS_STAT_FILE_REQUEST req = { SysSvFromCstr(p), &nativeStat }; uint32_t s = SysStatFile(&req); if (s != 0) { errno = PosixStatusToErrno(s); return -1; } return PosixFillStat(&nativeStat, out); } // Implements the fstat operation. __declspec(dllexport) int fstat(int fd, struct stat* out) { if (!out) { errno = EINVAL; return -1; } uint32_t pid = SysGetCurrentPid(); FD_ENTRY* e = FdGet(pid, fd); if (!e) return -1; switch (e->Type) { case FD_CONSOLE_R: case FD_CONSOLE_W: case FD_DEVNULL: case FD_DEVZERO: return PosixFillSyntheticStat(S_IFCHR, out); case FD_SOCKET: return PosixFillSyntheticStat(S_IFSOCK, out); case FD_FILE: { SYS_FILE_STAT nativeStat; uint32_t s = SysGetFileStat(e->KHandle, &nativeStat); if (s != 0) { errno = PosixStatusToErrno(s); return -1; } return PosixFillStat(&nativeStat, out); } default: errno = EBADF; return -1; } }