home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / utils / sossntr3 / src / files.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-19  |  36.0 KB  |  1,469 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.  
  31. #ifdef RCSID
  32. static char _rcsid_ = "$Id: files.c_v 1.6 1991/05/13 17:43:50 richb Exp $";
  33. #endif
  34.  
  35. #include "common.h"
  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. #include <sys/types.h>
  41. #include <sys/utime.h>
  42.  
  43. #include <errno.h>
  44. #include <ctype.h>
  45. #include "ntfsauth.h"
  46.  
  47.  
  48. #define READWITHCACHE  1        // turn off when problem
  49. #ifdef  READWITHCACHE
  50. //#define WRITEWITHCACHE  1
  51. #endif
  52.  
  53. /* Default permissions for files are 555 for read-only and 777  */
  54. /* for writeable.  The low-order 9 bits can be modified by the  */
  55. /* administrator.                       */
  56. u_short uperm_rdonly = UPERM_FILE | UPERM_READ | UPERM_EXEC;
  57. u_short uperm_write  = UPERM_FILE | UPERM_READ | UPERM_WRITE | UPERM_EXEC;
  58. u_short uperm_dir    = UPERM_DIR | UPERM_READ | UPERM_WRITE | UPERM_SEARCH;
  59.  
  60.  
  61. #ifdef NOVELL
  62. #include "novell.h"     /* Novell definitions */
  63. static struct _uidmap {
  64.     u_long  unix_ID;
  65.     u_long  Novell_ID;
  66.     } *uIDmappings = NULL;
  67. static int uIDcount;
  68. static u_long uIDoffset;
  69. static u_long gID;
  70. static u_short novelldirprot;
  71.  
  72. static bool_t ldnovell (u_long, char *, struct nfsfattr *);
  73. #endif /* NOVELL */
  74.  
  75.  
  76. #ifdef DOSAUTH
  77. /* Support for handling file authentication */
  78. struct _authent {
  79.     u_short uid;        /* UID of file owner */
  80.     u_short gid;        /* GID of file owner */
  81.     u_short mode;       /* Protection mode bits */
  82.     u_short reserved;
  83.     };
  84. #define AUTHSIZE (sizeof (struct _authent))
  85. #define AUTHFILE "AUTHS.DMP"
  86. static int authfh = 0;
  87. #endif /* DOSAUTH */
  88.  
  89. static int file_nsubdirs(char *);
  90. static bool_t file_readattr(char *, struct nfsfattr *);
  91. static void   cvtd2uattr (u_long, struct _finddata_t *, struct nfsfattr *);
  92. static void frdc_clr( void);
  93.  
  94. #define DRIVE_SCALINGFACTOR 4   /* scaling factor for NT */
  95.  
  96. BOOL
  97. setnormalfileattr(char *name)
  98. {
  99.     return SetFileAttributes(name,FILE_ATTRIBUTE_NORMAL);
  100. }
  101.  
  102. BOOL
  103. setreadonlyfileattr(char *name)
  104. {
  105.     return SetFileAttributes(name,FILE_ATTRIBUTE_READONLY);
  106. }
  107.  
  108. /*
  109.  *  bool_t file_getattr(char *path, struct nfsfattr *attr) --
  110.  *      Gets attributes for designated file or directory and puts
  111.  *      the information in *attr.  Returns TRUE if successful, FALSE otherwise.
  112.  */
  113. bool_t file_getattr(path, attr)
  114.     char *path;
  115.     struct nfsfattr *attr;
  116. {
  117.     if (path == NULL)
  118.       return FALSE;
  119. #ifdef READWITHCACHE
  120.     frdc_clr();
  121. #endif
  122.     /* See if info is cached in the inode tree */
  123.  
  124. #ifdef CACHEIT
  125.     if (inattrget (pntoin (path), attr) != NULL)
  126.     return TRUE;
  127. #endif
  128.  
  129.     /* Else go out to disk */
  130. DBGPRT1 (inode, "getattr going to disk, path = %s", path);
  131.     return  file_readattr(path, attr);
  132. }
  133.  
  134. /* myfindfirst - note that _findclose is called, so that the search */
  135. /* cannot be continued.  This only returns the first file match. */
  136. int
  137. myfindfirst(path, findbuf)
  138. char *path;
  139. struct _finddata_t *findbuf;
  140. {
  141.     long fhand;
  142.  
  143.     fhand = _findfirst(path,findbuf);
  144.     if ( fhand < 0 ) {
  145.         DBGPRT0 (inode, "myfindfirst, fhand<0");
  146.         return -1;
  147.     }
  148.     /* We used to check only for NORMAL/SUBDIR/RDONLY files, but that */
  149.     /* didn't seem to work right, and besides, it seems like we should */
  150.     /* just see most files, right? */
  151.     DBGPRT3 (inode, "myfindfirst  name=%s attrib=0x%x  access=%d",path,findbuf->attrib,_access(path,04));
  152.     _findclose(fhand);
  153.     return 0;
  154. }
  155.  
  156.  
  157. /*
  158.  *  bool_t file_readattr(char *path, struct nfsfattr *attr) --
  159.  *      Reads file attributes for a file from disk.
  160.  *      Returns TRUE if successful, FALSE otherwise.
  161.  *  Adds file to directory tree if the file does not already exist in
  162.  *  the tree.
  163.  */
  164. static bool_t file_readattr(path, attr)
  165.     char *path;
  166.     struct nfsfattr *attr;
  167. {
  168.     struct _finddata_t findbuf;
  169.     u_long nodeid;
  170.  
  171.     /* Special-case the root directory */
  172.     if (strlen (path) == 2 && path[1] == ':') {
  173.  
  174.         (void) bzero((char*)attr, sizeof(struct nfsfattr));
  175.         attr->na_blocksize = NFS_MAXDATA;
  176.  
  177.  
  178.         /* Set directory attributes */
  179.         attr->na_type = NFDIR;
  180.         attr->na_mode = uperm_dir;
  181.         attr->na_nlink = 2;
  182.         attr->na_blocks = 1;         /* just say 1 block */
  183.         attr->na_size = 1024;
  184. //        attr->na_size = 8192;
  185.  
  186.         /* cache this info */
  187.         inattrset (nodeid, attr);
  188.         return TRUE;
  189.     }
  190.  
  191.     /* Look for the file given */
  192. DBGPRT1 (inode, "caling myfindfirst for path= %s", path);
  193.     if (myfindfirst(path,&findbuf) != 0) {
  194.  
  195.         /* not successful */
  196.         if ((nodeid = pntoin(path)) != -1)
  197.               inremnode (nodeid);
  198.             DBGPRT0 (inode, "return false A");
  199.             return FALSE;
  200.         }
  201.         if ((nodeid = pntoin(path)) == -1) {
  202.           nodeid = addpathtodirtree(path);
  203.     }
  204.  
  205.     /* Load attributes from findbuf */
  206.     (void) bzero((char*)attr, sizeof(struct nfsfattr));
  207.     cvtd2uattr (nodeid, &findbuf, attr);
  208.  
  209.         if (findbuf.attrib & _A_SUBDIR)
  210.       attr->na_mode = uperm_dir;
  211.         else if (findbuf.attrib & _A_RDONLY)
  212.       attr->na_mode = uperm_rdonly;
  213.     else
  214.       attr->na_mode = uperm_write;
  215.  
  216. #ifdef NOVELL
  217.     /* Novell stuff */
  218.     (void) ldnovell (nodeid, path+2, attr);
  219. #endif
  220.  
  221. #ifdef NTFS
  222.     if( TRUE == NtfsCompDriveType( path, "NTFS"))
  223.         NtfsGetUnixAttrib( path, attr);    
  224. #endif
  225.  
  226. #ifdef DOSAUTH
  227.     /* Read authentication entry */
  228.     if (authfh != 0 && lseek (authfh, nodeid * AUTHSIZE, SEEK_SET) ==
  229.       nodeid * AUTHSIZE) {
  230.         struct _authent authentry;
  231.         if (read (authfh, &authentry, AUTHSIZE) == AUTHSIZE) {
  232.         attr->na_uid = authentry.uid;
  233.         attr->na_gid = authentry.gid;
  234.         attr->na_mode = authentry.mode;
  235.         }
  236.     }
  237. #endif /* DOSAUTH */
  238.     /* cache this info */
  239.     inattrset (nodeid, attr);
  240. DBGPRT0 (inode, "return true A");
  241.     return TRUE;
  242. }
  243.  
  244. static void cvtd2uattr (nodeid, findbuf, attr)
  245.      u_long nodeid;
  246.      struct _finddata_t *findbuf;
  247.      struct nfsfattr *attr;
  248. {
  249.     /* file protection bits and type */
  250.     if (findbuf->attrib & _A_SUBDIR) {      /* subdirectory */
  251.     attr->na_type = NFDIR;
  252.     attr->na_nlink = 2;  /*** + file_nsubdirs(path) ***/
  253.     /* # of subdirectories plus this one */
  254.     }
  255.     else if (findbuf->attrib & _A_RDONLY) {     /* rdonly */
  256.     attr->na_type = NFREG;
  257.     attr->na_nlink = 1;
  258.     }
  259.     else {
  260.     attr->na_type = NFREG;      /* normal file */
  261.     attr->na_nlink = 1;
  262.     }
  263.  
  264.     /* file size in bytes */
  265.     if (findbuf->attrib & _A_SUBDIR) {        /* directory */
  266.     attr->na_blocks = 1;         /* just say 1 block */
  267. //      attr->na_size = 8192;
  268.         attr->na_size = 1024;
  269.     }
  270.     else {
  271.     attr->na_size = findbuf->size;
  272.     attr->na_blocks = findbuf->size / BASIC_BLOCKSIZE + 
  273.       (findbuf->size % BASIC_BLOCKSIZE == 0 ? 0 : 1);
  274.     }
  275.     /* preferred transfer size in blocks */
  276.     attr->na_blocksize = NFS_MAXDATA;
  277.  
  278.     /* device # == drive # */
  279.     attr->na_fsid = ingetfsid (nodeid);
  280.     attr->na_rdev = attr->na_fsid;
  281.  
  282.     /* inode # */
  283.     attr->na_nodeid = nodeid;
  284.  
  285.     /* time of last access */
  286.     attr->na_atime.tv_usec = 0;
  287.     attr->na_atime.tv_sec = findbuf->time_write;
  288.  
  289.     /* time of last write */
  290.     attr->na_mtime = attr->na_atime;       /* note all times are the same */
  291.  
  292.     /* time of last change */
  293.     attr->na_ctime = attr->na_atime;
  294. }
  295.  
  296.  
  297. /*
  298.  *  int file_nsubdirs(char *path) --
  299.  *  Returns # of subdirectories in the given directory.
  300.  */
  301. static int file_nsubdirs(path)
  302.     char *path;
  303. {
  304.     int subdirs = 0;
  305. #define VALID(ft) (strcmp((ft).name, ".") != 0 && strcmp((ft).name, "..") != 0)
  306.  
  307. /* Hack:  this routine eats a lot of time and doesn't work anyway. */
  308.  
  309. printf("FILE_NSUBDIRS IS RETURNING 0 - A LIEEEEEEE!!!!\n");
  310. return 0;
  311.  
  312. #if 0
  313.     struct _finddata_t ft;
  314.     char name[MAXPATHNAMELEN];
  315.  
  316.     (void) strcpy(name, path);
  317.     (void) strcat(name, "\\*.*");       /* append wildcard */
  318.  
  319.  
  320. /* NOTE: NOT UPGRADED TO WINDOWS NT, SINCE THIS IS COMMENTED OUT */
  321.  
  322.     if (_dos_findfirst(name, _A_SUBDIR, &ft) != 0)
  323.         if (VALID(ft))
  324.             subdirs++;
  325.         else
  326.             return 0;
  327.  
  328.     while(_dos_findnext(&ft) == 0)
  329.         if (VALID(ft))
  330.             subdirs++;
  331.     DBGPRT2 (nfslookup, "dos_findfirst '%s', found %d subdirs",
  332.         name, subdirs);
  333.  
  334.     /* IF THIS CODE IS RESURRECTED, BE SURE TO CALL _findclose() !! */
  335.  
  336.     return subdirs;
  337. #endif /* 0 */
  338.  
  339. #undef VALID
  340. }
  341.  
  342. /*
  343.  *  int file_freeblocks(int drive, long *free, long *total) --
  344.  *      Return # of free blocks in specified filesystem (ie. drive).
  345.  */
  346. long file_freeblocks(drive, free, total)
  347.     int drive;
  348.     long *free, *total;
  349. {
  350.     char drvname[8];
  351.     DWORD nsectors, nbytes, nfreeclusters, nclusters;
  352.  
  353. #ifdef READWITHCACHE
  354.     frdc_clr();
  355. #endif
  356.     sprintf(drvname,"%c:\\",'A'+drive-1);
  357.     if ( GetDiskFreeSpace(drvname,&nsectors,&nbytes,
  358.             &nfreeclusters,&nclusters) == FALSE ) {
  359.         (void) fprintf(stderr, "freeblocks: err, cannot read\n");
  360.         return -1;
  361.     }
  362. /*  DBGPRT2 (nfsdebug, "%c: blocks free %ld", 'A'+drive-1,
  363.          (long) nfreeclustors * nsectors); */
  364.  
  365.     *free = ((long)nfreeclusters * nsectors) / DRIVE_SCALINGFACTOR;
  366.     *total = ((long)nclusters * (long)nsectors) / DRIVE_SCALINGFACTOR;
  367.  
  368.     return 0;
  369. }
  370.  
  371. #ifdef READWITHCACHE
  372. /* a file pointer cache for read requests */
  373. #define FRDCSIZ 10
  374. static struct {
  375.     u_long  nodeid;
  376.     FILE    *fp;
  377.     int     mode;
  378. } frdc_cache[FRDCSIZ];
  379.  
  380. static int frdc_last = 0;       /* last location saved */
  381. #endif
  382.  
  383. /*
  384.  *  void frdc_save(u_long nodeid, FILE *fp) --
  385.  *  Cache read file pointers.
  386.  */
  387. static void frdc_save( u_long nodeid, FILE* fp, int mode)
  388. {
  389. #ifdef READWITHCACHE
  390.     if (frdc_cache[frdc_last].fp != NULL)
  391.         (void) fclose(frdc_cache[frdc_last].fp);    /* throw away */
  392.     frdc_cache[frdc_last].nodeid = nodeid;
  393.     frdc_cache[frdc_last].mode = mode;
  394.     frdc_cache[frdc_last++].fp = fp;
  395.     if (frdc_last == FRDCSIZ)
  396.         frdc_last = 0;
  397. #endif
  398. }
  399.  
  400. /*
  401.  *  void frdc_del(u_long nodeid) --
  402.  *  Delete saved file pointer from read cache.  No effect if file
  403.  *  was not cached.  Closes file pointer also.
  404.  */
  405. static void frdc_del(nodeid)
  406.      u_long nodeid;
  407. {
  408. #ifdef READWITHCACHE
  409.     int i;
  410.  
  411.     for(i = 0; i < FRDCSIZ; i++) {
  412.         if (frdc_cache[i].fp != NULL && frdc_cache[i].nodeid == nodeid) {
  413.             (void) fclose(frdc_cache[i].fp);
  414.             frdc_cache[i].fp = NULL;
  415.             return;
  416.         }
  417.     }
  418. #endif
  419. }
  420.  
  421. /*
  422.  *  clear all cached files
  423.  *
  424.  */
  425.  
  426. static void frdc_clr( void)
  427. {
  428.     int i;
  429.  
  430.     for( i = 0; i < FRDCSIZ; i++)
  431.     {
  432.         if (frdc_cache[i].fp != NULL) {
  433.             (void) fclose(frdc_cache[i].fp);
  434.             frdc_cache[i].fp = NULL;
  435. printf("Close cached file\n");
  436.         }
  437.     }
  438. }
  439.  
  440. /*
  441.  *  FILE *frdc_find(u_long nodeid) --
  442.  *  Finds cached file pointer corresponding to nodeid, or NULL
  443.  *  if no such file exists.
  444.  */
  445.  
  446. static FILE *frdc_find(u_long nodeid, int mode)
  447. {
  448. #ifdef READWITHCACHE
  449.     int i;
  450.  
  451.     for(i = 0; i < FRDCSIZ; i++) {
  452.         if (frdc_cache[i].fp != NULL && frdc_cache[i].nodeid == nodeid)
  453.         {
  454.             if( frdc_cache[i].mode != mode)
  455.             {
  456.                 fclose( frdc_cache[i].fp);
  457.                 frdc_cache[i].fp = NULL;
  458.             }
  459.             else
  460.                 return frdc_cache[i].fp;
  461.         }
  462.     }
  463. #endif
  464.     return NULL;
  465. }
  466.  
  467. /*
  468.  *  int file_read(u_long nodeid, u_long offset,
  469.  *                u_long count, char *buffer) --
  470.  *  Reads count bytes at offset into buffer.  Returns # of bytes read,
  471.  *      and -1 if an error occurs, or 0 for EOF or null file.
  472.  */
  473. int file_read(nodeid, offset, count, buffer)
  474.      u_long nodeid;
  475.      u_long offset, count;
  476.      char *buffer;
  477. {
  478.     FILE *fp;
  479.     bool_t saved = FALSE;
  480.     int bytes = 0;
  481.     char path [MAXPATHNAMELEN];
  482.  
  483.     if ((fp = frdc_find(nodeid, 0)) != NULL) {
  484.     saved = TRUE;
  485.     }
  486.     else if ((fp = fopen(intopn (nodeid, path), "rb")) == NULL) {
  487.       DBGPRT3 (nfserr, "file_read open errno=%d path=%s nodeid=%d", errno,path,nodeid);
  488.       return -1;
  489.      }
  490.  
  491.     /* Seek to correct position */
  492.     if (fseek(fp, (long) offset, 0) != 0) {
  493.         if (!feof(fp)) {
  494.             (void) fclose(fp);
  495.             DBGPRT1 (nfserr, "file_read unable to seek? path=%s", path);
  496.             return -1;
  497.         }
  498.         else
  499.         {
  500. #ifndef READWITHCACHE
  501.           fclose( fp);
  502.           return 0; 
  503. #endif
  504.         }
  505.     }
  506.  
  507.     /* Read from the file */
  508.     bytes = fread(buffer, sizeof(char), (size_t) count, fp);
  509. #ifndef READWITHCACHE
  510.     fclose( fp);
  511. #else
  512.     if (!saved)
  513.       frdc_save(nodeid, fp, 0);
  514. #endif
  515.  
  516.     return bytes;
  517. }
  518.  
  519. /*
  520.  *  int file_rddir(u_long nodeid, u_long offs, struct udirect *udp) --
  521.  *      Put file information at offs in directory at path in nfs cookie 
  522.  *  at *udp. Returns # of bytes in record, 0 if there are no more entries
  523.  *      or -1 for a read error.
  524.  */
  525. int file_rddir(nodeid, offs, udp)
  526.      u_long nodeid;
  527.      u_long offs;
  528.      struct udirect *udp;
  529. {
  530.     char filename[MAXPATHNAMELEN];
  531.     char npath[MAXPATHNAMELEN], path[MAXPATHNAMELEN];
  532.     struct _finddata_t findbuf;
  533.     struct nfsfattr attr;
  534.     u_long fnode;
  535.     long fhand;
  536.  
  537. #define SUD  32 /*  sizeof(struct udirect) */ /* full udp cookie size */
  538.  
  539. #ifdef READWITHCACHE
  540.     frdc_clr();
  541. #endif
  542.     if (offs == 0) {
  543.     /* Force a read of the full directory if offset is zero. */
  544.  
  545.     if (intopn (nodeid, path) == NULL)
  546.       return -1;
  547.  
  548.     /* look for the first file in the directory */
  549.     (void) sprintf(npath, "%s\\*.*", path);
  550.  
  551.     if ( (fhand=_findfirst(npath, &findbuf)) >= 0) {
  552.  
  553.         /* Read file attributes from each entry into inode cache */
  554.         for (;;) {
  555.  
  556.         /* convert to lowercase and get the full path */
  557.         (void) strtolower(findbuf.name);
  558.         (void) sprintf(filename, "%s\\%s", path, findbuf.name);
  559.  
  560.         if ((fnode = pntoin(filename)) == -1)
  561.           fnode = addpathtodirtree(filename);
  562.         if (inattrget (fnode, &attr) == (struct nfsfattr *) NULL)
  563.           (void) bzero ((char*)&attr, sizeof (struct nfsfattr));
  564.         cvtd2uattr (fnode, &findbuf, &attr);
  565.         if (findbuf.attrib & _A_SUBDIR)
  566.           attr.na_mode = uperm_dir;
  567.         else if (findbuf.attrib & _A_RDONLY)
  568.           attr.na_mode = uperm_rdonly;
  569.         else
  570.           attr.na_mode = uperm_write;
  571. #ifdef NOVELL
  572.         (void) ldnovell (fnode, filename+2, &attr);
  573. #endif
  574.  
  575. #ifdef NTFS
  576.         if( TRUE == NtfsCompDriveType( path, "NTFS"))
  577.             NtfsGetUnixAttrib( filename, &attr);    
  578. #endif
  579.  
  580.         /* cache this info */
  581.         inattrset (fnode, &attr);
  582.  
  583.         /* fetch next entry */
  584.         if (_findnext(fhand,&findbuf) != 0) {
  585.           break;
  586.         }
  587.         }
  588.         _findclose(fhand);
  589.     }
  590.     }
  591.  
  592.     /* fetch the proper inode */
  593.     if ((udp->d_fileno = ingetentry (nodeid, offs / SUD, udp->d_name)) == -1)
  594.       return -1;
  595.  
  596.     /* store the remaining udp info */
  597.     udp->d_namlen = strlen(udp->d_name);
  598.     udp->d_offset = offs + SUD;
  599.     udp->d_reclen = UDIRSIZ(udp);
  600.  
  601.     /* return 0 if this is the last entry */
  602.     if (ingetentry (nodeid, (offs / SUD) + 1, filename) == -1)
  603.       return 0;
  604.     else
  605.       return udp->d_reclen;
  606.  
  607. #undef SUD
  608. }
  609.     
  610. /*
  611.  *  char *strtolower(char *s) --
  612.  *  Converts all characters in s to lower case.  Returns s.
  613.  */
  614. char *strtolower(s)
  615.     char *s;
  616. {
  617.     char *tmp;
  618.  
  619.     // no lowercasing
  620.     return s;
  621.  
  622.     tmp = s;
  623.     while(*s != '\0') {
  624.         if (isalpha(*s) && isupper(*s))
  625.             *s = tolower(*s);
  626.         s++; 
  627.     }
  628.  
  629.     return tmp;
  630. }
  631.  
  632. /*
  633.  *  enum nfsstat file_write(u_long nodeid, u_long offset,
  634.  *                          u_long count, char *buffer) --
  635.  *      Write to file with name at offset, count bytes of data from buffer.
  636.  *  File should already exist.  Returns 0 for success, or some error 
  637.  *  code if not.
  638.  */
  639. enum nfsstat file_write(nodeid, offset, count, buffer)
  640.     u_long nodeid;
  641.     u_long offset;
  642.     u_long count;
  643.     char *buffer;
  644. {
  645. #ifndef WRITEWITHCACHE
  646.     int handle;         /* write file handle */
  647.     long newoff;
  648.     char name [MAXPATHNAMELEN];
  649.     int fw_num = WR_SIZ;
  650.     struct nfsfattr attr;
  651.     time_t now;
  652.  
  653.     if (intopn (nodeid, name) == NULL)
  654.       return NFSERR_STALE;
  655.  
  656.     frdc_del(nodeid);           /* delete from read cache */
  657.  
  658.     /* Get cached file attributes */
  659.     if (inattrget (nodeid, &attr) == (struct nfsfattr *) NULL) {
  660.         fprintf (stderr, "file_write: attrget failed\n");
  661.     }
  662.     else {
  663.         /* If the file is read-only, temporarily set it to read/write */
  664.         if (!(attr.na_mode & UCHK_WR))
  665.           (void) setnormalfileattr(name);
  666.     }
  667.  
  668.     /* open for writing only */
  669.     handle = open(name, O_WRONLY | O_BINARY);
  670.     if (handle == -1)
  671.         return puterrno(errno); /* return error code */
  672.     DBGPRT4 (nfswrite, "%s, %ld bytes at %ld (len = %ld)",
  673.          name, count, offset, attr.na_size);
  674.  
  675.     newoff = lseek(handle, offset, 0);
  676.     if (count < WR_SIZ) fw_num = count;
  677.         if (write(handle, buffer, fw_num) == -1) {
  678.             (void) close(handle);
  679.             return puterrno(errno);     /* some error */
  680.         }
  681.  
  682.     /* Update cached file attributes */
  683.     attr.na_size = filelength (handle);
  684.     (void) time (&now);
  685.     attr.na_atime.tv_usec = 0;
  686.     attr.na_atime.tv_sec = now;
  687.     attr.na_mtime = attr.na_atime;
  688.     attr.na_ctime = attr.na_atime;
  689.     (void) inattrset (nodeid, &attr);
  690.  
  691.     (void) close(handle);
  692.     /* If the file is read-only, set its _A_RDONLY attribute */
  693. //    if (!(attr.na_mode & UCHK_WR))
  694. //      (void) setreadonlyfileattr(name);
  695. #else
  696.     FILE*   fp;
  697.     bool_t saved = FALSE;
  698.     long newoff;
  699.     char name [MAXPATHNAMELEN];
  700.     int fw_num = WR_SIZ;
  701.     struct nfsfattr attr;
  702.     time_t now;
  703.  
  704.     if (intopn (nodeid, name) == NULL)
  705.       return NFSERR_STALE;
  706.  
  707.     /* Get cached file attributes */
  708.     if (inattrget (nodeid, &attr) == (struct nfsfattr *) NULL) {
  709.         fprintf (stderr, "file_write: attrget failed\n");
  710.     }
  711.     else {
  712.     }
  713.  
  714.     if ((fp = frdc_find(nodeid, 1)) != NULL) {
  715. printf("Write file cached\n");
  716.         saved = TRUE;
  717.     }
  718.     else if ((fp = fopen(name, "r+b")) == NULL) {
  719.       DBGPRT3 (nfserr, "file_write open errno=%d path=%s nodeid=%d", errno,name,nodeid);
  720.       return -1;
  721.      }
  722.     DBGPRT4 (nfswrite, "%s, %ld bytes at %ld (len = %ld)",
  723.          name, count, offset, attr.na_size);
  724.  
  725.     newoff = fseek( fp, offset, 0);
  726.     if (count < WR_SIZ) fw_num = count;
  727.         if ( fwrite(buffer, 1, fw_num, fp) != fw_num) {
  728.             (void) fclose( fp);
  729.             return puterrno(errno);     /* some error */
  730.         }
  731.  
  732.     /* Update cached file attributes */
  733.     attr.na_size = filelength ( fileno( fp) );
  734.     (void) time (&now);
  735.     attr.na_atime.tv_usec = 0;
  736.     attr.na_atime.tv_sec = now;
  737.     attr.na_mtime = attr.na_atime;
  738.     attr.na_ctime = attr.na_atime;
  739.     (void) inattrset (nodeid, &attr);
  740.  
  741.     if (!saved)
  742.       frdc_save(nodeid, fp, 1);
  743. #endif    
  744.     return NFS_OK;
  745. }
  746.  
  747. /*
  748.  *  enum nfsstat file_create(char *name, struct nfssattr *sattr,
  749.  *                           struct nfsfattr *fattr)
  750.  *      Creates a file with full path name and attributes sattr, and returns
  751.  *      the file attributes in *fattr.  Adds file to directory tree.
  752.  *      Returns NFS_OK for success, or some error code for failure.
  753.  */
  754. enum nfsstat file_create(name, sattr, fattr)
  755.      char *name;
  756.      struct nfssattr *sattr;
  757.      struct nfsfattr *fattr;
  758. {
  759.     int handle;         /* file handle */
  760.     enum nfsstat stat;
  761.     u_long node;
  762.     int sattribs = S_IREAD;     /* set attributes */
  763.  
  764. #ifdef READWITHCACHE
  765.     frdc_clr();
  766. #endif
  767.     if (name == NULL)
  768.       return NFSERR_NOENT;
  769.  
  770.     if ((stat = validate_path (name)) != NFS_OK)
  771.       return (stat);
  772.  
  773.     if (sattr->sa_mode & UCHK_WR)      /* file is writeable */
  774.       sattribs |= S_IWRITE;    /* set DOS file to be read & write */
  775.  
  776.     /* Remove the inode if assigned */
  777.     if ((node = pntoin (name)) != -1) {
  778.     frdc_del (node);
  779.     inremnode (node);
  780.     }
  781.  
  782. #if 0
  783.  
  784.     /* obsolete code -- now get uid/gid from RPC header */
  785.     if (sattr->sa_uid == -1 || sattr->sa_gid == -1) {
  786.     char parent [MAXPATHNAMELEN];
  787.     struct nfsfattr pattr;      /* attributes of parent */
  788.     char *strrchr();
  789.  
  790.     /* Set up UID and GID defaults from parent inode */
  791.     strcpy (parent, name);
  792.     *strrchr (parent, '\\') = '\0';
  793.     if (!file_getattr (parent, &pattr)) {
  794.         DBGPRT1 (nfsdebug, "no attrs %s", parent);
  795.     }
  796.     else {
  797.         if (sattr->sa_uid == -1)
  798.           sattr->sa_uid = pattr.na_uid;
  799.         if (sattr->sa_gid == -1)
  800.           sattr->sa_uid = pattr.na_gid;
  801.     }
  802.     }
  803. #endif
  804.  
  805.     DBGPRT4 (nfsdebug, "file_create %s <%o> [%ld,%ld]", name,
  806.          (int) sattr->sa_mode, sattr->sa_uid, sattr->sa_gid);
  807.  
  808.     /* check if file already exists */
  809.     if ((handle = open(name, O_CREAT | O_TRUNC, sattribs)) == -1)
  810.       return puterrno (errno);
  811.     close(handle);
  812.  
  813.     /* Add to inode tree */
  814.     if ((node = pntoin(name)) == -1)
  815.       node = addpathtodirtree(name);
  816.  
  817.     /* Set the file's ownership */
  818.     //{
  819.     //    DWORD   time = GetCurrentTime() + 2000;
  820.     //    while( time > GetCurrentTime());
  821.     //}
  822. #if 0
  823.     (void) file_setowner (node, sattr->sa_uid, sattr->sa_gid);
  824. #else
  825.     (void) file_setattr(node, sattr->sa_uid, sattr->sa_gid, sattr->sa_mode);
  826. #endif
  827.     /* Read the file's attributes and return */
  828.     if (! file_readattr(name, fattr)) 
  829.       return NFSERR_IO;   /* just created but not found now! */
  830.  
  831.     return NFS_OK;
  832. }
  833.  
  834. /*
  835.  *  int file_setattr(char *path, long uid, long gid, long perm) --
  836.  *  Returns 0 for success or some error code if an error occurs.
  837.  */
  838. enum nfsstat file_setattr(nodeid, uid, gid, perm)
  839.      u_long nodeid;
  840.      long uid;
  841.      long gid;
  842.      long perm;
  843. {
  844.     int stat;
  845.     char path [MAXPATHNAMELEN];
  846.     struct nfsfattr attr;
  847.  
  848. #ifdef READWITHCACHE
  849.     frdc_clr();
  850. #endif
  851.     if (intopn(nodeid, path) == NULL)   /* get file name */
  852.       return NFSERR_STALE;
  853.     DBGPRT4 (nfsdebug, "file_settr %s <%o> [%ld,%ld]", path,
  854.          (int) perm, uid, gid);
  855.  
  856.     stat = TRUE;
  857.  
  858. #ifdef NTFS
  859.     if( FALSE == NtfsCompDriveType( path, "NTFS"))
  860. #endif
  861.     {
  862. #ifndef DOSAUTH
  863.         if (perm & UPERM_WRITE) {
  864.             stat = setnormalfileattr(path);
  865.             perm = uperm_write;
  866.         }
  867.         else {
  868.             stat = setreadonlyfileattr(path);
  869.             perm = uperm_rdonly;
  870.         }
  871. #endif
  872.     }
  873.  
  874.  
  875.     if (stat == TRUE) {
  876.         DBGPRT2 (nfsdebug, "file_setattr(%s..) %s", path, "point1");
  877.         /* Update cached file attributes */
  878.  
  879. #if 0        
  880.         if (inattrget (nodeid, &attr) != (struct nfsfattr *) NULL) 
  881. #endif
  882.         {
  883.             DBGPRT2 (nfsdebug, "file_setattr(%s..) %s", path, "point2");
  884.             attr.na_mode = perm;
  885.             attr.na_uid  = uid;
  886.             attr.na_gid  = gid;
  887. #ifdef NTFS
  888.             if(TRUE == NtfsCompDriveType( path, "NTFS"))
  889.                 stat = NtfsSetUnixAttrib( path, &attr);
  890. #endif
  891.             if( stat == TRUE)
  892.                 (void) inattrset (nodeid, &attr);
  893.         }
  894.         return NFS_OK;
  895.     } 
  896.     DBGPRT2 (nfsdebug, "file_setattr(%s..) %s", path, "point3");
  897.     return puterrno(errno);
  898. }
  899.  
  900. #if 0
  901. /*
  902.  *  int file_setperm(char *path, long perm) --
  903.  *      Sets file permissions depending on perm.  Perm is of two types,
  904.  *      uperm_write (regular file) or uperm_rdonly (read only).
  905.  *  Returns 0 for success or some error code if an error occurs.
  906.  */
  907. enum nfsstat file_setperm(nodeid, perm)
  908.      u_long nodeid;
  909.      long perm;
  910. {
  911.     int stat;
  912.     char path [MAXPATHNAMELEN];
  913.     struct nfsfattr attr;
  914.  
  915. #ifdef READWITHCACHE
  916.     frdc_clr();
  917. #endif
  918.     if (intopn(nodeid, path) == NULL)   /* get file name */
  919.       return NFSERR_STALE;
  920.  
  921.     stat = TRUE;
  922.  
  923. #ifdef NTFS
  924.     if( FALSE == NtfsCompDriveType( path, "NTFS"))
  925. #endif
  926.     {
  927. #ifndef DOSAUTH
  928.         if (perm & UPERM_WRITE) {
  929.             stat = setnormalfileattr(path);
  930.             perm = uperm_write;
  931.         }
  932.         else {
  933.             stat = setreadonlyfileattr(path);
  934.             perm = uperm_rdonly;
  935.         }
  936. #endif
  937.     }
  938.  
  939.  
  940.     if (stat == TRUE) {
  941.     /* Update cached file attributes */
  942.     if (inattrget (nodeid, &attr) != (struct nfsfattr *) NULL) {
  943.         attr.na_mode = perm;
  944. #ifdef NTFS
  945.         if(TRUE == NtfsCompDriveType( path, "NTFS"))
  946.             stat = NtfsSetUnixAttrib( path, &attr);
  947. #endif
  948.         if( stat == TRUE)
  949.             (void) inattrset (nodeid, &attr);
  950.     }
  951.     return NFS_OK;
  952.     } else
  953.       return puterrno(errno);
  954. }   
  955.         
  956. #endif
  957.  
  958. /*
  959.  *  int file_setsize(u_long nodeid, long size) --
  960.  *      Sets file size.
  961.  *  Returns 0 for success or some error code if an error occurs.
  962.  */
  963. enum nfsstat file_setsize(nodeid, size)
  964.      u_long nodeid;
  965.      long size;
  966. {
  967.     int handle;
  968.     char path [MAXPATHNAMELEN];
  969.     struct nfsfattr attr;
  970.  
  971. #ifdef READWITHCACHE
  972.     frdc_clr();
  973. #endif
  974.     if (intopn(nodeid, path) == NULL)   /* get file name */
  975.       return NFSERR_STALE;
  976.  
  977.     if (size == 0L) {
  978.     if ((handle = open(path, O_CREAT | O_TRUNC, S_IWRITE)) == -1)
  979.         return puterrno (errno);
  980.     close(handle);
  981.  
  982.     /* Update cached file attributes */
  983.     if (inattrget (nodeid, &attr) != (struct nfsfattr *) NULL) {
  984.         attr.na_size = 0;
  985.         (void) inattrset (nodeid, &attr);
  986.     }
  987.     return NFS_OK;
  988.     }
  989.     else
  990.       return NFSERR_IO;
  991. }   
  992.  
  993. /*
  994.  *  int file_settime(u_long nodeid, long secs) --
  995.  *      Sets file time specified by secs (# of seconds since 0000, Jan 1, 1970.
  996.  *  Returns 0 for success or some error code if an error occurs.
  997.  */
  998. enum nfsstat file_settime(nodeid, secs)
  999.      u_long nodeid;
  1000.      long secs;
  1001. {
  1002.     int stat;
  1003.     char path [MAXPATHNAMELEN];
  1004.     struct nfsfattr attr;
  1005.     struct _utimbuf ut;
  1006.  
  1007. #ifdef READWITHCACHE
  1008.     frdc_clr();
  1009. #endif
  1010.     if (intopn(nodeid, path) == NULL)   /* get file name */
  1011.       return NFSERR_STALE;
  1012.  
  1013.     ut.actime = ut.modtime = secs;
  1014.     stat = _utime(path, &ut);
  1015.  
  1016.     if (stat != 0)
  1017.       return puterrno(errno);
  1018.     else {
  1019.     /* Update cached file attributes */
  1020.     if (inattrget (nodeid, &attr) != (struct nfsfattr *) NULL) {
  1021.         attr.na_atime.tv_usec = 0;
  1022.         attr.na_atime.tv_sec = secs;
  1023.         attr.na_mtime = attr.na_atime;
  1024.         attr.na_ctime = attr.na_atime;
  1025.         (void) inattrset (nodeid, &attr);
  1026.     }
  1027.  
  1028.     return NFS_OK;
  1029.     }
  1030. }
  1031.  
  1032. #if 0
  1033. /*
  1034.  *  int file_setowner(u_long nodeid, long uid, long gid) --
  1035.  *      Sets file ownership values.
  1036.  *      This can only set the values in cache, because DOS doesn't
  1037.  *  support an on-disk representation.
  1038.  */
  1039. enum nfsstat file_setowner(nodeid, uid, gid)
  1040.      u_long nodeid;
  1041.      long uid, gid;
  1042. {
  1043.     struct nfsfattr attr;
  1044.     struct nfssattr sattr;
  1045.     char path [MAXPATHNAMELEN];
  1046.  
  1047. #ifdef READWITHCACHE
  1048.     frdc_clr();
  1049. #endif
  1050.     if (intopn (nodeid, path) == NULL)
  1051.       return NFSERR_NOENT;
  1052.     DBGPRT3 (nfsdebug, "Setting owner to [%ld,%ld] %s", uid, gid, path);
  1053.  
  1054.     if (file_getattr (path, &attr)) {
  1055. #ifdef NOVELL
  1056.     if (!(attr.na_mode & UPERM_DIR) && uid != -1) {
  1057.         /* Set up the Scan File Information request block, as defined on */
  1058.         /* page 283 of the Novell API Reference, rev 1.00.       */
  1059.  
  1060.         static struct _sfireq sfireq = /* These are placed in static */
  1061.           {0, 0x0F, -1, -1, 0, 0, 0};  /* memory because code here   */
  1062.         static struct _sfirep sfirep;  /* assumes seg register DS.   */
  1063.         static struct _setfireq setfireq =
  1064.           {0, 0x10, 0};
  1065.         static struct _setfirep setfirep;
  1066.         u_char handle;
  1067.         union REGS regsin, regsout;
  1068.         struct SREGS segregs;
  1069.         int i;
  1070.  
  1071.         if ((handle = novell_GDH (ingetfsid (nodeid))) != 255) {
  1072.         segregs.ds = get_ds();
  1073.         segregs.es = segregs.ds;
  1074.  
  1075.         sfireq.handle = handle;
  1076.         sfireq.pathlen = strlen (path+2);
  1077.         sfireq.len = 6 + sfireq.pathlen;
  1078.         sfirep.len = sizeof (sfirep) -2;
  1079.         strcpy (sfireq.path, path+2);
  1080.  
  1081.         novell_API(0xE3, &sfireq, &sfirep, regsin, ®sout, &segregs);
  1082.         if (regsout.h.al != 0)
  1083.             return NFSERR_IO;
  1084.  
  1085.         /* Set up the Set File Info request block */
  1086.         setfireq.handle = handle;
  1087.         setfireq.pathlen = strlen (path+2);
  1088.         setfireq.len = 4 + sizeof (struct _fileinfo) + sfireq.pathlen;
  1089.         setfirep.len = sizeof (setfirep) -2;
  1090.         strcpy (setfireq.path, path+2);
  1091.         setfireq.info = sfirep.info;
  1092.         setfireq.info.size = 0;
  1093.  
  1094.         /* Look up the Novell user ID */
  1095.         setfireq.info.ownerID = uid - uIDoffset;
  1096.         for (i = 0; i < uIDcount; i++)
  1097.           if (uIDmappings[i].unix_ID == uid + uIDoffset) {
  1098.               setfireq.info.ownerID = uIDmappings[i].Novell_ID;
  1099.               break;
  1100.           }
  1101.  
  1102.         /* Issue the Set File Information request */
  1103.         novell_API(0xE3, &setfireq, &setfirep, regsin, ®sout,
  1104.                &segregs);
  1105.         if (regsout.h.al != 0)
  1106.             return NFSERR_ACCES;
  1107.         }
  1108.     }
  1109. #endif /* NOVELL */
  1110.  
  1111.     /* Update cached file attributes */
  1112.     if (uid != -1)
  1113.       attr.na_uid = uid;
  1114.     if (gid != -1)
  1115.       attr.na_gid = gid;
  1116.  
  1117.         {
  1118. #ifdef NTFS
  1119.             BOOL    stat = TRUE;
  1120.             if(TRUE == NtfsCompDriveType( path, "NTFS"))
  1121.                 stat = NtfsSetUnixAttrib( path, &attr);
  1122.             if( stat != TRUE)
  1123.             {
  1124.                 DBGPRT3 (nfsdebug, "FAILED Setting owner to [%ld,%ld] %s", 
  1125.                     attr.na_uid, attr.na_gid, path);
  1126.             }
  1127.             else
  1128. #endif
  1129.                 (void) inattrset (nodeid, &attr);
  1130.         }
  1131.         return NFS_OK;
  1132.     }
  1133.     else
  1134.         return NFSERR_NOENT;
  1135. }
  1136.  
  1137. #endif
  1138.  
  1139. /*
  1140.  *  int file_unlink(char *name) --
  1141.  *       Removes named file.
  1142.  */
  1143. enum nfsstat file_unlink(name)
  1144.     char *name;
  1145. {
  1146.     u_long node;
  1147.     int    stat;
  1148.  
  1149. #ifdef READWITHCACHE
  1150.     frdc_clr();
  1151. #endif
  1152.     /* Close the file if we still have a handle to it */
  1153.     if ((node = pntoin (name)) != -1)
  1154.     frdc_del (node);
  1155.  
  1156.     /* Reset file attributes */
  1157.     (void) setnormalfileattr(name);
  1158.  
  1159.     /* Call unlink library function to remove the file. */
  1160.     stat = unlink(name);
  1161. DBGPRT3 (nfserr, "unlink %s: stat = %d, len = %d", name, stat, strlen(name));
  1162.  
  1163.     /* Remove the inode associated with the file, if present. */
  1164.     if (stat == 0 && node != -1)
  1165.     inremnode (node);
  1166.     return (stat == 0) ? NFS_OK : puterrno (errno);
  1167. }
  1168.  
  1169.  
  1170. /*
  1171.  *  int file_rename(char *oldname, char *newname) --
  1172.  *       Renames a file
  1173.  */
  1174. enum nfsstat file_rename(oldname, newname)
  1175.     char *oldname, *newname;
  1176. {
  1177.     u_long node;
  1178.     int    err;
  1179.     struct stat buf;
  1180.     enum   nfsstat code;
  1181.  
  1182. #ifdef READWITHCACHE
  1183.     frdc_clr();
  1184. #endif
  1185.     /* Close the file if we still have a handle to it */
  1186.     if ((node = pntoin (oldname)) != -1)
  1187.     frdc_del (node);
  1188.  
  1189.     /* Reset file attributes (e.g., read-only) */
  1190.     (void) setnormalfileattr(oldname);
  1191.  
  1192.     /* Validate the new filename */
  1193.     if ((code = validate_path (newname)) != NFS_OK)
  1194.       return (code);
  1195.  
  1196.     /* Delete destination file if present */
  1197.     if (stat (newname, &buf) == 0) {
  1198.     if (buf.st_mode & S_IFDIR)
  1199.       return NFSERR_ISDIR;
  1200.     if ((code = file_unlink (newname)) != NFS_OK)
  1201.       return code;
  1202.     }
  1203.  
  1204.     /* Call rename library function to rename the file. */
  1205.     err = rename(oldname,newname);
  1206.  
  1207.     /* Update the inode associated with the file, if present. */
  1208.     if (err == 0 && node != -1) {
  1209.     (void) inremnode (node);
  1210.     (void) addpathtodirtree(newname);
  1211.     }
  1212.     return (err == 0) ? NFS_OK : puterrno (errno);
  1213. }
  1214.  
  1215. /*
  1216.  *  enum nfsstat validate_path (char *name) --
  1217.  *       Validate a path name's syntax.  Returns 0 if OK.
  1218.  *       Modifies the path appropriately if NFS_TRUNCATENAMES is set.
  1219.  */
  1220. enum nfsstat validate_path (name)
  1221.      char *name;
  1222. {
  1223.     char *ptr, *ptr2, *strrchr(), *strchr();
  1224.     int i;
  1225.  
  1226. #ifdef READWITHCACHE
  1227.     frdc_clr();
  1228. #endif
  1229.     if ((ptr = strrchr (name, '\\')) == (char *)NULL &&
  1230.     (ptr = strrchr (name, ':')) == (char *)NULL)
  1231.     ptr = name;
  1232.     else
  1233.         ptr++;
  1234.  
  1235.     /* Check validity of characters in final component */
  1236.     for (ptr2 = ptr; *ptr2; ) {
  1237.     if (*ptr2 <= ' ' || (*ptr2 & 0x80) || !inchvalid[*ptr2 - '!'])
  1238.       return NFSERR_INVAL;
  1239.     else
  1240.       ptr2++;
  1241.     }
  1242. #if 1
  1243.     /* PCM 93.04.15 -- Added NTFS long file name check */
  1244.     /* if we're not truncating the names, check to see */
  1245.     /* if the volume is not FAT, and the name length is*/
  1246.     /* less than the allowable */
  1247.     if (!NFS_TRUNCATENAMES) {
  1248.         DWORD maxlen = 0;
  1249.         char root[64];
  1250.         char * p;
  1251.  
  1252.         strncpy(root, name, 63);
  1253.         root[63] = '\0';
  1254.         p=strchr(root, ':');
  1255.         if (p) {
  1256.             *++p = '\\';
  1257.             *++p = '\0';
  1258.         } else {
  1259.             p=strchr(root, '\\');
  1260.             if (p)
  1261.                 *++p = '\0';
  1262.             else
  1263.                 root[0] = '\0';
  1264.         }
  1265.  
  1266.  
  1267.         if( root[0])
  1268.             if(GetVolumeInformation(root, NULL, 0, 0, &maxlen, 
  1269.                     NULL, NULL, 0))
  1270.             {
  1271.             /* FAT systems return 12 -- handle in usual way */
  1272.             if ((maxlen>12)&&(strlen(ptr)<maxlen))
  1273.                 return NFS_OK;
  1274.             }
  1275.     }
  1276. #endif
  1277.     /* Verify there are no more than 8 chars before '.' */
  1278.     if ((i = strcspn (ptr, ".")) > 8) {
  1279.     if (!NFS_TRUNCATENAMES)
  1280.       return NFSERR_NAMETOOLONG;
  1281.     strcpy (ptr + 8, ptr + i);
  1282.     }
  1283.     if ((ptr2 = strchr (ptr, '.')) == (char *)NULL)
  1284.     return NFS_OK;
  1285.     else
  1286.         ptr2++;
  1287.     ptr = ptr2;
  1288.     if (strlen (ptr) > 3) {
  1289.     if (!NFS_TRUNCATENAMES)
  1290.       return NFSERR_NAMETOOLONG;
  1291.     ptr[3] = '\0';
  1292.     }
  1293.     return NFS_OK;
  1294. }
  1295.  
  1296.  
  1297.  
  1298. #ifdef NOVELL
  1299. /*
  1300.  *  u_char novell_GDH (int fsid) --
  1301.  *  Get Novell directory handle for a filesystem.
  1302.  */
  1303. u_char novell_GDH (fsid)
  1304. int fsid;
  1305. {
  1306. union REGS regsin, regsout;
  1307.  
  1308.     /* Get the file system's directory handle */
  1309.     regsin.x.ax = 0xE900;
  1310.     regsin.x.dx = fsid - 1;
  1311.     intdos (®sin, ®sout);
  1312.  
  1313.     /* Return -1 error code if the permanent directory bit is not set or */
  1314.     /* the local-directory bit is set.                       */
  1315.     if ((regsout.h.ah & 0x83) != 1)
  1316.       return 255;
  1317.  
  1318.     return regsout.h.al;
  1319. }
  1320.  
  1321. /*
  1322.  *  void ldnovell (u_long nodeid, char *path, struct nfsfattr *attr) --
  1323.  *  Loads attributes of a Novell network file
  1324.  */
  1325. static bool_t ldnovell (nodeid, path, attr)
  1326.      u_long nodeid;
  1327.      char   *path;
  1328.      struct nfsfattr *attr;
  1329. {
  1330.     FILE *fp, *fopen();
  1331.     int i;
  1332.     int stat;
  1333.     u_char handle;
  1334.     char fcn [10];
  1335.     union REGS regsin, regsout;
  1336.     struct SREGS segregs;
  1337.  
  1338.     if ((handle = novell_GDH (ingetfsid (nodeid))) == 255)
  1339.     return FALSE;
  1340.  
  1341.     /* Initialize the Novell ID mapping table if not set */
  1342.     if (uIDmappings == NULL) {
  1343.     uIDmappings = (struct _uidmap *) malloc (sizeof (struct _uidmap) *
  1344.                         MAXNOVELLID);
  1345.     if (uIDmappings == NULL) {
  1346.         fprintf (stderr, "out of memory\n");
  1347.         abort();
  1348.     }
  1349.     uIDoffset = uIDcount = gID = 0;
  1350.  
  1351.     /* Default protection is 775 */
  1352.     novelldirprot = UPERM_OWNER | UPERM_GROUP | UPERM_READ | UPERM_SEARCH;
  1353.  
  1354.     if ((fp = fopen(IDFILE, "r")) == NULL) {
  1355.         fprintf (stderr, ">>> File %s missing\n", IDFILE);
  1356.     }
  1357.     else {
  1358.         while(fscanf(fp, "%s", fcn) != EOF) {
  1359.         /* Check command line for 'offset', 'group', 'user', */
  1360.         /* 'protection'.                     */
  1361.         if (fcn[0] == 'o')
  1362.             fscanf(fp, "%ld", &uIDoffset);
  1363.         else if (fcn[0] == 'g')
  1364.             fscanf(fp, "%ld", &gID);
  1365.         else if (fcn[0] == 'p')
  1366.             fscanf(fp, "%o", &novelldirprot);
  1367.         else if (fcn[0] == 'u') {
  1368.             char user[20];
  1369.             fscanf(fp, "%s %ld %ld", user,
  1370.                &uIDmappings[uIDcount].unix_ID,
  1371.                &uIDmappings[uIDcount].Novell_ID);
  1372.             if (uIDcount < MAXNOVELLID-1)
  1373.               uIDcount++;
  1374.         }
  1375.         }
  1376.         fclose (fp);
  1377.     }
  1378.     }
  1379.  
  1380.     segregs.ds = get_ds();
  1381.     segregs.es = segregs.ds;
  1382.  
  1383.     if (attr->na_type != NFDIR) {
  1384.     /* Set up the Scan File Information request block, as defined on */
  1385.     /* page 283 of the Novell API Reference, rev 1.00.       */
  1386.  
  1387.     static struct _sfireq sfireq =  /* These are placed in static */
  1388.       {0, 0x0F, -1, -1, 0, 0, 0};   /* memory because code here   */
  1389.     static struct _sfirep sfirep;   /* assumes seg register DS.   */
  1390.  
  1391.     sfireq.handle = handle;
  1392.     sfireq.pathlen = strlen (path);
  1393.     sfireq.len = 6 + sfireq.pathlen;
  1394.     sfirep.len = sizeof (sfirep) -2;
  1395.     strcpy (sfireq.path, path);
  1396.  
  1397.     novell_API(0xE3, &sfireq, &sfirep, regsin, ®sout, &segregs);
  1398.     if (regsout.h.al != 0) {
  1399.         DBGPRT2 (nfsdebug, "%s sfi err %d", path, regsout.h.al);
  1400.         return FALSE;
  1401.     }
  1402.     attr->na_uid = sfirep.info.ownerID;
  1403.     attr->na_gid = gID;
  1404.     }
  1405.     else {
  1406.     /* Special case for directories:  invoke Scan Directory For   */
  1407.     /* Trustees system call, defined on p. 280 of Novell API Ref. */
  1408.  
  1409.     /* Load the protection bits */
  1410.     attr->na_mode = UPERM_DIR | novelldirprot;
  1411. #if 0
  1412.     /* SDFT not supported because Novell allows a directory to be */
  1413.     /* a member of several groups while Unix only attaches one    */
  1414.     /* group ID to the file.  We punt and just return the same    */
  1415.     /* group every time, to avoid confusion.              */
  1416.  
  1417.     static struct _sdftreq sdftreq = {0, 0x0C, 0, 0, 0};
  1418.     static struct _sdftrep sdftrep;
  1419.  
  1420.     sdftreq.handle = handle;
  1421.     sdftreq.pathlen = strlen (path);
  1422.     sdftreq.len = 4 + sdftreq.pathlen;
  1423.     sdftrep.len = sizeof (sdftrep) -2;
  1424.     strcpy (sdftreq.path, path);
  1425.  
  1426.     novell_API (0xE2, &sdftreq, &sdftrep, regsin, ®sout, &segregs);
  1427.     if (regsout.h.al == 0) {
  1428.         attr->na_uid = sdftrep.ownerID;
  1429.     }
  1430.     else
  1431. #endif /* 0 */
  1432.     {
  1433.         /* If SDFT call failed, usually due to access problems, */
  1434.         /* use the Scan Directory Info call.            */
  1435.         static struct _sdireq sdireq = {0, 0x02, 0, 0, 0};
  1436.         static struct _sdirep sdirep;
  1437.  
  1438.         sdireq.handle = handle;
  1439.         sdireq.pathlen = strlen (path);
  1440.         sdireq.len = 5 + sdireq.pathlen;
  1441.         sdirep.len = sizeof (sdirep) -2;
  1442.         strcpy (sdireq.path, path);
  1443.  
  1444.         novell_API (0xE2, &sdireq, &sdirep, regsin, ®sout, &segregs);
  1445.         DBGPRT3 (nfsdebug, "SDIREQ %d: %d %ld", sdireq.handle, regsout.h.al,
  1446.              sdirep.ownerID);
  1447.         if (regsout.h.al != 0)
  1448.           return FALSE;
  1449.         attr->na_uid = sdirep.ownerID;
  1450.         attr->na_gid = gID;
  1451.     }
  1452.     }
  1453.  
  1454.     DBGPRT2 (nfslookup, "%s ID = %ld", path, attr->na_uid);
  1455.  
  1456.     /* Look for ID in mapping table */
  1457.     for (i = 0; i < uIDcount; i++)
  1458.       if (uIDmappings[i].Novell_ID == attr->na_uid) {
  1459.       attr->na_uid = uIDmappings[i].unix_ID;
  1460.       return TRUE;
  1461.       }
  1462.  
  1463.     /* Not found in mapping table:  add the offset and return. */
  1464.     attr->na_uid += uIDoffset;
  1465.     return TRUE;
  1466. }
  1467. #endif /* NOVELL */
  1468.  
  1469.