home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Supreme Volume 6 #1
/
swsii.zip
/
swsii
/
165
/
CHKFRA.ZIP
/
CHKFRAG.C
< prev
next >
Wrap
Text File
|
1992-03-11
|
46KB
|
1,002 lines
/***************************************************
* *
* chkfrag - check disk for fragmentation *
* *
***************************************************/
/* ******************************************************************** *
Maintenance log
Version Date Description Who
------- -------- -------------------------------------- ----------
1.0 to 1.3 Various bug fixes Flanders/Holmes
1.3
1.4 16Dec91 DOS 5 compatibility Flanders/Holmes
.. Read FAT greater than 64K long
.. Minor compiler error on readlabel()
.. Compiles under MSC 6.0
.. Added pack pragma to remove need for
/Zp operand on compile
(Thanks to J. Stephen Myers for his fixes
to v1.2)
1.5 15Jan92 Two unrelated bugs .. Flanders
.. /F returned EXTRA SEGMENT value.
Now returns free segments.
.. Didn't check SUBST under DOS 5
(Thanks to Bruce Vrana for reporting
these bugs!)
1.6 16Jan92 Didn't recognize a LANTASTIC local Flanders/Holmes
shared drive as a network drive
1.7 11Mar92 Miscalulated 12 or 16 bit fat fixed Flanders/Holmes
* ******************************************************************** */
#pragma pack(1) /* Pack to byte alignment */
#include <stdio.h> /* standard library */
#include <dos.h> /* dos access and registers */
#include <malloc.h> /* memory allocation */
#include <stdlib.h> /* common lib modules */
#define UINT unsigned int /* unsigned integer type */
#define ULONG unsigned long /* unsigned long type */
#define NOT ! /* logical not */
#define BOOT b_rec /* boot record shorthand */
#define FILES (_A_SYSTEM | _A_HIDDEN | _A_SUBDIR) /* files type */
#define LABEL (_A_VOLID) /* label type */
#define CLEAR(s,c) strclr(s,c,sizeof(s)) /* string clear */
/*
* Globals
*/
char huge *fat, /* address of FAT */
cdrive[66], /* startup drive and path */
fat_16; /* true if 16 bit FAT entries */
int sections = 0, /* file sections */
secsize = 0 , /* sector size of drive */
frag = 0, /* fragmented files */
unfrag = 0, /* unfragmented files */
freespaces = 0, /* freespaces */
files = 0, /* processed files */
dirs = 0, /* processed directories */
dos4 = 0, /* use dos version 4 int24 */
list = 0; /* list frag'd files switch */
UINT nclusters, /* number of clusters */
sdrive; /* startup drive */
long nsectors; /* number of sectors on drive */
/*
* formal declarations
*/
void get_fat(int), /* read FAT into memory */
cfexit(int), /* exit routine */
check_frag(char *, UINT, int), /* check if file/dir is frag'd */
dir_search(char *), /* search directory */
strclr(char *, int, int), /* clear a string */
check_unlinked(); /* check for unlinked clusters */
int chkdrv(char); /* check local, SUBST/ASSIGN */
char *fname(char *, char*), /* fcb filename to normal fname */
*readlabel(int), /* read the drive label */
*translate_name(char far *); /* translate name */
long next_cluster(UINT, int, int *); /* find the next cluster in FAT */
struct fcb
{
char hexff; /* extended fcb first byte */
char extra[5]; /* extended fcb work area */
char attrib; /* extended fcb attribute */
char drive; /* fcb - drive */
char filename[8]; /* fcb - filename */
char ext[3]; /* fcb - extension */
unsigned
int block; /* fcb - block number */
unsigned
long filesize; /* fcb - file size */
int date; /* fcb - file date */
char system[10]; /* fcb - reserved area */
char record; /* fcb - current record */
unsigned
long rnd_recno; /* fcb - random record number */
} ;
/************************************************************************
* *
* mainline *
* *
************************************************************************/
main(argc, argv)
int argc; /* count of arguments */
char *argv[]; /* argument strings */
{
long pf = 0; /* percent fragmented */
UINT rc; /* return code */
int ctc = 0, /* return code chosen */
dc = 0, /* drive chosen */
pe = 0, /* parm in error */
i, j, /* loop counter, work */
option = 0; /* program option */
char *p; /* work pointer */
static
char drive[] = " :\\", /* drive and path to check */
*rc_type[] =
{ "Percentage",
"Number of Files",
"Number of Extra Segments",
"Number of Free Areas" },
*suggestion[] =
{ "No fragmentation found -- Defrag unnecessary",
"Little fragmentation -- Defrag optional",
"Moderate fragmentation -- Defrag should be performed soon",
"Fragmentation critical -- Defrag or Backup/Format/Restore" },
*errors[] =
{ "Invalid drive specified",
"Cannot CHKFRAG a network drive",
"Cannot CHKFRAG a SUBST'd or ASSIGN'd drive",
"Must run with DOS 2.0 or greater" },
*options[] =
{ "/%", "/N", "/E", "/F", "/L", "/4"} ;
printf("CHKFRAG 1.7 -- Copyright (c) 1992 Ziff Communications Co.\n%s%c%s\n",
"PC Magazine ", 254, " Bob Flanders & Michael Holmes\n");
_dos_getdrive(&sdrive); /* get the default drive */
*drive = sdrive + 'A' - 1; /* ..setup default drive */
for (i = 1; i < argc; i++) /* check each argument */
{
strupr(p = argv[i]); /* uppercase argument */
if (strlen(p) == 2 && p[1] == ':') /* q. drive parm specified? */
{
*drive = *p; /* a. yes .. setup drive */
dc++; /* .. show drive selected */
}
else
{
for (j = 0; strcmp(p, options[j]) /* search arguments */
&& (j < 6); j++);
switch(j) /* based on argument */
{
case 0: /* /% option */
case 1: /* /N option */
case 2: /* /E option */
case 3: /* /F option */
option = j; /* set up the option value */
ctc++; /* increment code type count*/
break; /* exit switch */
case 4: /* /L switch */
list++; /* .. show listing wanted */
break;
case 5: /* /4 switch */
dos4++; /* .. use version 4 int25 */
break;
case 6: /* error */
pe = j; /* argument in error */
break; /* .. error */
}
}
}
if (pe || (ctc > 1) || (list>1) || (dc > 1))/* q. any error? */
{ /* a. yes .. handle error */
printf("\n\tformat\tCHKFRAG [d:] [/%% | /N | /E] [/L]\n\n");
printf("\twhere\td: is the drive to check for fragmentation\n");
printf("\t\t/%% sets errorlevel as a percentage\n");
printf("\t\t/N sets errorlevel to number of fragmented files (max 254)\n");
printf("\t\t/E sets errorlevel number of extra sections (max 254)\n");
printf("\t\t/F sets errorlevel number of free space areas (max 254)\n");
printf("\t\t/L causes fragmented files to be listed\n");
printf("\t\t/4 causes DOS 4.0 interface to be used\n");
cfexit(255);
}
_dos_setdrive((*drive-'A')+1, &i); /* set up the work drive */
getcwd(cdrive, sizeof(cdrive)); /* get current drive/path */
if (i = chkdrv(*drive)) /* check drive, version err */
{
printf("Error: %s", errors[--i]); /* display any error */
cfexit(255); /* tell the batch job */
}
get_fat(*drive - 'A'); /* read FAT into memory */
dir_search(drive); /* search for files */
check_unlinked(); /* check unlinked clusters */
if (files + dirs) /* q. any files and dirs? */
pf = ((long) frag * 100L) / /* a. yes .. % files frag'd */
(files + dirs);
if (!pf && frag) /* q. something frag'd */
pf = 1; /* a. yes .. show non-zero */
printf("\n%d Files, %d Directories,\n", /* report to user */
files, dirs);
printf("%d Unfragmented, %d Fragmented, %d Extra Sections, %d Free Spaces\n",
unfrag, frag, sections, freespaces);
printf("%d%% of files are fragmented\n\n", pf);
switch(option) /* return w/errorlevel */
{
case 0: /* percentage return */
rc = pf;
break;
case 1: /* files return */
rc = frag;
break;
case 2: /* extra sections return */
rc = sections;
break;
case 3: /* freespace areas */
rc = freespaces;
}
if (pf == 0) /* q. no fragments? */
i = 0; /* a. yes .. tell 'em */
else if (pf < 11) /* q. little fragmentation? */
i = 1; /* a. yes .. set index */
else if (pf < 76) /* q. moderate fragm'tion */
i = 2; /* a. yes .. setup msg */
else
i = 3; /* ..push the button, Jim */
printf("%s%s\nCHKFRAG finished, Return code %d\n\n%s%s\n",
"Return type chosen: ", rc_type[option], rc,
"Suggestion:\n ", suggestion[i]);
cfexit(rc > 254 ? 254 : rc);; /* return w/errorlevel */
}
/************************************************************************
* *
* get_fat -- read boot record and fat into memory *
* *
************************************************************************/
void get_fat(drv)
int drv; /* drive number */
{
UINT i; /* work */
long max_secs, /* Maximum sectors to read */
next_sector, /* next sector to start read at */
num_secs; /* number of sectors to read */
char huge *fat_ptr; /* pointer into fat buffer */
int rc; /* return code work area */
union REGS r; /* work registers */
struct SREGS s; /* ..and work segment regs */
struct bootrec
{
char jmp[3], /* jump instruction */
oem[8]; /* OEM name */
UINT bytes; /* bytes per sector */
char cluster; /* sectors per cluster */
UINT res_sectors; /* reserved sectors */
char fats; /* number of fats */
UINT roots, /* number of root dir entries */
sectors; /* total sectors */
char media; /* media descriptor block */
UINT fatsize, /* sectors per fat */
tracksize, /* sectors per track */
heads; /* number of heads */
long hidden, /* hidden sectors */
sectors_32; /* sectors if above 32Mb */
} far *b_rec; /* boot record definition */
struct dos4_i25 /* dos 4.0 int 25 block */
{
long sector; /* sector to read */
int num_secs; /* number of sectors to read */
char far *read_addr; /* address of input area */
} d4_i25, far *d4_i25p; /* area and pointer */
char *nomem = "Not enough memory for processing\n";
r.h.ah = 0x36; /* ah = get freespace */
r.h.dl = drv + 1; /* get drive */
int86(0x21, &r, &r); /* r.x.cx = bytes/sector */
if ((BOOT = (struct bootrec far *) malloc(r.x.cx)) == NULL)
{ /* q. no memory? */
printf(nomem); /* a. yes .. give */
cfexit(255); /* ..error msg/exit */
}
if (dos4) /* dos version 4 interface? */
{
r.x.cx = -1; /* cx = 0xffff */
d4_i25.sector = 0L; /* read sector 0 */
d4_i25.num_secs = 1; /* .. for 1 sector */
d4_i25.read_addr = (char far *) BOOT; /* .. into boot record */
d4_i25p = &d4_i25; /* set up pointer */
r.x.bx = FP_OFF(d4_i25p); /* bx = offset of parm block*/
s.ds = FP_SEG(d4_i25p); /* ds = segment of block */
}
else
{
r.x.cx = 1; /* cx = number of sectors */
r.x.dx = 0; /* dx = starting sector */
r.x.bx = FP_OFF(BOOT); /* bx = offset of buffer */
s.ds = FP_SEG(BOOT); /* ds = segment of buffer */
}
r.h.al = drv; /* al = drive number */
int86x(0x25, &r, &r, &s); /* read boot sector */
if (r.x.cflag) /* q. error reading disk? */
{
printf("Error reading boot record\n"); /* a. yes .. give error msg */
cfexit(255); /* ..and return to DOS */
}
nsectors = (BOOT->sectors ? (long) BOOT->sectors : BOOT->sectors_32);
if ((fat = (char huge *) halloc((long) BOOT->fatsize * (long) BOOT->bytes, 1))
== (char huge *) NULL)
{ /* q. no memory? */
printf(nomem); /* a. yes .. give */
cfexit(255); /* ..error msg/exit */
}
if (dos4) /* dos version 4 interface? */
{
max_secs = 65536L / BOOT->bytes; /* max we can read/int 25 */
fat_ptr = (char far *) fat; /* initial offset in table */
next_sector = BOOT->res_sectors; /* get first sector of FAT */
d4_i25p = &d4_i25; /* set up pointer */
for (num_secs = BOOT->fatsize; /* get number of secs to rd */
num_secs;) /* while there are some left*/
{
r.x.cx = -1; /* cx = 0xffff */
d4_i25.sector = next_sector; /* read FAT area */
d4_i25.read_addr = fat_ptr; /* point at target of read */
num_secs -= /* size of next read ... */
(d4_i25.num_secs = /* .. size of this read */
min(max_secs, num_secs));/* .. .. smaller of max, num*/
next_sector += d4_i25.num_secs; /* Calc next sector number */
fat_ptr += (long) d4_i25.num_secs * /* Calc next buffer address */
BOOT->bytes;
r.x.bx = FP_OFF(d4_i25p); /* bx = offset of parm block*/
s.ds = FP_SEG(d4_i25p); /* ds = segment of block */
r.h.al = drv; /* al = drive number */
int86x(0x25, &r, &r, &s); /* read boot sector */
}
}
else
{
r.x.cx = BOOT->fatsize; /* cx = number of sectors */
r.x.dx = BOOT->res_sectors; /* dx = starting sector */
r.x.bx = FP_OFF(fat); /* bx = offset of buffer */
s.ds = FP_SEG(fat); /* ds = segment of buffer */
r.h.al = drv; /* al = drive number */
int86x(0x25, &r, &r, &s); /* read boot sector */
}
if (r.x.cflag) /* q. error reading disk? */
{
printf("%02.2x %02.2x Error reading FAT\n",
r.h.ah, r.x.di); /* a. yes .. give error msg */
cfexit(255); /* ..and return to DOS */
}
nclusters = (nsectors - (BOOT->res_sectors
+ (BOOT->fatsize * BOOT->fats)
+ ((BOOT->roots * 32) / BOOT->bytes)))
/ BOOT->cluster;
fat_16 = nclusters > 4086; /* set if 16bit FAT tbl */
printf("Drive %c:%s %lu Sectors, %u Clusters, %u Clustersize\n",
drv + 'A', readlabel(drv + 'A'),
nsectors,
nclusters,
BOOT->cluster * BOOT->bytes);
printf("\nChecking disk structure ..");
for(i = 2; i < nclusters;) /* look for freespaces */
{
if (next_cluster(i, 2, &rc) == 0) /* q. free? */
{
freespaces++; /* a. yes. increment free count */
while ((next_cluster(i, 2, &rc) == 0) && ( i < nclusters) )
i++; /* skip free spaces */
}
else
i++; /* else .. check next cluster */
}
}
/************************************************************************
* *
* check_frag -- check a file/directory for fragmentation *
* *
************************************************************************/
void check_frag(s, n, dflag)
char *s; /* file/directory name */
UINT n; /* starting cluster number */
int dflag; /* directory flag */
{
UINT i, j; /* working storage */
long nc; /* next cluster */
int flag = 0, /* flag for frag'd file */
rc; /* error return code */
for(; nc = next_cluster(n, 1, &rc); n = nc) /* walk down the chain */
{
if (nc < 0) /* q. invalid cluster? */
{
printf("\n\t%s -- %s%s\n%s\n", /* a. yes .. give err msg */
s, rc ? "Invalid cluster detected"
: "File cross-linked",
", Run aborted",
"\n\t** Please run CHKDSK **");
cfexit(255); /* ..and exit w/error code */
}
if ((n + 1) != nc) /* q. non-contiguous area? */
{
flag++; /* show fragmented file */
if (nc > n) /* q. possibly bad cluster? */
{
for (j = n + 1; /* check for bad spots */
next_cluster(j, 0, &rc) == 0xfff7 && j < nc;
j++);
if (j == i) /* q. was entire area bad? */
flag--; /* a. yes .. don't report */
else
sections++; /* incr files sections count*/
}
else
sections++; /* incr files sections count*/
}
}
if (flag) /* q. fragmented file */
{
if (NOT frag && list) /* q. first frag file? */
printf("\nFragmented Files/Directories:\n");
if (list) /* q. list frag'd files? */
printf("%s%s\n", /* a. yes .. give it to them*/
dflag ? "DIR> " : " ", s);
frag++; /* accumulate frag'd count */
}
else
unfrag++; /* else total unfrag'd files*/
}
/************************************************************************
* *
* next_cluster -- return next cluster number from FAT *
* *
************************************************************************/
long next_cluster(n, x, rc)
UINT n; /* current cluster number */
int x, /* flag, 1 = reset FAT entry */
*rc; /* error return code */
{
ULONG e; /* entry number in FAT */
long nc; /* next cluster value */
UINT huge *p, /* pointer for 16 bit FAT entry */
mask1, mask2; /* mask for and'ing and or'ing */
int flag; /* shift/and flag */
*rc = 0; /* clear return code */
nc = n; /* initialize nc */
if (! (e = nc)) /* q. invalid cluster nbr */
return(0); /* a. yes .. rtn EOF */
if (fat_16) /* q. 16 bit FAT entries? */
{
p = (UINT huge *) &fat[0]; /* a. yes .. get FAT addr */
nc = p[e]; /* retrieve next entry */
if (x == 2) /* q. return value? */
return(nc); /* a. yes .. return it */
if (NOT nc) /* q. unallocated cluster? */
{
nc = -1; /* a. yes .. error condition*/
*rc = 1; /* set return code */
}
if (x == 1) /* q. need to reset entry? */
p[e] = 1; /* a. yes .. show processed */
if (nc >= 0xfff0 && nc != 0xfff7) /* q. reserved and not bad */
nc = 0; /* a. yes .. show EOF */
}
else
{
e = (nc << 1) + nc; /* cluster number * 3 */
flag = e & 1; /* need to do shift later? */
e >>= 1; /* cluster number * 1.5 */
nc = *(UINT huge *) &fat[e]; /* get next cluster */
if (flag) /* q. need to do shift? */
{
nc >>= 4; /* a. yes .. shift by 4 bits*/
mask1 = 0x000f; /* mask to clear upper bits */
mask2 = 0x0010; /* ..and footprint mask */
}
else
{
nc &= 0xfff; /* else .. strip upper bits */
mask1 = 0xf000; /* mask to clear lower bits */
mask2 = 0x0001; /* ..and footprint mask */
}
if (x == 2) /* q. return value? */
return(nc); /* a. yes .. return value */
if (NOT nc) /* q. unallocated cluster? */
{
nc = -1; /* a. yes .. error condition*/
*rc = 1; /* set return code */
}
if (x == 1) /* q. need to reset entry? */
{
*(UINT huge *) &fat[e] &= mask1; /* a. yes .. 'and' off bits */
*(UINT huge *) &fat[e] |= mask2; /* ..and put down footprint */
}
if (nc >= 0xff0) /* q. EOF/reserved range? */
if (nc == 0xff7) /* q. bad cluster? */
nc = 0xfff7; /* a. yes .. show bad one */
else
nc = 0; /* else .. show EOF */
}
return(nc);
}
/************************************************************************
* *
* check_unlinked -- check for unlinked clusters *
* *
************************************************************************/
void check_unlinked()
{
int rc; /* error return code */
UINT i; /* loop counter */
long j; /* work return cluster nbr */
for (i = 2; i < nclusters; i++) /* check thru entire FAT */
{
if ((j = next_cluster(i, 2, &rc)) != 0 /* q. unallocated cluster? */
&& j != 1 /* ..or used */
&& j != 0xfff7) /* ..or bad cluster? */
{
printf("\nLost clusters detected, %s%s",/* a. no .. give msg */
"Run aborted\n",
"\t** Please run CHKDSK **\n");
cfexit(255); /* ..and exit w/error */
}
}
}
/************************************************************************
* *
* dir_search -- recursively search all files & subdirectories *
* *
************************************************************************/
void dir_search(base_dir)
char *base_dir; /* base subdirectory to search */
{
int oldds, /* old dta segment */
oldda; /* old dta address */
char pass, /* pass number */
work_dir[65], /* work directory */
first_done; /* find first done */
struct fcb find_work; /* fcb work area */
/*
* The following areas are STATIC .. not allocated on recursion
*/
static
struct SREGS s; /* segment registers */
static
union REGS r; /* other registers */
static
char far *cftmp, /* work pointer */
*bc = "\\|/-"; /* bar characters to use */
static
int rc, /* work return code */
bar = 0; /* next bar character */
static
union
{
char dtabuff[128]; /* dta area */
struct /* Disk transfer area layout */
{
char dta1[6]; /* first part of dta */
char attrib; /* attribute byte */
char drive; /* drive */
char filename[8]; /* filename */
char ext[3]; /* extension */
char d_attrib; /* directory attribute */
char dta2[10]; /* more reserved space */
unsigned
int d_time; /* directory time */
unsigned
int d_date; /* directory date */
unsigned
int d_cluster; /* first cluster */
unsigned
long d_filesize; /* size of file */
} dta;
} dta;
/*
* End of static area
*/
r.h.ah = 0x2f; /* ah = get dta */
int86x(0x21, &r, &r, &s); /* .. ask DOS */
oldds = s.es; /* save old DTA segment */
oldda = r.x.bx; /* .. and offset */
cftmp = (char far *) &dta; /* get current fcb address */
r.h.ah = 0x1a; /* ah = set DTA */
s.ds = FP_SEG(cftmp); /* ds -> DTA segment */
r.x.dx = FP_OFF(cftmp); /* ds:dx -> DTA */
int86x(0x21, &r, &r, &s); /* setup new DTA */
if (strcmp(base_dir, translate_name(base_dir))) /* q. JOIN'd? */
return; /* a. yes .. skip it */
chdir(base_dir); /* get the base directory */
for(first_done=pass=0;;) /* look through current dir */
{
if (first_done == 0) /* q. find first done? */
{ /* a. no .. do it */
if (base_dir[1] == ':') /* q. disk specified? */
find_work.drive = /* a. yes .. set fcb drive */
((base_dir[0] & 0xdf) - 'A') + 1;
else
find_work.drive = 0; /* else use default */
find_work.hexff = 0xff; /* extended fcb */
CLEAR(find_work.extra, 0); /* set extra area */
CLEAR(find_work.filename, '?'); /* .. and file name */
CLEAR(find_work.ext, '?'); /* .. and extension */
find_work.attrib = FILES; /* set up attribute to find */
r.h.ah = 0x11; /* ah = find first */
cftmp = (char far *) &find_work; /* get pointer to work fcb */
s.ds = FP_SEG(cftmp); /* ds -> segment of fcb */
r.x.dx = FP_OFF(cftmp); /* ds:dx -> offset */
int86x(0x21, &r, &r, &s); /* .. find first */
rc = r.h.al; /* get return code */
first_done = 1; /* first find done */
}
else
{
r.h.ah = 0x12; /* ah = find next */
cftmp = (char far *) &find_work; /* get pointer to work fcb */
s.ds = FP_SEG(cftmp); /* ds -> segment of fcb */
r.x.dx = FP_OFF(cftmp); /* ds:dx -> offset */
int86x(0x21, &r, &r, &s); /* .. find first */
rc = r.h.al; /* get return code */
}
if (NOT list) /* q. list in progress? */
{ /* a. no .. */
fprintf(stderr, "%c%c", bc[bar], 8);/* print bar, backspace */
if (++bar > 3) /* q. limit on chars? */
bar = 0; /* a. yes .. reset to zero */
}
strcpy(work_dir, base_dir); /* get current base */
if (work_dir[strlen(work_dir)-1] != '\\') /* if needed .. */
strcat(work_dir, "\\"); /* .. add a backslash */
strcat(work_dir, /* .. add the name */
fname(dta.dta.filename, dta.dta.ext));
if (pass) /* q. second pass? */
{
if (rc) /* q. more files found? */
break; /* a. no .. exit */
if (!(dta.dta.d_attrib & _A_SUBDIR) /* q. directory? */
|| (dta.dta.filename[0] == '.')) /* .. or a dot dir? */
continue; /* a. get next entry */
dirs++; /* accumulate dir count */
dir_search(work_dir); /* recursively call ourself */
}
else /* first pass processing */
{
if (rc) /* q. anything found? */
{ /* a. no .. */
first_done = 0; /* re-execute find-first */
pass++; /* go to next pass */
continue; /* .. continue processing */
}
if (dta.dta.filename[0] == '.') /* q. dot directory? */
continue; /* a. yes .. skip it */
if (!(dta.dta.d_attrib & _A_SUBDIR)) /* q. a file? */
files++; /* a. yes .. count them */
check_frag(work_dir, /* check for frag'd file */
dta.dta.d_cluster,
dta.dta.d_attrib & _A_SUBDIR);
}
}
r.h.ah = 0x1a; /* ah = set DTA */
s.ds = oldds; /* ds -> DTA segment */
r.x.dx = oldda; /* ds:dx -> DTA */
int86x(0x21, &r, &r, &s); /* setup new DTA */
}
/************************************************************************
* *
* fname -- build a normalized filename from an FCB *
* *
************************************************************************/
char *fname(filename, ext)
char *filename; /* filename with trailing blanks*/
char *ext; /* extension */
{
int i; /* loop control */
char *p; /* work pointer */
static
char fwork[13]; /* returned work area */
p = fwork; /* initialize string pointer*/
for (i = 0; (i < 8) && (*filename != ' '); i++) /* move fname w/o blanks*/
*p++ = *filename++;
if (*ext != ' ') /* q. extension blank? */
{
*p++ = '.'; /* a. no .. add the dot */
for (i = 0; (i < 3) && (*ext != ' '); i++) /* add ext w/o blanks */
*p++ = *ext++;
}
*p = 0; /* terminate string w/null */
return(fwork); /* return string to caller */
}
/************************************************************************
* *
* strclr -- clear an area to a value *
* *
************************************************************************/
void strclr(s, c, n)
char *s; /* area to initialize */
int c, /* value to use */
n; /* length of area to clear */
{
while(n--) /* initialize whole area */
*s++ = c; /* ..to value specified */
}
/************************************************************************
* *
* translate_name -- translate a DOS name *
* *
************************************************************************/
char *translate_name(name)
char far *name; /* name to translate */
{
static
char translate_area[65], /* work/return area */
far *sp; /* work pointer */
union REGS r; /* work registers */
struct SREGS s; /* ..and work segment regs */
r.h.ah = 0x60; /* ah = translate */
sp = (char far *) name; /* set up a pointer .. */
r.x.si = FP_OFF(sp); /* set pointer to input name */
s.ds = FP_SEG(sp); /* .. and segment */
sp = (char far *) translate_area; /* set up a pointer .. */
r.x.di = FP_OFF(sp); /* set pointer to output area */
s.es = FP_SEG(sp); /* .. and segment */
int86x(0x21, &r, &r, &s); /* translate the name */
if (r.x.cflag) /* if bad name .. */
return((char far *) NULL); /* .. return error */
else
return(translate_area); /* return xlated name */
}
/************************************************************************
* *
* chkdrv -- assure drive is LOCAL and not SUBST'd or ASSIGN'd *
* *
************************************************************************/
int chkdrv(c)
char c; /* drive to check */
{
static
char wdrv[] = " :\\"; /* work area for drive name */
union REGS r; /* work registers */
struct SREGS s; /* ..and work segment regs */
if (_osmajor < 2) /* q. pre-DOS 2.00? */
return(4); /* a. yes .. can't run it */
if ((_osmajor >= 3) || /* q. Higher than DOS 3.. */
((_osmajor = 3) && (_osminor >= 1))) /* - or - Higher than 3.1? */
{
r.x.ax = 0x4409; /* ah = ioctl, local test */
r.h.bl = (c - 'A') + 1; /* bl = drive to test */
int86(0x21, &r, &r); /* test drive */
if (r.x.cflag) /* q. bad drive? */
return(1); /* a. yes .. error */
if (r.x.dx & 0x1200) /* q. remote? */
return(2); /* a. yes .. error */
wdrv[0] = c; /* set up name */
if (strcmp(wdrv, translate_name(wdrv))) /* q. SUBST or ASSIGNED? */
return(3); /* a. yes .. return error */
}
dos4 |= (_osmajor > 3); /* check for dos v.4 */
return(0); /* return ok */
}
/************************************************************************
* *
* Read drive label, if available *
* *
************************************************************************/
char *readlabel(c)
int c; /* drive to check */
{
char *p, *q; /* work pointers */
struct find_t f; /* structure for directory entry*/
static
char work_dir[13] = { " :\\*.*" } ; /* directory to check */
work_dir[0] = c; /* setup for find first */
if (_dos_findfirst(work_dir, LABEL, &f)) /* q. error on label get? */
work_dir[0] = 0; /* a. yes .. then no label */
else
{
for(p = work_dir, q = f.name; *q; q++) /* copy label w/o middle . */
if (*q != '.') /* q. is this char a dot? */
*p++ = *q; /* a. no .. copy it */
*p = 0; /* terminate string */
}
return(work_dir); /* ..and return label string*/
}
/************************************************************************
* *
* cfexit() - return to DOS after resetting dir, dir *
* *
************************************************************************/
void cfexit(rc)
int rc; /* return code to exit with */
{
int i; /* work variable */
_dos_setdrive(sdrive, &i); /* reset the default drive */
chdir(cdrive); /* .. and directory */
exit(rc); /* .. and return to DOS */
}