// POSIX compatibility support for posix dir. #include #include #include #include #include "posix_internal.h" #include "posix_fd.h" #include "posix_path.h" typedef SYS_DIR_ENTRY KDIR_ENTRY; #define KATTR_DIR 0x10 // Publishes the process-local native CWD into the authoritative posixsrv process record. static KSTATUS PosixPublishCurrentDirectory(const char* nativeDirectory) { if (!nativeDirectory) return NTLSTATUS_INVALID_PARAMETER; size_t length = strlen(nativeDirectory); if (length == 0 || length > SYS_PATH_MAX) return NTLSTATUS_INVALID_PARAMETER; NTL_POSIX_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.Version = NTL_POSIX_PROTOCOL_VERSION; request.Operation = NTL_POSIX_OP_SET_CURRENT_DIRECTORY; request.Flags = NTL_POSIX_REQUEST_FLAG_NONE; request.PathLength = (uint32_t)length; memcpy(request.Path, nativeDirectory, length + 1u); NTL_POSIX_REPLY reply; KSTATUS status = PosixRuntimeCallServer(&request, &reply); if (!KSUCCESS(status)) return status; return reply.Status; } // Implements chdir while keeping the local path resolver and posixsrv authority synchronized. __declspec(dllexport) int chdir(const char* path) { if (!path) { errno = EINVAL; return -1; } char oldNative[SYS_PATH_MAX + 1u]; size_t oldRequired = 0; KSTATUS status = NtlGetCurrentDirectory(oldNative, sizeof(oldNative), &oldRequired); if (!KSUCCESS(status)) { errno = PosixStatusToErrno(status); return -1; } char native[SYS_PATH_MAX + 1u]; const char* translated = PosixTranslatePath(path, native, sizeof(native)); if (translated != native || native[0] == '\0') { errno = EINVAL; return -1; } status = NtlSetCurrentDirectory(SysSvFromCstr(native)); if (!KSUCCESS(status)) { errno = PosixStatusToErrno(status); return -1; } char canonical[SYS_PATH_MAX + 1u]; size_t required = 0; status = NtlGetCurrentDirectory(canonical, sizeof(canonical), &required); if (KSUCCESS(status)) status = PosixPublishCurrentDirectory(canonical); if (!KSUCCESS(status)) { (void)NtlSetCurrentDirectory(SysSvFromCstr(oldNative)); errno = PosixStatusToErrno(status); return -1; } return 0; } // Implements getcwd from the server-owned POSIX process attribute. __declspec(dllexport) char* getcwd(char* buf, size_t size) { if (!buf || size == 0) { errno = EINVAL; return (char*)0; } NTL_POSIX_REPLY reply; KSTATUS status = PosixRuntimeGetProcessAttributes(&reply); if (!KSUCCESS(status)) { errno = PosixStatusToErrno(status); return (char*)0; } if (reply.CurrentDirectoryLength == 0 || reply.CurrentDirectoryLength > SYS_PATH_MAX || reply.CurrentDirectory[reply.CurrentDirectoryLength] != '\0') { errno = EIO; return (char*)0; } char posix[SYS_PATH_MAX + 1u]; NativeToPosix(reply.CurrentDirectory, posix, sizeof(posix)); size_t needed = strlen(posix) + 1u; 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; uint32_t status = NtlRealPath(SysSvFromCstr(translated), (char*)0, 0, &required); if (status != NTLSTATUS_SUCCESS) { errno = PosixStatusToErrno(status); return (char*)0; } if (required == 0 || required > SYS_PATH_MAX + 1u) { errno = ERANGE; return (char*)0; } char nativeResolved[SYS_PATH_MAX + 1u]; status = NtlRealPath(SysSvFromCstr(translated), nativeResolved, sizeof(nativeResolved), &required); if (status != NTLSTATUS_SUCCESS) { errno = PosixStatusToErrno(status); return (char*)0; } char posix[SYS_PATH_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; uint32_t s = NtlOpenDir(SysSvFromCstr(native), SYS_DIR_ACCESS_ENUMERATE | SYS_DIR_ACCESS_OPEN, SYS_DIR_FLAG_NONE, &kh); 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; uint32_t s = NtlStatPath(SysSvFromCstr(p), &nativeStat); 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; } POSIX_OPEN_DESCRIPTION* description = PosixFdAcquire(fd); if (!description) return -1; int result = -1; switch (description->Type) { case PosixFdConsoleRead: case PosixFdConsoleWrite: case PosixFdDevNull: case PosixFdDevZero: result = PosixFillSyntheticStat(S_IFCHR, out); break; case PosixFdSocket: result = PosixFillSyntheticStat(S_IFSOCK, out); break; case PosixFdPipeRead: case PosixFdPipeWrite: result = PosixFillSyntheticStat(S_IFIFO, out); break; case PosixFdFile: { SYS_FILE_STAT nativeStat; uint32_t status = SysGetFileStat(description->KHandle, &nativeStat); if (status != NTLSTATUS_SUCCESS) errno = PosixStatusToErrno(status); else result = PosixFillStat(&nativeStat, out); break; } default: errno = EBADF; break; } PosixFdRelease(description); return result; }