From 8172b5f581fa4def265f803efd07187d609ac792 Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Tue, 12 Oct 2010 09:44:07 -0400 Subject: [PATCH] timestamps: setattr uses attributes cansettime,time_delta added time_delta argument to xdr_settime4(). if the normal 'time' argument is within time_delta of the current time (get_nfs_time()), it uses time_how=SET_TO_SERVER_TIME4. otherwise, it uses SET_TO_CLIENT_TIME4 and encodes the time as usual handle_nfs41_setattr() ignores times if superblock->cansettime==0. otherwise, it passes in superblock->time_delta (via info.time_delta) along with the other time attributes, for use with xdr_settime4() Signed-off-by: Casey Bodley --- daemon/nfs41_xdr.c | 44 ++++++++++++++++++++++++----------- daemon/setattr.c | 58 ++++++++++++++++++++++++++++------------------ 2 files changed, 67 insertions(+), 35 deletions(-) diff --git a/daemon/nfs41_xdr.c b/daemon/nfs41_xdr.c index 7699837..1ce8cdf 100644 --- a/daemon/nfs41_xdr.c +++ b/daemon/nfs41_xdr.c @@ -27,8 +27,10 @@ #include "nfs41_compound.h" #include "nfs41_ops.h" #include "nfs41_xdr.h" +#include "util.h" #include "daemon_debug.h" + static bool_t encode_file_attrs( fattr4 *attrs, nfs41_file_info *info); @@ -95,22 +97,38 @@ static bool_t xdr_nfstime4( /* settime4 */ +static uint32_t settime_how( + nfstime4 *newtime, + const nfstime4 *time_delta) +{ + nfstime4 current; + get_nfs_time(¤t); + /* get the absolute difference between current and newtime */ + nfstime_diff(¤t, newtime, ¤t); + nfstime_abs(¤t, ¤t); + /* compare the difference with time_delta */ + nfstime_diff(time_delta, ¤t, ¤t); + /* use client time if diff > delta (i.e. time_delta - current < 0) */ + return current.seconds < 0 ? SET_TO_CLIENT_TIME4 : SET_TO_SERVER_TIME4; +} + static bool_t xdr_settime4( XDR *xdr, - nfstime4 *nt) + nfstime4 *nt, + const nfstime4 *time_delta) { - if (xdr->x_op == XDR_ENCODE) { - uint32_t send_value = SET_TO_CLIENT_TIME4; - if (!xdr_u_int32_t(xdr, &send_value)) - return FALSE; - } else if (xdr->x_op == XDR_DECODE) { - uint32_t ignored_value; - if (!xdr_u_int32_t(xdr, &ignored_value)) - return FALSE; - } else + uint32_t how = settime_how(nt, time_delta); + + if (xdr->x_op != XDR_ENCODE) /* not used for decode */ return FALSE; - return xdr_nfstime4(xdr, nt); + if (!xdr_u_int32_t(xdr, &how)) + return FALSE; + + if (how == SET_TO_CLIENT_TIME4) + return xdr_nfstime4(xdr, nt); + + return TRUE; } /* stateid4 */ @@ -2334,7 +2352,7 @@ static bool_t encode_file_attrs( attrs->attrmask.arr[1] |= FATTR4_WORD1_MODE; } if (info->attrmask.arr[1] & FATTR4_WORD1_TIME_ACCESS_SET) { - if (!xdr_settime4(&localxdr, &info->time_access)) + if (!xdr_settime4(&localxdr, &info->time_access, info->time_delta)) return FALSE; attrs->attrmask.arr[1] |= FATTR4_WORD1_TIME_ACCESS_SET; } @@ -2344,7 +2362,7 @@ static bool_t encode_file_attrs( attrs->attrmask.arr[1] |= FATTR4_WORD1_TIME_CREATE; } if (info->attrmask.arr[1] & FATTR4_WORD1_TIME_MODIFY_SET) { - if (!xdr_settime4(&localxdr, &info->time_modify)) + if (!xdr_settime4(&localxdr, &info->time_modify, info->time_delta)) return FALSE; attrs->attrmask.arr[1] |= FATTR4_WORD1_TIME_MODIFY_SET; } diff --git a/daemon/setattr.c b/daemon/setattr.c index b065448..181d021 100644 --- a/daemon/setattr.c +++ b/daemon/setattr.c @@ -98,12 +98,12 @@ static void remove_unsupported_attrs( static int handle_nfs41_setattr(setattr_upcall_args *args) { - int status; PFILE_BASIC_INFO basic_info = (PFILE_BASIC_INFO)args->buf; nfs41_open_state *state = args->state; nfs41_superblock *superblock = state->file.fh.superblock; stateid4 stateid, *pstateid; nfs41_file_info info; + int status = NO_ERROR; pstateid = nfs41_lock_stateid_copy(&state->last_lock, &stateid); if (pstateid == NULL) @@ -115,24 +115,35 @@ static int handle_nfs41_setattr(setattr_upcall_args *args) info.hidden = basic_info->FileAttributes & FILE_ATTRIBUTE_HIDDEN ? 1 : 0; info.attrmask.arr[0] |= FATTR4_WORD0_HIDDEN; info.attrmask.count = 1; - /* time_create */ - if (basic_info->CreationTime.QuadPart > 0) { - file_time_to_nfs_time(&basic_info->CreationTime, &info.time_create); - info.attrmask.arr[1] |= FATTR4_WORD1_TIME_CREATE; - info.attrmask.count = 2; - } - /* time_access_set */ - if (basic_info->LastAccessTime.QuadPart > 0) { - file_time_to_nfs_time(&basic_info->LastAccessTime, &info.time_access); - info.attrmask.arr[1] |= FATTR4_WORD1_TIME_ACCESS_SET; - info.attrmask.count = 2; - } - /* time_modify_set */ - if (basic_info->LastWriteTime.QuadPart > 0) { - file_time_to_nfs_time(&basic_info->LastWriteTime, &info.time_modify); - info.attrmask.arr[1] |= FATTR4_WORD1_TIME_MODIFY_SET; - info.attrmask.count = 2; + + if (superblock->cansettime) { + /* set the time_delta so xdr_settime4() can decide + * whether or not to use SET_TO_SERVER_TIME4 */ + info.time_delta = &superblock->time_delta; + + /* time_create */ + if (basic_info->CreationTime.QuadPart > 0) { + file_time_to_nfs_time(&basic_info->CreationTime, + &info.time_create); + info.attrmask.arr[1] |= FATTR4_WORD1_TIME_CREATE; + info.attrmask.count = 2; + } + /* time_access_set */ + if (basic_info->LastAccessTime.QuadPart > 0) { + file_time_to_nfs_time(&basic_info->LastAccessTime, + &info.time_access); + info.attrmask.arr[1] |= FATTR4_WORD1_TIME_ACCESS_SET; + info.attrmask.count = 2; + } + /* time_modify_set */ + if (basic_info->LastWriteTime.QuadPart > 0) { + file_time_to_nfs_time(&basic_info->LastWriteTime, + &info.time_modify); + info.attrmask.arr[1] |= FATTR4_WORD1_TIME_MODIFY_SET; + info.attrmask.count = 2; + } } + /* mode */ if (basic_info->FileAttributes & FILE_ATTRIBUTE_READONLY) { info.mode = 0444; @@ -140,19 +151,22 @@ static int handle_nfs41_setattr(setattr_upcall_args *args) info.attrmask.count = 2; } + /* only ask for attributes that are supported by the filesystem */ AcquireSRWLockShared(&superblock->lock); remove_unsupported_attrs(&superblock->supported_attrs, &info.attrmask); ReleaseSRWLockShared(&superblock->lock); if (!info.attrmask.count) - return 0; + goto out; status = nfs41_setattr(state->session, &state->file, pstateid, &info); - if (status) + if (status) { dprintf(1, "nfs41_setattr() failed with error %s.\n", nfs_error_string(status)); - - return nfs_to_windows_error(status, ERROR_NOT_SUPPORTED); + status = nfs_to_windows_error(status, ERROR_NOT_SUPPORTED); + } +out: + return status; } static int handle_nfs41_remove(setattr_upcall_args *args)