Files
nt-lite/code/user/personalities/posix/posix_dir.c
T

224 lines
7.1 KiB
C

// POSIX compatibility support for posix dir.
#include <string.h>
#include <ntlite/syscall.h>
#include <stdlib.h>
#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;
}
}