diff --git a/daemon/open.c b/daemon/open.c index 2a7fe84..39c6742 100644 --- a/daemon/open.c +++ b/daemon/open.c @@ -303,7 +303,11 @@ static BOOLEAN open_for_attributes(uint32_t type, ULONG access_mask, if ((access_mask & FILE_READ_DATA) || (access_mask & FILE_WRITE_DATA) || (access_mask & FILE_APPEND_DATA) || - (access_mask & FILE_EXECUTE)) + (access_mask & FILE_EXECUTE) || + disposition == FILE_CREATE || + disposition == FILE_OVERWRITE_IF || + disposition == FILE_SUPERSEDE || + disposition == FILE_OPEN_IF) return FALSE; else { dprintf(1, "Open call that wants to manage attributes\n"); @@ -363,7 +367,7 @@ static int map_disposition_2_nfsopen(ULONG disposition, int in_status, bool_t pe } static void map_access_2_allowdeny(ULONG access_mask, ULONG access_mode, - uint32_t *allow, uint32_t *deny) + ULONG disposition, uint32_t *allow, uint32_t *deny) { if ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES)) && @@ -374,6 +378,16 @@ static void map_access_2_allowdeny(ULONG access_mask, ULONG access_mode, else if (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES)) *allow = OPEN4_SHARE_ACCESS_WRITE; + /* if we are creating a file and no data access is specified, then + * do an open and request no delegations. example open with share access 0 + * and share deny 0 (ie deny_both). + */ + if ((disposition == FILE_CREATE || disposition == FILE_OPEN_IF || + disposition == FILE_OVERWRITE_IF || disposition == FILE_SUPERSEDE) && + !(access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA | + FILE_WRITE_ATTRIBUTES | FILE_READ_DATA | FILE_EXECUTE))) + *allow = OPEN4_SHARE_ACCESS_READ | OPEN4_SHARE_ACCESS_WANT_NO_DELEG; + #define FIX_ALLOW_DENY_WIN2NFS_CONVERSION #ifdef FIX_ALLOW_DENY_WIN2NFS_CONVERSION if ((access_mode & FILE_SHARE_READ) && @@ -570,7 +584,7 @@ static int handle_open(nfs41_upcall *upcall) uint32_t create = 0, createhowmode = 0; map_access_2_allowdeny(args->access_mask, args->access_mode, - &state->share_access, &state->share_deny); + args->disposition, &state->share_access, &state->share_deny); status = map_disposition_2_nfsopen(args->disposition, status, state->session->flags & CREATE_SESSION4_FLAG_PERSIST, &create, &createhowmode, &upcall->last_error); diff --git a/sys/nfs41_driver.c b/sys/nfs41_driver.c index 8acb735..bea18fd 100644 --- a/sys/nfs41_driver.c +++ b/sys/nfs41_driver.c @@ -3247,6 +3247,15 @@ BOOLEAN isDataAccess( return FALSE; } +BOOLEAN isOpen2Create( + ULONG disposition) +{ + if (disposition == FILE_CREATE || disposition == FILE_OPEN_IF || + disposition == FILE_OVERWRITE_IF || disposition == FILE_SUPERSEDE) + return TRUE; + return FALSE; +} + NTSTATUS map_open_errors( DWORD status, USHORT len) @@ -3357,6 +3366,17 @@ 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->OpenCount && nfs41_fcb->StandardInfo.DeletePending && + !(params.ShareAccess & FILE_SHARE_DELETE)) { + DbgP("File opened already and marked for deletion\n"); + status = STATUS_DELETE_PENDING; + goto out; + } + #if defined(STORE_MOUNT_SEC_CONTEXT) && defined (USE_MOUNT_SEC_CONTEXT) status = nfs41_UpcallCreate(NFS41_OPEN, &pVNetRootContext->mount_sec_ctx, #else @@ -3374,7 +3394,7 @@ NTSTATUS nfs41_Create( entry->u.Open.disp = params.Disposition; entry->u.Open.copts = params.CreateOptions; entry->u.Open.srv_open = SrvOpen; - if (isDataAccess(params.DesiredAccess)) + if (isDataAccess(params.DesiredAccess) || isOpen2Create(params.Disposition)) { entry->u.Open.open_owner_id = InterlockedIncrement(&open_owner_id); // if we are creating a file check if nfsv3attributes were passed in if (params.Disposition != FILE_OPEN && params.Disposition != FILE_OVERWRITE) {