From 0020104b95f97243a7f1a8d5e8aaa1edf536a86a Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Fri, 23 Mar 2012 14:01:48 -0400 Subject: [PATCH] fixing handling of delete_on_close file can be opened with a delete_on_close flag set. this file can be opened again as long as opens specify "file_share_delete" access. after receiving the cleanup irp, the handle enters "delete-pending" state. opens in this state must fail with status_delete_pending. file query for standard_info.delete_pending now should return true. calling setattr with disposition=1 puts the file in "delete-pending" state. calling setattr with dispositon=0 will clear delete_on_close only if file is in "delete-pending" state. otherwise, setattr is ignored. --- sys/nfs41_driver.c | 57 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/sys/nfs41_driver.c b/sys/nfs41_driver.c index cda9c6b..9b70244 100644 --- a/sys/nfs41_driver.c +++ b/sys/nfs41_driver.c @@ -401,8 +401,9 @@ typedef struct _NFS41_FCB { FILE_BASIC_INFORMATION BasicInfo; FILE_STANDARD_INFORMATION StandardInfo; BOOLEAN Renamed; + BOOLEAN DeletePending; DWORD mode; - ULONGLONG changeattr; + ULONGLONG changeattr; } NFS41_FCB, *PNFS41_FCB; #define NFS41GetFcbExtension(pFcb) \ (((pFcb) == NULL) ? NULL : (PNFS41_FCB)((pFcb)->Context)) @@ -3373,6 +3374,7 @@ NTSTATUS nfs41_Create( __notnull PMRX_FCB Fcb = RxContext->pFcb; __notnull PNFS41_FCB nfs41_fcb = (PNFS41_FCB)Fcb->Context; PNFS41_FOBX nfs41_fobx = NULL; + BOOLEAN oldDeletePending = nfs41_fcb->StandardInfo.DeletePending; #ifdef ENABLE_TIMINGS LARGE_INTEGER t1, t2; t1 = KeQueryPerformanceCounter(NULL); @@ -3415,17 +3417,24 @@ NTSTATUS nfs41_Create( goto out; } - /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx - * If FILE_SHARE_DELETE flag is not specified, but the file or device has been - * opened for delete access, the function fails. + /* if FCB was marked for deletion and opened multiple times, as soon + * as first close happen, FCB transitions into delete_pending state + * no more opens allowed */ - if (Fcb->OpenCount && nfs41_fcb->StandardInfo.DeletePending && - !(params.ShareAccess & FILE_SHARE_DELETE)) { - DbgP("File opened already and marked for deletion\n"); + if (Fcb->OpenCount && nfs41_fcb->DeletePending) { status = STATUS_DELETE_PENDING; goto out; } + /* ms-fsa: 3.1.5.1.2.1 page 68 */ + if (Fcb->OpenCount && nfs41_fcb->StandardInfo.DeletePending && + !(params.ShareAccess & FILE_SHARE_DELETE) && + (params.DesiredAccess & (FILE_EXECUTE | FILE_READ_DATA | + FILE_WRITE_DATA | FILE_APPEND_DATA))) { + status = STATUS_SHARING_VIOLATION; + goto out; + } + if (isFilenameTooLong(SrvOpen->pAlreadyPrefixedName, pVNetRootContext)) { status = STATUS_OBJECT_NAME_INVALID; goto out; @@ -3574,10 +3583,6 @@ NTSTATUS nfs41_Create( if (Fcb->OpenCount == 0 || (Fcb->OpenCount > 0 && nfs41_fcb->changeattr != entry->u.Open.changeattr)) { -#ifdef DEBUG_OPEN - print_basic_info(1, &entry->u.Open.binfo); - print_std_info(1, &entry->u.Open.sinfo); -#endif RtlCopyMemory(&nfs41_fcb->BasicInfo, &entry->u.Open.binfo, sizeof(entry->u.Open.binfo)); RtlCopyMemory(&nfs41_fcb->StandardInfo, &entry->u.Open.sinfo, @@ -3585,6 +3590,9 @@ NTSTATUS nfs41_Create( nfs41_fcb->mode = entry->u.Open.mode; nfs41_fcb->changeattr = entry->u.Open.changeattr; nfs41_fcb->Flags = FCB_BASIC_INFO_CACHED | FCB_STANDARD_INFO_CACHED; + if (((params.CreateOptions & FILE_DELETE_ON_CLOSE) && + !pVNetRootContext->read_only) || oldDeletePending) + nfs41_fcb->StandardInfo.DeletePending = TRUE; RxFormInitPacket(InitPacket, &entry->u.Open.binfo.FileAttributes, @@ -3606,13 +3614,11 @@ NTSTATUS nfs41_Create( &InitPacket); } #ifdef DEBUG_OPEN - else { + else DbgP("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); - if (nfs41_fcb->Flags) { - print_basic_info(1, &nfs41_fcb->BasicInfo); - print_std_info(1, &nfs41_fcb->StandardInfo); - } - } + + print_basic_info(1, &nfs41_fcb->BasicInfo); + print_std_info(1, &nfs41_fcb->StandardInfo); #endif if (Fcb->OpenCount > 0 && @@ -3848,6 +3854,8 @@ NTSTATUS nfs41_CloseSrvOpen( entry->u.Close.srv_open = SrvOpen; entry->u.Close.filename = SrvOpen->pAlreadyPrefixedName; + if (nfs41_fcb->StandardInfo.DeletePending) + nfs41_fcb->DeletePending = TRUE; if (!RxContext->pFcb->OpenCount || (nfs41_fcb->StandardInfo.DeletePending && nfs41_fcb->StandardInfo.Directory)) @@ -4915,6 +4923,7 @@ NTSTATUS nfs41_QueryFileInformation( std_info->EndOfFile.QuadPart = nfs41_fcb->StandardInfo.EndOfFile.QuadPart; } + std_info->DeletePending = nfs41_fcb->DeletePending; } #endif if (nfs41_fcb->StandardInfo.DeletePending) @@ -5061,6 +5070,12 @@ NTSTATUS nfs41_SetFileInformation( PFILE_DISPOSITION_INFORMATION dinfo = (PFILE_DISPOSITION_INFORMATION)RxContext->Info.Buffer; if (dinfo->DeleteFile) { + if (nfs41_fcb->DeletePending) { + status = STATUS_DELETE_PENDING; + goto out; + } + + nfs41_fcb->DeletePending = TRUE; // we can delete directories right away if (nfs41_fcb->StandardInfo.Directory) break; @@ -5075,6 +5090,14 @@ NTSTATUS nfs41_SetFileInformation( nfs41_fcb->Renamed = TRUE; break; } + } else { + /* section 4.3.3 of [FSBO] + * "file system behavior in the microsoft windows environment" + */ + if (nfs41_fcb->DeletePending) { + nfs41_fcb->DeletePending = 0; + nfs41_fcb->StandardInfo.DeletePending = 0; + } } status = STATUS_SUCCESS; goto out;