516 lines
13 KiB
C
516 lines
13 KiB
C
|
|
/*****************************************************************/
|
|
/** Microsoft LAN Manager **/
|
|
/** Copyright(c) Microsoft Corp., 1988-1991 **/
|
|
/*****************************************************************/
|
|
|
|
/**** he - HexEdit a file
|
|
*
|
|
* Wrapper to HexEdit function to allow file (or drive) editting
|
|
*
|
|
* Written: Ken Reneris
|
|
*
|
|
*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <ntdddisk.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <process.h>
|
|
#include <windows.h>
|
|
#include "hexedit.h"
|
|
|
|
NTSTATUS fncRead(HANDLE, ULONGLONG, PUCHAR, DWORD);
|
|
NTSTATUS fncWrite(HANDLE, ULONGLONG, PUCHAR, DWORD);
|
|
|
|
void EditFile (char *name);
|
|
void ReadIni ();
|
|
|
|
WORD vAttrList, vAttrTitle, vAttrHigh;
|
|
|
|
VOID __cdecl
|
|
main (argc, argv)
|
|
USHORT argc;
|
|
char *argv[];
|
|
{
|
|
char *argument = argv[1];
|
|
|
|
if (argc < 2) {
|
|
printf ("he fname\n");
|
|
exit (1);
|
|
}
|
|
|
|
ReadIni ();
|
|
|
|
if ((strncmp(argv[1], "\\\\.\\", 4)) == 0) {
|
|
char *cp;
|
|
int index;
|
|
|
|
// Insure there is a backslash on the DosName being opened.
|
|
for (cp = argv[1], index = 0; *cp; *cp++, index++) {
|
|
// action in for loop
|
|
}
|
|
cp--;
|
|
if (*cp != '\\') {
|
|
|
|
// Need to add backslash to name.
|
|
|
|
argument = GlobalAlloc (0,index + 4);
|
|
if (!argument) {
|
|
printf("Out of memory\n");
|
|
exit (1);
|
|
}
|
|
for (cp = argv[1], index = 0; argument[index] = *cp; *cp++, index++) {
|
|
// action in for loop
|
|
}
|
|
argument[index] = '\\';
|
|
argument[index + 1] = '\0';
|
|
}
|
|
}
|
|
EditFile (argument);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
EditFile (
|
|
char *name
|
|
)
|
|
{
|
|
FILE_ALIGNMENT_INFORMATION AlignmentInfo;
|
|
PDISK_GEOMETRY_EX DiskGeo;
|
|
ULONGLONG li;
|
|
struct HexEditParm ei;
|
|
USHORT rc, rc1, i, l;
|
|
PWSTR WideName;
|
|
OBJECT_ATTRIBUTES oa;
|
|
NTSTATUS status;
|
|
UNICODE_STRING NtDriveName;
|
|
ANSI_STRING NtDriveNameAnsi;
|
|
IO_STATUS_BLOCK status_block;
|
|
UCHAR GeoBuf[ 8*1024];
|
|
UCHAR Root[12];
|
|
|
|
//
|
|
// Try to open & edit as regular filename
|
|
//
|
|
|
|
memset ((PUCHAR) &ei, 0, sizeof (ei));
|
|
ei.ename = name;
|
|
ei.flag = FHE_VERIFYONCE | FHE_SAVESCRN | FHE_JUMP;
|
|
ei.read = fncRead;
|
|
ei.write = fncWrite;
|
|
ei.ioalign = 1;
|
|
ei.Console = INVALID_HANDLE_VALUE;
|
|
ei.AttrNorm = vAttrList;
|
|
ei.AttrHigh = vAttrTitle;
|
|
ei.AttrReverse = vAttrHigh;
|
|
|
|
ei.handle = CreateFile (
|
|
name,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL );
|
|
|
|
if (ei.handle == INVALID_HANDLE_VALUE) {
|
|
// Try for just read access
|
|
|
|
ei.handle = CreateFile (
|
|
name,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL );
|
|
}
|
|
|
|
|
|
if (ei.handle != INVALID_HANDLE_VALUE) {
|
|
|
|
ULONG High = 0;
|
|
|
|
ei.totlen = 0;
|
|
ei.totlen = SetFilePointer (ei.handle, 0, &High, FILE_END);
|
|
ei.totlen |= ((ULONGLONG)High) << 32;
|
|
|
|
HexEdit (&ei);
|
|
return;
|
|
}
|
|
|
|
rc = (USHORT)GetLastError ();
|
|
|
|
//
|
|
// Try expanding the name from dosname to ntname.
|
|
// Since regular name failed, assume a sector edit
|
|
//
|
|
l = strlen(name)+1;
|
|
WideName = GlobalAlloc (0,l * sizeof(WCHAR));
|
|
if (!WideName) {
|
|
printf("Out of memory\n");
|
|
exit(1);
|
|
}
|
|
|
|
ZeroMemory(WideName, l*sizeof(WCHAR));
|
|
|
|
for(i=0; i < l; i++)
|
|
WideName[i] = name[i];
|
|
|
|
// OK, now get the corresponding NT name
|
|
rc1 = RtlDosPathNameToNtPathName_U (
|
|
WideName,
|
|
&NtDriveName,
|
|
NULL,
|
|
NULL );
|
|
|
|
if (!rc1) {
|
|
printf ("Open error %d\n", rc);
|
|
exit (rc);
|
|
}
|
|
|
|
|
|
// If the NT drive name has a trailing backslash, remove it.
|
|
l = NtDriveName.Length/sizeof(WCHAR);
|
|
if( NtDriveName.Buffer[l-1] == '\\' ) {
|
|
|
|
NtDriveName.Buffer[l-1] = 0;
|
|
NtDriveName.Length -= sizeof(WCHAR);
|
|
}
|
|
|
|
InitializeObjectAttributes(
|
|
&oa,
|
|
&NtDriveName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
0,
|
|
0 );
|
|
|
|
status = NtOpenFile(
|
|
&ei.handle,
|
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
|
|
&oa,
|
|
&status_block,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_ALERT );
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
// try for just read access
|
|
|
|
status = NtOpenFile(
|
|
&ei.handle,
|
|
SYNCHRONIZE | FILE_READ_DATA,
|
|
&oa,
|
|
&status_block,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_ALERT );
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
NtDriveName.Length = strlen(name) * sizeof(WCHAR);
|
|
NtDriveName.Buffer = WideName;
|
|
|
|
InitializeObjectAttributes(
|
|
&oa,
|
|
&NtDriveName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
0,
|
|
0 );
|
|
|
|
status = NtOpenFile(
|
|
&ei.handle,
|
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
|
|
&oa,
|
|
&status_block,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_ALERT );
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
// try for just read access
|
|
|
|
status = NtOpenFile(
|
|
&ei.handle,
|
|
SYNCHRONIZE | FILE_READ_DATA,
|
|
&oa,
|
|
&status_block,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_ALERT );
|
|
}
|
|
}
|
|
|
|
|
|
RtlUnicodeStringToAnsiString (&NtDriveNameAnsi, &NtDriveName, TRUE);
|
|
ei.ename = NtDriveNameAnsi.Buffer;
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
printf ("%s open error %lx\n", ei.ename, status);
|
|
exit (status);
|
|
}
|
|
/*
|
|
NtQueryInformationFile(
|
|
ei.handle,
|
|
&status_block,
|
|
&AlignmentInfo,
|
|
sizeof( AlignmentInfo ),
|
|
FileAlignmentInformation );
|
|
|
|
ei.ioalign = AlignmentInfo.AlignmentRequirement;
|
|
*/
|
|
ei.ioalign = 0;
|
|
|
|
ei.totlen = 0;
|
|
|
|
if (NtDriveNameAnsi.Buffer[ NtDriveNameAnsi.Length - 1] == ':') {
|
|
|
|
sprintf( Root, "%c:\\", NtDriveNameAnsi.Buffer[ NtDriveNameAnsi.Length - 2]);
|
|
|
|
//
|
|
// For non-cdrom drive letter opens, we need to use
|
|
// get partition info, not get disk info, for the partition size.
|
|
//
|
|
|
|
if (DRIVE_CDROM != GetDriveType( Root)) {
|
|
|
|
PPARTITION_INFORMATION Part = (PVOID)GeoBuf;
|
|
|
|
status = NtDeviceIoControlFile(
|
|
ei.handle,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&status_block,
|
|
IOCTL_DISK_GET_PARTITION_INFO,
|
|
NULL,
|
|
0,
|
|
GeoBuf,
|
|
sizeof( GeoBuf) );
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
ei.totlen = Part->PartitionLength.QuadPart;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get sectorsize and, if we haven't got it already, disk/partition size
|
|
//
|
|
|
|
status = NtDeviceIoControlFile( ei.handle,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&status_block,
|
|
IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
|
|
NULL,
|
|
0,
|
|
GeoBuf,
|
|
sizeof( GeoBuf) );
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
DiskGeo = (PVOID)GeoBuf;
|
|
|
|
if (ei.ioalign < DiskGeo->Geometry.BytesPerSector) {
|
|
|
|
ei.ioalign = DiskGeo->Geometry.BytesPerSector;
|
|
}
|
|
|
|
if (0 == ei.totlen) {
|
|
|
|
ei.totlen = DiskGeo->DiskSize.QuadPart;
|
|
}
|
|
}
|
|
else {
|
|
|
|
//
|
|
// The EX call failed, try the old one. GPT discs seem
|
|
// to fail the EX call.
|
|
//
|
|
|
|
PDISK_GEOMETRY OldGeo;
|
|
|
|
status = NtDeviceIoControlFile( ei.handle,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&status_block,
|
|
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|
NULL,
|
|
0,
|
|
GeoBuf,
|
|
sizeof( GeoBuf) );
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
OldGeo = (PVOID)GeoBuf;
|
|
|
|
if (ei.ioalign < OldGeo->BytesPerSector) {
|
|
|
|
ei.ioalign = OldGeo->BytesPerSector;
|
|
}
|
|
|
|
if (0 == ei.totlen) {
|
|
|
|
ei.totlen = OldGeo->Cylinders.QuadPart * OldGeo->BytesPerSector *
|
|
OldGeo->SectorsPerTrack * OldGeo->TracksPerCylinder;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Last resort for partition/disk size.
|
|
//
|
|
|
|
if (0 == ei.totlen) {
|
|
|
|
ULONG High = 0;
|
|
|
|
if (ei.ioalign < 0x200) {
|
|
|
|
ei.ioalign = 0x200;
|
|
}
|
|
|
|
ei.totlen = 0;
|
|
ei.totlen = SetFilePointer (ei.handle, 0, &High, FILE_END);
|
|
ei.totlen |= ((ULONGLONG)High) << 32;
|
|
}
|
|
|
|
//
|
|
// If a filesystem is mounted, we need to enable extended
|
|
// DASD io in order to read the whole volume. Ignore result,
|
|
// not all FSs support it.
|
|
//
|
|
|
|
status = NtDeviceIoControlFile(
|
|
ei.handle,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&status_block,
|
|
FSCTL_ALLOW_EXTENDED_DASD_IO,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0);
|
|
|
|
ei.flag = FHE_VERIFYALL | FHE_PROMPTSEC | FHE_SAVESCRN | FHE_JUMP;
|
|
HexEdit (&ei);
|
|
}
|
|
|
|
|
|
NTSTATUS fncRead (HANDLE h, ULONGLONG loc, PUCHAR data, DWORD len)
|
|
{
|
|
DWORD l, br;
|
|
ULONG High = (ULONG)(loc >> 32);
|
|
|
|
l = SetFilePointer (h, (ULONG)loc, &High, FILE_BEGIN);
|
|
if (l == -1)
|
|
return GetLastError();
|
|
|
|
if (!ReadFile (h, data, len, &br, NULL))
|
|
return GetLastError();
|
|
|
|
return (br != len ? ERROR_READ_FAULT : 0);
|
|
}
|
|
|
|
|
|
NTSTATUS fncWrite (HANDLE h, ULONGLONG loc, PUCHAR data, DWORD len)
|
|
{
|
|
DWORD l, bw;
|
|
ULONG High = (ULONG)(loc >> 32);
|
|
|
|
l = SetFilePointer (h, (ULONG)loc, &High, FILE_BEGIN);
|
|
if (l == -1)
|
|
return GetLastError();
|
|
|
|
if (!WriteFile (h, data, len, &bw, NULL))
|
|
return GetLastError();
|
|
|
|
return (bw != len ? ERROR_WRITE_FAULT : 0);
|
|
}
|
|
|
|
|
|
|
|
/*** xtoi - Hex to int
|
|
*
|
|
* Entry:
|
|
* pt - pointer to hex number
|
|
*
|
|
* Return:
|
|
* value of hex number
|
|
*
|
|
*/
|
|
unsigned xtoi (pt)
|
|
char *pt;
|
|
{
|
|
unsigned u;
|
|
char c;
|
|
|
|
u = 0;
|
|
while (c = *(pt++)) {
|
|
if (c >= 'a' && c <= 'f')
|
|
c -= 'a' - 'A';
|
|
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'))
|
|
u = u << 4 | c - (c >= 'A' ? 'A'-10 : '0');
|
|
}
|
|
return (u);
|
|
}
|
|
|
|
|
|
void
|
|
ReadIni ()
|
|
{
|
|
static char Delim[] = " :=;\t\r\n";
|
|
FILE *fp;
|
|
char *env, *verb, *value;
|
|
char s [200];
|
|
long l;
|
|
|
|
|
|
env = getenv ("INIT");
|
|
if (env == NULL)
|
|
return;
|
|
|
|
if ((strlen(env) + sizeof ("\\TOOLS.INI") + 1) > sizeof(s))
|
|
return;
|
|
|
|
strcpy (s, env);
|
|
strcat (s, "\\TOOLS.INI"); // just use list ini section
|
|
fp = fopen (s, "r");
|
|
if (fp == NULL)
|
|
return;
|
|
|
|
while (fgets (s, 200, fp) != NULL) {
|
|
if (s[0] != '[')
|
|
continue;
|
|
_strupr (s);
|
|
if (strstr (s, "LIST") == NULL)
|
|
continue;
|
|
/*
|
|
* ini file found w/ "list" keyword. Now read it.
|
|
*/
|
|
while (fgets (s, 200, fp) != NULL) {
|
|
if (s[0] == '[')
|
|
break;
|
|
verb = strtok (s, Delim);
|
|
value = strtok (NULL, Delim);
|
|
if (verb == NULL)
|
|
continue;
|
|
if (value == NULL)
|
|
value = "";
|
|
|
|
_strupr (verb);
|
|
if (strcmp (verb, "LCOLOR") == 0) vAttrList = (WORD)xtoi(value);
|
|
else if (strcmp (verb, "TCOLOR") == 0) vAttrTitle= (WORD)xtoi(value);
|
|
else if (strcmp (verb, "HCOLOR") == 0) vAttrHigh = (WORD)xtoi(value);
|
|
}
|
|
break;
|
|
}
|
|
fclose (fp);
|
|
}
|