home *** CD-ROM | disk | FTP | other *** search
- /***
- *files.c - disked file indexing
- *
- *Copyright (c) 1991-1995, Gregg Jennings. All wrongs reserved.
- * P O Box 200, Falmouth, MA 02541-0200
- *
- *Purpose:
- * Indexes all files.
- *
- *Notice:
- * This progam may be freely used and distributed. Any distrubution
- * with modifications must retain the above copyright statement and
- * modifications noted.
- * No pulp-publication, in whole or in part, permitted without
- * permission (magazines or books).
- *******************************************************************************/
-
- /*
- Versions
-
- 2.5 22-Dec-1994 enums, dDIR was DIR
- 2.4 04-Sep-1994 extern reference consolodation; getdir() changes
- 2.3 30-Jul-1994 added struct DIR * in getdir()
- 2.2 26-Feb-1994 huge clusters/files etc
- 2.1 14-Jan-1994 bug fix in initfiles()
-
-
- Notes: The error handling stuff is a bit crude (there has
- been sleight improvements since last release but it
- could still use some work).
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <malloc.h>
- #include <conio.h>
- #include <dos.h>
-
- #include "disked.h"
- #include "console.h" /* conout, print */
- #include "alloc.h"
- #include "diskio.h"
- #include "files.h"
- #include "error.h"
- #include "dirent.h"
- #include "direct.h"
-
- enum DOS_DIR_FILENAME
- {
- FILENAM = 8,
- FILETYP = 3,
- FILELEN = FILENAM+FILETYP
- };
-
- enum DOS_DIR_OFFSETS
- {
- ATTRIB = 11,
- CLUSTL = 26,
- CLUSTH = 27
- };
-
- enum DOS_DIR_FIRST_CHARS
- {
- ERACHR = 0xE5,
- DIRCHR = '.',
- WEIRDC = 5,
- ENDDIR = 0
- };
-
- enum DOS_DIR_ATTRIBUTES /* the ones we care about here */
- {
- DIRATR = 0x10, /* (bits) */
- VOLATR = 8
- };
-
- /* global data referenced here
-
- all of the DISKIO stuff
-
- */
-
- /* global data defined here */
-
- struct files_t __huge *files;
- unsigned int n_files,n_dirs; /* number of files and directories */
- int __huge *clusters; /* pointer to array of cluster entries */
- /* int limits this to 32000 clusters */
- /* static data */
-
- static unsigned int tn_files;
- static const char *module = "files";
-
- /* static functions */
-
- static int getdir(unsigned long sector,int parent,int nsecs);
- static int getfat12(int nsecs,unsigned int nclusters);
- static int getfat16(int nsecs,unsigned int nclusters);
- __inline static void namecpy(char *n, char *d);
-
-
- /***
- *initfiles() - read/index all files
- *
- * ver 3.0 13-Jan-1994 fixed getfatxx() return signed/unsigned mismatch
- *
- ****/
-
- extern int initfiles(void)
- {
- int mem,status;
-
- mem = status = 0;
-
- if (_osmajor < 3) /* always off if DOS != 3.x */
- {
- status = REQ_DOS_3;
- goto error;
- }
- if ((clusters=(int _huge *)hugealloc(num_clusters+1,sizeof(int)))==NULL)
- {
- status = NO_MEM;
- goto error;
- }
- mem = 1;
-
- if (num_clusters <= 4086) /* 12 bit FAT */
- status = getfat12(secs_fat,num_clusters);
- else
- status = getfat16(secs_fat,num_clusters);
-
- if (status == -1)
- goto error;
-
- n_files = status;
-
- tn_files = n_files + 2; /* NOTE extra entries */
-
- if ((files=(struct files_t _huge *)hugealloc(tn_files,sizeof(struct files_t)))==NULL)
- {
- status = NO_MEM;
- goto error;
- }
- mem = 2;
-
- n_files = n_dirs = 1;
- strcpy(files[0].name,"\\"); /* root directory name */
- files[0].parent = 0;
- files[0].dir = 1;
-
- if (getdir((dword)dir_sector,0,dir_sectors) != 0)
- {
- if (Display)
- {
- output('\r');
- clreol();
- }
- else
- output(' ');
- return 1; /* RETURN */
- }
- output(' ');
-
- error:
- if (mem == 2)
- hugefreep(files);
- if (mem)
- hugefreep(clusters);
- if (status == NO_MEM)
- {
- set_error(NULL,module,status,"initfiles");
- if (mem)
- set_err_arg("files:%lu",(long) \
- (((long)num_clusters*sizeof(int))+1) + \
- ((n_files+10)*sizeof(struct files_t)));
- else
- set_err_arg("clusters:%lu", \
- (long)((long)num_clusters*sizeof(int))+1);
- }
- return 0;
- }
-
- /***
- *getdir - read in ALL files on the drive
- *
- *
- * ver 2.1 04-Sep-1994 twirl chars; struct DIR, namecpy()
- ****/
-
- static int getdir(unsigned long sector,int parent,int nsecs)
- {
- unsigned int i,l;
- unsigned char *buffer;
- int status;
- dDIR *dir;
-
- status = 0;
-
- if (!Display)
- {
- static int ind;
- print("%c\b","\\|/-"[++ind%4]); /* for slow machines */
- /*if (ind == 5) ind = 0;*/ /* get rid of %4 and add this */
- }
- if ((buffer=(unsigned char *)alloc(sec_size,sizeof(char)))==NULL)
- {
- status = NO_MEM;
- goto error;
- }
-
- while (nsecs-- >0)
- {
- if (diskio(DISK_READ,sector++,buffer) != DISK_OK)
- goto error;
- dir = (dDIR *)buffer;
-
- for (i = 0; i < sec_size/sizeof(dDIR); i++,dir++)
- {
- if (dir->name[0] == ERACHR || dir->name[0] == DIRCHR)
- continue;
- if (dir->name[0] == ENDDIR)
- {
- freep(buffer);
- return n_files; /* so return */
- }
- l = dir->start;
- if (dir->attr.volume)
- {
- namecpy(volume,(char *)dir->name);
- continue;
- }
- if (l == 0) /* skip 0 length files */
- continue;
-
- namecpy(files[n_files].name,(char *)dir->name);
- files[n_files].parent=parent;
- ++n_files;
-
- if (n_files == tn_files) /* trying to write past end? */
- {
- status = NUM_FILES;
- goto error;
- }
- if (l > num_clusters)
- {
- status = INV_ST_CLUS;
- goto error;
- }
- if (dir->attr.subdir) /* is a directory? */
- {
- register int k;
- register int nf = n_files-1;
- if (Display)
- {
- print("\r%s",files[nf].name);
- clreol();
- }
- ++n_dirs;
- files[nf].dir = 1;
-
- /* get subdirectory */
-
- if (!getdir(clustertosector(l),nf,secs_cluster))
- goto error;
-
- while ((k = clusters[l]) > 0)
- {
- clusters[l] = nf;
- if (!getdir(clustertosector(k),nf,secs_cluster))
- goto error;
- l = k;
- }
- clusters[l] = nf;
- }
- else
- {
- register int k;
- register int nf = n_files-1;
- while ((k = clusters[l]) > 0)
- {
- if ((unsigned int)k == l)
- {
- status = FAT_PHASE;
- goto error;
- }
- clusters[l] = nf;
- l = k;
- }
- clusters[l] = nf;
- }
- }
- }
- freep(buffer);
- return n_files;
-
- error:
- freep(buffer);
- if (status)
- {
- set_error(err_msg[status],module,status,"getdir");
- if (status == INV_ST_CLUS)
- set_err_arg(" \"%s\" (%04x)",gfile(n_files-1),l);
- else if (status == NUM_FILES)
- set_err_arg(" (%d)",n_files);
- }
- return 0;
- }
-
- /* convert "AAAA XXX" to "AAAA.XXX\0" */
-
- __inline static void namecpy(char *n, char *d)
- {
- int j;
-
- for (j = 0; j < FILELEN; j++,d++)
- {
- if (*d == ' ')
- continue;
- if (j == FILENAM)
- *n++ = '.';
- *n++ = *d;
- }
- *n = '\0';
- }
-
- /*
- How FATs work:
-
- function: getfat12(number_of_sectors, number_of_clusters)
-
- reads all FAT sectors into a buffer and then convert the buffer
- into the clusters[] array.
-
- 12 bit: used on drives with up to 4086 clusters
-
- start from fatbuf[3], taking 3 unsigned chars at a time:
-
- ___ take the 0 from 40 (last 4 bits) and put it in
- || \ front of the 03 which results in 003
- 03 40 00
- \__|| take the 4 from 40 (first 4 bits) and put it in
- back of the 00 which results in 004
-
- But Remember: int's are stored in memory Least Significant
- Byte first.
-
- 000 unused
- ff7 bad
- ff8-fff last used cluster of the file
-
- What MS-DOS Programmer's Reference says:
-
- Start with the starting cluster number. Multiply cluster
- number just used by 1.5. The whole part of the product is
- an offset into the FAT, pointing to the entry that maps the
- cluster just used. That entry contains the cluster number
- of the next cluster of the file. Get the entry. If the
- last cluster used was an even number AND the entry
- with 0xfff to keep the low-order 12 bits otherwise shift
- it to the right 4 times.
-
-
- 16 bit: drives > 4086 clusters
-
- start from fatbuf[4], take an integer at a time (2 bytes)
-
- 03 00 results in 0003
-
- 0000 unused
- fff7 bad
- fff8-ffff last used cluster of the file
- */
-
- static int getfat12(int nsecs,unsigned nclusters)
- {
- register unsigned int h,n;
- unsigned int l;
- int status,i;
- int nf;
- unsigned char *buffer;
- unsigned char *bufptr;
- unsigned int *po;
- unsigned int *pe;
- int stat;
-
- stat = status = nf = 0;
- h = l = 0;
-
- if ((buffer = (unsigned char *)alloc(sec_size*nsecs,sizeof(char))) == NULL)
- {
- status = NO_MEM;
- goto error;
- }
- /* read logical sectors 1 to nsecs */
- stat = 1;
- for (i = 1, bufptr = buffer; i <= nsecs; i++, bufptr += sec_size)
- if (diskio(DISK_READ,(long)i,bufptr) != DISK_OK)
- goto error;
-
- for (h = 2, n = 3; h <= nclusters; n+=3)
- {
- pe = (unsigned int *)(buffer+n);
- po = (unsigned int *)(buffer+n+1);
- l = *pe&0xfff;
- if (l >= 0xff8) /* end of file */
- {
- clusters[h] = -1;
- ++nf;
- }
- else if (l==0xff7) /* bad */
- clusters[h] = -2;
- else
- clusters[h] = l;
- if (++h > nclusters)
- break;
- if (l > nclusters && l < 0xff7)
- {
- status = INV_CLUS;
- goto error;
- }
- l = *po>>4;
- if (l >= 0xff8)
- {
- ++nf;
- clusters[h] = -1;
- }
- else if (l == 0xff7)
- clusters[h] = -2;
- else
- clusters[h] = l;
- if (++h > nclusters)
- break;
- if (l > nclusters && l < 0xff7)
- {
- status = INV_CLUS;
- goto error;
- }
- }
- freep(buffer);
- return nf;
-
- error:
- if (stat)
- freep(buffer);
- if (status)
- {
- set_error(err_msg[status],module,status,"getfat12");
- if (status == NO_MEM)
- set_err_arg("%u",sec_size*nsecs);
- else if (status == INV_CLUS)
- set_err_arg("entry: %d value: %x",h,l);
- }
- return ERROR;
- }
-
- /*
- ver 2.0 14-Nov-1993 fixed bug where not all sectors read (oops!)
- (do..while tested: sector < nsecs)
- */
-
- static int getfat16(int nsecs,unsigned nclusters)
- {
- register unsigned int h = 0;
- unsigned int *pi;
- int n;
- unsigned int l = 0;
- int status;
- int nf;
- unsigned int sector;
- unsigned char *buffer;
- int stat;
-
- stat = status = nf = 0;
-
- /* allocate space for the FAT to be read */
- /* NOTE: sectors are read one at a time due due to 16 bit FATs
- being usually large.
- */
- if ((buffer=(unsigned char *)alloc(sec_size,sizeof(char)))==NULL)
- {
- status = NO_MEM;
- goto error;
- }
- stat = 1;
- sector = reserved_secs;
- h = 2;
- do
- {
- if (diskio(DISK_READ,(long)sector,buffer) != DISK_OK)
- {
- goto error;
- }
- if (sector == reserved_secs)
- n = 4; /* skip first 4 bytes in first sector */
- else
- n = 0;
-
- for (;n<(int)sec_size;n+=2)
- {
- pi = (unsigned int *)(buffer+n);
- l = *pi;
- if (l >= 0xfff8) /* end of entries */
- {
- ++nf; /* increment file count */
- clusters[h] = -1; /* mark file end */
- }
- else if (l == 0xfff7) /* cluster marked bad */
- clusters[h] = -2; /* flag it */
- else
- clusters[h] = l; /* else assume good cluster entry */
- if (++h > nclusters)
- break;
- if (l > nclusters && l < 0xfff7) /* check for out-of-range number */
- {
- status = INV_CLUS;
- goto error;
- }
- }
- ++sector;
- } while (sector < (unsigned)nsecs + reserved_secs);
- freep(buffer);
- return nf;
-
- error:
- if (stat)
- freep(buffer);
- if (status)
- {
- set_error(err_msg[status],module,status,"getfat16");
- if (status == NO_MEM)
- set_err_arg("%u",sec_size);
- else if (status == INV_CLUS)
- set_err_arg("entry: %d value: %x",h,l);
- }
- return ERROR;
- }
-
- /* print file name */
-
- extern int pfile(char *file, unsigned int i)
- {
- while (i != 0)
- i = pfile(files[i].name,files[i].parent);
- print("\\%s",file);
- return files[i].parent;
- }
-
- /* get file name matched to cluster number */
-
- #define F_LEV 10 /* directory name depth level */
-
- extern char *gfile(unsigned int index)
- {
- static char buf[67];
- int flev[F_LEV],i;
-
- buf[0] = '\0';
- i=0;
- memset(flev,0,sizeof(int)*F_LEV);
-
- while (index != 0)
- {
- if (i > F_LEV)
- {
- i = 0;
- strcpy(buf,"max lev error");
- break;
- }
- flev[i++] = index;
- index = files[index].parent;
- }
- while (i)
- {
- strcat(buf,"\\");
- strcat(buf,files[flev[i-1]].name);
- --i;
- }
- return buf;
- }
-
- /*
- * Findfile: Returns the first cluster number of the passed filename
- * if it is in the files structure.
- *
-
- *** BUG ***
-
- sometimes finds improperly; "temp" finds first
- string whether its "\foo\temp" or "\win\system\temp"
-
-
- * ver 0.0 9/91
- */
-
- extern unsigned int findfile(char *file)
- {
- register char *token;
- register unsigned int i,j;
-
- token = strtok(file,"\\");
- for (i = 0; i < n_files; i++)
- {
- if (stricmp(token,files[i].name) == 0)
- {
- token = strtok(NULL,"\\");
- if (token == NULL)
- {
- for (j = 2; j < num_clusters; j++)
- if (clusters[j] > 0 && (unsigned)clusters[j] == i)
- return j;
- break;
- }
- }
- }
- return 0;
- }
-
- extern unsigned int get_avail_clusters(void)
- {
- union REGS regs;
- unsigned c,j;
-
- if (!Files)
- {
- regs.x.ax = 0x3600;
- regs.x.dx = disk;
- intdos(®s,®s);
- return regs.x.bx;
- }
- else
- for (c = 0,j = 2; j <= num_clusters; j++)
- if (clusters[j] == 0)
- ++c;
- return c;
- }
-
- #ifdef MAP_FATS
-
- /* display FAT -- not done yet */
-
- extern void mapfat12(int sec)
- {
- register unsigned int h,n;
- int i;
- unsigned char *buffer = sec_buf;
- unsigned int *po;
- unsigned int *pe;
-
- if (sec == sec)
- n = 3;
-
- send('\n');
-
- for (h=2,n=3;n<sec_size-1;h+=8)
- {
- printf("\n%03d-",h);
- for (i=0;i<8;i++,n+=3)
- {
- pe=(unsigned int *)(buffer+n);
- po=(unsigned int *)(buffer+n+1);
- printf("%03x ",(unsigned int)*pe&0xfff);
- printf("%03x ",(unsigned int)*po>>4);
- }
- }
- }
-
- #endif
-