Ejemplo n.º 1
0
static BOOL Ntllio2X(
	BYTE Drive,
	DWORD Sector,
	WORD NumSectors, 
	LPBYTE Buffer,
	BOOL write
	)
{
    DISK_GEOMETRY Geometry;
    DWORD ReturnedByteCount;
	HANDLE hDevice; 
    BOOL fResult; 
	char dev[0x20];
	MakeDeviceName(Drive, dev, 0x20);
 
    hDevice = CreateFile(dev, 
		GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL,OPEN_EXISTING,0,NULL);

    if (hDevice == INVALID_HANDLE_VALUE) return FALSE; 

	fResult=LockVolume(hDevice);
//	if ( !fResult ) goto ret;

	fResult=GetDiskGeometry(hDevice,&Geometry);

	if(fResult){
		fResult=(((DWORD)-1)!=SetFilePointer(hDevice,Sector*Geometry.BytesPerSector,NULL,FILE_BEGIN));
		if(fResult)
		{
			LPBYTE buf=NULL;
			if(Geometry.BytesPerSector > 0x200)
			{
				buf=malloc(NumSectors*Geometry.BytesPerSector);
				if(!buf) fResult=FALSE;
				if(write)memcpy(buf,Buffer,NumSectors*0x200);
			}
			if(fResult)
			{
				if(write)
					fResult=WriteFile(hDevice,buf?buf:Buffer,NumSectors*Geometry.BytesPerSector,&ReturnedByteCount,NULL);
				else
					fResult=ReadFile(hDevice,buf?buf:Buffer,NumSectors*Geometry.BytesPerSector,&ReturnedByteCount,NULL);
			
			}
			if(buf)
			{
				if(!write)memcpy(Buffer,buf,NumSectors*0x200);
				free(buf);
			}
		}
	}

	UnlockVolume(hDevice);
//ret:
	CloseHandle(hDevice); 
	return fResult;
}
Ejemplo n.º 2
0
static BOOL Ntllio13(
	BYTE Disk,
	WORD Sector,
	BYTE Head,
	WORD NumSectors, 
	LPBYTE Buffer,
	BOOL write
	)
{
    DISK_GEOMETRY Geometry;
    DWORD ReturnedByteCount;
	HANDLE hDevice; 
    BOOL fResult; 
	DWORD sector;
	DWORD SecNo;
	DWORD CylNo;
	char dev[0x20];
	MakeDeviceName(Disk, dev, 0x20);

    hDevice = CreateFile(dev, 
		GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL,OPEN_EXISTING,0,NULL);

    if (hDevice == INVALID_HANDLE_VALUE) return FALSE; 

	fResult=LockVolume(hDevice);
//	if ( !fResult ) goto ret;

	fResult=GetDiskGeometry(hDevice,&Geometry);

	SecNo=Sector & 0x003F;
	CylNo=Sector<<2;
	CylNo&=0x0300;
	CylNo|=Sector>>8;
	sector = (CylNo*Geometry.TracksPerCylinder + Head)*Geometry.SectorsPerTrack + SecNo - 1;

	fResult=(((DWORD)-1)!=SetFilePointer(hDevice,sector*Geometry.BytesPerSector,NULL,FILE_BEGIN));
	if(fResult)
	{
		LPBYTE buf=NULL;
		if(Geometry.BytesPerSector > 0x200)
		{
			buf=malloc(NumSectors*Geometry.BytesPerSector);
			if(!buf) fResult=FALSE;
			if(write)memcpy(buf,Buffer,NumSectors*0x200);
		}
		if(fResult)
		{
			if(write)
				fResult=WriteFile(hDevice,buf?buf:Buffer,NumSectors*Geometry.BytesPerSector,&ReturnedByteCount,NULL);
			else
				fResult=ReadFile(hDevice,buf?buf:Buffer,NumSectors*Geometry.BytesPerSector,&ReturnedByteCount,NULL);
		
		}
		if(buf)
		{
			if(!write)memcpy(Buffer,buf,NumSectors*0x200);
			free(buf);
		}

	}

	UnlockVolume(hDevice);
//ret:
	CloseHandle(hDevice); 
	return fResult;
}
Ejemplo n.º 3
0
DualErr 
Volume::Format()
{
	DualErr		derr;
	FatData		fat;
	PGPBoolean	allocedBlockBuf, lockedForFormat;
	PGPUInt8	*blockBuf;
	PGPUInt64	megsDisk;

	pgpAssert(Mounted());
	pgpAssert(!LockedForReadWrite() || !LockedForFormat());

	allocedBlockBuf = lockedForFormat = FALSE;
	megsDisk = (GetTotalBlocks() * kDefaultBlockSize) / kBytesPerMeg;

	// Can only format drives with standard block sizes.
	if (GetBlockSize() != kDefaultBlockSize)
		derr = DualErr(kPGDMinorError_CantFormatDrive);

	// Too big for format?
	if (derr.IsntError())
	{
		if (GetBlockSize() > kMaxBlocksDiskWeFormat)
			derr = DualErr(kPGDMinorError_DiskTooBigToFormat);
	}

	// Get block buffer.
	if (derr.IsntError())
	{
		derr = GetByteBuffer(kDefaultBlockSize, &blockBuf);
		allocedBlockBuf = derr.IsntError();
	}

	// Lock the volume for format.
	if (derr.IsntError())
	{
		derr = LockVolumeForFormat();
		lockedForFormat = derr.IsntError();
	}

	if (derr.IsntError())
	{
		// Initialize FAT data.
		fat.fdFsId = kFS_FAT16;

		if (megsDisk < 2)
		{
			fat.fdFsId = kFS_FAT12;
		}
		else if ((megsDisk >= kMinFat32Megs) && 
			IsWin95OSR2CompatibleMachine())
		{
			fat.fdFsId = kFS_FAT32;
		}

		InitFatData(&fat, GetBlockSize());

		derr = ClearBlocks(0, fat.fdFirstSecData);
	}

	// Write out the FAT data structures.
	if (derr.IsntError())
	{
		BigFatBootFSInfo	bfInfo;
		BootSector12		bb12;
		BootSector16		bb16;
		BootSector32		bb32;
		PGPUInt32			fat16Sig;
		PGPUInt64			pos;

		pgpAssert(sizeof(bb12) == kDefaultBlockSize);
		pgpAssert(sizeof(bb16) == kDefaultBlockSize);
		pgpAssert(sizeof(bb32) == kDefaultBlockSize);

		pgpClearMemory(blockBuf, kDefaultBlockSize);

		pos = 0;

		switch (fat.fdFsId)
		{

		case kFS_FAT12:
			// Init the boot block.
			InitFAT12BootBlock(GetBlockSize(), &fat, &bb12);

			// Write the boot block.
			derr = Write((PGPUInt8 *) &bb12, pos, 1);

			// Write the first FAT.
			if (derr.IsntError())
			{
				pgpCopyMemory((PGPUInt8 *) &kFat12Sig, blockBuf, 
					sizeof(kFat12Sig));

				pos += fat.fdReservedSecs;
				derr = Write(blockBuf, pos, 1);
			}

			// Write the second FAT.
			if (derr.IsntError())
			{
				pos += fat.fdFatSize;
				derr = Write(blockBuf, pos, 1);
			}
			break;

		case kFS_FAT16:
			// Init the boot block.
			InitFAT16BootBlock(GetBlockSize(), &fat, &bb16);

			// Decide on a FAT signature.
			fat16Sig = (megsDisk < 16 ? kUnder16MbFat16Sig : 
				kOver16MbFat16Sig);

			// Write the boot block.
			derr = Write((PGPUInt8 *) &bb16, pos, 1);

			// Write the first FAT.
			if (derr.IsntError())
			{
				pgpCopyMemory((PGPUInt8 *) &fat16Sig, blockBuf, 
					sizeof(fat16Sig));

				pos += fat.fdReservedSecs;
				derr = Write(blockBuf, pos, 1);
			}

			// Write the second FAT.
			if (derr.IsntError())
			{
				pos += fat.fdFatSize;
				derr = Write(blockBuf, pos, 1);
			}
			break;

		case kFS_FAT32:
			// Init the boot block.
			InitFAT32BootBlock(GetBlockSize(), &fat, &bb32, &bfInfo);

			// Write the boot block.
			derr = Write((PGPUInt8 *) &bb32, pos, 1);

			// Write the BigFatBootInfo structure.
			if (derr.IsntError())
			{
				pgpCopyMemory((PGPUInt8 *) &bfInfo, blockBuf, 
					sizeof(bfInfo));

				pos += bb32.bsFsInfoSec;
				derr = Write(blockBuf, pos, 1);
			}

			if (derr.IsntError())
			{
				PGPUInt32 threeClusts[3];

				threeClusts[0] = kFat32Clust1;
				threeClusts[1] = kFat32Clust2;
				threeClusts[2] = kFat32Clust3;

				pgpClearMemory(blockBuf, kDefaultBlockSize);
				pgpCopyMemory((PGPUInt8 *) &threeClusts, blockBuf, 
					sizeof(threeClusts));

				// Write the first FAT.
				pos = fat.fdReservedSecs;
				derr = Write(blockBuf, pos, 1);

				// Write the second FAT.
				if (derr.IsntError())
				{
					pos += fat.fdFatSize;
					derr = Write(blockBuf, pos, 1);
				}
			}
			break;

		default:
			pgpAssert(FALSE);
			break;
		}
	}

	// Unlock the volume.
	if (lockedForFormat)
	{
		UnlockVolume();
	}

	// Free our block buffer.
	if (allocedBlockBuf)
	{
		FreeByteBuffer(blockBuf);
	}

	return derr;
}
Ejemplo n.º 4
0
DWORD
_cdecl
main(
    int argc,
    char *argv[],
    char *envp[]
    )
{
    char Drive[MAX_PATH];
    HANDLE hDrive, hDiskImage;
    DISK_GEOMETRY Geometry;
    UINT i;
    char c, *p;
    LPSTR DriveName;
    BOOL fUsage = TRUE;
    BOOL fShowGeometry = FALSE;
    BOOL fDiskImage = FALSE;
    BOOL SourceIsDrive;
    LPSTR Source, Destination, DiskImage;

    if ( argc > 1 ) {
        fUsage = FALSE;
        while (--argc) {
            p = *++argv;
            if (*p == '/' || *p == '-') {
                while (c = *++p)
                switch (toupper( c )) {
                case '?':
                    fUsage = TRUE;
                    break;

                case 'C':
                    fDiskImage = TRUE;
                    argc--, argv++;
                    Source = *argv;
                    argc--, argv++;
                    Destination = *argv;
                    break;

                case 'G':
                    fShowGeometry = TRUE;
                    argc--, argv++;
                    DriveName = *argv;
                    break;

                default:
                    printf("MFMT: Invalid switch - /%c\n", c );
                    fUsage = TRUE;
                    break;
                    }
                }
            }
        }

    if ( fUsage ) {
        printf("usage: MFMT switches \n" );
        printf("            [-?] display this message\n" );
        printf("            [-g drive] shows disk geometry\n" );
        printf("            [-c source destination] produce diskimage\n" );
        ExitProcess(1);
        }

    if ( fShowGeometry ) {
        sprintf(Drive,"\\\\.\\%s",DriveName);
        hDrive = CreateFile(
                    Drive,
                    GENERIC_READ | GENERIC_WRITE,
                    0,
                    NULL,
                    OPEN_EXISTING,
                    0,
                    NULL
                    );
        if ( hDrive == INVALID_HANDLE_VALUE ) {
            printf("MFMT: Open %s failed %d\n",DriveName,GetLastError());
            ExitProcess(1);
            }

        LockVolume(hDrive);

        if ( !GetDiskGeometry(hDrive,&Geometry) ) {
            printf("MFMT: GetDiskGeometry %s failed %d\n",DriveName,GetLastError());
            ExitProcess(1);
            }
        PrintGeometry(DriveName,&Geometry);

        if ( !GetSupportedGeometrys(hDrive) ) {
            printf("MFMT: GetSupportedGeometrys %s failed %d\n",DriveName,GetLastError());
            ExitProcess(1);
            }
        printf("\nDrive %s supports the following disk geometries\n",DriveName);

        for(i=0;i<SupportedGeometryCount;i++) {
            printf("\n");
            PrintGeometry(NULL,&SupportedGeometry[i]);
            }

        printf("\n");
        ExitProcess(0);
        }

    if ( fDiskImage ) {
        SourceIsDrive = FALSE;
        if ( Source[strlen(Source)-1] == ':' ) {
            SourceIsDrive = TRUE;
            sprintf(Drive,"\\\\.\\%s",Source);
            DiskImage = Destination;
            }
        if ( Destination[strlen(Destination)-1] == ':' ) {
            if ( SourceIsDrive ) {
                printf("MFMT: Source and Destination cannot both be drives\n");
                ExitProcess(1);
                }
            SourceIsDrive = FALSE;
            sprintf(Drive,"\\\\.\\%s",Destination);
            DiskImage = Source;
            }
        else {
            if ( !SourceIsDrive ) {
                printf("MFMT: Either Source or Destination must be a drive\n");
                ExitProcess(1);
                }
            }

        //
        // Open and Lock the drive
        //

        hDrive = CreateFile(
                    Drive,
                    GENERIC_READ | GENERIC_WRITE,
                    0,
                    NULL,
                    OPEN_EXISTING,
                    0,
                    NULL
                    );
        if ( hDrive == INVALID_HANDLE_VALUE ) {
            printf("MFMT: Open %s failed %d\n",DriveName,GetLastError());
            ExitProcess(1);
            }
        LockVolume(hDrive);

        if ( !GetDiskGeometry(hDrive,&Geometry) ) {
            printf("MFMT: GetDiskGeometry %s failed %d\n",DriveName,GetLastError());
            ExitProcess(1);
            }

        if ( !GetSupportedGeometrys(hDrive) ) {
            printf("MFMT: GetSupportedGeometrys %s failed %d\n",DriveName,GetLastError());
            ExitProcess(1);
            }

        //
        // Open the disk image file
        //

        hDiskImage = CreateFile(
                        DiskImage,
                        GENERIC_READ | GENERIC_WRITE,
                        0,
                        NULL,
                        SourceIsDrive ? CREATE_ALWAYS : OPEN_EXISTING,
                        0,
                        NULL
                        );
        if ( hDiskImage == INVALID_HANDLE_VALUE ) {
            printf("MFMT: Open %s failed %d\n",DiskImage,GetLastError());
            ExitProcess(1);
            }

        //
        // Now do the copy
        //
        {
            LPVOID IoBuffer;
            BOOL b;
            DWORD BytesRead, BytesWritten;
            DWORD FileSize;
            DWORD GeometrySize;

            //
            // If we are copying from floppy to file, just do the copy
            // Otherwise, we might have to format the floppy first
            //

            if ( SourceIsDrive ) {

                //
                // Device reads must be sector aligned. VirtualAlloc will
                // garuntee alignment
                //

                GeometrySize = Geometry.Cylinders.LowPart *
                               Geometry.TracksPerCylinder *
                               Geometry.SectorsPerTrack *
                               Geometry.BytesPerSector;

                IoBuffer = VirtualAlloc(NULL,GeometrySize,MEM_COMMIT,PAGE_READWRITE);

                if ( !IoBuffer ) {
                    printf("MFMT: Buffer Allocation Failed\n");
                    ExitProcess(1);
                    }

                b = ReadFile(hDrive,IoBuffer, GeometrySize, &BytesRead, NULL);
                if (b && BytesRead){
                    b = WriteFile(hDiskImage,IoBuffer, BytesRead, &BytesWritten, NULL);
                    if ( !b || ( BytesRead != BytesWritten ) ) {
                        printf("MFMT: Fatal Write Error %d\n",GetLastError());
                        ExitProcess(1);
                        }
                    }
                else {
                    printf("MFMT: Fatal Read Error %d\n",GetLastError());
                    ExitProcess(1);
                    }
                }
            else {

                //
                // Check to see if the image will fit on the floppy. If it
                // will, then LowLevelFormat the floppy and press on
                //

                FileSize = GetFileSize(hDiskImage,NULL);

                b = FALSE;
                for(i=0;i<SupportedGeometryCount;i++) {
                    GeometrySize = SupportedGeometry[i].Cylinders.LowPart *
                                   SupportedGeometry[i].TracksPerCylinder *
                                   SupportedGeometry[i].SectorsPerTrack *
                                   SupportedGeometry[i].BytesPerSector;
                    if ( GeometrySize >= FileSize ) {

                        IoBuffer = VirtualAlloc(NULL,GeometrySize,MEM_COMMIT,PAGE_READWRITE);

                        if ( !IoBuffer ) {
                            printf("MFMT: Buffer Allocation Failed\n");
                            ExitProcess(1);
                            }

                        //
                        // Format the floppy
                        //

                        LowLevelFormat(hDrive,&SupportedGeometry[i]);

                        b = ReadFile(hDiskImage,IoBuffer, GeometrySize, &BytesRead, NULL);
                        if (b && BytesRead){
                            b = WriteFile(hDrive,IoBuffer, BytesRead, &BytesWritten, NULL);
                            if ( !b || ( BytesRead != BytesWritten ) ) {
                                printf("MFMT: Fatal Write Error %d\n",GetLastError());
                                ExitProcess(1);
                                }
                            }
                        else {
                            printf("MFMT: Fatal Read Error %d\n",GetLastError());
                            ExitProcess(1);
                            }
                        b = TRUE;
                        break;
                        }
                    }

                if ( !b ) {
                    printf("MFMT: FileSize %d is not supported on drive %s\n",FileSize,DriveName);
                    ExitProcess(1);
                    }
                }
        }

        //
        // Dismounting forces the filesystem to re-evaluate the media id
        // and geometry. This is the same as popping the floppy in and out
        // of the disk drive
        //

        DismountVolume(hDrive);
        UnlockVolume(hDrive);

        ExitProcess(0);
        }
}
Ejemplo n.º 5
0
Archivo: dd4.c Proyecto: mingpen/OpenNT
void _CRTAPI1 main( int cArgs, char *szArg[] )
{

    HANDLE Handle;
        int i, j, k;
    BOOLEAN fMore = FALSE;
    ULONG cbRead;
    char c, chLastCmd;
    ULONG lsn;
    BOOLEAN fModify = FALSE;
    ULONG AlignmentMask;

    /* See if we are connected to CON */
    fBatch = !isatty( 0 );

    switch( cArgs ) {
    case 2:
        /* Nothing to do for level 2 */
        break;

    case 3:
        if( strcmp( _strupr(szArg[2]), "/E" ) == 0 ) {
                fModify = TRUE;
            fprintf( stderr,
                "Warning: Opening drive %s for write access!\n", szArg[1] );
            break;
        } else {
            fprintf(stderr, "%s: Invalid option '%s'\n", szArg[0], szArg[2]);
        }

        /* Note fall through to default: (usage case) */

    default:
        if( cArgs > 3 )
            fprintf( stderr, "%s: Too many arguments\n", szArg[0] );
        fprintf( stderr, "usage: %s drive_or_file [/e]\n", szArg[0] );

    exit(-1);
        break;
    }

    if( !OpenFile( szArg[1], &Handle ) ){

        fprintf( stderr, "%s:  Unable to open %s\n", szArg[0], szArg[1] );

    exit(1);
    }

    if( !QueryVolumeInformation( Handle, &AlignmentMask, &SectorSize ) ) {

        fprintf( stderr, "Cannot determine volume information.\n" );
        exit(1);
    }


    // Allocate a buffer to read and write sectors.  Note that this
    // buffer has to satisfy the device's alignment restrictions.

    DataBuffer = (PBYTE)malloc( SectorSize + AlignmentMask );

    if( DataBuffer == NULL ) {

        fprintf( stderr, "Out of memory.\n" );

        exit(1);
    }

    SectorData = (PBYTE)(((ULONG)(DataBuffer) + AlignmentMask) & ~AlignmentMask);


    //

    /* check if we want to do writes with dasd */
    if( fModify && szArg[1][1] == '\\' && szArg[1][2] == ':' ) {

        // This is a drive, and we want to modify it, so we need
        // to lock it.

        if( !LockVolume( Handle ) ) {

            printf( "Unable to lock volume.\n" );

            exit(1);
        }
    }

    /* default to sector 0 */
    lsn = 0;

    PromptUsr();
    while( fgets(szCommand, sizeof( szCommand ), stdin) ){

        if( (i = sscanf( szCommand, "%c %li", &c, &lsn )) > 1 ) {
            /*
             * The user entered a lsn as well as a command,
             * convert it to byte seek pos
             */
            lsn *= SectorSize;
        }

        fMore = FALSE;
        c = (char)tolower( (int)c );

        /* pre process command */
        if( c == 'q' )
            break;

        switch( c ) {
        case 'b':
            if( i == 1 && chLastCmd == c ) {
                /* same command with no new lsn, use the next one on disk */
                lsn -= cbRead;
            }
            break;

        case 'm':
        case 'd':
        case 'e':
            if( i == 1 && chLastCmd == c ) {
                /* same command with no new lsn, use the next one on disk */
                lsn += cbRead;
            }
            break;

        default:
            fprintf(stderr,"Unknown command '%c'\n", c );
            fprintf(stderr,"   d [####]\tDump sector ####\n" );
            fprintf(stderr,"   e [####]\tEdit sector ####\n" );
            fprintf(stderr,"   m [####]\tDump sector with 'MORE'\n");
            fprintf(stderr,"   b [####]\tSame as 'd' but defaults to"
                                                      " previous sector\n");
            fprintf(stderr,"   q     \tquit the program" );
            fprintf(stderr,"\n"
      "\n If no new sector is given and the command is the same, the next"
      "\n sector on the disk is used.  If no sector is given but the command"
      "\n is different from the previous command, the sector used in the"
      "\n last command will be used again.\n"
                    );
            PromptUsr();
            continue;

        }

        /* remember last command */
        chLastCmd = c;
        cbRead = 0;

        if( !ReadSector( Handle, lsn, SectorData, &cbRead ) ) {

            printf( "Unable to read sector %lx\n", lsn );

        } else {

                printf( "\n lsn:0x%lX  bytes read:%d\n",
                                            lsn / SectorSize, cbRead );

                switch( c ) {
                case 'm':
                    /*
                     * More
                     */
                    fMore = TRUE;
                    /* fall through to Dump */

                case 'd':
                case 'b':
                    /*
                     * Dump
                     */
                    k = 0;

                    for( i = 0; i < cbRead; i += CB_LINE ) {

                        if( fMore && k++ == 20 ) {
                            printf( "\n--MORE--" );
                            MyGetChr();
                            printf( "\r" );
                            k = 0;
                        }

                        printf("\n%04X  ", i );

                        for( j = 0; j < CB_LINE && (j + i) < cbRead; j++ ) {
                            printf( "%02X ", (BYTE)SectorData[i + j] );
                        }

                        printf( "   " );
                        for( j = 0; j < CB_LINE && (j + i) < cbRead; j++ ) {
                            if( (c = SectorData[i + j]) >= ' ' && c <= '\177' )
                                putchar( c );
                            else
                                putchar( '.' );
                        }
                    }
                    putchar( '\n' );
                    break;

                case 'e':
                    /*
                     * Edit
                     */
                    if( !fModify ) {
                        printf( "Can not edit, restart with /e option\n" );
                    } else {

                        for( i = 0; i < cbRead; i++ ) {
                            if( (i % CB_INPUTLINE) == 0 ) {
                                /* print line header */
                                printf("\n%04X\t", i );
                            }

                            printf( "%02X.", (BYTE)SectorData[i] );
                            if( MyGetInput( &j, &c ) ) {
                                SectorData[i] = (BYTE)j;
                            } else {
                                printf( "%02X", (BYTE)SectorData[i] );
                            }

                            if( c == '\r' )
                                break;

                            putchar( '\t' );
                        }

                        printf( "\nWrite new data to sector? (Y/N)" );
                        c = (char)MyGetChr();
                        if( (c = (char)toupper( c )) == 'Y' ) {

                            /* User wants to save the data */
                            printf( "Yes...." );

                            if( !WriteSector( Handle, lsn, SectorData ) ) {

                                    fprintf( stderr,
                                             "Write failed\n" );

                            } else {

                                /* indicate success */
                                printf( "\t[Done]\n" );
                            }

                        } else {

                            /* user chickened out */
                            printf( "No....\t[Nothing written]\n" );
                        }
                    }
                    break;
                }
        }

        PromptUsr();
    }

    /* if this was a dasd open, then unlock the drive */
    if( fModify ) {
        UnlockVolume( Handle );
    }

    CloseFile( Handle );


    exit(0);
}
Ejemplo n.º 6
0
void
_CRTAPI1 main(
    int ArgC,
    char *ArgS[]
    )
{
    HANDLE  handle;
    ULONG   bytesRead;
    ULONG   lsn;
    int     i;
    int     j;
    int     lines;
    char    c;
    char    lastCmd;
    char    currentDrive[12];
    PPTE    partitionTable;
    BOOLEAN modify = FALSE;
    BOOLEAN more = FALSE;

    // Disable hard-error popups.
    SetErrorMode(TRUE);

    // See if we are connected to CON
    Batch = (BOOLEAN)(!isatty(0));

    switch (ArgC) {
    case 2:
        // Nothing to do for level 2
        break;

    case 3:
        if (strcmp(_strupr(ArgS[2]), "/E") == 0) {
                modify = TRUE;
            fprintf(stderr,
                "Warning: Opening drive %s for write access!\n", ArgS[1]);
            break;
        } else {
            fprintf(stderr, "%s: Invalid option '%s'\n", ArgS[0], ArgS[2]);
        }

        // Note fall through to default: (usage case)

    default:
        if (ArgC > 3)
            fprintf(stderr, "%s: Too many arguments\n", ArgS[0]);

        fprintf(stderr, "usage: %s diskno [/e]\n", ArgS[0]);

        // Re-enable harderror popups.
        SetErrorMode(FALSE);

        exit(-1);
        break;
    }

    sprintf(currentDrive, "%s", ArgS[1]);

    if (!OpenFile(currentDrive, &handle)) {

        fprintf(stderr,
                "%s:  Unable to open %s\n", ArgS[0], currentDrive);

        // Re-enable harderror popups.
        SetErrorMode(FALSE);

        exit(1);
    }

    // check if we want to do writes with dasd
    if (modify) {

        // This is a drive, and we want to modify it, so we need
        // to lock it.

        if (!LockVolume(handle)) {

            printf("Unable to lock volume.\n");

            // Re-enable harderror popups.
            SetErrorMode(FALSE);

            exit(1);
        }
    }

    // default to sector 0
    lsn = 0;

    while (1)
    {
        PromptUsr();

        if (fgets(Command, sizeof(Command), stdin) == NULL)
            break;

        if ((i = sscanf(Command, "%c %li", &c, &lsn)) > 1) {
            if ((c != 'c') && (c != 'C')) {
                /*
                 * The user entered a lsn as well as an lsn based command,
                 * convert it to byte seek pos
                 */
                lsn *= SECSIZE;
            }
        }

        more = FALSE;
        c = (char)tolower((int)c);

        // pre process command
        if (c == 'q')
            break;

        if (c == '\n')
            c = lastCmd;

        switch (c) {
        case 'b':
            if (i == 1 && lastCmd == c) {
                // same command with no new lsn, use the next one on disk
                lsn -= bytesRead;
            }
            break;

        case 'c':
            // change drives.

            if (i != 2) {
                fprintf(stderr,
                        "You must specify a drive number to change drives.\n");
                continue;
            }

            CloseFile(handle);
            sprintf(currentDrive, "%d", lsn);

            if (!OpenFile(currentDrive, &handle)) {

                fprintf(stderr,
                        "%s:  Unable to open %s\n", ArgS[0], currentDrive);

                // Re-enable harderror popups.
                SetErrorMode(FALSE);

                exit(1);
            }

            // check if we want to do writes with dasd
            if (modify) {

                // This is a drive, and we want to modify it, so we need
                // to lock it.

                if (!LockVolume(handle)) {

                    printf("Unable to lock volume.\n");

                    // Re-enable harderror popups.
                    SetErrorMode(FALSE);

                    exit(1);
                }
            }

            // default to sector 0
            lsn = 0;
            continue;

        case 'g':
        {
            DISK_GEOMETRY   diskGeometry;
            IO_STATUS_BLOCK statusBlock;
            NTSTATUS        status;

            // Get and display drive geometry from system.

            status = NtDeviceIoControlFile(handle,
                                           0,
                                           NULL,
                                           NULL,
                                           &statusBlock,
                                           IOCTL_DISK_GET_DRIVE_GEOMETRY,
                                           NULL,
                                           0,
                                           &diskGeometry,
                                           sizeof(DISK_GEOMETRY));

            if (NT_SUCCESS(status)) {
                printf("BytesPerSector:    %d\n", diskGeometry.BytesPerSector);
                printf("SectorsPerTrack:   %d\n", diskGeometry.SectorsPerTrack);
                printf("TracksPerCylinder: %d\n", diskGeometry.TracksPerCylinder);
                printf("NumberOfCylinders: %d\n", diskGeometry.Cylinders);
            } else {
                fprintf(stderr, "Could not get geometry %x\n", status);
            }
            continue;
        }

        case 'm':
        case 'd':
        case 'e':
        case 'p':
            if (i == 1 && lastCmd == c) {
                // same command with no new lsn, use the next one on disk
                lsn += bytesRead;
            }
        break;

        default:
            fprintf(stderr,"Unknown command '%c'\n", c);
        case 'h':
        case '?':
            fprintf(stderr,"   d [####]\tDump sector ####\n");
            fprintf(stderr,"   e [####]\tEdit sector ####\n");
            fprintf(stderr,"   m [####]\tDump sector with 'MORE'\n");
            fprintf(stderr,"   b [####]\tSame as 'd' but defaults to"
                              " previous sector\n");
            fprintf(stderr,"   c [##]\tChange harddisk number\n");
            fprintf(stderr,"   p [####]\tDump partition table on sector ###\n");
            fprintf(stderr,"   q     \tquit the program");
            fprintf(stderr,"\n"
         "\n If no new sector is given and the command is the same, the next"
         "\n sector on the disk is used.  If no sector is given but the command"
         "\n is different from the previous command, the sector used in the"
         "\n last command will be used again.\n"
            );
            continue;
        }

        // remember last command
        lastCmd = c;
        bytesRead = 0;

        if(!ReadSector(handle, lsn, Sector, &bytesRead)) {

            printf("Unable to read sector %lx\n", lsn);

        } else {

            printf("\n lsn:0x%lX  bytes read:%d\n", lsn / SECSIZE, bytesRead);

            switch (c) {
            case 'm':
                /*
                 * More
                 */
                more = TRUE;
                // fall through to Dump

            case 'd':
            case 'b':
                /*
                 * Dump
                 */
                lines = 0;
                HexLine[0] = '\0';
                CharLine[0] = '\0';
                i = 0;
                sprintf(HexLine, "%04X  ", i);

                for (i = 0; i < (int)bytesRead; i++) {

                    sprintf(HexLine, "%s%2x ", HexLine, Sector[i]);
                    sprintf(CharLine, "%s%c", CharLine,
                            (isprint(Sector[i])) ? Sector[i] : '.');

                    if ((i != 0) && ((i % 16) == 15))
                    {
                        printf("%s *%s*\n", HexLine, CharLine);
                        HexLine[0] = '\0';
                        sprintf(HexLine, "%04X  ", i + 1);
                        CharLine[0] = '\0';
                        lines++;
                    }

                    if (more && (lines == 20)) {
                        printf("\n--MORE--");
                        MyGetChr();
                        printf("\r");
                        lines = 0;
                    }
                }
                putchar('\n');
                break;

            case 'p':
                /*
                 * dump partition table
                 */

                if (LoadWORD(&Sector[SIGNATURE_OFFSET]) == 0xaa55) {
                    partitionTable = ((PBOOTSECTOR)Sector)->PartitionTable;

                    for (i = 0; i < 4; i++) {

                        printf("\nEntry #%u:\n",i);
                        printf("  Boot flag       : %u\n",
                               partitionTable[i].BootIndicator);
                        printf("  System ID       : %u\n",
                               partitionTable[i].SysID);
                        printf("  Relative sectors: %u (0x%x)\n",
                               LoadDWORD(&partitionTable[i].Relative0),
                               LoadDWORD(&partitionTable[i].Relative0));
                        printf("  Sector count    : %u (0x%x) [%u MB]\n",
                               LoadDWORD(&partitionTable[i].SectorCount0),
                               LoadDWORD(&partitionTable[i].SectorCount0),
                               (LoadDWORD(&partitionTable[i].SectorCount0) *
                                          SECSIZE) / (1024*1024));
                        printf("  Start CHS       : %u %u %u\n",
                           partitionTable[i].StartCylinder |
                               ((partitionTable[i].StartSector & 0xc0) << 2),
                           partitionTable[i].StartHead,
                           partitionTable[i].StartSector & 0x3f);
                        printf("  End CHS         : %u %u %u\n",
                           partitionTable[i].EndCylinder |
                               ((partitionTable[i].EndSector & 0xc0) << 2),
                           partitionTable[i].EndHead,
                           partitionTable[i].EndSector & 0x3f);
                    }

                } else {
                    printf("\nSector %u is not a valid master boot sector.\n",
                           lsn/SECSIZE);
                }
                break;

            case 'e':
                /*
                 * Edit
                 */
                if (!modify) {

                    printf("Can not edit, restart with /e option\n");

                } else {

                    for (i = 0; i < (int)bytesRead; i++) {
                            if ((i % CB_INPUTLINE) == 0) {
                                // print line header
                                printf("\n%04X\t", i);
                            }

                            printf("%02X.", (BYTE)Sector[i]);

                            if (MyGetInput(&j, &c )) {

                                Sector[i] = (BYTE)j;

                            } else {

                                printf("%02X", (BYTE)Sector[i]);

                            }

                            if (c == '\r')
                                break;

                            putchar('\t');
                        }

                        printf("\nWrite new data to sector? (Y/N)");
                        c = (char)MyGetChr();
                        if ((c = (char)toupper(c)) == 'Y') {

                            // User wants to save the data
                            printf("Yes....");

                            if (!WriteSector(handle, lsn, Sector)) {

                                    fprintf(stderr, "Write failed\n");

                            } else {

                                // indicate success
                                printf("\t[Done]\n");
                            }

                        } else {

                            // user chickened out
                            printf("No....\t[Nothing written]\n");
                        }
                }
                break;
            }
        }
    }

    // if this was a dasd open, then unlock the drive
    if (modify) {
        UnlockVolume(handle);
    }

    CloseFile(handle);

    // Re-enable harderror popups.
    SetErrorMode(FALSE);

    exit(0);
}