#include "share.h" file files[FILES]; /* dynamic? */ int nfile = FILES; int nmoffset; doput() { int i; for(i = 0; i < nfile; i++) if(files[i].tag == client.tag) break; if(i >= nfile) { error("put: tag 0x%x not found\n", client.tag); client.errno = ENOENT; return; } if(files[i].tag == roottag) /* never toss the root */ return; close(files[i].fd); files[i].fd = -1; files[i].tag = 0; free(files[i].name); } /* real paranoia would check that name and fd still refer to the same file */ doupdate() { int i,f = 0; for(i = 0; i < nfile; i++) if(files[i].tag == client.tag) break; if(i >= nfile) { error("update: tag 0x%x not found\n", client.tag); client.errno = ENOENT; return; } errno = 0; if(client.ta) f++, client.ta += dtime; else client.ta = files[i].stb.st_atime; if(client.tm) f++, client.tm += dtime; else client.tm = files[i].stb.st_mtime; if(f) /* could someone have changed the file name underfoot? */ utime(files[i].name, &client.ta); if(errno) { client.errno = errno; error("update: utime errno %d\n", errno); /* and forget the rest of it */ return; } if(client.mode != files[i].stb.st_mode) { if(!isowner(&files[i].stb)) { /* except for client root, this should never happen */ error("doupdate: client user %d not owner of %s (chmod)\n", client.uid, files[i].name); client.errno = EPERM; return; } if(cray == 1) { /* stupid thing has no fchmod */ chmod(files[i].name, client.mode); if(errno) { error("chmod(%s,0%o) failed %d\n", files[i].name, client.mode, errno); return; } } else { fchmod(files[i].fd, client.mode); if(errno) { error("fchmod(%s,0%o) failed %d\n", files[i].name, client.mode, errno); return; } } } /* refresh the stat? */ } doread() { int i, n; for(i = 0; i < nfile; i++) if(client.tag == files[i].tag) break; if(i >= nfile) { error("doread: tag 0x%x missing\n", client.tag); client.errno = ENOENT; return; } /* permissions check missing here */ /* trust the client, except for unknown users, and our policy on `other' */ /*if(clientuid() == -1 && !otherok) { client.errno = EPERM; return; }*/ /*no point, can't get here */ /* if we're doing read-ahead, here's the spot */ if((files[i].stb.st_mode & S_IFMT) == S_IFDIR) { /* fancy directory handling would go here doreaddir(i); return;*/ } /* now we know that the headers for sndread add up to 16 bytes */ if(files[i].pos != client.offset) { lseek(files[i].fd, client.offset, 0); files[i].pos = client.offset; /* are you sure? */ } if(16 + client.count > inlen) /* sanity */ client.count = inlen - 16; n = read(files[i].fd, inbuf + 16, (int)client.count); if(n < 0) { files[i].pos = (unsigned int)-1; /* can't trust it? */ client.errno = errno; return; } client.resplen = 16 + n; /* read sets it */ files[i].pos += n; } dowrite(p) unsigned char *p; { int i, n; for(i = 0; i < nfile; i++) if(client.tag == files[i].tag) break; if(i >= nfile) { debug("dowrite: tag 0x%x missing\n", client.tag); client.errno = ENOENT; return; } /*if(clientuid() == -1 && !otherok) { client.errno = EPERM; return; }*/ /* no point, can't happen */ if(files[i].flags) { client.errno = EPERM; return; } if(files[i].pos != client.offset) { lseek(files[i].fd, client.offset, 0); files[i].pos = client.offset; } if(24 + client.count > inlen) { client.errno = EFAULT; return; } n = write(files[i].fd, inbuf + 24, (int)client.count); /* secret 24 */ if(n != client.count) { client.errno = errno? errno: EIO; files[i].pos = (unsigned int) -1; /* ??? */ return; } files[i].pos += i; } donami(p, len) unsigned char *p; { int i, offset; unsigned char *s, *t, *bufend; for(i = 0; i < nfile; i++) if(client.tag == files[i].tag) break; if(i >= nfile) { error("nami: tag 0x%x not found\n", client.tag); client.errno = ENOENT; return; } debug("nbnami: tag 0x%x for %d\n", client.tag, i); /* build the new name in nmbuf */ for(s = nmbuf, t = files[i].name; *t; ) *s++ = *t++; *s++ = '/'; nmoffset = s - nmbuf; bufend = s + len; for(t = p; *t && s < bufend; t++) { /* two tests for paranoia */ if(s >= nmbuf + inlen) { fatal("nami overran nmbuf\n"); client.errno = EFAULT; return; } *s++ = *t; } *s = 0; debug("nbnami: nmbuf |%s|\n", nmbuf); /* first write the simple code and then worry about . and .. and null */ if(client.flags == 0) { openit(); return; } switch(client.flags) { default: error("nami: unk flag %d\n", client.flags); client.errno = EINVAL; return; case NI_NXCREAT: /* expects it not to exist */ creatit(); break; case NI_LINK: /* expects it not to exist */ linkit(); break; case NI_MKDIR: /* expects it not to exist */ mkdirit(); break; case NI_RMDIR: /* expects it to exist */ rmdirit(); break; case NI_DEL: /* expects it to exist */ delit(); break; case NI_CREAT: /* doesn't care */ creatit(); break; } } /* are fd and name consistent? (when might they not be?) */ /* this is only called on fstat() or stats of the root */ dostat() { static int t = 0; int i, n; struct stat *x; if(++t % 3 == 1 || t < 3) { i = time(0) - client.ta; /* if(i != dtime) error("client time %d host time %d dtime %d\n", client.ta, time(0), i); */ dtime = i; } for(i = 0; i < nfile; i++) if(client.tag == files[i].tag) break; if(i >= nfile) { error("dostat: tag %d not found\n", client.tag); client.errno = ENOENT; return; } n = fstat(files[i].fd, &files[i].stb); if(n < 0) { /* this is probably a serious error */ error("dostat: returned errno %d %s(%d) %x\n", errno, files[i].name, files[i].fd, files[i].tag); client.errno = errno; return; } x = &files[i].stb; client.ino = x->st_ino; client.dev = hostdev(x->st_dev); client.nlink = x->st_nlink; client.uid = hostuid(x->st_uid); client.gid = hostgid(x->st_gid); client.mode = x->st_mode; /* permission calculation? */ client.size = x->st_size; client.ta = x->st_atime - dtime; client.tm = x->st_mtime - dtime; client.tc = x->st_ctime - dtime; if(cray && client.size >= 0x80000000) client.size = 0x7fffffff; if((client.mode & S_IFMT) != S_IFREG && (client.mode & S_IFMT) != S_IFDIR) client.mode = 0; } /* paranoia suggests checking that fd and name are consistent */ dotrunc() { int i, n; for(i = 0; i < nfile; i++) if(client.tag == files[i].tag) break; if(i >= nfile) { error("trunc: tag %d not found\n", client.tag); client.errno = ENOENT; return; } if(clientuid() == -1 && !otherok) { client.errno = EPERM; return; } n = creat(files[i].name, files[i].stb.st_mode); if(n < 0) { error("dotrunc: creat errno %d %s\n", errno, files[i].name); client.errno = errno; return; } close(n); }