home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 December / simtel1292_SIMTEL_1292_Walnut_Creek.iso / msdos / c / du.arc / DU.C next >
C/C++ Source or Header  |  1987-12-26  |  6KB  |  217 lines

  1. /*
  2.  * DU - Disk Usage. A Unix style utility. Written by Peter Lim 07-Dec-87.
  3.  *
  4.  *    Usage:  du [-s] [-a] [-z] [-c] [-r] [-h] [-nnnn] [pathname(s) ... ]
  5.  *        where,
  6.  *            -s : Summary listing only  (Toggle, default=off).
  7.  *            -a : Generate a list of all files
  8.  *                           (Toggle, default=off).
  9.  *            -z : Show total statistics (Toggle, default=on).
  10.  *            -c : Show cluster size       (Toggle, default=on).
  11.  *            -r : Recursive traversal of sub-directories
  12.  *                           (Toggle, default=on).
  13.  *            -h : Include HIDDEN & SYSTEM files
  14.  *                           (Toggle, default=off).
  15.  *            -nnnn : Force cluster size to be nnnn bytes.
  16.  *                nnnn = 0 releases previous forcing.
  17.  *        Default pathname is the current directory on current drive.
  18.  */
  19.  
  20. #include <stdio.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include "msd_dir.h"
  24. #include <dos.h>
  25. #include <strings.h>
  26. #include <ctype.h>
  27.  
  28.  
  29. unsigned long    traverse_dir();
  30. unsigned long    get_cluster_size();
  31. unsigned long    get_path_size ();
  32. #define  print_size(size, path)  printf ("%-11lu%s\n", size, path)
  33.  
  34. unsigned long    bpc;        /* number of bytes per cluster */
  35. int    filecnt=0, dircnt=0;
  36. int    summary=0, show_all=0, show_stat=1,
  37.     show_cluster=1, force_cluster=0, recurse=1, incl_hidn=0;
  38. unsigned int    att_mask;
  39.  
  40. main (argc, argv)
  41. int argc;
  42. char **argv;
  43. {
  44.     unsigned long    total=0;
  45.     int        path_specified=0;
  46.  
  47.     for (; --argc > 0; ) {
  48.         *++argv;
  49.         if (**argv == '-')
  50.             switch ((*argv)[1]) {
  51.                 case 's' :
  52.                 case 'S' :
  53.                     summary = !summary;
  54.                     continue;
  55.                 case 'z' :
  56.                 case 'Z' :
  57.                     show_stat = !show_stat;
  58.                     continue;
  59.                 case 'a' :
  60.                 case 'A' :
  61.                     show_all = !show_all;
  62.                     continue;
  63.                 case 'c' :
  64.                 case 'C' :
  65.                     show_cluster = !show_cluster;
  66.                     continue;
  67.                 case 'r' :
  68.                 case 'R' :
  69.                     recurse = !recurse;
  70.                     continue;
  71.                 case 'h' :
  72.                 case 'H' :
  73.                     incl_hidn = !incl_hidn;
  74.                     continue;
  75.                 default  :
  76.                     if (!sscanf (*argv, "-%lu", &bpc))
  77.                         printf ("Unknown option %s\n", *argv);
  78.                     else
  79.                         force_cluster = bpc ? 1 : 0;
  80.                     continue;
  81.             }
  82.         path_specified = 1;
  83.             /* At this point we know at least one path is specified. */
  84.         total += get_path_size(*argv);
  85.     }
  86.  
  87.     if (!path_specified)
  88.         total = get_path_size(".");
  89.         /* If no pathname were specified. */
  90.  
  91.     if (show_stat) {
  92.        printf ("Total %d files in %d directories.\n", filecnt, dircnt);
  93.        printf ("Total disk space used = %lu bytes (%.2lfk).\n",
  94.              total, total / 1024.0);
  95.     }
  96. }
  97.  
  98.  
  99. unsigned long    get_path_size (pathname)
  100. char *pathname;
  101. {
  102.     unsigned char    drive_id;
  103.     unsigned long    total;
  104.  
  105.     if (incl_hidn)
  106.         att_mask = (A_HIDDEN | A_SYSTEM);
  107.     else
  108.         att_mask = 0;    /* Set attribute mask for files to find.
  109.                    A_DIR will always be set. */
  110.     if (!force_cluster) {
  111.         if (isalpha (*pathname) && (pathname[1] == ':'))
  112.             drive_id = *pathname -  ((islower(*pathname)) ? 'a' : 'A') + 1;
  113.         else
  114.             drive_id = 0;
  115.         if (!(bpc =  get_cluster_size(drive_id))) {
  116.             printf ("Invalid drive %c\:\n", *pathname);
  117.             exit (1);
  118.         }
  119.     }
  120.     if (show_cluster)
  121.         printf ("Cluster size = %lu bytes.\n", bpc);
  122.     total = traverse_dir(pathname);
  123.     if (summary)
  124.         print_size (total, pathname);
  125.         /* At least say something even if only summary is required. */
  126.     return (total);
  127. }
  128.  
  129.  
  130. unsigned long    traverse_dir(cur_path)
  131. char    *cur_path;
  132. {
  133.     DIR *dp;
  134.     struct direct *direntry;
  135.     char    s[MAXPATHLEN+1];
  136.     char    c;
  137.     unsigned long    total, file_size;
  138.     unsigned int    dir_ent_cnt;    /* Count the number of directory entry. */
  139.     #define  bpdent (unsigned int) 32
  140.         /* Number of bytes per directory entry,
  141.            = 32 from DOS 2.10 tech ref pp. 4-5.  lim@mullian.oz */
  142.     int    not_root_dir;
  143.  
  144.     total = 0;
  145.     if (!(dp=opendir(cur_path, att_mask))) {
  146.         printf ("Can't open directory \"%s\" or memory allocation failure.\n",
  147.             cur_path);
  148.         exit(2);
  149.     }
  150.  
  151.     if (recurse) {
  152.         while (direntry=readdir(dp))
  153.             if (((*direntry).d_attribute == A_DIR)
  154.                 && (strcmp ((*direntry).d_name, "."))
  155.                 && (strcmp ((*direntry).d_name, ".."))) {
  156.                    strcpy (s, cur_path);
  157.                    if ((c = s[strlen(s)-1]) != '\\' &&
  158.                     c != '/' && c != ':')
  159.                     strcat (s, "\\");
  160.                    strcat (s, (*direntry).d_name);
  161.                     total += traverse_dir(s);
  162.             }
  163.         (void)    rewinddir(dp);
  164.     }
  165.  
  166.     dir_ent_cnt = not_root_dir = 0;
  167.     while (direntry=readdir(dp)) {
  168.         dir_ent_cnt++;
  169.         if ((*direntry).d_attribute != A_DIR) {
  170.             total += file_size = ( ((*direntry).d_size / bpc) +
  171.                  (((*direntry).d_size % bpc) ? 1 : 0) ) * bpc;
  172.             if (show_all) {
  173.                 strcpy (s, cur_path);
  174.                 if ((c = s[strlen(s)-1]) != '\\' && c != '/')
  175.                     strcat (s, "\\");
  176.                 print_size (file_size, strcat (s, (*direntry).d_name));
  177.             }
  178.             filecnt++;    /* Counting all files (exclude dir). */
  179.         }
  180.         else if (!strcmp ((*direntry).d_name, ".")) {
  181.             dircnt++;    /* Counting every occurance of ".". */
  182.             not_root_dir = 1;
  183.             /* Not root directory if "." exist. */
  184.         }
  185.     }
  186.     if (not_root_dir)
  187.         total += ( ((dir_ent_cnt * bpdent) / bpc) +
  188.               (((dir_ent_cnt * bpdent) % bpc) ? 1 : 0) ) * bpc;
  189.         /* Add the number of directory entry counted * bytes per entry rounded
  190.            up to the nearest cluster. The only things missed by this method of
  191.            counting are the directories with a lot of erased files. Can't be
  192.            helped without resorting to very low level FAT probing.
  193.            NOTE: The root directory uses zero byte here - complying
  194.              with CHKDSK from MS DOS.  Another MS DOS quirk. */
  195.     if (!summary)
  196.         print_size (total, cur_path);
  197.  
  198.     closedir(dp);
  199.     return (total);
  200. }
  201.  
  202.  
  203. #define DOSI_GDFREE    0x36;
  204. static    union REGS    reg, nreg;
  205.  
  206. unsigned long get_cluster_size(drive_id)
  207. unsigned char    drive_id;
  208. {
  209.     reg.h.ah = DOSI_GDFREE;
  210.     reg.h.dl = drive_id;
  211.     intdos(®, &nreg);
  212.     if (nreg.x.ax == 0xffff)
  213.         return ((unsigned long) 0);
  214.     else
  215.         return ((unsigned long) nreg.x.cx * nreg.x.ax);
  216. }
  217.