📄 nfs.c
字号:
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;}/**************************************************************************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_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 - Download extended BOOTP data, or kernel image from NFS server**************************************************************************/int nfs(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int)){ static int recursion = 0; int sport; int err, namelen = strlen(name); char dirname[300], *fname; char dirfh[NFS_FHSIZE]; /* file handle of directory */ char filefh[NFS_FHSIZE]; /* file handle of kernel image */ unsigned int block; int rlen, size, offs, len; struct rpc_t *rpc; rx_qdrain(); sport = oport++; if (oport > START_OPORT+OPORT_SWEEP) { oport = START_OPORT; } if ( name != dirname ) { memcpy(dirname, name, namelen + 1); } recursion = 0;nfssymlink: if ( recursion > NFS_MAXLINKDEPTH ) { printf ( "\nRecursion: More than %d symlinks followed. Abort.\n", NFS_MAXLINKDEPTH ); return 0; } recursion++; fname = dirname + (namelen - 1); while (fname >= dirname) { if (*fname == '/') { *fname = '\0'; fname++; break; } fname--; } if (fname < dirname) { printf("can't parse file name %s\n", name); return 0; } if (mount_port == -1) { mount_port = rpc_lookup(ARP_SERVER, PROG_MOUNT, 1, sport); } if (nfs_port == -1) { nfs_port = rpc_lookup(ARP_SERVER, PROG_NFS, 2, sport); } if (nfs_port == -1 || mount_port == -1) { printf("can't get nfs/mount ports from portmapper\n"); return 0; } err = nfs_mount(ARP_SERVER, mount_port, dirname, dirfh, sport); if (err) { printf("mounting %s: ", dirname); nfs_printerror(err); /* just to be sure... */ nfs_umountall(ARP_SERVER); return 0; } err = nfs_lookup(ARP_SERVER, nfs_port, dirfh, fname, filefh, sport); if (err) { printf("looking up %s: ", fname); nfs_printerror(err); nfs_umountall(ARP_SERVER); return 0; } offs = 0; block = 1; /* blocks are numbered starting from 1 */ size = -1; /* will be set properly with the first reply */ len = NFS_READ_SIZE; /* first request is always full size */ do { err = nfs_read(ARP_SERVER, nfs_port, filefh, offs, len, sport); if ((err <= -NFSERR_ISDIR)&&(err >= -NFSERR_INVAL) && (offs == 0)) { // An error occured. NFS servers tend to sending // errors 21 / 22 when symlink instead of real file // is requested. So check if it's a symlink! block = nfs_readlink(ARP_SERVER, nfs_port, dirfh, dirname, filefh, sport); if ( 0 == block ) { printf("\nLoading symlink:%s ..",dirname); goto nfssymlink; } nfs_printerror(err); nfs_umountall(ARP_SERVER); return 0; } if (err) { printf("reading at offset %d: ", offs); nfs_printerror(err); nfs_umountall(ARP_SERVER); return 0; } rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; /* size must be found out early to allow EOF detection */ if (size == -1) { size = ntohl(rpc->u.reply.data[6]); } rlen = ntohl(rpc->u.reply.data[18]); if (rlen > len) { rlen = len; /* shouldn't happen... */ } err = fnc((char *)&rpc->u.reply.data[19], block, rlen, (offs+rlen == size)); if (err <= 0) { nfs_umountall(ARP_SERVER); return err; } block++; offs += rlen; /* last request is done with matching requested read size */ if (size-offs < NFS_READ_SIZE) { len = size-offs; } } while (len != 0); /* len == 0 means that all the file has been read */ return 1;}#endif /* DOWNLOAD_PROTO_NFS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -