home *** CD-ROM | disk | FTP | other *** search
- /***
- *files.c - disk editor file indexing
- *
- *Copyright (c) 1991-1994, 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.1 14-Jan-1994 bug fix in initfiles()
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <malloc.h>
- #include <conio.h>
- #include <dos.h>
-
- #include "disked.h"
- #include "mylib.h" /* conout, print */
- #include "alloc.h"
- #include "diskio.h"
- #include "files.h"
- #include "error.h"
-
- static const char *module = "files";
- static char ebuf[80];
-
- #define FILENAM 8
- #define FILETYP 3
- #define FILELEN FILENAM+FILETYP
- #define ATTRIB 11
- #define CLUSTL 26
- #define CLUSTH 27
- #define ERACHR 0xE5
- #define DIRCHR '.'
- #define WEIRDC 5
- #define ENDDIR 0
- #define DIRATR 0x10
- #define VOLATR 8
-
- 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);
-
- struct files_t *files;
- unsigned int n_files,n_dirs; /* number of files and directories */
- int *clusters; /* pointer to array of cluster entries */
- /* int limits this to 32000 clusters */
- static unsigned int tn_files;
-
- /***
- *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 *)alloc(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 *)alloc(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)
- return(1);
-
- error:
- if (mem == 2)
- freep(files);
- if (mem)
- freep(clusters);
- if (status)
- {
- error.msg = err_msg[status];
- error.mod = module;
- error.num = status;
- error.func = "initfiles";
- if (status == NO_MEM)
- {
- if (mem)
- sprintf(ebuf,"files:%u",
- (num_clusters*sizeof(int))+1) + ((n_files+10)*sizeof(struct files_t));
- else
- sprintf(ebuf,"clusters:%u",(num_clusters*sizeof(int))+1);
- error.arg = ebuf;
- }
- }
- return(0);
- }
-
- static int getdir(unsigned long sector,int parent,int nsecs)
- {
- int c,d,temp;
- unsigned int i;
- register int j,k;
- unsigned l,templ;
- unsigned char *buffer;
- int status;
-
- status = 0;
-
- 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;
-
- for (i=0;i<sec_size;i+=32)
- {
- c=buffer[i];
- if (c==ERACHR || c==DIRCHR)
- continue;
- if (c==WEIRDC)
- buffer[i]=ERACHR;
- if (c==ENDDIR)
- {
- freep(buffer);
- return(n_files); /* so return */
- }
- d=buffer[i+ATTRIB]; /* d = attrib */
- l=buffer[i+CLUSTL] + (buffer[i+CLUSTH]*256); /* l = starting cluster */
- if (d&VOLATR)
- {
- for (j=0;j<FILELEN;j++) /* get volume label */
- volume[j]=buffer[i+j];
- volume[j]='\0';
- continue;
- }
- if (l==0) /* skip 0 length files */
- continue;
-
- for (j=0,k=0;j<FILELEN;j++) /* get filename */
- {
- if (buffer[i+j]==' ')
- continue;
- if (j==FILENAM)
- files[n_files].name[k++]='.';
- files[n_files].name[k++]=buffer[i+j];
- }
- files[n_files].name[k]='\0';
- 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 (d&DIRATR) /* is a directory */
- {
- ++n_dirs;
- files[n_files-1].dir = 1;
- templ = l;
- temp = n_files-1;
- if (!getdir(clustertosector(l),temp,secs_cluster))
- goto error;
- while ((k = clusters[templ]) > 0)
- {
- clusters[templ] = temp;
- if (!getdir(clustertosector(k),temp,secs_cluster))
- goto error;
- templ = k;
- }
- clusters[templ] = temp;
- }
- else
- {
- while ((k = clusters[l]) > 0)
- {
- if ((unsigned int)k == l)
- {
- status = FAT_PHASE;
- goto error;
- }
- clusters[l] = n_files-1;
- l = k;
- }
- clusters[l] = n_files-1;
- }
- }
- }
- freep(buffer);
- return(n_files);
-
- error:
- freep(buffer);
- if (status)
- {
- if (status == INV_ST_CLUS)
- {
- sprintf(ebuf," \"%s\" (%04x)",gfile(n_files-1),l);
- error.arg = ebuf;
- }
- else if (status == NUM_FILES)
- {
- sprintf(ebuf," (%d)",n_files);
- error.arg = ebuf;
- }
- error.num = status;
- error.msg = err_msg[status];
- error.mod = module;
- error.func = "getdir";
- }
- return(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;
-
- 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)
- {
- error.num = status;
- error.mod = module;
- error.msg = err_msg[status];
- if (status==NO_MEM)
- {
- sprintf(ebuf,"%u",sec_size*nsecs);
- error.arg = ebuf;
- }
- else if (status==INV_CLUS)
- {
- sprintf(ebuf,"entry: %d value: %x",h,l);
- error.arg = ebuf;
- }
- }
- 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;
- unsigned int *pi;
- int n;
- unsigned int l;
- 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)
- {
- error.num = status;
- error.msg = err_msg[status];
- error.mod = module;
- if (status == NO_MEM)
- {
- sprintf(ebuf,"%u",sec_size);
- error.arg = ebuf;
- }
- else if (status == INV_CLUS)
- {
- sprintf(ebuf,"entry: %d value: %x",h,l);
- error.arg = ebuf;
- }
- }
- return(ERROR);
- }
-
- /* print file name */
-
- extern int pfile(char *file, unsigned int i)
- {
- while (i != 0)
- i = pfile(files[i].name,files[i].parent);
- putch('\\');
- printf(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)
- {
- flev[i++] = index;
- index = files[index].parent;
- }
- while (i)
- {
- strcat(buf,"\\");
- strcat(buf,files[flev[i-1]].name);
- --i;
- }
- return(buf);
- }
-
- /*
- Displays all of the numbers matching fnum in the clusters[] array.
- */
- extern void mapfile(int fnum,int base)
- {
- register unsigned int index;
-
- for (index=2;index<num_clusters;index++)
- {
- if (clusters[index]==fnum)
- {
- char buf[8];
- printf(itoa(index,buf,base));
- putch(' ');
- }
- }
- }
-
- extern int homefile(int fnum)
- {
- register unsigned int index;
- register unsigned int c;
-
- for (c=num_clusters+1,index=2;index<num_clusters;index++)
- if (clusters[index]==fnum)
- if (index<c)
- c=index;
- return((int)c);
- }
-
- extern int endfile(register int fnum)
- {
- register unsigned int index;
- register unsigned int c;
-
- for (c = 0,index = 2; index < num_clusters; index++)
- if (*(clusters+index) == fnum)
- if (index > c)
- c = index;
- return (int)c;
- }
-
- /* Returns the next cluster of the file that the current cluster is
- allocated to, wrapping at either end, returns 0 if current cluster
- is unallocated. Searches though the clusters[] array for matching
- file number.
- */
- extern int jumpfile(register unsigned int cluster, register int direction)
- {
- int fnum;
-
- if ((fnum = *(clusters+cluster))==0)
- return(0);
- for (cluster += direction;;cluster += direction)
- {
- if (direction == -1 && cluster < 2)
- cluster = num_clusters;
- if (direction == 1 && cluster > num_clusters)
- cluster = 2;
- if (*(clusters+cluster) == fnum)
- return(cluster);
- }
- }
-
- /*
- * Findfile: Returns the first cluster number of the passed filename
- * if it is in the files structure.
- *
- * 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 void mapdisk(int base)
- {
- register unsigned int i;
- int zeros=0,indash=0;
- char buf[10];
-
- for (i=2;i<num_clusters;i++)
- {
- if (clusters[i]>0)
- {
- if (zeros==2)
- putch(' ');
- if (zeros>1)
- {
- printf(itoa(i-1,buf,base));
- putch(' ');
- }
- if (zeros==1)
- putch(' ');
- zeros=indash=0;
- }
- else
- {
- if (zeros==1)
- zeros++;
- else if (zeros==0)
- {
- printf(itoa(i,buf,base));
- zeros++;
- }
- else if (!indash)
- {
- putch('-');
- indash=1;
- zeros++;
- }
- }
- }
- }
-
- extern unsigned int get_avail_clusters(void)
- {
- union REGS regs;
- #ifdef DISKED
- unsigned c,j;
-
- if (!Files)
- {
- #endif
- regs.x.ax = 0x3600;
- regs.x.dx = disk;
- intdos(®s,®s);
- return regs.x.bx;
- #ifdef DISKED
- }
- else
- for (c=0,j=2; j <= num_clusters; j++)
- if (clusters[j] == 0)
- ++c;
- return c;
- #endif
- }
-
- #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
-