Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
BasicDiskImage.c
/* |
File: BasicDiskImage.c |
Contains: Puts the contents of a disk in a file. |
Written by: Q |
Copyright: Copyright © 1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
*/ |
///////////////////////////////////////////////////////////////// |
// MIB Setup |
#include "MoreSetup.h" |
// Mac OS Interfaces |
#include <Files.h> |
#include <Devices.h> |
#include <MacMemory.h> |
#include <Navigation.h> |
#include <StandardFile.h> |
// Standard C interfaces |
#include <stdio.h> |
#include <stdlib.h> |
// MoreIsBetter Interfaces |
#include "MoreDisks.h" |
///////////////////////////////////////////////////////////////// |
static void SetWidePosOffset(UInt32 blockOffset, XIOParamPtr pb) |
// Set up ioPosMode and either ioPosOffset or ioWPosOffset for a |
// device _Read or _Write. |
// |
// Code stolen from Technote 1189. |
{ |
pb->ioWPosOffset.lo = blockOffset << 9; // convert block number |
pb->ioWPosOffset.hi = blockOffset >> 23; // to wide byte offset |
if ( pb->ioWPosOffset.hi != 0 ) { |
// Offset on drive is >= 4G, so use wide positioning mode |
pb->ioPosMode = fsFromStart | (1 << kWidePosOffsetBit); |
} else { |
// Offset on drive is < 4G, so use regular positioning mode, |
// and move the offset into ioPosOffset |
pb->ioPosMode = fsFromStart; |
((IOParam *)pb)->ioPosOffset = pb->ioWPosOffset.lo; |
} |
} |
///////////////////////////////////////////////////////////////// |
enum { |
kBufferSize = 1024L * 1024L // Do the copy in 1 MB chunks. |
}; |
static OSStatus ImageDiskToFile(SInt16 driveNumber, UInt32 startBlock, UInt32 numBlocks, const FSSpec *fss) |
// Creates a file at fss containing the contents of blocks [startBlock..startBlock + numBlocks) |
// of the drive specified by driveNumber. |
{ |
OSStatus err; |
OSStatus junk; |
Ptr bufferPtr; |
SInt16 fileRefNum; |
XIOParam pb; |
UInt32 thisBlock; |
UInt32 lastBlock; |
UInt32 blocksThisTime; |
SInt32 bytesToWrite; |
bufferPtr = nil; |
fileRefNum = 0; |
// Create and open the file, and then allocate our memory buffer. |
junk = FSpCreate(fss, 'hDmp', 'BINA', 0); |
err = FSpOpenDF(fss, fsWrPerm, &fileRefNum); |
if (err == noErr) { |
bufferPtr = NewPtr(kBufferSize); |
err = MemError(); |
} |
if (err == noErr) { |
// Set up constant parts of param block. |
pb.ioRefNum = MoreGetDriveRefNum(driveNumber); |
pb.ioVRefNum = driveNumber; |
pb.ioBuffer = bufferPtr; |
pb.ioPosMode = fsFromStart; |
// Loop, reading blocks from the disk and writing them to the file until we're out of blocks. |
thisBlock = startBlock; |
lastBlock = startBlock + numBlocks; |
while ( (err == noErr) && (thisBlock != lastBlock) ) { |
if ( (lastBlock - thisBlock) > (kBufferSize / 512) ) { |
blocksThisTime = (kBufferSize / 512); |
} else { |
blocksThisTime = (lastBlock - thisBlock); |
} |
pb.ioReqCount = blocksThisTime * 512; |
SetWidePosOffset(thisBlock, &pb); |
err = PBReadSync( (ParmBlkPtr) &pb); |
if (err == noErr) { |
bytesToWrite = blocksThisTime * 512; |
err = FSWrite(fileRefNum, &bytesToWrite, bufferPtr); |
} |
if (err == noErr) { |
thisBlock += blocksThisTime; |
// Show some progress. |
printf("."); |
fflush(stdout); |
} |
} |
} |
// Clean up. |
if ( fileRefNum != 0 ) { |
junk = FSClose(fileRefNum); |
MoreAssertQ(junk == noErr); |
} |
if (bufferPtr != nil) { |
DisposePtr(bufferPtr); |
MoreAssertQ(MemError() == noErr); |
} |
return err; |
} |
///////////////////////////////////////////////////////////////// |
static void DoListDriveQueue(void) |
// Prints a list of drives and their sizes. Stolen from the test |
// code for the MoreDisks module of MoreIsBetter. |
{ |
SInt16 index; |
DrvQElPtr thisDrv; |
UInt32 sizeInBlocks; |
MoreDisksCDROMResponse isCDResponse; |
char cdChar; |
printf("List of drives:\n"); |
printf("DrvNum Size\n"); |
index = 1; |
do { |
thisDrv = MoreGetIndDrive(index); |
if (thisDrv != nil) { |
if ( MoreGetDriveSize(thisDrv->dQDrive, &sizeInBlocks) != noErr ) { |
sizeInBlocks = 0; |
} |
MoreIsDriveCDROM(thisDrv->dQDrive, &isCDResponse); |
switch (isCDResponse) { |
case kMoreDriveUnableToDetermineCDROM: cdChar = '?'; break; |
case kMoreDriveIsCDROM: cdChar = 'C'; break; |
case kMoreDriveIsNotCDROM: cdChar = 'N'; break; |
default: |
MoreAssertQ(false); |
break; |
} |
printf("%6d %8ld (%c)\n", thisDrv->dQDrive, sizeInBlocks, cdChar); |
index += 1; |
} |
} while (thisDrv != nil); |
} |
///////////////////////////////////////////////////////////////// |
// I wrote all the code to allow the user to choose where to save the |
// file using Nav, then remembered that I wanted to be able to run this |
// program even on systems that don't have Nav. So it was back to Standard |
// File. |
#if 0 |
static OSStatus NavExtractSingleReply(const NavReplyRecord *reply, FSSpec *fss) |
{ |
OSStatus err; |
SInt32 itemCount; |
AEKeyword junkKeyword; |
DescType junkDescType; |
Size junkSize; |
MoreAssertQ( (AECountItems(&reply->selection, &itemCount) == noErr) && (itemCount == 1)); |
err = AEGetNthPtr(&reply->selection, |
1, |
typeFSS, |
&junkKeyword, |
&junkDescType, |
fss, |
sizeof(*fss), |
&junkSize); |
if (err == noErr) { |
MoreAssertQ(junkDescType == typeFSS); |
MoreAssertQ(junkSize == sizeof(*fss)); |
// If Nav gave us a bogus FSSpec, fix it. |
if ( fss->name[0] == 0 ) { |
(void) FSMakeFSSpec(fss->vRefNum, fss->parID, fss->name, fss); |
} |
} |
return err; |
} |
{ |
NavReplyRecord reply; |
NavDialogOptions options; |
err = NavGetDefaultDialogOptions(&options); |
if (err == noErr) { |
err = NavPutFile(nil, &reply, &options, nil, 'BINA', 'hDmp', nil); |
if (err == noErr) { |
err = NavExtractSingleReply(&reply, &fss); |
} |
junk = NavDisposeReply(&reply); |
MoreAssertQ(junk == noErr); |
} |
} |
#endif |
///////////////////////////////////////////////////////////////// |
void main(void) |
// The main entry point. Ask the user to choose a disk, select |
// a section of the disk to save, and then choose a file for |
// where to place the disk image. |
{ |
OSStatus err; |
char tmpStr[256]; |
SInt16 driveNum; |
UInt32 sizeInBlocks; |
UInt32 startBlock; |
UInt32 blocksToRead; |
FSSpec fss; |
printf("BasicDiskImage\n"); |
printf("-- A program to copy the entire contents of a disk to a file.\n"); |
DoListDriveQueue(); |
printf("Enter a drive number:\n"); |
gets(tmpStr); |
driveNum = atol(tmpStr); |
err = MoreGetDriveSize(driveNum, &sizeInBlocks); |
if (err == noErr) { |
printf("Enter the first block number to image (return for 0).\n"); |
gets(tmpStr); |
if (tmpStr[0] == 0) { |
startBlock = 0; |
} else { |
startBlock = atol(tmpStr); |
} |
if (startBlock >= sizeInBlocks) { |
printf("startBlock must be less than sizeInBlocks.\n"); |
err = userCanceledErr; |
} |
} |
if (err == noErr) { |
printf("Enter the number of blocks to image (return for all).\n"); |
gets(tmpStr); |
if (tmpStr[0] == 0) { |
blocksToRead = sizeInBlocks - startBlock; |
} else { |
blocksToRead = atol(tmpStr); |
} |
if (blocksToRead > sizeInBlocks) { |
printf("blocksToRead must be less than sizeInBlocks.\n"); |
err = userCanceledErr; |
} |
if ((startBlock + blocksToRead) > sizeInBlocks) { |
printf("startBlock + blocksToRead must be less than or equal to sizeInBlocks.\n"); |
err = userCanceledErr; |
} |
} |
if (err == noErr) { |
StandardFileReply reply; |
StandardPutFile("\pSave a basic disk image:", "\pBasic Disk Image", &reply); |
if (reply.sfGood) { |
fss = reply.sfFile; |
if (reply.sfReplacing) { |
err = FSpDelete(&fss); |
} |
} else { |
err = userCanceledErr; |
} |
} |
if (err == noErr) { |
err = ImageDiskToFile(driveNum, startBlock, blocksToRead, &fss); |
printf("\n"); |
} |
if (err == noErr) { |
printf("Success.\n"); |
} else { |
printf("Failed with error %ld.\n", err); |
} |
printf("Done. Press command-Q to Quit.\n"); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14