aboutsummaryrefslogtreecommitdiff
path: root/nfs/nfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'nfs/nfs.c')
-rw-r--r--nfs/nfs.c555
1 files changed, 414 insertions, 141 deletions
diff --git a/nfs/nfs.c b/nfs/nfs.c
index 617ca334..4916df65 100644
--- a/nfs/nfs.c
+++ b/nfs/nfs.c
@@ -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;
+ }
}
}
-