22 Maxpath = 2+2+Segsize-8,
25 typedef struct Tfile Tfile;
29 uchar addr[IPaddrlen];
37 uchar ipaddr[IPaddrlen];
42 tfileget(uchar *addr, char *path)
47 for(f = files; f; f = f->next){
48 if(memcmp(addr, f->addr, IPaddrlen) == 0 && strcmp(path, f->path) == 0){
53 f = emalloc9p(sizeof *f);
54 memset(f, 0, sizeof(*f));
55 ipmove(f->addr, addr);
56 strncpy(f->path, path, Maxpath-1);
71 if(f==nil || decref(f))
77 for(pp = &files; *pp; pp = &(*pp)->next){
98 tfilestat(Req *r, char *path, vlong length)
100 memset(&r->d, 0, sizeof(r->d));
101 r->d.uid = estrdup9p("tftp");
102 r->d.gid = estrdup9p("tftp");
103 r->d.name = estrdup9p(basename(path));
104 r->d.atime = r->d.mtime = time0;
105 r->d.length = length;
106 r->d.qid.path = r->fid->qid.path;
107 if(r->fid->qid.path & Qdata){
111 r->d.qid.type = QTDIR;
112 r->d.mode = DMDIR|0555;
118 catch(void *, char *msg)
120 if(strstr(msg, "alarm"))
126 filereq(uchar *buf, char *path)
131 hnputs(buf, Tftp_READ);
135 /* hack: remove the trailing dot */
142 memcpy(p, "octet", 6);
150 int fd, cfd, last, block, seq, n, ndata;
151 char *err, adir[40], buf[256];
159 uchar buf[2+2+Segsize+1];
171 if((c = f->c) == nil)
174 threadsetname("%s", f->path);
176 snprint(buf, sizeof(buf), "%s/udp!*!0", net);
177 if((cfd = announce(buf, adir)) < 0){
178 err = "announce: %r";
181 if(write(cfd, "headers", 7) < 0){
182 err = "write ctl: %r";
185 strcat(adir, "/data");
186 if((fd = open(adir, ORDWR)) < 0){
191 n = filereq(msg.buf, f->path);
192 ipmove(msg.raddr, f->addr);
193 hnputs(msg.rport, TftpPort);
194 if(write(fd, &msg, sizeof(Udphdr) + n) < 0){
195 err = "send read request: %r";
205 if((n = read(fd, &msg, sizeof(Udphdr) + sizeof(msg.buf)-1)) < 0){
206 err = "receive response: %r";
213 switch(nhgets(msg.buf)){
215 werrstr("%s", (char*)msg.buf+4);
222 block = nhgets(msg.buf+2);
225 hnputs(msg.buf, Tftp_ACK);
226 if(write(fd, &msg, sizeof(Udphdr) + 4) < 0){
227 err = "send acknowledge: %r";
236 data = erealloc9p(data, ndata + n);
237 memcpy(data + ndata, msg.buf+4, n);
240 rloop: /* hanlde read request while downloading */
241 if((r != nil) && (r->ifcall.type == Tread) && (r->ifcall.offset < ndata)){
242 readbuf(r, data, ndata);
246 if((r == nil) && (nbrecv(c, &r) == 1)){
266 while((r != nil) || (r = recvp(c))){
268 snprint(buf, sizeof(buf), err);
271 switch(r->ifcall.type){
273 readbuf(r, data, ndata);
277 tfilestat(r, f->path, ndata);
280 respond(r, "bug in fs");
295 if(r->ifcall.aname && r->ifcall.aname[0]){
296 uchar addr[IPaddrlen];
298 if(parseip(addr, r->ifcall.aname) == -1){
299 respond(r, "bad ip specified");
302 f = tfileget(addr, "/");
304 if(ipcmp(ipaddr, IPnoaddr) == 0){
305 respond(r, "no ipaddr specified");
308 f = tfileget(ipaddr, "/");
311 r->fid->qid.type = QTDIR;
312 r->fid->qid.path = f->id<<1;
313 r->fid->qid.vers = 0;
314 r->ofcall.qid = r->fid->qid;
319 fswalk1(Fid *fid, char *name, Qid *qid)
325 t = smprint("%s/%s", f->path, name);
326 f = tfileget(f->addr, cleanname(t));
328 tfileput(fid->aux); fid->aux = f;
329 fid->qid.type = QTDIR;
330 fid->qid.path = f->id<<1;
333 * a dot in the path means the path element is not
334 * a directory. to force download of files containing
335 * no dot, a trailing dot can be appended that will
336 * be stripped out in the tftp read request.
338 if(strchr(f->path, '.') != nil){
340 fid->qid.path |= Qdata;
349 fsclone(Fid *oldfid, Fid *newfid)
360 fsdestroyfid(Fid *fid)
371 m = r->ifcall.mode & 3;
372 if(m != OREAD && m != OEXEC){
373 respond(r, "permission denied");
386 f->c = chancreate(sizeof(r), 0);
387 proccreate(download, f, 16*1024);
395 if(r->fid->qid.path & Qdata){
405 if(r->fid->qid.path & Qdata){
408 tfilestat(r, ((Tfile*)r->fid->aux)->path, 0);
415 .destroyfid= fsdestroyfid,
426 fprint(2, "usage: tftpfs [-D] [-s srvname] [-m mtpt] [-x net] [ipaddr]\n");
427 threadexitsall("usage");
431 threadmain(int argc, char **argv)
434 char *mtpt = "/n/tftp";
438 ipmove(ipaddr, IPnoaddr);
445 srvname = EARGF(usage());
449 mtpt = EARGF(usage());
452 setnetmtpt(net, sizeof net, EARGF(usage()));
462 if(parseip(ipaddr, *argv) == -1)
469 if(srvname==nil && mtpt==nil)
472 threadpostmountsrv(&fs, srvname, mtpt, MREPL|MCREATE);