home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume1 / 8712 / du-dos < prev    next >
Text File  |  1990-07-13  |  21KB  |  804 lines

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