home *** CD-ROM | disk | FTP | other *** search
/ PDA Software Library / pdasoftwarelib.iso / PSION / COMMS / P3NFS / NFSD / MP_PFS_O.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-16  |  23.9 KB  |  967 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #ifdef __svr4__
  4. #include <stdlib.h>
  5. #include <unistd.h>
  6. #include <string.h>
  7. #endif
  8. #include "nfs_prot.h"
  9. #include "mp.h"
  10.  
  11. static struct device *devices;
  12. struct cache *attrcache;
  13.  
  14. /*
  15.   Nfsd returned NFSERR_STALE if the psion wasn't present, but I didn't like
  16.   it because the kernel returns the same when the nfsd itself is absent
  17.  */
  18. #define NO_PSION    NFSERR_NXIO
  19.  
  20. /* FIXME: Send create attributes */
  21. static struct diropres *
  22. create_it(ca, isdir)
  23.   createargs *ca;
  24.   int isdir;
  25. {
  26.   static struct diropres res;
  27.   p_inode *dirinode = get_num(fh2inode(ca->where.dir.data));
  28.   char *name = dirinode->name;
  29.   fattr *fp;
  30.   p_inode *inode;
  31.  
  32.   if(debug)
  33.     printf("\tcreate: in %s %s (%#o, %d)\n",
  34.         name, ca->where.name, ca->attributes.mode, isdir);
  35.  
  36.   name = build_path(name, ca->where.name);
  37.  
  38.   if(sendop(isdir ? PFS_OP_MKDIR : PFS_OP_CREATE, iso2cp(name), (char *)0, 0))
  39.     {
  40.       res.status = psion_alive ? NFSERR_NAMETOOLONG : NO_PSION;
  41.       return &res;
  42.     }
  43.  
  44.   inode = get_nam(name);
  45.   inode2fh(inode->inode, res.diropres_u.diropres.file.data);
  46.  
  47.   fp = &res.diropres_u.diropres.attributes;
  48.   bzero((char *)fp, sizeof(fp));
  49.   if(isdir)
  50.     {
  51.       fp->type = NFDIR;
  52.       fp->mode = NFSMODE_DIR | 0700;
  53.       fp->nlink = 2;
  54.     }
  55.   else
  56.     {
  57.       fp->type = NFREG;
  58.       fp->mode = NFSMODE_REG | 0600;
  59.       fp->nlink = 1;
  60.     }
  61.  
  62.   fp->uid = root_fattr.uid;
  63.   fp->gid = root_fattr.gid;
  64.   fp->blocksize = BLOCKSIZE;
  65.   fp->fileid = inode->inode;
  66.   fp->atime.seconds = fp->mtime.seconds = fp->ctime.seconds = time((time_t *)0);
  67.   
  68.   res.status = NFS_OK;
  69.  
  70.   rem_cache(&attrcache, dirinode->inode);
  71.   rem_cache(&attrcache, inode->inode);
  72.   add_cache(&attrcache, inode->inode, fp);
  73.   return &res;
  74. }
  75.  
  76. struct diropres *
  77. nfsproc_create_2(ca)
  78.   createargs *ca;
  79. {
  80.   return create_it(ca, 0);
  81. }
  82.  
  83. struct diropres *
  84. nfsproc_mkdir_2(ca)
  85.   createargs *ca;
  86. {
  87.   return create_it(ca, 1);
  88. }
  89.  
  90. static void
  91. pattr2attr(op, fp, fh)
  92.   unsigned char *op, *fh;
  93.   fattr *fp;
  94. {
  95.   bzero((char *)fp, sizeof(*fp));
  96.  
  97.   if(op[2] & (1<<4))
  98.     {
  99.       fp->type   = NFDIR;
  100.       fp->mode   = NFSMODE_DIR | 0700;
  101. /* Damned filesystem.
  102.    We have to count the number of subdirectories on the psion. */
  103.       fp->nlink  = (op[0] | (op[1] << 8)) + 2;
  104.       fp->size   = BLOCKSIZE;
  105.       fp->blocks = 1;
  106.     }
  107.   else
  108.     {
  109.       fp->type   = NFREG;
  110.       fp->mode   = NFSMODE_REG;
  111.       fp->nlink  = 1;
  112.       fp->size   = pstr2long(op+4);
  113.       fp->blocks = (fp->size+BLOCKSIZE-1)/BLOCKSIZE;
  114.  
  115. /* Following flags have to be set in order to let backups work properly */
  116.       if(op[3] & (1<<0))    fp->mode |= 0400; /* File readable (?) */
  117.       if(op[2] & (1<<0))    fp->mode |= 0200; /* File writeable  */
  118.       if(op[3] & (1<<1))    fp->mode |= 0100; /* File executable */
  119.       if(!(op[2] & (1<<1))) fp->mode |= 0004; /* Not Hidden  <-> world read */
  120.       if(op[2] & (1<<2))    fp->mode |= 0002; /* System      <-> world write */
  121.       if(op[2] & (1<<3))    fp->mode |= 0001; /* Volume      <-> world exec */
  122.       if(op[2] & (1<<5))    fp->mode |= 0020; /* Modified    <-> group write */
  123.       if(op[3] & (1<<2))    fp->mode |= 0040; /* Byte        <-> group read */
  124.       if(op[3] & (1<<3))    fp->mode |= 0010; /* Text        <-> group exec */
  125.     }
  126.  
  127.   fp->uid = root_fattr.uid; fp->gid = root_fattr.gid;
  128.   fp->blocksize = BLOCKSIZE;
  129.   fp->fileid = fh2inode((char *)fh);
  130.   fp->rdev = fp->fsid = FID;
  131.   fp->atime.seconds = pstr2long(op+8) - gmtoffset;
  132.   fp->mtime.seconds = fp->ctime.seconds = fp->atime.seconds;
  133. }
  134.  
  135. static int
  136. query_devices()
  137. {
  138.   struct device *dp, *np, **pp;
  139.   unsigned char *sp, *p, namebuf[256];
  140.   int link_count = 2; /* set the root link count */
  141.  
  142.   if(query_cache)
  143.     return 0;
  144.   query_cache = 1;
  145.   for(dp = devices; dp; dp = np)
  146.     {
  147.       np = dp->next;
  148.       free(dp->name); free(dp);
  149.     }
  150.   devices = 0; *namebuf = 0;
  151.   if(sendop(PFS_OP_GETDEVS, namebuf, 0, 0))
  152.     return 1;
  153.   for(pp = &devices; ; pp = &(*pp)->next)
  154.     {
  155.       if(getstr(namebuf))
  156.         return 1;
  157.       if(!*namebuf)
  158.         break;
  159.       link_count++;
  160.       dp = (struct device *)malloc(sizeof(struct device));
  161.       *pp = dp;
  162.       dp->next = 0;
  163.       for(p = sp = cp2iso(namebuf); *p; p++)
  164.         if (isupper(*p))    /* norm@city.ac.uk, SunOS 4.0.2 */
  165.       *p = tolower(*p);
  166.     else if(*p >= 0xc0 && *p <= 0xde) /* Convert ISO8859-1 */
  167.       *p += 0x20;
  168.       dp->name = (char *)strdup(sp);
  169.  
  170.       if(getcount(dp->attrib, 14))
  171.         return 1;
  172.       dp->total = pstr2long((*pp)->attrib+6);
  173.       dp->free  = pstr2long((*pp)->attrib+10);
  174.     }
  175.   root_fattr.nlink = link_count;
  176.   return 0;
  177. }
  178.  
  179. struct attrstat *
  180. nfsproc_getattr_2(fh)
  181.   struct nfs_fh *fh;
  182. {
  183.   static struct attrstat res;
  184.   p_inode *inode = get_num(fh2inode(fh->data));
  185.   fattr *fp = &res.attrstat_u.attributes;
  186.   unsigned char op[12];
  187.   struct cache *cp;
  188.   int l;
  189.  
  190.   if(debug) printf("\tgetattr:'%s',%d\n", inode->name, inode->inode);
  191.   res.status = NFS_OK;
  192.  
  193.   if ((cp = search_cache(attrcache, inode->inode)))
  194.     {
  195.       if(debug) printf("\t\tgetattr: cache hit\n");
  196.       *fp = cp->attr;    /* gotcha, all done */
  197.       return &res;
  198.     }
  199.  
  200.   l = strlen(inode->name);
  201.  
  202.   if(inode->inode == root_fattr.fileid)
  203.     {
  204.       /* It's the root inode */
  205.       if(debug) printf("\t\tgetattr:root inode (%#o)\n", root_fattr.mode);
  206.   
  207.       if(query_devices()) /* root inode is always there */
  208.         root_fattr.nlink = 2;
  209.       *fp = root_fattr;
  210.     }
  211.   else if(l > 4 && !strncmp(inode->name+3, "::", 2) && 
  212.          (l == 5 || (l == 7 && *(inode->name+6) == ':')))
  213.     {
  214.       /* It's a device */
  215.       if(debug) printf("\tgetattr:device\n");
  216.       res.status = NO_PSION;
  217.       if(!query_devices())
  218.         {
  219.       struct device *dp;
  220.  
  221.       for(dp = devices; dp; dp = dp->next)
  222.         if(!strcmp(dp->name, inode->name))
  223.           break;
  224.       if(dp)
  225.         {
  226.           res.status = NFS_OK;
  227.           *fp = root_fattr;
  228.           /* If it's writeable... */
  229.           if(!(dp->attrib[2] == 5 || dp->attrib[2] == 6))
  230.             fp->mode |= 0200; 
  231.           fp->fileid = inode->inode;
  232.           /* FIXME */
  233.           if(!strcmp(inode->name, "rom::"))
  234.         fp->nlink = 2;
  235.           else
  236.             {
  237.           if(sendop(PFS_OP_STATDEV, iso2cp(inode->name), 0, 0) ||
  238.              getcount(op, 12))
  239.             {
  240.               res.status = psion_alive ? NFSERR_NOENT : NO_PSION;
  241.               return &res;
  242.             }
  243.           fp->nlink  = (op[0] | (op[1] << 8)) + 2;
  244.         }
  245.         }
  246.     }
  247.     }
  248.   else
  249.     {
  250.       /* It's a normal file/dir */
  251.  
  252.       if(sendop(PFS_OP_GETATTR, iso2cp(inode->name), 0, 0) || getcount(op, 12))
  253.     {
  254.       res.status = psion_alive ? NFSERR_NOENT : NO_PSION;
  255.       return &res;
  256.     }
  257.       pattr2attr(op, fp, (unsigned char *)fh->data);
  258.     }
  259.  
  260.   add_cache(&attrcache, inode->inode, fp);
  261.  
  262.   return &res;
  263. }
  264.  
  265. struct diropres *
  266. nfsproc_lookup_2(da)
  267.   diropargs *da;
  268. {
  269.   static struct diropres res;
  270.   struct attrstat *gres;
  271.   p_inode *inode = get_num(fh2inode(da->dir.data));
  272.   char *fp = res.diropres_u.diropres.file.data;
  273.  
  274.   if(!inode)
  275.     {
  276.       if(debug) printf("lookup: stale fh\n");
  277.       res.status = NO_PSION;
  278.       return &res;
  279.     }
  280.  
  281.   if(debug)
  282.     printf("\tlookup: in '%s'(%d) searching '%s'\n",
  283.            inode->name, inode->inode, da->name);
  284.  
  285.   if(inode->inode == root_fattr.fileid && !strcmp(da->name, "exit"))
  286.     {
  287.       exiting = 5; /* Lets try it 5 times (10 sec) */
  288.       res.status = NFSERR_EXIST;
  289.       return &res;
  290.     }
  291.   if(inode->inode == root_fattr.fileid && !strcmp(da->name, "debug"))
  292.     {
  293.       debug = (debug+1) & 3;  /* debug level of 0,1,2 & 3 */
  294.       printf("Set debug level to %d\n", debug);
  295.       res.status = NFSERR_EXIST;
  296.       return &res;
  297.     }
  298.  
  299.   if(!strcmp(da->name, "."))
  300.     inode2fh(fh2inode(da->dir.data), fp);
  301.   else if(!strcmp(da->name, ".."))
  302.     inode2fh(getpinode(inode), fp);
  303.   else
  304.     inode2fh(get_nam(build_path(inode->name, da->name))->inode, fp);
  305.  
  306.   gres = nfsproc_getattr_2((struct nfs_fh *)fp);
  307.  
  308.   res.status = gres->status;
  309.   res.diropres_u.diropres.attributes = gres->attrstat_u.attributes;
  310.   return &res;
  311. }
  312.  
  313. #define RA_MAXCOUNT ~0
  314.  
  315. static void
  316. addentry(ra, where, searchinode, inode, name)
  317.   readdirargs *ra;
  318.   entry ***where;
  319.   int inode, *searchinode;
  320.   char *name;
  321. {
  322.   int l, rndup;
  323.  
  324.   if(*searchinode)
  325.     {
  326.       if (*searchinode == inode)
  327.         *searchinode = 0;
  328.       return;
  329.     }
  330.   if (ra->count == RA_MAXCOUNT)
  331.     return;
  332.  
  333.   /* 
  334.    * From ddan@au.stratus.com Wed Feb  8 04:14 MET 1995
  335.    * Modifed in pl7.a by Dan Danz to fix problem of missing files in readdir 
  336.    * 
  337.    * In a shotgun attempt at fixing this, I surmised that perhaps addentry
  338.    * was putting one too many entries in the result, so I increased
  339.    * the number of bytes for each entry by +8  ... my reasoning was that
  340.    * you need to account for the filename pointer and for the cookie int ...
  341.    * but in retrospect, I'm not sure about this reasoning.  HOWEVER, it appears
  342.    * that this fixes the problem.
  343.    * FIXED: See next comment (Rudi)
  344.    */
  345.  
  346.   /*
  347.    * Count the bytes needed for the xdr encoded data. Xdr is trickier than 
  348.    * one (me :-) might think: Xdr converts a string into 
  349.    * length (4 bytes) + data (rounded up to 4 bytes).
  350.    */
  351. #define XDR_UNIT 4
  352.   l = strlen(name);
  353.   if((rndup = l % XDR_UNIT) > 0)
  354.     l += XDR_UNIT-rndup;
  355.   l += XDR_UNIT; /* Length of name */
  356.   l += sizeof(entry);
  357.  
  358.   if(l > ra->count)
  359.     {
  360.       ra->count = RA_MAXCOUNT;
  361.       return;
  362.     }
  363.   ra->count -= l;
  364.  
  365.   **where = (entry *)malloc(sizeof(entry));
  366.   (**where)->fileid = inode;
  367.   (**where)->name = (char *)strdup(name);
  368.   *(int *)(**where)->cookie = inode;
  369.   (**where)->nextentry = 0;
  370.   *where = &(**where)->nextentry;
  371. }
  372.  
  373. struct readdirres *
  374. nfsproc_readdir_2(ra)
  375.   readdirargs *ra;
  376. {
  377.   static readdirres res;
  378.   p_inode *inode = get_num(fh2inode(ra->dir.data));
  379.   entry *centry, *fentry, **cp;
  380.   unsigned char *sp, *p, *bp, buf[256];
  381.   int searchinode;
  382.  
  383.   if(!inode)
  384.     {
  385.       if(debug) printf("readdir: stale fh\n");
  386.       res.status = NO_PSION;
  387.       return &res;
  388.     }
  389.   cp = &res.readdirres_u.reply.entries;
  390.   for(fentry = *cp; fentry; fentry = centry)
  391.     {
  392.       centry = fentry->nextentry;
  393.       free(fentry->name);
  394.       free(fentry);
  395.     }
  396.   *cp = 0; searchinode = *(int *)ra->cookie;
  397.  
  398.   if(debug)
  399.     printf("\treaddir: %s, cookie:%x, count:%d\n",
  400.        inode->name, searchinode, ra->count);
  401.  
  402. /* . & .. */
  403.   addentry(ra, &cp, &searchinode, inode->inode, ".");
  404.   addentry(ra, &cp, &searchinode, getpinode(inode), "..");
  405.  
  406.   if(inode->inode == root_fattr.fileid) /* Root directory */
  407.     {
  408.       struct device *dp;
  409.  
  410.       if(query_devices())
  411.     {
  412.       res.status = NO_PSION;
  413.       return &res;
  414.     }
  415.       for(dp = devices; dp; dp = dp->next)
  416.     addentry(ra, &cp, &searchinode, get_nam(dp->name)->inode, dp->name);
  417.     }
  418.   else
  419.     {
  420.       if(sendop(PFS_OP_READDIR, iso2cp(dirname(inode->name)), 0, 0))
  421.     {
  422.       res.status = psion_alive ? NFSERR_NOENT : NO_PSION;
  423.       return &res;
  424.     }
  425.       for(;;)
  426.     {
  427.       if(getstr(buf))
  428.         {
  429.           res.status = NO_PSION;
  430.           return &res;
  431.         }
  432.       if(!*buf) break;
  433.       for(sp = p = cp2iso(buf); *p; p++)
  434.             if (isupper(*p))    /* norm@city.ac.uk, SunOS 4.0.2 */
  435.           *p = tolower(*p);
  436.         else if(*p >= 0xc0 && *p <= 0xde) /* Convert ISO8859-1 */
  437.           *p += 0x20;
  438.       bp = filname(sp);
  439.       addentry(ra, &cp, &searchinode,
  440.            get_nam(build_path(inode->name, bp))->inode, (char *)bp);
  441.     }
  442.     }
  443.  
  444.   res.readdirres_u.reply.eof = ra->count == RA_MAXCOUNT ? 0 : 1;
  445.   res.status = NFS_OK;
  446.   return &res;
  447. }
  448.  
  449. /* FIXME: mode & time not checked */
  450. struct attrstat *
  451. nfsproc_setattr_2(sa)
  452.   sattrargs *sa;
  453. {
  454.   static struct attrstat res;
  455.   p_inode *inode = get_num(fh2inode(sa->file.data));
  456.   fattr *fp;
  457.  
  458.   if(!inode)
  459.     {
  460.       if(debug) printf("setattr: stale fh\n");
  461.       res.status = NO_PSION;
  462.       return &res;
  463.     }
  464.   if(debug) printf("\tsetattr %s called\n", inode->name);
  465.   res = *nfsproc_getattr_2(&sa->file);
  466.   if(res.status != NFS_OK)
  467.     return &res;
  468.   fp = &res.attrstat_u.attributes;
  469.  
  470.   if(sa->attributes.size != -1 &&
  471.      sa->attributes.size != fp->size &&
  472.      fp->type == NFREG)
  473.     {
  474.       if(debug)
  475.         printf("\t\tsetattr truncating to %d bytes\n", sa->attributes.size);
  476.       if(sa->attributes.size != 0)
  477.         {
  478.       res.status = NFSERR_FBIG;
  479.       return &res;
  480.     }
  481.       if(sendop(PFS_OP_CREATE, iso2cp(inode->name), (char *)0, 0))
  482.     {
  483.       res.status = psion_alive ? NFSERR_ROFS : NO_PSION;
  484.       return &res;
  485.     }
  486.       fp->size = 0;
  487.       rem_cache(&attrcache, inode->inode);
  488.       add_cache(&attrcache, inode->inode, fp);
  489.     }
  490.   return &res;
  491. }
  492.  
  493. static nfsstat *
  494. remove_it(da, isdir)
  495.   diropargs *da;
  496.   int isdir;
  497. {
  498.   static nfsstat res;
  499.   p_inode *inode = get_num(fh2inode(da->dir.data));
  500.  
  501.   if(!inode)
  502.     {
  503.       if(debug) printf("setattr: stale fh\n");
  504.       res = NO_PSION;
  505.       return &res;
  506.     }
  507.   if(debug) printf("\tremove_it: in %s: %s (%d)\n",inode->name,da->name,isdir);
  508.  
  509.   if(sendop(isdir ? PFS_OP_RMDIR : PFS_OP_REMOVE,
  510.             iso2cp(build_path(inode->name, da->name)), 0, 0))
  511.     {
  512.       res = psion_alive ? NFSERR_ACCES : NO_PSION;
  513.       return &res;
  514.     }
  515.   rem_cache(&attrcache, inode->inode);
  516.   res = NFS_OK;
  517.   return &res;
  518. }
  519.  
  520. nfsstat *
  521. nfsproc_remove_2(da)
  522.   diropargs *da;
  523. {
  524.   return remove_it(da, 0);
  525. }
  526.  
  527. nfsstat *
  528. nfsproc_rmdir_2(da)
  529.   diropargs *da;
  530. {
  531.   return remove_it(da, 1);
  532. }
  533.  
  534. nfsstat *
  535. nfsproc_rename_2(ra)
  536.   renameargs *ra;
  537. {
  538.   static nfsstat res;
  539.   p_inode *from = get_num(fh2inode(ra->from.dir.data)),
  540.           *to   = get_num(fh2inode(ra->to.dir.data));
  541.   unsigned char ldata[300], *old, c;
  542.  
  543.   if(!from || !to)
  544.     {
  545.       if(debug) printf("rename: stale fh\n");
  546.       res = NO_PSION;
  547.       return &res;
  548.     }
  549.   strcpy((char *)ldata+1, (char *)iso2cp(build_path(to->name, ra->to.name)));
  550.   *ldata = strlen((char *)ldata+1);
  551.   c = *ldata+1;
  552.   old=iso2cp((unsigned char *)build_path(from->name, ra->from.name));
  553.  
  554.   if(debug) printf("\tRename: %s -> %s\n", old, ldata+1);
  555.   if(sendcmd(PFS_OP_RENAME, old, &c, 1) ||
  556.      senddata(ldata, c))
  557.     {
  558.       res = NO_PSION;
  559.       return &res;
  560.     }
  561.   res = getanswer() ?  NFSERR_ACCES : NFS_OK;
  562.   if(res == NFS_OK)
  563.     {
  564.       /* Preserve inode */
  565.       strcpy((char *)ldata, build_path(to->name, ra->to.name));
  566.       (void)re_nam(build_path(from->name, ra->from.name), ldata);
  567.     }
  568.  
  569.   rem_cache(&attrcache, from->inode);
  570.   rem_cache(&attrcache, to->inode);
  571.   return &res;
  572. }
  573.  
  574. /* ARGSUSED */
  575. struct statfsres *
  576. nfsproc_statfs_2(fh)
  577.   struct nfs_fh *fh;
  578. {
  579.   static statfsres res;
  580.   statfsokres *rp;
  581.   struct device *dp;
  582.  
  583.   if(debug) printf("\tstatfs..\n");
  584.  
  585.   rp = &res.statfsres_u.reply;
  586.   rp->tsize = PBUFSIZE;
  587.   rp->bsize = BLOCKSIZE;
  588.   rp->blocks = rp->bfree = 0;
  589.   res.status = NFS_OK;
  590.  
  591.   if(query_devices())
  592.     {
  593.       /* Allow to mount it whithout the psion attached */
  594.       if(psion_alive)
  595.         return &res; /* res.status = NO_PSION;  Hmm */
  596.     }
  597.   for(dp = devices; dp; dp = dp->next)
  598.     {
  599.       rp->blocks += (dp->total + BLOCKSIZE-1)/BLOCKSIZE;
  600.       rp->bfree += (dp->free + BLOCKSIZE-1)/BLOCKSIZE;
  601.     }
  602.   rp->bavail = rp->bfree;
  603.  
  604.   return &res;
  605. }
  606.  
  607. /*
  608.  * Problem:
  609.  * Since we are slow (Max 2Kbyte/s) and the biods are very impatient,
  610.  * we receive each request (number of biods + 1 for the kernel itself)
  611.  * times, this number can be lower for the last block. :-(
  612.  * Solution: (not the best, probably)
  613.  * Cache the read data. This cache will be invalidated if there are
  614.  * no more requests in the queue for at least XXX seconds.
  615.  * See also write :-(
  616.  */
  617. struct readres *
  618. nfsproc_read_2(ra)
  619.   struct readargs *ra;
  620. {
  621.   static struct readres res;
  622.   static unsigned char rop[NFS_MAXDATA];
  623.   p_inode *inode = get_num(fh2inode(ra->file.data));
  624.   fattr *fp;
  625.   struct cache *cp;
  626.   struct dcache *dcp;
  627.   int len;
  628.   unsigned int  i_crc;
  629.   unsigned char c_crc[2];
  630.  
  631.   if(!inode)
  632.     {
  633.       if(debug) printf("read: stale fh\n");
  634.       res.status = NO_PSION;
  635.       return &res;
  636.     }
  637.  
  638.   if(debug)
  639.     printf("\tread: %s off:%d count:%d\n", inode->name, ra->offset, ra->count);
  640.  
  641.   cp = search_cache(attrcache, inode->inode);
  642.   if(cp && (dcp = search_dcache(cp, ra->offset, ra->count)))
  643.     {
  644.       if(debug) printf("\tread: cache hit\n");
  645.       res.readres_u.reply.attributes = cp->attr;
  646.       bcopy(dcp->data, res.readres_u.reply.data.data_val, ra->count);
  647.       res.readres_u.reply.data.data_len = ra->count;
  648.  
  649.       res.status = NFS_OK;
  650.       return &res;
  651.     }
  652.  
  653.   long2pstr(ra->offset, rop);
  654.   short2pstr(ra->count, rop+4);
  655.   if(sendop(PFS_OP_READ, iso2cp(inode->name), rop, 6) ||
  656.      getcount(rop, 12))
  657.     {
  658.       res.status = psion_alive ? NFSERR_NOENT : NO_PSION;
  659.       return &res;
  660.     }
  661.  
  662.   fp = &res.readres_u.reply.attributes;
  663.   pattr2attr(rop, fp, (unsigned char *)ra->file.data);
  664.   if (cp == 0)
  665.     cp = add_cache(&attrcache, inode->inode, fp);
  666.  
  667.   len = fp->size - ra->offset;
  668.   if(len > ra->count) len = ra->count;
  669.   if(fp->size < ra->offset) len = 0;
  670.   if (debug > 1)
  671.      printf("Read: filesize %d read %d @ %d\n", fp->size, len,ra->offset);
  672.   res.readres_u.reply.data.data_len = len;
  673.   res.readres_u.reply.data.data_val = (char *)rop;
  674.  
  675.   if(getcount(rop, len))
  676.     {
  677.       res.status = NO_PSION;
  678.       return &res;
  679.     }
  680.  
  681.   if(!old_nfsc)
  682.     {
  683.       if(getcount(c_crc, 2)) /* Get CRC */
  684.     {
  685.       res.status = NO_PSION;
  686.       return &res;
  687.     }
  688.       i_crc = c_crc[0] | c_crc[1] << 8;
  689.       if(debug) printf("CRC: got %#x, computed %#x\n",i_crc,docrc16(rop, len));
  690.       if(i_crc != docrc16(rop, len))
  691.     {
  692.       printf("p3nfsd: CRC error.\n");
  693.       res.status = NO_PSION;
  694.       return &res;
  695.     }
  696.     }
  697.  
  698.   if (len)
  699.     {
  700.       dcp = add_dcache(cp, ra->offset, ra->count, rop);
  701.       dcp->written = 1;        /* don't write it back */
  702.     }
  703.  
  704.   res.status = NFS_OK;
  705.   return &res;
  706. }
  707.  
  708.  
  709. /*
  710.  * Returns cachepointer on full hit, 0 on partial or no hit,
  711.  * see below solaris comment
  712.  */
  713.  
  714. static int
  715. addwritecache(cp, doff, dlen, dp)
  716.   struct cache *cp;
  717.   int      doff, dlen;
  718.   unsigned char *dp;
  719. {
  720.   struct dcache *dcp;
  721.   int len, changed, os, oe;
  722.   unsigned char *pd, *pc;
  723.  
  724.   /* 
  725.    * do the cachesearch: we are interested in partial hits, as we don't
  726.    * want to write anything twice (flash ram)
  727.    */
  728.   for(dcp = cp->dcache; dcp; dcp = dcp->next)
  729.     if (doff < dcp->offset + dcp->len && doff + dlen > dcp->offset)
  730.       break;
  731.  
  732.   if(!dcp)
  733.     {
  734.       /* phew, nothing fancy to do */
  735.       add_dcache(cp, doff, dlen, dp);
  736.       return 0;
  737.     }
  738.   
  739.   os = doff > dcp->offset ? doff : dcp->offset;
  740.   oe = doff + dlen < dcp->offset + dcp->len ? doff + dlen : dcp->offset + dcp->len;
  741.   pd = dp + os - doff;
  742.   pc = dcp->data + os - dcp->offset;
  743.   len = oe - os;
  744.  
  745.   changed = 0;
  746.   if(bcmp(pd, pc, len))
  747.     {
  748.       bcopy(pd, pc, len);
  749.       dcp->written = 0;
  750.       changed = 1;
  751.     }
  752.  
  753.   if(doff >= dcp->offset && doff + dlen <= dcp->offset + dcp->len)
  754.     {
  755.       if(debug) printf("\twrite: full cache hit\n");
  756.       return !changed;
  757.     }
  758.  
  759.   if(debug)
  760.     printf("\twrite: partial cache hit (off %d len %d)\n", dcp->offset, dcp->len);
  761.   
  762.   /* Do we have some data below the cached area... */
  763.   if(doff < dcp->offset)
  764.     (void)addwritecache(cp, doff, dcp->offset - doff, dp);
  765.  
  766.   /* ...or some above? */
  767.   len = (doff + dlen) - (dcp->offset + dcp->len);
  768.   if(len > 0)
  769.     (void)addwritecache(cp, dcp->offset + dcp->len, len, dp);
  770.  
  771.   return 0;
  772. }
  773.  
  774.  
  775.  
  776. /*
  777.  * The same problem here as above: we receive numerous requests,
  778.  * not even in a specified order. The only good thing is that each request
  779.  * up to the last is exactly the same size.
  780.  * A new problem:
  781.  * Since I dunno how to seek to a point beyond the end of the file (psion),
  782.  * I can't sopport the exact semantics of write. Such files will never be 
  783.  * written completely. :-(
  784.  *
  785.  * Another dumb solaris (sysv?) problem: if the client is writing 512 byte
  786.  * blocks we receive following write requests:
  787.  * off 0 len 512, off 0 len 1024, off 0 len 1536, ... so on till len 4096,
  788.  * that means 4 times as much data as actually needed.
  789.  * We should check if the block was partially written, and write only the
  790.  * difference
  791.  */
  792. struct attrstat *
  793. nfsproc_write_2(wa)
  794.   writeargs *wa;
  795. {
  796.   static struct attrstat res;
  797.   p_inode *inode = get_num(fh2inode(wa->file.data));
  798.   struct cache *cp;
  799.   struct dcache *dcp;
  800.   fattr *fp;
  801.   unsigned char wop[12], c_crc[2];
  802.   struct attrstat *gres;
  803.   int c,len, dlen, doff;
  804.  
  805.   if(!inode)
  806.     {
  807.       if(debug) printf("write: stale fh\n");
  808.       res.status = NO_PSION;
  809.       return &res;
  810.     }
  811.   if(debug)
  812.     printf("\twrite:%s off:%d l:%d\n",inode->name,wa->offset,wa->data.data_len);
  813.  
  814.   dlen = wa->data.data_len;
  815.   doff = wa->offset;
  816.  
  817.   /* fetch attributes */
  818.   if ((cp = search_cache(attrcache, inode->inode)) == 0)
  819.     {
  820.       gres = nfsproc_getattr_2((struct nfs_fh *)wa->file.data);
  821.       if(gres->status != NFS_OK)
  822.         {
  823.       res.status = gres->status;
  824.       return &res;
  825.     }
  826.       cp = search_cache(attrcache, inode->inode);
  827.       if (!cp) abort();
  828.     }
  829.  
  830.   fp = &cp->attr;
  831.   if(fp->size < doff + dlen)
  832.     fp->size = doff + dlen;
  833.   fp->blocks = (fp->size + (BLOCKSIZE - 1))/ BLOCKSIZE;
  834.   fp->atime.seconds = fp->mtime.seconds = fp->ctime.seconds = time(0);
  835.  
  836.   res.attrstat_u.attributes = *fp;
  837.  
  838.   if(addwritecache(cp, doff, dlen, (unsigned char *)wa->data.data_val))
  839.     {
  840.       res.status = NFS_OK;
  841.       return &res;
  842.     }
  843.  
  844. /* Write out as many blocks from the cache as we can */
  845.   for(;;)
  846.     {
  847.       for(dcp = cp->dcache; dcp; dcp = dcp->next)
  848.         {
  849.       if(debug > 2)
  850.         printf("\t\tCheck: %d=%d,%d,%d>=%d\n",
  851.            inode->inode, cp->inode, dcp->written,
  852.            cp->actual_size, dcp->offset);
  853.       if(!dcp->written && cp->actual_size >= dcp->offset)
  854.         break;
  855.     }
  856.       if(!dcp) /* Can't write any blocks */
  857.         break;
  858.   
  859.       if(debug)
  860.         printf("\twriting off: %d, len: %d, act: %d\n",
  861.                       dcp->offset, dcp->len, cp->actual_size);
  862.       long2pstr(dcp->offset, wop);
  863.       short2pstr(dcp->len, wop+4);
  864.  
  865.       if(sendcmd(PFS_OP_WRITE, iso2cp(inode->name), wop, 6) || 
  866.      senddata(dcp->data, dcp->len))
  867.     {
  868.       if(debug) printf("write: dump failed\n");
  869.       res.status = psion_alive ? NFSERR_NOSPC : NO_PSION;
  870.       return &res;
  871.     }
  872.  
  873.       if(!old_nfsc)
  874.         {
  875.       short2pstr(docrc16(dcp->data, dcp->len), c_crc);
  876.       senddata(c_crc, 2);
  877.         }
  878.  
  879.       if((c = getanswer()) != 0)
  880.     {
  881.       if(debug) printf("Psion write error %d.\n", c);
  882.       res.status = NO_PSION;
  883.       return &res;
  884.     }
  885.       dcp->written = 1;
  886.       len = dcp->offset + dcp->len;
  887.       if(len > cp->actual_size)
  888.         cp->actual_size = len;
  889.       if(debug)
  890.         printf("\twritten: new length: %d\n", cp->actual_size);
  891.     }
  892.     
  893.   if(debug) 
  894.     printf("\twrite -> ISOK (%d, %d %d)\n",
  895.       res.attrstat_u.attributes.size,
  896.       res.attrstat_u.attributes.fileid,
  897.       res.attrstat_u.attributes.fsid);
  898.   res.status = NFS_OK;
  899.   return &res;
  900. }
  901.  
  902. /* Dummy routines */
  903. void *
  904. nfsproc_writecache_2()
  905. {
  906.   static char res;
  907.   if(debug) printf("writecache???\n");
  908.   res = (char)NFSERR_FBIG;
  909.   return &res;
  910. }
  911.  
  912. void *
  913. nfsproc_null_2()
  914. {
  915.   static char res;
  916.   if(debug) printf("null.\n");
  917.   res = (char)NFSERR_FBIG;
  918.   return &res;
  919. }
  920.  
  921. void *
  922. nfsproc_root_2()
  923. {
  924.   static char res;
  925.   if(debug) printf("root????\n");
  926.   res = (char)NFSERR_FBIG;
  927.   return &res;
  928. }
  929.  
  930. /* not possible operations */
  931. /* ARGSUSED */
  932. nfsstat *
  933. nfsproc_link_2(la)
  934.   linkargs *la;
  935. {
  936.   static nfsstat res;
  937.  
  938.   if(debug) printf("link..\n");
  939.   res = NFSERR_ACCES;
  940.   return &res;
  941. }
  942.  
  943.  
  944. /* ARGSUSED */
  945. struct readlinkres *
  946. nfsproc_readlink_2(fh)
  947.   struct nfs_fh *fh;
  948. {
  949.   static readlinkres res;
  950.  
  951.   if(debug) printf("readlink...\n");
  952.   res.status = NFSERR_ACCES;
  953.   return &res;
  954. }
  955.  
  956. /* ARGSUSED */
  957. nfsstat *
  958. nfsproc_symlink_2(sa)
  959.   symlinkargs *sa;
  960. {
  961.   static nfsstat res;
  962.  
  963.   if(debug) printf("symlink..\n");
  964.   res = NFSERR_ACCES;
  965.   return &res;
  966. }
  967.