/* Small CRT/POSIX compatibility surface used by libntfs-3g on NTLite. */ #include #include #include #include #include #include #include #include #include #include #include #include #include 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); }