home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / lan / soss.arj / SRC / FILES.C < prev    next >
C/C++ Source or Header  |  1991-04-11  |  31KB  |  1,120 lines

  1. /*
  2.  *  files.c --
  3.  *      File manipulation procedures.  This module is highly machine
  4.  *      dependent.
  5.  *
  6.  *  Author:
  7.  *      See-Mong Tan
  8.  *  Modified by:
  9.  *    Rich Braun @ Kronos
  10.  *
  11.  *  Revision history:
  12.  *  
  13.  * $Log: files.c_v $
  14.  * Revision 1.4  1991/04/11  20:36:51  richb
  15.  * Add name truncation support.
  16.  *
  17.  * Revision 1.3  1991/03/15  22:39:19  richb
  18.  * Several mods:  fixed unlink and rename.
  19.  *
  20.  */
  21.  
  22. #ifdef RCSID
  23. static char _rcsid_ = "$Id: files.c_v 1.4 1991/04/11 20:36:51 richb Exp $";
  24. #endif
  25.  
  26. #include "common.h"
  27. #include "msc-dos.h"        /* for dos drive and file routines */
  28. #include <direct.h>        /* for dos directory ops */
  29. #include <fcntl.h>        /* these ... */
  30. #include <sys/stat.h>        /* for ... */
  31. #include <io.h>            /* low level DOS access */
  32.  
  33. /* Default permissions for files are 555 for read-only and 777  */
  34. /* for writeable.  The low-order 9 bits can be modified by the  */
  35. /* administrator.                        */
  36. u_short uperm_rdonly = UPERM_FILE | UPERM_READ | UPERM_EXEC;
  37. u_short uperm_write  = UPERM_FILE | UPERM_READ | UPERM_WRITE | UPERM_EXEC;
  38. u_short uperm_dir    = UPERM_DIR | UPERM_READ | UPERM_WRITE | UPERM_SEARCH;
  39.  
  40. #ifdef NOVELL
  41. #include "novell.h"        /* Novell definitions */
  42. static struct _uidmap {
  43.     u_long    unix_ID;
  44.     u_long    Novell_ID;
  45.     } *uIDmappings = NULL;
  46. static int uIDcount;
  47. static u_long uIDoffset;
  48. static u_long gID;
  49. static u_short novelldirprot;
  50.  
  51. static bool_t ldnovell (u_long, char *, struct nfsfattr *);
  52. #endif /* NOVELL */
  53.  
  54. #ifdef DOSAUTH
  55. /* Support for handling file authentication */
  56. struct _authent {
  57.     u_short    uid;        /* UID of file owner */
  58.     u_short gid;        /* GID of file owner */
  59.     u_short mode;        /* Protection mode bits */
  60.     u_short reserved;
  61.     };
  62. #define AUTHSIZE (sizeof (struct _authent))
  63. #define AUTHFILE "AUTHS.DMP"
  64. static int authfh = 0;
  65. #endif /* DOSAUTH */
  66.  
  67. static int file_nsubdirs(char *);
  68. static bool_t file_readattr(char *, struct nfsfattr *);
  69. static void   cvtd2uattr (u_long, struct find_t *, struct nfsfattr *);
  70.  
  71. #define DRIVE_SCALINGFACTOR 2    /* scaling factor for dos drive blocks */
  72.  
  73. /*
  74.  *  bool_t file_getattr(char *path, struct nfsfattr *attr) --
  75.  *      Gets attributes for designated file or directory and puts
  76.  *      the information in *attr.  Returns TRUE if successful, FALSE otherwise.
  77.  */
  78. bool_t file_getattr(path, attr)
  79.     char *path;
  80.     struct nfsfattr *attr;
  81. {
  82.     if (path == NULL)
  83.       return FALSE;
  84.  
  85.     /* See if info is cached in the inode tree */
  86.  
  87.     if (inattrget (pntoin (path), attr) != NULL)
  88.     return TRUE;
  89.  
  90.     /* Else go out to disk */
  91.     return  file_readattr(path, attr);
  92. }
  93.  
  94. /*
  95.  *  bool_t file_readattr(char *path, struct nfsfattr *attr) --
  96.  *      Reads file attributes for a file from disk.
  97.  *      Returns TRUE if successful, FALSE otherwise.
  98.  *    Adds file to directory tree if the file does not already exist in
  99.  *    the tree.
  100.  */
  101. static bool_t file_readattr(path, attr)
  102.     char *path;
  103.     struct nfsfattr *attr;
  104. {
  105.     struct find_t findbuf;
  106.     u_long nodeid;
  107.     char   npath [10];
  108.  
  109.     /* Special-case the root directory */
  110.     if (strlen (path) == 2 && path[1] == ':') {
  111.  
  112.     (void) bzero(attr, sizeof(struct nfsfattr));
  113.     attr->na_blocksize = NFS_MAXDATA;
  114.  
  115.     /* Get attributes of volume label */
  116.     sprintf (npath, "%s\\*.*", path);
  117.     if (_dos_findfirst(npath, _A_VOLID, &findbuf) != 0) {
  118.  
  119.         /* Load attributes from findbuf */
  120.         cvtd2uattr (nodeid, &findbuf, attr);
  121.     }
  122.     /* Set directory attributes */
  123.     attr->na_type = NFDIR;
  124.     attr->na_mode = uperm_dir;
  125.     attr->na_nlink = 2;
  126.     attr->na_blocks = 1;         /* just say 1 block */
  127.     attr->na_size = 1024;
  128.  
  129.     /* cache this info */
  130.     inattrset (nodeid, attr);
  131.     return TRUE;
  132.     }
  133.  
  134.     /* Look for the file given */
  135.     else if (_dos_findfirst(path, _A_NORMAL | _A_SUBDIR | _A_RDONLY,
  136.                &findbuf) != 0) {
  137.     /* not successful */
  138.     if ((nodeid = pntoin(path)) != -1)
  139.       inremnode (nodeid);
  140.     return FALSE;
  141.     }
  142.     else {
  143.     if ((nodeid = pntoin(path)) == -1)
  144.       nodeid = addpathtodirtree(path);
  145.  
  146.     /* Load attributes from findbuf */
  147.     (void) bzero(attr, sizeof(struct nfsfattr));
  148.     cvtd2uattr (nodeid, &findbuf, attr);
  149.  
  150.         if (findbuf.attrib & _A_SUBDIR)
  151.       attr->na_mode = uperm_dir;
  152.         else if (findbuf.attrib & _A_RDONLY)
  153.       attr->na_mode = uperm_rdonly;
  154.     else
  155.       attr->na_mode = uperm_write;
  156.  
  157. #ifdef NOVELL
  158.     /* Novell stuff */
  159.     (void) ldnovell (nodeid, path+2, attr);
  160. #endif
  161. #ifdef DOSAUTH
  162.     /* Read authentication entry */
  163.     if (authfh != 0 && lseek (authfh, nodeid * AUTHSIZE, SEEK_SET) ==
  164.       nodeid * AUTHSIZE) {
  165.         struct _authent authentry;
  166.         if (read (authfh, &authentry, AUTHSIZE) == AUTHSIZE) {
  167.         attr->na_uid = authentry.uid;
  168.         attr->na_gid = authentry.gid;
  169.         attr->na_mode = authentry.mode;
  170.         }
  171.     }
  172. #endif /* DOSAUTH */
  173.     /* cache this info */
  174.     inattrset (nodeid, attr);
  175.     return TRUE;
  176.     }
  177. }
  178.  
  179. static void cvtd2uattr (nodeid, findbuf, attr)
  180.      u_long nodeid;
  181.      struct find_t *findbuf;
  182.      struct nfsfattr *attr;
  183. {
  184.     int handle;            /* DOS file handle */
  185.  
  186.     /* file protection bits and type */
  187.     if (findbuf->attrib & _A_SUBDIR) {           /* subdirectory */
  188.     attr->na_type = NFDIR;
  189.     attr->na_nlink = 2;  /*** + file_nsubdirs(path) ***/
  190.     /* # of subdirectories plus this one */
  191.     }
  192.     else if (findbuf->attrib & _A_RDONLY) {        /* rdonly */
  193.     attr->na_type = NFREG;
  194.     attr->na_nlink = 1;
  195.     }
  196.     else {
  197.     attr->na_type = NFREG;          /* normal file */
  198.     attr->na_nlink = 1;
  199.     }
  200.  
  201.     /* file size in bytes */
  202.     if (findbuf->attrib & _A_SUBDIR) {        /* directory */
  203.     attr->na_blocks = 1;         /* just say 1 block */
  204.     attr->na_size = 1024;
  205.     }
  206.     else {
  207.     attr->na_size = findbuf->size;
  208.     attr->na_blocks = findbuf->size / BASIC_BLOCKSIZE + 
  209.       (findbuf->size % BASIC_BLOCKSIZE == 0 ? 0 : 1);
  210.     }
  211.     /* preferred transfer size in blocks */
  212.     attr->na_blocksize = NFS_MAXDATA;
  213.  
  214.     /* device # == drive # */
  215.     attr->na_fsid = ingetfsid (nodeid);
  216.     attr->na_rdev = attr->na_fsid;
  217.  
  218.     /* inode # */
  219.     attr->na_nodeid = nodeid;
  220.  
  221.     /* time of last access */
  222.     attr->na_atime.tv_usec = 0;
  223.     attr->na_atime.tv_sec = unixtime(findbuf->wr_time, findbuf->wr_date);
  224.  
  225.     /* time of last write */
  226.     attr->na_mtime = attr->na_atime;       /* note all times are the same */
  227.  
  228.     /* time of last change */
  229.     attr->na_ctime = attr->na_atime;
  230. }
  231.  
  232. #ifdef NOVELL
  233. /*
  234.  *  u_char novell_GDH (int fsid) --
  235.  *    Get Novell directory handle for a filesystem.
  236.  */
  237. u_char novell_GDH (fsid)
  238. int fsid;
  239. {
  240. union REGS regsin, regsout;
  241.  
  242.     /* Get the file system's directory handle */
  243.     regsin.x.ax = 0xE900;
  244.     regsin.x.dx = fsid - 1;
  245.     intdos (®sin, ®sout);
  246.  
  247.     /* Return -1 error code if the permanent directory bit is not set or */
  248.     /* the local-directory bit is set.                          */
  249.     if ((regsout.h.ah & 0x83) != 1)
  250.       return 255;
  251.  
  252.     return regsout.h.al;
  253. }
  254.  
  255. /*
  256.  *  void ldnovell (u_long nodeid, char *path, struct nfsfattr *attr) --
  257.  *    Loads attributes of a Novell network file
  258.  */
  259. static bool_t ldnovell (nodeid, path, attr)
  260.      u_long nodeid;
  261.      char   *path;
  262.      struct nfsfattr *attr;
  263. {
  264.     FILE *fp, *fopen();
  265.     int i;
  266.     int stat;
  267.     u_char handle;
  268.     char fcn [10];
  269.     union REGS regsin, regsout;
  270.     struct SREGS segregs;
  271.  
  272.     if ((handle = novell_GDH (ingetfsid (nodeid))) == 255)
  273.     return FALSE;
  274.  
  275.     /* Initialize the Novell ID mapping table if not set */
  276.     if (uIDmappings == NULL) {
  277.     uIDmappings = (struct _uidmap *) malloc (sizeof (struct _uidmap) *
  278.                         MAXNOVELLID);
  279.     if (uIDmappings == NULL) {
  280.         fprintf (stderr, "out of memory\n");
  281.         abort();
  282.     }
  283.     uIDoffset = uIDcount = gID = 0;
  284.  
  285.     /* Default protection is 775 */
  286.     novelldirprot = UPERM_OWNER | UPERM_GROUP | UPERM_READ | UPERM_SEARCH;
  287.  
  288.     if ((fp = fopen(IDFILE, "r")) == NULL) {
  289.         fprintf (stderr, ">>> File %s missing\n", IDFILE);
  290.     }
  291.     else {
  292.         while(fscanf(fp, "%s", fcn) != EOF) {
  293.         /* Check command line for 'offset', 'group', 'user', */
  294.         /* 'protection'.                     */
  295.         if (fcn[0] == 'o')
  296.             fscanf(fp, "%ld", &uIDoffset);
  297.         else if (fcn[0] == 'g')
  298.             fscanf(fp, "%ld", &gID);
  299.         else if (fcn[0] == 'p')
  300.             fscanf(fp, "%o", &novelldirprot);
  301.         else if (fcn[0] == 'u') {
  302.             char user[20];
  303.             fscanf(fp, "%s %ld %ld", user,
  304.                &uIDmappings[uIDcount].unix_ID,
  305.                &uIDmappings[uIDcount].Novell_ID);
  306.             if (uIDcount < MAXNOVELLID-1)
  307.               uIDcount++;
  308.         }
  309.         }
  310.         fclose (fp);
  311.     }
  312.     }
  313.  
  314.     segregs.ds = get_ds();
  315.     segregs.es = segregs.ds;
  316.  
  317.     if (attr->na_type != NFDIR) {
  318.     /* Set up the Scan File Information request block, as defined on */
  319.     /* page 283 of the Novell API Reference, rev 1.00.         */
  320.  
  321.     static struct _sfireq sfireq =     /* These are placed in static */
  322.       {0, 0x0F, -1, -1, 0, 0, 0};    /* memory because code here   */
  323.     static struct _sfirep sfirep;    /* assumes seg register DS.   */
  324.  
  325.     sfireq.handle = handle;
  326.     sfireq.pathlen = strlen (path);
  327.     sfireq.len = 6 + sfireq.pathlen;
  328.     sfirep.len = sizeof (sfirep) -2;
  329.     strcpy (sfireq.path, path);
  330.  
  331.     novell_API(0xE3, &sfireq, &sfirep, regsin, ®sout, &segregs);
  332.     if (regsout.h.al != 0) {
  333.         DBGPRT2 (nfsdebug, "%s sfi err %d", path, regsout.h.al);
  334.         return FALSE;
  335.     }
  336.     attr->na_uid = sfirep.info.ownerID;
  337.     attr->na_gid = gID;
  338.     }
  339.     else {
  340.     /* Special case for directories:  invoke Scan Directory For   */
  341.     /* Trustees system call, defined on p. 280 of Novell API Ref. */
  342.  
  343.     /* Load the protection bits */
  344.     attr->na_mode = UPERM_DIR | novelldirprot;
  345. #if 0
  346.     /* SDFT not supported because Novell allows a directory to be */
  347.     /* a member of several groups while Unix only attaches one    */
  348.     /* group ID to the file.  We punt and just return the same    */
  349.     /* group every time, to avoid confusion.              */
  350.  
  351.     static struct _sdftreq sdftreq = {0, 0x0C, 0, 0, 0};
  352.     static struct _sdftrep sdftrep;
  353.  
  354.     sdftreq.handle = handle;
  355.     sdftreq.pathlen = strlen (path);
  356.     sdftreq.len = 4 + sdftreq.pathlen;
  357.     sdftrep.len = sizeof (sdftrep) -2;
  358.     strcpy (sdftreq.path, path);
  359.  
  360.     novell_API (0xE2, &sdftreq, &sdftrep, regsin, ®sout, &segregs);
  361.     if (regsout.h.al == 0) {
  362.         attr->na_uid = sdftrep.ownerID;
  363.     }
  364.     else
  365. #endif /* 0 */
  366.     {
  367.         /* If SDFT call failed, usually due to access problems, */
  368.         /* use the Scan Directory Info call.            */
  369.         static struct _sdireq sdireq = {0, 0x02, 0, 0, 0};
  370.         static struct _sdirep sdirep;
  371.  
  372.         sdireq.handle = handle;
  373.         sdireq.pathlen = strlen (path);
  374.         sdireq.len = 5 + sdireq.pathlen;
  375.         sdirep.len = sizeof (sdirep) -2;
  376.         strcpy (sdireq.path, path);
  377.  
  378.         novell_API (0xE2, &sdireq, &sdirep, regsin, ®sout, &segregs);
  379.         DBGPRT3 (nfsdebug, "SDIREQ %d: %d %ld", sdireq.handle, regsout.h.al,
  380.              sdirep.ownerID);
  381.         if (regsout.h.al != 0)
  382.           return FALSE;
  383.         attr->na_uid = sdirep.ownerID;
  384.         attr->na_gid = gID;
  385.     }
  386.     }
  387.  
  388.     DBGPRT2 (nfslookup, "%s ID = %ld", path, attr->na_uid);
  389.  
  390.     /* Look for ID in mapping table */
  391.     for (i = 0; i < uIDcount; i++)
  392.       if (uIDmappings[i].Novell_ID == attr->na_uid) {
  393.       attr->na_uid = uIDmappings[i].unix_ID;
  394.       return TRUE;
  395.       }
  396.  
  397.     /* Not found in mapping table:  add the offset and return. */
  398.     attr->na_uid += uIDoffset;
  399.     return TRUE;
  400. }
  401. #endif /* NOVELL */
  402.  
  403. /*
  404.  *  int file_nsubdirs(char *path) --
  405.  *    Returns # of subdirectories in the given directory.
  406.  */
  407. static int file_nsubdirs(path)
  408.     char *path;
  409. {
  410.     int subdirs = 0;
  411.     struct find_t ft;
  412.     char name[MAXPATHNAMELEN];
  413. #define VALID(ft) (strcmp((ft).name, ".") != 0 && strcmp((ft).name, "..") != 0)
  414.  
  415. /* Hack:  this routine eats a lot of time and doesn't work anyway. */
  416.  
  417. return 0;
  418.  
  419. #if 0
  420.     (void) strcpy(name, path);
  421.     (void) strcat(name, "\\*.*");        /* append wildcard */
  422.  
  423.     if (_dos_findfirst(name, _A_SUBDIR, &ft) != 0)
  424.         if (VALID(ft))
  425.             subdirs++;
  426.         else
  427.             return 0;
  428.  
  429.     while(_dos_findnext(&ft) == 0)
  430.         if (VALID(ft))
  431.             subdirs++;
  432.     DBGPRT2 (nfslookup, "dos_findfirst '%s', found %d subdirs",
  433.         name, subdirs);
  434.     return subdirs;
  435. #endif /* 0 */
  436.  
  437. #undef VALID
  438. }
  439.  
  440. /*
  441.  *  long file_freeblocks(int drive, long *free, long *total) --
  442.  *      Return # of free blocks in specified filesystem (ie. drive).
  443.  */
  444. long file_freeblocks(drive, free, total)
  445.     int drive;
  446.     long *free, *total;
  447. {
  448.     struct diskfree_t df;    /* disk free */
  449.  
  450.     if (_dos_getdiskfree(drive, &df) != 0) {    /* dos call */
  451.         (void) fprintf(stderr, "freeblocks: err, cannot read\n");
  452.         return 0;
  453.     }
  454. /*    DBGPRT2 (nfsdebug, "%c: blocks free %ld", 'A'+drive-1,
  455.          (long) df.avail_clusters * (long) df.sectors_per_cluster); */
  456.  
  457.     *free = ((long)df.avail_clusters * (long)df.sectors_per_cluster) 
  458.         / DRIVE_SCALINGFACTOR;
  459.     *total = ((long)df.total_clusters * (long)df.sectors_per_cluster) 
  460.          / DRIVE_SCALINGFACTOR;
  461.     return *free;
  462. }
  463.  
  464. /* a file pointer cache for read requests */
  465. #define FRDCSIZ 10
  466. static struct {
  467.     u_long nodeid;
  468.     FILE *fp;
  469. } frdc_cache[FRDCSIZ];        /* up to ten cached file handles */
  470.  
  471. static int frdc_last;        /* last location saved */
  472.  
  473. /*
  474.  *  void frdc_save(u_long nodeid, FILE *fp) --
  475.  *    Cache read file pointers.
  476.  */
  477. static void frdc_save(nodeid, fp)
  478.      u_long nodeid;
  479.      FILE *fp;
  480. {
  481.     if (frdc_cache[frdc_last].fp != NULL)
  482.         (void) fclose(frdc_cache[frdc_last].fp);      /* throw away */
  483.     frdc_cache[frdc_last].nodeid = nodeid;
  484.     frdc_cache[frdc_last++].fp = fp;
  485.     if (frdc_last == FRDCSIZ)
  486.         frdc_last = 0;
  487. }
  488.  
  489. /*
  490.  *  void frdc_del(u_long nodeid) --
  491.  *    Delete saved file pointer from read cache.  No effect if file
  492.  *    was not cached.  Closes file pointer also.
  493.  */
  494. static void frdc_del(nodeid)
  495.      u_long nodeid;
  496. {
  497.     int i;
  498.  
  499.     for(i = 0; i < FRDCSIZ; i++) {
  500.     if (frdc_cache[i].fp != NULL && frdc_cache[i].nodeid == nodeid) {
  501.         (void) fclose(frdc_cache[i].fp);
  502.         frdc_cache[i].fp = NULL;
  503.         return;
  504.     }
  505.     }
  506. }
  507.  
  508. /*
  509.  *  FILE *frdc_find(u_long nodeid) --
  510.  *    Finds cached file pointer corresponding to nodeid, or NULL
  511.  *    if no such file exists.
  512.  */
  513. FILE *frdc_find(nodeid)
  514.      u_long nodeid;
  515. {
  516.     int i;
  517.  
  518.     for(i = 0; i < FRDCSIZ; i++) {
  519.     if (frdc_cache[i].fp != NULL && frdc_cache[i].nodeid == nodeid)
  520.       return frdc_cache[i].fp;
  521.     }
  522.  
  523.     return NULL;
  524. }
  525.  
  526. /*
  527.  *  int file_read(u_long nodeid, u_long offset,
  528.  *                u_long count, char *buffer) --
  529.  *    Reads count bytes at offset into buffer.  Returns # of bytes read,
  530.  *      and -1 if an error occurs, or 0 for EOF or null file.
  531.  */
  532. int file_read(nodeid, offset, count, buffer)
  533.      u_long nodeid;
  534.      u_long offset, count;
  535.      char *buffer;
  536. {
  537.     FILE *fp;
  538.     bool_t saved = FALSE;
  539.     int bytes = 0;
  540.     char path [MAXPATHNAMELEN];
  541.  
  542.     if ((fp = frdc_find(nodeid)) != NULL) {
  543.     saved = TRUE;
  544.     }
  545.     else if ((fp = fopen(intopn (nodeid, path), "rb")) == NULL)
  546.       return -1;
  547.  
  548.     /* Seek to correct position */
  549.     if (fseek(fp, (long) offset, 0) != 0) {
  550.     if (!feof(fp)) {
  551.         (void) fclose(fp);
  552.         return -1;
  553.     }
  554.     else
  555.       return 0;
  556.     }
  557.  
  558.     /* Read from the file */
  559.     bytes = fread(buffer, sizeof(char), (size_t) count, fp);
  560.     if (!saved)
  561.       frdc_save(nodeid, fp);
  562.  
  563.     return bytes;
  564. }
  565.  
  566. /*
  567.  *  int file_rddir(u_long nodeid, u_long offs, struct udirect *udp) --
  568.  *      Put file information at offs in directory at path in nfs cookie 
  569.  *    at *udp. Returns # of bytes in record, 0 if there are no more entries
  570.  *       or -1 for a read error.
  571.  */
  572. int file_rddir(nodeid, offs, udp)
  573.      u_long nodeid;
  574.      u_long offs;
  575.      struct udirect *udp;
  576. {
  577.     char filename[MAXPATHNAMELEN];
  578.     char npath[MAXPATHNAMELEN], path[MAXPATHNAMELEN];
  579.     struct find_t findbuf;
  580.     struct nfsfattr attr;
  581.     u_long fnode;
  582.  
  583. #define SUD  32 /*    sizeof(struct udirect) */ /* full udp cookie size */
  584.  
  585.     if (offs == 0) {
  586.     /* Force a read of the full directory if offset is zero. */
  587.  
  588.     if (intopn (nodeid, path) == NULL)
  589.       return -1;
  590.  
  591.     /* look for the first file in the directory */
  592.     (void) sprintf(npath, "%s\\*.*", path);
  593.     if (_dos_findfirst(npath, _A_NORMAL | _A_SUBDIR |
  594.                _A_RDONLY, &findbuf) == 0) {
  595.  
  596.         /* Read file attributes from each entry into inode cache */
  597.         for (;;) {
  598.         /* convert to lowercase and get the full path */
  599.         (void) strtolower(findbuf.name);
  600.         (void) sprintf(filename, "%s\\%s", path, findbuf.name);
  601.  
  602.         if ((fnode = pntoin(filename)) == -1)
  603.           fnode = addpathtodirtree(filename);
  604.         if (inattrget (fnode, &attr) == (struct nfsfattr *) NULL)
  605.           (void) bzero (&attr, sizeof (struct nfsfattr));
  606.         cvtd2uattr (fnode, &findbuf, &attr);
  607.         if (findbuf.attrib & _A_SUBDIR)
  608.           attr.na_mode = uperm_dir;
  609.         else if (findbuf.attrib & _A_RDONLY)
  610.           attr.na_mode = uperm_rdonly;
  611.         else
  612.           attr.na_mode = uperm_write;
  613. #ifdef NOVELL
  614.         (void) ldnovell (fnode, filename+2, &attr);
  615. #endif
  616.         /* cache this info */
  617.         inattrset (fnode, &attr);
  618.  
  619.         /* fetch next entry */
  620.         if (_dos_findnext(&findbuf) != 0)
  621.           break;
  622.         }
  623.     }
  624.     }
  625.  
  626.     /* fetch the proper inode */
  627.     if ((udp->d_fileno = ingetentry (nodeid, offs / SUD, udp->d_name)) == -1)
  628.       return -1;
  629.  
  630.     /* store the remaining udp info */
  631.     udp->d_namlen = strlen(udp->d_name);
  632.     udp->d_offset = offs + SUD;
  633.     udp->d_reclen = UDIRSIZ(udp);
  634.  
  635.     /* return 0 if this is the last entry */
  636.     if (ingetentry (nodeid, (offs / SUD) + 1, filename) == -1)
  637.       return 0;
  638.     else
  639.       return udp->d_reclen;
  640.  
  641. #undef SUD
  642. }
  643.     
  644. /*
  645.  *  char *strtolower(char *s) --
  646.  *    Converts all characters in s to lower case.  Returns s.
  647.  */
  648. char *strtolower(s)
  649.     char *s;
  650. {
  651.     char *tmp;
  652.  
  653.     tmp = s;
  654.     while(*s != '\0') {
  655.         if (isalpha(*s) && isupper(*s))
  656.             *s = tolower(*s);
  657.         s++; 
  658.     }
  659.  
  660.     return tmp;
  661. }
  662.  
  663. /*
  664.  *  enum nfsstat file_write(u_long nodeid, u_long offset,
  665.  *                          u_long count, char *buffer) --
  666.  *      Write to file with name at offset, count bytes of data from buffer.
  667.  *    File should already exist.  Returns 0 for success, or some error 
  668.  *    code if not.
  669.  */
  670. enum nfsstat file_write(nodeid, offset, count, buffer)
  671.     u_long nodeid;
  672.     u_long offset;
  673.     u_long count;
  674.     char *buffer;
  675. {
  676.     int handle;            /* write file handle */
  677.     long newoff;
  678.     char name [MAXPATHNAMELEN];
  679.     int fw_num = WR_SIZ;
  680.     struct nfsfattr attr;
  681.     time_t now;
  682.  
  683.     if (intopn (nodeid, name) == NULL)
  684.       return NFSERR_STALE;
  685.  
  686.     frdc_del(nodeid);            /* delete from read cache */
  687.  
  688.     /* Get cached file attributes */
  689.     if (inattrget (nodeid, &attr) == (struct nfsfattr *) NULL) {
  690.         fprintf (stderr, "file_write: attrget failed\n");
  691.     }
  692.     else {
  693.         /* If the file is read-only, temporarily set it to read/write */
  694.         if (!(attr.na_mode & UCHK_WR))
  695.           (void) _dos_setfileattr(name, _A_NORMAL);
  696.     }
  697.  
  698.     /* open for writing only */
  699.     handle = open(name, O_WRONLY | O_BINARY);
  700.     if (handle == -1)
  701.         return puterrno(errno);    /* return error code */
  702.  
  703.     DBGPRT4 (nfswrite, "%s, %ld bytes at %ld (len = %ld)",
  704.          name, count, offset, filelength (handle));
  705.  
  706.     newoff = lseek(handle, offset, 0);
  707.     if (count < WR_SIZ) fw_num = count;
  708.     if (write(handle, buffer, fw_num) == -1) {
  709.         (void) close(handle);
  710.         return puterrno(errno);        /* some error */
  711.     }
  712.  
  713.     /* Update cached file attributes */
  714.     attr.na_size = filelength (handle);
  715.     (void) time (&now);
  716.     attr.na_atime.tv_usec = 0;
  717.     attr.na_atime.tv_sec = now - timezone * 2;  /** ?why times 2? **/
  718.     attr.na_mtime = attr.na_atime;
  719.     attr.na_ctime = attr.na_atime;
  720.     (void) inattrset (nodeid, &attr);
  721.  
  722.     (void) close(handle);
  723.     
  724.     /* If the file is read-only, set its _A_RDONLY attribute */
  725.     if (!(attr.na_mode & UCHK_WR))
  726.       (void) _dos_setfileattr(name, _A_RDONLY);
  727.     return NFS_OK;
  728. }
  729.  
  730. /*
  731.  *  enum nfsstat file_create(char *name, struct nfssattr *sattr,
  732.  *                           struct nfsfattr *fattr)
  733.  *      Creates a file with full path name and attributes sattr, and returns
  734.  *      the file attributes in *fattr.  Adds file to directory tree.
  735.  *      Returns NFS_OK for success, or some error code for failure.
  736.  */
  737. enum nfsstat file_create(name, sattr, fattr)
  738.      char *name;
  739.      struct nfssattr *sattr;
  740.      struct nfsfattr *fattr;
  741. {
  742.     int handle;            /* file handle */
  743.     enum nfsstat stat;
  744.     u_long node;
  745.     int sattribs = S_IREAD;        /* set attributes */
  746.  
  747.     if (name == NULL)
  748.       return NFSERR_NOENT;
  749.  
  750.     if ((stat = validate_path (name)) != NFS_OK)
  751.       return (stat);
  752.  
  753.     if (sattr->sa_mode & UCHK_WR)       /* file is writeable */
  754.       sattribs |= S_IWRITE;       /* set DOS file to be read & write */
  755.  
  756.     /* Remove the inode if assigned */
  757.     if ((node = pntoin (name)) != -1) {
  758.     frdc_del (node);
  759.     inremnode (node);
  760.     }
  761.  
  762. #if 0
  763.  
  764.     /* obsolete code -- now get uid/gid from RPC header */
  765.     if (sattr->sa_uid == -1 || sattr->sa_gid == -1) {
  766.     char parent [MAXPATHNAMELEN];
  767.     struct nfsfattr pattr;        /* attributes of parent */
  768.     char *strrchr();
  769.  
  770.     /* Set up UID and GID defaults from parent inode */
  771.     strcpy (parent, name);
  772.     *strrchr (parent, '\\') = '\0';
  773.     if (!file_getattr (parent, &pattr)) {
  774.         DBGPRT1 (nfsdebug, "no attrs %s", parent);
  775.     }
  776.     else {
  777.         if (sattr->sa_uid == -1)
  778.           sattr->sa_uid = pattr.na_uid;
  779.         if (sattr->sa_gid == -1)
  780.           sattr->sa_uid = pattr.na_gid;
  781.     }
  782.     }
  783. #endif
  784.  
  785.     DBGPRT4 (nfsdebug, "file_create %s <%o> [%ld,%ld]", name,
  786.          (int) sattr->sa_mode, sattr->sa_uid, sattr->sa_gid);
  787.  
  788.     /* check if file already exists */
  789.     if ((handle = open(name, O_CREAT | O_TRUNC, sattribs)) == -1)
  790.       return puterrno (errno);
  791.     close(handle);
  792.  
  793.     /* Add to inode tree */
  794.     if ((node = pntoin(name)) == -1)
  795.       node = addpathtodirtree(name);
  796.  
  797.     /* Set the file's ownership */
  798.     (void) file_setowner (node, sattr->sa_uid, sattr->sa_gid);
  799.  
  800.     /* Read the file's attributes and return */
  801.     if (! file_readattr(name, fattr)) 
  802.       return NFSERR_IO;      /* just created but not found now! */
  803.  
  804.     return NFS_OK;
  805. }
  806.  
  807. /*
  808.  *  int file_setperm(char *path, long perm) --
  809.  *      Sets file permissions depending on perm.  Perm is of two types,
  810.  *      uperm_write (regular file) or uperm_rdonly (read only).
  811.  *    Returns 0 for success or some error code if an error occurs.
  812.  */
  813. enum nfsstat file_setperm(nodeid, perm)
  814.      u_long nodeid;
  815.      long perm;
  816. {
  817.     int stat, attribs;
  818.     char path [MAXPATHNAMELEN];
  819.     struct nfsfattr attr;
  820.  
  821.     if (intopn(nodeid, path) == NULL)    /* get file name */
  822.       return NFSERR_STALE;
  823.  
  824. #ifndef DOSAUTH
  825.     if (perm & UPERM_WRITE) {
  826.     attribs = _A_NORMAL;
  827.     perm = uperm_write;
  828.     }
  829.     else {
  830.     attribs = _A_RDONLY;
  831.     perm = uperm_rdonly;
  832.     }
  833. #endif
  834.  
  835.     stat = _dos_setfileattr(path, attribs);
  836.     if (stat == 0) {
  837.     /* Update cached file attributes */
  838.     if (inattrget (nodeid, &attr) != (struct nfsfattr *) NULL) {
  839.         attr.na_mode = perm;
  840.         (void) inattrset (nodeid, &attr);
  841.         return NFS_OK;
  842.     }
  843.     } else
  844.       return puterrno(errno);
  845. }    
  846.         
  847. /*
  848.  *  int file_setsize(u_long nodeid, long size) --
  849.  *      Sets file size.
  850.  *    Returns 0 for success or some error code if an error occurs.
  851.  */
  852. enum nfsstat file_setsize(nodeid, size)
  853.      u_long nodeid;
  854.      long size;
  855. {
  856.     int stat, handle;
  857.     char path [MAXPATHNAMELEN];
  858.     struct nfsfattr attr;
  859.  
  860.     if (intopn(nodeid, path) == NULL)    /* get file name */
  861.       return NFSERR_STALE;
  862.  
  863.     if (size == 0L) {
  864.     if ((handle = open(path, O_CREAT | O_TRUNC, S_IWRITE)) == -1)
  865.         return puterrno (errno);
  866.     close(handle);
  867.  
  868.     /* Update cached file attributes */
  869.     if (inattrget (nodeid, &attr) != (struct nfsfattr *) NULL) {
  870.         attr.na_size = 0;
  871.         (void) inattrset (nodeid, &attr);
  872.     }
  873.     return NFS_OK;
  874.     }
  875.     else
  876.       return NFSERR_IO;
  877. }    
  878.  
  879. /*
  880.  *  int file_settime(u_long nodeid, long secs) --
  881.  *      Sets file time specified by secs (# of seconds since 0000, Jan 1, 1970.
  882.  *    Returns 0 for success or some error code if an error occurs.
  883.  */
  884. enum nfsstat file_settime(nodeid, secs)
  885.      u_long nodeid;
  886.      long secs;
  887. {
  888.     int stat, handle;
  889.     unsigned fdate, ftime;
  890.     char path [MAXPATHNAMELEN];
  891.     struct nfsfattr attr;
  892.  
  893.     if (intopn(nodeid, path) == NULL)    /* get file name */
  894.       return NFSERR_STALE;
  895.  
  896.     /* must open file to change time */
  897.     if ((handle = open(path, O_RDONLY, S_IREAD)) == -1)
  898.       return puterrno(errno);
  899.  
  900.     /* Convert Unix time format into DOS format */
  901.     dostime (secs, &fdate, &ftime);
  902.  
  903.     stat = _dos_setftime(handle, fdate, ftime);
  904.  
  905.     (void) close(handle);
  906.     if (stat != 0)
  907.       return puterrno(errno);
  908.     else {
  909.     /* Update cached file attributes */
  910.     if (inattrget (nodeid, &attr) != (struct nfsfattr *) NULL) {
  911.         attr.na_atime.tv_usec = 0;
  912.         attr.na_atime.tv_sec = secs;
  913.         attr.na_mtime = attr.na_atime;
  914.         attr.na_ctime = attr.na_atime;
  915.         (void) inattrset (nodeid, &attr);
  916.     }
  917.  
  918.     return NFS_OK;
  919.     }
  920. }
  921.  
  922. /*
  923.  *  int file_setowner(u_long nodeid, long uid, long gid) --
  924.  *      Sets file ownership values.
  925.  *      This can only set the values in cache, because DOS doesn't
  926.  *    support an on-disk representation.
  927.  */
  928. enum nfsstat file_setowner(nodeid, uid, gid)
  929.      u_long nodeid;
  930.      long uid, gid;
  931. {
  932.     struct nfsfattr attr;
  933.     char path [MAXPATHNAMELEN];
  934.  
  935.     if (intopn (nodeid, path) == NULL)
  936.       return NFSERR_NOENT;
  937.     DBGPRT3 (nfsdebug, "Setting owner to [%ld,%ld] %s", uid, gid, path);
  938.  
  939.     if (file_getattr (path, &attr)) {
  940. #ifdef NOVELL
  941.     if (!(attr.na_mode & UPERM_DIR) && uid != -1) {
  942.         /* Set up the Scan File Information request block, as defined on */
  943.         /* page 283 of the Novell API Reference, rev 1.00.         */
  944.  
  945.         static struct _sfireq sfireq = /* These are placed in static */
  946.           {0, 0x0F, -1, -1, 0, 0, 0};  /* memory because code here   */
  947.         static struct _sfirep sfirep;  /* assumes seg register DS.   */
  948.         static struct _setfireq setfireq =
  949.           {0, 0x10, 0};
  950.         static struct _setfirep setfirep;
  951.         u_char handle;
  952.         union REGS regsin, regsout;
  953.         struct SREGS segregs;
  954.         int i;
  955.  
  956.         if ((handle = novell_GDH (ingetfsid (nodeid))) != 255) {
  957.         segregs.ds = get_ds();
  958.         segregs.es = segregs.ds;
  959.  
  960.         sfireq.handle = handle;
  961.         sfireq.pathlen = strlen (path+2);
  962.         sfireq.len = 6 + sfireq.pathlen;
  963.         sfirep.len = sizeof (sfirep) -2;
  964.         strcpy (sfireq.path, path+2);
  965.  
  966.         novell_API(0xE3, &sfireq, &sfirep, regsin, ®sout, &segregs);
  967.         if (regsout.h.al != 0)
  968.             return NFSERR_IO;
  969.  
  970.         /* Set up the Set File Info request block */
  971.         setfireq.handle = handle;
  972.         setfireq.pathlen = strlen (path+2);
  973.         setfireq.len = 4 + sizeof (struct _fileinfo) + sfireq.pathlen;
  974.         setfirep.len = sizeof (setfirep) -2;
  975.         strcpy (setfireq.path, path+2);
  976.         setfireq.info = sfirep.info;
  977.         setfireq.info.size = 0;
  978.  
  979.         /* Look up the Novell user ID */
  980.         setfireq.info.ownerID = uid - uIDoffset;
  981.         for (i = 0; i < uIDcount; i++)
  982.           if (uIDmappings[i].unix_ID == uid + uIDoffset) {
  983.               setfireq.info.ownerID = uIDmappings[i].Novell_ID;
  984.               break;
  985.           }
  986.  
  987.         /* Issue the Set File Information request */
  988.         novell_API(0xE3, &setfireq, &setfirep, regsin, ®sout,
  989.                &segregs);
  990.         if (regsout.h.al != 0)
  991.             return NFSERR_ACCES;
  992.         }
  993.     }
  994. #endif /* NOVELL */
  995.  
  996.     /* Update cached file attributes */
  997.     if (uid != -1)
  998.       attr.na_uid = uid;
  999.     if (gid != -1)
  1000.       attr.na_gid = gid;
  1001.     (void) inattrset (nodeid, &attr);
  1002.     return NFS_OK;
  1003.     }
  1004.     else
  1005.     return NFSERR_NOENT;
  1006. }
  1007.  
  1008. /*
  1009.  *  int file_unlink(char *name) --
  1010.  *       Removes named file.
  1011.  */
  1012. enum nfsstat file_unlink(name)
  1013.     char *name;
  1014. {
  1015.     u_long node;
  1016.     int    stat;
  1017.  
  1018.     /* Close the file if we still have a handle to it */
  1019.     if ((node = pntoin (name)) != -1)
  1020.     frdc_del (node);
  1021.  
  1022.     /* Reset file attributes */
  1023.     (void) _dos_setfileattr(name, _A_NORMAL);
  1024.  
  1025.     /* Call unlink library function to remove the file. */
  1026.     stat = unlink(name);
  1027. DBGPRT3 (nfserr, "unlink %s: stat = %d, len = %d", name, stat, strlen(name));
  1028.  
  1029.     /* Remove the inode associated with the file, if present. */
  1030.     if (stat == 0 && node != -1)
  1031.     inremnode (node);
  1032.     return (stat == 0) ? NFS_OK : puterrno (errno);
  1033. }
  1034.  
  1035.  
  1036. /*
  1037.  *  int file_rename(char *oldname, char *newname) --
  1038.  *       Renames a file
  1039.  */
  1040. enum nfsstat file_rename(oldname, newname)
  1041.     char *oldname, *newname;
  1042. {
  1043.     u_long node;
  1044.     int    err;
  1045.     struct stat buf;
  1046.     enum   nfsstat code;
  1047.  
  1048.     /* Close the file if we still have a handle to it */
  1049.     if ((node = pntoin (oldname)) != -1)
  1050.     frdc_del (node);
  1051.  
  1052.     /* Reset file attributes (e.g., read-only) */
  1053.     (void) _dos_setfileattr(oldname, _A_NORMAL);
  1054.  
  1055.     /* Validate the new filename */
  1056.     if ((code = validate_path (newname)) != NFS_OK)
  1057.       return (code);
  1058.  
  1059.     /* Delete destination file if present */
  1060.     if (stat (newname, &buf) == 0) {
  1061.     if (buf.st_mode & S_IFDIR)
  1062.       return NFSERR_ISDIR;
  1063.     if ((code = file_unlink (newname)) != NFS_OK)
  1064.       return code;
  1065.     }
  1066.  
  1067.     /* Call rename library function to rename the file. */
  1068.     err = rename(oldname,newname);
  1069.  
  1070.     /* Update the inode associated with the file, if present. */
  1071.     if (err == 0 && node != -1) {
  1072.     (void) inremnode (node);
  1073.     (void) addpathtodirtree(newname);
  1074.     }
  1075.     return (err == 0) ? NFS_OK : puterrno (errno);
  1076. }
  1077.  
  1078. /*
  1079.  *  enum nfsstat validate_path (char *name) --
  1080.  *       Validate a path name's syntax.  Returns 0 if OK.
  1081.  *       Modifies the path appropriately if NFS_TRUNCATENAMES is set.
  1082.  */
  1083. enum nfsstat validate_path (name)
  1084.      char *name;
  1085. {
  1086.     char *ptr, *ptr2, *strrchr(), *strchr();
  1087.     int i;
  1088.  
  1089.     if ((ptr = strrchr (name, '\\')) == (char *)NULL &&
  1090.     (ptr = strrchr (name, ':')) == (char *)NULL)
  1091.     ptr = name;
  1092.     else
  1093.         ptr++;
  1094.  
  1095.     /* Check validity of characters in final component */
  1096.     for (ptr2 = ptr; *ptr2; ) {
  1097.     if (*ptr2 <= ' ' || (*ptr2 & 0x80) || !inchvalid[*ptr2 - '!'])
  1098.       return NFSERR_INVAL;
  1099.     else
  1100.       ptr2++;
  1101.     }
  1102.  
  1103.     /* Verify there are no more than 8 chars before '.' */
  1104.     if ((i = strcspn (ptr, ".")) > 8) {
  1105.     if (!NFS_TRUNCATENAMES)
  1106.       return NFSERR_NAMETOOLONG;
  1107.     strcpy (ptr + 8, ptr + i);
  1108.     }
  1109.     if ((ptr = strchr (name, '.')) == (char *)NULL)
  1110.     return NFS_OK;
  1111.     else
  1112.         ptr++;
  1113.     if (strlen (ptr) > 3) {
  1114.     if (!NFS_TRUNCATENAMES)
  1115.       return NFSERR_NAMETOOLONG;
  1116.     ptr[3] = '\0';
  1117.     }
  1118.     return NFS_OK;
  1119. }
  1120.