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