summaryrefslogtreecommitdiff
path: root/nfs
diff options
context:
space:
mode:
Diffstat (limited to 'nfs')
-rw-r--r--nfs/main.c36
-rw-r--r--nfs/mount.c60
-rw-r--r--nfs/nfs-spec.h4
-rw-r--r--nfs/nfs.c34
-rw-r--r--nfs/ops.c538
5 files changed, 476 insertions, 196 deletions
diff --git a/nfs/main.c b/nfs/main.c
index 3f4365c7..691d707d 100644
--- a/nfs/main.c
+++ b/nfs/main.c
@@ -197,7 +197,7 @@ static const struct argp_option startup_options[] = {
"Port for nfs operations"},
{"default-nfs-port", OPT_NFS_PORT_D,"PORT", 0,
"Port for nfs operations, if none can be found automatically"},
- {"nfs-program", OPT_NFS_PROG, "ID[.VERS]"},
+ {"nfs-program", OPT_NFS_PROG, "[ID.]VERS"},
{"pmap-port", OPT_PMAP_PORT, "SVC|PORT"},
@@ -338,6 +338,30 @@ parse_startup_opt (int key, char *arg, struct argp_state *state)
nfs_port = atoi (arg);
break;
+ case OPT_NFS_PROG:
+ {
+ const char* version = strrchr (arg, '.');
+ const char* program = NULL;
+
+ if (version != NULL)
+ {
+ program = arg;
+ version++;
+ }
+ else
+ version = arg;
+
+ nfs_version = atoi (version);
+ if (program)
+ nfs_program = atoi (program);
+
+ if (nfs_version < 2 || nfs_version > 3)
+ argp_error (state, "Invalid NFS version: %d", nfs_version);
+
+ protocol_version = nfs_version;
+ }
+ break;
+
case ARGP_KEY_ARG:
if (state->arg_num == 0)
remote_fs = arg;
@@ -378,12 +402,16 @@ main (int argc, char **argv)
struct sockaddr_in addr;
int ret;
- argp_parse (&argp, argc, argv, 0, 0, 0);
-
+ err = argp_parse (&argp, argc, argv, 0, 0, 0);
+ if (err)
+ error (1, err, "Invalid command line");
+
task_get_bootstrap_port (mach_task_self (), &bootstrap);
netfs_init ();
- main_udp_socket = socket (PF_INET, SOCK_DGRAM, 0);
+ if ((main_udp_socket = socket (PF_INET, SOCK_DGRAM, 0)) == -1)
+ error(1, errno, "Socket failed");
+
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons (IPPORT_RESERVED);
diff --git a/nfs/mount.c b/nfs/mount.c
index 45a2ad4f..44a29180 100644
--- a/nfs/mount.c
+++ b/nfs/mount.c
@@ -102,6 +102,7 @@ mount_root (char *name, char *host)
void *rpcbuf;
int port;
error_t err;
+ struct fhandle mount_fhandle;
struct node *np;
short pmapport;
@@ -110,13 +111,7 @@ mount_root (char *name, char *host)
{
struct servent *s;
- /* XXX This will always fail! pmap_service_name will always be "sunrpc"
- What should pmap_service_name really be? By definition the second
- argument is either "tcp" or "udp" Thus, is this backwards
- (as service_name suggests)? If so, should it read:
- s = getservbyname (pmap_service_name, "udp");
- or is there something I am missing here? */
- s = getservbyname ("sunrpc", pmap_service_name);
+ s = getservbyname (pmap_service_name, "udp");
if (s)
pmapport = s->s_port;
else
@@ -212,10 +207,9 @@ mount_root (char *name, char *host)
goto error_with_rpcbuf;
}
- /* Create the node for root */
- xdr_decode_fhandle (p, &np);
+ mount_fhandle.size = NFS2_FHSIZE;
+ memcpy(&mount_fhandle.data, p, mount_fhandle.size);
free (rpcbuf);
- pthread_mutex_unlock (&np->lock);
if (nfs_port_override)
port = nfs_port;
@@ -236,8 +230,8 @@ mount_root (char *name, char *host)
error (0, errno, "rpc");
goto error_with_rpcbuf;
}
- *(p++) = htonl (NFS_PROGRAM);
- *(p++) = htonl (NFS_VERSION);
+ *(p++) = htonl (nfs_program);
+ *(p++) = htonl (nfs_version);
*(p++) = htonl (IPPROTO_UDP);
*(p++) = htonl (0);
err = conduct_rpc (&rpcbuf, &p);
@@ -267,7 +261,47 @@ mount_root (char *name, char *host)
mounted_hostname = host;
mounted_nfs_port = port;
- return np;
+ /* The handle returned by the mount server is always NFS2_FHSIZE.
+ The handle on NFSv3 can be larger. An NFS server lookup for
+ the root node succeeds with the handle from the mount server
+ but a longer handle is returned as the true identity. This is
+ the one that must be maintained by the root node.
+ So refetch it here... */
+ p = initialize_rpc(nfs_program,
+ nfs_version,
+ NFSPROC_LOOKUP (protocol_version),
+ 0, &rpcbuf,
+ 0, 0, -1);
+ if (! p)
+ {
+ error (0, errno, "rpc");
+ goto error_with_rpcbuf;
+ }
+
+ p = xdr_encode_fhandle(p, &mount_fhandle);
+ p = xdr_encode_string (p, ".");
+
+ err = conduct_rpc (&rpcbuf, &p);
+
+ if (!err) {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ }
+ else
+ {
+ error (0, errno, "rpc");
+ goto error_with_rpcbuf;
+ }
+
+ if (!err)
+ {
+ /* Create the node for root */
+ xdr_decode_fhandle (p, &np);
+ pthread_mutex_unlock (&np->lock);
+ free(rpcbuf);
+
+ return np;
+ }
error_with_rpcbuf:
free (rpcbuf);
diff --git a/nfs/nfs-spec.h b/nfs/nfs-spec.h
index bed03874..4f7f5354 100644
--- a/nfs/nfs-spec.h
+++ b/nfs/nfs-spec.h
@@ -7,7 +7,9 @@
#define NFS_MAXNAMLEN 255
#define NFS2_FHSIZE 32
#define NFS3_FHSIZE 64
-#define NFS_COOKIESIZE 4
+#define NFS2_COOKIESIZE 4
+#define NFS3_COOKIESIZE 8
+#define NFS_MAXCOOKIESIZE NFS3_COOKIESIZE
#define NFS_FIFO_DEV -1
#define NFS3_COOKIEVERFSIZE 8
#define NFS3_CREATEVERFSIZE 8
diff --git a/nfs/nfs.c b/nfs/nfs.c
index cd377ff2..40e62669 100644
--- a/nfs/nfs.c
+++ b/nfs/nfs.c
@@ -25,6 +25,7 @@
#include <string.h>
#include <netinet/in.h>
+#include <stdbool.h>
#include <stdio.h>
#include <sys/sysmacros.h>
@@ -179,6 +180,30 @@ xdr_encode_string (int *p, const char *string)
return xdr_encode_data (p, string, strlen (string));
}
+/* Some NFSv3 rpcs can fail if the file size field
+ is set within the set attributes unnecessarily. */
+static inline bool
+nfs_sattr3_size_needed(mode_t mode, size_t sz)
+{
+ if (sz == 0)
+ {
+ switch (hurd_mode_to_nfs_type (mode))
+ {
+ case NFSOCK:
+ case NF3FIFO:
+ /* NFCHR and NFBLK probaly also fall into this
+ category but as unable to check then leave
+ those alone. */
+ return false;
+
+ default:
+ break;
+ }
+ }
+
+ return true;
+}
+
/* Encode a MODE into an otherwise empty sattr. */
int *
xdr_encode_sattr_mode (int *p, mode_t mode)
@@ -372,14 +397,17 @@ xdr_encode_sattr_stat (int *p,
}
else
{
+ bool needs_size = nfs_sattr3_size_needed (st->st_mode, st->st_size);
+
*(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 (needs_size); /* set size */
+ if (needs_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);
@@ -608,7 +636,7 @@ nfs_initialize_rpc (int rpc_proc, struct iouser *cred,
else
uid = gid = second_gid = -1;
- return initialize_rpc (NFS_PROGRAM, NFS_VERSION, rpc_proc, len, bufp,
+ return initialize_rpc (nfs_program, nfs_version, rpc_proc, len, bufp,
uid, gid, second_gid);
}
diff --git a/nfs/ops.c b/nfs/ops.c
index a34d905a..2976641f 100644
--- a/nfs/ops.c
+++ b/nfs/ops.c
@@ -27,6 +27,19 @@
#include <maptime.h>
#include <sys/sysmacros.h>
+/* Rules for locking/unlocking of 'struct node'->lock
+ applicable throughout the whole module:
+ 1) Only lock a single node at a time except when
+ 2) A new node is created beneath a directory when the
+ directory node->lock is held but
+ 3) Once the directory lock is released then 2) no
+ longer applies and rule 1) applies to the new node.
+*/
+
+static error_t
+nfs_lookup_rpc (struct iouser *cred, struct node *np,
+ const char *name, struct node **newnp);
+
/* We have fresh stat information for NP; the file attribute (fattr)
structure is at P. Update our entry. Return the address of the next
int after the fattr structure. */
@@ -134,6 +147,84 @@ process_wcc_stat (struct node *np, int *p, int mod)
}
}
+/* advance the reply buffer beyond the 'post_op_attr' (v3) or
+ 'fattr' (v2). Populating 'struct stat' for the purposes of
+ advancing the correct number of bytes might seem wasteful
+ but it is not expected that this function will be called
+ often. */
+static int *
+skip_returned_stat (int *p)
+{
+ struct stat st;
+
+ if (protocol_version == 2)
+ return xdr_decode_fattr (p, &st);
+
+ int attrs_exist = ntohl (*p);
+ p++;
+
+ return (attrs_exist ? xdr_decode_fattr (p, &st) : p);
+}
+
+/* The reply to CREATE, MKDIR, SYMLINK and MKNOD in v3 all have
+ the same reply content. 'np' should be supplied unlocked.
+ SYMLINK and MKNOD creation involve the translation of an
+ existing node '*newnp' that is supplied locked. On return
+ any '*newnp' is locked and 'np' is returned unlocked. */
+static error_t
+process_create_reply (struct iouser *cred,
+ struct node *np,
+ const char* name,
+ struct node **newnp,
+ int *p)
+{
+ assert_backtrace (protocol_version == 3);
+
+ error_t err = nfs_error_trans (ntohl (*p));
+ p++;
+
+ if (!err)
+ {
+ int handle_follows = ntohl (*p);
+ p++;
+
+ if (handle_follows)
+ {
+ p = (*newnp != NULL
+ ? recache_handle (p, *newnp)
+ : xdr_decode_fhandle (p, newnp));
+ p = process_returned_stat (*newnp, p, 1);
+ }
+ else
+ /* These will be refetched by nfs_lookup_rpc () */
+ p = skip_returned_stat (p);
+
+ if (*newnp)
+ pthread_mutex_unlock (&(*newnp)->lock);
+
+ pthread_mutex_lock (&np->lock);
+ p = process_wcc_stat (np, p, 1);
+
+ if (!handle_follows)
+ {
+ err = nfs_lookup_rpc (cred, np, name, newnp);
+ }
+ else
+ pthread_mutex_unlock (&np->lock);
+ }
+ else
+ {
+ if (*newnp)
+ pthread_mutex_unlock (&(*newnp)->lock);
+ pthread_mutex_lock (&np->lock);
+ p = process_wcc_stat (np, p, 1);
+ pthread_mutex_unlock (&np->lock);
+ if (*newnp)
+ pthread_mutex_lock (&(*newnp)->lock);
+ }
+
+ return err;
+}
/* Implement the netfs_validate_stat callback as described in
<hurd/netfs.h>. */
@@ -167,11 +258,11 @@ netfs_validate_stat (struct node *np, struct iouser *cred)
return err;
}
-/* Implement the netfs_attempt_chown callback as described in
- <hurd/netfs.h>. */
-error_t
-netfs_attempt_chown (struct iouser *cred, struct node *np,
- uid_t uid, gid_t gid)
+/* Generalised implementation of PROC_SETATTR rpc call requiring
+ only a localised sattr encoding function for each caller. */
+static error_t
+nfs_setattr_rpc (struct iouser *cred, struct node *np, gid_t gid,
+ int *(sattr_encoder) (int *))
{
int *p;
void *rpcbuf;
@@ -183,7 +274,7 @@ netfs_attempt_chown (struct iouser *cred, struct node *np,
return errno;
p = xdr_encode_fhandle (p, &np->nn->handle);
- p = xdr_encode_sattr_ids (p, uid, gid);
+ p = (sattr_encoder) (p);
if (protocol_version == 3)
*(p++) = 0; /* guard_check == 0 */
@@ -201,6 +292,20 @@ netfs_attempt_chown (struct iouser *cred, struct node *np,
return err;
}
+/* Implement the netfs_attempt_chown callback as described in
+ <hurd/netfs.h>. */
+error_t
+netfs_attempt_chown (struct iouser *cred, struct node *np,
+ uid_t uid, gid_t gid)
+{
+ int *_chown_sattr_encoder (int *p)
+ {
+ return xdr_encode_sattr_ids (p, uid, gid);
+ }
+
+ return nfs_setattr_rpc (cred, np, gid, _chown_sattr_encoder);
+}
+
/* Implement the netfs_attempt_chauthor callback as described in
<hurd/netfs.h>. */
error_t
@@ -216,13 +321,9 @@ error_t
netfs_attempt_chmod (struct iouser *cred, struct node *np,
mode_t mode)
{
- int *p;
- void *rpcbuf;
- error_t err;
-
if ((mode & S_IFMT) != 0)
{
- err = netfs_validate_stat (np, cred);
+ error_t err = netfs_validate_stat (np, cred);
if (err)
return err;
@@ -257,27 +358,12 @@ netfs_attempt_chmod (struct iouser *cred, struct node *np,
}
}
- p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version),
- cred, 0, &rpcbuf, np, -1);
- if (! p)
- return errno;
-
- p = xdr_encode_fhandle (p, &np->nn->handle);
- p = xdr_encode_sattr_mode (p, mode);
- if (protocol_version == 3)
- *(p++) = 0; /* guard check == 0 */
-
- err = conduct_rpc (&rpcbuf, &p);
- if (!err)
- {
- err = nfs_error_trans (ntohl (*p));
- p++;
- if (!err || protocol_version == 3)
- p = process_wcc_stat (np, p, !err);
- }
+ int *_chmod_sattr_encoder (int *p)
+ {
+ return xdr_encode_sattr_mode (p, mode);
+ }
- free (rpcbuf);
- return err;
+ return nfs_setattr_rpc (cred, np, -1, _chmod_sattr_encoder);
}
/* Implement the netfs_attempt_chflags callback as described in
@@ -295,37 +381,18 @@ error_t
netfs_attempt_utimes (struct iouser *cred, struct node *np,
struct timespec *atime, struct timespec *mtime)
{
- int *p;
- void *rpcbuf;
- error_t err;
-
if (!atime && !mtime)
return 0; /* nothing to update */
/* XXX For version 3 we can actually do this right, but we don't
just yet. */
- p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version),
- cred, 0, &rpcbuf, np, -1);
- if (! p)
- return errno;
-
- p = xdr_encode_fhandle (p, &np->nn->handle);
- p = xdr_encode_sattr_times (p, atime, mtime);
- if (protocol_version == 3)
- *(p++) = 0; /* guard check == 0 */
-
- err = conduct_rpc (&rpcbuf, &p);
- if (!err)
- {
- err = nfs_error_trans (ntohl (*p));
- p++;
- if (!err || protocol_version == 3)
- p = process_wcc_stat (np, p, !err);
- }
+ int *_utimes_sattr_encoder (int *p)
+ {
+ return xdr_encode_sattr_times (p, atime, mtime);
+ }
- free (rpcbuf);
- return err;
+ return nfs_setattr_rpc (cred, np, -1, _utimes_sattr_encoder);
}
/* Implement the netfs_attempt_set_size callback as described in
@@ -334,28 +401,14 @@ error_t
netfs_attempt_set_size (struct iouser *cred, struct node *np,
off_t size)
{
- int *p;
- void *rpcbuf;
error_t err;
- p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version),
- cred, 0, &rpcbuf, np, -1);
- if (! p)
- return errno;
+ int *_size_sattr_encoder (int *p)
+ {
+ return xdr_encode_sattr_size (p, size);
+ }
- p = xdr_encode_fhandle (p, &np->nn->handle);
- p = xdr_encode_sattr_size (p, size);
- if (protocol_version == 3)
- *(p++) = 0; /* guard_check == 0 */
-
- err = conduct_rpc (&rpcbuf, &p);
- if (!err)
- {
- err = nfs_error_trans (ntohl (*p));
- p++;
- if (!err || protocol_version == 3)
- p = process_wcc_stat (np, p, !err);
- }
+ err = nfs_setattr_rpc (cred, np, -1, _size_sattr_encoder);
/* If we got EACCES, but the user has the file open for writing,
then the NFS protocol has screwed us. There's nothing we can do,
@@ -371,15 +424,12 @@ netfs_attempt_set_size (struct iouser *cred, struct node *np,
err = 0;
}
- free (rpcbuf);
return err;
}
-/* Implement the netfs_attempt_statfs callback as described in
- <hurd/netfs.h>. */
-error_t
-netfs_attempt_statfs (struct iouser *cred, struct node *np,
- struct statfs *st)
+static error_t
+netfs_attempt_statfs_v2 (struct iouser *cred, struct node *np,
+ struct statfs *st)
{
int *p;
void *rpcbuf;
@@ -420,6 +470,68 @@ netfs_attempt_statfs (struct iouser *cred, struct node *np,
return err;
}
+static error_t
+netfs_attempt_statfs_v3 (struct iouser *cred, struct node *np,
+ struct statfs *st)
+{
+ int *p;
+ void *rpcbuf;
+ error_t err;
+
+ p = nfs_initialize_rpc (NFS3PROC_FSSTAT, cred, 0, &rpcbuf, np, -1);
+ if (! p)
+ return errno;
+
+ p = xdr_encode_fhandle (p, &np->nn->handle);
+
+ err = conduct_rpc (&rpcbuf, &p);
+ if (!err)
+ {
+ err = nfs_error_trans (ntohl (*p++));
+ p = process_returned_stat (np, p, 1);
+
+ if (!err)
+ {
+ /* NFS V3 does not support the concept of blocks */
+ st->f_bsize = 1;
+
+ /* uint64t FSSTAT3resok.tbytes */
+ p = xdr_decode_64bit(p, &st->f_blocks);
+ /* uint64t FSSTAT3resok.fbytes */
+ p = xdr_decode_64bit(p, &st->f_bfree);
+ /* uint64t FSSTAT3resok.abytes */
+ p = xdr_decode_64bit(p, &st->f_bavail);
+ /* uint64t FSSTAT3resok.tfiles */
+ p = xdr_decode_64bit(p, &st->f_files);
+ /* uint64t FSSTAT3resok.ffiles */
+ p = xdr_decode_64bit(p, &st->f_ffree);
+
+ /* No need to decode the reply further */
+ /* uint64t FSSTAT3resok.afiles */
+ /* uint32 FSSTAT3resok.invarsec */
+
+ st->f_type = FSTYPE_NFS;
+ st->f_fsid = getpid ();
+
+ st->f_namelen = 0;
+ }
+ }
+
+ free (rpcbuf);
+ return err;
+}
+
+/* Implement the netfs_attempt_statfs callback as described in
+ <hurd/netfs.h>. */
+error_t
+netfs_attempt_statfs (struct iouser *cred, struct node *np,
+ struct statfs *st)
+{
+ return (protocol_version == 2
+ ? netfs_attempt_statfs_v2 (cred, np, st)
+ : netfs_attempt_statfs_v3 (cred, np, st));
+}
+
/* Implement the netfs_attempt_sync callback as described in
<hurd/netfs.h>. */
error_t
@@ -462,10 +574,17 @@ netfs_attempt_read (struct iouser *cred, struct node *np,
return errno;
p = xdr_encode_fhandle (p, &np->nn->handle);
- *(p++) = htonl (offset);
- *(p++) = htonl (thisamt);
if (protocol_version == 2)
- *(p++) = 0;
+ {
+ *(p++) = htonl (offset);
+ *(p++) = htonl (thisamt);
+ *(p++) = 0;
+ }
+ else
+ {
+ p = xdr_encode_64bit (p, offset);
+ *(p++) = htonl (thisamt);
+ }
err = conduct_rpc (&rpcbuf, &p);
if (!err)
@@ -489,8 +608,15 @@ netfs_attempt_read (struct iouser *cred, struct node *np,
if (protocol_version == 3)
{
+ size_t opaque_data_len;
+
eof = ntohl (*p);
p++;
+ opaque_data_len = ntohl (*p++);
+
+ /* opaque_len should surely equal trans_len, however... */
+ if (opaque_data_len < trans_len)
+ trans_len = opaque_data_len;
}
else
eof = (trans_len < thisamt);
@@ -537,12 +663,17 @@ netfs_attempt_write (struct iouser *cred, struct node *np,
p = xdr_encode_fhandle (p, &np->nn->handle);
if (protocol_version == 2)
+ {
*(p++) = 0;
- *(p++) = htonl (offset);
- if (protocol_version == 2)
+ *(p++) = htonl (offset);
*(p++) = 0;
- if (protocol_version == 3)
+ }
+ else
+ {
+ p = xdr_encode_64bit(p, offset);
+ *(p++) = htonl (thisamt);
*(p++) = htonl (FILE_SYNC);
+ }
p = xdr_encode_data (p, data, thisamt);
err = conduct_rpc (&rpcbuf, &p);
@@ -632,12 +763,6 @@ error_t
netfs_attempt_lookup (struct iouser *cred, struct node *np,
const char *name, struct node **newnp)
{
- int *p;
- void *rpcbuf;
- error_t err;
- char dirhandle[NFS3_FHSIZE];
- size_t dirlen;
-
/* Check the cache first. */
*newnp = check_lookup_cache (np, name);
if (*newnp)
@@ -651,10 +776,30 @@ netfs_attempt_lookup (struct iouser *cred, struct node *np,
return 0;
}
+ return nfs_lookup_rpc (cred, np, name, newnp);
+}
+
+/* LOOKUP rpc call to refetch the status of 'name' in directory
+ 'np' which is supplied locked. Any '*newnp' supplied should be
+ unlocked and will be recached with the returned handle. On
+ return 'np' is unlocked and any '*newnp' is locked. */
+static error_t
+nfs_lookup_rpc (struct iouser *cred, struct node *np,
+ const char *name, struct node **newnp)
+{
+ int *p;
+ void *rpcbuf;
+ error_t err;
+ char dirhandle[NFS3_FHSIZE];
+ size_t dirlen;
+
p = nfs_initialize_rpc (NFSPROC_LOOKUP (protocol_version),
cred, 0, &rpcbuf, np, -1);
if (! p)
- return errno;
+ {
+ pthread_mutex_unlock (&np->lock);
+ return errno;
+ }
p = xdr_encode_fhandle (p, &np->nn->handle);
p = xdr_encode_string (p, name);
@@ -673,27 +818,33 @@ netfs_attempt_lookup (struct iouser *cred, struct node *np,
p++;
if (!err)
{
- p = xdr_decode_fhandle (p, newnp);
+ if (*newnp != NULL)
+ {
+ pthread_mutex_lock (&(*newnp)->lock);
+ p = recache_handle (p, *newnp);
+ }
+ else
+ p = xdr_decode_fhandle (p, newnp);
+
p = process_returned_stat (*newnp, p, 1);
}
- if (err)
- *newnp = 0;
if (protocol_version == 3)
{
if (*newnp)
pthread_mutex_unlock (&(*newnp)->lock);
pthread_mutex_lock (&np->lock);
- p = process_returned_stat (np, p, 0); /* XXX Do we have to lock np? */
+ p = process_returned_stat (np, p, 0);
pthread_mutex_unlock (&np->lock);
if (*newnp)
pthread_mutex_lock (&(*newnp)->lock);
}
}
- else
- *newnp = 0;
- /* Notify the cache of the hit or miss. */
- enter_lookup_cache (dirhandle, dirlen, *newnp, name);
+ if (!err || err == ENOENT)
+ {
+ /* Notify the cache of the hit or miss. */
+ enter_lookup_cache (dirhandle, dirlen, *newnp, name);
+ }
free (rpcbuf);
@@ -732,18 +883,31 @@ netfs_attempt_mkdir (struct iouser *cred, struct node *np,
p = xdr_encode_string (p, name);
p = xdr_encode_create_state (p, mode, owner);
+ pthread_mutex_unlock (&np->lock);
+
err = conduct_rpc (&rpcbuf, &p);
if (!err)
{
- err = nfs_error_trans (ntohl (*p));
- p++;
+ if (protocol_version == 2)
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+
+ if (!err)
+ {
+ p = xdr_decode_fhandle (p, &newnp);
+ p = process_returned_stat (newnp, p, 1);
+ }
+ }
+ else
+ {
+ newnp = NULL;
+ err = process_create_reply (cred, np, name, &newnp, p);
+ }
}
if (!err)
{
- p = xdr_decode_fhandle (p, &newnp);
- p = process_returned_stat (newnp, p, 1);
-
/* Did we set the owner correctly? If not, try, but ignore failures. */
if (!netfs_validate_stat (newnp, (struct iouser *) -1)
&& newnp->nn_stat.st_uid != owner)
@@ -754,6 +918,8 @@ netfs_attempt_mkdir (struct iouser *cred, struct node *np,
netfs_nput (newnp);
}
+ pthread_mutex_lock (&np->lock);
+
free (rpcbuf);
return err;
}
@@ -890,8 +1056,6 @@ netfs_attempt_link (struct iouser *cred, struct node *dir,
}
pthread_mutex_unlock (&np->lock);
- pthread_mutex_lock (&dir->lock);
-
purge_lookup_cache (dir, name, strlen (name));
err = conduct_rpc (&rpcbuf, &p);
if (!err)
@@ -902,6 +1066,7 @@ netfs_attempt_link (struct iouser *cred, struct node *dir,
if (protocol_version == 2 && !err)
{
free (rpcbuf);
+ pthread_mutex_lock (&dir->lock);
/* NFSPROC_SYMLINK stupidly does not pass back an
fhandle, so we have to fetch one now. */
@@ -935,23 +1100,14 @@ netfs_attempt_link (struct iouser *cred, struct node *dir,
}
else if (protocol_version == 3)
{
- if (!err)
- {
- pthread_mutex_unlock (&dir->lock);
- pthread_mutex_lock (&np->lock);
- p = recache_handle (p, np);
- p = process_returned_stat (np, p, 1);
- pthread_mutex_unlock (&np->lock);
- pthread_mutex_lock (&dir->lock);
- }
- p = process_wcc_stat (dir, p, !err);
- pthread_mutex_unlock (&dir->lock);
+ /* process_create_reply needs the start of the buffer */
+ p--;
+
+ pthread_mutex_lock (&np->lock);
+ err = process_create_reply (cred, dir, name, &np, p);
+ pthread_mutex_unlock (&np->lock);
}
- else
- pthread_mutex_unlock (&dir->lock);
}
- else
- pthread_mutex_unlock (&dir->lock);
free (rpcbuf);
break;
@@ -1047,19 +1203,9 @@ netfs_attempt_link (struct iouser *cred, struct node *dir,
err = conduct_rpc (&rpcbuf, &p);
if (!err)
{
- err = nfs_error_trans (ntohl (*p));
- p++;
-
- if (!err)
- {
- pthread_mutex_lock (&np->lock);
- p = recache_handle (p, np);
- p = process_returned_stat (np, p, 1);
- pthread_mutex_unlock (&np->lock);
- }
- pthread_mutex_lock (&dir->lock);
- p = process_wcc_stat (dir, p, !err);
- pthread_mutex_unlock (&dir->lock);
+ pthread_mutex_lock (&np->lock);
+ err = process_create_reply (cred, dir, name, &np, p);
+ pthread_mutex_unlock (&np->lock);
}
free (rpcbuf);
}
@@ -1108,16 +1254,17 @@ netfs_attempt_mkfile (struct iouser *cred, struct node *dir,
name = malloc (50);
if (! name)
- return ENOMEM;
+ {
+ pthread_mutex_unlock (&dir->lock);
+ return ENOMEM;
+ }
do
{
sprintf (name, ".nfstmpgnu.%d", n++);
err = netfs_attempt_create_file (cred, dir, name, mode, newnp);
if (err == EEXIST)
- pthread_mutex_lock (&dir->lock); /* XXX is this right? does create need this
- and drop this on error? Doesn't look
- like it. */
+ pthread_mutex_lock (&dir->lock);
}
while (err == EEXIST);
@@ -1174,8 +1321,10 @@ netfs_attempt_create_file (struct iouser *cred, struct node *np,
p = nfs_initialize_rpc (NFSPROC_CREATE (protocol_version),
cred, 0, &rpcbuf, np, -1);
- if (! p)
+ if (! p) {
+ pthread_mutex_unlock (&np->lock);
return errno;
+ }
p = xdr_encode_fhandle (p, &np->nn->handle);
p = xdr_encode_string (p, name);
@@ -1193,37 +1342,36 @@ netfs_attempt_create_file (struct iouser *cred, struct node *np,
p = xdr_encode_create_state (p, mode, owner);
err = conduct_rpc (&rpcbuf, &p);
+ *newnp = 0;
pthread_mutex_unlock (&np->lock);
if (!err)
{
- err = nfs_error_trans (ntohl (*p));
- p++;
- if (!err)
+ if (protocol_version == 2)
{
- p = xdr_decode_fhandle (p, newnp);
- p = process_returned_stat (*newnp, p, 1);
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ if (!err)
+ {
+ p = xdr_decode_fhandle (p, newnp);
+ p = process_returned_stat (*newnp, p, 1);
+ }
}
- if (err)
- *newnp = 0;
- if (protocol_version == 3)
+ else
+ err = process_create_reply (cred, np, name, newnp, p);
+
+ if (protocol_version == 3 && !err)
{
- if (*newnp)
- pthread_mutex_unlock (&(*newnp)->lock);
- pthread_mutex_lock (&np->lock);
- p = process_wcc_stat (np, p, 1);
- pthread_mutex_unlock (&np->lock);
- if (*newnp)
- pthread_mutex_lock (&(*newnp)->lock);
- }
+ int *_cs_sattr_encoder (int * sp)
+ {
+ return xdr_encode_create_state (sp, mode, owner);
+ }
- if (*newnp && !netfs_validate_stat (*newnp, (struct iouser *) -1)
- && (*newnp)->nn_stat.st_uid != owner)
- netfs_attempt_chown ((struct iouser *) -1, *newnp, owner, (*newnp)->nn_stat.st_gid);
+ err = nfs_setattr_rpc(cred, *newnp, -1, _cs_sattr_encoder);
+ /* Unlink *newnp if err ? */
+ }
}
- else
- *newnp = 0;
free (rpcbuf);
return err;
@@ -1354,10 +1502,10 @@ netfs_attempt_rename (struct iouser *cred, struct node *fromdir,
pthread_mutex_lock (&fromdir->lock);
err = netfs_attempt_lookup (cred, fromdir, fromname, &np);
- pthread_mutex_unlock (&fromdir->lock);
if (err)
return err;
+ pthread_mutex_unlock(&np->lock);
err = netfs_attempt_link (cred, todir, np, toname, 1);
netfs_nput (np);
if (err)
@@ -1408,7 +1556,10 @@ netfs_attempt_rename (struct iouser *cred, struct node *fromdir,
{
pthread_mutex_lock (&fromdir->lock);
p = process_wcc_stat (fromdir, p, !err);
+ pthread_mutex_unlock (&fromdir->lock);
+ pthread_mutex_lock (&todir->lock);
p = process_wcc_stat (todir, p, !err);
+ pthread_mutex_unlock (&todir->lock);
}
}
@@ -1528,9 +1679,8 @@ netfs_report_access (struct iouser *cred,
{
err = nfs_error_trans (ntohl (*p));
p++;
- p = process_returned_stat (np, p, 0); /* XXX Should this be
- protected by the
- if (!err) ? */
+ p = process_returned_stat (np, p, 0);
+
if (!err)
{
ret = ntohl (*p);
@@ -1697,7 +1847,6 @@ fetch_directory (struct iouser *cred, struct node *dir,
void **bufp, size_t *bufsizep, int *totalentries)
{
void *buf;
- int cookie;
int *p;
void *rpcbuf;
struct dirent *entry;
@@ -1707,6 +1856,12 @@ fetch_directory (struct iouser *cred, struct node *dir,
error_t err;
int isnext;
+ /* Treat all cookies as opaque data of the appropriate size */
+ char cookieverf[NFS3_COOKIEVERFSIZE];
+ char cookie[NFS_MAXCOOKIESIZE];
+ const unsigned int cookie_size =
+ (protocol_version == 2 ? NFS2_COOKIESIZE : NFS3_COOKIESIZE);
+
bufmalloced = read_size;
buf = malloc (bufmalloced);
@@ -1714,7 +1869,9 @@ fetch_directory (struct iouser *cred, struct node *dir,
return ENOMEM;
bp = buf;
- cookie = 0;
+ memset (cookie, 0, cookie_size);
+ if (protocol_version == 3)
+ memset (cookieverf, 0, sizeof (cookieverf));
eof = 0;
*totalentries = 0;
@@ -1730,20 +1887,44 @@ fetch_directory (struct iouser *cred, struct node *dir,
}
p = xdr_encode_fhandle (p, &dir->nn->handle);
- *(p++) = cookie;
+ memcpy (p, cookie, cookie_size);
+ p += INTSIZE (cookie_size);
+
+ if (protocol_version == 3)
+ {
+ memcpy (p, cookieverf, sizeof (cookieverf));
+ p += INTSIZE (sizeof (cookieverf));
+ }
+
*(p++) = ntohl (read_size);
err = conduct_rpc (&rpcbuf, &p);
- if (!err)
+ if (err)
{
- err = nfs_error_trans (ntohl (*p));
- p++;
+ free (rpcbuf);
+ free (buf);
+ return err;
}
+
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+
+ if (protocol_version == 3)
+ /* 'post_op_attr' is present for any value of 'err' */
+ p = process_returned_stat (dir, p, 1);
+
if (err)
{
+ free (rpcbuf);
free (buf);
return err;
}
+ if (protocol_version == 3)
+ {
+ memcpy (cookieverf, p, sizeof (cookieverf));
+ p += INTSIZE (sizeof (cookieverf));
+ }
+
isnext = ntohl (*p);
p++;
@@ -1754,8 +1935,14 @@ fetch_directory (struct iouser *cred, struct node *dir,
int namlen;
int reclen;
- fileno = ntohl (*p);
- p++;
+ if (protocol_version == 2)
+ {
+ fileno = ntohl (*p);
+ p++;
+ }
+ else
+ p = xdr_decode_64bit(p, &fileno);
+
namlen = ntohl (*p);
p++;
@@ -1790,7 +1977,8 @@ fetch_directory (struct iouser *cred, struct node *dir,
++*totalentries;
- cookie = *(p++);
+ memcpy (cookie, p, cookie_size);
+ p += INTSIZE (cookie_size);
isnext = ntohl (*p);
p++;
}