home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / PAX20.ZIP / MSDOS.C < prev    next >
C/C++ Source or Header  |  1990-11-12  |  16KB  |  721 lines

  1. /* $Source: /u/mark/src/pax/RCS/msdos.c,v $
  2.  *
  3.  * $Revision: 1.3 $
  4.  *
  5.  * msdos.c - functions to make things works under MS-DOS
  6.  *
  7.  * DESCRIPTION
  8.  *
  9.  *    These routines provide the necessary functions to make pax work
  10.  *    under MS-DOS.
  11.  *
  12.  *    NOTE: Before these routines can be used to read/write directly to
  13.  *    the disk, bypassing the logical file structure, MSDOS MUST know
  14.  *    what kind of disk is in the drive you intend to write to.  This can
  15.  *    be accomplished by putting a formatted disk in the drive of
  16.  *    interest and doing a DIR on it.  MSDOS then remembers the disk type
  17.  *    for a while.
  18.  *
  19.  *    WARNING: DISABLING THE BUILT IN CHECK AND CALLING THESE ROUTINES
  20.  *    WITH THE DRIVE SET TO CORRESPOND TO YOUR HARD DISK WILL PROBABLY
  21.  *    TRASH IT COMPLETELY!
  22.  *
  23.  * AUTHOR
  24.  *
  25.  *    Mark H. Colburn, Open Systems Architects, Inc. (mark@minnetech.mn.org)
  26.  *    Harold Walters, Oklahoma State University (walters@1.ce.okstate.edu)
  27.  *
  28.  * COPYRIGHT
  29.  *
  30.  *    Copyright (c) 1989 Mark H. Colburn.  All rights reserved.
  31.  *
  32.  *    Redistribution and use in source and binary forms are permitted
  33.  *    provided that the above copyright notice and this paragraph are
  34.  *    duplicated in all such forms and that any documentation,
  35.  *    advertising materials, and other materials related to such
  36.  *    distribution and use acknowledge that the software was developed
  37.  *    by Mark H. Colburn.
  38.  *
  39.  *    THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  40.  *    IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  41.  *    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  42.  *
  43.  * $Log:    msdos.c,v $
  44.  * Revision 1.3  89/10/30  07:50:09  mark
  45.  * Added dio_to_binary to support real character devices (from Harold Walters)
  46.  *
  47.  * Revision 1.2  89/10/13  02:35:19  mark
  48.  * Beta Test Freeze
  49.  *
  50.  */
  51.  
  52. #ifndef lint
  53. static char *ident = "$Id: msdos.c,v 1.3 89/10/30 07:50:09 mark Exp Locker: mark $";
  54. static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.";
  55. #endif /* not lint */
  56.  
  57. /* Headers */
  58.  
  59. #include "pax.h"
  60.  
  61. #ifdef MSDOS
  62. #include <sys/types.h>
  63. #include <stdio.h>
  64. #include <stdlib.h>
  65. #include <ctype.h>
  66. #include <errno.h>
  67. #include <dos.h>
  68.  
  69.  
  70. #ifdef DIO
  71.  
  72. /* Function Prototypes */
  73.  
  74. #ifdef __STDC__
  75.  
  76. static int        dio_adw(unsigned int drive, char *buf,
  77.                 unsigned int secnum, unsigned int secknt,
  78.                 unsigned int *err);
  79. static int         dio_adr(unsigned int drive, char *buf,
  80.                 unsigned int secnum, unsigned int secknt,
  81.                 unsigned int *err);
  82. static int         dio_drive_check(int d);
  83. static int        dio_err_hand(unsigned int drive, int rw, unsigned int err);
  84. static int         dio_read1(int drive, char *buf, unsigned int sec);
  85. static int         dio_write1(int drive, char *buf, unsigned int sec);
  86.  
  87. #else /* !STDC */
  88.  
  89. static int          dio_adw();
  90. static int          dio_adr();
  91. static int          dio_drive_check();
  92. static int          dio_err_hand();
  93. static int          dio_read1();
  94. static int          dio_write1();
  95.  
  96. #endif /* STDC */
  97.  
  98.  
  99. /* Defines */
  100.  
  101. #define SECSIZ 512
  102.  
  103.  
  104. /* Local Variables */
  105.  
  106. static unsigned long fptr = 0L;
  107. static char         secbuf[SECSIZ];
  108. static int          rwsec = 0;
  109.  
  110. static union REGS   reg;
  111. static union REGS   rreg;
  112.  
  113. #if defined(M_I86LM) || defined(M_I86CM)
  114. static struct SREGS sreg;
  115. #endif /* !M_I86LM */
  116.  
  117.  
  118. void
  119. dio_str(s)
  120.     char       *s;
  121. {
  122.     DBUG_ENTER("dio_str");
  123.     for ( ; *s; s++) {
  124.     if (*s == '\\') {
  125.         *s = '/';
  126.     } else if (isupper(*s)) {
  127.         *s = tolower(*s);
  128.     }
  129.     }
  130.     DBUG_VOID_RETURN;
  131. }
  132.  
  133.  
  134. static int
  135. dio_adw(drive, buf, secnum, secknt, err)
  136.     unsigned int        drive;
  137.     unsigned int        secnum;
  138.     unsigned int    secknt;
  139.     unsigned int       *err;
  140.     char               *buf;
  141. {
  142.     DBUG_ENTER("dio_adw");
  143.     rwsec = secnum;
  144.     reg.x.ax = drive;
  145.     reg.x.dx = secnum;
  146.     reg.x.cx = secknt;
  147. #if defined(M_I86LM) || defined(M_I86CM)
  148.     reg.x.bx = FP_OFF(buf);
  149.     sreg.ds = FP_SEG(buf);
  150.     int86x(0x26, ®, &rreg, &sreg);
  151. #else /* !M_I86LM */
  152.     reg.x.dx = (int) buf;
  153.     int86(0x26, ®, &rreg);
  154. #endif /* !M_I86LM */
  155.     *err = rreg.x.ax;
  156.     if (rreg.x.cflag) {
  157.     DBUG_RETURN (-1);
  158.     } else {
  159.     DBUG_RETURN (0);
  160.     }
  161. }
  162.  
  163.  
  164. static int
  165. dio_adr(drive, buf, secnum, secknt, err)
  166.     unsigned int        drive;
  167.     unsigned int        secnum;
  168.     unsigned int        secknt;
  169.     unsigned int       *err;
  170.     char               *buf;
  171. {
  172.     DBUG_ENTER("dio_adr");
  173.     rwsec = secnum;
  174.     reg.x.ax = drive;
  175.     reg.x.dx = secnum;
  176.     reg.x.cx = secknt;
  177. #if defined(M_I86LM) || defined(M_I86CM)
  178.     reg.x.bx = FP_OFF(buf);
  179.     sreg.ds = FP_SEG(buf);
  180.     int86x(0x25, ®, &rreg, &sreg);
  181. #else /* !M_I86LM */
  182.     reg.x.dx = (int) buf;
  183.     int86(0x25, ®, &rreg);
  184. #endif /* !M_I86LM */
  185.     *err = rreg.x.ax;
  186.     if (rreg.x.cflag) {
  187.     DBUG_RETURN (-1);
  188.     } else {
  189.     DBUG_RETURN (0);
  190.     }
  191.  
  192. }
  193.  
  194.  
  195. static char        *doserr[] = {
  196.     "write-protect error",
  197.     "unknown unit",
  198.     "drive not ready",
  199.     "unknown command",
  200.     "data error (bad CRC)",
  201.     "bad request structure length",
  202.     "seek error",
  203.     "unknown media type",
  204.     "sector not found",
  205.     "printer out of paper",
  206.     "write fault",
  207.     "read fault",
  208.     "general failure",
  209.     " ",
  210.     " ",
  211.     "invalid disk change (DOS 3.x)",
  212.     ""
  213. };
  214.  
  215. static char        *bioserr[] = {
  216.     "general error",
  217.     "",
  218.     "bad address mark",
  219.     "write-protect error",
  220.     "sector not found",
  221.     "", "", "",
  222.     "DMA failure",
  223.     "", "", "", "", "",
  224.     "", "",
  225.     "data error (bad CRC)",
  226.     "", "", "", "", "", "", "", "", "", "",
  227.     "", "", "", "", "",
  228.     "controller failed",
  229.     "", "", "", "", "", "", "", "", "", "",
  230.     "", "", "", "", "", "", "", "", "", "",
  231.     "", "", "", "", "", "", "", "", "", "",
  232.     "",
  233.     "seek error",
  234.     "", "", "", "", "", "", "", "", "", "",
  235.     "", "", "", "", "", "", "", "", "", "",
  236.     "", "", "", "", "", "", "", "", "", "",
  237.     "", "", "", "", "", "", "", "", "", "",
  238.     "", "", "", "", "", "", "", "", "", "",
  239.     "", "", "", "", "", "", "", "", "", "",
  240.     "", "", "",
  241.     "disk time out",
  242.     ""
  243. };
  244.  
  245.  
  246. static int
  247. dio_drive_check(d)
  248.     int                 d;
  249. {
  250.     DBUG_ENTER("dio_drive_check");
  251.     d = -(d + 1);
  252.     switch (d) {
  253.  
  254.     case 0:            /* a */
  255.     case 1:            /* b */
  256.     break;
  257.  
  258.     default:
  259.     fprintf(stderr, "dio: dio to drive %1c: not supported\n",
  260.         'a' + d);
  261.     exit(1);
  262.     }
  263.     DBUG_RETURN (d);
  264. }
  265.  
  266.  
  267. static int
  268. dio_err_hand(drive, rw, err)
  269.     unsigned int        drive;
  270.     int                 rw;
  271.     unsigned int        err;
  272. {
  273.     unsigned int        high,
  274.                         low;
  275.  
  276.     DBUG_ENTER("dio_err_hand");
  277.     low = err & 0x000f;
  278.     high = (err >> 8) & 0x00ff;
  279.     if (!(high == 0x04 && low == 0x08)) {
  280.     fprintf(stderr,
  281.         "dio: sector %d: %s error 0x%x\ndio: dos: %s: bios: %s\n",
  282.         (rw == (int) 'r') ? rwsec : rwsec,
  283.         (rw == (int) 'r') ? "read" : "write", err,
  284.         doserr[low], bioserr[high]);
  285.     }
  286.     if (high == 0x04 && low == 0x08) {    /* sector not found */
  287.     if (rw == (int) 'r') {
  288.         rwsec = 0;
  289.         DBUG_RETURN (0);
  290.     } else {
  291.         errno = ENOSPC;
  292.         rwsec = 0;
  293.         DBUG_RETURN (-1);
  294.     }
  295.     }
  296.     exit(1);
  297. }
  298.  
  299.  
  300. static int
  301. dio_read1(drive, buf, sec)
  302.     int                 drive;
  303.     char               *buf;
  304.     unsigned int        sec;
  305. {
  306.     unsigned int        err;
  307.  
  308.     if (dio_adr(drive, buf, sec, 1, &err) == -1) {
  309.     if (dio_adr(drive, buf, sec, 1, &err) == -1) {
  310.         if (dio_adr(drive, buf, sec, 1, &err) == -1) {
  311.         if (dio_err_hand(drive, (int) 'r', err) == 0) {
  312.             DBUG_RETURN (0);
  313.         }
  314.         }
  315.     }
  316.     }
  317.     DBUG_RETURN (SECSIZ);
  318. }
  319.  
  320. static int
  321. dio_write1(drive, buf, sec)
  322.     int                 drive;
  323.     char               *buf;
  324.     unsigned int        sec;
  325. {
  326.     unsigned int        err;
  327.  
  328.     DBUG_ENTER("dio_write1");
  329.     if (dio_adw(drive, buf, sec, 1, &err) == -1) {
  330.     if (dio_adw(drive, buf, sec, 1, &err) == -1) {
  331.         if (dio_adw(drive, buf, sec, 1, &err) == -1) {
  332.         if (dio_err_hand(drive, (int) 'w', err) == -1) {
  333.             DBUG_RETURN (-1);
  334.         }
  335.         }
  336.     }
  337.     }
  338.     DBUG_RETURN (SECSIZ);
  339. }
  340.  
  341.  
  342. int
  343. dio_write(drive, from_buf, from_cnt)
  344.     int                 drive;    /* a -> -1, b -> -2, etc */
  345.     char               *from_buf;    /* buffer containing bytes to be
  346.                      * written */
  347.     unsigned int        from_cnt;    /* number of bytes to write */
  348. {
  349.     unsigned int        amt;
  350.     unsigned int        err;
  351.     unsigned int        nn;
  352.     unsigned int        fquo;
  353.     unsigned int        frem;
  354.     unsigned int        cquo;
  355.     unsigned int        crem;
  356.  
  357.     DBUG_ENTER("dio_write");
  358.     drive = dio_drive_check(drive);
  359.     amt = 0;
  360.     err = 0;
  361.     cquo = 0;
  362.     crem = 0;
  363.     DBUG_PRINT("msdos", ("W drive %d from_cnt %d fptr %ld\n",
  364.              drive, from_cnt, fptr));
  365.     fquo = (unsigned int) (fptr / SECSIZ);
  366.     frem = (unsigned int) (fptr % SECSIZ);
  367.     if (frem > 0) {
  368.     if (dio_read1(drive, secbuf, fquo) == 0) {
  369.         DBUG_RETURN (-1);
  370.     }
  371.     if ((nn = SECSIZ - frem) > from_cnt) {
  372.         nn = from_cnt;
  373.     }
  374.     memcpy(&secbuf[frem], from_buf, nn);
  375.     if (dio_write1(drive, secbuf, fquo) == -1) {
  376.         DBUG_RETURN (-1);
  377.     }
  378.     amt += nn;
  379.     fptr += nn;
  380.     if (SECSIZ - frem <= from_cnt) {
  381.         fquo++;
  382.     }
  383.     from_buf += nn;
  384.     from_cnt -= nn;
  385.     DBUG_PRINT("msdos", ("W fr fptr %ld fquo %d frem %d cquo %d crem %d amt %d from_cnt %d\n",
  386.                  fptr, fquo, frem, cquo, crem, amt, from_cnt));
  387.     }
  388.     cquo = from_cnt / SECSIZ;
  389.     crem = from_cnt % SECSIZ;
  390.     if (cquo > 0) {
  391.     if (dio_adw(drive, from_buf, fquo, cquo, &err) == -1) {
  392.         if (dio_adw(drive, from_buf, fquo, cquo, &err) == -1) {
  393.         if (dio_adw(drive, from_buf, fquo, cquo, &err) == -1) {
  394.             if (dio_err_hand(drive, (int) 'w', err) == -1) {
  395.             DBUG_RETURN (-1);
  396.             }
  397.         }
  398.         }
  399.     }
  400.     nn = cquo * SECSIZ;
  401.     amt += nn;
  402.     fptr += nn;
  403.     fquo += cquo;
  404.     from_buf += nn;
  405.     from_cnt -= nn;
  406.     DBUG_PRINT("msdos", ("W cq fptr %ld fquo %d frem %d cquo %d crem %d amt %d from_cnt %d\n",
  407.                  fptr, fquo, frem, cquo, crem, amt, from_cnt));
  408.     }
  409.     if (crem > 0) {
  410.     if (dio_read1(drive, secbuf, fquo) == 0) {
  411.         DBUG_RETURN (-1);
  412.     }
  413.     nn = crem;
  414.     memcpy(&secbuf[0], from_buf, nn);
  415.     if (dio_write1(drive, secbuf, fquo) == -1) {
  416.         DBUG_RETURN (-1);
  417.     }
  418.     amt += nn;
  419.     fptr += nn;
  420.     from_buf += nn;
  421.     from_cnt -= nn;
  422.     DBUG_PRINT("msdos", ("W cr fptr %ld fquo %d frem %d cquo %d crem %d amt %d from_cnt %d\n",
  423.                  fptr, fquo, frem, cquo, crem, amt, from_cnt));
  424.     }
  425.     DBUG_RETURN (amt);
  426. }
  427.  
  428.  
  429. /* read data directly from the disk using INT 25 */
  430.  
  431. int
  432. dio_read(drive, to_buf, to_cnt)
  433.     int                 drive;    /* a -> -1, b -> -2, etc */
  434.     char               *to_buf;    /* buffer containing bytes to be written */
  435.     unsigned int        to_cnt;    /* number of bytes to write */
  436. {
  437.     unsigned int        amt;
  438.     unsigned int        err;
  439.     unsigned int        nn;
  440.     unsigned int        fquo;
  441.     unsigned int        frem;
  442.     unsigned int        cquo;
  443.     unsigned int        crem;
  444.  
  445.     DBUG_ENTER("dio_read");
  446.     drive = dio_drive_check(drive);
  447.     amt = 0;
  448.     err = 0;
  449.     cquo = 0;
  450.     crem = 0;
  451.     DBUG_PRINT("msdos", ("R drive %d to_cnt %d fptr %ld\n", drive, to_cnt,
  452.              fptr));
  453.     fquo = (unsigned int) (fptr / SECSIZ);
  454.     frem = (unsigned int) (fptr % SECSIZ);
  455.     if (frem > 0) {
  456.     if (dio_read1(drive, secbuf, fquo) == 0) {
  457.         DBUG_RETURN (0);
  458.     }
  459.     if ((nn = SECSIZ - frem) > to_cnt) {
  460.         nn = to_cnt;
  461.     }
  462.     memcpy(to_buf, &secbuf[frem], nn);
  463.     amt += nn;
  464.     fptr += nn;
  465.     if (SECSIZ - frem <= to_cnt) {
  466.         fquo++;
  467.     }
  468.     to_buf += nn;
  469.  
  470.     to_cnt -= nn;
  471.     DBUG_PRINT("msdos", ("R fr fptr %ld fquo %d frem %d cquo %d crem %d amt %d to_cnt %d\n",
  472.                  fptr, fquo, frem, cquo, crem, amt, to_cnt));
  473.     }
  474.     cquo = to_cnt / SECSIZ;
  475.     crem = to_cnt % SECSIZ;
  476.     if (cquo > 0) {
  477.     if (dio_adr(drive, to_buf, fquo, cquo, &err) == -1) {
  478.         if (dio_adr(drive, to_buf, fquo, cquo, &err) == -1) {
  479.         if (dio_adr(drive, to_buf, fquo, cquo, &err) == -1) {
  480.             if (dio_err_hand(drive, (int) 'r', err) == 0) {
  481.             DBUG_RETURN (0);
  482.             }
  483.         }
  484.         }
  485.     }
  486.     nn = cquo * SECSIZ;
  487.     amt += nn;
  488.     fptr += nn;
  489.     fquo += cquo;
  490.     to_buf += nn;
  491.     to_cnt -= nn;
  492.     DBUG_PRINT("msdos", ("R cq fptr %ld fquo %d frem %d cquo %d crem %d amt %d to_cnt %d\n",
  493.             fptr, fquo, frem, cquo, crem, amt, to_cnt));
  494.     }
  495.     if (crem > 0) {
  496.     if (dio_read1(drive, secbuf, fquo) == 0) {
  497.         DBUG_RETURN (0);
  498.     }
  499.     nn = crem;
  500.     memcpy(to_buf, &secbuf[0], nn);
  501.     amt += nn;
  502.     fptr += nn;
  503.     to_buf += nn;
  504.     to_cnt -= nn;
  505.     DBUG_PRINT("msdos", ("R cr fptr %ld fquo %d frem %d cquo %d crem %d amt %d to_cnt %d\n",
  506.             fptr, fquo, frem, cquo, crem, amt, to_cnt));
  507.     }
  508.     DBUG_RETURN (amt);
  509. }
  510.  
  511. /* changes true character devices to binary mode
  512.  * ignores dio and dos files but will change all of
  513.  * stdin, stdout, stderr to binary mode if called with
  514.  * h = to 0, 1, or 2
  515.  * inspired by John B. Thiel (jbthiel@ogc.cse.edu)
  516.  */
  517.  
  518. int
  519. dio_to_binary(h)
  520.    int h;
  521. {
  522.    union REGS           regs;
  523.    DBUG_ENTER("dio_to_binary");
  524.    if (h < 0) {
  525.        DBUG_RETURN(0);
  526.    }
  527.    regs.h.ah = 0x44;
  528.    regs.h.al = 0x00;
  529.    regs.x.bx = h;
  530.    intdos(®s, ®s);
  531.    if (regs.x.cflag || regs.x.ax == 0xff) {
  532.        DBUG_RETURN(-1);
  533.    }
  534.    if (regs.h.dl & 0x80) {
  535.        regs.h.ah = 0x44;
  536.        regs.h.al = 0x01;
  537.        regs.x.bx = h;
  538.        regs.h.dh = 0;
  539.        regs.h.dl |= 0x20;
  540.        intdos(®s, ®s);
  541.    }
  542.    if (regs.x.cflag || regs.x.ax == 0xff) {
  543.           DBUG_RETURN(-1);
  544.    } else {
  545.           DBUG_RETURN(0);
  546.    }
  547. }
  548.  
  549. int
  550. dio_open_check(s)
  551.     char               *s;
  552. {
  553.     DBUG_ENTER("dio_open_check");
  554.     if (!stricmp(s, "a:dio") || !stricmp(s, "b:dio")) {
  555.     DBUG_RETURN (-(*s - 'a' + 1));
  556.     } else {
  557.     DBUG_RETURN (0);
  558.     }
  559. }
  560.  
  561.  
  562. int
  563. dio_open2(p, f)
  564.     char               *p;
  565.     int                 f;
  566. {
  567.     int                 h;
  568.  
  569.     DBUG_ENTER("dio_open2");
  570.     h = dio_open_check(p);
  571.     if (h < 0) {
  572.     fptr = 0L;
  573.     }
  574.     DBUG_RETURN (h);
  575. }
  576.  
  577.  
  578. int
  579. dio_open3(p, f, m)
  580.     char               *p;
  581.     int                 f,
  582.                         m;
  583. {
  584.     int                 h;
  585.  
  586.     DBUG_ENTER("dio_open3");
  587.     h = dio_open_check(p);
  588.     if (h < 0) {
  589.     fptr = 0L;
  590.     }
  591.     DBUG_RETURN (h);
  592. }
  593.  
  594.  
  595. int
  596. dio_close(h)
  597.     int                 h;
  598. {
  599.     return(0);
  600. }
  601.  
  602.  
  603. long
  604. dio_lseek(h, o, r)
  605.     int                 h;
  606.     long                o;
  607.     int                 r;
  608. {
  609.     long                check;
  610.  
  611.     DBUG_ENTER("dio_lseek");
  612.     if (h >= 0) {
  613.     errno = EBADF;
  614.     DBUG_RETURN (-1L);
  615.     }
  616.     check = fptr;
  617.     switch (r) {
  618.  
  619.     case 0:
  620.     check = o;
  621.     break;
  622.  
  623.     case 1:
  624.     check += o;
  625.     break;
  626.  
  627.     case 2:
  628.     default:
  629.     errno = EINVAL;
  630.     fprintf(stderr, "dio: origin %d not supported\n", r);
  631.     DBUG_RETURN (-1L);
  632.     }
  633.  
  634.     if (check < 0L) {
  635.     errno = EINVAL;
  636.     DBUG_RETURN (-1L);
  637.     }
  638.     fptr = check;
  639.     DBUG_RETURN (fptr);
  640. }
  641.  
  642. #endif
  643.  
  644. static struct passwd npwd = {"", "", 0, 0, 0, "", "", "", ""};
  645. static char gmem1[] = "";
  646. static char *gmem2[] = {gmem1, (char *) NULL};
  647. static struct group ngrp = {"", "", 0, gmem2};
  648.  
  649. struct passwd *
  650. getpwuid(x)
  651.     int            x;
  652. {
  653.     return(&npwd);
  654. }
  655.  
  656.  
  657. struct passwd *
  658. getpwnam(s)
  659.     char           *s;
  660. {
  661.     return(&npwd);
  662. }
  663.  
  664.  
  665. struct group *
  666. getgrgid(x)
  667.     int            x;
  668. {
  669.     return(&ngrp);
  670. }
  671.  
  672.  
  673. struct group *
  674. getgrnam(s)
  675.     char           *s;
  676. {
  677.     return(&ngrp);
  678. }
  679.  
  680.  
  681. int
  682. setgrent()
  683. {
  684.     return(0);
  685. }
  686.  
  687.  
  688. int
  689. getuid()
  690. {
  691.     return(0);
  692. }
  693.  
  694.  
  695. int
  696. getgid()
  697. {
  698.     return(0);
  699. }
  700.  
  701.  
  702. int
  703. link(from, to)
  704.     char           *from;
  705.     char           *to;
  706. {
  707.     return(-1);
  708. }
  709.  
  710.  
  711. int
  712. chown(name, uid, gid)
  713.     char                  *name;
  714.     int            uid;
  715.     int            gid;
  716. {
  717.     return(0);
  718. }
  719.  
  720. #endif /* MSDOS */
  721.