home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Devices and Hardware / Disks / BasicDiskImage / BasicDiskImage.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  8.1 KB  |  323 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        BasicDiskImage.c
  3.  
  4.     Contains:    Puts the contents of a disk in a file.
  5.  
  6.     Written by:    Q
  7.  
  8.     Copyright:    Copyright © 1999 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.  
  20. */
  21.  
  22. /////////////////////////////////////////////////////////////////
  23.  
  24. // MIB Setup
  25.  
  26. #include "MoreSetup.h"
  27.  
  28. // Mac OS Interfaces
  29.  
  30. #include <Files.h>
  31. #include <Devices.h>
  32. #include <MacMemory.h>
  33. #include <Navigation.h>
  34. #include <StandardFile.h>
  35.  
  36. // Standard C interfaces
  37.  
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40.  
  41. // MoreIsBetter Interfaces
  42.  
  43. #include "MoreDisks.h"
  44.  
  45. /////////////////////////////////////////////////////////////////
  46.  
  47. static void SetWidePosOffset(UInt32 blockOffset, XIOParamPtr pb)
  48.     // Set up ioPosMode and either ioPosOffset or ioWPosOffset for a
  49.     // device _Read or _Write.
  50.     //
  51.     // Code stolen from Technote 1189.
  52. {
  53.     pb->ioWPosOffset.lo = blockOffset << 9;  // convert block number
  54.     pb->ioWPosOffset.hi = blockOffset >> 23; // to wide byte offset
  55.  
  56.     if ( pb->ioWPosOffset.hi != 0 ) {
  57.         // Offset on drive is >= 4G, so use wide positioning mode
  58.         pb->ioPosMode = fsFromStart | (1 << kWidePosOffsetBit);
  59.     } else {
  60.         // Offset on drive is < 4G, so use regular positioning mode,
  61.         // and move the offset into ioPosOffset
  62.         pb->ioPosMode = fsFromStart;
  63.         ((IOParam *)pb)->ioPosOffset = pb->ioWPosOffset.lo;
  64.     }
  65. }
  66.  
  67. /////////////////////////////////////////////////////////////////
  68.  
  69. enum {
  70.     kBufferSize = 1024L * 1024L        // Do the copy in 1 MB chunks.
  71. };
  72.  
  73. static OSStatus ImageDiskToFile(SInt16 driveNumber, UInt32 startBlock, UInt32 numBlocks, const FSSpec *fss)
  74.     // Creates a file at fss containing the contents of blocks [startBlock..startBlock + numBlocks)
  75.     // of the drive specified by driveNumber.
  76. {
  77.     OSStatus err;
  78.     OSStatus junk;
  79.     Ptr bufferPtr;
  80.     SInt16 fileRefNum;
  81.     XIOParam pb;
  82.     UInt32 thisBlock;
  83.     UInt32 lastBlock;
  84.     UInt32 blocksThisTime;
  85.     SInt32 bytesToWrite;
  86.  
  87.     bufferPtr = nil;
  88.     fileRefNum = 0;
  89.     
  90.     // Create and open the file, and then allocate our memory buffer.
  91.     
  92.     junk = FSpCreate(fss, 'hDmp', 'BINA', 0);
  93.     err  = FSpOpenDF(fss, fsWrPerm, &fileRefNum);
  94.     if (err == noErr) {
  95.         bufferPtr = NewPtr(kBufferSize);
  96.         err = MemError();
  97.     }
  98.     if (err == noErr) {
  99.  
  100.         // Set up constant parts of param block.
  101.  
  102.         pb.ioRefNum    = MoreGetDriveRefNum(driveNumber);
  103.         pb.ioVRefNum   = driveNumber;
  104.         pb.ioBuffer    = bufferPtr;
  105.         pb.ioPosMode   = fsFromStart;
  106.  
  107.         // Loop, reading blocks from the disk and writing them to the file until we're out of blocks.
  108.         
  109.         thisBlock = startBlock;
  110.         lastBlock = startBlock + numBlocks;
  111.         while ( (err == noErr) && (thisBlock != lastBlock) ) {
  112.             if ( (lastBlock - thisBlock) > (kBufferSize / 512) ) {
  113.                 blocksThisTime = (kBufferSize / 512);
  114.             } else {
  115.                 blocksThisTime = (lastBlock - thisBlock);
  116.             }
  117.             pb.ioReqCount  = blocksThisTime * 512;
  118.             SetWidePosOffset(thisBlock, &pb);
  119.             err = PBReadSync( (ParmBlkPtr) &pb);
  120.             if (err == noErr) {
  121.                 bytesToWrite = blocksThisTime * 512;
  122.                 err = FSWrite(fileRefNum, &bytesToWrite, bufferPtr);
  123.             }
  124.             if (err == noErr) {
  125.                 thisBlock += blocksThisTime;
  126.                 
  127.                 // Show some progress.
  128.                 
  129.                 printf(".");
  130.                 fflush(stdout);
  131.             }
  132.         }
  133.     }
  134.  
  135.     // Clean up.
  136.     
  137.     if ( fileRefNum != 0 ) {
  138.         junk = FSClose(fileRefNum);
  139.         MoreAssertQ(junk == noErr);
  140.     }
  141.     if (bufferPtr != nil) {
  142.         DisposePtr(bufferPtr);
  143.         MoreAssertQ(MemError() == noErr);
  144.     }
  145.     
  146.     return err;
  147. }
  148.  
  149. /////////////////////////////////////////////////////////////////
  150.  
  151. static void DoListDriveQueue(void)
  152.     // Prints a list of drives and their sizes.  Stolen from the test
  153.     // code for the MoreDisks module of MoreIsBetter.
  154. {
  155.     SInt16 index;
  156.     DrvQElPtr thisDrv;
  157.     UInt32 sizeInBlocks;
  158.     MoreDisksCDROMResponse isCDResponse;
  159.     char cdChar;
  160.  
  161.     printf("List of drives:\n");
  162.     printf("DrvNum Size\n");
  163.     index = 1;
  164.     do {
  165.         thisDrv = MoreGetIndDrive(index);
  166.         if (thisDrv != nil) {
  167.             if ( MoreGetDriveSize(thisDrv->dQDrive, &sizeInBlocks) != noErr ) {
  168.                 sizeInBlocks = 0;
  169.             }
  170.             MoreIsDriveCDROM(thisDrv->dQDrive, &isCDResponse);
  171.             switch (isCDResponse) {
  172.                 case kMoreDriveUnableToDetermineCDROM: cdChar = '?'; break;
  173.                 case kMoreDriveIsCDROM: cdChar = 'C'; break;
  174.                 case kMoreDriveIsNotCDROM: cdChar = 'N'; break;
  175.                 default:
  176.                     MoreAssertQ(false);
  177.                     break;
  178.             }
  179.             
  180.             printf("%6d %8ld (%c)\n", thisDrv->dQDrive, sizeInBlocks, cdChar);
  181.             index += 1;
  182.         }
  183.     } while (thisDrv != nil);
  184. }
  185.  
  186. /////////////////////////////////////////////////////////////////
  187.  
  188. // I wrote all the code to allow the user to choose where to save the 
  189. // file using Nav, then remembered that I wanted to be able to run this
  190. // program even on systems that don't have Nav.  So it was back to Standard
  191. // File.
  192.  
  193. #if 0
  194.  
  195. static OSStatus NavExtractSingleReply(const NavReplyRecord *reply, FSSpec *fss)
  196. {
  197.     OSStatus err;
  198.     SInt32 itemCount;
  199.     AEKeyword junkKeyword;
  200.     DescType junkDescType;
  201.     Size junkSize;
  202.     
  203.     MoreAssertQ( (AECountItems(&reply->selection, &itemCount) == noErr) && (itemCount == 1));
  204.     
  205.     err = AEGetNthPtr(&reply->selection,
  206.                                  1,
  207.                                  typeFSS,
  208.                                  &junkKeyword,
  209.                                  &junkDescType,
  210.                                  fss,
  211.                                  sizeof(*fss),
  212.                                  &junkSize);
  213.     if (err == noErr) {
  214.         MoreAssertQ(junkDescType == typeFSS);
  215.         MoreAssertQ(junkSize == sizeof(*fss));
  216.         
  217.         // If Nav gave us a bogus FSSpec, fix it.
  218.         
  219.         if ( fss->name[0] == 0 ) {
  220.             (void) FSMakeFSSpec(fss->vRefNum, fss->parID, fss->name, fss);
  221.         }
  222.     }
  223.     return err;
  224. }
  225.  
  226. {
  227.     NavReplyRecord reply;
  228.     NavDialogOptions options;
  229.     
  230.     err = NavGetDefaultDialogOptions(&options);
  231.     if (err == noErr) {
  232.         err = NavPutFile(nil, &reply, &options, nil, 'BINA', 'hDmp', nil);
  233.         if (err == noErr) {
  234.             err = NavExtractSingleReply(&reply, &fss);
  235.         }
  236.         junk = NavDisposeReply(&reply);
  237.         MoreAssertQ(junk == noErr);
  238.     }
  239. }
  240.  
  241. #endif
  242.  
  243. /////////////////////////////////////////////////////////////////
  244.  
  245. void main(void)
  246.     // The main entry point.  Ask the user to choose a disk, select
  247.     // a section of the disk to save, and then choose a file for
  248.     // where to place the disk image.
  249. {
  250.     OSStatus err;
  251.     char tmpStr[256];
  252.     SInt16 driveNum;
  253.     UInt32 sizeInBlocks;
  254.     UInt32 startBlock;
  255.     UInt32 blocksToRead;
  256.     FSSpec fss;
  257.     
  258.     printf("BasicDiskImage\n");
  259.     printf("-- A program to copy the entire contents of a disk to a file.\n");
  260.  
  261.     DoListDriveQueue();
  262.  
  263.     printf("Enter a drive number:\n");
  264.     gets(tmpStr);
  265.     driveNum = atol(tmpStr);
  266.     
  267.     err = MoreGetDriveSize(driveNum, &sizeInBlocks);
  268.     if (err == noErr) {
  269.         printf("Enter the first block number to image (return for 0).\n");
  270.         gets(tmpStr);
  271.         if (tmpStr[0] == 0) {
  272.             startBlock = 0;
  273.         } else {
  274.             startBlock = atol(tmpStr);
  275.         }
  276.         if (startBlock >= sizeInBlocks) {
  277.             printf("startBlock must be less than sizeInBlocks.\n");
  278.             err = userCanceledErr;
  279.         }
  280.     }
  281.     if (err == noErr) {
  282.         printf("Enter the number of blocks to image (return for all).\n");
  283.         gets(tmpStr);
  284.         if (tmpStr[0] == 0) {
  285.             blocksToRead = sizeInBlocks - startBlock;
  286.         } else {
  287.             blocksToRead = atol(tmpStr);
  288.         }
  289.         if (blocksToRead > sizeInBlocks) {
  290.             printf("blocksToRead must be less than sizeInBlocks.\n");
  291.             err = userCanceledErr;
  292.         }
  293.         if ((startBlock + blocksToRead) > sizeInBlocks) {
  294.             printf("startBlock + blocksToRead must be less than or equal to sizeInBlocks.\n");
  295.             err = userCanceledErr;
  296.         }
  297.     }
  298.     if (err == noErr) {
  299.         StandardFileReply reply;
  300.         
  301.         StandardPutFile("\pSave a basic disk image:", "\pBasic Disk Image", &reply);
  302.         if (reply.sfGood) {
  303.             fss = reply.sfFile;
  304.             if (reply.sfReplacing) {
  305.                 err = FSpDelete(&fss);
  306.             }
  307.         } else {
  308.             err = userCanceledErr;
  309.         }
  310.     }
  311.     if (err == noErr) {
  312.         err = ImageDiskToFile(driveNum, startBlock, blocksToRead, &fss);
  313.         printf("\n");
  314.     }
  315.  
  316.     if (err == noErr) {
  317.         printf("Success.\n");
  318.     } else {
  319.         printf("Failed with error %ld.\n", err);
  320.     }
  321.     
  322.     printf("Done.  Press command-Q to Quit.\n");
  323. }