diff options
Diffstat (limited to 'plpnfsd/mp_pfs_ops.c')
-rw-r--r-- | plpnfsd/mp_pfs_ops.c | 1474 |
1 files changed, 0 insertions, 1474 deletions
diff --git a/plpnfsd/mp_pfs_ops.c b/plpnfsd/mp_pfs_ops.c deleted file mode 100644 index 46310ed..0000000 --- a/plpnfsd/mp_pfs_ops.c +++ /dev/null @@ -1,1474 +0,0 @@ -/* $Id$ - * - * Original version of this file from p3nfsd-5.4 by - * Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) - * - * Modifications for plputils by Fritz Elfert <felfert@to.com> - * - */ -#include "OSdefs.h" -#include <stdio.h> -#include <ctype.h> -#include <pwd.h> -#if defined(__SVR4) || defined(__GLIBC__) || defined(__NetBSD__) -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#endif -#include "nfs_prot.h" -#include "mp.h" -#include "rfsv_api.h" -#include "builtins.h" - -static device *devices; -struct cache *attrcache = NULL; - -long param_read(builtin_node *node, char *buf, unsigned long offset, long len) { - char tmp[10]; - unsigned long val = 0; - - if (!strcmp(node->name, "acache")) - val = cache_keep; - if (!strcmp(node->name, "dcache")) - val = devcache_keep; - if (!strcmp(node->name, "debuglevel")) - val = debug; - sprintf(tmp, "%ld\n", val); - if (offset >= strlen(tmp)) - return 0; - strncpy(buf, &tmp[offset], len); - return strlen(buf); -} - -long param_write(builtin_node *node, char *buf, unsigned long offset, long len) { - unsigned long val; - - if (len > 1 && offset == 0) { - int res = sscanf(buf, "%ld", &val); - if (res == 1) { - if (!strcmp(node->name, "acache")) - cache_keep = val; - if (!strcmp(node->name, "dcache")) - devcache_keep = val; - if (!strcmp(node->name, "debuglevel")) { - if (val != debug) { - if (val > debug) - debug = val; - debuglog("Set debug level to %d\n", val); - debug = val; - } - } - } - } - return len; -} - -long param_getsize(builtin_node *node) { - char tmp[10]; - return param_read(node, tmp, 0, sizeof(tmp)); -} - -long exit_write(builtin_node *node, char *buf, unsigned long offset, long len) { - if (len >= 4 && offset == 0) { - if (!strncmp(buf, "stop", 4)) - exiting = 5; /* Let's try it 5 times (10 sec) */ - } - return len; -} - -long exit_read(builtin_node *node, char *buf, unsigned long offset, long len) { - if (offset > 4) - return 0; - if ((len + offset) > 5) - len = 5 - offset; - strncpy(buf, "----\n", len); - return strlen(buf); -} - -long user_write(builtin_node *node, char *buf, unsigned long offset, long len) { - char tmp[256]; - if (len > 1 && offset == 0) { - char *p; - - if (len > (sizeof(tmp) - 1)) - len = sizeof(tmp) - 1; - strncpy(tmp, buf, len); - debuglog("pwrite: %d\n", len); - tmp[len] = '\0'; - if ((p = strchr(tmp, '\n'))) - *p = '\0'; - set_owner(tmp, 0); - } - return len; -} - -long user_read(builtin_node *node, char *buf, unsigned long offset, long len) { - struct passwd *pw = getpwuid(root_fattr.uid); - char tmp[255]; - - if (pw) - sprintf(tmp, "%s\n", pw->pw_name); - else - sprintf(tmp, "???\n"); - endpwent(); - if (offset >= strlen(tmp)) - return 0; - strncpy(buf, &tmp[offset], len); - return strlen(buf); -} - -long user_getsize(builtin_node *node) { - char tmp[255]; - return user_read(node, tmp, 0, sizeof(tmp)); -} - -static long generic_sattr(builtin_node *p, unsigned long sa, unsigned long da) { - p->attr |= sa; - p->attr &= ~da; - return 0; -} - -long generic_getlinks(builtin_node *node) { - builtin_child *cp = node->childs; - long ncount = 0; - - while (cp) { - if ((cp->node->flags & BF_EXISTS_ALWAYS) || rfsv_isalive()) - ncount++; - cp = cp->next; - } - return ncount; -} - -long generic_getdents(builtin_node *node, dentry **e) { - builtin_child *cp = node->childs; - - while (cp) { - if ((cp->node->flags & BF_EXISTS_ALWAYS) || rfsv_isalive()) { - dentry *tmp = (dentry *)calloc(1, sizeof(dentry)); - if (!tmp) - return -1; - tmp->time = time(0); - tmp->size = cp->node->getsize ? cp->node->getsize(cp->node) : cp->node->size; - tmp->attr = cp->node->attr; - tmp->name = strdup(cp->node->name); - tmp->next = *e; - *e = tmp; - } - cp = cp->next; - } - return 0; -} - -static builtin_node *builtins = NULL; -static void dump_proctree(builtin_node *n); - -static void clear_procs(builtin_child **childs) { - builtin_child **cp = childs; - - debuglog("Before clear_procs\n"); - dump_proctree(builtins); - while (*cp) { - if ((*cp)->node->flags & BF_ISPROCESS) { - builtin_child *tmp = *cp; - *cp = (*cp)->next; - unregister_builtin(tmp->node); - free(tmp); - } else - cp = &((*cp)->next); - } - debuglog("After clear_procs\n"); - dump_proctree(builtins); -} - -static time_t procs_stamp = 0; -static long procs_keep = 10; - -static long proc_getlinks(builtin_node *node) { - builtin_child *cp; - long ncount = 0; - - if ((time(0) - procs_stamp) > procs_keep) { - debuglog("PROCESSLIST\n"); - clear_procs(&node->childs); - rpcs_ps(); - procs_stamp = time(0); - debuglog("After rpcs_ps\n"); - dump_proctree(builtins); - } - cp = node->childs; - while (cp) { - if ((cp->node->flags & BF_EXISTS_ALWAYS) || rfsv_isalive()) - ncount++; - cp = cp->next; - } - return ncount; -} - -static long proc_getdents(builtin_node *node, dentry **e) { - builtin_child *cp = node->childs; - - while (cp) { - if ((cp->node->flags & BF_EXISTS_ALWAYS) || rfsv_isalive()) { - dentry *tmp = (dentry *)calloc(1, sizeof(dentry)); - if (!tmp) - return -1; - tmp->time = time(0); - tmp->size = cp->node->getsize ? cp->node->getsize(cp->node) : cp->node->size; - tmp->attr = cp->node->attr; - tmp->name = strdup(cp->node->name); - tmp->next = *e; - *e = tmp; - } - cp = cp->next; - } - return 0; -} - - -static builtin_node proc_node = { - NULL, NULL, NULL, NULL, "proc", BF_EXISTS_ALWAYS|BF_NOCACHE, PSI_A_DIR, 0, NULL, NULL, NULL, NULL, proc_getlinks, proc_getdents -}; - -static builtin_node fixed_builtins[] = { - { NULL, NULL, NULL, NULL, "owner", 0, PSI_A_READ | PSI_A_RDONLY, 0, rpcs_ownerSize, rpcs_ownerRead, NULL, NULL, NULL, NULL }, - { NULL, NULL, NULL, NULL, "debuglevel", BF_EXISTS_ALWAYS|BF_NOCACHE, PSI_A_READ, 0, param_getsize, param_read, param_write, generic_sattr, NULL, NULL }, - { NULL, NULL, NULL, NULL, "acache", BF_EXISTS_ALWAYS|BF_NOCACHE, PSI_A_READ, 0, param_getsize, param_read, param_write, generic_sattr, NULL, NULL }, - { NULL, NULL, NULL, NULL, "dcache", BF_EXISTS_ALWAYS|BF_NOCACHE, PSI_A_READ, 0, param_getsize, param_read, param_write, generic_sattr, NULL, NULL }, - { NULL, NULL, NULL, NULL, "unixowner", BF_EXISTS_ALWAYS|BF_NOCACHE, PSI_A_READ, 0, user_getsize, user_read, user_write, NULL, NULL, NULL }, - { NULL, NULL, NULL, NULL, "exit", BF_EXISTS_ALWAYS|BF_NOCACHE, PSI_A_READ, 5, NULL, exit_read, exit_write, NULL, NULL, NULL }, -}; -static int num_fixed_builtins = sizeof(fixed_builtins) / sizeof(builtin_node); - -static void dump_proctree(builtin_node *n) { - while (n) { - if (n->name) - debuglog("node@%p, \"%s\"\n", n, n->name); - else - debuglog("node@%p, \"(null)\"\n", n); - if (n->childs) { - builtin_child *c = n->childs; - debuglog("Childs:\n"); - while (c) { - if (c->node) - debuglog(" %s\n", c->node->name ? c->node->name : "(null)"); - c = c->next; - } - } - if (n->parent) - debuglog("Parent: %s\n", n->parent->name); - n = n->next; - } -} - -static int add_child(builtin_child **childs, builtin_node *node) { - builtin_child *newc = malloc(sizeof(builtin_child)); - if (!newc) { - errorlog("Out of memory in add_child %s\n", node->name); - return -1; - } - newc->next = *childs; - newc->node = node; - *childs = newc; - return 0; -} - -static int remove_child(builtin_child **childs, builtin_node *node) { - builtin_child **cp = childs; - - if (debug) - debuglog("remove_child %s\n", node->name); - while (*cp) { - if ((*cp)->node == node) { - builtin_child *tmp = *cp; - *cp = (*cp)->next; - free(tmp); - return 0; - } - cp = &((*cp)->next); - } - return -1; -} - -char *builtin_path(builtin_node *node) { - static char tmp[1024]; - char tmp2[1024]; - - strcpy(tmp, node->name); - node = node->parent; - while (node) { - sprintf(tmp2, "%s\\%s", node->name, tmp); - strcpy(tmp, tmp2); - node = node->parent; - } - return tmp; -} - -int unregister_builtin(builtin_node *node) { - builtin_child *cp = node->childs; - builtin_node **n; - - /** - * Unlink and free childs. - */ - if (debug) - debuglog("unregister_builtin %s\n", node->name); - - while (cp) { - builtin_child *old = cp; - cp->node->parent = 0L; - unregister_builtin(cp->node); - cp = cp->next; - free(old); - } - /** - * Unlink ourselves from parent child list. - */ - if (node->parent) - remove_child(&node->parent->childs, node); - n = &builtins; - while (*n) { - if (*n == node) { - *n = node->next; - break; - } else - n = &(*n)->next; - } - if (node->name) - free(node->name); - if (node->private_data) - free(node->private_data); - free(node); - return 0; -} - -builtin_node *register_builtin(char *parent, builtin_node *node) { - builtin_node *bn; - builtin_node *parent_node = 0L; - - debuglog("register_builtin node=%p\n", node); - if (!node) { - errorlog("register_builtin called with NULL node\n"); - return NULL; - } - if (!node->name) { - errorlog("register_builtin called without name\n"); - return NULL; - } - if (parent) { - debuglog("register_builtin parent: %s\n", parent); - for (bn = builtins; bn; bn = bn->next) { - debuglog("cmp parent: %s %s\n", builtin_path(bn), parent); - if (!strcmp(builtin_path(bn), parent)) { - debuglog("cmp parent found bn=%s\n", bn->name); - break; - } - } - if (!bn) { - errorlog("register_builtin for %s called with nonexistent parent %s\n", node->name, parent); - return NULL; - } - parent_node = bn; - } - bn = malloc(sizeof(builtin_node)); - if (!bn) { - errorlog("out of memory while registering builtin %s\n", node->name); - return NULL; - } - memset(bn, 0, sizeof(builtin_node)); - bn->name = strdup(node->name); - if (!bn->name) { - errorlog("out of memory while registering builtin %s\n", node->name); - free(bn); - return NULL; - } - if (parent_node) - debuglog("register_builtin %s in %s\n", node->name, builtin_path(parent_node)); - else - debuglog("register_builtin %s\n", node->name); - bn->parent = parent_node; - bn->flags = node->flags; - bn->attr = node->attr; - bn->size = node->size; - bn->getsize = node->getsize; - bn->read = node->read; - bn->write = node->write; - bn->sattr = node->sattr; - bn->getlinks = node->getlinks; - bn->getdents = node->getdents; - bn->private_data = node->private_data; - if (parent_node) { - debuglog("Add child %s in %s\n", bn->name, bn->parent->name); - if (add_child(&(parent_node->childs), bn)) { - errorlog("Couldn't add child %s\n", bn->name); - free(bn->name); - free(bn); - return NULL; - } - } - bn->next = builtins; - builtins = bn; - debuglog("After register_builtin\n"); - dump_proctree(builtins); - debuglog("register_builtin new node=%p\n", bn); - return bn; -} - -/* - * nfsd returned NFSERR_STALE if the Psion wasn't present, but I didn't like - * it because the kernel returns the same when the nfsd itself is absent - */ - -#define NO_PSION NFSERR_NXIO - -/* FIXME: Send create attributes */ -static struct diropres * -create_it(createargs *ca, int isdir) -{ - static struct diropres res; - p_inode *dirinode = get_num(fh2inode(ca->where.dir.data)); - char *name = dirinode->name; - fattr *fp; - p_inode *inode; - u_int32_t phandle; - int rfsv_ret; - - debuglog("create: in %s %s (%#o, %d)\n", - name, ca->where.name, ca->attributes.mode, isdir); - - name = build_path(name, ca->where.name); - - if (isdir) - rfsv_ret = rfsv_mkdir(name); - else { - rfsv_ret = rfsv_fcreate(0x200, name, &phandle); - if (rfsv_ret == 0) - rfsv_ret = rfsv_fclose(phandle); - } - if (rfsv_ret) { - res.status = rfsv_isalive() ? NFSERR_NAMETOOLONG : NO_PSION; - return &res; - } - inode = get_nam(name); - inode2fh(inode->inode, res.diropres_u.diropres.file.data); - - fp = &res.diropres_u.diropres.attributes; - bzero((char *) fp, sizeof(fp)); - if (isdir) { - fp->type = NFDIR; - fp->mode = NFSMODE_DIR | 0700; - fp->nlink = 2; - } else { - fp->type = NFREG; - fp->mode = NFSMODE_REG | 0600; - fp->nlink = 1; - } - - fp->uid = root_fattr.uid; - fp->gid = root_fattr.gid; - fp->blocksize = BLOCKSIZE; - fp->fileid = inode->inode; - fp->atime.seconds = fp->mtime.seconds = fp->ctime.seconds = time((time_t *) 0); - - res.status = NFS_OK; - - rem_cache(&attrcache, dirinode->inode); - rem_cache(&attrcache, inode->inode); - if (rfsv_isalive()) - add_cache(&attrcache, inode->inode, fp); - return &res; -} - -struct diropres * -nfsproc_create_2(createargs *ca) -{ - return create_it(ca, 0); -} - -struct diropres * -nfsproc_mkdir_2(createargs *ca) -{ - return create_it(ca, 1); -} - -static void -attr2pattr(long oattr, long nattr, long *psisattr, long *psidattr) -{ - /* - * Following flags have to be set in order to let backups - * work properly - */ - *psisattr = *psidattr = 0; - if ((oattr & 0400) != (nattr & 0400)) { - if (nattr & 0400) /* readable */ - *psisattr |= PSI_A_READ; - else - *psidattr |= PSI_A_READ; - } - if ((oattr & 0200) != (nattr & 0200)) { - if (nattr & 0200) /* readonly */ - *psidattr |= PSI_A_RDONLY; - else - *psisattr |= PSI_A_RDONLY; - } - if ((oattr & 0020) != (nattr & 0020)) { - if (nattr & 0020) /* group-write -> archive */ - *psisattr |= PSI_A_ARCHIVE; - else - *psidattr |= PSI_A_ARCHIVE; - } - if ((oattr & 0004) != (nattr & 0004)) { - if (nattr & 0004) /* Not world-read -> hidden */ - *psidattr |= PSI_A_HIDDEN; - else - *psisattr |= PSI_A_HIDDEN; - } - if ((oattr & 0002) != (nattr & 0002)) { - if (nattr & 0002) /* world-write -> system */ - *psisattr |= PSI_A_SYSTEM; - else - *psidattr |= PSI_A_SYSTEM; - } -} - -static void -pattr2attr(long psiattr, long size, long ftime, fattr *fp, int inode) -{ - bzero((char *) fp, sizeof(*fp)); - - if (psiattr & PSI_A_DIR) { - fp->type = NFDIR; - fp->mode = NFSMODE_DIR | 0700; - /* - * Damned filesystem. - * We have to count the number of subdirectories - * on the psion. - */ - fp->nlink = 0; - fp->size = BLOCKSIZE; - fp->blocks = 1; - } else { - fp->type = NFREG; - fp->mode = NFSMODE_REG; - fp->nlink = 1; - fp->size = size; - fp->blocks = (fp->size + BLOCKSIZE - 1) / BLOCKSIZE; - - /* - * Following flags have to be set in order to let backups - * work properly - */ - if (psiattr & PSI_A_READ) - fp->mode |= 0400; /* File readable (?) */ - if (!(psiattr & PSI_A_RDONLY)) - fp->mode |= 0200; /* File writeable */ - /* fp->mode |= 0100; File executable */ - if (!(psiattr & PSI_A_HIDDEN)) - fp->mode |= 0004; /* Not Hidden <-> world read */ - if (psiattr & PSI_A_SYSTEM) - fp->mode |= 0002; /* System <-> world write */ - if (psiattr & PSI_A_VOLUME) - fp->mode |= 0001; /* Volume <-> world exec */ - if (psiattr & PSI_A_ARCHIVE) - fp->mode |= 0020; /* Modified <-> group write */ - /* fp->mode |= 0040; Byte <-> group read */ - /* fp->mode |= 0010; Text <-> group exec */ - } - - fp->uid = root_fattr.uid; - fp->gid = root_fattr.gid; - fp->blocksize = BLOCKSIZE; - fp->fileid = inode; - fp->rdev = fp->fsid = FID; - fp->atime.seconds = ftime; - fp->mtime.seconds = fp->ctime.seconds = fp->atime.seconds; -} - -static int proc_top = 0; - -static int -query_devices() -{ - device *dp, *np; - int link_count = 2; /* set the root link count */ - - if (!proc_top) { - int i; - if (register_builtin(NULL, &proc_node)) { - for (i = 0; i < num_fixed_builtins; i++) - if (register_builtin(proc_node.name, &fixed_builtins[i])) - proc_top++; - } else - errorlog("Couldn't register /proc\n"); - if (proc_top != num_fixed_builtins) - proc_top = 0; - } - if (query_cache) - return 0; - for (dp = devices; dp; dp = np) { - np = dp->next; - free(dp->name); - free(dp); - } - devices = 0; - debuglog("RFSV drivelist\n"); - if (rfsv_drivelist(&link_count, &devices)) - return 1; - query_cache = 1; - devcache_stamp = time(0); - root_fattr.nlink = link_count + 1; - return 0; -} - -static int -mp_dircount(p_inode *inode, long *count) -{ - dentry *e = NULL; - long ret; - builtin_node *bn; - - *count = 0; - debuglog("dircount: %s\n", inode->name); - for (bn = builtins; bn; bn = bn->next) { - if ((!strcmp(builtin_path(bn), inode->name) && (bn->attr & PSI_A_DIR))) { - if (bn->getlinks) - *count = bn->getlinks(bn); - return 0; - } - } - debuglog("RFSV dir %s\n", inode->name); - if ((ret = rfsv_dir(dirname(inode->name), &e))) - return ret; - while (e) { - fattr fp; - char *bp; - dentry *o; - int ni; - - bp = filname(e->name); - ni = get_nam(build_path(inode->name, bp))->inode; - free(e->name); - if (!search_cache(attrcache, ni)) { - pattr2attr(e->attr, e->size, e->time, &fp, ni); - if (rfsv_isalive()) - add_cache(&attrcache, ni, &fp); - } - o = e; - e = e->next; - free(o); - if (fp.type == NFDIR) - (*count)++; - } - debuglog("count %d\n", *count); - return 0; -} - -struct attrstat * -nfsproc_getattr_2(struct nfs_fh *fh) -{ - static struct attrstat res; - p_inode *inode = get_num(fh2inode(fh->data)); - fattr *fp = &res.attrstat_u.attributes; - struct cache *cp; - long pattr; - long psize; - long ptime; - long dcount; - int builtin = 0; - int l; - - debuglog("getattr: '%s', %d\n", inode->name, inode->inode); - res.status = NFS_OK; - - if ((cp = search_cache(attrcache, inode->inode))) { - debuglog("getattr: cache hit\n"); - *fp = cp->attr; /* gotcha */ - if (fp->nlink > 0) - return &res; - } - l = strlen(inode->name); - - if (inode->inode == root_fattr.fileid) { - /* It's the root inode */ - debuglog("getattr: root inode (%#o)\n", root_fattr.mode); - - if (query_devices()) /* root inode and proc is always there */ - root_fattr.nlink = 3; - *fp = root_fattr; - } else if (l == 2 && inode->name[1] == ':') { - debuglog("getattr: device\n"); - res.status = NO_PSION; - if (!query_devices()) { - device *dp; - - for (dp = devices; dp; dp = dp->next) { - debuglog("cmp '%c', '%s'\n", dp->letter, - inode->name); - if (dp->letter == inode->name[0]) - break; - } - debuglog("device: %s\n", dp ? "exists" : "does not exist"); - if (dp) { - res.status = NFS_OK; - *fp = root_fattr; - /* If it's writeable... */ - if (dp->attrib != 7) - fp->mode |= 0200; - fp->fileid = inode->inode; - if (mp_dircount(inode, &dcount)) { - res.status = rfsv_isalive() ? NFSERR_NOENT : NO_PSION; - return &res; - } - if (fp->nlink != dcount + 2) - fp->mtime.seconds = time(0); - fp->nlink = dcount + 2; - } - } - } else { - builtin_node *bn; - - for (bn = builtins; bn; bn = bn->next) { - if (!strcmp(inode->name, builtin_path(bn))) { - pattr = bn->attr; - if (pattr & PSI_A_DIR) - psize = 0; - else - psize = (bn->getsize) ? bn->getsize(bn) : bn->size; - ptime = time(0); - res.status = NFS_OK; - builtin = 1; - if (bn->flags && BF_NOCACHE) - builtin++; - break; - } - } - - if (!builtin) { - debuglog("getattr: fileordir\n"); - /* It's a normal file/dir */ - debuglog("RFSV getattr %s\n", inode->name); - if (rfsv_getattr(inode->name, &pattr, &psize, &ptime)) { - res.status = rfsv_isalive() ? NFSERR_NOENT : NO_PSION; - return &res; - } - } - pattr2attr(pattr, psize, ptime, fp, fh2inode((char *) fh->data)); - if (fp->type == NFDIR) { - debuglog("%s is a dir\n", inode->name); - if (mp_dircount(inode, &dcount)) { - res.status = rfsv_isalive() ? NFSERR_NOENT : NO_PSION; - return &res; - } - if (fp->nlink != dcount + 2) - fp->mtime.seconds = time(0); - fp->nlink = dcount + 2; - } - } - if (rfsv_isalive() && builtin < 2) - add_cache(&attrcache, inode->inode, fp); - return &res; -} - -struct diropres * -nfsproc_lookup_2(diropargs *da) -{ - static struct diropres res; - struct attrstat *gres; - p_inode *inode = get_num(fh2inode(da->dir.data)); - char *fp = res.diropres_u.diropres.file.data; - - if (!inode) { - debuglog("lookup: stale fh\n"); - res.status = NO_PSION; - return &res; - } - debuglog("lookup: in '%s' (%d) finding '%s'\n", - inode->name, inode->inode, da->name); - if (!strcmp(da->name, ".")) - inode2fh(fh2inode(da->dir.data), fp); - else if (!strcmp(da->name, "..")) - inode2fh(getpinode(inode), fp); - else - inode2fh(get_nam(build_path(inode->name, da->name))->inode, fp); - - gres = nfsproc_getattr_2((struct nfs_fh *) fp); - - res.status = gres->status; - res.diropres_u.diropres.attributes = gres->attrstat_u.attributes; - return &res; -} - -#define RA_MAXCOUNT ~0 - -static void -addentry(readdirargs *ra, entry ***where, int *searchi, int inode, char *name) -{ - int l, rndup; - - if (*searchi) { - if (*searchi == inode) - *searchi = 0; - return; - } - if (ra->count == RA_MAXCOUNT) - return; - - /* - * Count the bytes needed for the xdr encoded data. Xdr is trickier than - * one (me :-) might think: Xdr converts a string into - * length (4 bytes) + data (rounded up to 4 bytes). - */ -#define XDR_UNIT 4 - l = strlen(name); - if ((rndup = l % XDR_UNIT) > 0) - l += XDR_UNIT - rndup; - l += XDR_UNIT; /* Length of name */ - l += sizeof(entry); - - if (l > ra->count) { - ra->count = RA_MAXCOUNT; - return; - } - ra->count -= l; - - **where = (entry *) malloc(sizeof(entry)); - (**where)->fileid = inode; - (**where)->name = (char *) strdup(name); - *(int *) (**where)->cookie = inode; - (**where)->nextentry = 0; - *where = &(**where)->nextentry; -} - -struct readdirres * -nfsproc_readdir_2(readdirargs *ra) -{ - static readdirres res; - p_inode *inode = get_num(fh2inode(ra->dir.data)); - entry *centry, *fentry, **cp; - int searchinode; - - if (!inode) { - debuglog("readdir: stale fh\n"); - res.status = NO_PSION; - return &res; - } - cp = &res.readdirres_u.reply.entries; - for (fentry = *cp; fentry; fentry = centry) { - centry = fentry->nextentry; - free(fentry->name); - free(fentry); - } - *cp = 0; - searchinode = *(int *) ra->cookie; - - debuglog("readdir: %s, cookie:%x, count:%d\n", - inode->name, searchinode, ra->count); - - /* . & .. */ - addentry(ra, &cp, &searchinode, inode->inode, "."); - addentry(ra, &cp, &searchinode, getpinode(inode), ".."); - - if (inode->inode == root_fattr.fileid) { /* Root directory */ - device *dp; - - addentry(ra, &cp, &searchinode, get_nam("/proc")->inode, "proc"); - if (query_devices()) { - res.readdirres_u.reply.eof = ra->count == RA_MAXCOUNT ? 0 : 1; - res.status = NFS_OK; - debuglog("readdir: eof=%d\n", res.readdirres_u.reply.eof); - return &res; - } - for (dp = devices; dp; dp = dp->next) { - char n[3]; - sprintf(n, "%c:", dp->letter); - addentry(ra, &cp, &searchinode, get_nam(dp->name)->inode, n); - } - } else { - builtin_node *bn; - int builtin = 0; - dentry *e = NULL; - debuglog("nfsdir: dir\n"); - - for (bn = builtins; bn ; bn = bn->next) - if (!strcmp(inode->name, builtin_path(bn))) { - if (bn->attr & PSI_A_DIR) { - if (bn->getdents) - bn->getdents(bn, &e); - builtin = 1; - } else { - res.status = NFSERR_NOTDIR; - return &res; - } - } - if (!builtin) { - debuglog("RFSV dir2 %s\n", inode->name); - if (rfsv_dir(dirname(inode->name), &e)) { - res.status = rfsv_isalive() ? NFSERR_NOENT : NO_PSION; - return &res; - } - } - while (e) { - fattr fp; - dentry *o; - int ni; - char *bp; - - bp = filname(e->name); - if (debug > 1) - debuglog(" %s\n", bp); - ni = get_nam(build_path(inode->name, bp))->inode; - addentry(ra, &cp, &searchinode, ni, (char *) bp); - free(e->name); - pattr2attr(e->attr, e->size, e->time, &fp, ni); - if (rfsv_isalive()) - add_cache(&attrcache, ni, &fp); - o = e; - e = e->next; - free(o); - } - } - - res.readdirres_u.reply.eof = ra->count == RA_MAXCOUNT ? 0 : 1; - res.status = NFS_OK; - debuglog("readdir: eof=%d\n", res.readdirres_u.reply.eof); - return &res; -} - -struct attrstat * -nfsproc_setattr_2(sattrargs *sa) -{ - static struct attrstat res; - p_inode *inode = get_num(fh2inode(sa->file.data)); - fattr *fp; - builtin_node *bn; - int builtin = 0; - - if (!inode) { - debuglog("setattr: stale fh\n"); - res.status = NO_PSION; - return &res; - } - debuglog("setattr '%s'\n", inode->name); - res = *nfsproc_getattr_2(&sa->file); - if (res.status != NFS_OK) - return &res; - fp = &res.attrstat_u.attributes; - - for (bn = builtins; bn; bn = bn->next) - if (!strcmp(inode->name, builtin_path(bn))) { - builtin = 1; - break; - } - - if ((fp->type == NFREG) && - (sa->attributes.size != -1) && - (sa->attributes.size != fp->size)) { - debuglog("RFSV setsize %s %d\n", inode->name, sa->attributes.size); - if (builtin) { - if (bn->attr & PSI_A_RDONLY) { - res.status = NFSERR_ACCES; - return &res; - } - } else { - if (rfsv_setsize(inode->name, sa->attributes.size) != 0) { - // FIXME: more different error codes - res.status = rfsv_isalive() ? NFSERR_ROFS : NO_PSION; - return &res; - } - } - fp->size = sa->attributes.size; - rem_cache(&attrcache, inode->inode); - if (rfsv_isalive()) - add_cache(&attrcache, inode->inode, fp); - } - if ((sa->attributes.mtime.seconds != fp->mtime.seconds) && - (sa->attributes.mtime.seconds != -1) && !builtin) { - debuglog("RFSV setmtime %s %d\n", inode->name, sa->attributes.mtime.seconds); - if (rfsv_setmtime(inode->name, sa->attributes.mtime.seconds)) { - res.status = (rfsv_isalive()) ? NFSERR_ACCES : NO_PSION; - return &res; - } - fp->mtime.seconds = fp->atime.seconds = sa->attributes.mtime.seconds; - rem_cache(&attrcache, inode->inode); - if (rfsv_isalive()) - add_cache(&attrcache, inode->inode, fp); - } - if ((sa->attributes.mode != (fp->mode & ~NFSMODE_MASK)) && - (sa->attributes.mode != -1)) { - long psisattr, psidattr; - attr2pattr(sa->attributes.mode, fp->mode, &psisattr, &psidattr); - debuglog("RFSV setattr '%s' %d %d\n", inode->name, psisattr, psidattr); - if (builtin) { - if ((bn->sattr == NULL) || bn->sattr(bn, psisattr, psidattr)) { - res.status = NFSERR_ACCES; - return &res; - } - } else { - if (rfsv_setattr(inode->name, psisattr, psidattr)) { - res.status = (rfsv_isalive()) ? NFSERR_ACCES : NO_PSION; - return &res; - } - } - debuglog("changing mode from %o to %o\n", fp->mode, (fp->mode & NFSMODE_MASK) | sa->attributes.mode); - fp->mode = (fp->mode & NFSMODE_MASK) | sa->attributes.mode; - rem_cache(&attrcache, inode->inode); - if (rfsv_isalive() && !builtin) - add_cache(&attrcache, inode->inode, fp); - } - res.status = NFS_OK; - return &res; -} - -static nfsstat * -remove_it(diropargs *da, int isdir) -{ - static nfsstat res; - p_inode *inode = get_num(fh2inode(da->dir.data)); - long rfsv_res; - - if (!inode) { - debuglog("remove_it: stale fh\n"); - res = NO_PSION; - return &res; - } - debuglog("remove_it: in %s: %s (%d)\n", inode->name, da->name, isdir); - - rem_cache(&attrcache, inode->inode); - if (isdir) { - debuglog("RFSV rmdir %s\n", build_path(inode->name, da->name)); - rfsv_res = rfsv_rmdir(build_path(inode->name, da->name)); - } else { - debuglog("RFSV remove %s\n", build_path(inode->name, da->name)); - rfsv_res = rfsv_remove(build_path(inode->name, da->name)); - } - if (rfsv_res != 0) { - res = rfsv_isalive() ? NFSERR_ACCES : NO_PSION; - return &res; - } - res = NFS_OK; - return &res; -} - -nfsstat * -nfsproc_remove_2(diropargs *da) -{ - return remove_it(da, 0); -} - -nfsstat * -nfsproc_rmdir_2(diropargs *da) -{ - return remove_it(da, 1); -} - -nfsstat * -nfsproc_rename_2(renameargs *ra) -{ - static nfsstat res; - p_inode *from = get_num(fh2inode(ra->from.dir.data)); - p_inode *to = get_num(fh2inode(ra->to.dir.data)); - /* FIXME: Buffer overflow */ - char ldata[300], *old, c; - - if (!from || !to) { - debuglog("rename: stale fh\n"); - res = NO_PSION; - return &res; - } - strcpy(ldata + 1, build_path(to->name, ra->to.name)); - *ldata = strlen(ldata + 1); - c = *ldata + 1; - old = build_path(from->name, ra->from.name); - - res = NFS_OK; - debuglog("RFSV rename %s -> %s\n", old, ldata + 1); - if (rfsv_rename(old, ldata + 1)) { - res = (rfsv_isalive()) ? NFSERR_ACCES : NO_PSION; - return &res; - } - if (res == NFS_OK) { - /* Preserve inode */ - strcpy((char *) ldata, build_path(to->name, ra->to.name)); - (void) re_nam(build_path(from->name, ra->from.name), ldata); - } - rem_cache(&attrcache, from->inode); - rem_cache(&attrcache, to->inode); - return &res; -} - -/* ARGSUSED */ -struct statfsres * -nfsproc_statfs_2(struct nfs_fh *fh) -{ - static statfsres res; - statfsokres *rp; - device *dp; - - debuglog("statfs..\n"); - - rp = &res.statfsres_u.reply; - rp->tsize = PBUFSIZE; - rp->bsize = BLOCKSIZE; - rp->blocks = rp->bfree = 0; - res.status = NFS_OK; - - if (query_devices()) { - /* Allow to mount it without the psion attached */ - if (rfsv_isalive()) - return &res; /* res.status = NO_PSION; Hmm */ - } - for (dp = devices; dp; dp = dp->next) { - rp->blocks += (dp->total + BLOCKSIZE - 1) / BLOCKSIZE; - rp->bfree += (dp->free + BLOCKSIZE - 1) / BLOCKSIZE; - } - rp->bavail = rp->bfree; - - return &res; -} - -/* - * Problem: - * Since we are slow (Max 2Kbyte/s) and the biods are very impatient, - * we receive each request (number of biods + 1 for the kernel itself) - * times, this number can be lower for the last block. :-( - * Solution: (not the best, probably) - * Cache the read data. This cache will be invalidated if there are - * no more requests in the queue for at least XXX seconds. - * See also write :-( - */ -struct readres * -nfsproc_read_2(struct readargs *ra) -{ - static struct readres res; - static unsigned char rop[NFS_MAXDATA]; - p_inode *inode = get_num(fh2inode(ra->file.data)); - fattr *fp; - struct cache *cp; - struct dcache *dcp; - long pattr; - long psize; - long ptime; - int len = 0; - builtin_node *bn; - int builtin = 0; - - if (!inode) { - debuglog("read: stale fh\n"); - res.status = NO_PSION; - return &res; - } - debuglog("read: %s off:%d count:%d\n", inode->name, ra->offset, ra->count); - - cp = search_cache(attrcache, inode->inode); - if (cp && (dcp = search_dcache(cp, ra->offset, ra->count))) { - debuglog("read: dcache hit\n"); - res.readres_u.reply.attributes = cp->attr; - bcopy(dcp->data, res.readres_u.reply.data.data_val, ra->count); - res.readres_u.reply.data.data_len = ra->count; - - res.status = NFS_OK; - return &res; - } - - debuglog("RFSV read %s\n", inode->name); - - for (bn = builtins; bn; bn = bn->next) { - if (!strcmp(inode->name, builtin_path(bn))) { - if (bn->attr & PSI_A_DIR) { - res.status = NFSERR_ISDIR; - return &res; - } - if (bn->read) { - len = bn->read(bn, rop, ra->offset, ra->count); - builtin = 1; - break; - } else { - res.status = NFSERR_IO; - return &res; - } - } - } - - if (!builtin) { - if (rfsv_read(rop, ra->offset, - ra->count, inode->name) < 0) { - res.status = rfsv_isalive() ? NFSERR_NOENT : NO_PSION; - return &res; - } - } - fp = &res.readres_u.reply.attributes; - if (!cp) { - // Problem: if an EPOC process is enlarging the file, we won't recognize it - debuglog("RFSV getattr '%s'\n", inode->name); - if (builtin) { - pattr = bn->attr; - psize = (bn->getsize) ? bn->getsize(bn) : bn->size; - ptime = time(0); - } else - rfsv_getattr(inode->name, &pattr, &psize, &ptime); - pattr2attr(pattr, psize, ptime, fp, fh2inode((char *)ra->file.data)); - cp = add_cache(&attrcache, inode->inode, fp); - } else { - *fp = cp->attr; - } - - len = cp->actual_size - ra->offset; - if (len > ra->count) - len = ra->count; - if (cp->actual_size < ra->offset) - len = 0; - if (debug > 1) - debuglog("Read: filesize %d read %d @ %d\n", cp->actual_size, len, ra->offset); - if (len) { - dcp = add_dcache(cp, ra->offset, ra->count, rop); - dcp->towrite = 0; /* don't write it back */ - } - if (builtin) - rem_cache(&attrcache, inode->inode); - res.readres_u.reply.data.data_len = len; - res.readres_u.reply.data.data_val = (char *) rop; - - res.status = NFS_OK; - return &res; -} - - -/* - * Returns cachepointer on full hit, 0 on partial or no hit, - * see below solaris comment - */ - -static int -addwritecache(struct cache *cp, int doff, int dlen, unsigned char *dp) -{ - struct dcache *dcp; - int len, changed, os, oe; - unsigned char *pd, *pc; - - /* - * do the cachesearch: we are interested in partial hits, as we don't - * want to write anything twice (flash ram) - */ - for (dcp = cp->dcache; dcp; dcp = dcp->next) - if (doff < dcp->offset + dcp->len && doff + dlen > dcp->offset) - break; - - if (!dcp) { - /* phew, nothing fancy to do */ - add_dcache(cp, doff, dlen, dp); - return 0; - } - os = doff > dcp->offset ? doff : dcp->offset; - oe = doff + dlen < dcp->offset + dcp->len ? doff + dlen : dcp->offset + dcp->len; - pd = dp + os - doff; - pc = dcp->data + os - dcp->offset; - len = oe - os; - - changed = 0; - if (bcmp(pd, pc, len)) { - bcopy(pd, pc, len); - dcp->towrite = 1; - changed = 1; - } - if (doff >= dcp->offset && doff + dlen <= dcp->offset + dcp->len) { - debuglog("write: full cache hit\n"); - return !changed; - } - debuglog("write: partial cache hit (off %d len %d)\n", dcp->offset, dcp->len); - - /* Do we have some data below the cached area... */ - if (doff < dcp->offset) - (void) addwritecache(cp, doff, dcp->offset - doff, dp); - - /* ...or some above? */ - len = (doff + dlen) - (dcp->offset + dcp->len); - if (len > 0) - (void) addwritecache(cp, dcp->offset + dcp->len, len, dp + dlen - len); - - return 0; -} - - - -/* - * The same problem here as above: we receive numerous requests, - * not even in a specified order. The only good thing is that each request - * up to the last is exactly the same size. - * A new problem: - * Since I dunno how to seek to a point beyond the end of the file (psion), - * I can't support the exact semantics of write. Such files will never be - * written completely. :-( - * - * Another dumb solaris (sysv?) problem: if the client is writing 512 byte - * blocks we receive following write requests: - * off 0 len 512, off 0 len 1024, off 0 len 1536, ... so on till len 4096, - * that means 4 times as much data as actually needed. - * We should check if the block was partially written, and write only the - * difference - */ -struct attrstat * -nfsproc_write_2(writeargs *wa) -{ - static struct attrstat res; - p_inode *inode = get_num(fh2inode(wa->file.data)); - struct cache *cp; - struct dcache *dcp; - fattr *fp; - struct attrstat *gres; - int len = 0; - int dlen, doff; - builtin_node *bn; - - if (!inode) { - debuglog("write: stale fh\n"); - res.status = NO_PSION; - return &res; - } - debuglog("write:%s off:%d l:%d\n", inode->name, wa->offset, wa->data.data_len); - - dlen = wa->data.data_len; - doff = wa->offset; - - for (bn = builtins; bn ; bn = bn->next) { - if (!strcmp(inode->name, builtin_path(bn))) { - if (bn->attr & PSI_A_DIR) - res.status = NFSERR_ISDIR; - else { - debuglog("builtin write %s %d@%d\n", inode->name, dlen, doff); - if (bn->write) { - int l = bn->write(bn, (unsigned char *)wa->data.data_val, doff, dlen); - res.status = (l == dlen) ? NFS_OK : NFSERR_IO; - } else - res.status = NFSERR_ACCES; - } - return &res; - } - } - /* fetch attributes */ - if ((cp = search_cache(attrcache, inode->inode)) == 0) { - gres = nfsproc_getattr_2((struct nfs_fh *) wa->file.data); - if (gres->status != NFS_OK) { - res.status = gres->status; - return &res; - } - cp = search_cache(attrcache, inode->inode); - if (!cp) { - errorlog("nfsproc_write_2: cache is NULL\n"); - res.status = NFSERR_IO; - return &res; - } - } - fp = &cp->attr; - if (fp->size < doff + dlen) - fp->size = doff + dlen; - fp->blocks = (fp->size + (BLOCKSIZE - 1)) / BLOCKSIZE; - fp->atime.seconds = fp->mtime.seconds = fp->ctime.seconds = time(0); - - res.attrstat_u.attributes = *fp; - - if (addwritecache(cp, doff, dlen, (unsigned char *) wa->data.data_val)) { - res.status = NFS_OK; - return &res; - } - /* Write out as many blocks from the cache as we can */ - for (;;) { - if (debug > 2) - for (dcp = cp->dcache; dcp; dcp = dcp->next) - debuglog("Check: %d=%d,%d,%d>=%d\n", - inode->inode, cp->inode, dcp->towrite, - cp->actual_size, dcp->offset); - for (dcp = cp->dcache; dcp; dcp = dcp->next) - if (dcp->towrite && cp->actual_size >= dcp->offset) - break; - if (!dcp) /* Can't write any blocks */ - break; - - debuglog("writing off: %d, len: %d, act: %d\n", - dcp->offset, dcp->len, cp->actual_size); - - debuglog("RFSV write %s\n", inode->name); - - if (rfsv_write(dcp->data, dcp->offset, dcp->len, inode->name) != dcp->len) { - debuglog("write: dump failed\n"); - res.status = rfsv_isalive() ? NFSERR_NOSPC : NO_PSION; - return &res; - } - dcp->towrite = 0; - len = dcp->offset + dcp->len; - if (len > cp->actual_size) - cp->actual_size = len; - debuglog("written: new length: %d\n", cp->actual_size); - } - - debuglog("write -> ISOK (%d, %d %d)\n", - res.attrstat_u.attributes.size, - res.attrstat_u.attributes.fileid, - res.attrstat_u.attributes.fsid); - res.status = NFS_OK; - return &res; -} - -/* Dummy routines */ -void * -nfsproc_writecache_2() -{ - static char res; - debuglog("writecache???\n"); - res = (char) NFSERR_FBIG; - return (void *) &res; -} - -void * -nfsproc_null_2() -{ - static char res; - debuglog("null (NFS operation)\n"); - res = (char) NFSERR_FBIG; - return (void *) &res; -} - -void * -nfsproc_root_2() -{ - static char res; - debuglog("root????\n"); - res = (char) NFSERR_FBIG; - return (void *) &res; -} - -/* - * Links and symlinks are not supported on Psion - */ - -/* ARGSUSED */ -nfsstat * -nfsproc_link_2(linkargs *la) -{ - static nfsstat res; - - debuglog("link: not supported\n"); - res = NFSERR_ACCES; - return &res; -} - -/* ARGSUSED */ -struct readlinkres * -nfsproc_readlink_2(struct nfs_fh *fh) -{ - static readlinkres res; - - debuglog("readlink: not supported\n"); - res.status = NFSERR_ACCES; - return &res; -} - -/* ARGSUSED */ -nfsstat * -nfsproc_symlink_2(symlinkargs *sa) -{ - static nfsstat res; - - debuglog("symlink: not supported\n"); - res = NFSERR_ACCES; - return &res; -} |