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 <cbodley@umich.edu>
This commit is contained in:
Casey Bodley 2010-10-12 09:44:07 -04:00
parent a8eca1ca7b
commit 8172b5f581
2 changed files with 67 additions and 35 deletions

View file

@ -27,8 +27,10 @@
#include "nfs41_compound.h" #include "nfs41_compound.h"
#include "nfs41_ops.h" #include "nfs41_ops.h"
#include "nfs41_xdr.h" #include "nfs41_xdr.h"
#include "util.h"
#include "daemon_debug.h" #include "daemon_debug.h"
static bool_t encode_file_attrs( static bool_t encode_file_attrs(
fattr4 *attrs, fattr4 *attrs,
nfs41_file_info *info); nfs41_file_info *info);
@ -95,22 +97,38 @@ static bool_t xdr_nfstime4(
/* settime4 */ /* settime4 */
static uint32_t settime_how(
nfstime4 *newtime,
const nfstime4 *time_delta)
{
nfstime4 current;
get_nfs_time(&current);
/* get the absolute difference between current and newtime */
nfstime_diff(&current, newtime, &current);
nfstime_abs(&current, &current);
/* compare the difference with time_delta */
nfstime_diff(time_delta, &current, &current);
/* 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( static bool_t xdr_settime4(
XDR *xdr, XDR *xdr,
nfstime4 *nt) nfstime4 *nt,
const nfstime4 *time_delta)
{ {
if (xdr->x_op == XDR_ENCODE) { uint32_t how = settime_how(nt, time_delta);
uint32_t send_value = SET_TO_CLIENT_TIME4;
if (!xdr_u_int32_t(xdr, &send_value)) if (xdr->x_op != XDR_ENCODE) /* not used for decode */
return FALSE;
} else if (xdr->x_op == XDR_DECODE) {
uint32_t ignored_value;
if (!xdr_u_int32_t(xdr, &ignored_value))
return FALSE;
} else
return FALSE; 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 */ /* stateid4 */
@ -2334,7 +2352,7 @@ static bool_t encode_file_attrs(
attrs->attrmask.arr[1] |= FATTR4_WORD1_MODE; attrs->attrmask.arr[1] |= FATTR4_WORD1_MODE;
} }
if (info->attrmask.arr[1] & FATTR4_WORD1_TIME_ACCESS_SET) { 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; return FALSE;
attrs->attrmask.arr[1] |= FATTR4_WORD1_TIME_ACCESS_SET; 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; attrs->attrmask.arr[1] |= FATTR4_WORD1_TIME_CREATE;
} }
if (info->attrmask.arr[1] & FATTR4_WORD1_TIME_MODIFY_SET) { 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; return FALSE;
attrs->attrmask.arr[1] |= FATTR4_WORD1_TIME_MODIFY_SET; attrs->attrmask.arr[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
} }

View file

@ -98,12 +98,12 @@ static void remove_unsupported_attrs(
static int handle_nfs41_setattr(setattr_upcall_args *args) static int handle_nfs41_setattr(setattr_upcall_args *args)
{ {
int status;
PFILE_BASIC_INFO basic_info = (PFILE_BASIC_INFO)args->buf; PFILE_BASIC_INFO basic_info = (PFILE_BASIC_INFO)args->buf;
nfs41_open_state *state = args->state; nfs41_open_state *state = args->state;
nfs41_superblock *superblock = state->file.fh.superblock; nfs41_superblock *superblock = state->file.fh.superblock;
stateid4 stateid, *pstateid; stateid4 stateid, *pstateid;
nfs41_file_info info; nfs41_file_info info;
int status = NO_ERROR;
pstateid = nfs41_lock_stateid_copy(&state->last_lock, &stateid); pstateid = nfs41_lock_stateid_copy(&state->last_lock, &stateid);
if (pstateid == NULL) 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.hidden = basic_info->FileAttributes & FILE_ATTRIBUTE_HIDDEN ? 1 : 0;
info.attrmask.arr[0] |= FATTR4_WORD0_HIDDEN; info.attrmask.arr[0] |= FATTR4_WORD0_HIDDEN;
info.attrmask.count = 1; info.attrmask.count = 1;
/* time_create */
if (basic_info->CreationTime.QuadPart > 0) { if (superblock->cansettime) {
file_time_to_nfs_time(&basic_info->CreationTime, &info.time_create); /* set the time_delta so xdr_settime4() can decide
info.attrmask.arr[1] |= FATTR4_WORD1_TIME_CREATE; * whether or not to use SET_TO_SERVER_TIME4 */
info.attrmask.count = 2; info.time_delta = &superblock->time_delta;
}
/* time_access_set */ /* time_create */
if (basic_info->LastAccessTime.QuadPart > 0) { if (basic_info->CreationTime.QuadPart > 0) {
file_time_to_nfs_time(&basic_info->LastAccessTime, &info.time_access); file_time_to_nfs_time(&basic_info->CreationTime,
info.attrmask.arr[1] |= FATTR4_WORD1_TIME_ACCESS_SET; &info.time_create);
info.attrmask.count = 2; info.attrmask.arr[1] |= FATTR4_WORD1_TIME_CREATE;
} info.attrmask.count = 2;
/* time_modify_set */ }
if (basic_info->LastWriteTime.QuadPart > 0) { /* time_access_set */
file_time_to_nfs_time(&basic_info->LastWriteTime, &info.time_modify); if (basic_info->LastAccessTime.QuadPart > 0) {
info.attrmask.arr[1] |= FATTR4_WORD1_TIME_MODIFY_SET; file_time_to_nfs_time(&basic_info->LastAccessTime,
info.attrmask.count = 2; &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 */ /* mode */
if (basic_info->FileAttributes & FILE_ATTRIBUTE_READONLY) { if (basic_info->FileAttributes & FILE_ATTRIBUTE_READONLY) {
info.mode = 0444; info.mode = 0444;
@ -140,19 +151,22 @@ static int handle_nfs41_setattr(setattr_upcall_args *args)
info.attrmask.count = 2; info.attrmask.count = 2;
} }
/* only ask for attributes that are supported by the filesystem */
AcquireSRWLockShared(&superblock->lock); AcquireSRWLockShared(&superblock->lock);
remove_unsupported_attrs(&superblock->supported_attrs, &info.attrmask); remove_unsupported_attrs(&superblock->supported_attrs, &info.attrmask);
ReleaseSRWLockShared(&superblock->lock); ReleaseSRWLockShared(&superblock->lock);
if (!info.attrmask.count) if (!info.attrmask.count)
return 0; goto out;
status = nfs41_setattr(state->session, &state->file, pstateid, &info); status = nfs41_setattr(state->session, &state->file, pstateid, &info);
if (status) if (status) {
dprintf(1, "nfs41_setattr() failed with error %s.\n", dprintf(1, "nfs41_setattr() failed with error %s.\n",
nfs_error_string(status)); nfs_error_string(status));
status = nfs_to_windows_error(status, ERROR_NOT_SUPPORTED);
return nfs_to_windows_error(status, ERROR_NOT_SUPPORTED); }
out:
return status;
} }
static int handle_nfs41_remove(setattr_upcall_args *args) static int handle_nfs41_remove(setattr_upcall_args *args)