diff options
Diffstat (limited to 'nfs')
-rw-r--r-- | nfs/main.c | 36 | ||||
-rw-r--r-- | nfs/mount.c | 60 | ||||
-rw-r--r-- | nfs/nfs-spec.h | 4 | ||||
-rw-r--r-- | nfs/nfs.c | 34 | ||||
-rw-r--r-- | nfs/ops.c | 538 |
5 files changed, 476 insertions, 196 deletions
@@ -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 @@ -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); } @@ -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++; } |