home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 406_01 / disked25 / source / files.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-13  |  16.6 KB  |  719 lines

  1. /***
  2. *files.c - disk editor file indexing
  3. *
  4. *Copyright (c) 1991-1994, Gregg Jennings.  All wrongs reserved.
  5. *   P O Box 200, Falmouth, MA 02541-0200
  6. *
  7. *Purpose:
  8. *   Indexes all files.
  9. *
  10. *Notice:
  11. *   This progam may be freely used and distributed.  Any distrubution
  12. *   with modifications must retain the above copyright statement and
  13. *   modifications noted.
  14. *   No pulp-publication, in whole or in part, permitted without
  15. *   permission (magazines or books).
  16. *******************************************************************************/
  17.  
  18. /*
  19.    Versions
  20.  
  21.    2.1   14-Jan-1994    bug fix in initfiles()
  22. */
  23.  
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <stdlib.h>
  27. #include <malloc.h>
  28. #include <conio.h>
  29. #include <dos.h>
  30.  
  31. #include "disked.h"
  32. #include "mylib.h"                     /* conout, print */
  33. #include "alloc.h"
  34. #include "diskio.h"
  35. #include "files.h"
  36. #include "error.h"
  37.  
  38. static const char *module = "files";
  39. static char ebuf[80];
  40.  
  41. #define FILENAM 8
  42. #define FILETYP 3
  43. #define FILELEN FILENAM+FILETYP
  44. #define ATTRIB 11
  45. #define CLUSTL 26
  46. #define CLUSTH 27
  47. #define ERACHR 0xE5
  48. #define DIRCHR '.'
  49. #define WEIRDC 5
  50. #define ENDDIR 0
  51. #define DIRATR 0x10
  52. #define VOLATR 8
  53.  
  54. static int getdir(unsigned long sector,int parent,int nsecs);
  55. static int getfat12(int nsecs,unsigned int nclusters);
  56. static int getfat16(int nsecs,unsigned int nclusters);
  57.  
  58. struct files_t *files;
  59. unsigned int n_files,n_dirs;  /* number of files and directories */
  60. int *clusters;                /* pointer to array of cluster entries */
  61.                               /* int limits this to 32000 clusters */
  62. static unsigned int tn_files;
  63.  
  64. /***
  65. *initfiles() - read/index all files
  66. *
  67. *  ver   3.0 13-Jan-1994   fixed getfatxx() return signed/unsigned mismatch
  68. *
  69. ****/
  70.  
  71. extern int initfiles(void)
  72. {
  73. int mem,status;
  74.  
  75.    mem = status = 0;
  76.  
  77.    if (_osmajor < 3)          /* always off if DOS != 3.x */
  78.    {
  79.       status = REQ_DOS_3;
  80.       goto error;
  81.    }
  82.    if ((clusters=(int *)alloc(num_clusters+1,sizeof(int)))==NULL)
  83.    {
  84.       status = NO_MEM;
  85.       goto error;
  86.    }
  87.    mem = 1;
  88.  
  89.    if (num_clusters <= 4086)                       /* 12 bit FAT */
  90.       status = getfat12(secs_fat,num_clusters);
  91.    else
  92.       status = getfat16(secs_fat,num_clusters);
  93.  
  94.    if (status == -1)
  95.       goto error;
  96.  
  97.    n_files = status;
  98.  
  99.    tn_files = n_files + 2;         /* NOTE extra entries */
  100.  
  101.    if ((files=(struct files_t *)alloc(tn_files,sizeof(struct files_t)))==NULL)
  102.    {
  103.       status = NO_MEM;
  104.       goto error;
  105.    }
  106.    mem = 2;
  107.  
  108.    n_files = n_dirs = 1;
  109.    strcpy(files[0].name,"\\");        /* root directory name */
  110.    files[0].parent = 0;
  111.    files[0].dir = 1;
  112.  
  113.    if (getdir((dword)dir_sector,0,dir_sectors) != 0)
  114.       return(1);
  115.  
  116. error:
  117.    if (mem == 2)
  118.       freep(files);
  119.    if (mem)
  120.       freep(clusters);
  121.    if (status)
  122.    {
  123.       error.msg = err_msg[status];
  124.       error.mod = module;
  125.       error.num = status;
  126.       error.func = "initfiles";
  127.       if (status == NO_MEM)
  128.       {
  129.          if (mem)
  130.             sprintf(ebuf,"files:%u",
  131.             (num_clusters*sizeof(int))+1) + ((n_files+10)*sizeof(struct files_t));
  132.          else
  133.             sprintf(ebuf,"clusters:%u",(num_clusters*sizeof(int))+1);
  134.          error.arg = ebuf;
  135.       }
  136.    }
  137.    return(0);
  138. }
  139.  
  140. static int getdir(unsigned long sector,int parent,int nsecs)
  141. {
  142. int c,d,temp;
  143. unsigned int i;
  144. register int j,k;
  145. unsigned l,templ;
  146. unsigned char *buffer;
  147. int status;
  148.  
  149.    status = 0;
  150.  
  151.    if ((buffer=(unsigned char *)alloc(sec_size,sizeof(char)))==NULL)
  152.    {
  153.       status = NO_MEM;
  154.       goto error;
  155.    }
  156.  
  157.    while (nsecs-- >0)
  158.    {
  159.       if (diskio(DISK_READ,sector++,buffer) != DISK_OK)
  160.          goto error;
  161.  
  162.       for (i=0;i<sec_size;i+=32)
  163.       {
  164.          c=buffer[i];
  165.          if (c==ERACHR || c==DIRCHR)
  166.              continue;
  167.          if (c==WEIRDC)
  168.              buffer[i]=ERACHR;
  169.          if (c==ENDDIR)
  170.          {
  171.             freep(buffer);
  172.             return(n_files);                    /* so return */
  173.          }
  174.          d=buffer[i+ATTRIB];                     /* d = attrib */
  175.          l=buffer[i+CLUSTL] + (buffer[i+CLUSTH]*256);    /* l = starting cluster */
  176.          if (d&VOLATR)
  177.          {
  178.             for (j=0;j<FILELEN;j++)                  /* get volume label */
  179.                volume[j]=buffer[i+j];
  180.             volume[j]='\0';
  181.             continue;
  182.          }
  183.          if (l==0)                                  /* skip 0 length files */
  184.             continue;
  185.  
  186.          for (j=0,k=0;j<FILELEN;j++)                  /* get filename */
  187.          {
  188.             if (buffer[i+j]==' ')
  189.                continue;
  190.             if (j==FILENAM)
  191.                files[n_files].name[k++]='.';
  192.             files[n_files].name[k++]=buffer[i+j];
  193.          }
  194.          files[n_files].name[k]='\0';
  195.          files[n_files].parent=parent;
  196.  
  197.          ++n_files;
  198.  
  199.          if (n_files == tn_files)      /* trying to write past end? */
  200.          {
  201.             status = NUM_FILES;
  202.             goto error;
  203.          }
  204.          if (l > num_clusters)
  205.          {
  206.             status = INV_ST_CLUS;
  207.             goto error;
  208.          }
  209.          if (d&DIRATR)                           /* is a directory */
  210.          {
  211.             ++n_dirs;
  212.             files[n_files-1].dir = 1;
  213.             templ = l;
  214.             temp = n_files-1;
  215.             if (!getdir(clustertosector(l),temp,secs_cluster))
  216.                goto error;
  217.             while ((k = clusters[templ]) > 0)
  218.             {
  219.                clusters[templ] = temp;
  220.                if (!getdir(clustertosector(k),temp,secs_cluster))
  221.                   goto error;
  222.                templ = k;
  223.             }
  224.             clusters[templ] = temp;
  225.          }
  226.          else
  227.          {
  228.             while ((k = clusters[l]) > 0)
  229.             {
  230.                if ((unsigned int)k == l)
  231.                {
  232.                   status = FAT_PHASE;
  233.                   goto error;
  234.                }
  235.                clusters[l] = n_files-1;
  236.                l = k;
  237.             }
  238.             clusters[l] = n_files-1;
  239.          }
  240.       }
  241.    }
  242.    freep(buffer);
  243.    return(n_files);
  244.  
  245. error:
  246.    freep(buffer);
  247.    if (status)
  248.    {
  249.       if (status == INV_ST_CLUS)
  250.       {
  251.          sprintf(ebuf," \"%s\" (%04x)",gfile(n_files-1),l);
  252.          error.arg = ebuf;
  253.       }
  254.       else if (status == NUM_FILES)
  255.       {
  256.          sprintf(ebuf," (%d)",n_files);
  257.          error.arg = ebuf;
  258.       }
  259.       error.num = status;
  260.       error.msg = err_msg[status];
  261.       error.mod = module;
  262.       error.func = "getdir";
  263.    }
  264.    return(0);
  265. }
  266.  
  267. /*
  268.    How FATs work:
  269.  
  270.    function: getfat12(number_of_sectors, number_of_clusters)
  271.  
  272.    reads all FAT sectors into a buffer and then convert the buffer
  273.    into the clusters[] array.
  274.  
  275.     12 bit:  used on drives with up to 4086 clusters
  276.  
  277.     start from fatbuf[3], taking 3 unsigned chars at a time:
  278.  
  279.     ___         take the 0 from 40 (last 4 bits) and put it in
  280.     || \        front of the 03 which results in 003
  281.     03 40 00
  282.        \__||    take the 4 from 40 (first 4 bits) and put it in
  283.                     back of the 00 which results in 004
  284.  
  285.         But Remember: int's are stored in memory Least Significant
  286.                       Byte first.
  287.  
  288.     000         unused
  289.     ff7         bad
  290.     ff8-fff     last used cluster of the file
  291.  
  292.         What MS-DOS Programmer's Reference says:
  293.  
  294.         Start with the starting cluster number.  Multiply cluster
  295.         number just used by 1.5.  The whole part of the product is
  296.         an offset into the FAT, pointing to the entry that maps the
  297.         cluster just used.  That entry contains the cluster number
  298.         of the next cluster of the file.  Get the entry.  If the
  299.         last cluster used was an even number AND the entry
  300.         with 0xfff to keep the low-order 12 bits otherwise shift
  301.         it to the right 4 times.
  302.  
  303.  
  304.    16 bit:  drives > 4086 clusters
  305.  
  306.     start from fatbuf[4], take an integer at a time (2 bytes)
  307.  
  308.     03 00       results in 0003
  309.  
  310.     0000        unused
  311.     fff7        bad
  312.     fff8-ffff   last used cluster of the file
  313. */
  314.  
  315. static int getfat12(int nsecs,unsigned nclusters)
  316. {
  317. register unsigned int h,n;
  318. unsigned int l;
  319. int status,i;
  320. int nf;
  321. unsigned char *buffer;
  322. unsigned char *bufptr;
  323. unsigned int *po;
  324. unsigned int *pe;
  325. int stat;
  326.  
  327.    stat = status = nf = 0;
  328.  
  329.    if ((buffer = (unsigned char *)alloc(sec_size*nsecs,sizeof(char))) == NULL)
  330.    {
  331.       status = NO_MEM;
  332.       goto error;
  333.    }
  334.    /* read logical sectors 1 to nsecs */
  335.    stat = 1;
  336.    for (i=1,bufptr=buffer;i<=nsecs;i++,bufptr+=sec_size)
  337.       if (diskio(DISK_READ,(long)i,bufptr) != DISK_OK)
  338.          goto error;
  339.  
  340.    for (h=2,n=3;h<=nclusters;n+=3)
  341.    {
  342.       pe = (unsigned int *)(buffer+n);
  343.       po = (unsigned int *)(buffer+n+1);
  344.       l = *pe&0xfff;
  345.       if (l >= 0xff8)        /* end of file */
  346.       {
  347.          clusters[h] = -1;
  348.          ++nf;
  349.       }
  350.       else if (l==0xff7)   /* bad */
  351.          clusters[h] = -2;
  352.       else
  353.          clusters[h] = l;
  354.       if (++h > nclusters)
  355.          break;
  356.       if (l > nclusters && l < 0xff7)
  357.       {
  358.          status = INV_CLUS;
  359.          goto error;
  360.       }
  361.       l = *po>>4;
  362.       if (l >= 0xff8)
  363.       {
  364.          ++nf;
  365.          clusters[h] = -1;
  366.       }
  367.       else if (l == 0xff7)
  368.          clusters[h] = -2;
  369.       else
  370.          clusters[h] = l;
  371.       if (++h > nclusters)
  372.          break;
  373.       if (l > nclusters && l < 0xff7)
  374.       {
  375.          status = INV_CLUS;
  376.          goto error;
  377.       }
  378.    }
  379.    freep(buffer);
  380.    return(nf);
  381.  
  382. error:
  383.    if (stat)
  384.       freep(buffer);
  385.    if (status)
  386.    {
  387.       error.num = status;
  388.       error.mod = module;
  389.       error.msg = err_msg[status];
  390.       if (status==NO_MEM)
  391.       {
  392.          sprintf(ebuf,"%u",sec_size*nsecs);
  393.          error.arg = ebuf;
  394.       }
  395.       else if (status==INV_CLUS)
  396.       {
  397.          sprintf(ebuf,"entry: %d value: %x",h,l);
  398.          error.arg = ebuf;
  399.       }
  400.    }
  401.    return(ERROR);
  402. }
  403.  
  404. /*
  405.    ver 2.0 14-Nov-1993 fixed bug where not all sectors read (oops!)
  406.                        (do..while tested: sector < nsecs)
  407. */
  408.  
  409. static int getfat16(int nsecs,unsigned nclusters)
  410. {
  411. register unsigned int h;
  412. unsigned int *pi;
  413. int n;
  414. unsigned int l;
  415. int status;
  416. int nf;
  417. unsigned int sector;
  418. unsigned char *buffer;
  419. int stat;
  420.  
  421.    stat = status = nf = 0;
  422.  
  423.    /* allocate space for the FAT to be read */
  424.    /* NOTE: sectors are read one at a time due due to 16 bit FATs
  425.       being usually large.
  426.    */
  427.    if ((buffer=(unsigned char *)alloc(sec_size,sizeof(char)))==NULL)
  428.    {
  429.       status = NO_MEM;
  430.       goto error;
  431.    }
  432.    stat = 1;
  433.    sector = reserved_secs;
  434.    h = 2;
  435.    do
  436.    {
  437.       if (diskio(DISK_READ,(long)sector,buffer) != DISK_OK)
  438.       {
  439.          goto error;
  440.       }
  441.       if (sector == reserved_secs)
  442.          n = 4;                        /* skip first 4 bytes in first sector */
  443.       else
  444.          n = 0;
  445.  
  446.       for (;n<(int)sec_size;n+=2)
  447.       {
  448.          pi = (unsigned int *)(buffer+n);
  449.          l = *pi;
  450.          if (l >= 0xfff8)              /* end of entries */
  451.          {
  452.             ++nf;                      /* increment file count */
  453.             clusters[h] = -1;          /* mark file end */
  454.          }
  455.          else if (l == 0xfff7)         /* cluster marked bad */
  456.             clusters[h] = -2;          /* flag it */
  457.          else
  458.             clusters[h] = l;           /* else assume good cluster entry */
  459.          if (++h > nclusters)
  460.             break;
  461.          if (l > nclusters && l < 0xfff7)  /* check for out-of-range number */
  462.          {
  463.             status = INV_CLUS;
  464.             goto error;
  465.          }
  466.       }
  467.       ++sector;
  468.    } while (sector < (unsigned)nsecs + reserved_secs);
  469.    freep(buffer);
  470.    return(nf);
  471.  
  472. error:
  473.    if (stat)
  474.       freep(buffer);
  475.    if (status)
  476.    {
  477.       error.num = status;
  478.       error.msg = err_msg[status];
  479.       error.mod = module;
  480.       if (status == NO_MEM)
  481.       {
  482.          sprintf(ebuf,"%u",sec_size);
  483.          error.arg = ebuf;
  484.       }
  485.       else if (status == INV_CLUS)
  486.       {
  487.          sprintf(ebuf,"entry: %d value: %x",h,l);
  488.          error.arg = ebuf;
  489.       }
  490.    }
  491.    return(ERROR);
  492. }
  493.  
  494. /* print file name */
  495.  
  496. extern int pfile(char *file, unsigned int i)
  497. {
  498.     while (i != 0)
  499.        i = pfile(files[i].name,files[i].parent);
  500.     putch('\\');
  501.     printf(file);
  502.     return(files[i].parent);
  503. }
  504.  
  505. /* get file name matched to cluster number */
  506.  
  507. #define F_LEV 10     /* directory name depth level */
  508.  
  509. extern char *gfile(unsigned int index)
  510. {
  511. static char buf[67];
  512. int flev[F_LEV],i;
  513.  
  514.    buf[0] = '\0';
  515.    i=0;
  516.    memset(flev,0,sizeof(int)*F_LEV);
  517.  
  518.    while (index != 0)
  519.    {
  520.       flev[i++] = index;
  521.       index = files[index].parent;
  522.    }
  523.    while (i)
  524.    {
  525.       strcat(buf,"\\");
  526.       strcat(buf,files[flev[i-1]].name);
  527.       --i;
  528.    }
  529.    return(buf);
  530. }
  531.  
  532. /*
  533.     Displays all of the numbers matching fnum in the clusters[] array.
  534. */
  535. extern void mapfile(int fnum,int base)
  536. {
  537. register unsigned int index;
  538.  
  539.    for (index=2;index<num_clusters;index++)
  540.    {
  541.       if (clusters[index]==fnum)
  542.       {
  543.          char buf[8];
  544.          printf(itoa(index,buf,base));
  545.          putch(' ');
  546.       }
  547.    }
  548. }
  549.  
  550. extern int homefile(int fnum)
  551. {
  552. register unsigned int index;
  553. register unsigned int c;
  554.  
  555.    for (c=num_clusters+1,index=2;index<num_clusters;index++)
  556.       if (clusters[index]==fnum)
  557.          if (index<c)
  558.             c=index;
  559.    return((int)c);
  560. }
  561.  
  562. extern int endfile(register int fnum)
  563. {
  564. register unsigned int index;
  565. register unsigned int c;
  566.  
  567.    for (c = 0,index = 2; index < num_clusters; index++)
  568.       if (*(clusters+index) == fnum)
  569.          if (index > c)
  570.             c = index;
  571.    return (int)c;
  572. }
  573.  
  574. /* Returns the next cluster of the file that the current cluster is
  575.    allocated to, wrapping at either end, returns 0 if current cluster
  576.    is unallocated.  Searches though the clusters[] array for matching
  577.    file number.
  578. */
  579. extern int jumpfile(register unsigned int cluster, register int direction)
  580. {
  581. int fnum;
  582.  
  583.    if ((fnum = *(clusters+cluster))==0)
  584.       return(0);
  585.    for (cluster += direction;;cluster += direction)
  586.    {
  587.       if (direction == -1 && cluster < 2)
  588.          cluster = num_clusters;
  589.       if (direction == 1 && cluster > num_clusters)
  590.          cluster = 2;
  591.       if (*(clusters+cluster) == fnum)
  592.          return(cluster);
  593.    }
  594. }
  595.  
  596. /*
  597.  * Findfile:  Returns the first cluster number of the passed filename
  598.  * if it is in the files structure.
  599.  *
  600.  *   ver  0.0  9/91
  601.  */
  602. extern unsigned int findfile(char *file)
  603. {
  604. register char *token;
  605. register unsigned int i,j;
  606.  
  607.    token=strtok(file,"\\");
  608.    for (i=0;i<n_files;i++)
  609.    {
  610.       if (stricmp(token,files[i].name)==0)
  611.       {
  612.          token=strtok(NULL,"\\");
  613.          if (token==NULL)
  614.          {
  615.             for (j=2;j<num_clusters;j++)
  616.                if (clusters[j]>0 && (unsigned)clusters[j]==i)
  617.                   return(j);
  618.             break;
  619.          }
  620.       }
  621.    }
  622.    return(0);
  623. }
  624.  
  625. extern void mapdisk(int base)
  626. {
  627. register unsigned int i;
  628. int zeros=0,indash=0;
  629. char buf[10];
  630.  
  631.    for (i=2;i<num_clusters;i++)
  632.    {
  633.       if (clusters[i]>0)
  634.       {
  635.          if (zeros==2)
  636.             putch(' ');
  637.          if (zeros>1)
  638.          {
  639.             printf(itoa(i-1,buf,base));
  640.             putch(' ');
  641.          }
  642.          if (zeros==1)
  643.             putch(' ');
  644.          zeros=indash=0;
  645.       }
  646.       else
  647.       {
  648.          if (zeros==1)
  649.             zeros++;
  650.          else if (zeros==0)
  651.          {
  652.             printf(itoa(i,buf,base));
  653.             zeros++;
  654.          }
  655.          else if (!indash)
  656.          {
  657.             putch('-');
  658.             indash=1;
  659.             zeros++;
  660.          }
  661.       }
  662.    }
  663. }
  664.  
  665. extern unsigned int get_avail_clusters(void)
  666. {
  667. union REGS regs;
  668. #ifdef DISKED
  669. unsigned c,j;
  670.  
  671.    if (!Files)
  672.    {
  673. #endif
  674.       regs.x.ax = 0x3600;
  675.       regs.x.dx = disk;
  676.       intdos(®s,®s);
  677.       return regs.x.bx;
  678. #ifdef DISKED
  679.    }
  680.    else
  681.       for (c=0,j=2; j <= num_clusters; j++)
  682.          if (clusters[j] == 0)
  683.              ++c;
  684.    return c;
  685. #endif
  686. }
  687.  
  688. #ifdef MAP_FATS
  689.  
  690. /* display FAT -- not done yet */
  691.  
  692. extern void mapfat12(int sec)
  693. {
  694. register unsigned int h,n;
  695. int i;
  696. unsigned char *buffer = sec_buf;
  697. unsigned int *po;
  698. unsigned int *pe;
  699.  
  700.    if (sec == sec)
  701.       n = 3;
  702.  
  703.    send('\n');
  704.  
  705.    for (h=2,n=3;n<sec_size-1;h+=8)
  706.    {
  707.       printf("\n%03d-",h);
  708.       for (i=0;i<8;i++,n+=3)
  709.       {
  710.          pe=(unsigned int *)(buffer+n);
  711.          po=(unsigned int *)(buffer+n+1);
  712.          printf("%03x ",(unsigned int)*pe&0xfff);
  713.          printf("%03x ",(unsigned int)*po>>4);
  714.       }
  715.    }
  716. }
  717.  
  718. #endif
  719.