home *** CD-ROM | disk | FTP | other *** search
- /*
- * DU - Disk Usage. A Unix style utility. Written by Peter Lim 07-Dec-87.
- *
- * Usage: du [-s] [-a] [-z] [-c] [-r] [-h] [-nnnn] [pathname(s) ... ]
- * where,
- * -s : Summary listing only (Toggle, default=off).
- * -a : Generate a list of all files
- * (Toggle, default=off).
- * -z : Show total statistics (Toggle, default=on).
- * -c : Show cluster size (Toggle, default=on).
- * -r : Recursive traversal of sub-directories
- * (Toggle, default=on).
- * -h : Include HIDDEN & SYSTEM files
- * (Toggle, default=off).
- * -nnnn : Force cluster size to be nnnn bytes.
- * nnnn = 0 releases previous forcing.
- * Default pathname is the current directory on current drive.
- */
-
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include "msd_dir.h"
- #include <dos.h>
- #include <strings.h>
- #include <ctype.h>
-
-
- unsigned long traverse_dir();
- unsigned long get_cluster_size();
- unsigned long get_path_size ();
- #define print_size(size, path) printf ("%-11lu%s\n", size, path)
-
- unsigned long bpc; /* number of bytes per cluster */
- int filecnt=0, dircnt=0;
- int summary=0, show_all=0, show_stat=1,
- show_cluster=1, force_cluster=0, recurse=1, incl_hidn=0;
- unsigned int att_mask;
-
- main (argc, argv)
- int argc;
- char **argv;
- {
- unsigned long total=0;
- int path_specified=0;
-
- for (; --argc > 0; ) {
- *++argv;
- if (**argv == '-')
- switch ((*argv)[1]) {
- case 's' :
- case 'S' :
- summary = !summary;
- continue;
- case 'z' :
- case 'Z' :
- show_stat = !show_stat;
- continue;
- case 'a' :
- case 'A' :
- show_all = !show_all;
- continue;
- case 'c' :
- case 'C' :
- show_cluster = !show_cluster;
- continue;
- case 'r' :
- case 'R' :
- recurse = !recurse;
- continue;
- case 'h' :
- case 'H' :
- incl_hidn = !incl_hidn;
- continue;
- default :
- if (!sscanf (*argv, "-%lu", &bpc))
- printf ("Unknown option %s\n", *argv);
- else
- force_cluster = bpc ? 1 : 0;
- continue;
- }
- path_specified = 1;
- /* At this point we know at least one path is specified. */
- total += get_path_size(*argv);
- }
-
- if (!path_specified)
- total = get_path_size(".");
- /* If no pathname were specified. */
-
- if (show_stat) {
- printf ("Total %d files in %d directories.\n", filecnt, dircnt);
- printf ("Total disk space used = %lu bytes (%.2lfk).\n",
- total, total / 1024.0);
- }
- }
-
-
- unsigned long get_path_size (pathname)
- char *pathname;
- {
- unsigned char drive_id;
- unsigned long total;
-
- if (incl_hidn)
- att_mask = (A_HIDDEN | A_SYSTEM);
- else
- att_mask = 0; /* Set attribute mask for files to find.
- A_DIR will always be set. */
- if (!force_cluster) {
- if (isalpha (*pathname) && (pathname[1] == ':'))
- drive_id = *pathname - ((islower(*pathname)) ? 'a' : 'A') + 1;
- else
- drive_id = 0;
- if (!(bpc = get_cluster_size(drive_id))) {
- printf ("Invalid drive %c\:\n", *pathname);
- exit (1);
- }
- }
- if (show_cluster)
- printf ("Cluster size = %lu bytes.\n", bpc);
- total = traverse_dir(pathname);
- if (summary)
- print_size (total, pathname);
- /* At least say something even if only summary is required. */
- return (total);
- }
-
-
- unsigned long traverse_dir(cur_path)
- char *cur_path;
- {
- DIR *dp;
- struct direct *direntry;
- char s[MAXPATHLEN+1];
- char c;
- unsigned long total, file_size;
- unsigned int dir_ent_cnt; /* Count the number of directory entry. */
- #define bpdent (unsigned int) 32
- /* Number of bytes per directory entry,
- = 32 from DOS 2.10 tech ref pp. 4-5. lim@mullian.oz */
- int not_root_dir;
-
- total = 0;
- if (!(dp=opendir(cur_path, att_mask))) {
- printf ("Can't open directory \"%s\" or memory allocation failure.\n",
- cur_path);
- exit(2);
- }
-
- if (recurse) {
- while (direntry=readdir(dp))
- if (((*direntry).d_attribute == A_DIR)
- && (strcmp ((*direntry).d_name, "."))
- && (strcmp ((*direntry).d_name, ".."))) {
- strcpy (s, cur_path);
- if ((c = s[strlen(s)-1]) != '\\' &&
- c != '/' && c != ':')
- strcat (s, "\\");
- strcat (s, (*direntry).d_name);
- total += traverse_dir(s);
- }
- (void) rewinddir(dp);
- }
-
- dir_ent_cnt = not_root_dir = 0;
- while (direntry=readdir(dp)) {
- dir_ent_cnt++;
- if ((*direntry).d_attribute != A_DIR) {
- total += file_size = ( ((*direntry).d_size / bpc) +
- (((*direntry).d_size % bpc) ? 1 : 0) ) * bpc;
- if (show_all) {
- strcpy (s, cur_path);
- if ((c = s[strlen(s)-1]) != '\\' && c != '/')
- strcat (s, "\\");
- print_size (file_size, strcat (s, (*direntry).d_name));
- }
- filecnt++; /* Counting all files (exclude dir). */
- }
- else if (!strcmp ((*direntry).d_name, ".")) {
- dircnt++; /* Counting every occurance of ".". */
- not_root_dir = 1;
- /* Not root directory if "." exist. */
- }
- }
- if (not_root_dir)
- total += ( ((dir_ent_cnt * bpdent) / bpc) +
- (((dir_ent_cnt * bpdent) % bpc) ? 1 : 0) ) * bpc;
- /* Add the number of directory entry counted * bytes per entry rounded
- up to the nearest cluster. The only things missed by this method of
- counting are the directories with a lot of erased files. Can't be
- helped without resorting to very low level FAT probing.
- NOTE: The root directory uses zero byte here - complying
- with CHKDSK from MS DOS. Another MS DOS quirk. */
- if (!summary)
- print_size (total, cur_path);
-
- closedir(dp);
- return (total);
- }
-
-
- #define DOSI_GDFREE 0x36;
- static union REGS reg, nreg;
-
- unsigned long get_cluster_size(drive_id)
- unsigned char drive_id;
- {
- reg.h.ah = DOSI_GDFREE;
- reg.h.dl = drive_id;
- intdos(®, &nreg);
- if (nreg.x.ax == 0xffff)
- return ((unsigned long) 0);
- else
- return ((unsigned long) nreg.x.cx * nreg.x.ax);
- }
-