/* * nfs_read_req - Read File on NFS Server */ static int nfs_read_req(struct file_priv *priv, int offset, int readlen) { uint32_t data[1024]; uint32_t *p; uint32_t *filedata; int len; int ret; int rlen; p = &(data[0]); p = rpc_add_credentials(p); memcpy (p, priv->filefh, NFS_FHSIZE); p += (NFS_FHSIZE / 4); *p++ = htonl(offset); *p++ = htonl(readlen); *p++ = 0; len = p - &(data[0]); ret = rpc_req(priv->npriv, PROG_NFS, NFS_READ, data, len); if (ret) return ret; filedata = (uint32_t *)(nfs_packet + sizeof(struct rpc_reply)); rlen = ntohl(net_read_uint32(filedata + 18)); kfifo_put(priv->fifo, (char *)(filedata + 19), rlen); return 0; }
/************************************************************************** NFS_READ - Read File on NFS Server **************************************************************************/ static int nfs_read(int server, int port, char *fh, int offset, int len, int sport) { struct rpc_t buf, *rpc; unsigned long id; int retries; long *p; static int tokens=0; /* * Try to implement something similar to a window protocol in * terms of response to losses. On successful receive, increment * the number of tokens by 1 (cap at 256). On failure, halve it. * When the number of tokens is >= 2, use a very short timeout. */ id = rpc_id++; buf.u.call.id = htonl(id); buf.u.call.type = htonl(MSG_CALL); buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */ buf.u.call.prog = htonl(PROG_NFS); buf.u.call.vers = htonl(2); /* nfsd is version 2 */ buf.u.call.proc = htonl(NFS_READ); p = rpc_add_credentials((long *)buf.u.call.data); memcpy(p, fh, NFS_FHSIZE); p += NFS_FHSIZE / 4; *p++ = htonl(offset); *p++ = htonl(len); *p++ = 0; /* unused parameter */ for (retries = 0; retries < MAX_RPC_RETRIES; retries++) { long timeout = rfc2131_sleep_interval(TIMEOUT, retries); if (tokens >= 2) timeout = TICKS_PER_SEC/2; udp_transmit(arptable[server].ipaddr.s_addr, sport, port, (char *)p - (char *)&buf, &buf); if (await_reply(await_rpc, sport, &id, timeout)) { if (tokens < 256) tokens++; rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; if (rpc->u.reply.rstatus || rpc->u.reply.verifier || rpc->u.reply.astatus || rpc->u.reply.data[0]) { rpc_printerror(rpc); if (rpc->u.reply.rstatus) { /* RPC failed, no verifier, data[0] */ return -9999; } if (rpc->u.reply.astatus) { /* RPC couldn't decode parameters */ return -9998; } return -ntohl(rpc->u.reply.data[0]); } else { return 0; } } else tokens >>= 1; } return -1; }
/************************************************************************** NFS_LOOKUP - Lookup Pathname **************************************************************************/ static void nfs_lookup_req(char *fname) { uint32_t data[1024]; uint32_t *p; int len; int fnamelen; fnamelen = strlen(fname); p = &(data[0]); p = (uint32_t *)rpc_add_credentials((long *)p); memcpy(p, dirfh, NFS_FHSIZE); p += (NFS_FHSIZE / 4); *p++ = htonl(fnamelen); if (fnamelen & 3) *(p + fnamelen / 4) = 0; memcpy(p, fname, fnamelen); p += (fnamelen + 3) / 4; len = (uint32_t *)p - (uint32_t *)&(data[0]); rpc_req(PROG_NFS, NFS_LOOKUP, data, len); }
static void *nfs_readdirattr_req(struct file_priv *priv, int *plen, uint32_t cookie) { uint32_t data[1024]; uint32_t *p; int len; int ret; void *buf; p = &(data[0]); p = rpc_add_credentials(p); memcpy(p, priv->filefh, NFS_FHSIZE); p += (NFS_FHSIZE / 4); *p++ = htonl(cookie); /* cookie */ *p++ = htonl(1024); /* count */ *p++ = 0; len = p - &(data[0]); ret = rpc_req(priv->npriv, PROG_NFS, NFS_READDIR, data, len); if (ret) return NULL; *plen = nfs_len - sizeof(struct rpc_reply) + 4; buf = xzalloc(*plen); memcpy(buf, nfs_packet + sizeof(struct rpc_reply) + 4, *plen); return buf; }
static int nfs_attr_req(struct file_priv *priv, struct stat *s) { uint32_t data[1024]; uint32_t *p; int len; int ret; struct fattr *fattr; uint32_t type; p = &(data[0]); p = rpc_add_credentials(p); memcpy(p, priv->filefh, NFS_FHSIZE); p += (NFS_FHSIZE / 4); *p++ = 0; len = p - &(data[0]); ret = rpc_req(priv->npriv, PROG_NFS, NFS_GETATTR, data, len); if (ret) return ret; fattr = nfs_packet + sizeof(struct rpc_reply) + 4; type = ntohl(net_read_uint32(&fattr->type)); s->st_size = ntohl(net_read_uint32(&fattr->size)); s->st_mode = ntohl(net_read_uint32(&fattr->mode)); return 0; }
/* * nfs_lookup_req - Lookup Pathname */ static int nfs_lookup_req(struct file_priv *priv, const char *filename, int fnamelen) { uint32_t data[1024]; uint32_t *p; int len; int ret; p = &(data[0]); p = rpc_add_credentials(p); memcpy(p, priv->filefh, NFS_FHSIZE); p += (NFS_FHSIZE / 4); *p++ = htonl(fnamelen); if (fnamelen & 3) *(p + fnamelen / 4) = 0; memcpy(p, filename, fnamelen); p += (fnamelen + 3) / 4; len = p - &(data[0]); ret = rpc_req(priv->npriv, PROG_NFS, NFS_LOOKUP, data, len); if (ret) return ret; memcpy(priv->filefh, nfs_packet + sizeof(struct rpc_reply) + 4, NFS_FHSIZE); return 0; }
/* * nfs_mount_req - Mount an NFS Filesystem */ static int nfs_mount_req(struct nfs_priv *npriv) { uint32_t data[1024]; uint32_t *p; int len; int pathlen; int ret; pathlen = strlen(npriv->path); debug("%s: %s\n", __func__, npriv->path); p = &(data[0]); p = rpc_add_credentials(p); *p++ = htonl(pathlen); if (pathlen & 3) *(p + pathlen / 4) = 0; memcpy (p, npriv->path, pathlen); p += (pathlen + 3) / 4; len = p - &(data[0]); ret = rpc_req(npriv, PROG_MOUNT, MOUNT_ADDENTRY, data, len); if (ret) return ret; memcpy(npriv->rootfh, nfs_packet + sizeof(struct rpc_reply) + 4, NFS_FHSIZE); return 0; }
/************************************************************************** NFS_LOOKUP - Lookup Pathname **************************************************************************/ static int nfs_lookup(int server, int port, char *fh, char *path, char *nfh, int sport) { struct rpc_t buf, *rpc; unsigned long id; long *p; int retries; int pathlen = strlen(path); id = rpc_id++; buf.u.call.id = htonl(id); buf.u.call.type = htonl(MSG_CALL); buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */ buf.u.call.prog = htonl(PROG_NFS); buf.u.call.vers = htonl(2); /* nfsd is version 2 */ buf.u.call.proc = htonl(NFS_LOOKUP); p = rpc_add_credentials((long *)buf.u.call.data); memcpy(p, fh, NFS_FHSIZE); p += (NFS_FHSIZE / 4); *p++ = htonl(pathlen); if (pathlen & 3) { *(p + pathlen / 4) = 0; /* add zero padding */ } memcpy(p, path, pathlen); p += (pathlen + 3) / 4; for (retries = 0; retries < MAX_RPC_RETRIES; retries++) { long timeout = rfc2131_sleep_interval(TIMEOUT, retries); udp_transmit(arptable[server].ipaddr.s_addr, sport, port, (char *)p - (char *)&buf, &buf); if (await_reply(await_rpc, sport, &id, timeout)) { rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; if (rpc->u.reply.rstatus || rpc->u.reply.verifier || rpc->u.reply.astatus || rpc->u.reply.data[0]) { rpc_printerror(rpc); if (rpc->u.reply.rstatus) { /* RPC failed, no verifier, data[0] */ return -9999; } if (rpc->u.reply.astatus) { /* RPC couldn't decode parameters */ return -9998; } return -ntohl(rpc->u.reply.data[0]); } else { memcpy(nfh, rpc->u.reply.data + 1, NFS_FHSIZE); return 0; } } } return -1; }
/*************************************************************************** * NFS_READLINK (AH 2003-07-14) * This procedure is called when read of the first block fails - * this probably happens when it's a directory or a symlink * In case of successful readlink(), the dirname is manipulated, * so that inside the nfs() function a recursion can be done. **************************************************************************/ static void nfs_readlink_req(void) { uint32_t data[1024]; uint32_t *p; int len; p = &(data[0]); p = rpc_add_credentials(p); memcpy (p, filefh, NFS_FHSIZE); p += (NFS_FHSIZE / 4); len = p - &(data[0]); rpc_req(PROG_NFS, NFS_READLINK, data, len); }
/************************************************************************** NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server **************************************************************************/ static void nfs_umountall_req(void) { uint32_t data[1024]; uint32_t *p; int len; if (nfs_server_mount_port < 0) /* Nothing mounted, nothing to umount */ return; p = &(data[0]); p = rpc_add_credentials(p); len = p - &(data[0]); rpc_req(PROG_MOUNT, MOUNT_UMOUNTALL, data, len); }
/************************************************************************** NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server **************************************************************************/ static void nfs_umountall_req(void) { uint32_t data[1024]; uint32_t *p; int len; if ((NfsSrvMountPort == -1) || (!fs_mounted)) /* Nothing mounted, nothing to umount */ return; p = &(data[0]); p = (uint32_t *)rpc_add_credentials((long *)p); len = (uint32_t *)p - (uint32_t *)&(data[0]); rpc_req(PROG_MOUNT, MOUNT_UMOUNTALL, data, len); }
/************************************************************************** NFS_READ - Read File on NFS Server **************************************************************************/ static void nfs_read_req(int offset, int readlen) { uint32_t data[1024]; uint32_t *p; int len; p = &(data[0]); p = rpc_add_credentials(p); memcpy (p, filefh, NFS_FHSIZE); p += (NFS_FHSIZE / 4); *p++ = htonl(offset); *p++ = htonl(readlen); *p++ = 0; len = p - &(data[0]); rpc_req(PROG_NFS, NFS_READ, data, len); }
/************************************************************************** NFS_MOUNT - Mount an NFS Filesystem **************************************************************************/ static void nfs_mount_req (char *path) { uint32_t data[1024]; uint32_t *p; int len; int pathlen; pathlen = strlen (path); p = &(data[0]); p = (uint32_t *)rpc_add_credentials((long *)p); *p++ = htonl(pathlen); if (pathlen & 3) *(p + pathlen / 4) = 0; memcpy (p, path, pathlen); p += (pathlen + 3) / 4; len = (uint32_t *)p - (uint32_t *)&(data[0]); rpc_req (PROG_MOUNT, MOUNT_ADDENTRY, data, len); }
/************************************************************************** NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server **************************************************************************/ void nfs_umountall(int server) { struct rpc_t buf, *rpc; unsigned long id; int retries; long *p; if (!arptable[server].ipaddr.s_addr) { /* Haven't sent a single UDP packet to this server */ return; } if ((mount_port == -1) || (!fs_mounted)) { /* Nothing mounted, nothing to umount */ return; } id = rpc_id++; buf.u.call.id = htonl(id); buf.u.call.type = htonl(MSG_CALL); buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */ buf.u.call.prog = htonl(PROG_MOUNT); buf.u.call.vers = htonl(1); /* mountd is version 1 */ buf.u.call.proc = htonl(MOUNT_UMOUNTALL); p = rpc_add_credentials((long *)buf.u.call.data); for (retries = 0; retries < MAX_RPC_RETRIES; retries++) { long timeout = rfc2131_sleep_interval(TIMEOUT, retries); udp_transmit(arptable[server].ipaddr.s_addr, oport, mount_port, (char *)p - (char *)&buf, &buf); if (await_reply(await_rpc, oport, &id, timeout)) { rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; if (rpc->u.reply.rstatus || rpc->u.reply.verifier || rpc->u.reply.astatus) { rpc_printerror(rpc); } fs_mounted = 0; return; } } }
/* * nfs_umountall_req - Unmount all our NFS Filesystems on the Server */ static void nfs_umount_req(struct nfs_priv *npriv) { uint32_t data[1024]; uint32_t *p; int len; int pathlen; pathlen = strlen(npriv->path); p = &(data[0]); p = rpc_add_credentials(p); *p++ = htonl(pathlen); if (pathlen & 3) *(p + pathlen / 4) = 0; memcpy (p, npriv->path, pathlen); p += (pathlen + 3) / 4; len = p - &(data[0]); rpc_req(npriv, PROG_MOUNT, MOUNT_UMOUNT, data, len); }
static int nfs_readlink_req(struct file_priv *priv, char* buf, size_t size) { uint32_t data[1024]; uint32_t *p; int len; int ret; char *path; uint32_t *filedata; p = &(data[0]); p = rpc_add_credentials(p); memcpy(p, priv->filefh, NFS_FHSIZE); p += (NFS_FHSIZE / 4); len = p - &(data[0]); ret = rpc_req(priv->npriv, PROG_NFS, NFS_READLINK, data, len); if (ret) return ret; filedata = nfs_packet + sizeof(struct rpc_reply); filedata++; len = ntohl(net_read_uint32(filedata)); /* new path length */ filedata++; path = (char *)filedata; if (len > size) len = size; memcpy(buf, path, len); return 0; }
/*************************************************************************** * NFS_READLINK (AH 2003-07-14) * This procedure is called when read of the first block fails - * this probably happens when it's a directory or a symlink * In case of successful readlink(), the dirname is manipulated, * so that inside the nfs() function a recursion can be done. **************************************************************************/ static int nfs_readlink(int server, int port, char *fh, char *path, char *nfh, int sport) { struct rpc_t buf, *rpc; unsigned long id; long *p; int retries; int pathlen = strlen(path); id = rpc_id++; buf.u.call.id = htonl(id); buf.u.call.type = htonl(MSG_CALL); buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */ buf.u.call.prog = htonl(PROG_NFS); buf.u.call.vers = htonl(2); /* nfsd is version 2 */ buf.u.call.proc = htonl(NFS_READLINK); p = rpc_add_credentials((long *)buf.u.call.data); memcpy(p, nfh, NFS_FHSIZE); p += (NFS_FHSIZE / 4); for (retries = 0; retries < MAX_RPC_RETRIES; retries++) { long timeout = rfc2131_sleep_interval(TIMEOUT, retries); udp_transmit(arptable[server].ipaddr.s_addr, sport, port, (char *)p - (char *)&buf, &buf); if (await_reply(await_rpc, sport, &id, timeout)) { rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; if (rpc->u.reply.rstatus || rpc->u.reply.verifier || rpc->u.reply.astatus || rpc->u.reply.data[0]) { rpc_printerror(rpc); if (rpc->u.reply.rstatus) { /* RPC failed, no verifier, data[0] */ return -9999; } if (rpc->u.reply.astatus) { /* RPC couldn't decode parameters */ return -9998; } return -ntohl(rpc->u.reply.data[0]); } else { // It *is* a link. // If it's a relative link, append everything to dirname, filename TOO! retries = strlen ( (char *)(&(rpc->u.reply.data[2]) )); if ( *((char *)(&(rpc->u.reply.data[2]))) != '/' ) { path[pathlen++] = '/'; while ( ( retries + pathlen ) > 298 ) { retries--; } if ( retries > 0 ) { memcpy(path + pathlen, &(rpc->u.reply.data[2]), retries + 1); } else { retries = 0; } path[pathlen + retries] = 0; } else { // Else make it the only path. if ( retries > 298 ) { retries = 298; } memcpy ( path, &(rpc->u.reply.data[2]), retries + 1 ); path[retries] = 0; } return 0; } } } return -1; }