#include #include #include #include #include #include #include #include #include #include #include #include #include "defs.h" #include "types.h" #include "globals.h" HANDLE VolumeHandle; const ULONG SectorSize = 512; PVOID TransferBuffer = NULL; PVOID TransferLocation = NULL; BOOLEAN open_disk( char* DosDriveName, BOOLEAN WriteAccess ) /*++ Routine Description: This function uses the NT native API to open a drive. Arguments: DosDriveName -- supplies the DOS name of the drive. WriteAccess -- supplies a flag which indicates, if TRUE, that the volume should be opened for write access. Return Value: TRUE upon successful completion. The handle is stored in VolumeHandle (local to this module). Notes: If the volume is opened for write access, it is also locked. --*/ { FILE_ALIGNMENT_INFORMATION AlignmentInfo; OBJECT_ATTRIBUTES oa; UNICODE_STRING NtDriveName; PWSTR WideCharDosName; IO_STATUS_BLOCK status_block; NTSTATUS status; int CharsInName, i; ULONG TransferOffset, BufferSize, AlignMask; ACCESS_MASK AccessMask; // Create a wide-character string with the DOS drive name. // Note that I assume that the drive name is ASCII, and ignore // multi-byte characters. CharsInName = strlen( DosDriveName ); WideCharDosName = malloc ( (CharsInName+1) * sizeof(WCHAR) ); if( WideCharDosName == NULL ) { return FALSE; } for( i = 0; i < CharsInName; i++ ) { WideCharDosName[i] = DosDriveName[i]; } WideCharDosName[CharsInName] = 0; // OK, now get the corresponding NT name, in wide characters: if( !RtlDosPathNameToNtPathName_U( WideCharDosName, &NtDriveName, NULL, NULL ) ) { free( WideCharDosName ); return FALSE; } // If the NT drive name has a trailing backslash, remove it. // BUGBUG billmc -- why is this necessary? CharsInName = NtDriveName.Length/sizeof(WCHAR); if( NtDriveName.Buffer[CharsInName-1] == '\\' ) { NtDriveName.Buffer[CharsInName-1] = 0; NtDriveName.Length -= sizeof(WCHAR); CharsInName -= 1; } InitializeObjectAttributes( &oa, &NtDriveName, OBJ_CASE_INSENSITIVE, 0, 0 ); AccessMask = SYNCHRONIZE | FILE_READ_DATA; if( WriteAccess ) { AccessMask |= FILE_WRITE_DATA; } if( !NT_SUCCESS( NtOpenFile( &VolumeHandle, AccessMask, &oa, &status_block, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT ) ) ) { return FALSE; } // If we're opening for write access, lock it, too. if( WriteAccess && !fUnsafe && !lock_disk() ) { NtClose( VolumeHandle ); return FALSE; } // Get the volume's alignment factor, and allocate a // properly-aligned transfer buffer. status = NtQueryInformationFile( VolumeHandle, &status_block, &AlignmentInfo, sizeof( AlignmentInfo ), FileAlignmentInformation ); if( !NT_SUCCESS(status) ) { NtClose( VolumeHandle ); return FALSE; } AlignMask = AlignmentInfo.AlignmentRequirement; BufferSize = SectorSize * 4 + AlignMask + 1; if( (TransferBuffer = malloc( BufferSize )) == NULL ) { NtClose( VolumeHandle ); return FALSE; } if( (ULONG)TransferBuffer & AlignMask ) { TransferOffset = AlignMask + 1 - ((ULONG)TransferBuffer & AlignMask); } else { // This buffer is properly aligned. TransferOffset = 0; } TransferLocation = (PVOID)((PCHAR)TransferBuffer + TransferOffset); // BUGBUG billmc -- memory leak through NtDriveName? return TRUE; } BOOLEAN read_scratch( ULONG Lbn, void* UserBuffer, ULONG NumberOfSectors ) { IO_STATUS_BLOCK StatusBlock; LARGE_INTEGER ByteOffset; NTSTATUS Status; ULONG ThisChunk, Offset; ByteOffset.LowPart = SectorSize * Lbn; ByteOffset.HighPart = 0; Offset = 0; while( NumberOfSectors ) { ThisChunk = (NumberOfSectors < 4) ? NumberOfSectors : 4; Status = NtReadFile( VolumeHandle, 0, NULL, NULL, &StatusBlock, TransferLocation, SectorSize * ThisChunk, &ByteOffset, NULL ); if( !NT_SUCCESS(Status) || StatusBlock.Information != SectorSize * ThisChunk ) { return FALSE; } memcpy( (PCHAR)UserBuffer + Offset, TransferLocation, ThisChunk * SectorSize ); NumberOfSectors -= ThisChunk; ByteOffset.LowPart += ThisChunk * SectorSize; Offset += ThisChunk * SectorSize; } return( TRUE ); } BOOLEAN write_scratch( ULONG Lbn, void* UserBuffer, ULONG NumberOfSectors ) { IO_STATUS_BLOCK StatusBlock; LARGE_INTEGER ByteOffset; NTSTATUS Status; ULONG ThisChunk, Offset; ByteOffset.LowPart = SectorSize * Lbn; ByteOffset.HighPart = 0; Offset = 0; while( NumberOfSectors ) { ThisChunk = (NumberOfSectors < 4) ? NumberOfSectors : 4; memcpy( TransferLocation, (PCHAR)UserBuffer + Offset, ThisChunk * SectorSize ); Status = NtWriteFile( VolumeHandle, 0, NULL, NULL, &StatusBlock, TransferLocation, SectorSize * ThisChunk, &ByteOffset, NULL ); if( !NT_SUCCESS(Status) || StatusBlock.Information != SectorSize * ThisChunk ) { return FALSE; } NumberOfSectors -= ThisChunk; ByteOffset.LowPart += ThisChunk * SectorSize; Offset += ThisChunk * SectorSize; } return( TRUE ); } BOOLEAN lock_disk( ) /**+ Routine Description: This function locks the disk. Note that the matching unlock_disk function is not required, since the handle is automatically unlocked when it is closed. Arguments: None. Return Value: None. --*/ { IO_STATUS_BLOCK IoStatusBlock; if( !NT_SUCCESS(NtFsControlFile( VolumeHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0 )) ) { return FALSE; } return TRUE; } VOID close_disk( ) /*++ Routine Description: This function closes a previously-opened volume. Arguments: Handle -- supplies the volume handle. Return Value: None. Notes: This is currently just a wrapper for NtClose, but it creates a channel where I can put piggyback stuff on open/close of volumes. --*/ { NtClose( VolumeHandle ); } /*** write_log -- append a field to a file * * This function appends a line of the form "set =" * to the file specified by the /L: command line switch. * This allows the user to save information the DAMAGE found for later * use. * * write_log(item) * * ENTRY item is the number of the field that the function is * to save * * EXIT log file is modified * * WARNINGS none * * CALLS printf, log_gets, fprintf */ void write_log(USHORT item) { UCHAR szVar[40]; UCHAR szValue[40]; UCHAR *get_time(); struct SuperSpare *s; struct FNODE *f; struct DIRBLK *d; struct ALSEC *a; union dp dp; ULONG *l, offset; UCHAR *p; UCHAR szHex8[6]; UCHAR szHex4[5]; UCHAR szHex2[5]; UCHAR szStr[3]; strcpy(szHex8, "%08lx"); strcpy(szHex4, "%04x"); strcpy(szHex2, "%02x"); strcpy(szStr, "%s"); // get name to write printf("Name of variable: "); log_gets(szVar); if (!strlen(szVar)) return; // get field value switch (currobj.type) { case TYPE_SUPERB: s = (struct SuperSpare *)currobj.mem; if (currobj.offset == FIELDOFFSET (struct SuperSpare, spb)) { if (item == iSPB_SIG1) sprintf(szValue, szHex8, s->spb.SPB_SIG1); else if (item == iSPB_SIG2) sprintf(szValue, szHex8, s->spb.SPB_SIG2); else if (item == iSPB_FLAG) sprintf(szValue, szHex8, s->spb.SPB_FLAG); else if (item == iSPB_HFSEC) sprintf(szValue, szHex8, s->spb.SPB_HFSEC); else if (item == iSPB_HFUSE) sprintf(szValue, szHex8, s->spb.SPB_HFUSE); else if (item == iSPB_HFMAX) sprintf(szValue, szHex8, s->spb.SPB_HFMAX); else if (item == iSPB_SDBCNT) sprintf(szValue, szHex8, s->spb.SPB_SDBCNT); else if (item == iSPB_SDBMAX) sprintf(szValue, szHex8, s->spb.SPB_SDBMAX); #ifdef CODEPAGE else if (item == iSPB_CPSEC) sprintf(szValue, szHex8, s->spb.SPB_CPSEC); else if (item == iSPB_CPCNT) sprintf(szValue, szHex8, s->spb.SPB_CPCNT); else sprintf(szValue, szHex8, s->spb.SPB_SPARDB[item - iSPB_CPCNT + 1]); #else else sprintf(szValue, szHex8, s->spb.SPB_SPARDB[item - 9]); #endif } else { if (item == iSB_SIG1) sprintf(szValue, szHex8, s->sb.SB_SIG1); else if (item == iSB_SIG2) sprintf(szValue, szHex8, s->sb.SB_SIG2); else if (item == iSB_VER) sprintf(szValue, szHex2, s->sb.SB_VER); else if (item == iSB_FVER) sprintf(szValue, szHex2, s->sb.SB_FVER); else if (item == iSB_ROOT) sprintf(szValue, szHex8, s->sb.SB_ROOT); else if (item == iSB_SEC) sprintf(szValue, szHex8, s->sb.SB_SEC); else if (item == iSB_BSEC) sprintf(szValue, szHex8, s->sb.SB_BSEC); else if (item == iSB_BII_P) sprintf(szValue, szHex8, s->sb.SB_BII.P); else if (item == iSB_BBL_P) sprintf(szValue, szHex8, s->sb.SB_BBL.P); else if (item == iSB_CDDAT) sprintf(szValue, szStr, get_time(s->sb.SB_CDDAT)); else if (item == iSB_DODAT) sprintf(szValue, szStr, get_time(s->sb.SB_DODAT)); else if (item == iSB_DBSIZE) sprintf(szValue, szHex8, s->sb.SB_DBSIZE); else if (item == iSB_DBLOW) sprintf(szValue, szHex8, s->sb.SB_DBLOW); else if (item == iSB_DBHIGH) sprintf(szValue, szHex8, s->sb.SB_DBHIGH); else if (item == iSB_DBMAP) sprintf(szValue, szHex8, s->sb.SB_DBMAP); } break; case TYPE_BII: l = (ULONG *)((UCHAR *)currobj.mem + currobj.offset); sprintf(szValue, "%3d) %08lx ", item, l[item - 1]); break; case TYPE_BBL: l = (ULONG *)((UCHAR *)currobj.mem + currobj.offset); if (item == 1) sprintf(szValue, szHex8, *(ULONG *)currobj.mem); else sprintf(szValue, szHex8, l[item - 2]); break; case TYPE_HFSEC: l = ((ULONG *)currobj.mem) + currobj.offset + (item-1)/3; if (!(item % 3)) sprintf(szValue, szHex8, *(l + 2*hfmax)); else if ((item % 3) == 1) sprintf(szValue, szHex8, *(l + hfmax)); else sprintf(szValue, szHex8, *l); break; case TYPE_FNODE: f = (struct FNODE *)currobj.mem; if (!currobj.offset) { if (item == iFN_SIG) sprintf(szValue, szHex8, f->FN_SIG); else if (item == iFN_SRH) sprintf(szValue, szHex8, f->FN_SRH); else if (item == iFN_FRH) sprintf(szValue, szHex8, f->FN_FRH); else if (item == iFN_XXX) sprintf(szValue, szHex8, f->FN_SIG); else if (item == iFN_HCNT) sprintf(szValue, szHex2, f->FN_HCNT); else if (item == iFN_CONTFN) sprintf(szValue, szHex8, f->FN_CONTFN); else if (item == iFN_ACL_AI_DAL) sprintf(szValue, szHex8, f->FN_AclDiskLength); else if (item == iFN_ACL_AI_SEC) sprintf(szValue, szHex8, f->FN_AclSector); else if (item == iFN_ACL_AI_FNL) sprintf(szValue, szHex4, f->FN_AclFnodeLength); else if (item == iFN_ACL_AI_DAT) sprintf(szValue, szHex2, f->FN_AclDataFlag); else if (item == iFN_EA_AI_DAL) sprintf(szValue, szHex8, f->FN_EaDiskLength); else if (item == iFN_EA_AI_SEC) sprintf(szValue, szHex8, f->FN_EaSector); else if (item == iFN_EA_AI_FNL) sprintf(szValue, szHex4, f->FN_EaFnodeLength); else if (item == iFN_EA_AI_DAT) sprintf(szValue, szHex2, f->FN_EaDataFlag); } else if (currobj.offset == FIELDOFFSET (struct FNODE, FN_AB)) { if (item == iAB_FLAG) sprintf(szValue, szHex8, f->FN_AB.AB_FLAG); else if (item == iAB_FCNT) sprintf(szValue, szHex2, f->FN_AB.AB_FCNT); else if (item == iAB_OCNT) sprintf(szValue, szHex2, f->FN_AB.AB_OCNT); else if (item == iAB_FREP) sprintf(szValue, szHex4, f->FN_AB.AB_FREP); } else if (currobj.offset == FIELDOFFSET (struct FNODE, FN_ALREC [0])) { l = (ULONG *)f->FN_ALREC; sprintf(szValue, szHex8, *(l + (item - 1))); } break; case TYPE_DIRBLK: d = (struct DIRBLK *)currobj.mem; dp.p = (UCHAR *)currobj.mem + currobj.offset; if (item == iDB_SIG) sprintf(szValue, szHex8, d->DB_SIG); else if (item == iDB_FREP) sprintf(szValue, szHex8, d->DB_FREP); else if (item == iDB_CCNT) sprintf(szValue, szHex8, d->DB_CCNT); else if (item == iDB_PAR) sprintf(szValue, szHex8, d->DB_PAR); else if (item == iDB_SEC) sprintf(szValue, szHex8, d->DB_SEC); else if (item == iDIR_ELEN) sprintf(szValue, szHex4, dp.d->DIR_ELEN); else if (item == iDIR_FLAG) sprintf(szValue, szHex8, dp.d->DIR_FLAG); else if (item == iDIR_FN) sprintf(szValue, szHex8, dp.d->DIR_FN); else if (item == iDIR_MTIM) sprintf(szValue, szStr, get_time(dp.d->DIR_MTIM)); else if (item == iDIR_SIZE) sprintf(szValue, szHex8, dp.d->DIR_SIZE); else if (item == iDIR_ATIM) sprintf(szValue, szStr, get_time(dp.d->DIR_ATIM)); else if (item == iDIR_CTIM) sprintf(szValue, szStr, get_time(dp.d->DIR_CTIM)); else if (item == iDIR_EALEN) sprintf(szValue, szHex8, dp.d->DIR_EALEN); else if (item == iDIR_NAML) sprintf(szValue, szHex2, dp.d->DIR_NAML); else if (item == iDIR_NAMA) { strncpy(scratch, &dp.d->DIR_NAMA, dp.d->DIR_NAML); scratch[dp.d->DIR_NAML] = '\0'; sprintf(szValue, szStr, scratch); } else if (item == iDIR_BTP) sprintf(szValue, szHex8, DOWN_PTR(dp)); break; case TYPE_ALSEC: a = (struct ALSEC *)currobj.mem; if (!currobj.offset) { if (item == iAS_SIG) sprintf(szValue, szHex8, a->AS_SIG); else if (item == iAS_SEC) sprintf(szValue, szHex8, a->AS_SEC); else if (item == iAS_RENT) sprintf(szValue, szHex8, a->AS_RENT); else if (item == iAS_ALBLK_AB_FLAG) sprintf(szValue, szHex8, a->AS_ALBLK.AB_FLAG); else if (item == iAS_ALBLK_AB_FCNT) sprintf(szValue, szHex2, a->AS_ALBLK.AB_FCNT); else if (item == iAS_ALBLK_AB_OCNT) sprintf(szValue, szHex2, a->AS_ALBLK.AB_OCNT); else if (item == iAS_ALBLK_AB_FREP) sprintf(szValue, szHex4, a->AS_ALBLK.AB_FREP); } else { l = (ULONG *)((UCHAR *)currobj.mem + currobj.offset); sprintf(szValue, szHex8, *(l + (item - 1))); } break; default: printf("log: unknown type\n"); } // write to file fprintf(fpLog, "set %s=%s\n", szVar, szValue); }