Files
nt-lite/code/drivers/fs/ntfs/ntfs3g/ntfs3g_port.c
T
maksw 73abd6f90d isolate POSIX builds from the host UCRT, wire lwext4 and ntfs-3g as ext4.sys and ntfs.sys, split the FAT driver into directory/file/async/driver/mount units, add posixsrv and dwm plus input/console/desktop syscall clients and a pile of new smoke targets, rename serial.sys to cereal.sys, name HDA/USB/lwIP/AHCI workers, harden ATA probing/reset/removal around actual hardware deadlines, absent-channel detection, diagnostics and explicit worker lifetime, redo ACPI S5 shutdown around GAS/MMIO and HW-reduced firmware, scan SSDTs for _S5 and deal with Intel SMI sleep trapping, make serial and SMP timeouts use real monotonic deadlines, add thread names and fix terminal thread teardown, scheduler and APC prepare/commit races, make advisory file locks queryable and preserve split ranges and add mutable file append state, add shared-memory pipes with kernel-assisted wait/wake, introduce capability-scoped input and display managers, split surface map rights into read/write, add explicit unmap and replace present with commit/generation/damage tracking while keeping physical presentation under the display manager, decouple native exception classes from Win32 exception numbers and translate them in kernel32, add opaque process startup data, bump the resource protocol to v3 with namespace directories, symlinks and enumeration and service control to v2 with generic READY handle exports, add the new POSIX errno/status surface and rebuild fds around posixsrv-owned shared open descriptions, descriptor-local flags, exact inheritance snapshots, dup/fcntl/record locks and shared-ring pipes, add waitpid, POSIX credentials/groups/sessions/passwd/group lookups and move sockets onto stable open descriptions, port the shells and apps to the new console/input services and surface commit API, teach init to load services.ini and start/supervise RSSRV, DWM and generic services under restricted capabilities while publishing their endpoints through RSSRV, split RSSRV into namespace, volume, display, session, input, console and resource components and make /SystemRoot a real symlink to the independently published system volume, shift the syscall table again, expand lock/resource/surface/POSIX/service/thread smoke coverage, make docs scream ASK QUESTIONS and DISCUSS at LLMs, replace MIT No Attribution with WTFPL+.
2026-09-16 10:33:20 +02:00

307 lines
9.7 KiB
C

/* Small CRT/POSIX compatibility surface used by libntfs-3g on NTLite. */
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <locale.h>
#include <ntlite/ddk/memory.h>
#include <ntlite/ddk/time.h>
#include <ntlite/ddk/debug.h>
static int gNtfs3gErrno;
int _fltused; /* MSVC floating-point helper anchor required by printf.obj */
int* __cdecl _errno(void) { return &gNtfs3gErrno; }
static FILE gNtfs3gStderr;
static FILE gNtfs3gStdout;
static FILE gNtfs3gStdin;
FILE* stderr = &gNtfs3gStderr;
FILE* stdout = &gNtfs3gStdout;
FILE* stdin = &gNtfs3gStdin;
void* malloc(size_t size) {
if (!size) size = 1;
return MmAllocatePool(size);
}
void* calloc(size_t count, size_t size) {
if (count && size > SIZE_MAX / count) {
errno = ENOMEM;
return NULL;
}
size_t total = count * size;
if (!total) total = 1;
void* p = MmAllocatePool(total);
if (!p) {
errno = ENOMEM;
return NULL;
}
memset(p, 0, total);
return p;
}
void* realloc(void* ptr, size_t size) {
if (!ptr) return malloc(size);
if (!size) {
MmFreePool(ptr);
return NULL;
}
void* p = MmReallocatePool(ptr, size);
if (!p) errno = ENOMEM;
return p;
}
void free(void* ptr) {
if (ptr) MmFreePool(ptr);
}
char* strdup(const char* text) {
if (!text) return NULL;
size_t n = strlen(text) + 1;
char* p = (char*)malloc(n);
if (p) memcpy(p, text, n);
return p;
}
char* strndup(const char* text, size_t limit) {
if (!text) return NULL;
size_t n = 0;
while (n < limit && text[n]) ++n;
char* p = (char*)malloc(n + 1);
if (!p) return NULL;
memcpy(p, text, n);
p[n] = '\0';
return p;
}
void qsort(void* base, size_t count, size_t size,
int (*compare)(const void*, const void*)) {
if (!base || !compare || size == 0 || count < 2) return;
unsigned char* bytes = (unsigned char*)base;
for (size_t i = 1; i < count; ++i) {
size_t j = i;
while (j) {
unsigned char* a = bytes + (j - 1) * size;
unsigned char* b = bytes + j * size;
if (compare(a, b) <= 0) break;
for (size_t k = 0; k < size; ++k) {
unsigned char t = a[k]; a[k] = b[k]; b[k] = t;
}
--j;
}
}
}
void* bsearch(const void* key, const void* base, size_t count, size_t size,
int (*compare)(const void*, const void*)) {
if (!key || !base || !compare || !size) return NULL;
size_t lo = 0, hi = count;
const unsigned char* bytes = (const unsigned char*)base;
while (lo < hi) {
size_t mid = lo + (hi - lo) / 2;
const void* item = bytes + mid * size;
int c = compare(key, item);
if (c == 0) return (void*)item;
if (c < 0) hi = mid; else lo = mid + 1;
}
return NULL;
}
int abs(int value) { return value < 0 ? -value : value; }
long labs(long value) { return value < 0 ? -value : value; }
long long llabs(long long value) { return value < 0 ? -value : value; }
static int Ntfs3gDigit(int c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'z') return c - 'a' + 10;
if (c >= 'A' && c <= 'Z') return c - 'A' + 10;
return -1;
}
static unsigned long long Ntfs3gParseUnsigned(const char* text, char** end, int base, bool* negative) {
const char* p = text;
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') ++p;
*negative = false;
if (*p == '+' || *p == '-') { *negative = (*p == '-'); ++p; }
if (base == 0) {
if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { base = 16; p += 2; }
else if (p[0] == '0') base = 8;
else base = 10;
} else if (base == 16 && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
p += 2;
}
unsigned long long value = 0;
const char* first = p;
for (;;) {
int d = Ntfs3gDigit((unsigned char)*p);
if (d < 0 || d >= base) break;
value = value * (unsigned)base + (unsigned)d;
++p;
}
if (end) *end = (char*)(p == first ? text : p);
return value;
}
long strtol(const char* text, char** end, int base) {
bool neg; unsigned long long v = Ntfs3gParseUnsigned(text, end, base, &neg);
return neg ? -(long)v : (long)v;
}
unsigned long strtoul(const char* text, char** end, int base) {
bool neg; unsigned long long v = Ntfs3gParseUnsigned(text, end, base, &neg);
return neg ? (unsigned long)(0 - (unsigned long)v) : (unsigned long)v;
}
long long strtoll(const char* text, char** end, int base) {
bool neg; unsigned long long v = Ntfs3gParseUnsigned(text, end, base, &neg);
return neg ? -(long long)v : (long long)v;
}
unsigned long long strtoull(const char* text, char** end, int base) {
bool neg; unsigned long long v = Ntfs3gParseUnsigned(text, end, base, &neg);
return neg ? 0ull - v : v;
}
char* strerror(int error) {
switch (error) {
case 0: return "success";
case EPERM: return "operation not permitted";
case ENOENT: return "no such file or directory";
case EIO: return "I/O error";
case ENOMEM: return "out of memory";
case EACCES: return "permission denied";
case EBUSY: return "device or resource busy";
case EEXIST: return "file exists";
case ENODEV: return "no such device";
case ENOTDIR: return "not a directory";
case EISDIR: return "is a directory";
case EINVAL: return "invalid argument";
case ENOSPC: return "no space left on device";
case EROFS: return "read-only filesystem";
case ENOTEMPTY: return "directory not empty";
case EOVERFLOW: return "value too large";
case ENOTSUP: return "operation not supported";
default: return "ntfs-3g error";
}
}
char* getenv(const char* name) { (void)name; return NULL; }
char* __cdecl setlocale(int category, const char* locale) { (void)category; (void)locale; return "C"; }
uid_t getuid(void) { return 0; }
uid_t geteuid(void) { return 0; }
gid_t getgid(void) { return 0; }
gid_t getegid(void) { return 0; }
int fsync(int fd) { (void)fd; return 0; }
int strcasecmp(const char* a, const char* b) {
while (*a && *b) {
unsigned char ca = (unsigned char)*a++, cb = (unsigned char)*b++;
if (ca >= 'A' && ca <= 'Z') ca += 'a' - 'A';
if (cb >= 'A' && cb <= 'Z') cb += 'a' - 'A';
if (ca != cb) return (int)ca - (int)cb;
}
return (unsigned char)*a - (unsigned char)*b;
}
int strncasecmp(const char* a, const char* b, size_t count) {
while (count--) {
unsigned char ca = (unsigned char)*a++, cb = (unsigned char)*b++;
if (ca >= 'A' && ca <= 'Z') ca += 'a' - 'A';
if (cb >= 'A' && cb <= 'Z') cb += 'a' - 'A';
if (ca != cb || !ca || !cb) return (int)ca - (int)cb;
}
return 0;
}
time_t __cdecl time(time_t* out) {
time_t now = (time_t)KeQueryUnixTimeSeconds();
if (out) *out = now;
return now;
}
static int Ntfs3gLogV(const char* format, va_list args) {
char buffer[512];
int n = vsnprintf(buffer, sizeof(buffer), format, args);
buffer[sizeof(buffer) - 1] = '\0';
DbgPrint("ntfs3g: %s", buffer);
return n;
}
int vfprintf(FILE* stream, const char* format, va_list args) {
(void)stream;
return Ntfs3gLogV(format, args);
}
int fprintf(FILE* stream, const char* format, ...) {
va_list args;
va_start(args, format);
int n = vfprintf(stream, format, args);
va_end(args);
return n;
}
int fflush(FILE* stream) { (void)stream; return 0; }
int fputs(const char* text, FILE* stream) {
(void)stream;
if (!text) return -1;
DbgPrint("ntfs3g: %s", text);
return (int)strlen(text);
}
int puts(const char* text) {
int n = fputs(text, stdout);
DbgPrint("\n");
return n;
}
void abort(void) {
DbgPrint("ntfs3g: abort()\n");
for (;;) { }
}
/* Minimal process/account/syslog compatibility used by libntfs-3g internals.
* The kernel driver never intentionally executes the daemon/process paths. */
struct passwd;
struct group;
struct passwd* getpwnam(const char* name) { (void)name; return (struct passwd*)0; }
struct passwd* getpwuid(uid_t uid) { (void)uid; return (struct passwd*)0; }
struct group* getgrnam(const char* name) { (void)name; return (struct group*)0; }
struct group* getgrgid(gid_t gid) { (void)gid; return (struct group*)0; }
int fork(void) { errno = ENOSYS; return -1; }
void _exit(int status) { (void)status; abort(); }
pid_t setsid(void) { errno = ENOSYS; return (pid_t)-1; }
int chdir(const char* path) { (void)path; errno = ENOSYS; return -1; }
int open(const char* path, int flags, ...) { (void)path; (void)flags; errno = ENOSYS; return -1; }
int dup2(int oldfd, int newfd) { (void)oldfd; (void)newfd; errno = ENOSYS; return -1; }
int close(int fd) { (void)fd; errno = ENOSYS; return -1; }
void openlog(const char* ident, int option, int facility) { (void)ident; (void)option; (void)facility; }
void closelog(void) {}
void vsyslog(int priority, const char* format, va_list args) {
(void)priority;
char buffer[512];
vsnprintf(buffer, sizeof(buffer), format, args);
DbgPrint("ntfs3g: %s", buffer);
}
void syslog(int priority, const char* format, ...) {
va_list args;
va_start(args, format);
vsyslog(priority, format, args);
va_end(args);
}
static unsigned long ntfs3g_rand_state = 1;
void srandom(unsigned int seed) { ntfs3g_rand_state = seed ? seed : 1; }
long random(void) { ntfs3g_rand_state = ntfs3g_rand_state * 1103515245u + 12345u; return (long)((ntfs3g_rand_state >> 1) & 0x7fffffff); }
pid_t getpid(void) { return 1; }
ssize_t read(int fd, void* buffer, size_t count) { (void)fd; (void)buffer; (void)count; errno = ENOSYS; return -1; }
int atoi(const char* text) { return (int)strtol(text, (char**)0, 10); }