From 529b93b8f6cc94830325cfde1b237f0ca04af38e Mon Sep 17 00:00:00 2001 From: Michael Kelly Date: Sun, 20 Jul 2025 14:19:11 +0200 Subject: 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. --- nfs/nfs.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) (limited to 'nfs/nfs.c') 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 #include +#include #include #include @@ -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); -- cgit v1.2.3