ultradefrag/src/wincalls/windows.c

937 lines
22 KiB
C

/*
* UltraDefrag - powerful defragmentation tool for Windows NT.
* Copyright (c) 2011 by Jean-Pierre Andre for the Linux version
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* Extra code for Windows running Posix threads and curses
*
* This is not needed when using Windows native threads and display
*/
#include "compiler.h"
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include "extrawin.h"
/*
* Currently CURSES implies linemode
* threaded + linemode implies POSIX
* So force POSIX if CURSES and not UNTHREADED
*/
#if defined(CURSES) & !defined(UNTHREADED)
#define POSIX 1 /* use POSIX-type synchronizations instead of the native ones */
#else
#undef POSIX
#endif
#if defined(POSIX) & !defined(UNTHREADED)
#include <pthread.h>
#endif
#define UNDEF(name) int name() { undefined(#name); return (0); }
#define WUNDEF(name) int __stdcall name() { undefined(#name); return (0); }
#define RUNDEF(name) { undefined(#name); return (0); }
#define VUNDEF(name) { undefined(#name); }
#define get_out(n) exit(n)
#define pthread_exit(p) pthread_mutex_lock(&mainlock); /* stop there ! */
#define PBUFSZ MAX_PATH /* temporary print buffer size */
#define STACKSZ 131072
/*
* A few defines for some special situations
*
* probably better include ntndk.h
*/
typedef long NTSTATUS;
typedef int EVENT_TYPE;
#define STATUS_SUCCESS 0
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001)
#define NTAPI __stdcall
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
typedef struct _CLIENT_ID
{
HANDLE UniqueProcess;
HANDLE UniqueThread;
} CLIENT_ID, *PCLIENT_ID;
/*
* Declarations which should be shared winhack/linux
*/
struct TRANSLATIONS {
struct TRANSLATIONS *greater;
struct TRANSLATIONS *less;
const char *source;
utf16_t translation[1];
} ;
void safe_dump(FILE*, const char*, const char*, int);
void showstack(const char*);
extern int trace;
#if defined(POSIX) & !defined(UNTHREADED)
struct THREADLIST {
struct THREADLIST *next;
PTHREAD_START_ROUTINE start;
PVOID param;
ULONG_PTR minstack;
ULONG_PTR maxstack;
int state;
int tid;
pthread_t thread;
} ;
#define THREADCREATED 1
#define THREADSTARTED 2
#define THREADTERMINATED 4
#define THREADCLOSED 8
struct EVENTLIST {
struct EVENTLIST *next;
const char *name;
} ;
pthread_mutex_t loglock;
pthread_mutex_t threadlock;
pthread_mutex_t eventlock;
pthread_mutex_t mainlock;
struct THREADLIST *threadlist;
struct EVENTLIST *eventlist;
#endif
static struct TRANSLATIONS *translations = (struct TRANSLATIONS*)NULL;
static void undefined(const char *name)
{
fprintf(stderr,"Undefined function %s()\n",name);
exit(1);
}
void showstack(const char *text)
{
fprintf(stderr,"Stack at %s : 0x%lx\n",text,&text);
}
static void initwincalls(void)
{
static int inited = 0;
#if defined(POSIX) & !defined(UNTHREADED)
if (!inited++) {
threadlist = (struct THREADLIST*)NULL;
eventlist = (struct EVENTLIST*)NULL;
pthread_mutex_init(&loglock,(pthread_mutexattr_t*)NULL);
pthread_mutex_init(&threadlock,(pthread_mutexattr_t*)NULL);
pthread_mutex_init(&eventlock,(pthread_mutexattr_t*)NULL);
/* prevent other threads to exit */
pthread_mutex_init(&mainlock,(pthread_mutexattr_t*)NULL);
pthread_mutex_lock(&mainlock);
}
#endif
}
void safe_dump(FILE *f, const char *text, const char *zone, int cnt)
{
int i,j;
#if defined(POSIX) & !defined(UNTHREADED)
pthread_mutex_lock(&loglock);
#endif
fprintf(stderr,"Dump of %s %d bytes at 0x%lx",text,cnt,(long)zone);
fprintf(stderr," (Windows endian)\n");
#if defined(POSIX) & !defined(UNTHREADED)
pthread_mutex_unlock(&loglock);
#endif
for (i=0; i<cnt; i+=16) {
#if defined(POSIX) & !defined(UNTHREADED)
pthread_mutex_lock(&loglock);
#endif
fprintf(stderr,"%06lx %04x ",((long)&zone[i]) & 0xffffff,i);
for (j=0; (j<16) && ((i+j)<cnt); j++)
fprintf(stderr,(j & 3 ? "%02x" : " %02x"),zone[i+j] & 255);
while (j < 18)
fprintf(stderr,(j++ & 3 ? " " : " "));
for (j=0; (j<16) && ((i+j)<cnt); j++)
fprintf(stderr,"%c",
((zone[i+j] >= ' ') && (zone[i+j] < 0x7f) ? zone[i+j] : '.'));
fprintf(stderr,"\n");
#if defined(POSIX) & !defined(UNTHREADED)
pthread_mutex_unlock(&loglock);
#endif
}
}
/*
* Serialized logging
*/
int safe_fprintf(FILE *f, const char *format, ...)
{
int r;
va_list ap;
va_start(ap,format);
#if defined(POSIX) & !defined(UNTHREADED)
pthread_mutex_lock(&loglock);
r = vfprintf(f,format,ap);
pthread_mutex_unlock(&loglock);
#else
r = vfprintf(f,format,ap);
#endif
va_end(ap);
return (r);
}
void WgxDbgPrintLastError(const char *format, ...)
{
va_list ap;
va_start(ap,format);
#if defined(POSIX) & !defined(UNTHREADED)
pthread_mutex_lock(&loglock);
vfprintf(stderr,format,ap);
fprintf(stderr,"\n");
pthread_mutex_unlock(&loglock);
#else
vfprintf(stderr,format,ap);
fprintf(stderr,"\n");
#endif
va_end(ap);
}
UNDEF(_cputs)
int optopt;
char *optarg;
int optind;
int getopt_long(int argc, char * const *argv, const char *sopt,
const struct option *lopt, int *v)
{
int opt;
const char *ptr;
int sz;
const struct option *pt;
const char *ptr2;
const char *ptxt;
static int xargc = 0;
static int iarg = 0;
if (!xargc) initwincalls(); /* use this opportunity to initialize */
if (!iarg) xargc++;
if (xargc < argc)
{
optarg = argv[xargc];
ptr = &argv[xargc][iarg];
if (!iarg && (ptr[0] == '-') && (ptr[1] == '-') && lopt)
{
pt = lopt;
ptxt = pt->name; // pt->lopt;
while (ptxt
&& strncmp(ptxt,&ptr[2],strlen(ptxt)))
{
pt++;
ptxt = pt->name; // pt->lopt;
}
opt = -1; /* default return */
if (ptxt)
{
sz = strlen(ptxt);
if (pt->has_arg) // pt->args)
{ /* argument expected */
if (ptr[sz + 2] == '=')
{
optarg = &argv[xargc][sz + 3];
}
else
if ((xargc + 1) < argc) /* isolated argument */
{
ptr = argv[xargc + 1];
if (*ptr != '-')
{
xargc++;
optarg = argv[xargc];
}
}
opt = pt->val; // pt->sopt;
}
else
if (!ptr[sz + 2] && !pt->has_arg) // !pt->args)
{ /* no arg and none expected */
opt = pt->val; // pt->sopt;
}
}
iarg = 0;
}
else
if ((iarg || (ptr[0] == '-'))
&& (((ptr[1] >= 'a') && (ptr[1] <= 'z'))
|| ((ptr[1] >= 'A') && (ptr[1] <= 'Z'))
|| ((ptr[1] >= '0') && (ptr[1] <= '9')))
&& sopt)
{
opt = ptr[1];
ptr2 = strchr(sopt,ptr[1]);
if (ptr2 && (ptr2[1] == ':'))
{
iarg = 0;
if (ptr[2]) /* argument appended */
{
optarg = strchr(&ptr[2],ptr[2]); /* this is &ptr[2]; */
}
else
if ((xargc + 1) < argc) /* isolated argument */
{
ptr = argv[xargc + 1];
if (*ptr != '-')
{
xargc++;
optarg = argv[xargc];
}
}
}
else /* no argument expected, another option may follow */
if (ptr[2]) iarg++;
else iarg = 0;
}
else
opt = -1; /* this is not an option */
optind = xargc + 1;
}
else opt = -1;
optopt = 0; /* todo... */
return (opt);
}
/*
* Translate from utf16 for outputing text.
* It is wise to reserve a target size at least three times
* the incnt to avoid overflow when converting to utf8
*/
int ntfs_toutf8(char *out, const utf16_t *in, int incnt)
{
char *t;
const char *cin;
int i, size;
utf16_t halfpair;
halfpair = 0;
t = out;
cin = (char*)in;
size = 0;
for (i = 0; i < incnt; i++) {
unsigned short c = (cin[2*i] & 255) + ((cin[2*i+1] & 255) << 8);
if (halfpair) {
if ((c >= 0xdc00) && (c < 0xe000)) {
*t++ = 0xf0 + (((halfpair + 64) >> 8) & 7);
*t++ = 0x80 + (((halfpair + 64) >> 2) & 63);
*t++ = 0x80 + ((c >> 6) & 15) + ((halfpair & 3) << 4);
*t++ = 0x80 + (c & 63);
halfpair = 0;
} else
goto fail;
} else if (c < 0x80) {
*t++ = c;
} else {
if (c < 0x800) {
*t++ = (0xc0 | ((c >> 6) & 0x3f));
*t++ = 0x80 | (c & 0x3f);
} else if (c < 0xd800) {
*t++ = 0xe0 | (c >> 12);
*t++ = 0x80 | ((c >> 6) & 0x3f);
*t++ = 0x80 | (c & 0x3f);
} else if (c < 0xdc00)
halfpair = c;
else if (c >= 0xe000) {
*t++ = 0xe0 | (c >> 12);
*t++ = 0x80 | ((c >> 6) & 0x3f);
*t++ = 0x80 | (c & 0x3f);
} else goto fail;
}
}
fail :
return (t - out);
}
/*
* Translate to utf16le
*
* The incnt is the number of bytes (may contain a '\0')
* Returns the number of utf16 little endian chars.
*/
int ntfs_toutf16(utf16_t *out, const char *in, int incnt)
{
int i;
int outcnt;
unsigned int c;
char *p;
i = 0;
outcnt = 0;
p = (char*)out;
while (i < incnt)
{
c = in[i++] & 255;
if (c > 127)
{
if (c < 224)
c = ((c & 31) << 6) + (in[i++] & 63);
else
{
c = ((c & 15) << 6) + (in[i++] & 63);
c = (c << 6) + (in[i++] & 63);
}
}
*p++ = c & 255;
*p++ = (c >> 8) & 255;
outcnt++;
}
return (outcnt);
}
const char *printableutf16(const utf16_t *in)
{
static char buf[PBUFSZ*8];
static int n = 0;
int sz;
char *p;
if (in) {
sz = utflen(in);
p = &buf[(++n & 7)*PBUFSZ];
ntfs_toutf8(p,in,sz+1);
} else
p = "(*null*)";
return (p);
}
const char *printableutf(const utf16_t *in)
{
return (printableutf16(in));
}
const char *printablepath(const utf16_t *path, int lth)
{
return (printableutf16(path));
}
BOOLEAN WINAPI IncreaseGoogleAnalyticsCounter(const char *hostname,
const char *path, const char *account)
{
return (TRUE);
}
wchar_t *_wcsupr(wchar_t *p)
RUNDEF(_wcsupr)
int _snwprintf(wchar_t *buf, size_t sz, const wchar_t *format, ...)
{
va_list ap;
int r;
va_start(ap,format);
r = vsnwprintf(buf,sz,format,ap);
va_end(ap);
return (r);
}
UNDEF(_kbhit)
UNDEF(udefrag_toupper)
UNDEF(_inp)
UNDEF(_outpw)
utf16_t ** WINAPI CommandLineToArgvW(const utf16_t *a, const int *b)
RUNDEF(CommandLineToArgvW)
UNDEF(_getch)
WUNDEF(udefrag_fbsize)
UNDEF(_cgets)
UNDEF(_putch)
UNDEF(_outp)
UNDEF(_getche)
int _snprintf(char *buf, size_t sz, const char *format, ...)
{
va_list ap;
int r;
va_start(ap,format);
r = vsnprintf(buf,sz,format,ap);
va_end(ap);
return (r);
}
UNDEF(_inpw)
UNDEF(_ungetch)
int _vsnprintf(char *buf, size_t sz, const char * format, va_list args)
{
int r;
vsnprintf(buf,sz,format,args);
return (r);
}
char *_strupr(char *strg)
{
int i;
/* replaces original */
for (i=0; strg[i]; i++)
if ((strg[i] >= 'a') && (strg[i] <= 'z'))
strg[i] += 'A' - 'a';
return (strg);
}
char *_strlwr(char *strg)
{
int i;
/* replaces original */
for (i=0; strg[i]; i++)
if ((strg[i] >= 'A') && (strg[i] <= 'Z'))
strg[i] += 'a' - 'A';
return (strg);
}
long _wtol(const utf16_t *s)
{
long v;
BOOLEAN neg;
v = 0;
neg = FALSE;
while (*s == ' ') s++;
if (*s == '-') {
neg = TRUE;
s++;
}
while ((*s >= '0') && (*s <= '9'))
v = v*10 + (*s++) - '0';
if (neg) v = -v;
return (v);
}
int _wtoi(const utf16_t *s)
{
return (_wtol(s));
}
#ifdef POSIX
/*
* Processes, threads and synchronization, the Posix way
*/
HANDLE WINAPI GetCurrentThread(void)
{
#ifndef UNTHREADED
HANDLE h;
struct THREADLIST *item;
h = (HANDLE)NULL;
pthread_mutex_lock(&threadlock);
item = threadlist;
while (item
&& (((ULONG_PTR)&h < item->minstack)
|| ((ULONG_PTR)&h > item->maxstack)))
item = item->next;
if (item)
h = (HANDLE)item->thread;
pthread_mutex_unlock(&threadlock);
return (h); /* NULL in main thread */
#else
return ((HANDLE)getpid());
#endif
}
BOOL WINAPI SetThreadPriority(HANDLE h, int p)
{
return (TRUE);
}
#ifndef UNTHREADED
NTSTATUS NTAPI ZwTerminateThread(HANDLE h, NTSTATUS b)
{
#ifndef UNTHREADED
NTSTATUS r;
HANDLE th;
HANDLE curr;
struct THREADLIST *item;
struct THREADLIST *previous;
if (trace > 2)
safe_fprintf(stderr,"ZwTerminateThread 0x%lx pid %d\n",(long)h);
r = STATUS_UNSUCCESSFUL;
previous = (struct THREADLIST*)NULL;
curr = GetCurrentThread();
if (h = (HANDLE)-2)
th = curr;
else
th = h;
if (th) {
pthread_mutex_lock(&threadlock);
item = threadlist;
while (item && ((HANDLE)item->thread != th)) {
previous = item;
item = item->next;
}
if (item && ((HANDLE)item->thread == th)) {
if (trace > 2)
safe_fprintf(stderr,"terminating thread 0x%lx item 0x%lx\n",
(long)h,(long)item);
/* terminated and closed : remove from list */
if (item->state & THREADCLOSED) {
if (previous)
threadlist = previous->next;
else
threadlist = item->next;
free(item);
if (th == curr) {
pthread_mutex_unlock(&threadlock);
pthread_exit((void*)NULL);
get_out(1); /* should not happen */
}
} else
item->state |= THREADTERMINATED;
r = STATUS_SUCCESS;
pthread_mutex_unlock(&threadlock);
} else {
pthread_mutex_unlock(&threadlock);
if (trace > 2)
safe_fprintf(stderr,"** Failed to terminate thread\n");
get_out(1);
}
} else {
safe_fprintf(stderr,"** Cannot terminate main thread\n");
get_out(1);
}
return (r);
#else
return (STATUS_UNSUCCESSFUL);
#endif
}
/*
* Effective start of a thread
*
* Collect starting parameters
*/
void *threadstart(void *arg)
{
struct THREADLIST *item;
static int tid = 0;
item = (struct THREADLIST*)arg;
if (trace > 2)
safe_fprintf(stderr,"Thread starting item 0x%lx start 0x%lx\n",
(long)item,(long)item->start);
pthread_mutex_lock(&threadlock);
item->tid = ++tid;
item->maxstack = (ULONG_PTR)&item; /* assume stack grows down */
item->minstack = item->maxstack - STACKSZ; /* assume stack grows down */
item->state |= THREADSTARTED;
pthread_mutex_unlock(&threadlock);
(*item->start)(item->param);
if (trace > 2)
safe_fprintf(stderr,"thread 0x%lx %d done\n",(long)item->thread,item->tid);
ZwTerminateThread((HANDLE)item->thread,STATUS_SUCCESS);
get_out(1); /* should not happen */
return ((void*)NULL);
}
#endif
NTSTATUS NTAPI RtlCreateUserThread(HANDLE parent, PSECURITY_DESCRIPTOR psec,
SIZE_T susp, SIZE_T zero,
SIZE_T reserv, SIZE_T comm,
PTHREAD_START_ROUTINE start, PVOID param,
PHANDLE ph, PCLIENT_ID pcid)
{
#ifndef UNTHREADED
NTSTATUS r;
pthread_t thread;
struct THREADLIST *newitem;
typedef void *(*start_routine)(void*);
r = STATUS_UNSUCCESSFUL;
newitem = (struct THREADLIST*)malloc(sizeof(struct THREADLIST));
if (newitem) {
newitem->state = THREADCREATED;
newitem->start = start;
newitem->param = param;
newitem->tid = 0;
newitem->maxstack = 0;
newitem->thread = (pthread_t)NULL;
pthread_mutex_lock(&threadlock);
newitem->next = threadlist;
threadlist = newitem;
pthread_mutex_unlock(&threadlock);
/* start through an auxiliary routine */
if (!pthread_create(&thread,(pthread_attr_t*)NULL,
(start_routine)threadstart,newitem)) {
if (trace > 2)
safe_fprintf(stderr,"Thread created, handle 0x%lx item 0x%lx\n",
(long)thread,(long)newitem);
newitem->thread = thread;
*ph = (PHANDLE)thread;
if (pcid) {
pcid->UniqueProcess = (HANDLE)NULL;
pcid->UniqueThread = (HANDLE)thread;
}
r = STATUS_SUCCESS;
}
}
return (r);
#else
return (STATUS_UNSUCCESSFUL);
#endif
}
HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES psec, DWORD size,
LPTHREAD_START_ROUTINE start,
LPVOID param, DWORD flags, LPDWORD pid)
{
#ifndef UNTHREADED
HANDLE h;
NTSTATUS r;
CLIENT_ID,cid;
r = RtlCreateUserThread((HANDLE)NULL, (PSECURITY_DESCRIPTOR)NULL,
0, 0, size, size, start, param, &h, &cid);
if (pid && (r == STATUS_SUCCESS))
*pid = (DWORD)(ULONG_PTR)cid.UniqueThread;
return (r == STATUS_SUCCESS ? h : (HANDLE)NULL);
#else
return ((HANDLE)NULL);
#endif
}
HANDLE WINAPI CreateEvent(LPSECURITY_ATTRIBUTES pattr, BOOL reset,
BOOL initial, LPCTSTR name)
{
#ifndef UNTHREADED
HANDLE h;
struct EVENTLIST *event;
struct EVENTLIST *newevent;
h = (HANDLE)NULL;
newevent = (struct EVENTLIST*)malloc(sizeof(struct EVENTLIST));
if (newevent && !pattr && !reset && initial && name) {
pthread_mutex_lock(&eventlock);
event = eventlist;
while (event && strcmp(event->name,name))
event = event->next;
if (event) {
h = (HANDLE)event;
errno = ERROR_ALREADY_EXISTS;
free(newevent);
} else {
h = (HANDLE)newevent;
newevent->name = name;
newevent->next = eventlist;
eventlist = newevent;
}
pthread_mutex_unlock(&eventlock);
}
return ((HANDLE)h);
#else
return ((HANDLE)NULL);
#endif
}
NTSTATUS NTAPI NtCreateEvent(PHANDLE ph, ACCESS_MASK b, const OBJECT_ATTRIBUTES *c, SIZE_T d, SIZE_T e)
{
initwincalls();
if (trace > 2)
safe_fprintf(stderr,"** Skipping NtCreateEvent\n");
*ph = (void*)NULL;
return (STATUS_SUCCESS);
}
NTSTATUS NTAPI NtClose(HANDLE h)
{
NTSTATUS r;
typedef NTSTATUS NTAPI (*tNtClose)(HANDLE);
tNtClose pNtClose = (tNtClose)NULL;
HANDLE ntdll;
#ifndef UNTHREADED
struct THREADLIST *item;
struct THREADLIST *previous;
struct EVENTLIST *event;
struct EVENTLIST *previousevent;
#endif
if (trace > 2)
safe_fprintf(stderr,"NtClose h 0x%lx\n",(long)h);
r = STATUS_UNSUCCESSFUL;
if (!pNtClose) {
ntdll = LoadLibrary("ntdll.dll");
pNtClose = (tNtClose)GetProcAddress(ntdll,"NtClose");
}
#ifndef UNTHREADED
pthread_mutex_lock(&threadlock);
item = threadlist;
previous = (struct THREADLIST*)NULL;
while (item && ((HANDLE)item->thread != h)) {
previous = item;
item = item->next;
}
if (item && ((HANDLE)item->thread == h)) {
/* terminated and closed : remove from list */
if (item->state & THREADTERMINATED) {
if (previous)
threadlist = previous->next;
else
threadlist = item->next;
free(item);
}else
item->state |= THREADCLOSED;
r = STATUS_SUCCESS;
pthread_mutex_unlock(&threadlock);
} else {
pthread_mutex_unlock(&threadlock);
pthread_mutex_lock(&eventlock);
event = eventlist;
previousevent = (struct EVENTLIST*)NULL;
while (event && (event != (HANDLE)h)) {
previousevent = event;
event = event->next;
}
if (event == (HANDLE)h) {
if (previousevent)
previousevent->next = event->next;
else
eventlist = event->next;
free(event);
r = STATUS_SUCCESS;
pthread_mutex_unlock(&eventlock);
} else {
pthread_mutex_unlock(&eventlock);
if (pNtClose)
r = (*pNtClose)(h);
}
}
#else
if (pNtClose)
r = (*pNtClose)(h);
#endif
if (trace > 2)
safe_fprintf(stderr,"NtClose 0x%lx : 0x%lx\n",(long)h,(long)r);
return (r);
}
BOOL WINAPI CloseHandle(HANDLE h)
{
NTSTATUS r;
if (trace > 2)
safe_fprintf(stderr,"CloseHandle 0x%lx\n",(long)h);
r = NtClose(h);
return (r == STATUS_SUCCESS);
}
#else /* POSIX */
/*
* We have a problem with NtCreateEvent in native mode
*/
NTSTATUS NTAPI NtCreateEvent(PHANDLE EventHandle, ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
EVENT_TYPE EventType, BOOLEAN InitialState)
{
if (trace > 2)
safe_fprintf(stderr,"** Skipping NtCreateEvent\n");
*EventHandle = (void*)NULL;
return (STATUS_SUCCESS);
}
#endif
long long _atoi64(const char *s)
{
long long r;
r = atoi64(s);
return (r);
}
NTSTATUS NTAPI NtDeleteFile(const POBJECT_ATTRIBUTES ObjectAttributes)
{
int r;
int cnt;
PWSTR p;
r = 0;
cnt = ObjectAttributes->ObjectName->Length;
p = (PWSTR)malloc((cnt + 1)*sizeof(*p));
if (p) {
memcpy(p,ObjectAttributes->ObjectName->Buffer,cnt*sizeof(*p));
p[cnt] = 0;
r = DeleteFileW(p);
if (trace > 2) {
fprintf(stderr,"deleting %s : r 0x%lx\n",
printableutf(p),(long)r);
}
free(p);
}
return (r ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
}
DWORD WINAPI FormatMessageA(DWORD flg, LPCVOID src, DWORD idmess,
DWORD idlang, LPSTR buf, DWORD sz, va_list *args)
{
return (-1); /* return an error */
}