224 lines
7.1 KiB
C
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 != NTLSTATUS_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 != NTLSTATUS_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;
|
|
}
|
|
}
|