diff options
author | Michael Kelly <mike@weatherwax.co.uk> | 2025-07-20 14:19:11 +0200 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2025-07-20 14:19:11 +0200 |
commit | 529b93b8f6cc94830325cfde1b237f0ca04af38e (patch) | |
tree | 2d1319b3725a1481737bf4f553173d3d8236d302 | |
parent | 2c39bb58dfbcc018d2f2104d60733e6cf6be4adc (diff) |
nfs: fix the handling of replies to MKNOD and SYMLINK
The Linux NFS server does not accept a setting of file size to 0 for
sockets and FIFOs so there is code to strip that for those cases. I also
spotted that the file modification times were not being applied to a
created file so there is now just one rpc to set all file attributes using
xdr_encode_create_state(). This sets the times to be server time which is
appropriate for a new file (even though it was created in the previous RPC
call). The previous code was supplying the 'gid' based on that returned by
the 'stat' but I don't think that can be relied on since the V3 protocol
states that CREATE3 using EXCLUSIVE cannot guarantee any file attributes
until after the SETATTR3.
-rw-r--r-- | nfs/nfs.c | 32 | ||||
-rw-r--r-- | nfs/ops.c | 52 |
2 files changed, 47 insertions, 37 deletions
@@ -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); @@ -1056,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) @@ -1068,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. */ @@ -1101,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; @@ -1213,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); } @@ -1381,13 +1361,15 @@ netfs_attempt_create_file (struct iouser *cred, struct node *np, else err = process_create_reply (cred, np, name, newnp, p); - if (*newnp && !netfs_validate_stat (*newnp, (struct iouser *) -1)) + if (protocol_version == 3 && !err) { - if ((*newnp)->nn_stat.st_uid != owner) - err = netfs_attempt_chown ((struct iouser *) -1, *newnp, owner, (*newnp)->nn_stat.st_gid); + int *_cs_sattr_encoder (int * sp) + { + return xdr_encode_create_state (sp, mode, owner); + } - if (!err && (*newnp)->nn_stat.st_mode != mode) - err = netfs_attempt_chmod (cred, *newnp, mode); + err = nfs_setattr_rpc(cred, *newnp, -1, _cs_sattr_encoder); + /* Unlink *newnp if err ? */ } } |