diff --git a/sys/nfs41_driver.c b/sys/nfs41_driver.c index 6bba83a..a9a9718 100644 --- a/sys/nfs41_driver.c +++ b/sys/nfs41_driver.c @@ -4557,6 +4557,7 @@ NTSTATUS map_setea_error( case ERROR_NETNAME_DELETED: return STATUS_NETWORK_NAME_DELETED; case ERROR_FILE_TOO_LARGE: return STATUS_EA_TOO_LARGE; case ERROR_BUFFER_OVERFLOW: return STATUS_BUFFER_OVERFLOW; + case STATUS_BUFFER_TOO_SMALL: case ERROR_INSUFFICIENT_BUFFER: return STATUS_BUFFER_TOO_SMALL; case ERROR_INVALID_EA_HANDLE: return STATUS_NONEXISTENT_EA_ENTRY; case ERROR_NO_MORE_FILES: return STATUS_NO_MORE_EAS; @@ -4734,6 +4735,63 @@ out: return status; } +static NTSTATUS QueryCygwinSymlink( + IN OUT PRX_CONTEXT RxContext, + IN PFILE_GET_EA_INFORMATION query, + OUT PFILE_FULL_EA_INFORMATION info) +{ + __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext = + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot); + __notnull PNFS41_NETROOT_EXTENSION NetRootContext = + NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot); + __notnull PNFS41_FOBX Fobx = NFS41GetFobxExtension(RxContext->pFobx); + nfs41_updowncall_entry *entry; + UNICODE_STRING TargetName; + const USHORT HeaderLen = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) + + query->EaNameLength + 1; + NTSTATUS status; + + if (RxContext->Info.LengthRemaining < HeaderLen) { + status = STATUS_BUFFER_TOO_SMALL; + RxContext->InformationToReturn = HeaderLen; + goto out; + } + + TargetName.Buffer = (PWCH)(info->EaName + query->EaNameLength + 1); + TargetName.MaximumLength = (USHORT)min(RxContext->Info.LengthRemaining - + HeaderLen, 0xFFFF); + + status = nfs41_UpcallCreate(NFS41_SYMLINK, &Fobx->sec_ctx, + VNetRootContext->session, Fobx->nfs41_open_state, + NetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry); + if (status) goto out; + + entry->u.Symlink.filename = SrvOpen->pAlreadyPrefixedName; + entry->u.Symlink.target = &TargetName; + entry->u.Symlink.set = FALSE; + + status = nfs41_UpcallWaitForReply(entry, VNetRootContext->timeout); + if (status) goto out; + + status = map_setea_error(entry->status); + if (status == STATUS_SUCCESS) { + info->NextEntryOffset = 0; + info->Flags = 0; + info->EaNameLength = query->EaNameLength; + info->EaValueLength = TargetName.Length - sizeof(UNICODE_NULL); + TargetName.Buffer[TargetName.Length/sizeof(WCHAR)] = UNICODE_NULL; + RtlCopyMemory(info->EaName, query->EaName, query->EaNameLength); + RxContext->Info.LengthRemaining = HeaderLen + info->EaValueLength; + } else if (status == STATUS_BUFFER_TOO_SMALL) { + RxContext->InformationToReturn = HeaderLen + + entry->u.Symlink.target->Length; + } + RxFreePool(entry); +out: + return status; +} + static NTSTATUS QueryCygwinEA( IN OUT PRX_CONTEXT RxContext, IN PFILE_GET_EA_INFORMATION query, @@ -4744,6 +4802,11 @@ static NTSTATUS QueryCygwinEA( if (query == NULL) goto out; + if (AnsiStrEq(&NfsSymlinkTargetName, query->EaName, query->EaNameLength)) { + status = QueryCygwinSymlink(RxContext, query, info); + goto out; + } + if (AnsiStrEq(&NfsV3Attributes, query->EaName, query->EaNameLength)) { nfs3_attrs attrs; @@ -4773,8 +4836,7 @@ static NTSTATUS QueryCygwinEA( goto out; } - if (AnsiStrEq(&NfsActOnLink, query->EaName, query->EaNameLength) || - AnsiStrEq(&NfsSymlinkTargetName, query->EaName, query->EaNameLength)) { + if (AnsiStrEq(&NfsActOnLink, query->EaName, query->EaNameLength)) { const LONG LengthRequired = sizeof(FILE_FULL_EA_INFORMATION) + query->EaNameLength - sizeof(CHAR);