307 lines
9.7 KiB
C
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); }
|