- diff --git a/daemon/setattr.c b/daemon/setattr.c
- index 3c01a47..164c789 100644
- --- a/daemon/setattr.c
- +++ b/daemon/setattr.c
- @@ -349,6 +349,9 @@ static int handle_nfs41_rename(void *daemon_context, setattr_upcall_args *args)
- #endif /* NFS41_REJECT_CYGWIN_SILLYRENAME_FOR_DIRS */
- int status;
- +#ifdef NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE
- + args->rename_stale_dst_path_replaced = FALSE;
- +#endif /* NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE */
- src_name = &state->file.name;
- if (rename->FileNameLength == 0) {
- @@ -720,10 +723,24 @@ static int handle_nfs41_rename(void *daemon_context, setattr_upcall_args *args)
- DPRINTF(1, ("nfs41_rename() failed with error '%s'.\n",
- nfs_error_string(status)));
- status = nfs_to_windows_error(status, ERROR_ACCESS_DENIED);
- - } else {
- - /* rename state->path on success */
- - open_state_rename(state, &dst_path);
- + goto out;
- + }
- +
- +#ifdef NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE
- + if (rename->ReplaceIfExists) {
- + /*
- + * Send the (processed) destination path back to the kernel so it can
- + * be marked there as "stale". Otherwise we can do a SRVOPEN collapsing
- + * for a SRVOPEN which has been replaced
- + */
- + abs_path_copy(&args->rename_stale_dst_path, &dst_path);
- + args->rename_stale_dst_path_replaced = TRUE;
- }
- +#endif /* NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE */
- +
- + /* rename state->path on success */
- + open_state_rename(state, &dst_path);
- +
- out:
- return status;
- }
- @@ -1080,8 +1097,30 @@ static int marshall_setattr(
- uint32_t *restrict length,
- nfs41_upcall *restrict upcall)
- {
- + int status;
- const setattr_upcall_args *args = &upcall->args.setattr;
- - return safe_write(&buffer, length, &args->ctime, sizeof(args->ctime));
- + status = safe_write(&buffer, length, &args->ctime, sizeof(args->ctime));
- + if (status) goto out;
- +
- +#ifdef NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE
- + if (args->set_class == FileRenameInformation) {
- + status = safe_write(&buffer, length,
- + &args->rename_stale_dst_path_replaced,
- + sizeof(args->rename_stale_dst_path_replaced));
- + if (status) goto out;
- + if (args->rename_stale_dst_path_replaced) {
- + USHORT dst_path_len = args->rename_stale_dst_path.len;
- + status = safe_write(&buffer, length, &dst_path_len, sizeof(dst_path_len));
- + if (status) goto out;
- + status = safe_write(&buffer, length,
- + &args->rename_stale_dst_path.path[0], dst_path_len);
- + if (status) goto out;
- + }
- + }
- +#endif /* NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE */
- +
- +out:
- + return status;
- }
- diff --git a/daemon/upcall.h b/daemon/upcall.h
- index 01a84ed..a9f3dfe 100644
- --- a/daemon/upcall.h
- +++ b/daemon/upcall.h
- @@ -140,6 +140,11 @@ typedef struct __setattr_upcall_args {
- uint32_t buf_len;
- int set_class;
- ULONGLONG ctime;
- + /* Downcall info */
- +#ifdef NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE
- + BOOLEAN rename_stale_dst_path_replaced;
- + nfs41_abs_path rename_stale_dst_path;
- +#endif /* NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE */
- } setattr_upcall_args;
- typedef struct __getexattr_upcall_args {
- diff --git a/nfs41_build_features.h b/nfs41_build_features.h
- index 63a0a2d..53f65ee 100644
- --- a/nfs41_build_features.h
- +++ b/nfs41_build_features.h
- @@ -384,4 +384,18 @@
- */
- #define NFS41_DRIVER_COLLAPSEOPEN 1
- +/*
- + * |NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE| - mark
- + * the destination path of a |FileRenameInformation| as "stale" if we
- + * replace that file/dir.
- + * Otherwise we can use the old SRVOPEN (of the file/dir which was already
- + * relaced) for SRVOPEN collapsing, which breaks native Windows git (e.g.
- + * try git version "2.51.1.windows.1" like this
- + * $ '/cygdrive/c/Program Files/Git/cmd/git' clone \
- + * https://github.com/kofemann/ms-nfs41-client.git # will fail with
- + * "warning: remote HEAD refers to nonexistent ref, unable to checkout"
- + * because we use the old NFS handle for ".git/HEAD".
- + */
- +#define NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE 1
- +
- #endif /* !_NFS41_DRIVER_BUILDFEATURES_ */
- diff --git a/sys/nfs41sys_driver.c b/sys/nfs41sys_driver.c
- index 091e61a..e62d007 100644
- --- a/sys/nfs41sys_driver.c
- +++ b/sys/nfs41sys_driver.c
- @@ -998,7 +998,6 @@ NTSTATUS nfs41_ComputeNewBufferingState(
- #ifdef DEBUG_TIME_BASED_COHERENCY
- ULONG oldFlags = pSrvOpen->BufferingFlags;
- #endif
- -
- switch(flag) {
- case DISABLE_CACHING:
- if (pSrvOpen->BufferingFlags &
- diff --git a/sys/nfs41sys_driver.h b/sys/nfs41sys_driver.h
- index 441d8f7..8c303ab 100644
- --- a/sys/nfs41sys_driver.h
- +++ b/sys/nfs41sys_driver.h
- @@ -276,6 +276,13 @@ typedef struct _updowncall_entry {
- FILE_INFORMATION_CLASS InfoClass;
- PVOID buf;
- ULONG buf_len;
- +#ifdef NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE
- + struct {
- + BOOLEAN path_replaced;
- + USHORT path_len;
- + const unsigned char *path_buf;
- + } rename_stale_dst;
- +#endif /* NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE */
- } SetFile;
- struct {
- DWORD mode;
- @@ -507,6 +514,10 @@ typedef struct _NFS41_FCB {
- typedef struct _NFS41_SRV_OPEN {
- BOOLEAN initialised;
- +#ifdef NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE
- + BOOLEAN stale;
- +#endif /* NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE */
- +
- /*
- * |sec_ctx| must be per |SRV_OPEN| to handle newgrp()/|setgid()|
- * support. But this only works if we prevent |SRV_OPEN| collapsing
- @@ -945,6 +956,10 @@ void unmarshal_nfs41_attrget(
- ULONG *attr_len,
- const unsigned char *restrict *restrict buf,
- BOOL copy_partial);
- +void unmarshal_nfs41_getchangetime(
- + nfs41_updowncall_entry *cur,
- + PULONGLONG dest_buf,
- + const unsigned char *restrict *restrict buf);
- NTSTATUS nfs41_UpcallCreate(
- IN nfs41_opcodes opcode,
- IN PSECURITY_CLIENT_CONTEXT clnt_sec_ctx,
- @@ -977,7 +992,6 @@ NTSTATUS marshal_nfs41_fileset(
- ULONG *len);
- void unmarshal_nfs41_setattr(
- nfs41_updowncall_entry *cur,
- - PULONGLONG dest_buf,
- const unsigned char *restrict *restrict buf);
- void unmarshal_nfs41_getattr(
- nfs41_updowncall_entry *cur,
- diff --git a/sys/nfs41sys_fileinfo.c b/sys/nfs41sys_fileinfo.c
- index b7ef8ec..3f75f5f 100644
- --- a/sys/nfs41sys_fileinfo.c
- +++ b/sys/nfs41sys_fileinfo.c
- @@ -160,8 +160,14 @@ NTSTATUS marshal_nfs41_fileset(
- }
- #endif /* NFS41_DRIVER_STOMP_CYGWIN_SILLYRENAME_INVALID_UTF16_SEQUENCE_SUPPORT */
- + /*
- + * We use %lu here for |ReplaceIfExists| because of
- + * |FileRenameInformationEx| uses a ULONG flags field
- + */
- DbgP("marshal_nfs41_fileset: "
- - "FILE_RENAME_INFORMATION.(FileNameLength=%d FileName='%.*ls')\n",
- + "FILE_RENAME_INFORMATION."
- + "(ReplaceIfExists=%lu FileNameLength=%d FileName='%.*ls')\n",
- + (unsigned long)fri->ReplaceIfExists,
- (int)fri->FileNameLength,
- (int)(fri->FileNameLength/sizeof(wchar_t)), fri->FileName);
- }
- @@ -207,14 +213,27 @@ out:
- void unmarshal_nfs41_setattr(
- nfs41_updowncall_entry *cur,
- - PULONGLONG dest_buf,
- const unsigned char *restrict *restrict buf)
- {
- - RtlCopyMemory(dest_buf, *buf, sizeof(*dest_buf));
- - *buf += sizeof(*dest_buf);
- -#ifdef DEBUG_MARSHAL_DETAIL
- - DbgP("unmarshal_nfs41_setattr: returned ChangeTime %llu\n", *dest_buf);
- -#endif
- + RtlCopyMemory(&cur->ChangeTime, *buf, sizeof(cur->ChangeTime));
- + *buf += sizeof(cur->ChangeTime);
- +
- +#ifdef NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE
- + if (cur->u.SetFile.InfoClass == FileRenameInformation) {
- + RtlCopyMemory(&cur->u.SetFile.rename_stale_dst.path_replaced,
- + *buf, sizeof(cur->u.SetFile.rename_stale_dst.path_replaced));
- + *buf += sizeof(cur->u.SetFile.rename_stale_dst.path_replaced);
- +
- + if (cur->u.SetFile.rename_stale_dst.path_replaced) {
- + RtlCopyMemory(&cur->u.SetFile.rename_stale_dst.path_len,
- + *buf, sizeof(cur->u.SetFile.rename_stale_dst.path_len));
- + *buf += sizeof(cur->u.SetFile.rename_stale_dst.path_len);
- +
- + cur->u.SetFile.rename_stale_dst.path_buf = *buf;
- + *buf += cur->u.SetFile.rename_stale_dst.path_len;
- + }
- + }
- +#endif /* NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE */
- }
- void unmarshal_nfs41_getattr(
- @@ -737,6 +756,58 @@ out:
- return status;
- }
- +#ifdef NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE
- +VOID nfs41_mark_file_as_non_collapsible(
- + PNET_ROOT netroot,
- + PUNICODE_STRING nonc_filename)
- +{
- + PFCB fcb;
- + PNFS41_SRV_OPEN nfs41_srvopen;
- +
- + DbgP("nfs41_mark_file_as_non_collapsible: "
- + "argument filename='%wZ'\n",
- + nonc_filename);
- +
- + RxAcquireFcbTableLockExclusive(&netroot->FcbTable, TRUE);
- +
- + fcb = RxFcbTableLookupFcb(&netroot->FcbTable, nonc_filename);
- +
- + RxReleaseFcbTableLock(&netroot->FcbTable);
- +
- + if (fcb) {
- + PLIST_ENTRY pSrvOpenListEntry;
- + PSRV_OPEN srv_open;
- +
- + pSrvOpenListEntry = fcb->SrvOpenList.Flink;
- +
- + for (;;) {
- + if (pSrvOpenListEntry == &fcb->SrvOpenList) {
- + break;
- + }
- +
- + srv_open = (PSRV_OPEN)
- + CONTAINING_RECORD(pSrvOpenListEntry, SRV_OPEN, SrvOpenQLinks);
- + nfs41_srvopen = NFS41GetSrvOpenExtension(srv_open);
- +
- + DbgP("nfs41_mark_file_as_non_collapsible: "
- + "marking filename='%wZ'/fcb=0x%p/srv_open=0x%p as stale\n",
- + nonc_filename, (void *)fcb, (void *)srv_open);
- +
- + nfs41_srvopen->stale = TRUE;
- +
- + pSrvOpenListEntry = pSrvOpenListEntry->Flink;
- + }
- +
- + RxpDereferenceNetFcb(fcb);
- + }
- + else {
- + DbgP("nfs41_mark_file_as_non_collapsible: "
- + "nothing found for filename='%wZ'\n",
- + nonc_filename);
- + }
- +}
- +#endif /* NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE */
- +
- static
- NTSTATUS nfs41_SetFileInformationImpl(
- IN OUT PRX_CONTEXT RxContext,
- @@ -902,6 +973,49 @@ NTSTATUS nfs41_SetFileInformationImpl(
- (FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA)))
- nfs41_update_fcb_list(RxContext->pFcb, entry->ChangeTime);
- nfs41_fcb->changeattr = entry->ChangeTime;
- +
- +#ifdef NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE
- + if (RxContext->Info.FileInformationClass == FileRenameInformation) {
- + DbgP("nfs41_SetFileInformationImpl: "
- + "finishig FileRenameInformation for filename='%wZ', "
- + "rename_stale_dst.path_replaced=%d\n",
- + entry->filename,
- + (int)entry->u.SetFile.rename_stale_dst.path_replaced);
- +
- + if (entry->u.SetFile.rename_stale_dst.path_replaced) {
- + DbgP("nfs41_SetFileInformationImpl: "
- + "rename_stale_dst.path_len=%d inbuf='%.*s'\n",
- + (int)entry->u.SetFile.rename_stale_dst.path_len,
- + (int)entry->u.SetFile.rename_stale_dst.path_len,
- + entry->u.SetFile.rename_stale_dst.path_buf);
- + UTF8_STRING stale_utf8filename = {
- + .Length = (USHORT)
- + entry->u.SetFile.rename_stale_dst.path_len,
- + .MaximumLength = (USHORT)
- + entry->u.SetFile.rename_stale_dst.path_len,
- + .Buffer = (PCHAR)
- + entry->u.SetFile.rename_stale_dst.path_buf
- + };
- +
- + UNICODE_STRING stale_filename;
- +
- + status = RtlUTF8StringToUnicodeString(&stale_filename,
- + &stale_utf8filename, TRUE);
- + if (NT_SUCCESS(status)) {
- + DbgP("nfs41_SetFileInformationImpl/stale: "
- + "stale_filename='%wZ'\n",
- + &stale_filename);
- +
- + nfs41_mark_file_as_non_collapsible(
- + (PNET_ROOT)SrvOpen->pVNetRoot->pNetRoot,
- + &stale_filename);
- +
- + RtlFreeUnicodeString(&stale_filename);
- + status = STATUS_SUCCESS;
- + }
- + }
- + }
- +#endif /* NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE */
- }
- out:
- if (entry) {
- diff --git a/sys/nfs41sys_openclose.c b/sys/nfs41sys_openclose.c
- index eaf04f0..af546c8 100644
- --- a/sys/nfs41sys_openclose.c
- +++ b/sys/nfs41sys_openclose.c
- @@ -1385,6 +1385,16 @@ NTSTATUS nfs41_ShouldTryToCollapseThisOpen(
- goto out;
- }
- +#ifdef NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE
- + if (nfs41_srvopen->stale) {
- + DbgP("nfs41_ShouldTryToCollapseThisOpen: "
- + "filename='%wZ' nfs41_srvopen->stale set, cannot collapse\n",
- + SrvOpen->pAlreadyPrefixedName);
- + status = STATUS_MORE_PROCESSING_REQUIRED;
- + goto out;
- + }
- +#endif /* NFS41_DRIVER_MARK_OVERWRITTEN_RENAME_DST_PATH_SRVOPEN_AS_STALE */
- +
- #ifdef WINBUG_NO_COLLAPSE_IF_PRIMARYGROUPS_DIFFER
- /*
- * Reject srvopens if the primary group used to create
- diff --git a/sys/nfs41sys_updowncall.c b/sys/nfs41sys_updowncall.c
- index 15f948c..dedfa4e 100644
- --- a/sys/nfs41sys_updowncall.c
- +++ b/sys/nfs41sys_updowncall.c
- @@ -193,6 +193,19 @@ void unmarshal_nfs41_attrget(
- *buf += buf_len;
- }
- +void unmarshal_nfs41_getchangetime(
- + nfs41_updowncall_entry *cur,
- + PULONGLONG dest_buf,
- + const unsigned char *restrict *restrict buf)
- +{
- + RtlCopyMemory(dest_buf, *buf, sizeof(*dest_buf));
- + *buf += sizeof(*dest_buf);
- +#ifdef DEBUG_MARSHAL_DETAIL
- + DbgP("unmarshal_nfs41_getchangetime: "
- + "returned ChangeTime %llu\n", *dest_buf);
- +#endif
- +}
- +
- NTSTATUS handle_upcall(
- IN PRX_CONTEXT RxContext,
- IN nfs41_updowncall_entry *entry,
- @@ -773,13 +786,13 @@ NTSTATUS nfs41_downcall(
- break;
- case NFS41_SYSOP_FILE_SET:
- case NFS41_SYSOP_FILE_SET_AT_CLEANUP:
- - unmarshal_nfs41_setattr(cur, &cur->ChangeTime, &inbuf);
- + unmarshal_nfs41_setattr(cur, &inbuf);
- break;
- case NFS41_SYSOP_EA_SET:
- - unmarshal_nfs41_setattr(cur, &cur->ChangeTime, &inbuf);
- + unmarshal_nfs41_getchangetime(cur, &cur->ChangeTime, &inbuf);
- break;
- case NFS41_SYSOP_ACL_SET:
- - unmarshal_nfs41_setattr(cur, &cur->ChangeTime, &inbuf);
- + unmarshal_nfs41_getchangetime(cur, &cur->ChangeTime, &inbuf);
- break;
- case NFS41_SYSOP_FSCTL_QUERYALLOCATEDRANGES:
- unmarshal_nfs41_queryallocatedranges(cur, &inbuf);
make replaced srvopen as stale fix
Posted by Anonymous on Wed 18th Feb 2026 19:34
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