home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume12 / du-pc / part01 next >
Encoding:
Text File  |  1990-05-05  |  23.1 KB  |  894 lines

  1. Newsgroups: comp.sources.misc
  2. From: exos:<@crdgw1.crd.ge.com:pnl@hpfinote.fc.hp.com>
  3. Subject: v12i017: Disk Usage program for PC (Re: Cluster Size)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 12, Issue 17
  7. Submitted-by: exos:<@crdgw1.crd.ge.com:pnl@hpfinote.fc.hp.com>
  8. Archive-name: du-pc/part01
  9.  
  10. [Time for comp.sources.ibm.pc, I think.  No, I am *not* going to create it.  :-}
  11. This is the first of two PC sources in this batch.
  12.  
  13. It's been a long week, between Dayton and ncoast losing a disk partition.
  14. I'm a bit behind, but hope to catch up if I don't get thrown off again.  ++bsa]
  15.  
  16. This shell archive contain the "DU" program as described below. A few
  17. people has requested this posting since I mentioned in comp.sys.ibm.pc
  18. that I have this program written some time ago. So, it might be a good
  19. idea to post it on comp.sources.ibm.pc.
  20.  
  21.  
  22. Regards,                       ## Life is fast enough as it is ........
  23. Peter Lim.                     ## .... DON'T PUSH IT !!          >>>-------,
  24.                                ########################################### :
  25. E-mail:  plim@hpsgwg.HP.COM     Snail-mail:  Hewlett Packard Singapore,    :
  26. Tel:     (065)-279-2289                      (ICDS, ICS)                   |
  27. Telnet:        520-2289                      1150 Depot Road,           __\@/__
  28.   ... also at: pnl@hpfipnl.HP.COM            Singapore   0410.           SPLAT !
  29.  
  30.  
  31. ---------------------- Program description ------------------------------------
  32.  
  33.   DU - Disk Usage. A Unix style utility. Written by Peter Lim 07-Dec-87.
  34.  
  35.      Usage:  du [-s] [-a] [-z] [-c] [-r] [-h] [-nnnn] [pathname(s) ... ]
  36.          where,
  37.              -s : Summary listing only  (Toggle, default=off).
  38.              -a : Generate a list of all files
  39.                             (Toggle, default=off).
  40.              -z : Show total statistics (Toggle, default=on).
  41.              -c : Show cluster size       (Toggle, default=on).
  42.              -r : Recursive traversal of sub-directories
  43.                             (Toggle, default=on).
  44.              -h : Include HIDDEN & SYSTEM files
  45.                             (Toggle, default=off).
  46.              -nnnn : Force cluster size to be nnnn bytes.
  47.                  nnnn = 0 releases previous forcing.
  48.          Default pathname is the current directory on current drive.
  49.  
  50.  
  51. #---------------------------------- cut here ----------------------------------
  52. # This is a shell archive.  Remove anything before this line,
  53. # then unpack it by saving it in a file and typing "sh file".
  54. #
  55. # Wrapped by Peter Lim <pnl@hpfipnl> on Thu Apr 19 12:00:52 1990
  56. #
  57. # This archive contains:
  58. #    du.hlp        du.c        make.msc    msd_dir.c    
  59. #    msd_dir.h    read.me        readme        showbug.c    
  60. #
  61. # Error checking via sum(1) will be performed.
  62.  
  63. LANG=""; export LANG
  64. PATH=/bin:/usr/bin:$PATH; export PATH
  65.  
  66. if sum -r </dev/null >/dev/null 2>&1
  67. then
  68.     sumopt='-r'
  69. else
  70.     sumopt=''
  71. fi
  72.  
  73. echo x - du.hlp
  74. cat >du.hlp <<'@EOF'
  75.  
  76.   DU - Disk Usage. A Unix style utility. Written by Peter Lim 07-Dec-87.
  77.  
  78.      Usage:  du [-s] [-a] [-z] [-c] [-r] [-h] [-nnnn] [pathname(s) ... ]
  79.          where,
  80.              -s : Summary listing only  (Toggle, default=off).
  81.              -a : Generate a list of all files
  82.                             (Toggle, default=off).
  83.              -z : Show total statistics (Toggle, default=on).
  84.              -c : Show cluster size       (Toggle, default=on).
  85.              -r : Recursive traversal of sub-directories
  86.                             (Toggle, default=on).
  87.              -h : Include HIDDEN & SYSTEM files
  88.                             (Toggle, default=off).
  89.              -nnnn : Force cluster size to be nnnn bytes.
  90.                  nnnn = 0 releases previous forcing.
  91.          Default pathname is the current directory on current drive.
  92.  
  93. @EOF
  94. set `sum $sumopt <du.hlp`; if test $1 -ne 22172
  95. then
  96.     echo ERROR: du.hlp checksum is $1 should be 22172
  97. fi
  98.  
  99. chmod 666 du.hlp
  100.  
  101. echo x - du.c
  102. cat >du.c <<'@EOF'
  103. /*
  104.  * DU - Disk Usage. A Unix style utility. Written by Peter Lim 07-Dec-87.
  105.  *
  106.  *    Usage:  du [-s] [-a] [-z] [-c] [-r] [-h] [-nnnn] [pathname(s) ... ]
  107.  *        where,
  108.  *            -s : Summary listing only  (Toggle, default=off).
  109.  *            -a : Generate a list of all files
  110.  *                           (Toggle, default=off).
  111.  *            -z : Show total statistics (Toggle, default=on).
  112.  *            -c : Show cluster size       (Toggle, default=on).
  113.  *            -r : Recursive traversal of sub-directories
  114.  *                           (Toggle, default=on).
  115.  *            -h : Include HIDDEN & SYSTEM files
  116.  *                           (Toggle, default=off).
  117.  *            -nnnn : Force cluster size to be nnnn bytes.
  118.  *                nnnn = 0 releases previous forcing.
  119.  *        Default pathname is the current directory on current drive.
  120.  */
  121.  
  122. #include <stdio.h>
  123. #include <sys/types.h>
  124. #include <sys/stat.h>
  125. #include "msd_dir.h"
  126. #include <dos.h>
  127. #include <strings.h>
  128. #include <ctype.h>
  129.  
  130.  
  131. unsigned long    traverse_dir();
  132. unsigned long    get_cluster_size();
  133. unsigned long    get_path_size ();
  134. #define  print_size(size, path)  printf ("%-11lu%s\n", size, path)
  135.  
  136. unsigned long    bpc;        /* number of bytes per cluster */
  137. int    filecnt=0, dircnt=0;
  138. int    summary=0, show_all=0, show_stat=1,
  139.     show_cluster=1, force_cluster=0, recurse=1, incl_hidn=0;
  140. unsigned int    att_mask;
  141.  
  142. main (argc, argv)
  143. int argc;
  144. char **argv;
  145. {
  146.     unsigned long    total=0;
  147.     int        path_specified=0;
  148.  
  149.     for (; --argc > 0; ) {
  150.         *++argv;
  151.         if (**argv == '-')
  152.             switch ((*argv)[1]) {
  153.                 case 's' :
  154.                 case 'S' :
  155.                     summary = !summary;
  156.                     continue;
  157.                 case 'z' :
  158.                 case 'Z' :
  159.                     show_stat = !show_stat;
  160.                     continue;
  161.                 case 'a' :
  162.                 case 'A' :
  163.                     show_all = !show_all;
  164.                     continue;
  165.                 case 'c' :
  166.                 case 'C' :
  167.                     show_cluster = !show_cluster;
  168.                     continue;
  169.                 case 'r' :
  170.                 case 'R' :
  171.                     recurse = !recurse;
  172.                     continue;
  173.                 case 'h' :
  174.                 case 'H' :
  175.                     incl_hidn = !incl_hidn;
  176.                     continue;
  177.                 default  :
  178.                     if (!sscanf (*argv, "-%lu", &bpc))
  179.                         printf ("Unknown option %s\n", *argv);
  180.                     else
  181.                         force_cluster = bpc ? 1 : 0;
  182.                     continue;
  183.             }
  184.         path_specified = 1;
  185.             /* At this point we know at least one path is specified. */
  186.         total += get_path_size(*argv);
  187.     }
  188.  
  189.     if (!path_specified)
  190.         total = get_path_size(".");
  191.         /* If no pathname were specified. */
  192.  
  193.     if (show_stat) {
  194.        printf ("Total %d files in %d directories.\n", filecnt, dircnt);
  195.        printf ("Total disk space used = %lu bytes (%.2lfk).\n",
  196.              total, total / 1024.0);
  197.     }
  198. }
  199.  
  200.  
  201. unsigned long    get_path_size (pathname)
  202. char *pathname;
  203. {
  204.     unsigned char    drive_id;
  205.     unsigned long    total;
  206.  
  207.     if (incl_hidn)
  208.         att_mask = (A_HIDDEN | A_SYSTEM);
  209.     else
  210.         att_mask = 0;    /* Set attribute mask for files to find.
  211.                    A_DIR will always be set. */
  212.     if (!force_cluster) {
  213.         if (isalpha (*pathname) && (pathname[1] == ':'))
  214.             drive_id = *pathname -  ((islower(*pathname)) ? 'a' : 'A') + 1;
  215.         else
  216.             drive_id = 0;
  217.         if (!(bpc =  get_cluster_size(drive_id))) {
  218.             printf ("Invalid drive %c\:\n", *pathname);
  219.             exit (1);
  220.         }
  221.     }
  222.     if (show_cluster)
  223.         printf ("Cluster size = %lu bytes.\n", bpc);
  224.     total = traverse_dir(pathname);
  225.     if (summary)
  226.         print_size (total, pathname);
  227.         /* At least say something even if only summary is required. */
  228.     return (total);
  229. }
  230.  
  231.  
  232. unsigned long    traverse_dir(cur_path)
  233. char    *cur_path;
  234. {
  235.     DIR *dp;
  236.     struct direct *direntry;
  237.     char    s[MAXPATHLEN+1];
  238.     char    c;
  239.     unsigned long    total, file_size;
  240.     unsigned int    dir_ent_cnt;    /* Count the number of directory entry. */
  241.     #define  bpdent (unsigned int) 32
  242.         /* Number of bytes per directory entry,
  243.            = 32 from DOS 2.10 tech ref pp. 4-5.  lim@mullian.oz */
  244.     int    not_root_dir;
  245.  
  246.     total = 0;
  247.     if (!(dp=opendir(cur_path, att_mask))) {
  248.         printf ("Can't open directory \"%s\" or memory allocation failure.\n",
  249.             cur_path);
  250.         exit(2);
  251.     }
  252.  
  253.     if (recurse) {
  254.         while (direntry=readdir(dp))
  255.             if (((*direntry).d_attribute == A_DIR)
  256.                 && (strcmp ((*direntry).d_name, "."))
  257.                 && (strcmp ((*direntry).d_name, ".."))) {
  258.                    strcpy (s, cur_path);
  259.                    if ((c = s[strlen(s)-1]) != '\\' &&
  260.                     c != '/' && c != ':')
  261.                     strcat (s, "\\");
  262.                    strcat (s, (*direntry).d_name);
  263.                     total += traverse_dir(s);
  264.             }
  265.         (void)    rewinddir(dp);
  266.     }
  267.  
  268.     dir_ent_cnt = not_root_dir = 0;
  269.     while (direntry=readdir(dp)) {
  270.         dir_ent_cnt++;
  271.         if ((*direntry).d_attribute != A_DIR) {
  272.             total += file_size = ( ((*direntry).d_size / bpc) +
  273.                  (((*direntry).d_size % bpc) ? 1 : 0) ) * bpc;
  274.             if (show_all) {
  275.                 strcpy (s, cur_path);
  276.                 if ((c = s[strlen(s)-1]) != '\\' && c != '/')
  277.                     strcat (s, "\\");
  278.                 print_size (file_size, strcat (s, (*direntry).d_name));
  279.             }
  280.             filecnt++;    /* Counting all files (exclude dir). */
  281.         }
  282.         else if (!strcmp ((*direntry).d_name, ".")) {
  283.             dircnt++;    /* Counting every occurance of ".". */
  284.             not_root_dir = 1;
  285.             /* Not root directory if "." exist. */
  286.         }
  287.     }
  288.     if (not_root_dir)
  289.         total += ( ((dir_ent_cnt * bpdent) / bpc) +
  290.               (((dir_ent_cnt * bpdent) % bpc) ? 1 : 0) ) * bpc;
  291.         /* Add the number of directory entry counted * bytes per entry rounded
  292.            up to the nearest cluster. The only things missed by this method of
  293.            counting are the directories with a lot of erased files. Can't be
  294.            helped without resorting to very low level FAT probing.
  295.            NOTE: The root directory uses zero byte here - complying
  296.              with CHKDSK from MS DOS.  Another MS DOS quirk. */
  297.     if (!summary)
  298.         print_size (total, cur_path);
  299.  
  300.     closedir(dp);
  301.     return (total);
  302. }
  303.  
  304.  
  305. #define DOSI_GDFREE    0x36;
  306. static    union REGS    reg, nreg;
  307.  
  308. unsigned long get_cluster_size(drive_id)
  309. unsigned char    drive_id;
  310. {
  311.     reg.h.ah = DOSI_GDFREE;
  312.     reg.h.dl = drive_id;
  313.     intdos(®, &nreg);
  314.     if (nreg.x.ax == 0xffff)
  315.         return ((unsigned long) 0);
  316.     else
  317.         return ((unsigned long) nreg.x.cx * nreg.x.ax);
  318. }
  319. @EOF
  320. set `sum $sumopt <du.c`; if test $1 -ne 6976
  321. then
  322.     echo ERROR: du.c checksum is $1 should be 6976
  323. fi
  324.  
  325. chmod 666 du.c
  326.  
  327. echo x - make.msc
  328. cat >make.msc <<'@EOF'
  329. CFLAGS = -AC -c
  330. LFLAGS = /STACK:20480
  331.  
  332. .c.obj:
  333.         cl $(CFLAGS) $*.c
  334.  
  335. du.obj:        du.c msd_dir.h
  336.  
  337. msd_dir.obj:    msd_dir.c msd_dir.h
  338.  
  339. du.exe:        du.obj msd_dir.obj
  340.         link $(LFLAGS) du+msd_dir;
  341. @EOF
  342. set `sum $sumopt <make.msc`; if test $1 -ne 16735
  343. then
  344.     echo ERROR: make.msc checksum is $1 should be 16735
  345. fi
  346.  
  347. chmod 666 make.msc
  348.  
  349. echo x - msd_dir.c
  350. cat >msd_dir.c <<'@EOF'
  351. /*
  352.  * @(#)msd_dir.c 1.4 87/11/06    Public Domain.
  353.  *
  354.  *  A public domain implementation of BSD directory routines for
  355.  *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
  356.  *  August 1897
  357.  *
  358.  *  Extended by Peter Lim (lim@mullian.oz) to overcome some MS DOS quirks
  359.  *  and returns 2 more pieces of information - file size & attribute.
  360.  *  Plus a little reshuffling of #define's positions    December 1987
  361.  */
  362.  
  363. #include    <stdio.h>
  364. #include    <sys/types.h>
  365. #include    <sys/stat.h>
  366. #include    "msd_dir.h"
  367. #include    <malloc.h>
  368. #include    <string.h>
  369. #include    <ctype.h>
  370. #include    <dos.h>
  371. #include    <direct.h>
  372.  
  373. #ifndef    NULL
  374. # define    NULL    0
  375. #endif    /* NULL */
  376.  
  377. /* dos call values */
  378. #define    DOSI_FINDF    0x4e
  379. #define    DOSI_FINDN    0x4f
  380. #define    DOSI_SDTA    0x1a
  381. #define DOSI_GCDIR    0x47
  382.  
  383. #define    Newisnull(a, t)        ((a = (t *) malloc(sizeof(t))) == (t *) NULL)
  384.  
  385. /* what find first/next calls look use */
  386. typedef struct {
  387.     char        d_buf[21];
  388.     char        d_attribute;
  389.     unsigned short    d_time;
  390.     unsigned short    d_date;
  391.     unsigned long    d_size;
  392.     char        d_name[13];
  393. } Dta_buf;
  394.  
  395. static    char    *getdirent();
  396. static    void    setdta();
  397. static    void    free_dircontents();
  398. static    char    *extgetcwd();
  399.  
  400. static    Dta_buf        dtabuf;
  401. static    Dta_buf        *dtapnt = &dtabuf;
  402. static    union REGS    reg, nreg;
  403.  
  404. #if    defined(M_I86LM)
  405. static    struct SREGS    sreg;
  406. #endif
  407.  
  408. DIR    *
  409. opendir(pathname, att_mask)
  410.     char    *pathname;
  411.     unsigned int    att_mask;
  412. {
  413.     struct    stat        statb;
  414.     DIR            *dirp;
  415.     char            c;
  416.     char            *s;
  417.     struct _dircontents    *dp;
  418.     char            nbuf[MAXPATHLEN + 1];
  419.     char            name[MAXPATHLEN + 1];
  420.     unsigned char        drive_id;
  421.     char            *phead;
  422.     
  423.     strcpy (name, pathname);
  424.         /* Work on temporary buffer only. Never write it back,
  425.            the calling argument may not have room for it ! */
  426.     if (stat(name, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR) {
  427.         /* Give it a second try, after modifying input pathname,
  428.            before giving up to counter some MS DOS quirks.
  429.            This kludge is fairly simple and will not handle weird
  430.            though valid path name correctly such as multiple ../.. and
  431.            other mix which eventually end up on the root directory. */
  432.         if (isalpha (*name) && (name[1] == ':')) {
  433.             drive_id = *name -  ((islower(*name)) ? 'a' : 'A') + 1;
  434.             phead = pathname+2;
  435.         }
  436.         else {
  437.             drive_id = 0;
  438.             phead = pathname;
  439.         }
  440.         if ((c = name[strlen(name) - 1]) == '\\' || c == '/')
  441.             name[strlen(name) - 1] = NULL;
  442.             /* Try removing one trailing / or \ */
  443.         if (*phead == '.' || *phead == '\0') {
  444.             /* If . or nothing specified, assume current directory
  445.                and go get the directory. */
  446.             if (extgetcwd (drive_id, name, MAXPATHLEN) == NULL)
  447.                 return (DIR *) NULL;
  448.             strcpy (nbuf, name);
  449.             /* There is an undocumented BUG in MSC 4.0 such that
  450.                stat (root, ..) will cause the current directory on the
  451.                specified drive to be changed to root if the current
  452.                directory in question is exactly one level deep !
  453.                So, keep current directory for chdir() back after doing
  454.                stat (root, ..).  lim@mullian.oz */
  455.             if (*(phead+1) == '.') {
  456.                 /* i.e. ".." specified. Then backup one level. Firstly
  457.                     check that we are not already at the root. */
  458.                 if (name[strlen(name) - 1] == '\\')
  459.                     return (DIR *) NULL;
  460.                 while (name[strlen(name) - 1] != '\\')
  461.                     name[strlen(name) - 1] = NULL;
  462.                 if (*(phead+2) == '\\' || *(phead+2) == '/')
  463.                     /* Make sure we don't have a '\' double up. */
  464.                     strcat (name, phead+3);
  465.             }
  466.             else if (*(phead) == '.')
  467.                 /* Just plain "." specified. */
  468.                 strcat (name, phead+1);
  469.         }
  470.         else
  471.             *nbuf = NULL;        /* Don't chdir() wrongly. */
  472.         if (stat(name, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR)
  473.             return (DIR *) NULL;
  474.         if (*nbuf)
  475.             (void) chdir (nbuf);    /* Fixing the stat() BUG ! */
  476.     }
  477.     if (Newisnull(dirp, DIR))
  478.         return (DIR *) NULL;
  479.     if (*name && (c = name[strlen(name) - 1]) != '\\' && c != '/')
  480.         (void) strcat(strcpy(nbuf, name), "\\*.*");
  481.     else
  482.         (void) strcat(strcpy(nbuf, name), "*.*");
  483.     dirp->dd_loc = 0;
  484.     setdta();
  485.     dirp->dd_contents = dirp->dd_cp = (struct _dircontents *) NULL;
  486.     if ((s = getdirent(nbuf, att_mask | A_DIR)) == (char *) NULL)
  487.         return dirp;
  488.     do {
  489.         if (Newisnull(dp, struct _dircontents) || (dp->_d_entry =
  490.             (char *) malloc((unsigned) (strlen(s) + 1))) == (char *) NULL)
  491.         {
  492.             if (dp)
  493.                 free((char *) dp);
  494.             free_dircontents(dirp->dd_contents);
  495.             return (DIR *) NULL;
  496.         }
  497.         if (dirp->dd_contents)
  498.             dirp->dd_cp = dirp->dd_cp->_d_next = dp;
  499.         else
  500.             dirp->dd_contents = dirp->dd_cp = dp;
  501.         (void) strcpy(dp->_d_entry, s);
  502.         dp->d_attribute = dtabuf.d_attribute;
  503.         dp->d_size = dtabuf.d_size;
  504.         /* A SUPER Kludge ! Using 'dtabuf' as global variable. lim@mullian.oz */
  505.         dp->_d_next = (struct _dircontents *) NULL;
  506.     } while ((s = getdirent((char *) NULL, att_mask | A_DIR)) != (char *) NULL);
  507.     dirp->dd_cp = dirp->dd_contents;
  508.  
  509.     return dirp;
  510. }
  511.  
  512. void
  513. closedir(dirp)
  514.     DIR    *dirp;
  515. {
  516.     free_dircontents(dirp->dd_contents);
  517.     free((char *) dirp);
  518. }
  519.  
  520. struct direct    *
  521. readdir(dirp)
  522.     DIR    *dirp;
  523. {
  524.     static    struct direct    dp;
  525.     
  526.     if (dirp->dd_cp == (struct _dircontents *) NULL)
  527.         return (struct direct *) NULL;
  528.     dp.d_namlen = dp.d_reclen =
  529.         strlen(strcpy(dp.d_name, dirp->dd_cp->_d_entry));
  530.     dp.d_ino = 0;
  531.     dp.d_attribute = dirp->dd_cp->d_attribute;
  532.     dp.d_size = dirp->dd_cp->d_size;
  533.     dirp->dd_cp = dirp->dd_cp->_d_next;
  534.     dirp->dd_loc++;
  535.  
  536.     return &dp;
  537. }
  538.  
  539. void
  540. seekdir(dirp, off)
  541.     DIR    *dirp;
  542.     long    off;
  543. {
  544.     long            i = off;
  545.     struct _dircontents    *dp;
  546.  
  547.     if (off < 0)
  548.         return;
  549.     for (dp = dirp->dd_contents ; --i >= 0 && dp ; dp = dp->_d_next)
  550.         ;
  551.     dirp->dd_loc = off - (i + 1);
  552.     dirp->dd_cp = dp;
  553. }
  554.  
  555. long
  556. telldir(dirp)
  557.     DIR    *dirp;
  558. {
  559.     return dirp->dd_loc;
  560. }
  561.  
  562. static    void
  563. free_dircontents(dp)
  564.     struct    _dircontents    *dp;
  565. {
  566.     struct _dircontents    *odp;
  567.  
  568.     while (dp) {
  569.         if (dp->_d_entry)
  570.             free(dp->_d_entry);
  571.         dp = (odp = dp)->_d_next;
  572.         free((char *) odp);
  573.     }
  574. }
  575.  
  576. static    char    *
  577. getdirent(dir, att_mask)
  578.     char    *dir;
  579.     unsigned int    att_mask;
  580. {
  581.     if (dir != (char *) NULL) {        /* get first entry */
  582.         reg.h.ah = DOSI_FINDF;
  583.         reg.h.cl = att_mask;
  584. #if    defined(M_I86LM)
  585.         reg.x.dx = FP_OFF(dir);
  586.         sreg.ds = FP_SEG(dir);
  587. #else
  588.         reg.x.dx = (unsigned) dir;
  589. #endif
  590.     } else {                /* get next entry */
  591.         reg.h.ah = DOSI_FINDN;
  592. #if    defined(M_I86LM)
  593.         reg.x.dx = FP_OFF(dtapnt);
  594.         sreg.ds = FP_SEG(dtapnt);
  595. #else
  596.         reg.x.dx = (unsigned) dtapnt;
  597. #endif
  598.     }
  599. #if    defined(M_I86LM)
  600.     intdosx(®, &nreg, &sreg);
  601. #else
  602.     intdos(®, &nreg);
  603. #endif
  604.     if (nreg.x.cflag)
  605.         return (char *) NULL;
  606.  
  607.     return dtabuf.d_name;
  608. }
  609.  
  610. static    void
  611. setdta()
  612. {
  613.     reg.h.ah = DOSI_SDTA;
  614. #if    defined(M_I86LM)
  615.     reg.x.dx = FP_OFF(dtapnt);
  616.     sreg.ds = FP_SEG(dtapnt);
  617.     intdosx(®, &nreg, &sreg);
  618. #else
  619.     reg.x.dx = (int) dtapnt;
  620.     intdos(®, &nreg);
  621. #endif
  622. }
  623.  
  624. static    char    *extgetcwd(drive_id, buffer, buffer_size)
  625. /* Extended get current directory on specified drive.  Peter Lim 07-Dec-87. */
  626. unsigned char drive_id;
  627. char *buffer;
  628. int  buffer_size;
  629. {
  630.     char    tmpbuffer[MAXPATHLEN+1];
  631.  
  632.     if (!drive_id)
  633.         return (getcwd (buffer, buffer_size));
  634.     /* If it is current drive, use the standard getcwd() */
  635.  
  636.     reg.h.ah = DOSI_GCDIR;
  637.     reg.h.dl = drive_id;
  638. #if    defined(M_I86LM)
  639.     reg.x.si = FP_OFF(tmpbuffer);
  640.     sreg.ds = FP_SEG(tmpbuffer);
  641.     intdosx(®, &nreg, &sreg);
  642. #else
  643.     reg.x.si = (int) tmpbuffer;
  644.     intdos(®, &nreg);
  645. #endif
  646.     if (nreg.x.ax == 0xf)
  647.         return ((char *) NULL);
  648.         /* Invalid drive specification. */
  649.     else {
  650.         if (drive_id)
  651.             sprintf (buffer, "%c:\\%s", drive_id+'A'-1, tmpbuffer);
  652.         else
  653.             sprintf (buffer, "\\%s", tmpbuffer);
  654.         return (buffer);
  655.     }
  656. }
  657. @EOF
  658. set `sum $sumopt <msd_dir.c`; if test $1 -ne 34566
  659. then
  660.     echo ERROR: msd_dir.c checksum is $1 should be 34566
  661. fi
  662.  
  663. chmod 666 msd_dir.c
  664.  
  665. echo x - msd_dir.h
  666. cat >msd_dir.h <<'@EOF'
  667. /*
  668.  * @(#)msd_dir.h 1.4 87/11/06    Public Domain.
  669.  *
  670.  *  A public domain implementation of BSD directory routines for
  671.  *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
  672.  *  August 1897
  673.  *
  674.  *  Extended by Peter Lim (lim@mullian.oz) to overcome some MS DOS quirks
  675.  *  and returns 2 more pieces of information - file size & attribute.
  676.  *  Plus a little reshuffling of some #define's positions    December 1987
  677.  */
  678.  
  679. #define    rewinddir(dirp)    seekdir(dirp, 0L)
  680.  
  681. #define    MAXNAMLEN    12
  682.  
  683. #ifndef    MAXPATHLEN
  684. # define    MAXPATHLEN    255
  685. #endif    /* MAXPATHLEN */
  686.  
  687. /* attribute stuff */
  688. #define    A_RONLY        0x01
  689. #define    A_HIDDEN    0x02
  690. #define    A_SYSTEM    0x04
  691. #define    A_LABEL        0x08
  692. #define    A_DIR        0x10
  693. #define    A_ARCHIVE    0x20
  694.  
  695. struct direct {
  696.     ino_t    d_ino;            /* a bit of a farce */
  697.     int    d_reclen;        /* more farce */
  698.     int    d_namlen;        /* length of d_name */
  699.     char    d_name[MAXNAMLEN + 1];        /* garentee null termination */
  700.     char    d_attribute;
  701.     unsigned long    d_size;
  702. };
  703.  
  704. struct _dircontents {
  705.     char    *_d_entry;
  706.     char    d_attribute;
  707.     unsigned long    d_size;
  708.     struct _dircontents    *_d_next;
  709. };
  710.  
  711. typedef struct _dirdesc {
  712.     int        dd_id;    /* uniquely identify each open directory */
  713.     long        dd_loc;    /* where we are in directory entry is this */
  714.     struct _dircontents    *dd_contents;    /* pointer to contents of dir */
  715.     struct _dircontents    *dd_cp;    /* pointer to current position */
  716. } DIR;
  717.  
  718. extern    DIR        *opendir();
  719. extern    struct direct    *readdir();
  720. extern    void        seekdir();
  721. extern    long        telldir();
  722. extern    void        closedir();
  723. @EOF
  724. set `sum $sumopt <msd_dir.h`; if test $1 -ne 26221
  725. then
  726.     echo ERROR: msd_dir.h checksum is $1 should be 26221
  727. fi
  728.  
  729. chmod 666 msd_dir.h
  730.  
  731. echo x - read.me
  732. cat >read.me <<'@EOF'
  733. This program (DU) should be compiled at least using COMPACT memory model.
  734. The recursive nature would readily overflow a SMALL memory model program's
  735. data space. Beside that, the stack should be much bigger than the default
  736. value of 2048 (say 10k or 20k would be fine). However, one might consider
  737. using the xVARSTCK.OBJ supplied by Microsoft (see page 197, chapter 9 --
  738. Advanced Topics, of Microsoft C compiler User's Guide). Then one should use
  739. the /Gs or /Ox option during compilation.
  740.  
  741.  
  742. One probable compilation command would be :
  743.  
  744.   CL /Gs /Ox /AC du.c msd_dir.c cvarstck.obj -o du -link /STACK:20480
  745.  
  746.  
  747. Peter lim
  748. 07-Dec-87
  749. @EOF
  750. set `sum $sumopt <read.me`; if test $1 -ne 41276
  751. then
  752.     echo ERROR: read.me checksum is $1 should be 41276
  753. fi
  754.  
  755. chmod 666 read.me
  756.  
  757. echo x - readme
  758. sed 's/^@//' >readme <<'@EOF'
  759.  
  760. I have waited around long enough for a proper MS DOS DU, so I wrote my
  761. own.
  762.  
  763. This "DU" compiles in MSC 4.0 under MS DOS. As such it has very strong
  764. MS DOS flavour. It is basically a superset of the Unix DU - a lot more
  765. options available - to cater for the quirks of MS DOS. Essentially it
  766. produces the same reading as CHKDSK in MS DOS except in cases where
  767. you have directories which used to hold a lot of files which has been
  768. erased - the erased directory entries will not be accounted for, and
  769. can't be without resorting to very low level FAT fiddling which is not
  770. worth the while. At the moment, it doesn't allow specification of files
  771. - only the whole directory - may be someone would like to change this.
  772. It also displays sizes in bytes and not kilobytes - a feature to suit
  773. MS DOS's various cluster sizes.
  774.  
  775. Msd_dir.* are borrowed from the TAR package put together by Michael
  776. Rendell ({uunet,utai}michael@garfield) with some fairly kludgy modifi-
  777. cations and extensions. See read.me for some extra info (not much :-)).
  778. For now type 'make make.msc' to compile DU.
  779.  
  780. -----------------------------------------------------------------------
  781. This program is placed in the public domain without any warranty. As
  782. far as I know it is not a virius ;-).
  783.  
  784. @From:    Peter Lim,    lim@mullian.oz
  785.  
  786. -----------------------------------------------------------------------
  787. Posted again                            8:55 pm, Monday, April 16, 1990
  788. @....... still public domain without any warranty.
  789. @....... still doesn't allow specification of files (ie. not directory).
  790.  
  791. @From:   Peter Lim,      plim@hpsgwk.HP.COM  pnl@hpfipnl.HP.COM
  792.  
  793. Verified working with MSC 5.1.
  794.  
  795. @EOF
  796. set `sum $sumopt <readme`; if test $1 -ne 6097
  797. then
  798.     echo ERROR: readme checksum is $1 should be 6097
  799. fi
  800.  
  801. chmod 666 readme
  802.  
  803. echo x - showbug.c
  804. cat >showbug.c <<'@EOF'
  805. /*
  806.  *    To show the bug associated with stat(), it works okay if the drive
  807.  *    letter entered is for the current drive.
  808.  */
  809.  
  810. #include    <stdio.h>
  811. #include    <dos.h>
  812. #include    <sys/types.h>
  813. #include    <sys/stat.h>
  814. #include    <strings.h>
  815. #include    <ctype.h>
  816. struct    stat        statb;
  817.  
  818. static    char    *extgetcwd();
  819. #define DOSI_GCDIR    0x47
  820. static    union REGS    reg, nreg;
  821. #if    defined(M_I86LM)
  822. static    struct SREGS    sreg;
  823. #endif
  824. #define    MAXPATHLEN    128
  825.  
  826. main()
  827. {
  828.     char    *s = ":\\tmp";
  829.     char    ss[MAXPATHLEN+1], dd[MAXPATHLEN+1];
  830.     char    c;
  831.  
  832.     printf ("Enter drive letter with directory \\tmp : ");
  833.     c = getchar();
  834.     if (isupper(c))
  835.         c += 'a' - 'A';
  836.     ss[0] = c;
  837.     ss[1] = NULL;
  838.     strcat (ss, s);
  839.     chdir(ss);
  840.     extgetcwd (c+1, ss, MAXPATHLEN);
  841.     printf ("Current directory before stat() = %s\n", ss);
  842.     dd[0] = c;
  843.     dd[1] = NULL;
  844.     strcat (dd, ":\\");
  845.     stat(dd, &statb);
  846.     extgetcwd (c+1, dd, MAXPATHLEN);
  847.     printf ("Current directory after stat() = %s\n", dd);
  848. }
  849.  
  850.  
  851. static    char    *extgetcwd(drive_id, buffer, buffer_size)
  852. /* Extended get current directory on specified drive.  Peter Lim 07-Dec-87. */
  853. unsigned char drive_id;
  854. char *buffer;
  855. int  buffer_size;
  856. {
  857.     char    tmpbuffer[MAXPATHLEN+1];
  858.  
  859.     if (!drive_id)
  860.         return (getcwd (buffer, buffer_size));
  861.     /* If it is current drive, use the standard getcwd() */
  862.  
  863.     reg.h.ah = DOSI_GCDIR;
  864.     reg.h.dl = drive_id;
  865. #if    defined(M_I86LM)
  866.     reg.x.si = FP_OFF(tmpbuffer);
  867.     sreg.ds = FP_SEG(tmpbuffer);
  868.     intdosx(®, &nreg, &sreg);
  869. #else
  870.     reg.x.si = (int) tmpbuffer;
  871.     intdos(®, &nreg);
  872. #endif
  873.     if (nreg.x.ax == 0xf)
  874.         return ((char *) NULL);
  875.         /* Invalid drive specification. */
  876.     else {
  877.         if (drive_id)
  878.             sprintf (buffer, "%c:\\%s", drive_id+'A'-1, tmpbuffer);
  879.         else
  880.             sprintf (buffer, "\\%s", tmpbuffer);
  881.         return (buffer);
  882.     }
  883. }
  884.  
  885. @EOF
  886. set `sum $sumopt <showbug.c`; if test $1 -ne 52333
  887. then
  888.     echo ERROR: showbug.c checksum is $1 should be 52333
  889. fi
  890.  
  891. chmod 666 showbug.c
  892.  
  893. exit 0
  894.