home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 155_01 / disk3.c < prev    next >
Text File  |  1979-12-31  |  14KB  |  454 lines

  1. /*
  2.     DISK UTILITY PROGRAM
  3.  
  4.     Written by Richard Damon
  5.     Modified by Alexander von Obert
  6.     Buergweg 13, D-8500 Nuernberg, W. Germany
  7.     Tel. (0)911/57 13 74 or (0)761/4011-371
  8.  
  9.     Version 2.0, December 1984
  10.  
  11.     This program allows the operator to examine and modify
  12. a CPM diskette. All information needed about the specific
  13. format is fetched from the CP/M 2.X BIOS. 
  14. Compile with: CC disk3 -e2500 when using L2.COM
  15.  
  16.     The commands available in this package are :
  17.  
  18. Tn  set current track to n 
  19. Sn  set current sector to n
  20. Dn  set current disk number to n 
  21. Bn  set current track and sector to point to block n 
  22. N   set current track and sector to next sector/block
  23.     next sector if last set command was for track or sector
  24.     next block if last set command was for block
  25. I   turn off sector scewing, if used by this installation.
  26.     Turned on again by nxt Dn command
  27. R   read sector/block into buffer
  28. W   write sector/block from buffer
  29. P   print out contents of buffer, along with 
  30.     track/sector/block information
  31. Ea n n n n
  32.     edit buffer starting from location a filling 
  33.     with values n n n.
  34. Fn  Fill buffer with value n
  35. X   exit program
  36. M   print disk allocation map
  37.  
  38. Notes:
  39.     1)  Multiple commands may be specified on a line except for X
  40.     which must be the only command on the line followed by return.
  41.     2)  Commands may be in upper or lower case letters
  42.     3)  Spaces are ignored except in the E command where they are used
  43.     as separaters for the numbers
  44.  
  45. Typical commands:
  46. d0t0s1rp    read in the track 0 sector 1 of disk 0 (Drive A) 
  47.         and print it
  48. e1A 4F 20 11    set buffer location 1A to 4F, 1B to 20, and 1C to 11.
  49. e0a 00w        set buffer location 0a to 0 and write buffer
  50.             Note no space after last data byte
  51. nrp        get next buffer and print it
  52.  
  53. Disk Allocation Map
  54.     The M command is designed to allow the directory blocks 
  55. (the first blocks after th reserved tracks) to be printed out in a 
  56. convinient format. The directory is print out in the following format:
  57.  
  58.  Section 1:
  59.     The top half of the directory listing is a listing of the name
  60.     inforamtion of the directory entries.  Each line corresponds to 
  61.     1 sector of the directory.  A typical entry would be:
  62.     f=DISKTESTCOM/1 4c
  63.     The first letter is a code letter used to referance into section 2.
  64.     The equal sign indicats that the file exists, a star here indicates
  65.       that this entry is a deleted file.
  66.     Next comes the filename and extension.
  67.     The following /n is printed if this is other then the first extent 
  68.       (extent 0) of a file where n is the extent number of this entry.
  69.     The following number is the hex record count for this extent.
  70.  
  71.  Section 2:
  72.     The bottom half of the directory listing is a disk allocation 
  73.     map showing which blocks are in use and by which file. Free blocks 
  74.     are indicated by a dot while used blocks are marked by the file 
  75.     control etter asigned to a file in section 1.  This listing has been 
  76.     blocked off in groups of 8 and 16 to ease reading.
  77.  
  78. If a particular disk format uses more than 64 directory entries, more
  79. maps may be printed. All blocks used in previously shown maps are marked
  80. in section 2 by '@'.
  81.  
  82. CPM FILE STRUCTURE
  83.  
  84.     To help the user of this program the following is a brief description
  85. of the format used in CPM.  The first 2 or so tracks of a disk are 
  86. reserved for the bootstrap and the copy of the CPM operating system or to 
  87. divide a large (Winchester-)drive inseveral logical units. The following 
  88. tracks, according to the capacity given in the disk prameter block (DPB), 
  89. store the data of this logical drive.  To speed up disk access, CPM allows 
  90. to store consecutive data in not consecutive sectors.  Instead the designer 
  91. of the bios may choose to skip e.g. 5 physical sectors between logically
  92. following sectors. This allows to read, compute and read again more
  93. than one sector per turn of the disk. The designer puts a translation
  94. table in the BIOS. For a skip factor of 6 this list is:
  95.  1 7 13 19 25 5 11 17 23 3 9 15 21 2 8 14 20 26 6 12 18 24 4 10 16 22
  96. This interleaving is taken care of when reading in multiple sectors
  97. or when incrementing the disk address with the N command.
  98.      To simplify the disk allocation scheme the sectors are the collected 
  99. into groups of 8, 16 or more, called blocks. These blocks are numbered 
  100. from 0 starting at the beginning of the dirctory. 
  101.     The directory is organized to use the first block(s) of storage to
  102. store information on the file extensions.  A file extension is a part of 
  103. a file.  The directory entry for a file extension is as follows:
  104.  
  105. byte  0   : file code : 0 if file exists, E5 if file is deleted
  106. byte  1- 8: file name : ascii representation of file name
  107. byte  9-11: file type : ascii representation of file type
  108. byte 12   : file ext  : binary number for extent number
  109. byte 13,14: unused
  110. byte 15   : rec count : count of number of sectors in extent
  111. byte 16-31: map       : list of block numbers used by this extent
  112.  
  113. */
  114. /* Two data structures are extracted from the bios:
  115. */
  116. int    *dph;        /* disk parameter header, contains
  117.                following information:            */
  118. #define    XLT    0    /* address of logical to physical
  119.                translation vector                */
  120. #define    DPB    5    /* address o disk parameter block        */
  121.  
  122. char    *dpb;        /* disk parameter block, contains
  123.                following information:            */
  124. #define    SPT    0    /* int, number of sectors per track        */
  125. #define    BSH    2    /* byte, data allocation block shift factor    */
  126. #define    BLM    3    /* byte, data allocation block length mark    */
  127. #define    DSM    5    /* int, total storage capacity of drive        */
  128. #define    DRM    7    /* int, number of directory entries        */
  129. #define    OFF    13    /* int, number of reserved tracks        */
  130.  
  131. #define    MAXL    4    /* maximum block length (kByte)            */
  132. #define MAXB    1000    /* maximum number of blocks            */
  133. #define    MAXE    192    /* maximum number of directory entries        */
  134. #define STAT    1    /* set true, if you want a STAT DSK: like
  135.                (but more detailled) display every time
  136.                you exit a Dn command            */
  137. #define    MINS    0    /* maybe you must change that to 1        */
  138.             /* for those withot a copy of the CP/M alternation 
  139.                guide: names of the BIOS enty points:    */
  140. #define SELDSK    9    /* next drive to access, C=0 --> A:        */
  141. #define SETTRK    10    /* BC = next track to access            */
  142. #define SETSEC    11    /* BC = next sector to access            */
  143. #define SETDMA    12    /* BC = start of 128 byte file buffer        */
  144. #define READ    13    /* read, on RET: A=0: ok, A=1: read error    */
  145. #define WRITE    14    /* wite, on RET: A=0: ok,A=1: write error    */
  146.  
  147. int    maxtrk, maxsec, maxblk, blockl, restrk, entries, capac, longbn;
  148. char    *physlog, buff[80], *bufp;
  149.  
  150. main(){
  151.     int track,sector,disk,nsect,t,s,i,j,k,l,block,d;
  152.     char buffer[1024*MAXB],c,mc;
  153.     char dir[32*MAXE],map[MAXB];
  154.  
  155.     puts ("\nDisk Utility Program V 2.0\n");
  156.     disk=getdiskp(bdos(25));
  157.     track=0;
  158.     sector=MINS;
  159.     nsect=1;
  160.     puts("\nDUP>");
  161.     while(tolower(*(bufp=gets(buff))) != 'x' || *(bufp+1) != '\0'){
  162.         while((c=*bufp++) != '\0')
  163.         switch(toupper(c)){
  164.             case 'T' : track=getnum(&bufp,0,maxtrk-1,10);
  165.                 nsect=1;
  166.                 break;
  167.             case 'S' : sector=getnum(&bufp,MINS,maxsec-1+MINS,10);
  168.                 nsect=1;
  169.                 break;
  170.             case 'D' : disk=getdiskp(getnum(&bufp,0,15,10));
  171.                 break;
  172.             case 'B' : block=getnum(&bufp,0,maxblk-1,16);
  173.                 nsect=8*blockl;
  174.                 track=restrk+(block*blockl*8)/maxsec;
  175.                 sector=(block*8*blockl)%maxsec;
  176.                 break;
  177.             case 'N' : sector+=nsect;
  178.                 if(!update(§or,&track))sector-=nsect;
  179.                 break;
  180.             case 'I' : 
  181.                 break;
  182.             case 'R' : bios(SELDSK,disk);
  183.                 t=track;
  184.                 s=sector;
  185.                 for(i=0;i<nsect;i++){
  186.                     bios(SETTRK,t);
  187.                     bios(SETSEC,transl(s));
  188.                     bios(SETDMA,&buffer[i*128]);
  189.                     if(bios(READ))puts("\nCan't read");
  190.                     if(i!=nsect-1){
  191.                         s++;
  192.                         if(!update(&s,&t)){
  193.                             s--;
  194.                             break;
  195.                         }
  196.                     }
  197.                 }
  198.                 break;
  199.             case 'W' : bios(SELDSK,disk);
  200.                 t=track;
  201.                 s=sector;
  202.                 for(i=0;i<nsect;i++){
  203.                     bios(SETTRK,t);
  204.                     bios(SETSEC,transl(s));
  205.                     bios(SETDMA,&buffer[i*128]);
  206.                     if(bios(WRITE))puts("\NCan't write");
  207.                     bdos(13);
  208.                     if(i!=nsect-1){
  209.                         s++;
  210.                         if(!update(&s,&t)){
  211.                             s-=1;
  212.                             break;
  213.                         }
  214.                     }
  215.                 }
  216.                 break;
  217.             case 'P' : block=sector+(track-restrk)*maxsec;
  218.                 printf("track %d  sector %d ",track,sector);
  219.                 printf(" block %x.%d ",
  220.                     block/(8*blockl),block%(8*blockl));
  221.                 for(i=0;i<128*nsect;i+=16){
  222.                     printf("\n %4x  ",i);
  223.                     for(j=0;j<16;j++){
  224.                         printf("%2x ",buffer[i+j]);
  225.                         if(j%4 == 3) printf(" ");
  226.                     }
  227.                     for(j=0;j<16;j++){
  228.                         c=buffer[i+j]&0x7f;
  229.                         c=c<' '||c==0x7f ? '.' : c;
  230.                         putchar(c);
  231.                     }
  232.                     if(kbhit()) break;
  233.                 }
  234.                 putchar('\n');
  235.                 break;
  236.             case 'E' : i=getnum(&bufp,0,nsect*128-1,16);
  237.                 while(*bufp==' '){
  238.                     buffer[i++]=getnum(&bufp,0,255,16);
  239.                     if(i>=nsect*128) break;
  240.                 }
  241.                 break;
  242.             case 'F' : i=getnum(&bufp,0,255,16);
  243.                 for(j=0;j<nsect*128;j++) buffer[j]=i;
  244.                 break;
  245.             case 'M' : bios(SELDSK,disk);
  246.                 /* read directory from disk        */
  247.                 copydir(dir);
  248.                 /* output allocation info        */
  249.                 l=0;
  250.                 setmem(&map,maxblk,'.');
  251.                 while(l<=entries){
  252.                     /* output up to 64 dir. entries    */
  253.                     j=(l+64<entries) ? l+64 : entries+1;    
  254.                     for(i=l;i<j;i++){
  255.                         if(i%4==0) putchar('\n');
  256.                         mc=putentry(dir+i*32,i%64);
  257.                         setmap(map,dir+i*32+16,mc);
  258.                     }
  259.                     puts("\n");
  260.                     /* output block map        */
  261.                     for(i=0;i<maxblk;i++){
  262.                         bldblk(i);/* format    */
  263.                         putchar(map[i]);
  264.                         if(map[i]!='.')map[i]='@';
  265.                     }
  266.                     putchar('\n');
  267.                     l+=64;
  268.                     if(l<entries){
  269.                         puts("\nNext part of map? (Y/N)");
  270.                         if(tolower(getchar())=='n'){
  271.                             puts("\n");
  272.                             break;
  273.                         }
  274.                     }
  275.                 }
  276.                 break;
  277.             case ' ' : break;
  278.             default : printf("%c ??????\n",c);
  279.                 *bufp='\0';
  280.                 break;
  281.         }
  282.     if(kbhit()) getchar();
  283.     puts("\nDUP>");
  284.     }
  285. }
  286. int getnum(pntr,low,high,base)
  287. int low,high,base;
  288. char **pntr;
  289. {
  290.     int number;
  291.     char c,buffer[50],*bp;
  292.     number=0;
  293.     while( **pntr== ' ') (*pntr)++ ;
  294.     while( (c=toupper(*(*pntr)++))>='0' && c<= '9' ||
  295.         base==16 && (c-=7) > '9' && c <= ('F'-7) )
  296.             number=base*number+c-'0';
  297.     (*pntr)--;
  298.     if (number<low || number>high){
  299.         printf("bad number %d ",number);
  300.         bp=gets(buffer);
  301.         number=getnum(&bp,low,high,base);
  302.     }
  303.     return (number);
  304. }
  305. mapchar(i)
  306. char i;
  307. {    if(i<10) return(i+'0');
  308.     if(i<36) return(i-10+'a');
  309.     return(i-36+'A');
  310. }
  311. putchar(c)
  312. char c;
  313. {
  314.     putch(c&127);
  315. }
  316. int update(sector,track)
  317. char *sector,*track;
  318. {    char ttrack,tsector;
  319.     ttrack=*track;
  320.     tsector=*sector;
  321.     if(tsector>(maxsec-1+MINS)){
  322.         tsector-=maxsec;
  323.         ttrack++;
  324.     }
  325.     if((ttrack==maxtrk)&&(tsector==maxsec)){
  326.         puts("\n*** end of disk ***\n");
  327.         return(0);
  328.     }
  329.     *track=ttrack;
  330.     *sector=tsector;
  331.     return(1);
  332. }
  333. int getdiskp(disk)
  334. int disk;
  335. {    do{    dph=biosh(SELDSK,disk,0);    /* SELDISK returns adr. of DPH */
  336.         if (dph==0){
  337.             puts("\nThis drive does not exist, 0 selected!\n");
  338.             return(0);
  339.         }
  340.     }while (dph==0);
  341.  
  342.     physlog=dph[XLT];
  343.     dpb=dph[DPB];
  344.     maxsec=ctoi(&dpb[SPT]);
  345.     blockl=bshblm(dpb[BSH],dpb[BLM]);
  346.     restrk=ctoi(&dpb[OFF]);
  347.     maxblk=ctoi(&dpb[DSM])+1;
  348.     maxtrk=restrk+maxblk*blockl*8/maxsec+1;
  349.     entries=ctoi(&dpb[DRM]);
  350.     capac=blockl*maxblk;
  351.     if(maxblk>255)longbn=1;
  352.     else longbn=0;
  353. #if STAT
  354.     printf("\nDisk parameter header at %X",dph);
  355.     printf("\nDisk parameter block at %X",dpb);
  356.     if(physlog)printf("\nSector translation table at %X",physlog);
  357.     else puts("\nNo sector translation");
  358.     printf("\N\N%4d 128 Byte Record Capacity", 8*blockl*(capac+1));
  359.     printf("\n%4d Kilobyte drive capacity", capac);
  360.     printf("\n%4d 32 Byte Directory Entries",entries+1);
  361.     printf("\n%4d Records/ Extent", 8*8*blockl*(2-longbn));
  362.     printf("\n%4d Records/ Block",8*blockl);
  363.     printf("\n%4d sectors/ track",maxsec);
  364.     printf("\n%4d Reserved Tracks",restrk);
  365.     printf("\n%4d tracks on disk",maxtrk);
  366.     printf("\n%4d blocks on disk",maxblk);
  367.     puts("\n");
  368. #endif
  369.     if (entries<=MAXE)
  370.         if(maxblk<=MAXB)
  371.             if(blockl<=MAXL) return(disk);
  372.     puts("\nYour disk would bomb this program.");
  373.     puts("\nSo please set MAXE, MAXB and MAXL constants to");
  374.     puts("\nappropriate values and compile this program again!");
  375.     exit();
  376. }
  377. int transl(logsec)
  378. int logsec;
  379. {    if (physlog==0)return(logsec);
  380.     else return(physlog[logsec]);
  381. }
  382. int bshblm(bsh,blm)
  383. int bsh,blm;
  384. {    int blockl;
  385.     for (blockl=-2;bsh--;blockl++){
  386.         if(blm==0){
  387.             puts("\nBLM too small.\n");
  388.             blockl=0;
  389.             break;
  390.         }
  391.         blm>>=1;
  392.     }
  393.     if(blm!=0)puts("\nBLM too big.\n");
  394.     return(blockl);
  395. }
  396. copydir(dir)
  397. char *dir;
  398. {    int sector, track, i;
  399.      track=restrk;
  400.      sector=0;
  401.      for(i=0;i<(entries+1)/4;i++){
  402.         bios(SETTRK,track);
  403.         bios(SETSEC,transl(sector));
  404.         bios(SETDMA,dir+i*128);
  405.         if(bios(READ))puts("\nCan't read");
  406.         sector++;
  407.         update(§or,&track);
  408.     }
  409. }
  410. char putentry(dir,i)
  411. char *dir;
  412. int  i;
  413. {    char c,d,mc;
  414.     c=(*dir==0) ? '=' : '*';
  415.     d=dir[12];
  416.     mc=mapchar(i);
  417.     if(d==0xe5)        /* entry not used before */
  418.         printf("%c%18s",mc,"");
  419.     else{            /* output filename     */
  420.         dir[12]=0;
  421.         printf("%c%c%s",mc,c,dir+1);
  422.                 /* output extension number */
  423.         if(d != 0) printf("/%x",d%0x10);
  424.         else printf("  ");
  425.                 /* output record count    */
  426.         printf(" %2x ",dir[15]);
  427.     }
  428.     return (c=='=') ? mc : mc + 128;    
  429. }
  430. setmap(map,blnum,mc)
  431. char *map, *blnum, mc;
  432. {    int k,l;
  433.     if(longbn){
  434.         for(k=0;k<16&&(l=ctoi(blnum+k));k+=2){
  435.             if(mc<128) map[l]=mc;
  436.         }
  437.     }
  438.     else{
  439.         for(k=0;k<16&&(l=blnum[k]);k++){
  440.             if(mc<128) map[l]=mc;
  441.         }
  442.     }
  443. }
  444. int ctoi(integer)
  445. char *integer;
  446. {
  447.     return(*integer+(*(integer+1)<<8));
  448. }
  449. bldblk(i)
  450. int i;
  451. {    if(i%64==0) putchar('\n');
  452.     else if(i%16==0) printf("  ");
  453.     else if(i%8==0) printf(" ");
  454. }