diff options
Diffstat (limited to 'nfsd/ops.c')
-rw-r--r-- | nfsd/ops.c | 405 |
1 files changed, 254 insertions, 151 deletions
@@ -1,5 +1,7 @@ -/* NFS daemon protocol operations - Copyright (C) 1996 Free Software Foundation, Inc. +/* ops.c NFS daemon protocol operations. + + Copyright (C) 1996, 2001, 2002, 2007 Free Software Foundation, Inc. + Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -24,15 +26,18 @@ #include <hurd/paths.h> #include <hurd.h> #include <dirent.h> +#include <string.h> +#include <sys/mman.h> #include "nfsd.h" -#include "../nfs/rpcsvc/mount.h" /* XXX */ +#include "../nfs/mount.h" /* XXX */ #include <rpc/pmap_prot.h> static error_t op_null (struct cache_handle *c, int *p, - int **reply) + int **reply, + int version) { return 0; } @@ -40,14 +45,15 @@ op_null (struct cache_handle *c, static error_t op_getattr (struct cache_handle *c, int *p, - int **reply) + int **reply, + int version) { struct stat st; error_t err; - + err = io_stat (c->port, &st); if (!err) - *reply = encode_fattr (*reply, &st); + *reply = encode_fattr (*reply, &st, version); return err; } @@ -65,74 +71,89 @@ complete_setattr (mach_port_t port, if (err) return err; - uid = ntohl (*p++); - gid = ntohl (*p++); - if ((uid != -1 && uid != st.st_uid) - || (gid != -1 && gid != st.st_gid)) - { - if (uid == -1) - uid = st.st_uid; - if (gid == -1) - gid = st.st_gid; - err = file_chown (port, uid, gid); - if (err) - return err; - } - - size = ntohl (*p++); + uid = ntohl (*p); + p++; + gid = ntohl (*p); + p++; + if (uid == -1) + uid = st.st_uid; + if (gid == -1) + gid = st.st_gid; + if (uid != st.st_uid || gid != st.st_gid) + err = file_chown (port, uid, gid); + if (err) + return err; + + size = ntohl (*p); + p++; if (size != -1 && size != st.st_size) err = file_set_size (port, size); if (err) return err; - - atime.seconds = ntohl (*p++); - atime.microseconds = ntohl (*p++); - mtime.seconds = ntohl (*p++); - mtime.microseconds = ntohl (*p++); + + atime.seconds = ntohl (*p); + p++; + atime.microseconds = ntohl (*p); + p++; + mtime.seconds = ntohl (*p); + p++; + mtime.microseconds = ntohl (*p); + p++; + if (atime.seconds != -1 && atime.microseconds == -1) atime.microseconds = 0; if (mtime.seconds != -1 && mtime.microseconds == -1) mtime.microseconds = 0; - if (atime.seconds != -1 || mtime.seconds != -1 - || atime.microseconds != -1 || mtime.microseconds != -1) - { - if (atime.seconds == -1) - atime.seconds = st.st_atime; - if (atime.microseconds == -1) - atime.microseconds = st.st_atime_usec; - if (mtime.seconds == -1) - mtime.seconds = st.st_mtime; - if (mtime.microseconds == -1) - mtime.microseconds = st.st_mtime_usec; - err = file_utimes (port, atime, mtime); - if (err) - return err; - } - - return 0; + + if (atime.seconds == -1) + atime.seconds = st.st_atim.tv_sec; + if (atime.microseconds == -1) + atime.microseconds = st.st_atim.tv_nsec / 1000; + if (mtime.seconds == -1) + mtime.seconds = st.st_mtim.tv_sec; + if (mtime.microseconds == -1) + mtime.microseconds = st.st_mtim.tv_nsec / 1000; + + if (atime.seconds != st.st_atim.tv_sec + || atime.microseconds != st.st_atim.tv_nsec / 1000 + || mtime.seconds != st.st_mtim.tv_sec + || mtime.microseconds != st.st_mtim.tv_nsec / 1000) + err = file_utimes (port, atime, mtime); + + return err; } static error_t op_setattr (struct cache_handle *c, int *p, - int **reply) + int **reply, + int version) { error_t err = 0; mode_t mode; + struct stat st; - mode = ntohl (*p++); + mode = ntohl (*p); + p++; if (mode != -1) err = file_chmod (c->port, mode); + + if (!err) + err = complete_setattr (c->port, p); + if (!err) + err = io_stat (c->port, &st); if (err) return err; - - return complete_setattr (c->port, p); + + *reply = encode_fattr (*reply, &st, version); + return 0; } static error_t op_lookup (struct cache_handle *c, int *p, - int **reply) + int **reply, + int version) { error_t err; char *name; @@ -143,65 +164,76 @@ op_lookup (struct cache_handle *c, struct stat st; decode_name (p, &name); - + err = dir_lookup (c->port, name, O_NOTRANS, 0, &do_retry, retry_name, &newport); free (name); - /* Block attempts to bounce out of this filesystem by any technique */ + /* Block attempts to bounce out of this filesystem by any technique. */ if (!err && (do_retry != FS_RETRY_NORMAL || retry_name[0] != '\0')) err = EACCES; - + if (!err) err = io_stat (newport, &st); - + if (err) return err; - + newc = create_cached_handle (*(int *)c->handle, c, newport); if (!newc) return ESTALE; *reply = encode_fhandle (*reply, newc->handle); - *reply = encode_fattr (*reply, &st); + *reply = encode_fattr (*reply, &st, version); return 0; } static error_t op_readlink (struct cache_handle *c, int *p, - int **reply) + int **reply, + int version) { char buf[2048], *transp = buf; mach_msg_type_number_t len = sizeof (buf); error_t err; - - /* Shamelessly copied from the libc readlink */ + + /* Shamelessly copied from the libc readlink. */ err = file_get_translator (c->port, &transp, &len); if (err) - return err; - + { + if (transp != buf) + munmap (transp, len); + return err; + } + if (len < sizeof (_HURD_SYMLINK) || memcmp (transp, _HURD_SYMLINK, sizeof (_HURD_SYMLINK))) return EINVAL; - + transp += sizeof (_HURD_SYMLINK); - + *reply = encode_string (*reply, transp); + + if (transp != buf) + munmap (transp, len); + return 0; } static size_t -count_read_buffersize (int *p) +count_read_buffersize (int *p, int version) { - return ntohl (*++p); /* skip OFFSET, return COUNT */ + p++; /* Skip OFFSET. */ + return ntohl (*p); /* Return COUNT. */ } static error_t op_read (struct cache_handle *c, int *p, - int **reply) + int **reply, + int version) { off_t offset; size_t count; @@ -210,26 +242,37 @@ op_read (struct cache_handle *c, struct stat st; error_t err; - offset = ntohl (*p++); - count = ntohl (*p++); - + offset = ntohl (*p); + p++; + count = ntohl (*p); + p++; + err = io_read (c->port, &bp, &buflen, offset, count); if (err) - return err; - + { + if (bp != buf) + munmap (bp, buflen); + return err; + } + err = io_stat (c->port, &st); if (err) return err; - - *reply = encode_fattr (*reply, &st); + + *reply = encode_fattr (*reply, &st, version); *reply = encode_data (*reply, bp, buflen); + + if (bp != buf) + munmap (bp, buflen); + return 0; } static error_t op_write (struct cache_handle *c, int *p, - int **reply) + int **reply, + int version) { off_t offset; size_t count; @@ -239,11 +282,13 @@ op_write (struct cache_handle *c, struct stat st; p++; - offset = ntohl (*p++); + offset = ntohl (*p); + p++; + p++; + count = ntohl (*p); p++; - count = ntohl (*p++); bp = (char *) *reply; - + while (count) { err = io_write (c->port, bp, count, offset, &amt); @@ -255,20 +300,21 @@ op_write (struct cache_handle *c, bp += amt; offset += amt; } - + file_sync (c->port, 1, 0); err = io_stat (c->port, &st); if (err) return err; - *reply = encode_fattr (*reply, &st); + *reply = encode_fattr (*reply, &st, version); return 0; } static error_t op_create (struct cache_handle *c, int *p, - int **reply) + int **reply, + int version) { error_t err; char *name; @@ -278,26 +324,51 @@ op_create (struct cache_handle *c, struct cache_handle *newc; struct stat st; mode_t mode; + int statchanged = 0; + off_t size; p = decode_name (p, &name); - mode = ntohl (*p++); - - err = dir_lookup (c->port, name, O_NOTRANS | O_CREAT | O_EXCL, mode, + mode = ntohl (*p); + p++; + + err = dir_lookup (c->port, name, O_NOTRANS | O_CREAT | O_TRUNC, mode, &do_retry, retry_name, &newport); if (!err && (do_retry != FS_RETRY_NORMAL || retry_name[0] != '\0')) err = EACCES; - + if (err) return err; - err = complete_setattr (newport, p); if (!err) err = io_stat (newport, &st); + if (err) + goto errout; + + /* NetBSD ignores most of the setattr fields given; that's good enough + for me too. */ + + p++, p++; /* Skip uid and gid. */ + + size = ntohl (*p); + p++; + if (size != -1 && size != st.st_size) + { + err = file_set_size (newport, size); + statchanged = 1; + } + if (err) + goto errout; + + /* Ignore times. */ + + if (statchanged) + err = io_stat (newport, &st); if (err) { + errout: dir_unlink (c->port, name); free (name); return err; @@ -307,41 +378,43 @@ op_create (struct cache_handle *c, newc = create_cached_handle (*(int *)c->handle, c, newport); if (!newc) return ESTALE; - + *reply = encode_fhandle (*reply, newc->handle); - *reply = encode_fattr (*reply, &st); + *reply = encode_fattr (*reply, &st, version); return 0; } static error_t op_remove (struct cache_handle *c, int *p, - int **reply) + int **reply, + int version) { error_t err; char *name; - + decode_name (p, &name); - + err = dir_unlink (c->port, name); free (name); - + return 0; } static error_t op_rename (struct cache_handle *fromc, int *p, - int **reply) + int **reply, + int version) { struct cache_handle *toc; char *fromname, *toname; error_t err = 0; - + p = decode_name (p, &fromname); p = lookup_cache_handle (p, &toc, fromc->ids); decode_name (p, &toname); - + if (!toc) err = ESTALE; if (!err) @@ -354,20 +427,21 @@ op_rename (struct cache_handle *fromc, static error_t op_link (struct cache_handle *filec, int *p, - int **reply) + int **reply, + int version) { struct cache_handle *dirc; char *name; error_t err = 0; - + p = lookup_cache_handle (p, &dirc, filec->ids); decode_name (p, &name); - + if (!dirc) err = ESTALE; if (!err) err = dir_link (dirc->port, filec->port, name, 1); - + free (name); return err; } @@ -375,7 +449,8 @@ op_link (struct cache_handle *filec, static error_t op_symlink (struct cache_handle *c, int *p, - int **reply) + int **reply, + int version) { char *name, *target; error_t err; @@ -386,7 +461,8 @@ op_symlink (struct cache_handle *c, p = decode_name (p, &name); p = decode_name (p, &target); - mode = ntohl (*p++); + mode = ntohl (*p); + p++; if (mode == -1) mode = 0777; @@ -416,7 +492,8 @@ op_symlink (struct cache_handle *c, static error_t op_mkdir (struct cache_handle *c, int *p, - int **reply) + int **reply, + int version) { char *name; mode_t mode; @@ -428,8 +505,9 @@ op_mkdir (struct cache_handle *c, error_t err; p = decode_name (p, &name); - mode = ntohl (*p++); - + mode = ntohl (*p); + p++; + err = dir_mkdir (c->port, name, mode); if (err) @@ -437,7 +515,7 @@ op_mkdir (struct cache_handle *c, free (name); return err; } - + err = dir_lookup (c->port, name, O_NOTRANS, 0, &do_retry, retry_name, &newport); free (name); @@ -447,29 +525,31 @@ op_mkdir (struct cache_handle *c, err = EACCES; if (err) return err; - - err = complete_setattr (newport, p); + + /* Ignore the rest of the sattr structure. */ + if (!err) err = io_stat (newport, &st); if (err) return err; - + newc = create_cached_handle (*(int *)c->handle, c, newport); if (!newc) return ESTALE; *reply = encode_fhandle (*reply, newc->handle); - *reply = encode_fattr (*reply, &st); + *reply = encode_fattr (*reply, &st, version); return 0; } static error_t op_rmdir (struct cache_handle *c, int *p, - int **reply) + int **reply, + int version) { char *name; error_t err; - + decode_name (p, &name); err = dir_rmdir (c->port, name); @@ -480,7 +560,8 @@ op_rmdir (struct cache_handle *c, static error_t op_readdir (struct cache_handle *c, int *p, - int **reply) + int **reply, + int version) { int cookie; unsigned count; @@ -491,20 +572,29 @@ op_readdir (struct cache_handle *c, int nentries; int i; int *replystart; + int *r; - cookie = ntohl (*p++); - count = ntohl (*p++); + cookie = ntohl (*p); + p++; + count = ntohl (*p); + p++; - buf = alloca (count); - bufsize = count; + buf = (char *) 0; + bufsize = 0; err = dir_readdir (c->port, &buf, &bufsize, cookie, -1, count, &nentries); if (err) - return err; + { + if (buf) + munmap (buf, bufsize); + return err; + } + + r = *reply; if (nentries == 0) { - *(*reply)++ = htonl (0); /* no entry */ - *(*reply)++ = htonl (1); /* EOF */ + *(r++) = htonl (0); /* No entry. */ + *(r++) = htonl (1); /* EOF. */ } else { @@ -514,31 +604,39 @@ op_readdir (struct cache_handle *c, && (char *)reply < (char *)replystart + count); i++, dp = (struct dirent *) ((char *)dp + dp->d_reclen)) { - *(*reply)++ = htonl (1); /* entry present */ - *(*reply)++ = htonl (dp->d_ino); - *reply = encode_string (*reply, dp->d_name); - *(*reply)++ = htonl (i + cookie + 1); /* next entry */ + *(r++) = htonl (1); /* Entry present. */ + *(r++) = htonl (dp->d_ino); + r = encode_string (r, dp->d_name); + *(r++) = htonl (i + cookie + 1); /* Next entry. */ } - *(*reply)++ = htonl (0); /* not EOF */ + *(r++) = htonl (0); /* No more entries. */ + *(r++) = htonl (0); /* Not EOF. */ } - + + *reply = r; + + if (buf) + munmap (buf, bufsize); + return 0; } -static size_t -count_readdir_buffersize (int *p) +static size_t +count_readdir_buffersize (int *p, int version) { - return ntohl (*++p); /* skip COOKIE; return COUNT */ + p++; /* Skip COOKIE. */ + return ntohl (*p); /* Return COUNT. */ } static error_t op_statfs (struct cache_handle *c, int *p, - int **reply) + int **reply, + int version) { struct statfs st; error_t err; - + err = file_statfs (c->port, &st); if (!err) *reply = encode_statfs (*reply, &st); @@ -548,14 +646,15 @@ op_statfs (struct cache_handle *c, static error_t op_mnt (struct cache_handle *c, int *p, - int **reply) + int **reply, + int version) { file_t root; struct cache_handle *newc; char *name; - + decode_name (p, &name); - + root = file_name_lookup (name, 0, 0); if (!root) { @@ -574,14 +673,18 @@ op_mnt (struct cache_handle *c, static error_t op_getport (struct cache_handle *c, int *p, - int **reply) + int **reply, + int version) { int prog, vers, prot; - - prog = ntohl (*p++); - vers = ntohl (*p++); - prot = ntohl (*p++); - + + prog = ntohl (*p); + p++; + vers = ntohl (*p); + p++; + prot = ntohl (*p); + p++; + if (prot != IPPROTO_UDP) *(*reply)++ = htonl (0); else if ((prog == MOUNTPROG && vers == MOUNTVERS) @@ -591,24 +694,24 @@ op_getport (struct cache_handle *c, *(*reply)++ = htonl (PMAPPORT); else *(*reply)++ = 0; - + return 0; } -struct proctable nfstable = +struct proctable nfs2table = { - NFSPROC_NULL, /* first proc */ - NFSPROC_STATFS, /* last proc */ + NFS2PROC_NULL, /* First proc. */ + NFS2PROC_STATFS, /* Last proc. */ { { op_null, 0, 0, 0}, { op_getattr, 0, 1, 1}, { op_setattr, 0, 1, 1}, - { 0, 0, 0, 0 }, /* deprecated NFSPROC_ROOT */ + { 0, 0, 0, 0 }, /* Deprecated NFSPROC_ROOT. */ { op_lookup, 0, 1, 1}, { op_readlink, 0, 1, 1}, { op_read, count_read_buffersize, 1, 1}, - { 0, 0, 0, 0 }, /* nonexistent NFSPROC_WRITECACHE */ + { 0, 0, 0, 0 }, /* Nonexistent NFSPROC_WRITECACHE. */ { op_write, 0, 1, 1}, { op_create, 0, 1, 1}, { op_remove, 0, 1, 1}, @@ -622,25 +725,25 @@ struct proctable nfstable = } }; - + struct proctable mounttable = { - MOUNTPROC_NULL, /* first proc */ - MOUNTPROC_EXPORT, /* last proc */ + MOUNTPROC_NULL, /* First proc. */ + MOUNTPROC_EXPORT, /* Last proc. */ { { op_null, 0, 0, 0}, { op_mnt, 0, 0, 1}, { 0, 0, 0, 0}, /* MOUNTPROC_DUMP */ - { 0, 0, 0, 0}, /* MOUNTPROC_UMNT */ - { 0, 0, 0, 0}, /* MOUNTPROC_UMNTALL */ + { op_null, 0, 0, 0}, /* MOUNTPROC_UMNT */ + { op_null, 0, 0, 0}, /* MOUNTPROC_UMNTALL */ { 0, 0, 0, 0}, /* MOUNTPROC_EXPORT */ } }; -struct proctable pmaptable = +struct proctable pmaptable = { - PMAPPROC_NULL, /* first proc */ - PMAPPROC_CALLIT, /* last proc */ + PMAPPROC_NULL, /* First proc. */ + PMAPPROC_CALLIT, /* Last proc. */ { { op_null, 0, 0, 0}, { 0, 0, 0, 0}, /* PMAPPROC_SET */ |