<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf8">
<title>/usr/web/sources/contrib/nemo/trfs.c - Plan 9 from Bell Labs</title>
<!-- THIS FILE IS AUTOMATICALLY GENERATED. -->
<!-- EDIT sources.tr INSTEAD. -->
</meta>
</head>
<body>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;">
<span style="font-size: 10pt"><a href="/plan9/">Plan 9 from Bell Labs</a>&rsquo;s /usr/web/sources/contrib/nemo/trfs.c</span></p>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center><font size=-1>
Copyright © 2009 Alcatel-Lucent.<br />
Distributed under the
<a href="/plan9/license.html">Lucent Public License version 1.02</a>.
<br />
<a href="/plan9/download.html">Download the Plan 9 distribution.</a>
</font>
</center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<table width="100%" cellspacing=0 border=0><tr><td align="center">
<table cellspacing=0 cellpadding=5 bgcolor="#eeeeff"><tr><td align="left">
<pre>
<!-- END HEADER -->
#include &lt;u.h&gt;
#include &lt;libc.h&gt;
#include &lt;fcall.h&gt;
#include &lt;thread.h&gt;
#include &lt;9p.h&gt;


enum {
       Maxmsglen       = IOHDRSZ + 8 * 1024,   // Max message size
       Nnames          = 128,                  // Max # of names in a message
};

#define dprint  if(debug)print

Rune    altspc = L'·';
Rune    altlparen = L'«';
Rune    altrparen = L'»';
Rune    altquote = L'´';
Rune    altamp = L'­';

int     debug;
int     verbose;

uchar   rxbuf[Maxmsglen];
uchar   txbuf[Maxmsglen];
char    statbuf[Maxmsglen];
char    dirbuf[2*Maxmsglen];

Fidpool*fidpool;


static void
usage(void)
{
       fprint(2, "usage: %s [-Dv] [-RUNE] [-s srvfile] [-n addr] servename\n", argv0);
       exits("usage");
}


static ulong
getaux(Fid* fp)
{
       assert(sizeof(ulong) &lt;= sizeof(fp-&gt;aux));
       return (ulong)fp-&gt;aux;
}

static void
setaux(Fid* fp, ulong aux)
{
       assert(sizeof(ulong) &lt;= sizeof(fp-&gt;aux));
       fp-&gt;aux = (void*) aux;
}

static char*
emalloc(int l)
{
       char* r;
       r = malloc(l);
       if (r == nil)
               sysfatal("not enough memory");
       return r;
}

int     nnames;
char*   names[Nnames];

void
cleannames(void)
{
       int i;

       for (i = 0; i &lt; nnames; i++)
               free(names[i]);
       nnames = 0;
}

/* From Plan 9 to Unix */
char*
exportname(char* name)
{
       Rune r;
       int   nr;
       char *uxname;
       char *up;

       if (name == 0 ||
               (utfrune(name, altspc) == 0 &amp;&amp;
                utfrune(name,altlparen) == 0 &amp;&amp;
                utfrune(name,altrparen) == 0 &amp;&amp;
                utfrune(name,altamp) == 0 &amp;&amp;
                utfrune(name,altquote) == 0))
               return name;
       up = uxname = emalloc(strlen(name) + 1);
       names[nnames++] = uxname;
       while(*name != 0){
               nr = chartorune(&amp;r, name);
               if (r == altspc)
                       r = ' ';
               if (r == altlparen)
                       r = '(';
               if (r == altrparen)
                       r = ')';
               if (r == altamp)
                       r = '&amp;';
               if (r == altquote)
                       r = '\'';
               up += runetochar(up, &amp;r);
               name += nr;
       }
       *up = 0;
       return uxname;
}

/* From Unix to Plan 9 */
char*
importname(char* name)
{
       Rune r;
       int  nr;
       char *up;
       char *p9name;

       if (name == 0 ||
          (strchr(name, ' ') == 0 &amp;&amp; strchr(name, '(') == 0 &amp;&amp;
           strchr(name, ')') == 0 &amp;&amp; strchr(name, '&amp;') == 0 &amp;&amp;
           strchr(name, '\'')== 0))
               return name;
       p9name = emalloc(strlen(name) * 3 + 1); // worst case: all blanks + 0
       up = p9name;
       names[nnames++] = p9name;
       while (*name != 0){
               nr = chartorune(&amp;r, name);
               if (r == ' ')
                       r = altspc;
               if (r == '(')
                       r = altlparen;
               if (r == ')')
                       r = altrparen;
               if (r == '&amp;')
                       r = altamp;
               if (r == '\'')
                       r = altquote;
               up += runetochar(up, &amp;r);
               name += nr;
       }
       *up = 0;
       return p9name;
}

static int
isfdir(Fcall* f, Fid **fpp)
{
       Fid*    fp;
       int     r;
       fp = lookupfid(fidpool, f-&gt;fid);
       if (fp == nil)
               return 0;
       r = (fp-&gt;qid.type&amp;QTDIR);
       if (r)
               *fpp = fp;
       else
               closefid(fp);
       return r;
}

static int
getfcall(int fd, Fcall* f)
{
       int r;

       r = read9pmsg(fd, rxbuf, sizeof(rxbuf));
       if (r &lt;= 0)
               return 0;
       if (convM2S(rxbuf, sizeof(rxbuf), f) == 0)
               return -1;
       return 1;
}

static int
putfcall(int fd, Fcall* f)
{
       int n;

       n = convS2M(f, txbuf, sizeof(txbuf));
       if (n == 0)
               return -1;
       if (write(fd, txbuf, n) != n)
               return -1;
       return n;
}

static void
twalk(Fcall* f)
{
       int     i;

       cleannames();
       for (i = 0; i &lt; f-&gt;nwname; i++)
               f-&gt;wname[i] = exportname(f-&gt;wname[i]);
}

static void
tcreate(Fcall* f)
{
       cleannames();
       f-&gt;name = exportname(f-&gt;name);
}


// Dir read is tricky.
// We have to change the user supplied offset to match the sizes
// seen by the server. Sizes seen by client are greater than those
// seen by server since the change from ' ' to '␣' adds 2 bytes.
static void
tread(Fcall* f)
{
       Fid*    fp;

       fp = nil;
       if (!isfdir(f, &amp;fp))
               return;
       f-&gt;count /= 3;       // sizes will grow upon return.
       if (fp == nil)
               sysfatal("can't find fid\n");
       if (f-&gt;offset == 0)
               setaux(fp, 0);
       f-&gt;offset -= getaux(fp);     // cumulative size delta
       closefid(fp);
}

static void
rread(Fcall* f)
{
       ulong   n, rn, nn, delta;
       Dir     d;
       Fid*    fp;

       if (!isfdir(f, &amp;fp))
               return;
       if (f-&gt;count == 0)
               goto done;
       cleannames();
       for (n = nn = 0; n &lt; f-&gt;count; n += rn){
               rn = convM2D((uchar*)f-&gt;data + n, f-&gt;count - n, &amp;d, statbuf);
               if (rn &lt;= BIT16SZ)
                       break;
               d.name = importname(d.name);
               //dprint("⇒ %D\n", &amp;d);
               nn += convD2M(&amp;d, (uchar*)dirbuf + nn, sizeof(dirbuf) - nn);
       }
       delta = nn - n;
       setaux(fp, getaux(fp) + delta);
       f-&gt;count = nn;
       f-&gt;data = dirbuf;
done:
       closefid(fp);
}

static void
twstat(Fcall* f)
{
       Dir     d;

       cleannames();
       if (convM2D(f-&gt;stat, f-&gt;nstat, &amp;d, statbuf) &lt;= BIT16SZ)
               return;
       d.name = exportname(d.name);
       f-&gt;nstat = convD2M(&amp;d, (uchar*)dirbuf, sizeof(dirbuf));
       f-&gt;stat = (uchar*)dirbuf;
       if (statcheck(f-&gt;stat, f-&gt;nstat) &lt; 0)
               dprint("stat fails\n");
}

static void
rstat(Fcall* f)
{
       Dir     d;

       cleannames();
       convM2D(f-&gt;stat, f-&gt;nstat, &amp;d, statbuf);
       d.name = importname(d.name);
       f-&gt;nstat = convD2M(&amp;d, (uchar*)dirbuf, sizeof(dirbuf));
       f-&gt;stat = (uchar*)dirbuf;
       if (statcheck(f-&gt;stat, f-&gt;nstat) &lt; 0)
               dprint("stat fails\n");
}

void
nop(Fid*)
{
}


static void
service(int cfd, int sfd, int dfd)
{
       Fcall   f;
       int     r;
       Fid*    fp;

       fidpool = allocfidpool(nop);
       for(;;){
               fp = nil;
               r = getfcall(cfd, &amp;f);
               if (r &lt;= 0){
                       fprint(dfd, "trfs: getfcall %r\n");
                       break;
               }
               if(verbose)
                       fprint(dfd , "c→s %F\n", &amp;f);
               switch(f.type){
               case Tclunk:
               case Tremove:
                       // BUG in lib9p? removefid leaks fid.
                       // is that what it should do?
                       fp = lookupfid(fidpool, f.fid);
                       if (fp != nil){
                               removefid(fidpool, f.fid);
                               closefid(fp);
                               closefid(fp);
                               fp = nil;
                       }
                       break;
               case Tcreate:
                       tcreate(&amp;f);
                       // and also...
               case Topen:
                       fp = allocfid(fidpool, f.fid);
                       fp-&gt;aux = 0;
                       break;
               case Tread:
                       tread(&amp;f);
                       break;
               case Twalk:
                       twalk(&amp;f);
                       break;
               case Twstat:
                       twstat(&amp;f);
                       break;
               }
               if(verbose &amp;&amp; debug)
                       fprint(dfd , "c→s %F\n", &amp;f);
               if (putfcall(sfd, &amp;f) &lt; 0)
                       fprint(dfd , "can't putfcall: %r\n");


               r = getfcall(sfd, &amp;f);
               if (r &lt;= 0){
                       fprint(dfd, "trfs: 2nd getfcall %r\n");
                       break;
               }
               if (verbose)
                       fprint(dfd, "c←s %F\n", &amp;f);
               switch(f.type){
               case Ropen:
               case Rcreate:
                       fp-&gt;qid = f.qid;
                       break;
               case Rread:
                       rread(&amp;f);
                       break;
               case Rstat:
                       rstat(&amp;f);
                       break;
               }
               if(verbose &amp;&amp; debug)
                       fprint(dfd , "c←s %F\n", &amp;f);
               if (putfcall(cfd, &amp;f) &lt; 0)
                       fprint(dfd , "can't 2n dputfcall: %r\n");
               if (fp != nil)
                       closefid(fp);
       }
}

void
main(int argc, char* argv[])
{
       char*   srv = nil;
       char*   sname = nil;
       char*   addr = nil;
       int     fd;
       int     p[2];

       ARGBEGIN{
       case 'D':
               debug = 1;
               break;
       case 'n':
               addr = EARGF(usage());
               break;
       case 'v':
               verbose = 1;
               break;
       case 's':
               sname = EARGF(usage());
               break;
       default:
               altspc = ARGC();
       }ARGEND;
       if (addr == nil){
               if (argc &lt; 1)
                       usage();
               srv = *argv;
               argc--;
       }
       if (argc &gt; 0)
               usage();
       if (sname == nil)
               sname = (addr != nil) ? addr : "trfs";
       fmtinstall('D', dirfmt);
       fmtinstall('M', dirmodefmt);
       fmtinstall('F', fcallfmt);

       if (addr == nil)
               fd = open(srv, ORDWR);
       else
               fd = dial(netmkaddr(addr, "net", "9fs"), 0, 0, 0);
       if (fd &lt; 0 || pipe(p) &lt; 0)
               sysfatal("can't connect to  server %s: %r\n", (addr?addr:srv));
       if (postfd(sname, p[0]) &lt; 0)
               sysfatal("can't post srv: %r\n");
       rfork(RFNOTEG);
       switch(rfork(RFPROC|RFNOTEG)){
       case 0:
               service(p[1], fd, 2);
               break;
       case -1:
               sysfatal("can't fork server: %r\n");
               break;
       }
       exits(nil);
}
<!-- BEGIN TAIL -->
</pre>
</td></tr></table>
</td></tr></table>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;">
<span style="font-size: 10pt"></span></p>
<p style="margin-top: 0; margin-bottom: 0.50in"></p>
<p style="margin-top: 0; margin-bottom: 0.33in"></p>
<center><table border="0"><tr>
<td valign="middle"><a href="http://www.alcatel-lucent.com/"><img border="0" src="/plan9/img/logo_ft.gif" alt="Bell Labs" />
</a></td>
<td valign="middle"><a href="http://www.opensource.org"><img border="0" alt="OSI certified" src="/plan9/img/osi-certified-60x50.gif" />
</a></td>
<td><img style="padding-right: 45px;" alt="Powered by Plan 9" src="/plan9/img/power36.gif" />
</td>
</tr></table></center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center>
<span style="font-size: 10pt">(<a href="/plan9/">Return to Plan 9 Home Page</a>)</span>
</center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center><font size=-1>
<span style="font-size: 10pt"><a href="http://www.lucent.com/copyright.html">Copyright</a></span>
<span style="font-size: 10pt">© 2009 Alcatel-Lucent.</span>
<span style="font-size: 10pt">All Rights Reserved.</span>
<br />
<span style="font-size: 10pt">Comments to</span>
<span style="font-size: 10pt"><a href="mailto:[email protected]">[email protected]</a>.</span>
</font></center>
</body>
</html>