diff --git a/daemon/nfs41_ops.c b/daemon/nfs41_ops.c index 268ef4d..81bf06e 100644 --- a/daemon/nfs41_ops.c +++ b/daemon/nfs41_ops.c @@ -1385,7 +1385,8 @@ int nfs41_link( IN nfs41_path_fh *src, IN nfs41_path_fh *dst_dir, IN const nfs41_component *target, - OUT OPTIONAL nfs41_path_fh *link_out) + OUT OPTIONAL nfs41_path_fh *link_out, + OUT nfs41_file_info *cinfo) { int status; nfs41_compound compound; @@ -1403,15 +1404,15 @@ int nfs41_link( nfs41_getfh_res getfh_res; nfs41_getattr_args getattr_args[2]; nfs41_getattr_res getattr_res[2]; - nfs41_file_info info[2] = { 0 }; + nfs41_file_info info = { 0 }; nfs41_path_fh file; if (link_out == NULL) link_out = &file; - init_getattr_request(&info[0].attrmask); - init_getattr_request(&info[1].attrmask); - info[1].attrmask.arr[0] |= FATTR4_WORD0_FSID; + init_getattr_request(&info.attrmask); + init_getattr_request(&cinfo->attrmask); + cinfo->attrmask.arr[0] |= FATTR4_WORD0_FSID; compound_init(&compound, argops, resops, "link"); @@ -1437,9 +1438,9 @@ int nfs41_link( /* GETATTR(dst_dir) */ compound_add_op(&compound, OP_GETATTR, &getattr_args[0], &getattr_res[0]); - getattr_args[0].attr_request = &info[0].attrmask; + getattr_args[0].attr_request = &info.attrmask; getattr_res[0].obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; - getattr_res[0].info = &info[0]; + getattr_res[0].info = &info; /* LOOKUP(target) */ compound_add_op(&compound, OP_LOOKUP, &lookup_args, &lookup_res); @@ -1447,9 +1448,9 @@ int nfs41_link( /* GETATTR(target) */ compound_add_op(&compound, OP_GETATTR, &getattr_args[1], &getattr_res[1]); - getattr_args[1].attr_request = &info[1].attrmask; + getattr_args[1].attr_request = &cinfo->attrmask; getattr_res[1].obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; - getattr_res[1].info = &info[1]; + getattr_res[1].info = cinfo; /* GETFH(target) */ compound_add_op(&compound, OP_GETFH, NULL, &getfh_res); @@ -1463,25 +1464,25 @@ int nfs41_link( goto out; /* fill in the file handle's fileid and superblock */ - link_out->fh.fileid = info[1].fileid; + link_out->fh.fileid = cinfo->fileid; status = nfs41_superblock_for_fh(session, - &info[1].fsid, &dst_dir->fh, link_out); + &cinfo->fsid, &dst_dir->fh, link_out); if (status) goto out; /* update the attributes of the destination directory */ - memcpy(&info[0].attrmask, &getattr_res[0].obj_attributes.attrmask, + memcpy(&info.attrmask, &getattr_res[0].obj_attributes.attrmask, sizeof(bitmap4)); nfs41_attr_cache_update(session_name_cache(session), - info[0].fileid, &info[0]); + info.fileid, &info); /* add the new file handle and attributes to the name cache */ - memcpy(&info[1].attrmask, &getattr_res[1].obj_attributes.attrmask, + memcpy(&cinfo->attrmask, &getattr_res[1].obj_attributes.attrmask, sizeof(bitmap4)); AcquireSRWLockShared(&dst_dir->path->lock); nfs41_name_cache_insert(session_name_cache(session), dst_dir->path->path, target, &link_out->fh, - &info[1], &link_res.cinfo, OPEN_DELEGATE_NONE); + cinfo, &link_res.cinfo, OPEN_DELEGATE_NONE); ReleaseSRWLockShared(&dst_dir->path->lock); nfs41_superblock_space_changed(dst_dir->fh.superblock); diff --git a/daemon/nfs41_ops.h b/daemon/nfs41_ops.h index ca2204f..696cc84 100644 --- a/daemon/nfs41_ops.h +++ b/daemon/nfs41_ops.h @@ -1170,7 +1170,8 @@ int nfs41_link( IN nfs41_path_fh *src, IN nfs41_path_fh *dst_dir, IN const nfs41_component *target, - OUT OPTIONAL nfs41_path_fh *link_out); + OUT OPTIONAL nfs41_path_fh *link_out, + OUT nfs41_file_info *cinfo); /* symlink.c */ int nfs41_symlink_target( diff --git a/daemon/setattr.c b/daemon/setattr.c index b6df221..3d2bfb3 100644 --- a/daemon/setattr.c +++ b/daemon/setattr.c @@ -127,6 +127,7 @@ static int handle_nfs41_setattr(setattr_upcall_args *args) nfs_error_string(status)); status = nfs_to_windows_error(status, ERROR_NOT_SUPPORTED); } + args->ctime = info.change; out: return status; } @@ -355,6 +356,7 @@ static int handle_nfs41_set_size(setattr_upcall_args *args) AcquireSRWLockExclusive(&state->lock); state->pnfs_last_offset = info.size ? info.size - 1 : 0; ReleaseSRWLockExclusive(&state->lock); + args->ctime = info.change; out: return status = nfs_to_windows_error(status, ERROR_NOT_SUPPORTED); } @@ -368,6 +370,7 @@ static int handle_nfs41_link(setattr_upcall_args *args) nfs41_path_fh dst_dir, dst; nfs41_component dst_name; uint32_t depth = 0; + nfs41_file_info info = { 0 }; int status; dst_path.len = (unsigned short)WideCharToMultiByte(CP_UTF8, 0, @@ -449,12 +452,13 @@ static int handle_nfs41_link(setattr_upcall_args *args) OPEN_DELEGATE_READ, FALSE); status = nfs41_link(state->session, &state->file, - &dst_dir, &dst_name, NULL); + &dst_dir, &dst_name, NULL, &info); if (status) { dprintf(1, "nfs41_link() failed with error %s.\n", nfs_error_string(status)); status = nfs_to_windows_error(status, ERROR_INVALID_PARAMETER); } + args->ctime = info.change; out: return status; } @@ -491,6 +495,11 @@ static int handle_setattr(nfs41_upcall *upcall) return status; } +static int marshall_setattr(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall) +{ + setattr_upcall_args *args = &upcall->args.setattr; + return safe_write(&buffer, length, &args->ctime, sizeof(args->ctime)); +} /* NFS41_EA_SET */ static int parse_setexattr(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) @@ -548,6 +557,7 @@ static int handle_setexattr(nfs41_upcall *upcall) nfs_error_string(status)); return nfs_to_windows_error(status, ERROR_NOT_SUPPORTED); } + args->ctime = info.change; } else { status = nfs41_rpc_openattr(state->session, &state->file, TRUE, &parent.fh); if (status) { @@ -612,12 +622,19 @@ out: return status; } +static int marshall_setexattr(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall) +{ + setexattr_upcall_args *args = &upcall->args.setexattr; + return safe_write(&buffer, length, &args->ctime, sizeof(args->ctime)); +} const nfs41_upcall_op nfs41_op_setattr = { parse_setattr, - handle_setattr + handle_setattr, + marshall_setattr }; const nfs41_upcall_op nfs41_op_setexattr = { parse_setexattr, - handle_setexattr + handle_setexattr, + marshall_setexattr }; diff --git a/daemon/upcall.h b/daemon/upcall.h index 12fe3ee..f2b9742 100644 --- a/daemon/upcall.h +++ b/daemon/upcall.h @@ -107,6 +107,7 @@ typedef struct __setattr_upcall_args { unsigned char *buf; uint32_t buf_len; int set_class; + ULONGLONG ctime; } setattr_upcall_args; typedef struct __getexattr_upcall_args { @@ -126,6 +127,7 @@ typedef struct __setexattr_upcall_args { unsigned char *buf; uint32_t buf_len; uint32_t mode; + ULONGLONG ctime; } setexattr_upcall_args; typedef struct __readdir_upcall_args { diff --git a/sys/nfs41_driver.c b/sys/nfs41_driver.c index 21548b5..cf117aa 100644 --- a/sys/nfs41_driver.c +++ b/sys/nfs41_driver.c @@ -202,12 +202,14 @@ typedef struct _updowncall_entry { PVOID buf; ULONG buf_len; FILE_INFORMATION_CLASS InfoClass; + ULONGLONG ChangeTime; } SetFile; struct { PUNICODE_STRING filename; PVOID buf; ULONG buf_len; DWORD mode; + ULONGLONG ChangeTime; } SetEa; struct { PUNICODE_STRING filename; @@ -1534,6 +1536,15 @@ void unmarshal_nfs41_mount( cur->version); } +VOID unmarshal_nfs41_setattr( + nfs41_updowncall_entry *cur, + PULONGLONG dest_buf, + unsigned char **buf) +{ + RtlCopyMemory(dest_buf, *buf, sizeof(ULONGLONG)); + DbgP("[setattr] returned ChangeTime %llu\n", *dest_buf); +} + NTSTATUS unmarshal_nfs41_rw( nfs41_updowncall_entry *cur, unsigned char **buf) @@ -1804,6 +1815,12 @@ NTSTATUS nfs41_downcall( case NFS41_ACL_QUERY: status = unmarshal_nfs41_getacl(cur, &buf); break; + case NFS41_FILE_SET: + unmarshal_nfs41_setattr(cur, &cur->u.SetFile.ChangeTime, &buf); + break; + case NFS41_EA_SET: + unmarshal_nfs41_setattr(cur, &cur->u.SetEa.ChangeTime, &buf); + break; } } DbgP("[downcall] About to signal waiting IO thread\n");