- diff --git a/daemon/daemon_debug.c b/daemon/daemon_debug.c
- index e0b99cb..f79d37d 100644
- --- a/daemon/daemon_debug.c
- +++ b/daemon/daemon_debug.c
- @@ -490,6 +490,8 @@ const char* opcode2string(nfs41_opcodes opcode)
- NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY)
- NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_QUERY_IDMAP_INFO)
- NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_QUERY_DELEGATION_INFO)
- + NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_REQUEST_DELEGATION)
- + NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_RETURN_DELEGATION)
- NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_SET_DAEMON_DEBUGLEVEL)
- NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_SHUTDOWN)
- NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_INVALID_OPCODE1)
- diff --git a/daemon/delegation.c b/daemon/delegation.c
- index 28bbfe0..33061ff 100644
- --- a/daemon/delegation.c
- +++ b/daemon/delegation.c
- @@ -449,6 +449,36 @@ static int delegation_find(
- return status;
- }
- +int nfs41_delegation_return_file(
- + IN nfs41_session *session,
- + IN nfs41_path_fh *file)
- +{
- + nfs41_client *client = session->client;
- + nfs41_delegation_state *deleg;
- + int status;
- +
- + status = delegation_find(client, &file->fh, deleg_file_cmp, &deleg);
- + if (status)
- + return status;
- +
- + AcquireSRWLockExclusive(&deleg->lock);
- + if (deleg->status == DELEGATION_GRANTED) {
- + deleg->status = DELEGATION_RETURNING;
- + status = NFS4_OK;
- + } else {
- + while (deleg->status == DELEGATION_RETURNING)
- + SleepConditionVariableSRW(&deleg->cond, &deleg->lock, INFINITE, 0);
- + status = NFS4ERR_BADHANDLE;
- + }
- + ReleaseSRWLockExclusive(&deleg->lock);
- +
- + if (status == NFS4_OK)
- + status = delegation_return(client, deleg, FALSE, TRUE);
- +
- + nfs41_delegation_deref(deleg);
- + return status;
- +}
- +
- int nfs41_delegation_get_type(
- IN nfs41_client *client,
- IN const nfs41_fh *fh,
- diff --git a/daemon/delegation.h b/daemon/delegation.h
- index ebca425..bdb4376 100644
- --- a/daemon/delegation.h
- +++ b/daemon/delegation.h
- @@ -96,6 +96,10 @@ int nfs41_client_delegation_recall_any(
- IN bool recall_read_delegs,
- IN bool recall_write_delegs);
- +int nfs41_delegation_return_file(
- + IN nfs41_session *session,
- + IN nfs41_path_fh *file);
- +
- int nfs41_delegation_get_type(
- IN nfs41_client *client,
- IN const nfs41_fh *fh,
- diff --git a/daemon/fsctl.c b/daemon/fsctl.c
- index 936f634..4e5adac 100644
- --- a/daemon/fsctl.c
- +++ b/daemon/fsctl.c
- @@ -1405,3 +1405,132 @@ const nfs41_upcall_op nfs41_op_querydelegationinfo = {
- .marshall = marshall_querydelegationinfo,
- .arg_size = sizeof(querydelegationinfo_upcall_args)
- };
- +
- +static int parse_requestdelegation(const unsigned char *restrict buffer,
- + uint32_t length, nfs41_upcall *upcall)
- +{
- + int status;
- +
- + status = safe_read(&buffer, &length,
- + &upcall->args.requestdelegation.requested_type,
- + sizeof(upcall->args.requestdelegation.requested_type));
- + if (status) goto out;
- +
- + EASSERT(length == 0);
- +
- +out:
- + return ERROR_SUCCESS;
- +}
- +
- +static int handle_requestdelegation(void *daemon_context, nfs41_upcall *upcall)
- +{
- + nfs41_open_state *state = upcall->state_ref;
- + enum open_delegation_type4 current;
- + enum open_delegation_type4 requested = (enum open_delegation_type4)
- + upcall->args.requestdelegation.requested_type;
- + open_delegation4 delegation = { 0 };
- + nfs41_delegation_state *deleg_state = NULL;
- + deleg_claim4 claim = { CLAIM_FH, 0 };
- + uint32_t want;
- + int status;
- +
- + if ((state == NULL) || (state->session == NULL))
- + return ERROR_INVALID_HANDLE;
- + if ((requested != OPEN_DELEGATE_READ) && (requested != OPEN_DELEGATE_WRITE))
- + return ERROR_INVALID_PARAMETER;
- +
- + status = nfs41_delegation_get_type(state->session->client,
- + &state->file.fh, ¤t);
- + if (status == NFS4_OK)
- + return ERROR_ALREADY_EXISTS;
- + if (status != NFS4ERR_BADHANDLE)
- + return nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
- +
- + want = requested == OPEN_DELEGATE_READ ?
- + OPEN4_SHARE_ACCESS_WANT_READ_DELEG : OPEN4_SHARE_ACCESS_WANT_WRITE_DELEG;
- + status = nfs41_want_delegation(state->session, &state->file,
- + &claim, want, TRUE, &delegation);
- + if (status)
- + return nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
- +
- + upcall->args.requestdelegation.deleg_type = (ULONG)delegation.type;
- + upcall->args.requestdelegation.why_no_delegation =
- + delegation.type == OPEN_DELEGATE_NONE_EXT ?
- + (ULONG)delegation.why_no_delegation : 0UL;
- +
- + if ((delegation.type == OPEN_DELEGATE_READ) ||
- + (delegation.type == OPEN_DELEGATE_WRITE)) {
- + status = nfs41_delegation_granted(state->session, &state->parent,
- + &state->file, &delegation, TRUE, &deleg_state);
- + if (status)
- + return nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
- + nfs41_delegation_deref(deleg_state);
- + }
- +
- + return ERROR_SUCCESS;
- +}
- +
- +static int marshall_requestdelegation(unsigned char *restrict buffer,
- + uint32_t *restrict length, nfs41_upcall *restrict upcall)
- +{
- + int status;
- +
- + status = safe_write(&buffer, length,
- + &upcall->args.requestdelegation.deleg_type,
- + sizeof(upcall->args.requestdelegation.deleg_type));
- + if (status) goto out;
- + status = safe_write(&buffer, length,
- + &upcall->args.requestdelegation.why_no_delegation,
- + sizeof(upcall->args.requestdelegation.why_no_delegation));
- +out:
- + return status;
- +}
- +
- +const nfs41_upcall_op nfs41_op_requestdelegation = {
- + .parse = parse_requestdelegation,
- + .handle = handle_requestdelegation,
- + .marshall = marshall_requestdelegation,
- + .arg_size = sizeof(requestdelegation_upcall_args)
- +};
- +
- +static int handle_returndelegation(void *daemon_context, nfs41_upcall *upcall)
- +{
- + nfs41_open_state *state = upcall->state_ref;
- + enum open_delegation_type4 current;
- + int status;
- +
- + if ((state == NULL) || (state->session == NULL))
- + return ERROR_INVALID_HANDLE;
- +
- + status = nfs41_delegation_get_type(state->session->client,
- + &state->file.fh, ¤t);
- + if (status == NFS4ERR_BADHANDLE)
- + return ERROR_NOT_FOUND;
- + if (status)
- + return nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
- +
- + status = nfs41_delegation_return_file(state->session, &state->file);
- + if (status == NFS4ERR_BADHANDLE)
- + return ERROR_NOT_FOUND;
- + return status ?
- + nfs_to_windows_error(status, ERROR_BAD_NET_RESP) : ERROR_SUCCESS;
- +}
- +
- +static int parse_returndelegation(const unsigned char *restrict buffer,
- + uint32_t length, nfs41_upcall *upcall)
- +{
- + return (length == 0) ? ERROR_SUCCESS : ERROR_BAD_LENGTH;
- +}
- +
- +static int marshall_returndelegation(unsigned char *restrict buffer,
- + uint32_t *restrict length, nfs41_upcall *restrict upcall)
- +{
- + return ERROR_SUCCESS;
- +}
- +
- +const nfs41_upcall_op nfs41_op_returndelegation = {
- + .parse = parse_returndelegation,
- + .handle = handle_returndelegation,
- + .marshall = marshall_returndelegation,
- + .arg_size = 0
- +};
- diff --git a/daemon/nfs41_ops.h b/daemon/nfs41_ops.h
- index d3fc3b1..9772a99 100644
- --- a/daemon/nfs41_ops.h
- +++ b/daemon/nfs41_ops.h
- @@ -994,9 +994,9 @@ typedef struct __nfs41_setattr_res {
- /* OP_WANT_DELEGATION */
- typedef struct __deleg_claim4 {
- - uint32_t claim;
- + enum open_claim_type4 claim;
- /* case CLAIM_PREVIOUS: */
- - uint32_t prev_delegate_type;
- + enum open_delegation_type4 prev_delegate_type;
- } deleg_claim4;
- typedef struct __nfs41_want_delegation_args {
- diff --git a/daemon/nfs41_types.h b/daemon/nfs41_types.h
- index 6b1cf12..830926e 100644
- --- a/daemon/nfs41_types.h
- +++ b/daemon/nfs41_types.h
- @@ -148,6 +148,8 @@ typedef struct __open_delegation4 {
- stateid4 stateid;
- nfsace4 permissions;
- enum open_delegation_type4 type;
- + uint32_t why_no_delegation;
- + bool_t will_signal;
- bool_t recalled;
- } open_delegation4;
- diff --git a/daemon/nfs41_xdr.c b/daemon/nfs41_xdr.c
- index 46061a5..ceb3f18 100644
- --- a/daemon/nfs41_xdr.c
- +++ b/daemon/nfs41_xdr.c
- @@ -2340,17 +2340,15 @@ static bool_t decode_open_none_delegation4(
- XDR *xdr,
- open_delegation4 *delegation)
- {
- - enum_t why_no_deleg;
- - bool_t will_signal;
- -
- - if (!xdr_enum(xdr, (enum_t*)&why_no_deleg))
- + if (!xdr_enum(xdr, (enum_t*)&delegation->why_no_delegation))
- return FALSE;
- - switch (why_no_deleg)
- + delegation->will_signal = FALSE;
- + switch (delegation->why_no_delegation)
- {
- case WND4_CONTENTION:
- case WND4_RESOURCE:
- - return xdr_bool(xdr, &will_signal);
- + return xdr_bool(xdr, &delegation->will_signal);
- default:
- return TRUE;
- }
- @@ -3057,6 +3055,27 @@ static bool_t decode_op_setattr(
- /*
- * OP_WANT_DELEGATION
- */
- +static bool_t encode_deleg_claim4(
- + XDR *xdr,
- + deleg_claim4 *claim)
- +{
- + if (!xdr_enum(xdr, (enum_t *)&claim->claim))
- + return FALSE;
- +
- + switch (claim->claim)
- + {
- + case CLAIM_FH:
- + case CLAIM_DELEG_PREV_FH:
- + return TRUE;
- + case CLAIM_PREVIOUS:
- + return xdr_enum(xdr, (enum_t *)&claim->prev_delegate_type);
- + default:
- + eprintf("encode_deleg_claim4: unsupported claim=%d\n",
- + (int)claim->claim);
- + return FALSE;
- + }
- +}
- +
- static bool_t encode_op_want_delegation(
- XDR *xdr,
- nfs_argop4 *argop)
- @@ -3069,11 +3088,7 @@ static bool_t encode_op_want_delegation(
- if (!xdr_uint32_t(xdr, &args->want))
- return FALSE;
- - if (!xdr_uint32_t(xdr, &args->claim->claim))
- - return FALSE;
- -
- - return args->claim->claim != CLAIM_PREVIOUS ||
- - xdr_uint32_t(xdr, &args->claim->prev_delegate_type);
- + return encode_deleg_claim4(xdr, args->claim);
- }
- static bool_t decode_op_want_delegation(
- @@ -3106,8 +3121,9 @@ static bool_t decode_op_want_delegation(
- case OPEN_DELEGATE_WRITE:
- return decode_open_write_delegation4(xdr, res->delegation);
- default:
- - eprintf("decode_open_res_ok: delegation type %d not "
- - "supported.\n", res->delegation->type);
- + eprintf("decode_op_want_delegation: "
- + "delegation type=%d not supported\n",
- + (int)res->delegation->type);
- return FALSE;
- }
- }
- diff --git a/daemon/upcall.c b/daemon/upcall.c
- index 0e1f43e..ece7fed 100644
- --- a/daemon/upcall.c
- +++ b/daemon/upcall.c
- @@ -56,6 +56,8 @@ extern const nfs41_upcall_op nfs41_op_duplicatedata;
- extern const nfs41_upcall_op nfs41_op_offload_datacopy;
- extern const nfs41_upcall_op nfs41_op_queryidmapinfo;
- extern const nfs41_upcall_op nfs41_op_querydelegationinfo;
- +extern const nfs41_upcall_op nfs41_op_requestdelegation;
- +extern const nfs41_upcall_op nfs41_op_returndelegation;
- extern const nfs41_upcall_op nfs41_op_setdaemondebuglevel;
- /* |_nfs41_opcodes| and |g_upcall_op_table| must be in sync! */
- @@ -86,6 +88,8 @@ static const nfs41_upcall_op *g_upcall_op_table[] = {
- &nfs41_op_offload_datacopy,
- &nfs41_op_queryidmapinfo,
- &nfs41_op_querydelegationinfo,
- + &nfs41_op_requestdelegation,
- + &nfs41_op_returndelegation,
- &nfs41_op_setdaemondebuglevel,
- NULL, /* NFS41_SYSOP_SHUTDOWN */
- NULL
- @@ -172,12 +176,14 @@ int upcall_parse(
- if (op) {
- /*
- - * |NFS41_SYSOP_SYMLINK_GET|+|NFS41_SYSOP_UNMOUNT| has 0 payload,
- + * { |NFS41_SYSOP_SYMLINK_GET|, |NFS41_SYSOP_UNMOUNT|,
- + * |NFS41_SYSOP_FSCTL_RETURN_DELEGATION| } have a 0byte payload,
- * |NFS41_SYSOP_SET_DAEMON_DEBUGLEVEL| has a |ULONG| payload
- */
- if ((upcall_upcode != NFS41_SYSOP_SYMLINK_GET) &&
- (upcall_upcode != NFS41_SYSOP_UNMOUNT) &&
- - (upcall_upcode != NFS41_SYSOP_SET_DAEMON_DEBUGLEVEL)) {
- + (upcall_upcode != NFS41_SYSOP_SET_DAEMON_DEBUGLEVEL) &&
- + (upcall_upcode != NFS41_SYSOP_FSCTL_RETURN_DELEGATION)) {
- EASSERT_MSG(op->arg_size >= sizeof(void*),
- ("upcall->opcode=%u, op->arg_size=%ld\n",
- (unsigned int)upcall_upcode,
- @@ -187,10 +193,12 @@ int upcall_parse(
- }
- if (op && op->parse) {
- - /* |NFS41_SYSOP_UNMOUNT| has 0 payload */
- + /* Skip opcalls with 0 payload */
- if ((upcall_upcode != NFS41_SYSOP_SYMLINK_GET) &&
- (upcall_upcode != NFS41_SYSOP_UNMOUNT) &&
- - (upcall_upcode != NFS41_SYSOP_FSCTL_QUERY_DELEGATION_INFO)) {
- + (upcall_upcode != NFS41_SYSOP_FSCTL_QUERY_DELEGATION_INFO) &&
- + (upcall_upcode != NFS41_SYSOP_FSCTL_REQUEST_DELEGATION) &&
- + (upcall_upcode != NFS41_SYSOP_FSCTL_RETURN_DELEGATION)) {
- EASSERT(length > 0);
- }
- diff --git a/daemon/upcall.h b/daemon/upcall.h
- index 7baad6c..ec0bf55 100644
- --- a/daemon/upcall.h
- +++ b/daemon/upcall.h
- @@ -258,6 +258,12 @@ typedef struct __querydelegationinfo_upcall_args {
- ULONG deleg_type;
- } querydelegationinfo_upcall_args;
- +typedef struct __requestdelegation_upcall_args {
- + ULONG requested_type;
- + ULONG deleg_type;
- + ULONG why_no_delegation;
- +} requestdelegation_upcall_args;
- +
- typedef struct __setdaemondebuglevel_upcall_args {
- LONG debuglevel;
- } setdaemondebuglevel_upcall_args;
- @@ -284,6 +290,7 @@ typedef union __upcall_args {
- duplicatedata_upcall_args duplicatedata;
- queryidmapinfo_upcall_args queryidmapinfo;
- querydelegationinfo_upcall_args querydelegationinfo;
- + requestdelegation_upcall_args requestdelegation;
- setdaemondebuglevel_upcall_args setdaemondebuglevel;
- } upcall_args;
- diff --git a/include/nfs41_driver.h b/include/nfs41_driver.h
- index 1e0b7d6..726e649 100644
- --- a/include/nfs41_driver.h
- +++ b/include/nfs41_driver.h
- @@ -116,6 +116,14 @@ typedef struct _FILE_NFS41_QUERY_DELEGATION_INFORMATION {
- } FILE_NFS41_QUERY_DELEGATION_INFORMATION,
- *PFILE_NFS41_QUERY_DELEGATION_INFORMATION;
- +#define FSCTL_NFS41_REQUEST_DELEGATION \
- + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800+66, METHOD_BUFFERED, \
- + FILE_READ_DATA | FILE_WRITE_DATA)
- +
- +#define FSCTL_NFS41_RETURN_DELEGATION \
- + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800+67, METHOD_BUFFERED, \
- + FILE_READ_DATA | FILE_WRITE_DATA)
- +
- /*
- * NFS41_SYS_MAX_PATH_LEN - Maximum path length
- * Notes:
- @@ -162,11 +170,25 @@ typedef enum _nfs41_opcodes {
- NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY,
- NFS41_SYSOP_FSCTL_QUERY_IDMAP_INFO,
- NFS41_SYSOP_FSCTL_QUERY_DELEGATION_INFO,
- + NFS41_SYSOP_FSCTL_REQUEST_DELEGATION,
- + NFS41_SYSOP_FSCTL_RETURN_DELEGATION,
- NFS41_SYSOP_SET_DAEMON_DEBUGLEVEL,
- NFS41_SYSOP_SHUTDOWN,
- NFS41_SYSOP_INVALID_OPCODE1
- } nfs41_opcodes;
- +typedef enum _nfs41_why_no_delegation {
- + NFS41_WND4_NOT_WANTED = 0,
- + NFS41_WND4_CONTENTION = 1,
- + NFS41_WND4_RESOURCE = 2,
- + NFS41_WND4_NOT_SUPP_FTYPE = 3,
- + NFS41_WND4_WRITE_DELEG_NOT_SUPP_FTYPE = 4,
- + NFS41_WND4_NOT_SUPP_UPGRADE = 5,
- + NFS41_WND4_NOT_SUPP_DOWNGRADE = 6,
- + NFS41_WND4_CANCELED = 7,
- + NFS41_WND4_IS_DIR = 8
- +} nfs41_why_no_delegation;
- +
- /* Same as "daemon/nfs41_ops.h" |open_delegation_type4| */
- typedef enum _nfs41_open_delegation_type {
- NFS41_OPEN_DELEGATE_NONE = 0,
- @@ -179,6 +201,12 @@ typedef enum _nfs41_open_delegation_type {
- (((dt) == NFS41_OPEN_DELEGATE_NONE) || \
- ((dt) == NFS41_OPEN_DELEGATE_NONE_EXT))
- +typedef struct _FILE_NFS41_REQUEST_DELEGATION_RESULT {
- + nfs41_open_delegation_type DelegType;
- + nfs41_why_no_delegation WhyNoDelegation;
- +} FILE_NFS41_REQUEST_DELEGATION_RESULT,
- + *PFILE_NFS41_REQUEST_DELEGATION_RESULT;
- +
- /*
- * Same as |FILE_FS_ATTRIBUTE_INFORMATION| but with inline buffer
- * for 32 characters
- diff --git a/sys/nfs41sys_debug.c b/sys/nfs41sys_debug.c
- index 09f41fa..8739c13 100644
- --- a/sys/nfs41sys_debug.c
- +++ b/sys/nfs41sys_debug.c
- @@ -716,6 +716,8 @@ const char *opcode2string(nfs41_opcodes opcode)
- case NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY:
- return "NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY";
- case NFS41_SYSOP_FSCTL_QUERY_IDMAP_INFO: return "NFS41_SYSOP_FSCTL_QUERY_IDMAP_INFO";
- + case NFS41_SYSOP_FSCTL_REQUEST_DELEGATION: return "NFS41_SYSOP_FSCTL_REQUEST_DELEGATION";
- + case NFS41_SYSOP_FSCTL_RETURN_DELEGATION: return "NFS41_SYSOP_FSCTL_RETURN_DELEGATION";
- default: return "UNKNOWN";
- }
- }
- diff --git a/sys/nfs41sys_driver.h b/sys/nfs41sys_driver.h
- index 32e99c3..44a231c 100644
- --- a/sys/nfs41sys_driver.h
- +++ b/sys/nfs41sys_driver.h
- @@ -362,6 +362,11 @@ typedef struct _updowncall_entry {
- ULONGLONG fileid;
- ULONG deleg_type;
- } QueryDelegationInfo;
- + struct {
- + ULONG requested_type;
- + ULONG deleg_type;
- + ULONG why_no_delegation;
- + } RequestDelegation;
- struct {
- FILE_ZERO_DATA_INFORMATION setzerodata;
- } SetZeroData;
- @@ -795,6 +800,14 @@ NTSTATUS marshal_nfs41_querydelegationinfo(
- NTSTATUS unmarshal_nfs41_querydelegationinfo(
- nfs41_updowncall_entry *cur,
- const unsigned char *restrict *restrict buf);
- +NTSTATUS marshal_nfs41_requestdelegation(
- + nfs41_updowncall_entry *entry,
- + unsigned char *buf,
- + ULONG buf_len,
- + ULONG *len);
- +NTSTATUS unmarshal_nfs41_requestdelegation(
- + nfs41_updowncall_entry *cur,
- + const unsigned char *restrict *restrict buf);
- /* nfs41sys_ioctl.c */
- NTSTATUS nfs41_IoCtl(
- diff --git a/sys/nfs41sys_fsctl.c b/sys/nfs41sys_fsctl.c
- index 87040f0..e4806c8 100644
- --- a/sys/nfs41sys_fsctl.c
- +++ b/sys/nfs41sys_fsctl.c
- @@ -1794,6 +1794,169 @@ NTSTATUS unmarshal_nfs41_querydelegationinfo(
- return STATUS_SUCCESS;
- }
- +
- +static NTSTATUS nfs41_RequestDelegation(
- + IN OUT PRX_CONTEXT RxContext)
- +{
- + NTSTATUS status;
- + nfs41_updowncall_entry *entry = NULL;
- + PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
- + PNFS41_SRV_OPEN nfs41_srvopen = NFS41GetSrvOpenExtension(SrvOpen);
- + PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
- + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
- + PNFS41_NETROOT_EXTENSION pNetRootContext =
- + NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
- + XXCTL_LOWIO_COMPONENT *FsCtl =
- + &RxContext->LowIoContext.ParamsFor.FsCtl;
- + const nfs41_open_delegation_type *input;
- + PFILE_NFS41_REQUEST_DELEGATION_RESULT output;
- +
- + RxContext->IoStatusBlock.Information = 0;
- +
- + if ((FsCtl->pInputBuffer == NULL) ||
- + (FsCtl->InputBufferLength != sizeof(*input)))
- + return STATUS_INVALID_PARAMETER;
- +
- + input = (const nfs41_open_delegation_type *)FsCtl->pInputBuffer;
- + if ((*input != NFS41_OPEN_DELEGATE_READ) &&
- + (*input != NFS41_OPEN_DELEGATE_WRITE))
- + return STATUS_INVALID_PARAMETER;
- +
- + if ((FsCtl->pOutputBuffer == NULL) ||
- + (FsCtl->OutputBufferLength <
- + sizeof(FILE_NFS41_REQUEST_DELEGATION_RESULT))) {
- + RxContext->InformationToReturn =
- + sizeof(FILE_NFS41_REQUEST_DELEGATION_RESULT);
- + return STATUS_BUFFER_TOO_SMALL;
- + }
- + output = (PFILE_NFS41_REQUEST_DELEGATION_RESULT)FsCtl->pOutputBuffer;
- +
- + status = nfs41_UpcallCreate(NFS41_SYSOP_FSCTL_REQUEST_DELEGATION,
- + &nfs41_srvopen->sec_ctx,
- + pVNetRootContext->session,
- + nfs41_srvopen->nfs41_open_state,
- + pNetRootContext->nfs41d_version,
- + SrvOpen->pAlreadyPrefixedName,
- + &entry);
- + if (status)
- + goto out;
- +
- + entry->u.RequestDelegation.requested_type = (ULONG)*input;
- +
- + status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
- + if (status) {
- + /* |nfs41_downcall()| owns an abandoned entry */
- + entry = NULL;
- + goto out;
- + }
- +
- + if (entry->status != NO_ERROR) {
- + status = map_setfile_error(entry->status);
- + RxContext->CurrentIrp->IoStatus.Status = status;
- + goto out;
- + }
- +
- + output->DelegType = (nfs41_open_delegation_type)
- + entry->u.RequestDelegation.deleg_type;
- + output->WhyNoDelegation = (nfs41_why_no_delegation)
- + entry->u.RequestDelegation.why_no_delegation;
- +
- + status = RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
- + RxContext->IoStatusBlock.Information = sizeof(*output);
- +out:
- + if (entry)
- + nfs41_UpcallDestroy(entry);
- + return status;
- +}
- +
- +static NTSTATUS nfs41_ReturnDelegation(
- + IN OUT PRX_CONTEXT RxContext)
- +{
- + NTSTATUS status;
- + nfs41_updowncall_entry *entry = NULL;
- + PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
- + PNFS41_SRV_OPEN nfs41_srvopen = NFS41GetSrvOpenExtension(SrvOpen);
- + PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
- + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
- + PNFS41_NETROOT_EXTENSION pNetRootContext =
- + NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
- + XXCTL_LOWIO_COMPONENT *FsCtl =
- + &RxContext->LowIoContext.ParamsFor.FsCtl;
- +
- + RxContext->IoStatusBlock.Information = 0;
- +
- + if (FsCtl->InputBufferLength != 0)
- + return STATUS_INVALID_PARAMETER;
- +
- + status = nfs41_UpcallCreate(NFS41_SYSOP_FSCTL_RETURN_DELEGATION,
- + &nfs41_srvopen->sec_ctx,
- + pVNetRootContext->session,
- + nfs41_srvopen->nfs41_open_state,
- + pNetRootContext->nfs41d_version,
- + SrvOpen->pAlreadyPrefixedName,
- + &entry);
- + if (status)
- + goto out;
- +
- + status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
- + if (status) {
- + /* |nfs41_downcall()| owns an abandoned entry */
- + entry = NULL;
- + goto out;
- + }
- +
- + if (entry->status != NO_ERROR) {
- + status = map_setfile_error(entry->status);
- + RxContext->CurrentIrp->IoStatus.Status = status;
- + goto out;
- + }
- +
- + status = RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
- +out:
- + if (entry)
- + nfs41_UpcallDestroy(entry);
- + return status;
- +}
- +
- +NTSTATUS marshal_nfs41_requestdelegation(
- + nfs41_updowncall_entry *entry,
- + unsigned char *buf,
- + ULONG buf_len,
- + ULONG *len)
- +{
- + NTSTATUS status;
- + ULONG required;
- + unsigned char *tmp = buf;
- +
- + status = marshal_nfs41_header(entry, tmp, buf_len, len);
- + if (status)
- + return status;
- + tmp += *len;
- +
- + required = *len + sizeof(entry->u.RequestDelegation.requested_type);
- + if (required > buf_len)
- + return STATUS_INSUFFICIENT_RESOURCES;
- +
- + UPDOWNCALL_MEMCPY(tmp, &entry->u.RequestDelegation.requested_type,
- + sizeof(entry->u.RequestDelegation.requested_type));
- + tmp += sizeof(entry->u.RequestDelegation.requested_type);
- + *len = (ULONG)(tmp - buf);
- + return STATUS_SUCCESS;
- +}
- +
- +NTSTATUS unmarshal_nfs41_requestdelegation(
- + nfs41_updowncall_entry *cur,
- + const unsigned char *restrict *restrict buf)
- +{
- + UPDOWNCALL_MEMCPY(&cur->u.RequestDelegation.deleg_type, *buf,
- + sizeof(cur->u.RequestDelegation.deleg_type));
- + *buf += sizeof(cur->u.RequestDelegation.deleg_type);
- + UPDOWNCALL_MEMCPY(&cur->u.RequestDelegation.why_no_delegation, *buf,
- + sizeof(cur->u.RequestDelegation.why_no_delegation));
- + *buf += sizeof(cur->u.RequestDelegation.why_no_delegation);
- + return STATUS_SUCCESS;
- +}
- +
- NTSTATUS nfs41_FsCtl(
- IN OUT PRX_CONTEXT RxContext)
- {
- @@ -1849,6 +2012,12 @@ NTSTATUS nfs41_FsCtl(
- case FSCTL_NFS41_QUERY_DELEGATION_INFO:
- status = nfs41_QueryDelegationInfo(RxContext);
- break;
- + case FSCTL_NFS41_REQUEST_DELEGATION:
- + status = nfs41_RequestDelegation(RxContext);
- + break;
- + case FSCTL_NFS41_RETURN_DELEGATION:
- + status = nfs41_ReturnDelegation(RxContext);
- + break;
- default:
- break;
- }
- diff --git a/sys/nfs41sys_updowncall.c b/sys/nfs41sys_updowncall.c
- index 49c7768..eb81afd 100644
- --- a/sys/nfs41sys_updowncall.c
- +++ b/sys/nfs41sys_updowncall.c
- @@ -320,6 +320,13 @@ NTSTATUS handle_upcall(
- status = marshal_nfs41_querydelegationinfo(entry,
- pbOut, cbOut, len);
- break;
- + case NFS41_SYSOP_FSCTL_REQUEST_DELEGATION:
- + status = marshal_nfs41_requestdelegation(entry,
- + pbOut, cbOut, len);
- + break;
- + case NFS41_SYSOP_FSCTL_RETURN_DELEGATION:
- + status = marshal_nfs41_header(entry, pbOut, cbOut, len);
- + break;
- default:
- status = STATUS_INVALID_PARAMETER;
- print_error("handle_upcall: Unknown nfs41 ops %d\n",
- @@ -827,6 +834,10 @@ NTSTATUS nfs41_downcall(
- case NFS41_SYSOP_FSCTL_QUERY_DELEGATION_INFO:
- unmarshal_nfs41_querydelegationinfo(cur, &inbuf);
- break;
- + case NFS41_SYSOP_FSCTL_REQUEST_DELEGATION:
- + unmarshal_nfs41_requestdelegation(cur, &inbuf);
- + break;
- + case NFS41_SYSOP_FSCTL_RETURN_DELEGATION:
- case NFS41_SYSOP_SET_DAEMON_DEBUGLEVEL:
- case NFS41_SYSOP_SHUTDOWN:
- /* no unmarshal function */
- diff --git a/tests/winfsinfo1/winfsinfo.c b/tests/winfsinfo1/winfsinfo.c
- index d8859d2..dce3287 100644
- --- a/tests/winfsinfo1/winfsinfo.c
- +++ b/tests/winfsinfo1/winfsinfo.c
- @@ -1974,6 +1974,161 @@ static int fsctlnfs41querydelegationinfo(
- return EXIT_SUCCESS;
- }
- +static const char *why_no_delegation_name(ULONG why)
- +{
- + switch (why) {
- + case NFS41_WND4_NOT_WANTED: return "WND4_NOT_WANTED";
- + case NFS41_WND4_CONTENTION: return "WND4_CONTENTION";
- + case NFS41_WND4_RESOURCE: return "WND4_RESOURCE";
- + case NFS41_WND4_NOT_SUPP_FTYPE: return "WND4_NOT_SUPP_FTYPE";
- + case NFS41_WND4_WRITE_DELEG_NOT_SUPP_FTYPE:
- + return "WND4_WRITE_DELEG_NOT_SUPP_FTYPE";
- + case NFS41_WND4_NOT_SUPP_UPGRADE: return "WND4_NOT_SUPP_UPGRADE";
- + case NFS41_WND4_NOT_SUPP_DOWNGRADE: return "WND4_NOT_SUPP_DOWNGRADE";
- + case NFS41_WND4_CANCELED: return "WND4_CANCELED";
- + case NFS41_WND4_IS_DIR: return "WND4_IS_DIR";
- + default: return NULL;
- + }
- +}
- +
- +static int fsctlnfs41delegationtest(const char *progname,
- + const char *command_list, const char *filename)
- +{
- + char *commands;
- + char *saveptr = NULL;
- + char *command;
- + HANDLE hFile;
- + int retval = EXIT_FAILURE;
- + size_t command_list_len;
- + unsigned int command_number = 0;
- +
- + command_list_len = strlen(command_list);
- + commands = malloc(command_list_len + 1);
- + if (commands == NULL) {
- + (void)fprintf(stderr, "%s: malloc() failed\n", progname);
- + return EXIT_FAILURE;
- + }
- + (void)memcpy(commands, command_list, command_list_len + 1);
- +
- + hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
- + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- + if (hFile == INVALID_HANDLE_VALUE) {
- + (void)fprintf(stderr, "%s: Error opening file '%s', lasterr=%d\n",
- + progname, filename, (int)GetLastError());
- + free(commands);
- + return EXIT_FAILURE;
- + }
- +
- + command = strtok_r(commands, ",", &saveptr);
- + if (command == NULL) {
- + (void)fprintf(stderr, "%s: delegation command list is empty\n",
- + progname);
- + goto out;
- + }
- +
- + do {
- + DWORD bytes_returned = 0;
- +
- + command_number++;
- + if (!strcmp(command, "requestreaddeleg") ||
- + !strcmp(command, "requestwritedeleg")) {
- + nfs41_open_delegation_type request =
- + !strcmp(command, "requestreaddeleg") ?
- + NFS41_OPEN_DELEGATE_READ : NFS41_OPEN_DELEGATE_WRITE;
- + FILE_NFS41_REQUEST_DELEGATION_RESULT result = { 0 };
- + const char *type_name;
- + const char *why_name = NULL;
- +
- + if (!DeviceIoControl(hFile, FSCTL_NFS41_REQUEST_DELEGATION,
- + &request, sizeof(request), &result, sizeof(result),
- + &bytes_returned, NULL)) {
- + (void)fprintf(stderr,
- + "%s: command %u ('%s'): "
- + "FSCTL_NFS41_REQUEST_DELEGATION failed, lasterr=%d\n",
- + progname, command_number, command, (int)GetLastError());
- + goto out;
- + }
- + if (bytes_returned != sizeof(result)) {
- + (void)fprintf(stderr,
- + "%s: command %u ('%s'): returned %lu bytes, expected %ld\n",
- + progname, command_number, command, bytes_returned,
- + (long)sizeof(result));
- + goto out;
- + }
- +
- + type_name = delegation_type_name(result.DelegType);
- + if (type_name == NULL) {
- + (void)fprintf(stderr,
- + "%s: command %u ('%s'): invalid delegation type %lu\n",
- + progname, command_number, command,
- + (unsigned long)result.DelegType);
- + goto out;
- + }
- + if (result.DelegType == NFS41_OPEN_DELEGATE_NONE_EXT) {
- + why_name = why_no_delegation_name(result.WhyNoDelegation);
- + if (why_name == NULL) {
- + (void)fprintf(stderr,
- + "%s: command %u ('%s'): "
- + "invalid why_no_delegation4 %lu\n",
- + progname, command_number, command,
- + (unsigned long)result.WhyNoDelegation);
- + goto out;
- + }
- + }
- +
- + (void)printf("nfs41_delegation_test_result=(\n"
- + "\tcommand_number=%u\n"
- + "\tcommand='%s'\n"
- + "\tdeleg_type=%lu\n"
- + "\tdeleg_type_name='%s'\n",
- + command_number, command, (unsigned long)result.DelegType,
- + type_name);
- + if (why_name != NULL) {
- + (void)printf("\twhy_no_delegation=%lu\n"
- + "\twhy_no_delegation_name='%s'\n",
- + (unsigned long)result.WhyNoDelegation, why_name);
- + }
- + (void)printf(")\n");
- + }
- + else if (!strcmp(command, "returndeleg")) {
- + if (!DeviceIoControl(hFile, FSCTL_NFS41_RETURN_DELEGATION,
- + NULL, 0, NULL, 0, &bytes_returned, NULL)) {
- + (void)fprintf(stderr,
- + "%s: command %u ('%s'): "
- + "FSCTL_NFS41_RETURN_DELEGATION failed, lasterr=%d\n",
- + progname, command_number, command, (int)GetLastError());
- + goto out;
- + }
- + if (bytes_returned != 0) {
- + (void)fprintf(stderr,
- + "%s: command %u ('%s'): returned %lu bytes, expected 0\n",
- + progname, command_number, command, bytes_returned);
- + goto out;
- + }
- + (void)printf("nfs41_delegation_test_result=(\n"
- + "\tcommand_number=%u\n"
- + "\tcommand='%s'\n"
- + "\tstatus=success\n"
- + ")\n", command_number, command);
- + }
- + else {
- + (void)fprintf(stderr,
- + "%s: command %u: unknown delegation command '%s'\n",
- + progname, command_number, command);
- + goto out;
- + }
- +
- + command = strtok_r(NULL, ",", &saveptr);
- + } while (command != NULL);
- +
- + retval = EXIT_SUCCESS;
- +out:
- + (void)CloseHandle(hFile);
- + free(commands);
- + return retval;
- +}
- +
- static
- void usage(void)
- {
- @@ -2004,7 +2159,8 @@ void usage(void)
- "get_wnetgetresourceinformation|"
- "get_wnetgetresourceparent|"
- "fsctlnfs41queryidmapinfo|"
- - "fsctlnfs41querydelegationinfo"
- + "fsctlnfs41querydelegationinfo|"
- + "fsctlnfs41delegationtest"
- "> args\n");
- }
- @@ -2100,8 +2256,23 @@ int main(int ac, char *av[])
- return fsctlnfs41queryidmapinfo(av[0], av[2]);
- }
- else if (!strcmp(subcmd, "fsctlnfs41querydelegationinfo")) {
- + if (ac != 4) {
- + (void)fprintf(stderr, "%s: fsctlnfs41querydelegationinfo "
- + "<read|write|execute|all> filename\n", av[0]);
- + return EXIT_FAILURE;
- + }
- return fsctlnfs41querydelegationinfo(av[0], av[2], av[3]);
- }
- + else if (!strcmp(subcmd, "fsctlnfs41delegationtest")) {
- + if (ac != 4) {
- + (void)fprintf(stderr, "%s: fsctlnfs41delegationtest "
- + "command[,command...] filename\n"
- + "commands: requestreaddeleg, requestwritedeleg, "
- + "returndeleg\n", av[0]);
- + return EXIT_FAILURE;
- + }
- + return fsctlnfs41delegationtest(av[0], av[2], av[3]);
- + }
- else {
- (void)fprintf(stderr, "%s: Unknown subcmd '%s'\n", av[0], subcmd);
- return EXIT_FAILURE;
FSCTL for deleg control
Posted by Anonymous on Wed 9th Sep 2026 17:00
raw | new post
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.
nrubsig.kpaste.net RSS