mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1716 lines
43 KiB
1716 lines
43 KiB
/*
|
|
* NTSYS.C - C lang sys routines for slm specific to NT/WIN32
|
|
*
|
|
* Copyright Microsoft Corp (1992)
|
|
*
|
|
* This module contains system interface routines for SLM to using the
|
|
* WIN32 API.
|
|
*
|
|
* The functions which appear in this module are:
|
|
*
|
|
* int mkredir(char *, PTH *);
|
|
* int endredir(char *);
|
|
* int getredir(int, char *, char *);
|
|
* char getswitch(void);
|
|
* int SLM_Unlink(char *);
|
|
* int SLM_Rename(char *, char *);
|
|
* int lockfile(int, int);
|
|
* void geterr(void);
|
|
* int DnGetCur(void);
|
|
* char DtForDn(int);
|
|
* int setro(char *, int);
|
|
* int hide(char *szFile);
|
|
* char *LpbAllocCb(unsigned, F);
|
|
* void FreeLpb(char *);
|
|
* int ucreat(char *, int);
|
|
* int chngtime(char *, char *);
|
|
*
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
EnableAssert
|
|
|
|
BOOL (WINAPI * DebuggerPresent)(VOID) = NULL;
|
|
BOOL (WINAPI * TestForUnicode)(PVOID, ULONG, PULONG) = NULL;
|
|
BOOL WINAPI SlmIsTextUnicode( PVOID Buffer, ULONG Size, PULONG Result );
|
|
BOOL WINAPI SlmIsDebuggerPresent( VOID );
|
|
static void InitIsText(void)
|
|
{
|
|
// Since this it the first NT specific function to be called, initialize
|
|
// the Unicode test ptr.
|
|
|
|
if ((GetVersion() >> 16 & 0x00007fff) < 546)
|
|
TestForUnicode = SlmIsTextUnicode;
|
|
else {
|
|
TestForUnicode = (BOOL (WINAPI *)(PVOID, ULONG, PULONG))
|
|
GetProcAddress(LoadLibrary("ADVAPI32"), "IsTextUnicode");
|
|
|
|
// Make sure we always have something.
|
|
if (TestForUnicode == NULL)
|
|
TestForUnicode = SlmIsTextUnicode;
|
|
}
|
|
|
|
DebuggerPresent = (BOOL (WINAPI *)(VOID))
|
|
GetProcAddress(LoadLibrary("KERNEL32"), "IsDebuggerPresent");
|
|
if (DebuggerPresent == NULL)
|
|
DebuggerPresent = SlmIsDebuggerPresent;
|
|
}
|
|
|
|
#pragma data_seg(".CRT$XCU")
|
|
static void (*pInitIsText)(void) = InitIsText;
|
|
#pragma data_seg()
|
|
|
|
static int TFindex;
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* MKREDIR()
|
|
*
|
|
* Defined in ntsys.c- int mkredir(char *, PTH *);
|
|
*
|
|
* Parms: szDev - (char *) name of redirected DRIVE
|
|
* pthNet - (PTH *) UNC name of base directory of master share
|
|
* password follows name...
|
|
*
|
|
* Establish redirection to the network drive.
|
|
*/
|
|
int
|
|
mkredir(
|
|
char *szDev,
|
|
char *pthNet)
|
|
{
|
|
char *Password;
|
|
int i;
|
|
DWORD rc;
|
|
NETRESOURCE nr;
|
|
|
|
nr.lpRemoteName = _strdup(pthNet); // Connect to this share
|
|
nr.lpLocalName = szDev; // with this drive letter
|
|
nr.lpProvider = NULL; // using whatever provider is appropriate
|
|
nr.dwType = RESOURCETYPE_DISK; // and make sure it's a disk
|
|
|
|
i = 0;
|
|
|
|
for (i=0; nr.lpRemoteName[i]; i++)
|
|
if (nr.lpRemoteName[i] == '/')
|
|
nr.lpRemoteName[i] = '\\';
|
|
|
|
// Password follows immediately after resource name
|
|
Password = pthNet + strlen(pthNet) + 1;
|
|
|
|
if (*Password == '\0')
|
|
Password = NULL; // Use default password if none is specified...
|
|
|
|
rc = WNetAddConnection2( &nr, Password, NULL, 0 );
|
|
|
|
free(nr.lpRemoteName);
|
|
|
|
if (rc == ERROR_DEVICE_ALREADY_REMEMBERED ||
|
|
rc == ERROR_CONNECTION_UNAVAIL)
|
|
rc = ERROR_ALREADY_ASSIGNED;
|
|
|
|
_doserrno = rc;
|
|
|
|
return ((int)rc);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* ENDREDIR()
|
|
*
|
|
* Defined in path.c- int endredir(char *);
|
|
*
|
|
* Parms: szDev - (char *) name of redirected DRIVE
|
|
*
|
|
* End redirection to the network
|
|
*/
|
|
int
|
|
endredir(
|
|
char *szDev)
|
|
{
|
|
DWORD rc;
|
|
|
|
// Disconnect. Make sure it's not stored as persistant and ignore open files, etc.
|
|
|
|
rc = WNetCancelConnection2(szDev, CONNECT_UPDATE_PROFILE, TRUE);
|
|
|
|
_doserrno = rc;
|
|
|
|
return((int)rc);
|
|
}
|
|
|
|
|
|
#if cchMachMax < (MAX_COMPUTER_NAME + 1)
|
|
#error cchMachMax value is too low
|
|
#endif
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* getmach()
|
|
*
|
|
* get the name of the machine on which we are running.
|
|
*/
|
|
int
|
|
getmach(
|
|
char *sz)
|
|
{
|
|
DWORD dwBufSize = cchMachMax;
|
|
|
|
if (GetComputerName(sz, &dwBufSize))
|
|
_doserrno = 0;
|
|
else
|
|
_doserrno = GetLastError();
|
|
|
|
return(_doserrno);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* GETSWITCH()
|
|
* defined in args.c
|
|
* char getswitch(void);
|
|
*/
|
|
char
|
|
getswitch(
|
|
void)
|
|
{
|
|
return ('/');
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Name: setro
|
|
* Purpose: set readonly bit based on fReadOnly
|
|
* Assumes:
|
|
* Returns: 0 for success, or a dos error code for failure
|
|
*/
|
|
int
|
|
setro(
|
|
char *sz,
|
|
int fReadOnly)
|
|
{
|
|
DWORD dwAttr;
|
|
|
|
if ((dwAttr = GetFileAttributes(sz)) == -1)
|
|
_doserrno = GetLastError();
|
|
else
|
|
{
|
|
/* if it's in the correct state, we succeeded */
|
|
if (((dwAttr & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY) ==
|
|
!!fReadOnly)
|
|
_doserrno = 0;
|
|
else
|
|
{
|
|
if (fReadOnly)
|
|
dwAttr |= FILE_ATTRIBUTE_READONLY; /* read only */
|
|
else
|
|
dwAttr &= ~FILE_ATTRIBUTE_READONLY; /* read and write */
|
|
|
|
_doserrno = SetFileAttributes(sz, dwAttr) ? 0 : GetLastError();
|
|
}
|
|
}
|
|
return(_doserrno);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* hide()
|
|
* defined in proto.h
|
|
* extern int hide(char *szFile);
|
|
*
|
|
* Parms: szFile = full path name of file
|
|
*/
|
|
int
|
|
hide(
|
|
char *szFile)
|
|
{
|
|
DWORD dwAttr;
|
|
|
|
if ((dwAttr = GetFileAttributes(szFile)) == -1L)
|
|
_doserrno = GetLastError();
|
|
else
|
|
{
|
|
dwAttr |= FILE_ATTRIBUTE_HIDDEN; /* make file hidden */
|
|
dwAttr &= ~FILE_ATTRIBUTE_DIRECTORY;/* strip off DIR bit
|
|
to avoid access violation */
|
|
if (SetFileAttributes(szFile, dwAttr))
|
|
_doserrno = 0;
|
|
else
|
|
_doserrno = GetLastError();
|
|
}
|
|
|
|
return(_doserrno);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Name: SLM_Unlink
|
|
* Purpose: remove a file, changing attributes if necessary
|
|
* Assumes: if the file was already gone, that's ok
|
|
* Returns: 0 for success, or non-zero for failure
|
|
*/
|
|
int SLM_Unlink(char *sz)
|
|
{
|
|
DWORD dwAttr;
|
|
|
|
if ((dwAttr = GetFileAttributes(sz)) == -1)
|
|
{
|
|
_doserrno = GetLastError();
|
|
_doserrno = ERROR_FILE_NOT_FOUND == _doserrno ? 0 : _doserrno;
|
|
return(_doserrno);
|
|
}
|
|
|
|
if (dwAttr & FILE_ATTRIBUTE_READONLY)
|
|
if (!SetFileAttributes(sz, FILE_ATTRIBUTE_NORMAL))
|
|
{
|
|
_doserrno = GetLastError();
|
|
return(_doserrno);
|
|
}
|
|
|
|
if (dwAttr & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
_doserrno = RemoveDirectory(sz) ? 0 : GetLastError();
|
|
if (_doserrno == ERROR_DIR_NOT_EMPTY) _doserrno = 0;
|
|
}
|
|
else
|
|
_doserrno = DeleteFile(sz) ? 0 : GetLastError();
|
|
|
|
return(_doserrno);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* SLM_rename()
|
|
* defined in proto.h
|
|
* int SLM_rename(char *, char *);
|
|
*
|
|
* Parms: szTo = pointer to new file name
|
|
* szFrom = pointer to old file name
|
|
* returns 0 for success, non-zero for failure
|
|
*/
|
|
int
|
|
SLM_Rename(
|
|
char *szFrom,
|
|
char *szTo)
|
|
{
|
|
if (MoveFile(szFrom, szTo))
|
|
_doserrno = 0;
|
|
else
|
|
_doserrno = GetLastError();
|
|
|
|
return(_doserrno);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* lockfile()
|
|
* defined in proto.h
|
|
* int lockfile(int, int);
|
|
*
|
|
* Parms: fd = file descriptor
|
|
* fUnlock = boolean flag / Unlock file if fTrue
|
|
*
|
|
*
|
|
* The locking flags of 0x7ffffffff represent a very large lock
|
|
* region in the file. For SLM this is the whole file. SLM
|
|
* will lock the whole file or none of it. That is the purpose
|
|
* of this routine.
|
|
*/
|
|
int
|
|
lockfile(
|
|
int fd,
|
|
int fUnlock)
|
|
{
|
|
HANDLE hf = (HANDLE)_get_osfhandle(fd);
|
|
|
|
if ((long)hf == -1)
|
|
{
|
|
_doserrno = 0;
|
|
return (errno);
|
|
}
|
|
|
|
if (fUnlock)
|
|
_doserrno = UnlockFile(hf, 0, 0, 0x7fffffffL, 0) ? 0 : GetLastError();
|
|
else
|
|
_doserrno = LockFile(hf, 0, 0, 0x7fffffffL, 0) ? 0 : GetLastError();
|
|
return (_doserrno);
|
|
}
|
|
|
|
BYTE mpenea[] = {
|
|
/* 0 */ 0,
|
|
/* 1 */ eaCleanUp,
|
|
/* 2 */ eaUserErr,
|
|
/* 3 */ eaUserErr,
|
|
/* 4 */ eaCleanUp,
|
|
/* 5 */ eaUserErr,
|
|
/* 6 */ eaCleanUp,
|
|
/* 7 */ eaAbort,
|
|
/* 8 */ eaCleanUp,
|
|
/* 9 */ eaCleanUp,
|
|
/* 10 */ eaCleanUp,
|
|
/* 11 */ eaCleanUp,
|
|
/* 12 */ eaCleanUp,
|
|
/* 13 */ eaCleanUp,
|
|
/* 14 */ eaCleanUp,
|
|
/* 15 */ eaUserErr,
|
|
/* 16 */ eaUserErr,
|
|
/* 17 */ eaUserErr,
|
|
/* 18 */ eaUserErr,
|
|
/* 19 */ eaURetry,
|
|
/* 20 */ eaAbort,
|
|
/* 21 */ eaURetry,
|
|
/* 22 */ eaAbort,
|
|
/* 23 */ eaCleanUp,
|
|
/* 24 */ eaAbort,
|
|
/* 25 */ eaRetry,
|
|
/* 26 */ eaURetry,
|
|
/* 27 */ eaCleanUp,
|
|
/* 28 */ eaURetry,
|
|
/* 29 */ eaCleanUp,
|
|
/* 30 */ eaCleanUp,
|
|
/* 31 */ eaCleanUp,
|
|
/* 32 */ eaDRetry,
|
|
/* 33 */ eaDRetry,
|
|
/* 34 */ eaURetry,
|
|
/* 35 */ eaCleanUp,
|
|
/* 36 */ eaCleanUp,
|
|
/* 37 */ eaCleanUp,
|
|
/* 38 */ eaCleanUp,
|
|
/* 39 */ eaCleanUp,
|
|
/* 40 */ eaCleanUp,
|
|
/* 41 */ eaCleanUp,
|
|
/* 42 */ eaCleanUp,
|
|
/* 43 */ eaCleanUp,
|
|
/* 44 */ eaCleanUp,
|
|
/* 45 */ eaCleanUp,
|
|
/* 46 */ eaCleanUp,
|
|
/* 47 */ eaCleanUp,
|
|
/* 48 */ eaCleanUp,
|
|
/* 49 */ eaCleanUp,
|
|
/* 50 */ eaUserErr,
|
|
/* 51 */ eaDRetry,
|
|
/* 52 */ eaCleanUp,
|
|
/* 53 */ eaUserErr,
|
|
/* 54 */ eaDRetry,
|
|
/* 55 */ eaCleanUp,
|
|
/* 56 */ eaDRetry,
|
|
/* 57 */ eaCleanUp,
|
|
/* 58 */ eaCleanUp,
|
|
/* 59 */ eaCleanUp,
|
|
/* 60 */ eaCleanUp,
|
|
/* 61 */ eaDRetry,
|
|
/* 62 */ eaDRetry,
|
|
/* 63 */ eaCleanUp,
|
|
/* 64 */ eaCleanUp,
|
|
/* 65 */ eaUserErr,
|
|
/* 66 */ eaUserErr,
|
|
/* 67 */ eaUserErr,
|
|
/* 68 */ eaCleanUp,
|
|
/* 69 */ eaCleanUp,
|
|
/* 70 */ eaDRetry,
|
|
/* 71 */ eaCleanUp,
|
|
/* 72 */ eaRetry,
|
|
/* 73 */ eaCleanUp,
|
|
/* 74 */ eaCleanUp,
|
|
/* 75 */ eaCleanUp,
|
|
/* 76 */ eaCleanUp,
|
|
/* 77 */ eaCleanUp,
|
|
/* 78 */ eaCleanUp,
|
|
/* 79 */ eaCleanUp,
|
|
/* 80 */ eaUserErr,
|
|
/* 81 */ eaCleanUp,
|
|
/* 82 */ eaCleanUp,
|
|
/* 83 */ eaCleanUp,
|
|
/* 84 */ eaCleanUp,
|
|
/* 85 */ eaUserErr,
|
|
/* 86 */ eaUserErr,
|
|
/* 87 */ eaUserErr,
|
|
/* 88 */ eaCleanUp
|
|
};
|
|
|
|
#define enMax (sizeof mpenea / sizeof mpenea[0])
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* geterr()
|
|
* defined in sys.c
|
|
* void geterr(void);
|
|
*/
|
|
void
|
|
geterr(
|
|
void)
|
|
{
|
|
extern int eaCur;
|
|
extern int enCur;
|
|
|
|
if (_doserrno == 0 && errno != 0)
|
|
{
|
|
enCur = errno;
|
|
eaCur = eaNil;
|
|
}
|
|
else
|
|
{
|
|
enCur = _doserrno;
|
|
eaCur = (_doserrno > 0 && _doserrno <= enMax) ? mpenea[_doserrno]
|
|
: eaNil;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* DnGetCur()
|
|
* defined in path.c
|
|
* int DnGetCur(void);
|
|
*/
|
|
int
|
|
DnGetCur(
|
|
void)
|
|
{
|
|
char buf[MAX_PATH];
|
|
DWORD Len;
|
|
|
|
Len = GetCurrentDirectory(MAX_PATH, buf);
|
|
|
|
if (Len > 0 && Len < MAX_PATH)
|
|
return (DnForCh(toupper(buf[0])));
|
|
else
|
|
return (-1);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* DtForDn()
|
|
* defined in path.c
|
|
* char DtForDn(int);
|
|
*
|
|
* Parms: dn = drive number
|
|
*
|
|
* Get current drive number
|
|
*
|
|
* function: find out whether the drive number passed in is a
|
|
* local drive or not
|
|
* returns: 1 (local drive) or 0 (not mapped)
|
|
*/
|
|
char
|
|
DtForDn(
|
|
unsigned int dn)
|
|
{
|
|
char rootDir[4] = "?:\\";
|
|
|
|
rootDir[0] = ChForDn(dn);
|
|
|
|
switch (GetDriveType(rootDir))
|
|
{
|
|
default:
|
|
case 0: /* can't be determined */
|
|
return (dtUnknown);
|
|
case 1: /* does not exist -> no mapping */
|
|
return (dtNil);
|
|
case DRIVE_REMOVABLE:
|
|
case DRIVE_FIXED:
|
|
return (dtLocal);
|
|
case DRIVE_REMOTE:
|
|
return (dtUserNet);
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* LpbAllocCb()
|
|
* defined in util.h
|
|
* char *LpbAllocCb(unsigned, F);
|
|
*
|
|
* Parms: cb = number of bytes to allocate
|
|
* fClear = boolean flag to Clear buffer before returning..
|
|
*/
|
|
char *
|
|
LpbAllocCb(
|
|
unsigned cb,
|
|
int fClear)
|
|
{
|
|
char *pb;
|
|
|
|
if (!cb)
|
|
cb++; /* must allocate at least one byte */
|
|
|
|
if (fClear)
|
|
pb = calloc((size_t)cb, sizeof(char));
|
|
else
|
|
pb = malloc((size_t)cb);
|
|
|
|
return (pb);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* FreeLpb()
|
|
* defined in proto.h
|
|
* void FreeLpb(char *);
|
|
*
|
|
* Parms: pb = pointer to buffer to free
|
|
*/
|
|
void
|
|
FreeLpb(
|
|
char *pb)
|
|
{
|
|
free(pb);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* ucreat()
|
|
* defined in proto.h
|
|
*
|
|
* Creates a file with a unique name
|
|
*
|
|
*
|
|
* Parms: sz = path name of file/dir to open/creat
|
|
* mode = open mode
|
|
*/
|
|
|
|
#define MAXATTEMPTS 1000
|
|
#define MAXFNO 9950
|
|
|
|
int
|
|
ucreat(
|
|
char *sz,
|
|
int mode)
|
|
{
|
|
char szTemp[128];
|
|
USHORT newmode;
|
|
int attempts, errnoCheck;
|
|
HANDLE hf;
|
|
SECURITY_ATTRIBUTES Security;
|
|
|
|
newmode = FILE_ATTRIBUTE_ARCHIVE;
|
|
|
|
if (mode & 0x8000)
|
|
newmode |= FILE_ATTRIBUTE_HIDDEN;
|
|
|
|
attempts = 0;
|
|
|
|
Security.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
Security.lpSecurityDescriptor = NULL;
|
|
Security.bInheritHandle = fTrue;
|
|
|
|
errnoCheck = ERROR_FILE_EXISTS;
|
|
hf = INVALID_HANDLE_VALUE;
|
|
|
|
while (INVALID_HANDLE_VALUE == hf && ERROR_FILE_EXISTS == errnoCheck)
|
|
{
|
|
// failed because no unique name
|
|
if ((sprintf(szTemp, "%sT%04d", sz, TFindex++) < (int)(strlen(sz)+5))
|
|
|| (attempts > MAXATTEMPTS))
|
|
{
|
|
_doserrno = ERROR_FILE_EXISTS;
|
|
return (fdNil);
|
|
}
|
|
|
|
if (TFindex > MAXFNO)
|
|
TFindex = TFindex % MAXFNO;
|
|
|
|
hf = CreateFile(szTemp, GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ, &Security, CREATE_NEW,
|
|
newmode, NULL);
|
|
|
|
errnoCheck = GetLastError();
|
|
}
|
|
|
|
if (INVALID_HANDLE_VALUE == hf)
|
|
{
|
|
_doserrno = errnoCheck;
|
|
Error("SLM Error creating tmp. file %s, Code %d\n", szTemp, _doserrno);
|
|
return (fdNil);
|
|
}
|
|
|
|
_doserrno = 0;
|
|
strcpy(sz, szTemp);
|
|
return (_open_osfhandle((long)hf, 0));
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* chngtime()
|
|
* defined in sys.c
|
|
* int chngtime(char *, char *);
|
|
*
|
|
* Parms: szChng = path name of file to change time for
|
|
* szTime = path name of file with wanted time
|
|
* mode = open mode
|
|
*/
|
|
int
|
|
chngtime(
|
|
char *szChng,
|
|
char *szTime)
|
|
{
|
|
HANDLE fd;
|
|
FILETIME LastWriteTime;
|
|
|
|
_doserrno = 0;
|
|
|
|
// Get date and time of the file with the wanted time
|
|
fd = CreateFile(szTime, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, OPEN_EXISTING, 0, NULL);
|
|
if (INVALID_HANDLE_VALUE == fd
|
|
|| !GetFileTime(fd, NULL, NULL, &LastWriteTime))
|
|
{
|
|
_doserrno = GetLastError();
|
|
CloseHandle(fd);
|
|
return (_doserrno);
|
|
}
|
|
CloseHandle(fd);
|
|
|
|
// Set date and time of the file to change
|
|
fd = CreateFile(szChng, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
|
if (INVALID_HANDLE_VALUE == fd
|
|
|| !SetFileTime(fd, NULL, NULL, &LastWriteTime))
|
|
{
|
|
_doserrno = GetLastError();
|
|
}
|
|
CloseHandle(fd);
|
|
|
|
return (_doserrno);
|
|
}
|
|
|
|
|
|
void
|
|
Append_Date(
|
|
char *dbuf,
|
|
int fd)
|
|
{
|
|
FILETIME LastWriteTime;
|
|
SYSTEMTIME SystemTime;
|
|
HANDLE hf = (HANDLE)_get_osfhandle(fd);
|
|
|
|
if (hf == INVALID_HANDLE_VALUE)
|
|
return;
|
|
|
|
if (!GetFileTime(hf, NULL, NULL, &LastWriteTime))
|
|
return;
|
|
|
|
if (!FileTimeToLocalFileTime(&LastWriteTime, &LastWriteTime))
|
|
return;
|
|
|
|
if (!FileTimeToSystemTime(&LastWriteTime, &SystemTime))
|
|
return;
|
|
|
|
SzPrint(dbuf + strlen(dbuf), " (%u-%u @ %02u:%02u) ",
|
|
SystemTime.wMonth, SystemTime.wDay,
|
|
SystemTime.wHour, SystemTime.wMinute);
|
|
}
|
|
|
|
|
|
DWORD dwPageSize; // Saved for stfile.c (PshCommit)
|
|
|
|
/* retrieves the network path mappings and machine name. For Novell, we also
|
|
get the preferred server.
|
|
*/
|
|
void
|
|
InitPath(
|
|
void)
|
|
{
|
|
DWORD Status;
|
|
DWORD i;
|
|
char *Local;
|
|
char *Remote;
|
|
char szNet[ MAX_PATH ];
|
|
int dn;
|
|
HANDLE enumHandle;
|
|
DWORD numEntries;
|
|
BOOL endOfList;
|
|
NETRESOURCE netResource[8192/sizeof(NETRESOURCE)];
|
|
DWORD bufferSize = sizeof(netResource);
|
|
SYSTEM_INFO SystemInfo;
|
|
|
|
GetSystemInfo(&SystemInfo);
|
|
dwPageSize = SystemInfo.dwPageSize;
|
|
|
|
dnCur = DnGetCur();
|
|
|
|
InitDtMap();
|
|
|
|
//
|
|
// Get name of machine on which we are running; this is simply for
|
|
// identification purposes.
|
|
//
|
|
if (getmach(szCurMach) != 0 || *szCurMach == '\0') {
|
|
|
|
PTH *pth;
|
|
|
|
//
|
|
// Get volume name for current drive and use as machine name
|
|
//
|
|
AssertF(cchPthMax <= 128);
|
|
if ((pth = PthGetDn(dnCur)) == 0) {
|
|
FatalError("drive %c must have a proper volume label\n", ChForDn(dnCur));
|
|
}
|
|
|
|
ExtMach(pth, (PTH *)szNet, szCurMach);
|
|
strcpy(szCurMach, szCurMach+2); /* get rid of drive id */
|
|
}
|
|
|
|
//
|
|
// First enumerate all the CONNECTED network drives.
|
|
//
|
|
|
|
Status = WNetOpenEnum(
|
|
RESOURCE_CONNECTED,
|
|
RESOURCETYPE_DISK,
|
|
RESOURCEUSAGE_CONNECTABLE,
|
|
NULL,
|
|
&enumHandle );
|
|
|
|
if ( Status != NO_ERROR ) {
|
|
FatalError("Cannot enumerate network connections (%d)\n", Status );
|
|
return;
|
|
}
|
|
|
|
endOfList = FALSE;
|
|
|
|
do {
|
|
numEntries = 0xFFFFFFFF;
|
|
Status = WNetEnumResource( enumHandle, &numEntries, netResource, &bufferSize );
|
|
|
|
switch( Status ) {
|
|
|
|
case NO_ERROR:
|
|
break;
|
|
|
|
case ERROR_NO_NETWORK:
|
|
//
|
|
// If the network has not started we'll continue
|
|
// (so users can work in local projects).
|
|
//
|
|
case ERROR_NO_MORE_ITEMS:
|
|
endOfList = TRUE;
|
|
numEntries = 0;
|
|
break;
|
|
|
|
case ERROR_EXTENDED_ERROR:
|
|
{
|
|
CHAR ErrorString [256];
|
|
CHAR Network[256];
|
|
DWORD dwError;
|
|
WNetGetLastError(&dwError, ErrorString, 256, Network, 256);
|
|
FatalError("Cannot enumerate network connections (%d)\n"
|
|
"Net: %s\n"
|
|
"Error: (%d) %s\n",
|
|
Status,
|
|
Network,
|
|
dwError,
|
|
ErrorString );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
FatalError("Cannot enumerate network connections (%d)\n", Status );
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < numEntries; i++) {
|
|
|
|
Local = netResource[i].lpLocalName;
|
|
|
|
if ( Local != NULL) {
|
|
|
|
ConvToSlash( Local );
|
|
|
|
if ( FDriveId( Local, &dn ) ) {
|
|
Remote = netResource[i].lpRemoteName;
|
|
ConvToSlash( Remote );
|
|
|
|
mpdnpth[dn] = _strdup( Remote );
|
|
mpdndt[dn] = dtUserNet;
|
|
}
|
|
}
|
|
}
|
|
|
|
} while ( !endOfList );
|
|
|
|
WNetCloseEnum( enumHandle );
|
|
|
|
//
|
|
// Now enumerate all the persistant drives. For each one, find it in the
|
|
// drive array from the CONNECTED drives enumeration. If not found than
|
|
// unavailable. Otherwise update the drive type to dtPermNet
|
|
//
|
|
Status = WNetOpenEnum(
|
|
RESOURCE_REMEMBERED,
|
|
RESOURCETYPE_DISK,
|
|
RESOURCEUSAGE_CONNECTABLE,
|
|
NULL,
|
|
&enumHandle );
|
|
|
|
if ( Status != NO_ERROR ) {
|
|
FatalError("Cannot enumerate network connections (%d)\n", Status );
|
|
return;
|
|
}
|
|
|
|
endOfList = FALSE;
|
|
|
|
do {
|
|
numEntries = 0xFFFFFFFF;
|
|
Status = WNetEnumResource( enumHandle, &numEntries, netResource, &bufferSize );
|
|
|
|
switch( Status ) {
|
|
|
|
case NO_ERROR:
|
|
break;
|
|
|
|
case ERROR_NO_NETWORK:
|
|
//
|
|
// If the network has not started we'll continue
|
|
// (so users can work in local projects).
|
|
//
|
|
case ERROR_NO_MORE_ITEMS:
|
|
endOfList = TRUE;
|
|
numEntries = 0;
|
|
break;
|
|
|
|
case ERROR_EXTENDED_ERROR:
|
|
{
|
|
CHAR ErrorString [256];
|
|
CHAR Network[256];
|
|
DWORD dwError;
|
|
WNetGetLastError(&dwError, ErrorString, 256, Network, 256);
|
|
FatalError("Cannot enumerate network connections (%d)\n"
|
|
"Net: %s\n"
|
|
"Error: (%d) %s\n",
|
|
Status,
|
|
Network,
|
|
dwError,
|
|
ErrorString );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
FatalError("Cannot enumerate network connections (%d)\n", Status );
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < numEntries; i++) {
|
|
|
|
Local = netResource[i].lpLocalName;
|
|
|
|
if ( Local != NULL) {
|
|
|
|
ConvToSlash( Local );
|
|
|
|
if ( FDriveId( Local, &dn ) ) {
|
|
if (mpdndt[dn] == dtUserNet) {
|
|
mpdndt[dn] = dtPermNet;
|
|
Remote = netResource[i].lpRemoteName;
|
|
ConvToSlash( Remote );
|
|
mpdnpth[dn] = _strdup( Remote );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} while ( !endOfList );
|
|
|
|
WNetCloseEnum( enumHandle );
|
|
|
|
if (PthGetDn(dnCur) == 0) {
|
|
if (FLocalDn(dnCur)) {
|
|
FatalError("drive %c must have a proper volume label\n", ChForDn(dnCur));
|
|
} else {
|
|
FatalError("network drive %c not in redirection list\n", ChForDn(dnCur));
|
|
}
|
|
}
|
|
|
|
//
|
|
// We ALWAYS have mpdnpth[dnCur]
|
|
//
|
|
AssertF(!FEmptyPth(mpdnpth[dnCur]) && *szCurMach != '\0');
|
|
}
|
|
|
|
|
|
/*
|
|
* Under OS/2, we always return entries that are normal, archived or
|
|
* read-only.
|
|
*
|
|
* SRCHATTR contains those attribute bits that are used for matching.
|
|
*/
|
|
|
|
#define SRCHATTR (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)
|
|
|
|
BOOL
|
|
AttributesMatch(
|
|
DE *pde);
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* findfirst()
|
|
* defined in proto.h
|
|
* int findfirst(DE *, char *, int);
|
|
*
|
|
* Parms: szFile = full path name of file
|
|
*/
|
|
int
|
|
findfirst(
|
|
DE *pde,
|
|
char *sz,
|
|
int fa)
|
|
{
|
|
// We remember the desired attributes, for findnext
|
|
pde->faMatch = (FA)fa;
|
|
|
|
if ((pde->hdir = FindFirstFile(sz, &pde->FindData))
|
|
== INVALID_HANDLE_VALUE)
|
|
{
|
|
_doserrno = GetLastError();
|
|
return (-1);
|
|
}
|
|
|
|
if (!strcmp(pde->FindData.cFileName, ".") ||
|
|
!strcmp(pde->FindData.cFileName, "..") ||
|
|
!AttributesMatch(pde))
|
|
{
|
|
// If the attributes are not what we want, or we got one
|
|
// of the magic directories (. or ..) we keep trying...
|
|
return (findnext(pde));
|
|
}
|
|
|
|
FileTimeToLocalFileTime(&pde->FindData.ftCreationTime,
|
|
&pde->FindData.ftCreationTime);
|
|
FileTimeToLocalFileTime(&pde->FindData.ftLastAccessTime,
|
|
&pde->FindData.ftLastAccessTime);
|
|
FileTimeToLocalFileTime(&pde->FindData.ftLastWriteTime,
|
|
&pde->FindData.ftLastWriteTime);
|
|
|
|
return (_doserrno = 0);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* findnext()
|
|
* defined in proto.h
|
|
* int findnext(DE *);
|
|
*
|
|
* Parms: szFile = full path name of file
|
|
*/
|
|
int
|
|
findnext(
|
|
DE *pde)
|
|
{
|
|
while (fTrue)
|
|
{
|
|
// We will keep trying until either we find an entry that
|
|
// matches our atribute criterira, or we run out of entries
|
|
if (!FindNextFile(pde->hdir, (LPWIN32_FIND_DATA)pde))
|
|
{
|
|
// No more entries, return
|
|
_doserrno = GetLastError();
|
|
return (-1);
|
|
}
|
|
else if (strcmp(pde->FindData.cFileName, ".") &&
|
|
strcmp(pde->FindData.cFileName, "..") &&
|
|
AttributesMatch(pde))
|
|
{
|
|
// This is our guy
|
|
FileTimeToLocalFileTime(&pde->FindData.ftCreationTime,
|
|
&pde->FindData.ftCreationTime);
|
|
FileTimeToLocalFileTime(&pde->FindData.ftLastAccessTime,
|
|
&pde->FindData.ftLastAccessTime);
|
|
FileTimeToLocalFileTime(&pde->FindData.ftLastWriteTime,
|
|
&pde->FindData.ftLastWriteTime);
|
|
|
|
return (_doserrno = 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
AttributesMatch(
|
|
DE *pde)
|
|
{
|
|
// Emulate the OS/2-DOS behaviour of attribute matching.
|
|
|
|
pde->FindData.dwFileAttributes &= (0x000000FF & ~(FILE_ATTRIBUTE_NORMAL));
|
|
|
|
return (!((pde->FindData.dwFileAttributes & SRCHATTR) & ~(pde->faMatch)));
|
|
}
|
|
|
|
/* map MF file into memory */
|
|
VOID *
|
|
MapMf(
|
|
MF *pmf,
|
|
int Access)
|
|
{
|
|
#if !defined(PAGE_WRITECOPY)
|
|
/* NOT INCLUDING MEMORY MAPPED FILE I/O! */
|
|
return (NULL);
|
|
#else
|
|
|
|
VOID * MappedBase = NULL;
|
|
HANDLE hFile, hFileMap;
|
|
|
|
AssertF(FIsOpenMf(pmf));
|
|
|
|
if (pmf->fdRead != fdNil)
|
|
hFile = (HANDLE)_get_osfhandle(pmf->fdRead);
|
|
else
|
|
hFile = (HANDLE)_get_osfhandle(pmf->fdWrite);
|
|
|
|
hFileMap = CreateFileMapping(hFile,
|
|
NULL,
|
|
Access == ReadOnly ? PAGE_READONLY : PAGE_WRITECOPY | SEC_COMMIT,
|
|
0,
|
|
0,
|
|
NULL);
|
|
if (hFileMap != NULL)
|
|
MappedBase = MapViewOfFile(hFileMap, Access == ReadOnly ? FILE_MAP_READ : FILE_MAP_COPY, 0, 0, 0);
|
|
|
|
CloseHandle(hFileMap); // If we don't do this, we'll get weird Sharing violations later...
|
|
|
|
return(MappedBase);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
* Write buffer content to the output;
|
|
* if output is a console, use WriteConsoleW API
|
|
*/
|
|
|
|
int WriteLpbCb (int fh, void far *lpb, unsigned int cb)
|
|
{
|
|
BOOL bUnicode;
|
|
DWORD cbWritten;
|
|
HANDLE hdl;
|
|
DWORD dwMode;
|
|
|
|
bUnicode = (*TestForUnicode) (lpb, cb, NULL);
|
|
|
|
hdl = (HANDLE) _get_osfhandle (fh);
|
|
|
|
if (bUnicode && GetConsoleMode(hdl, &dwMode))
|
|
{
|
|
WriteConsoleW (hdl, lpb, cb / sizeof(WCHAR), &cbWritten, NULL);
|
|
cbWritten *= sizeof(WCHAR);
|
|
}
|
|
else
|
|
cbWritten = _write (fh, lpb, cb);
|
|
|
|
return (cbWritten);
|
|
}
|
|
|
|
/**
|
|
|
|
Stolen from \nt\private\ntos\rtl\nls.c. For NT versions > 546, use the
|
|
version in advapi32.
|
|
**/
|
|
|
|
#define UNICODE_FFFF 0xFFFF
|
|
#define REVERSE_BYTE_ORDER_MARK 0xFFFE
|
|
#define BYTE_ORDER_MARK 0xFEFF
|
|
|
|
#define PARAGRAPH_SEPARATOR 0x2029
|
|
#define LINE_SEPARATOR 0x2028
|
|
|
|
#define UNICODE_TAB 0x0009
|
|
#define UNICODE_LF 0x000A
|
|
#define UNICODE_CR 0x000D
|
|
#define UNICODE_SPACE 0x0020
|
|
#define UNICODE_CJK_SPACE 0x3000
|
|
|
|
#define UNICODE_R_TAB 0x0900
|
|
#define UNICODE_R_LF 0x0A00
|
|
#define UNICODE_R_CR 0x0D00
|
|
#define UNICODE_R_SPACE 0x2000
|
|
#define UNICODE_R_CJK_SPACE 0x0030 /* Ambiguous - same as ASCII '0' */
|
|
|
|
#define ASCII_CRLF 0x0A0D
|
|
|
|
#define __max(a,b) (((a) > (b)) ? (a) : (b))
|
|
#define __min(a,b) (((a) < (b)) ? (a) : (b))
|
|
|
|
|
|
BOOL WINAPI SlmIsTextUnicode( PVOID Buffer, ULONG Size, PULONG Result )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
IsTextUnicode performs a series of inexpensive heuristic checks
|
|
on a buffer in order to verify that it contains Unicode data.
|
|
|
|
|
|
[[ need to fix this section, see at the end ]]
|
|
|
|
Found Return Result
|
|
|
|
BOM TRUE BOM
|
|
RBOM FALSE RBOM
|
|
FFFF FALSE Binary
|
|
NULL FALSE Binary
|
|
null TRUE null bytes
|
|
ASCII_CRLF FALSE CRLF
|
|
UNICODE_TAB etc. TRUE Zero Ext Controls
|
|
UNICODE_TAB_R FALSE Reversed Controls
|
|
UNICODE_ZW etc. TRUE Unicode specials
|
|
|
|
1/3 as little variation in hi-byte as in lo byte: TRUE Correl
|
|
3/1 or worse " FALSE AntiCorrel
|
|
|
|
Arguments:
|
|
|
|
Buffer - pointer to buffer containing text to examine.
|
|
|
|
Size - size of buffer in bytes. At most 256 characters in this will
|
|
be examined. If the size is less than the size of a unicode
|
|
character, then this function returns FALSE.
|
|
|
|
Result - optional pointer to a flag word that contains additional information
|
|
about the reason for the return value. If specified, this value on
|
|
input is a mask that is used to limit the factors this routine uses
|
|
to make it decision. On output, this flag word is set to contain
|
|
those flags that were used to make its decision.
|
|
|
|
Return Value:
|
|
|
|
Boolean value that is TRUE if Buffer contains unicode characters.
|
|
|
|
--*/
|
|
{
|
|
WCHAR UNALIGNED *lpBuff = Buffer;
|
|
ULONG iBOM = 0;
|
|
ULONG iCR = 0;
|
|
ULONG iLF = 0;
|
|
ULONG iTAB = 0;
|
|
ULONG iSPACE = 0;
|
|
ULONG iCJK_SPACE = 0;
|
|
ULONG iFFFF = 0;
|
|
ULONG iPS = 0;
|
|
ULONG iLS = 0;
|
|
|
|
ULONG iRBOM = 0;
|
|
ULONG iR_CR = 0;
|
|
ULONG iR_LF = 0;
|
|
ULONG iR_TAB = 0;
|
|
ULONG iR_SPACE = 0;
|
|
|
|
ULONG iNull = 0;
|
|
ULONG iUNULL = 0;
|
|
ULONG iCRLF = 0;
|
|
ULONG iTmp;
|
|
ULONG LastLo = 0;
|
|
ULONG LastHi = 0;
|
|
ULONG iHi, iLo;
|
|
ULONG HiDiff = 0;
|
|
ULONG LoDiff = 0;
|
|
|
|
ULONG iResult = 0;
|
|
|
|
if (Size < 2 ) {
|
|
if (Result != NULL)
|
|
*Result = IS_TEXT_UNICODE_ASCII16 | IS_TEXT_UNICODE_CONTROLS;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Check at most 256 wide character, collect various statistics
|
|
for (iTmp = 0; iTmp < __min( 256, Size / sizeof( WCHAR ) ); iTmp++) {
|
|
switch (lpBuff[iTmp]) {
|
|
case BYTE_ORDER_MARK:
|
|
iBOM++;
|
|
break;
|
|
case PARAGRAPH_SEPARATOR:
|
|
iPS++;
|
|
break;
|
|
case LINE_SEPARATOR:
|
|
iLS++;
|
|
break;
|
|
case UNICODE_LF:
|
|
iLF++;
|
|
break;
|
|
case UNICODE_TAB:
|
|
iTAB++;
|
|
break;
|
|
case UNICODE_SPACE:
|
|
iSPACE++;
|
|
break;
|
|
case UNICODE_CJK_SPACE:
|
|
iCJK_SPACE++;
|
|
break;
|
|
case UNICODE_CR:
|
|
iCR++;
|
|
break;
|
|
|
|
// The following codes are expected to show up in
|
|
// byte reversed files
|
|
case REVERSE_BYTE_ORDER_MARK:
|
|
iRBOM++;
|
|
break;
|
|
case UNICODE_R_LF:
|
|
iR_LF++;
|
|
break;
|
|
case UNICODE_R_TAB:
|
|
iR_TAB++;
|
|
break;
|
|
case UNICODE_R_CR:
|
|
iR_CR++;
|
|
break;
|
|
case UNICODE_R_SPACE:
|
|
iR_SPACE++;
|
|
break;
|
|
|
|
// The following codes are illegal and should never occur
|
|
case UNICODE_FFFF:
|
|
iFFFF++;
|
|
break;
|
|
case UNICODE_NULL:
|
|
iUNULL++;
|
|
break;
|
|
|
|
// The following is not currently a Unicode character
|
|
// but is expected to show up accidentally when reading
|
|
// in ASCII files which use CRLF on a little endian machine
|
|
case ASCII_CRLF:
|
|
iCRLF++;
|
|
break; /* little endian */
|
|
}
|
|
|
|
// Collect statistics on the fluctuations of high bytes
|
|
// versus low bytes
|
|
|
|
iHi = HIBYTE (lpBuff[iTmp]);
|
|
iLo = LOBYTE (lpBuff[iTmp]);
|
|
|
|
iNull += (iHi ? 0 : 1) + (iLo ? 0 : 1); /* count Null bytes */
|
|
|
|
HiDiff += __max( iHi, LastHi ) - __min( LastHi, iHi );
|
|
LoDiff += __max( iLo, LastLo ) - __min( LastLo, iLo );
|
|
|
|
LastLo = iLo;
|
|
LastHi = iHi;
|
|
}
|
|
|
|
// sift the statistical evidence
|
|
if (LoDiff < 127 && HiDiff == 0) {
|
|
iResult |= IS_TEXT_UNICODE_ASCII16; /* likely 16-bit ASCII */
|
|
}
|
|
|
|
if (HiDiff && LoDiff == 0) {
|
|
iResult |= IS_TEXT_UNICODE_REVERSE_ASCII16; /* reverse order 16-bit ASCII */
|
|
}
|
|
|
|
if (3 * HiDiff < LoDiff) {
|
|
iResult |= IS_TEXT_UNICODE_STATISTICS;
|
|
}
|
|
|
|
if (3 * LoDiff < HiDiff) {
|
|
iResult |= IS_TEXT_UNICODE_REVERSE_STATISTICS;
|
|
}
|
|
|
|
//
|
|
// Any control codes widened to 16 bits? Any Unicode character
|
|
// which contain one byte in the control code range?
|
|
//
|
|
|
|
if (iCR + iLF + iTAB + iSPACE + iCJK_SPACE /*+iPS+iLS*/) {
|
|
iResult |= IS_TEXT_UNICODE_CONTROLS;
|
|
}
|
|
|
|
if (iR_LF + iR_CR + iR_TAB + iR_SPACE) {
|
|
iResult |= IS_TEXT_UNICODE_REVERSE_CONTROLS;
|
|
}
|
|
|
|
//
|
|
// Any characters that are illegal for Unicode?
|
|
//
|
|
|
|
if (iRBOM+iFFFF + iUNULL + iCRLF) {
|
|
iResult |= IS_TEXT_UNICODE_ILLEGAL_CHARS;
|
|
}
|
|
|
|
//
|
|
// Odd buffer length cannot be Unicode
|
|
//
|
|
|
|
if (Size & 1) {
|
|
iResult |= IS_TEXT_UNICODE_ODD_LENGTH;
|
|
}
|
|
|
|
//
|
|
// Any NULL bytes? (Illegal in ANSI)
|
|
//
|
|
if (iNull) {
|
|
iResult |= IS_TEXT_UNICODE_NULL_BYTES;
|
|
}
|
|
|
|
//
|
|
// POSITIVE evidence, BOM or RBOM used as signature
|
|
//
|
|
|
|
if (*lpBuff == BYTE_ORDER_MARK) {
|
|
iResult |= IS_TEXT_UNICODE_SIGNATURE;
|
|
}
|
|
else
|
|
if (*lpBuff == REVERSE_BYTE_ORDER_MARK) {
|
|
iResult |= IS_TEXT_UNICODE_REVERSE_SIGNATURE;
|
|
}
|
|
|
|
//
|
|
// limit to desired categories if requested.
|
|
//
|
|
|
|
if (Result != NULL) {
|
|
iResult &= *Result;
|
|
*Result = iResult;
|
|
}
|
|
|
|
//
|
|
// There are four separate conclusions:
|
|
//
|
|
// 1: The file APPEARS to be Unicode AU
|
|
// 2: The file CANNOT be Unicode CU
|
|
// 3: The file CANNOT be ANSI CA
|
|
//
|
|
//
|
|
// This gives the following possible results
|
|
//
|
|
// CU
|
|
// + -
|
|
//
|
|
// AU AU
|
|
// + - + -
|
|
// -------- --------
|
|
// CA +| 0 0 2 3
|
|
// |
|
|
// -| 1 1 4 5
|
|
//
|
|
//
|
|
// Note that there are only 6 really different cases, not 8.
|
|
//
|
|
// 0 - This must be a binary file
|
|
// 1 - ANSI file
|
|
// 2 - Unicode file (High probability)
|
|
// 3 - Unicode file (more than 50% chance)
|
|
// 5 - No evidence for Unicode (ANSI is default)
|
|
//
|
|
// The whole thing is more complicated if we allow the assumption
|
|
// of reverse polarity input. At this point we have a simplistic
|
|
// model: some of the reverse Unicode evidence is very strong,
|
|
// we ignore most weak evidence except statistics. If this kind of
|
|
// strong evidence is found together with Unicode evidence, it means
|
|
// its likely NOT Text at all. Furthermore if a REVERSE_BYTE_ORDER_MARK
|
|
// is found, it precludes normal Unicode. If both byte order marks are
|
|
// found it's not Unicode.
|
|
//
|
|
|
|
//
|
|
// Unicode signature : uncontested signature outweighs reverse evidence
|
|
//
|
|
|
|
if ((iResult & IS_TEXT_UNICODE_SIGNATURE) &&
|
|
!(iResult & IS_TEXT_UNICODE_NOT_UNICODE_MASK)
|
|
) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// If we have conflicting evidence, its not Unicode
|
|
//
|
|
|
|
if (iResult & IS_TEXT_UNICODE_REVERSE_MASK) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Statistical and other results (cases 2 and 3)
|
|
//
|
|
|
|
if (!(iResult & IS_TEXT_UNICODE_NOT_UNICODE_MASK) &&
|
|
((iResult & IS_TEXT_UNICODE_NOT_ASCII_MASK) ||
|
|
(iResult & IS_TEXT_UNICODE_UNICODE_MASK)
|
|
)
|
|
) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
BOOL WINAPI SlmIsDebuggerPresent( VOID )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
F
|
|
OpenMappedFile(
|
|
PTH *pth,
|
|
BOOL fWriteAccess,
|
|
unsigned cbInitial,
|
|
PHANDLE hf,
|
|
void **pBase
|
|
)
|
|
{
|
|
F fOk;
|
|
char sz[cchPthMax];
|
|
HANDLE hm;
|
|
DWORD dwAttributes;
|
|
|
|
SzPhysPath(sz, pth);
|
|
|
|
dwAttributes = GetFileAttributes(sz);
|
|
if (dwAttributes != -1 && (dwAttributes & FILE_ATTRIBUTE_READONLY))
|
|
SetFileAttributes(sz, dwAttributes & ~FILE_ATTRIBUTE_READONLY);
|
|
|
|
fOk = fFalse;
|
|
*pBase = NULL;
|
|
*hf = CreateFile(sz,
|
|
fWriteAccess ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
0,
|
|
NULL);
|
|
if (*hf != INVALID_HANDLE_VALUE)
|
|
{
|
|
hm = CreateFileMapping(*hf,
|
|
NULL,
|
|
fWriteAccess ? PAGE_READWRITE | SEC_COMMIT : PAGE_READONLY,
|
|
0,
|
|
0,
|
|
NULL);
|
|
if (hm != NULL)
|
|
{
|
|
*pBase = MapViewOfFile(hm, fWriteAccess ? FILE_MAP_WRITE : FILE_MAP_READ, 0, 0, 0);
|
|
if (*pBase != NULL)
|
|
{
|
|
fOk = fTrue;
|
|
}
|
|
CloseHandle(hm);
|
|
}
|
|
else
|
|
if (GetLastError() == ERROR_FILE_INVALID)
|
|
{
|
|
return GrowMappedFile(*hf, pBase, cbInitial);
|
|
}
|
|
}
|
|
|
|
return fOk;
|
|
}
|
|
|
|
|
|
F
|
|
GrowMappedFile(
|
|
HANDLE hf,
|
|
void **pBase,
|
|
unsigned cbNewSize
|
|
)
|
|
{
|
|
F fOk;
|
|
HANDLE hm;
|
|
DWORD dwSize, dwOldSize;
|
|
|
|
if (*pBase != NULL)
|
|
{
|
|
FlushViewOfFile(*pBase, 0);
|
|
UnmapViewOfFile(*pBase);
|
|
*pBase = NULL;
|
|
}
|
|
|
|
dwOldSize = GetFileSize(hf, NULL);
|
|
|
|
dwSize = cbNewSize;
|
|
if (SetFilePointer(hf, dwSize, NULL, FILE_BEGIN) == dwSize &&
|
|
SetEndOfFile(hf)
|
|
)
|
|
{
|
|
hm = CreateFileMapping(hf,
|
|
NULL,
|
|
PAGE_READWRITE | SEC_COMMIT,
|
|
0,
|
|
0,
|
|
NULL);
|
|
if (hm != NULL)
|
|
{
|
|
*pBase = MapViewOfFile(hm, FILE_MAP_WRITE, 0, 0, dwSize);
|
|
if (*pBase != NULL)
|
|
{
|
|
fOk = fTrue;
|
|
// Safe, since cbNewSize is > dwOldSize
|
|
memset(((char *) *pBase) + dwOldSize, 0, dwSize-dwOldSize);
|
|
}
|
|
CloseHandle(hm);
|
|
}
|
|
}
|
|
|
|
return fOk;
|
|
}
|
|
|
|
|
|
void
|
|
CloseMappedFile(
|
|
PTH *pth,
|
|
HANDLE *hf,
|
|
void **pBase
|
|
)
|
|
{
|
|
char sz[cchPthMax];
|
|
|
|
if (pth[0] != '\0') {
|
|
SzPhysPath(sz, pth);
|
|
pth[0] = '\0';
|
|
}
|
|
|
|
if (*pBase != NULL)
|
|
{
|
|
FlushViewOfFile(*pBase, 0);
|
|
UnmapViewOfFile(*pBase);
|
|
*pBase = NULL;
|
|
}
|
|
|
|
if (*hf != NULL) {
|
|
CloseHandle(*hf);
|
|
*hf = NULL;
|
|
}
|
|
|
|
if (sz[0] != '\0')
|
|
SetFileAttributes(sz, FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_ARCHIVE);
|
|
|
|
return;
|
|
}
|
|
|
|
extern F fDisplayStatusFilePath;
|
|
static HANDLE hTerminatePeekThreadEvent;
|
|
static HANDLE hInputHandle;
|
|
static F fInputIsConsole;
|
|
|
|
DWORD
|
|
WINAPI
|
|
SlmPeekThread(
|
|
LPVOID Parameter
|
|
)
|
|
{
|
|
AD *pad = (AD *)Parameter;
|
|
DWORD dwWaitIndex;
|
|
HANDLE hWaitHandles[3];
|
|
DWORD dwNumberOfWaitHandles;
|
|
|
|
INPUT_RECORD ConsoleBuffer;
|
|
DWORD NumberOfEventsRead;
|
|
|
|
char InputBuffer[ 1 ];
|
|
DWORD NumberOfBytesAvailable;
|
|
DWORD NumberOfBytesRead;
|
|
|
|
dwNumberOfWaitHandles = 2;
|
|
hWaitHandles[0] = hTerminatePeekThreadEvent;
|
|
hWaitHandles[1] = hInputHandle;
|
|
hWaitHandles[2] = OpenEvent( EVENT_ALL_ACCESS, FALSE, "TerminateSLM" );
|
|
if (hWaitHandles[2] != NULL) {
|
|
dwNumberOfWaitHandles = 3;
|
|
}
|
|
|
|
while (TRUE) {
|
|
dwWaitIndex = WaitForMultipleObjects( dwNumberOfWaitHandles,
|
|
hWaitHandles,
|
|
FALSE,
|
|
INFINITE
|
|
);
|
|
if (dwWaitIndex == 0)
|
|
break;
|
|
|
|
if (dwWaitIndex == 2) {
|
|
while (TRUE) {
|
|
FakeCtrlBreak();
|
|
Sleep( 1000 );
|
|
}
|
|
}
|
|
else
|
|
if (fInputIsConsole) {
|
|
if (PeekConsoleInput( hInputHandle,
|
|
&ConsoleBuffer,
|
|
1,
|
|
&NumberOfEventsRead
|
|
) &&
|
|
NumberOfEventsRead == 1
|
|
) {
|
|
if (ReadConsoleInput( hInputHandle,
|
|
&ConsoleBuffer,
|
|
1,
|
|
&NumberOfEventsRead
|
|
) &&
|
|
NumberOfEventsRead == 1 &&
|
|
ConsoleBuffer.EventType == KEY_EVENT &&
|
|
ConsoleBuffer.Event.KeyEvent.bKeyDown) {
|
|
FlushConsoleInputBuffer( hInputHandle );
|
|
fDisplayStatusFilePath = fTrue;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (PeekNamedPipe( hInputHandle,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&NumberOfBytesAvailable,
|
|
NULL
|
|
) &&
|
|
NumberOfBytesAvailable > 0
|
|
) {
|
|
while (NumberOfBytesAvailable > 0) {
|
|
NumberOfBytesRead = sizeof( InputBuffer );
|
|
if (NumberOfBytesRead > NumberOfBytesAvailable) {
|
|
NumberOfBytesRead = NumberOfBytesAvailable;
|
|
}
|
|
|
|
if (ReadFile( hInputHandle,
|
|
InputBuffer,
|
|
NumberOfBytesRead,
|
|
&NumberOfBytesRead,
|
|
NULL
|
|
) &&
|
|
NumberOfBytesRead > 0
|
|
)
|
|
NumberOfBytesAvailable -= NumberOfBytesRead;
|
|
}
|
|
|
|
fDisplayStatusFilePath = fTrue;
|
|
}
|
|
}
|
|
}
|
|
|
|
ExitThread( NO_ERROR );
|
|
return NO_ERROR;
|
|
}
|
|
|
|
void
|
|
CreatePeekThread(
|
|
AD *pad
|
|
)
|
|
{
|
|
HANDLE hThread;
|
|
DWORD dwThreadId;
|
|
DWORD dwConsoleMode;
|
|
|
|
hTerminatePeekThreadEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
|
|
if (hTerminatePeekThreadEvent == NULL)
|
|
return;
|
|
|
|
hInputHandle = GetStdHandle( STD_INPUT_HANDLE );
|
|
if (GetConsoleMode(hInputHandle, &dwConsoleMode))
|
|
fInputIsConsole = fTrue;
|
|
else
|
|
fInputIsConsole = fFalse;
|
|
|
|
hThread = CreateThread( NULL, 0, SlmPeekThread, pad, 0, &dwThreadId );
|
|
if (hThread != NULL)
|
|
CloseHandle( hThread );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
DestroyPeekThread( void )
|
|
{
|
|
if (hTerminatePeekThreadEvent == NULL)
|
|
return;
|
|
|
|
SetEvent(hTerminatePeekThreadEvent);
|
|
CloseHandle(hTerminatePeekThreadEvent);
|
|
|
|
return;
|
|
}
|