diff options
Diffstat (limited to 'nfs/nfs.c')
-rw-r--r-- | nfs/nfs.c | 555 |
1 files changed, 414 insertions, 141 deletions
@@ -1,5 +1,8 @@ -/* XDR frobbing and lower level routines for NFS client - Copyright (C) 1995, 1996 Free Software Foundation, Inc. +/* nfs.c - XDR frobbing and lower level routines for NFS client. + + Copyright (C) 1995, 1996, 1997, 1999, 2002, 2007 + Free Software Foundation, Inc. + Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -24,12 +27,13 @@ #include <netinet/in.h> #include <stdio.h> -/* Convert an NFS mode (TYPE and MODE) to a Hurd mode and return it. */ +/* Convert an NFS mode (TYPE and MODE) to a Hurd mode and return + it. */ mode_t nfs_mode_to_hurd_mode (int type, int mode) { int hurdmode; - + switch (type) { case NFDIR: @@ -45,12 +49,9 @@ nfs_mode_to_hurd_mode (int type, int mode) break; case NFREG: - case NFNON: - case NFBAD: - default: hurdmode = S_IFREG; break; - + case NFLNK: hurdmode = S_IFLNK; break; @@ -59,16 +60,39 @@ nfs_mode_to_hurd_mode (int type, int mode) hurdmode = S_IFSOCK; break; - case NFFIFO: - hurdmode = S_IFIFO; + default: + if (protocol_version == 2) + switch (type) + { + case NF2NON: + case NF2BAD: + default: + hurdmode = S_IFREG; + break; + + case NF2FIFO: + hurdmode = S_IFIFO; + break; + } + else + switch (type) + { + case NF3FIFO: + hurdmode = S_IFIFO; + break; + + default: + hurdmode = S_IFREG; + break; + } break; } - + hurdmode |= mode & ~NFSMODE_FMT; return hurdmode; } -/* Convert a Hurd mode to an NFS mode */ +/* Convert a Hurd mode to an NFS mode. */ int hurd_mode_to_nfs_mode (mode_t mode) { @@ -77,170 +101,384 @@ hurd_mode_to_nfs_mode (mode_t mode) return mode & 07777; } +/* Convert a Hurd mode to an NFS type. */ +int +hurd_mode_to_nfs_type (mode_t mode) +{ + switch (mode & S_IFMT) + { + case S_IFDIR: + return NFDIR; + + case S_IFCHR: + default: + return NFCHR; + + case S_IFBLK: + return NFBLK; + + case S_IFREG: + return NFREG; + + case S_IFLNK: + return NFLNK; + + case S_IFSOCK: + return NFSOCK; + + case S_IFIFO: + return protocol_version == 2 ? NF2FIFO : NF3FIFO; + } +} + + /* Each of the functions on this page copies its second arg to *P, converting it to XDR representation along the way. They then - return the address after the copied value. */ + return the address after the copied value. */ -/* Encode an NFS file handle. */ +/* Encode an NFS file handle. */ int * -xdr_encode_fhandle (int *p, void *fhandle) +xdr_encode_fhandle (int *p, struct fhandle *fhandle) { - bcopy (fhandle, p, NFS_FHSIZE); - return p + INTSIZE (NFS_FHSIZE); + if (protocol_version == 2) + { + memcpy (p, fhandle->data, NFS2_FHSIZE); + return p + INTSIZE (NFS2_FHSIZE); + } + else + return xdr_encode_data (p, fhandle->data, fhandle->size); } -/* Encode uninterpreted bytes. */ +/* Encode uninterpreted bytes. */ int * xdr_encode_data (int *p, char *data, size_t len) { int nints = INTSIZE (len); - + p[nints] = 0; - *p++ = htonl (len); - bcopy (data, p, len); + *(p++) = htonl (len); + memcpy (p, data, len); return p + nints; } -/* Encode a C string. */ +/* Encode a 64 bit integer. */ +int * +xdr_encode_64bit (int *p, long long n) +{ + *(p++) = htonl (n & 0xffffffff00000000LL >> 32); + *(p++) = htonl (n & 0xffffffff); + return p; +} + +/* Encode a C string. */ int * xdr_encode_string (int *p, char *string) { return xdr_encode_data (p, string, strlen (string)); } - -/* Encode a MODE into an otherwise empty sattr. */ + +/* Encode a MODE into an otherwise empty sattr. */ int * xdr_encode_sattr_mode (int *p, mode_t mode) { - *p++ = htonl (hurd_mode_to_nfs_mode (mode)); - *p++ = -1; /* uid */ - *p++ = -1; /* gid */ - *p++ = -1; /* size */ - *p++ = -1; /* atime secs */ - *p++ = -1; /* atime usecs */ - *p++ = -1; /* mtime secs */ - *p++ = -1; /* mtime usecs */ + if (protocol_version == 2) + { + *(p++) = htonl (hurd_mode_to_nfs_mode (mode)); + *(p++) = -1; /* uid */ + *(p++) = -1; /* gid */ + *(p++) = -1; /* size */ + *(p++) = -1; /* atime secs */ + *(p++) = -1; /* atime usecs */ + *(p++) = -1; /* mtime secs */ + *(p++) = -1; /* mtime usecs */ + } + else + { + *(p++) = htonl (1); /* set mode */ + *(p++) = htonl (hurd_mode_to_nfs_mode (mode)); + *(p++) = 0; /* no uid */ + *(p++) = 0; /* no gid */ + *(p++) = 0; /* no size */ + *(p++) = DONT_CHANGE; /* no atime */ + *(p++) = DONT_CHANGE; /* no mtime */ + } return p; } -/* Encode UID and GID into an otherwise empty sattr. */ +/* Encode UID and GID into an otherwise empty sattr. */ int * xdr_encode_sattr_ids (int *p, u_int uid, u_int gid) { - *p++ = -1; /* mode */ - *p++ = htonl (uid); - *p++ = htonl (gid); - *p++ = -1; /* size */ - *p++ = -1; /* atime secs */ - *p++ = -1; /* atime usecs */ - *p++ = -1; /* mtime secs */ - *p++ = -1; /* mtime usecs */ + if (protocol_version == 2) + { + *(p++) = -1; /* mode */ + *(p++) = htonl (uid); + *(p++) = htonl (gid); + *(p++) = -1; /* size */ + *(p++) = -1; /* atime secs */ + *(p++) = -1; /* atime usecs */ + *(p++) = -1; /* mtime secs */ + *(p++) = -1; /* mtime usecs */ + } + else + { + *(p++) = 0; /* no mode */ + *(p++) = htonl (1); /* set uid */ + *(p++) = htonl (uid); + *(p++) = htonl (1); /* set gid */ + *(p++) = htonl (gid); + *(p++) = 0; /* no size */ + *(p++) = DONT_CHANGE; /* no atime */ + *(p++) = DONT_CHANGE; /* no mtime */ + } return p; } -/* Encode a file size into an otherwise empty sattr. */ +/* Encode a file size into an otherwise empty sattr. */ int * xdr_encode_sattr_size (int *p, off_t size) { - *p++ = -1; /* mode */ - *p++ = -1; /* uid */ - *p++ = -1; /* gid */ - *p++ = htonl (size); - *p++ = -1; /* atime secs */ - *p++ = -1; /* atime usecs */ - *p++ = -1; /* mtime secs */ - *p++ = -1; /* mtime secs */ + if (protocol_version == 2) + { + *(p++) = -1; /* mode */ + *(p++) = -1; /* uid */ + *(p++) = -1; /* gid */ + *(p++) = htonl (size); + *(p++) = -1; /* atime secs */ + *(p++) = -1; /* atime usecs */ + *(p++) = -1; /* mtime secs */ + *(p++) = -1; /* mtime secs */ + } + else + { + *(p++) = 0; /* no mode */ + *(p++) = 0; /* no uid */ + *(p++) = 0; /* no gid */ + *(p++) = htonl (1); /* size */ + p = xdr_encode_64bit (p, size); + *(p++) = DONT_CHANGE; /* no atime */ + *(p++) = DONT_CHANGE; /* no mtime */ + } return p; } -/* Encode ATIME and MTIME into an otherwise empty sattr. */ +/* Encode ATIME and MTIME into an otherwise empty sattr. */ int * xdr_encode_sattr_times (int *p, struct timespec *atime, struct timespec *mtime) { - *p++ = -1; /* mode */ - *p++ = -1; /* uid */ - *p++ = -1; /* gid */ - *p++ = -1; /* size */ - *p++ = htonl (atime->tv_sec); - *p++ = htonl (atime->tv_nsec * 1000); - *p++ = htonl (mtime->tv_sec); - *p++ = htonl (mtime->tv_nsec * 1000); + if (protocol_version == 2) + { + *(p++) = -1; /* mode */ + *(p++) = -1; /* uid */ + *(p++) = -1; /* gid */ + *(p++) = -1; /* size */ + *(p++) = htonl (atime->tv_sec); + *(p++) = htonl (atime->tv_nsec / 1000); + *(p++) = htonl (mtime->tv_sec); + *(p++) = htonl (mtime->tv_nsec / 1000); + } + else + { + *(p++) = 0; /* no mode */ + *(p++) = 0; /* no uid */ + *(p++) = 0; /* no gid */ + *(p++) = 0; /* no size */ + *(p++) = htonl (SET_TO_CLIENT_TIME); /* atime */ + *(p++) = htonl (atime->tv_sec); + *(p++) = htonl (atime->tv_nsec); + *(p++) = htonl (SET_TO_CLIENT_TIME); /* mtime */ + *(p++) = htonl (mtime->tv_sec); + *(p++) = htonl (mtime->tv_nsec); + } return p; } -/* Encode MODE and a size of 0 into an otherwise empty sattr. */ +/* Encode MODE, a size of zero, and the specified owner into an + otherwise empty sattr. */ int * -xdr_encode_create_state (int *p, - mode_t mode) +xdr_encode_create_state (int *p, + mode_t mode, + uid_t owner) { - *p++ = htonl (hurd_mode_to_nfs_mode (mode)); - *p++ = -1; /* uid */ - *p++ = -1; /* gid */ - *p++ = 0; /* size */ - *p++ = -1; /* atime sec */ - *p++ = -1; /* atime usec */ - *p++ = -1; /* mtime sec */ - *p++ = -1; /* mtime usec */ + if (protocol_version == 2) + { + *(p++) = htonl (hurd_mode_to_nfs_mode (mode)); + *(p++) = htonl (owner); /* uid */ + *(p++) = -1; /* gid */ + *(p++) = 0; /* size */ + *(p++) = -1; /* atime sec */ + *(p++) = -1; /* atime usec */ + *(p++) = -1; /* mtime sec */ + *(p++) = -1; /* mtime usec */ + } + else + { + *(p++) = htonl (1); /* mode */ + *(p++) = htonl (hurd_mode_to_nfs_mode (mode)); + *(p++) = htonl (1); /* set uid */ + *(p++) = htonl (owner); + *(p++) = 0; /* no gid */ + *(p++) = htonl (1); /* set size */ + p = xdr_encode_64bit (p, 0); + *(p++) = htonl (SET_TO_SERVER_TIME); /* atime */ + *(p++) = htonl (SET_TO_SERVER_TIME); /* mtime */ + } return p; } -/* Encode ST into an sattr. */ +/* Encode ST into an sattr. */ int * xdr_encode_sattr_stat (int *p, struct stat *st) { - *p++ = htonl (st->st_mode); - *p++ = htonl (st->st_uid); - *p++ = htonl (st->st_gid); - *p++ = htonl (st->st_size); - *p++ = htonl (st->st_atime); - *p++ = htonl (st->st_atime_usec); - *p++ = htonl (st->st_mtime); - *p++ = htonl (st->st_mtime_usec); + if (protocol_version == 2) + { + *(p++) = htonl (hurd_mode_to_nfs_mode (st->st_mode)); + *(p++) = htonl (st->st_uid); + *(p++) = htonl (st->st_gid); + *(p++) = htonl (st->st_size); + *(p++) = htonl (st->st_atim.tv_sec); + *(p++) = htonl (st->st_atim.tv_nsec / 1000); + *(p++) = htonl (st->st_mtim.tv_sec); + *(p++) = htonl (st->st_mtim.tv_nsec / 1000); + } + else + { + *(p++) = htonl (1); /* set mode */ + *(p++) = htonl (hurd_mode_to_nfs_mode (st->st_mode)); + *(p++) = htonl (1); /* set uid */ + *(p++) = htonl (st->st_uid); + *(p++) = htonl (1); /* set gid */ + *(p++) = htonl (st->st_gid); + *(p++) = htonl (1); /* set size */ + p = xdr_encode_64bit (p, st->st_size); + *(p++) = htonl (SET_TO_CLIENT_TIME); /* set atime */ + *(p++) = htonl (st->st_atim.tv_sec); + *(p++) = htonl (st->st_atim.tv_nsec); + *(p++) = htonl (SET_TO_CLIENT_TIME); /* set mtime */ + *(p++) = htonl (st->st_mtim.tv_sec); + *(p++) = htonl (st->st_mtim.tv_nsec); + } return p; } +/* Decode *P into a long long; return the address of the following + data. */ +int * +xdr_decode_64bit (int *p, long long *n) +{ + long long high, low; + high = ntohl (*p); + p++; + low = ntohl (*p); + p++; + *n = ((high & 0xffffffff) << 32) | (low & 0xffffffff); + return p; +} + +/* Decode *P into an fhandle and look up the associated node. Return + the address of the following data. */ +int * +xdr_decode_fhandle (int *p, struct node **npp) +{ + size_t len; + + if (protocol_version == 2) + len = NFS2_FHSIZE; + else + { + len = ntohl (*p); + p++; + } + /* Enter into cache. */ + lookup_fhandle (p, len, npp); + return p + len / sizeof (int); +} + /* Decode *P into a stat structure; return the address of the - following data. */ + following data. */ int * xdr_decode_fattr (int *p, struct stat *st) { int type, mode; - - type = ntohl (*p++); - mode = ntohl (*p++); + + type = ntohl (*p); + p++; + mode = ntohl (*p); + p++; st->st_mode = nfs_mode_to_hurd_mode (type, mode); - st->st_nlink = ntohl (*p++); - st->st_uid = ntohl (*p++); - st->st_gid = ntohl (*p++); - st->st_size = ntohl (*p++); - st->st_blksize = ntohl (*p++); - st->st_rdev = ntohl (*p++); - st->st_blocks = ntohl (*p++); - st->st_fsid = ntohl (*p++); - st->st_ino = ntohl (*p++); - st->st_atime = ntohl (*p++); - st->st_atime_usec = ntohl (*p++); - st->st_mtime = ntohl (*p++); - st->st_mtime_usec = ntohl (*p++); - st->st_ctime = ntohl (*p++); - st->st_ctime_usec = ntohl (*p++); + st->st_nlink = ntohl (*p); + p++; + st->st_uid = ntohl (*p); + p++; + st->st_gid = ntohl (*p); + p++; + if (protocol_version == 2) + { + st->st_size = ntohl (*p); + p++; + st->st_blksize = ntohl (*p); + p++; + st->st_rdev = ntohl (*p); + p++; + st->st_blocks = ntohl (*p); + p++; + } + else + { + long long size; + int major, minor; + p = xdr_decode_64bit (p, &size); + st->st_size = size; + p = xdr_decode_64bit (p, &size); + st->st_blocks = size / 512; + st->st_blksize = read_size < write_size ? read_size : write_size; + major = ntohl (*p); + p++; + minor = ntohl (*p); + p++; + st->st_rdev = makedev (major, minor); + } + st->st_fsid = ntohl (*p); + p++; + st->st_ino = ntohl (*p); + p++; + st->st_atim.tv_sec = ntohl (*p); + p++; + st->st_atim.tv_nsec = ntohl (*p); + p++; + st->st_mtim.tv_sec = ntohl (*p); + p++; + st->st_mtim.tv_nsec = ntohl (*p); + p++; + st->st_ctim.tv_sec = ntohl (*p); + p++; + st->st_ctim.tv_nsec = ntohl (*p); + p++; + + if (protocol_version < 3) + { + st->st_atim.tv_nsec *= 1000; + st->st_mtim.tv_nsec *= 1000; + st->st_ctim.tv_nsec *= 1000; + } return p; } /* Decode *P into a string, stored at BUF; return the address - of the following data. */ + of the following data. */ int * xdr_decode_string (int *p, char *buf) { int len; - - len = ntohl (*p++); - bcopy (p, buf, len); + + len = ntohl (*p); + p++; + memcpy (buf, p, len); buf[len] = '\0'; return p + INTSIZE (len); } @@ -253,28 +491,29 @@ xdr_decode_string (int *p, char *buf) means superuser), NP (identifying the node we are operating on), and SECOND_GID (specifying another GID the server might be interested in). Allocate at least LEN bytes of space for bulk data in - addition to the normal amount for an RPC. */ + addition to the normal amount for an RPC. */ int * -nfs_initialize_rpc (int rpc_proc, struct netcred *cred, +nfs_initialize_rpc (int rpc_proc, struct iouser *cred, size_t len, void **bufp, struct node *np, uid_t second_gid) { uid_t uid; uid_t gid; error_t err; - + /* Use heuristics to figure out what ids to present to the server. - Don't lie, but adjust ids as necessary to secure the desired result. */ + Don't lie, but adjust ids as necessary to secure the desired + result. */ - if (cred == (struct netcred *) -1) + if (cred == (struct iouser *) -1) { uid = gid = 0; second_gid = -1; } else if (cred - && (cred->nuids || cred->ngids)) + && (cred->uids->num || cred->gids->num)) { - if (cred_has_uid (cred, 0)) + if (idvec_contains (cred->uids, 0)) { err = netfs_validate_stat (np, 0); uid = 0; @@ -284,35 +523,35 @@ nfs_initialize_rpc (int rpc_proc, struct netcred *cred, } else { - if (cred->nuids == 0) + if (cred->uids->num == 0) uid = -2; - else if (cred->nuids == 1) - uid = cred->uids[0]; + else if (cred->uids->num == 1) + uid = cred->uids->ids[0]; else { err = netfs_validate_stat (np, 0); if (err) { - uid = cred->uids[0]; + uid = cred->uids->ids[0]; printf ("NFS warning, internal stat failure\n"); } else { - if (cred_has_uid (cred, np->nn_stat.st_uid)) + if (idvec_contains (cred->uids, np->nn_stat.st_uid)) uid = np->nn_stat.st_uid; else - uid = cred->uids[0]; + uid = cred->uids->ids[0]; } } - if (cred->ngids == 0) + if (cred->gids->num == 0) { gid = -2; second_gid = -1; } - else if (cred->ngids == 1) + else if (cred->gids->num == 1) { - gid = cred->gids[0]; + gid = cred->gids->ids[0]; second_gid = -1; } else @@ -320,18 +559,18 @@ nfs_initialize_rpc (int rpc_proc, struct netcred *cred, err = netfs_validate_stat (np, 0); if (err) { - gid = cred->gids[0]; + gid = cred->gids->ids[0]; printf ("NFS warning, internal stat failure\n"); } else { - if (cred_has_gid (cred, np->nn_stat.st_gid)) + if (idvec_contains (cred->gids, np->nn_stat.st_gid)) gid = np->nn_stat.st_gid; else - gid = cred->gids[0]; - } + gid = cred->gids->ids[0]; + } if (second_gid != -1 - && !cred_has_gid (cred, second_gid)) + && !idvec_contains (cred->gids, second_gid)) second_gid = -1; } } @@ -343,7 +582,8 @@ nfs_initialize_rpc (int rpc_proc, struct netcred *cred, uid, gid, second_gid); } -/* ERROR is an NFS error code; return the correspending Hurd error. */ +/* ERROR is an NFS error code; return the correspending Hurd + error. */ error_t nfs_error_trans (int error) { @@ -351,58 +591,91 @@ nfs_error_trans (int error) { case NFS_OK: return 0; - + case NFSERR_PERM: return EPERM; case NFSERR_NOENT: return ENOENT; - + case NFSERR_IO: return EIO; - + case NFSERR_NXIO: return ENXIO; - + case NFSERR_ACCES: return EACCES; - + case NFSERR_EXIST: return EEXIST; - + case NFSERR_NODEV: return ENODEV; - + case NFSERR_NOTDIR: return ENOTDIR; - + case NFSERR_ISDIR: return EISDIR; - + case NFSERR_FBIG: return E2BIG; - + case NFSERR_NOSPC: return ENOSPC; case NFSERR_ROFS: return EROFS; - + case NFSERR_NAMETOOLONG: return ENAMETOOLONG; - + case NFSERR_NOTEMPTY: return ENOTEMPTY; - + case NFSERR_DQUOT: return EDQUOT; - + case NFSERR_STALE: return ESTALE; - + case NFSERR_WFLUSH: - default: + /* Not known in v3, but we just give EINVAL for unknown errors + so it's the same. */ return EINVAL; + + default: + if (protocol_version == 2) + return EINVAL; + else + switch (error) + { + case NFSERR_XDEV: + return EXDEV; + + case NFSERR_INVAL: + case NFSERR_REMOTE: /* not sure about this one */ + default: + return EINVAL; + + case NFSERR_MLINK: + return EMLINK; + + case NFSERR_NOTSUPP: + case NFSERR_BADTYPE: + return EOPNOTSUPP; + + case NFSERR_SERVERFAULT: + return EIO; + + case NFSERR_BADHANDLE: + case NFSERR_NOT_SYNC: + case NFSERR_BAD_COOKIE: + case NFSERR_TOOSMALL: + case NFSERR_JUKEBOX: /* ??? */ + /* These indicate bugs in the client, so EGRATUITOUS is right. */ + return EGRATUITOUS; + } } } - |