Category : File Managers
Archive   : HOW-BIG2.ZIP
Filename : HOW-BIG2.C
#include "dos.h"
#include "stdlib.h"
#include "stdio.h"
/*===========================================================================*\
|| HOW-BIG ||
|| Copyright (C) 1987 Rip Toren ||
|| POB 674 ||
|| Columbia, MD 21045 ||
|| ||
|| Will display (may be redirected to a file) the sub-directory struct. ||
|| under the current directory. For each entry the total size of the ||
|| file (in bytes) will be display, followed by the total byte count for ||
|| all the sub-directories under that one. This will allow you to tell ||
|| where (or at lest which branch) is using up most of your disk space. ||
|| This process is limited to 20 levels of sub-directories, just as ||
|| a sanity check on the recursion. ||
|| ||
||===========================================================================||
|| INVOKATION ||
|| ||
|| >HOW-BIG d v ||
|| d = display = [0|1] 0 is default. ||
|| v = verbosity = [0|1|2|3|4] 0 is default. ||
|| ||
||===========================================================================||
|| HISTORY ||
|| 5-27-87 V2 Rip Toren, Columbia MD ||
|| 5-01-87 Original release Rip Toren, Columbia MD ||
|| ||
||===========================================================================||
|| DEVELOPMENT data ||
|| The program was compiled with Lattice 'C' 3.1 in a small memory ||
|| model. There are a number of DOS specific functions that you may have ||
|| to supply if they are not part of your compiler: ||
|| ||
|| dfind - DOS service 0x4E find first match ||
|| dnext - DOS service 0x4F find next match ||
|| In Lattice, these only work in current directory ??? ||
|| chdir - DOS service 0x3B change directory ||
|| getdsk - DOS service 0x19 get default drive (a:=0) ||
|| getdfs - DOS service 0x1B get disk stats ||
|| ||
|| DEBUGING ||
|| I have left in all the conditional debugging statements. You may ||
|| watch the process take place by defining "DEBUG" in the beginning. ||
|| You may also obtain much of the data with a verbosity of 4. ||
|| ||
||===========================================================================||
|| DATA STRUCTURE ||
|| +------------------------+ ||
|| root -> | name | ||
|| ^ | bytes in files | ||
|| | | clusters (if children) | ||
|| | | 1st child pointer | --------+ ||
|| | | twin pointer | -----+ | ||
|| |----- | parent pointer | | | ||
|| +------------------------+ | | ||
|| | | ||
|| V V ||
|| ||
|| a CHILD is the first sub-directory inder this parent on the next ||
|| level down. The child entries are linked as TWINS. ||
|| ||
|| a TWIN is the second (and all subsequent) directories under the same ||
|| parent at this level. ||
|| ||
|| ||
\*===========================================================================*/
/*===========================================================================*\
|| attributes in HEX ||
|| 01 = read-only 10 = subdirectory ||
|| 02 = hidden 20 = arcvive bit ||
|| 04 = system ||
|| 08 = vol label all others are zero upon return ! ||
\*===========================================================================*/
#ifdef DEBUG
#define chdir do_chdir
#endif
#define VERBOSE(x) if (verbose_cnt >= x )
/*------------------------------------------------------------------------*\
| storage for disk and file data |
\*------------------------------------------------------------------------*/
struct FILEINFO fi; /* Lattice dfind data */
struct DISKINFO di; /* Lattice getdfs data */
/*------------------------------------------------------------------------*\
| Allocated for each directory entry in the tree. |
\*------------------------------------------------------------------------*/
struct sub_d {
char sd_name [13]; /* simple name - no slash */
int child_cnt; /* how many sub-dirs under on next lev*/
long bytes ; /* total current byte count */
long blocks ; /* total alloacation unit count */
long sd_bytes ; /* total child sub-dir byte count */
long sd_blocks; /* total sub-dir allocation count */
struct sub_d * _parent; /* pointer to parent */
struct sub_d * _twin; /* pointer to first child of current */
struct sub_d * _child; /* pointer to twin under same parent */
} ;
typedef struct sub_d * sd_ptr;
typedef struct sub_d sd_member;
/*------------------------------------------------------------------------*\
| Forward definitions |
\*------------------------------------------------------------------------*/
sd_ptr add_twin();
sd_ptr add_child();
sd_ptr new_member();
/*------------------------------------------------------------------------*\
| Other incidental items |
\*------------------------------------------------------------------------*/
sd_ptr root_ptr; /* 1st entry in string */
char start_point[75]; /* full name of starting directory */
int child_level ; /* count the number of levels down */
char drive [2]; /* build drive letter */
char curr_dir [65]; /* current directory we are in */
long bytes_per_cluster; /* V2 from us int */
char dbug_dir [65]; /* result of VERBOSE get dir name */
static int
verbose_cnt = 0; /* wants to watch progress */
display_var = 0; /* type of display */
/*-----------------------------------------------------------------------*\
| Lattice way to specify the amout of stack space. Each recursion |
| cost 81 bytes (each sub-directory) |
\*-----------------------------------------------------------------------*/
int _stack = 10000;
/*===========================================================================*\
|| ||
\*===========================================================================*/
main (argc,argv)
int argc;
char *argv[];
{
/*------------------------------------------------------------------------*\
| LOGO |
\*------------------------------------------------------------------------*/
puts ("HOW-BIG (2.0) Disk Utilization Display");
puts ("(C) 1987 Rip Toren, POB 674, Columbia MD 21045");
puts ("Non-commercial distribution authorized (*SHAREWARE*)\n");
/*------------------------------------------------------------------------*\
| Check for level of verbosity |
\*------------------------------------------------------------------------*/
if (argc >= 2) display_var = atoi (argv[1]);
if (argc == 3) verbose_cnt = atoi (argv[2]);
/*------------------------------------------------------------------------*\
| Set up blocking factor (cluster size) |
\*------------------------------------------------------------------------*/
getdfs (0,&di);
bytes_per_cluster = (di.bps * di.spc);
VERBOSE(1) {
printf ("Bytes per sector : %d\n",di.bps);
printf ("Sectors per cluster: %d\n",di.spc);
printf ("Bytes per cluster : %ld\n",bytes_per_cluster);
printf ("Clusters per drive : %d\n",di.cpd);
printf ("Free clusters : %d\n\n",di.free);
}
/*------------------------------------------------------------------------*\
| establish current drive |
\*------------------------------------------------------------------------*/
drive[0] = getdsk() + 'A';
drive[1] = 0;
strcpy (curr_dir,drive); /* get the letter */
strcat (curr_dir,":\\"); /* append the :\ */
/*------------------------------------------------------------------------*\
| insert the first node in the chain |
\*------------------------------------------------------------------------*/
root_ptr = new_member(); /* insert member for current dir. */
if (getcd (0,start_point) ==0) { /* build full name for curr dir. */
strcpy (root_ptr -> sd_name, start_point);
strins(start_point,":\\");
strins(start_point,drive);
}
/*------------------------------------------------------------------------*\
| Initialize where we are |
\*------------------------------------------------------------------------*/
child_level =0;
proc_dir (root_ptr); /* extract its byte count & sub-dirs. */
/*------------------------------------------------------------------------*\
| Done building memory chains, return to start and display |
\*------------------------------------------------------------------------*/
chdir (start_point); /* be sure back in starting dir. */
list_chain (root_ptr, ""); /* display the results */
}
/*===========================================================================*\
|| Recursive procedure to look through each directory ||
|| Accumulate the byte and block counts. Add any newly found sub-dirs to ||
|| the chains. Then do a 'depth-first' search down the child chain, folowed ||
|| by a look at the next twin on this level. ||
\*===========================================================================*/
proc_dir(here)
sd_ptr here;
{
int s; /* status code */
sd_ptr h1; /* temp holder for the pointer */
char my_dir[65]; /* the location of this directory */
strcpy (my_dir, curr_dir);
getcd (0,&my_dir[3]); /* full path after the drive:\ */
VERBOSE(2) {
printf ("PROC_DIR passed name = [%-13s], getcd = <%s>\n",
here -> sd_name,my_dir);
}
/*------------------------------------------------------------------------*\
| locate first file in directory |
\*------------------------------------------------------------------------*/
s = dfind (&fi, "*.*",0x37); /* not VOL LABEL */
if (s != 0) { /* ERROR */
fprintf (stderr,"ERROR in 'dfind' = %d name = %s\n",
s, here -> sd_name);
return;
}
/*------------------------------------------------------------------------*\
| Now get the rest of the files |
\*------------------------------------------------------------------------*/
while (s == 0) { /* while there are more entries */
if (fi.attr != 0x10) { /* a file !! not equal sub-dir */
here -> bytes += fi.size; /* add on the bytes */
/*----------------------------------------------------------------*\
| If file has some bytes, add on the the cluster allocations |
\*----------------------------------------------------------------*/
if (fi.size > 0 )
here -> blocks += ((long)fi.size / bytes_per_cluster) + 1;
}
else { /* sub-directory */
if (fi.name[0] != '.') { /* not self-references or parent */
VERBOSE(2) {
printf (" Add sub-dir [%-13s] to [%-13s] as child\n",
fi.name,here -> sd_name);
}
h1 = add_child (here); /* add sub-dir. under 'here' */
/* insert the name of the sub-dir. */
strcpy(h1 -> sd_name,fi.name);
}
}
s = dnext (&fi); /* and on to the next ! */
}
/*------------------------------------------------------------------------*\
| Have accumulated all space in this dir as well as added any |
| child sub-directories. Now start a 'depth first' search down |
| through the children. After that look for the next directory |
| on this level (TWIN) and process it. |
\*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*\
| now look at the child directories |
\*------------------------------------------------------------------------*/
VERBOSE(3) {
getcd(0,dbug_dir); /* Insure what dir we are in */
printf (" PROC_DIR [%-13s] looking for child. current dir = <%s>\n",
here -> sd_name,dbug_dir);
}
if (here -> _child != NULL) { /* Has sub-dirs. */
VERBOSE(3) {
printf (" has child named [%-13s]\n",here -> _child -> sd_name);
}
if (child_level++ > 20) { /* check for too much depth */
puts ("PROC_DIR (recursive error ?) child_level too deep");
exit(-1);
}
/* move down to the child */
chdir (here -> _child -> sd_name);
proc_dir ( here -> _child ); /* proc single child */
}
/*------------------------------------------------------------------------*\
| Now check for twins |
| a twin is the second or subsequent child of the parent |
| |
\*------------------------------------------------------------------------*/
VERBOSE(3) {
getcd(0,dbug_dir);
printf (" PROC_DIR [%-13s] looking for twin. current dir = <%s>\n",
here -> sd_name,dbug_dir);
}
if (here -> _twin != NULL) { /* no twins */
chdir (".."); /* back to parent */
/* down to twin */
VERBOSE(3) {
printf (" has twin named [%-13s]\n",here -> _twin -> sd_name);
}
chdir (here -> _twin -> sd_name);
proc_dir ( here -> _twin ); /* proc single twin */
/*--------------------------------------------------------------------*\
| Now reset to 'my_dir' to keep things current, just in case |
| since the twin did not know the name of the sub-dir prior. |
\*--------------------------------------------------------------------*/
chdir (my_dir);
}
/*------------------------------------------------------------------------*\
| NOW UPDATE COUNTS IN THE PARENT as to the total byte count, as well |
| the block (cluster) count for this child directory. |
\*------------------------------------------------------------------------*/
if (here -> _parent != NULL) { /* root has no parent! */
here -> _parent -> sd_bytes += (here -> bytes) + (here -> sd_bytes);
here -> _parent -> sd_blocks+= (here -> blocks) + (here -> sd_blocks);
}
chdir (".."); /* back to parent */
child_level --; /* back up a level */
return;
}
/*===========================================================================*\
|| ADD_CHILD ||
|| add a child record under the given parent. If the parent ||
|| Return a pointer to the new allocation, so that the name may be filled in ||
|| ||
\*===========================================================================*/
sd_ptr
add_child (parent)
sd_ptr parent;
{
sd_ptr new_child;
VERBOSE(4) printf (" ADD_CHILD to %s\n",parent -> sd_name);
if (parent -> _child != NULL) { /* already has one */
VERBOSE(4) printf (" already has child, add a twin\n");
parent -> child_cnt ++;
return (add_twin (parent -> _child));
}
new_child = new_member(); /* allocate space */
new_child -> _parent = parent; /* set back pointer */
parent -> _child = new_child; /* set parent pointer */
parent -> child_cnt ++; /* need this for graphic display */
return (new_child); /* return allocation pointer */
}
/*===========================================================================*\
|| ADD_TWIN ||
|| Allocate a new member and link it as a twin to the entry passed. ||
|| ||
\*===========================================================================*/
sd_ptr
add_twin (sibling)
sd_ptr sibling;
{
sd_ptr sib_ptr;
VERBOSE(4) printf (" ADD_TWIN to %s\n",sibling-> sd_name);
/* search twin chain */
for (sib_ptr = sibling;
sib_ptr -> _twin != NULL;
sib_ptr = sib_ptr -> _twin);
sib_ptr -> _twin = new_member(); /* allocate it & add to chain */
/* set parent pointer */
sib_ptr -> _twin -> _parent = sibling -> _parent;
return (sib_ptr -> _twin) ; /* return allocation pointer */
}
/*===========================================================================*\
|| NEW_MEMBER ||
|| Allocate and init a new member for someone. ||
\*===========================================================================*/
sd_ptr
new_member ()
{
sd_ptr nm;
VERBOSE(4) printf (" .... NEW_MEMBER\n");
nm = (sd_ptr) calloc (sizeof (sd_member),1);
if (nm == NULL) {
puts ("Error during new member allocation");
exit (-1);
}
nm -> child_cnt = 0; /* I don't trust calloc */
nm -> _parent = NULL;
nm -> _twin = NULL;
nm -> _child = NULL;
return (nm);
}
/*===========================================================================*\
|| LIST_CHAIN ||
|| Recursive process to list out the items in the list. The 'offset' ||
|| supplied is the grapgic string to place in from of this entry when ||
|| it is printed. ||
|| ||
\*===========================================================================*/
list_chain (sdpt,offset)
sd_ptr sdpt;
char *offset;
{
static int at_root = 1;
char my_offset [50];
char * direct_name;
int lastm;
float perc1, perc2;
long space1, space2;
strcpy (my_offset,offset); /* make my copy to pass along */
/*------------------------------------------------------------------------*\
| 'lastm' is the length of the offset -2. On the initial entry, a value |
| <0 indicates the first entry. On all others, it is the symbols that |
| were used on the last level. These need to be adjusted for |
| continueing vertical line between sub-dirs on higher levels. |
\*------------------------------------------------------------------------*/
lastm=strlen(offset)-2; /* figure outif outer values must chng*/
if (at_root ) { /* Top level only */
puts (" This Directory (All Sub-Directories)");
puts (" dsk spc slack dsk spc ");
}
do {
/* is this the top? use start point */
if (sdpt != root_ptr) direct_name = sdpt -> sd_name;
else direct_name = start_point;
/* get rid of tail on last child line */
if (sdpt -> _parent -> child_cnt == 1)
my_offset [lastm] = 0xc0;
/*--------------------------------------------------------------------*\
| Compute the slack percentage |
\*--------------------------------------------------------------------*/
space1 = (sdpt -> blocks * bytes_per_cluster) - sdpt -> bytes;
if (space1 > 0)
perc1 = ((float)space1 / (float)(sdpt -> blocks * bytes_per_cluster)) * 100.0;
else perc1 = 0;
/* space2 = (sdpt -> sd_blocks * bytes_per_cluster) - sdpt -> sd_bytes;
-- if (space2 > 0)
-- perc2 = ((float)space2 / (float)(sdpt -> sd_blocks * bytes_per_cluster) ) * 100.0;
-- else perc2 = 0;
*/
/*--------------------------------------------------------------------*\
| Print the line itself. |
\*--------------------------------------------------------------------*/
if (display_var == 0) { /* leading numbers */
if (sdpt -> sd_blocks > 0)
printf ("%6ldk %4.1f%% (%6ldk) %s%-s\n",
(long) ((sdpt -> blocks * bytes_per_cluster) / 1024),
perc1,
(long) ((sdpt -> sd_blocks * bytes_per_cluster) / 1024),
my_offset,direct_name);
else
printf ("%6ldk %4.1f%% ( ) %s%-s\n",
(long) ((sdpt -> blocks * bytes_per_cluster) / 1024),
perc1,
my_offset,direct_name);
}
else /* trailing numbers for subs */ {
if (sdpt -> sd_blocks > 0)
printf ("%6ldk %4.1f%% %s%-s ++(%ldk) \n",
(long) ((sdpt -> blocks * bytes_per_cluster) / 1024),
perc1,
my_offset,direct_name,
(long) ((sdpt -> sd_blocks * bytes_per_cluster) / 1024));
else
printf ("%6ldk %4.1f%% %s%-s\n",
(long) ((sdpt -> blocks * bytes_per_cluster) / 1024),
perc1,
my_offset,direct_name);
}
/*--------------------------------------------------------------------*\
| If we are not at the root, decrement the child count for this |
| entries parent. |
\*--------------------------------------------------------------------*/
if (at_root) at_root = 0;
else sdpt -> _parent -> child_cnt --;
if (sdpt -> child_cnt > 0) { /* this entry has children */
/*----------------------------------------------------------------*\
| adjust display above this level |
\*----------------------------------------------------------------*/
if (lastm >= 0) { /* below sdpt level */
if (my_offset[lastm] == 0xc3) my_offset[lastm] = 0xb3;
else my_offset[lastm] = ' ';
my_offset[lastm+1] = ' ';
}
/*----------------------------------------------------------------*\
| add new character to offset for next level |
\*----------------------------------------------------------------*/
if (lastm >= 0) {
if (sdpt -> child_cnt > 1) strcat (my_offset,"\xc3\xc4");
else strcat (my_offset,"\xc0\xc4");
}
else
strcat (my_offset,"\xc3\xc4");
if (sdpt -> _child != NULL) /* do that one */
list_chain (sdpt -> _child,my_offset);
strcpy (my_offset,offset); /* make my copy to pass along */
}
sdpt = sdpt -> _twin; /* process the next on same level */
} while (sdpt != NULL); /* while there are some */
return;
}
#ifdef DEBUG
#undef chdir
do_chdir(s)
char *s;
{
char pdir[60];
getcd (0,pdir);
printf ("> FROM [%s] -> [%s] = ", pdir,s);
chdir (s);
getcd (0,pdir);
printf ("<%s>\n",pdir);
}
#endif
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/