home *** CD-ROM | disk | FTP | other *** search
/ CD-ROM Aktief 1995 #6 / CDA_6.iso / shell / utils / disked29.arj / SOURCE.ZIP / FILES.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-07  |  15.5 KB  |  668 lines

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