summaryrefslogtreecommitdiff
path: root/nfs/nfs.c
diff options
context:
space:
mode:
authorMichael Kelly <mike@weatherwax.co.uk>2025-07-20 14:19:11 +0200
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2025-07-20 14:19:11 +0200
commit529b93b8f6cc94830325cfde1b237f0ca04af38e (patch)
tree2d1319b3725a1481737bf4f553173d3d8236d302 /nfs/nfs.c
parent2c39bb58dfbcc018d2f2104d60733e6cf6be4adc (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.
Diffstat (limited to 'nfs/nfs.c')
-rw-r--r--nfs/nfs.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/nfs/nfs.c b/nfs/nfs.c
index 313c1e4a..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);