1 /* NFSv4.1 client for Windows
2 * Copyright © 2012 The Regents of the University of Michigan
4 * Olga Kornievskaia <aglo@umich.edu>
5 * Casey Bodley <cbodley@umich.edu>
7 * This library is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or (at
10 * your option) any later version.
12 * This library is distributed in the hope that it will be useful, but
13 * without any warranty; without even the implied warranty of merchantability
14 * or fitness for a particular purpose. See the GNU Lesser General Public
15 * License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 #define MINIRDR__NAME "Value is ignored, only fact of definition"
27 #include <ntstrsafe.h>
30 #include <pseh/pseh2.h>
33 #include "nfs41_driver.h"
35 #include "nfs41_debug.h"
37 #if defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_WIN7)
38 NTSTATUS NTAPI
RtlUnicodeToUTF8N(CHAR
*utf8_dest
, ULONG utf8_bytes_max
,
39 ULONG
*utf8_bytes_written
,
40 const WCHAR
*uni_src
, ULONG uni_bytes
);
41 NTSTATUS NTAPI
RtlUTF8ToUnicodeN(WCHAR
*uni_dest
, ULONG uni_bytes_max
,
42 ULONG
*uni_bytes_written
,
43 const CHAR
*utf8_src
, ULONG utf8_bytes
);
44 #endif /* defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_WIN7) */
46 #define USE_MOUNT_SEC_CONTEXT
48 /* debugging printout defines */
49 #define DEBUG_MARSHAL_HEADER
50 #define DEBUG_MARSHAL_DETAIL
54 #define DEBUG_INVALIDATE_CACHE
57 //#define DEBUG_DIR_QUERY
58 //#define DEBUG_FILE_QUERY
59 //#define DEBUG_FILE_SET
60 //#define DEBUG_ACL_QUERY
61 //#define DEBUG_ACL_SET
62 //#define DEBUG_EA_QUERY
63 //#define DEBUG_EA_SET
66 #define DEBUG_TIME_BASED_COHERENCY
68 //#define DEBUG_VOLUME_QUERY
70 //#define ENABLE_TIMINGS
71 //#define ENABLE_INDV_TIMINGS
73 typedef struct __nfs41_timings
{
78 nfs41_timings lookup
, readdir
, open
, close
, getattr
, setattr
, getacl
, setacl
, volume
,
79 read
, write
, lock
, unlock
, setexattr
, getexattr
;
81 DRIVER_INITIALIZE DriverEntry
;
82 DRIVER_UNLOAD nfs41_driver_unload
;
83 DRIVER_DISPATCH ( nfs41_FsdDispatch
);
85 struct _MINIRDR_DISPATCH nfs41_ops
;
86 PRDBSS_DEVICE_OBJECT nfs41_dev
;
88 #define DISABLE_CACHING 0
89 #define ENABLE_READ_CACHING 1
90 #define ENABLE_WRITE_CACHING 2
91 #define ENABLE_READWRITE_CACHING 3
93 #define NFS41_MM_POOLTAG ('nfs4')
94 #define NFS41_MM_POOLTAG_ACL ('acls')
95 #define NFS41_MM_POOLTAG_MOUNT ('mnts')
96 #define NFS41_MM_POOLTAG_OPEN ('open')
97 #define NFS41_MM_POOLTAG_UP ('upca')
98 #define NFS41_MM_POOLTAG_DOWN ('down')
101 FAST_MUTEX upcallLock
, downcallLock
, fcblistLock
;
103 FAST_MUTEX openOwnerLock
;
106 LONG open_owner_id
= 1;
108 #define DECLARE_CONST_ANSI_STRING(_var, _string) \
109 const CHAR _var ## _buffer[] = _string; \
110 const ANSI_STRING _var = { sizeof(_string) - sizeof(CHAR), \
111 sizeof(_string), (PCH) _var ## _buffer }
112 #define RELATIVE(wait) (-(wait))
113 #define NANOSECONDS(nanos) (((signed __int64)(nanos)) / 100L)
114 #define MICROSECONDS(micros) (((signed __int64)(micros)) * NANOSECONDS(1000L))
115 #define MILLISECONDS(milli) (((signed __int64)(milli)) * MICROSECONDS(1000L))
116 #define SECONDS(seconds) (((signed __int64)(seconds)) * MILLISECONDS(1000L))
118 DECLARE_CONST_ANSI_STRING(NfsV3Attributes
, "NfsV3Attributes");
119 DECLARE_CONST_ANSI_STRING(NfsSymlinkTargetName
, "NfsSymlinkTargetName");
120 DECLARE_CONST_ANSI_STRING(NfsActOnLink
, "NfsActOnLink");
122 INLINE BOOL
AnsiStrEq(
123 IN
const ANSI_STRING
*lhs
,
125 IN
const UCHAR rhs_len
)
127 return lhs
->Length
== rhs_len
&&
128 RtlCompareMemory(lhs
->Buffer
, rhs
, rhs_len
) == rhs_len
;
131 typedef struct _nfs3_attrs
{
132 DWORD type
, mode
, nlink
, uid
, gid
, filler1
;
133 LARGE_INTEGER size
, used
;
138 LONGLONG fsid
, fileid
;
139 LONGLONG atime
, mtime
, ctime
;
141 LARGE_INTEGER unix_time_diff
; //needed to convert windows time to unix
153 typedef enum _nfs41_updowncall_state
{
154 NFS41_WAITING_FOR_UPCALL
,
155 NFS41_WAITING_FOR_DOWNCALL
,
156 NFS41_DONE_PROCESSING
,
158 } nfs41_updowncall_state
;
165 typedef struct _updowncall_entry
{
170 nfs41_updowncall_state state
;
176 SECURITY_CLIENT_CONTEXT sec_ctx
;
177 PSECURITY_CLIENT_CONTEXT psec_ctx
;
180 PUNICODE_STRING filename
;
183 ULONGLONG ChangeTime
;
186 PUNICODE_STRING srv_name
;
187 PUNICODE_STRING root
;
188 PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs
;
197 PRX_CONTEXT rxcontext
;
207 LOWIO_LOCK_LIST locks
;
210 FILE_BASIC_INFORMATION binfo
;
211 FILE_STANDARD_INFORMATION sinfo
;
212 UNICODE_STRING symlink
;
223 BOOLEAN symlink_embedded
;
233 PUNICODE_STRING filter
;
234 FILE_INFORMATION_CLASS InfoClass
;
235 BOOLEAN restart_scan
;
236 BOOLEAN return_single
;
237 BOOLEAN initial_query
;
242 FILE_INFORMATION_CLASS InfoClass
;
252 BOOLEAN ReturnSingleEntry
;
256 PUNICODE_STRING target
;
260 FS_INFORMATION_CLASS query
;
263 SECURITY_INFORMATION query
;
267 } nfs41_updowncall_entry
;
269 typedef struct _updowncall_list
{
271 } nfs41_updowncall_list
;
272 nfs41_updowncall_list upcall
, downcall
;
274 typedef struct _nfs41_mount_entry
{
277 HANDLE authsys_session
;
283 typedef struct _nfs41_mount_list
{
287 #define nfs41_AddEntry(lock,list,pEntry) \
288 ExAcquireFastMutex(&lock); \
289 InsertTailList(&(list).head, &(pEntry)->next); \
290 ExReleaseFastMutex(&lock);
291 #define nfs41_RemoveFirst(lock,list,pEntry) \
292 ExAcquireFastMutex(&lock); \
293 pEntry = (IsListEmpty(&(list).head) \
295 : RemoveHeadList(&(list).head)); \
296 ExReleaseFastMutex(&lock);
297 #define nfs41_RemoveEntry(lock,pEntry) \
298 ExAcquireFastMutex(&lock); \
299 RemoveEntryList(&pEntry->next); \
300 ExReleaseFastMutex(&lock);
301 #define nfs41_IsListEmpty(lock,list,flag) \
302 ExAcquireFastMutex(&lock); \
303 flag = IsListEmpty(&(list).head); \
304 ExReleaseFastMutex(&lock);
305 #define nfs41_GetFirstEntry(lock,list,pEntry) \
306 ExAcquireFastMutex(&lock); \
307 pEntry = (IsListEmpty(&(list).head) \
309 : (nfs41_updowncall_entry *) \
310 (CONTAINING_RECORD((list).head.Flink, \
311 nfs41_updowncall_entry, \
313 ExReleaseFastMutex(&lock);
314 #define nfs41_GetFirstMountEntry(lock,list,pEntry) \
315 ExAcquireFastMutex(&lock); \
316 pEntry = (IsListEmpty(&(list).head) \
318 : (nfs41_mount_entry *) \
319 (CONTAINING_RECORD((list).head.Flink, \
322 ExReleaseFastMutex(&lock);
324 /* In order to cooperate with other network providers,
325 * we only claim paths of the format '\\server\nfs4\path' */
326 DECLARE_CONST_UNICODE_STRING(NfsPrefix
, L
"\\nfs4");
327 DECLARE_CONST_UNICODE_STRING(AUTH_SYS_NAME
, L
"sys");
328 DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5_NAME
, L
"krb5");
329 DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5I_NAME
, L
"krb5i");
330 DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5P_NAME
, L
"krb5p");
331 DECLARE_CONST_UNICODE_STRING(SLASH
, L
"\\");
332 DECLARE_CONST_UNICODE_STRING(EMPTY_STRING
, L
"");
334 #define SERVER_NAME_BUFFER_SIZE 1024
335 #define MOUNT_CONFIG_RW_SIZE_MIN 1024
336 #define MOUNT_CONFIG_RW_SIZE_DEFAULT 1048576
337 #define MOUNT_CONFIG_RW_SIZE_MAX 1048576
338 #define MAX_SEC_FLAVOR_LEN 12
339 #define UPCALL_TIMEOUT_DEFAULT 50 /* in seconds */
341 typedef struct _NFS41_MOUNT_CONFIG
{
347 WCHAR srv_buffer
[SERVER_NAME_BUFFER_SIZE
];
348 UNICODE_STRING SrvName
;
349 WCHAR mntpt_buffer
[MAX_PATH
];
350 UNICODE_STRING MntPt
;
351 WCHAR sec_flavor
[MAX_SEC_FLAVOR_LEN
];
352 UNICODE_STRING SecFlavor
;
354 } NFS41_MOUNT_CONFIG
, *PNFS41_MOUNT_CONFIG
;
356 typedef struct _NFS41_NETROOT_EXTENSION
{
357 NODE_TYPE_CODE NodeTypeCode
;
358 NODE_BYTE_SIZE NodeByteSize
;
359 DWORD nfs41d_version
;
361 FAST_MUTEX mountLock
;
362 nfs41_mount_list mounts
;
363 } NFS41_NETROOT_EXTENSION
, *PNFS41_NETROOT_EXTENSION
;
364 #define NFS41GetNetRootExtension(pNetRoot) \
365 (((pNetRoot) == NULL) ? NULL : \
366 (PNFS41_NETROOT_EXTENSION)((pNetRoot)->Context))
368 /* FileSystemName as reported by FileFsAttributeInfo query */
369 #define FS_NAME L"NFS"
370 #define FS_NAME_LEN (sizeof(FS_NAME) - sizeof(WCHAR))
371 #define FS_ATTR_LEN (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + FS_NAME_LEN)
373 /* FileSystemName as reported by FileFsAttributeInfo query */
374 #define VOL_NAME L"PnfsVolume"
375 #define VOL_NAME_LEN (sizeof(VOL_NAME) - sizeof(WCHAR))
376 #define VOL_ATTR_LEN (sizeof(FILE_FS_VOLUME_INFORMATION) + VOL_NAME_LEN)
378 typedef struct _NFS41_V_NET_ROOT_EXTENSION
{
379 NODE_TYPE_CODE NodeTypeCode
;
380 NODE_BYTE_SIZE NodeByteSize
;
382 FILE_FS_ATTRIBUTE_INFORMATION FsAttrs
;
389 #define STORE_MOUNT_SEC_CONTEXT
390 #ifdef STORE_MOUNT_SEC_CONTEXT
391 SECURITY_CLIENT_CONTEXT mount_sec_ctx
;
393 } NFS41_V_NET_ROOT_EXTENSION
, *PNFS41_V_NET_ROOT_EXTENSION
;
394 #define NFS41GetVNetRootExtension(pVNetRoot) \
395 (((pVNetRoot) == NULL) ? NULL : \
396 (PNFS41_V_NET_ROOT_EXTENSION)((pVNetRoot)->Context))
398 typedef struct _NFS41_FCB
{
399 NODE_TYPE_CODE NodeTypeCode
;
400 NODE_BYTE_SIZE NodeByteSize
;
401 FILE_BASIC_INFORMATION BasicInfo
;
402 FILE_STANDARD_INFORMATION StandardInfo
;
404 BOOLEAN DeletePending
;
406 ULONGLONG changeattr
;
407 } NFS41_FCB
, *PNFS41_FCB
;
408 #define NFS41GetFcbExtension(pFcb) \
409 (((pFcb) == NULL) ? NULL : (PNFS41_FCB)((pFcb)->Context))
411 typedef struct _NFS41_FOBX
{
412 NODE_TYPE_CODE NodeTypeCode
;
413 NODE_BYTE_SIZE NodeByteSize
;
415 HANDLE nfs41_open_state
;
416 SECURITY_CLIENT_CONTEXT sec_ctx
;
423 } NFS41_FOBX
, *PNFS41_FOBX
;
424 #define NFS41GetFobxExtension(pFobx) \
425 (((pFobx) == NULL) ? NULL : (PNFS41_FOBX)((pFobx)->Context))
427 typedef struct _NFS41_SERVER_ENTRY
{
428 PMRX_SRV_CALL pRdbssSrvCall
;
429 WCHAR NameBuffer
[SERVER_NAME_BUFFER_SIZE
];
430 UNICODE_STRING Name
; // the server name.
431 } NFS41_SERVER_ENTRY
, *PNFS41_SERVER_ENTRY
;
433 typedef struct _NFS41_DEVICE_EXTENSION
{
434 NODE_TYPE_CODE NodeTypeCode
;
435 NODE_BYTE_SIZE NodeByteSize
;
436 PRDBSS_DEVICE_OBJECT DeviceObject
;
438 HANDLE SharedMemorySection
;
439 DWORD nfs41d_version
;
440 BYTE VolAttrs
[VOL_ATTR_LEN
];
442 HANDLE openlistHandle
;
443 } NFS41_DEVICE_EXTENSION
, *PNFS41_DEVICE_EXTENSION
;
445 #define NFS41GetDeviceExtension(RxContext,pExt) \
446 PNFS41_DEVICE_EXTENSION pExt = (PNFS41_DEVICE_EXTENSION) \
447 ((PBYTE)(RxContext->RxDeviceObject) + sizeof(RDBSS_DEVICE_OBJECT))
449 typedef struct _nfs41_fcb_list_entry
{
453 PNFS41_FOBX nfs41_fobx
;
454 ULONGLONG ChangeTime
;
456 } nfs41_fcb_list_entry
;
458 typedef struct _nfs41_fcb_list
{
461 nfs41_fcb_list openlist
;
463 typedef enum _NULMRX_STORAGE_TYPE_CODES
{
464 NTC_NFS41_DEVICE_EXTENSION
= (NODE_TYPE_CODE
)0xFC00,
465 } NFS41_STORAGE_TYPE_CODES
;
466 #define RxDefineNode( node, type ) \
467 node->NodeTypeCode = NTC_##type; \
468 node->NodeByteSize = sizeof(type);
470 #define RDR_NULL_STATE 0
471 #define RDR_UNLOADED 1
472 #define RDR_UNLOADING 2
473 #define RDR_LOADING 3
475 #define RDR_STOPPED 5
476 #define RDR_STOPPING 6
477 #define RDR_STARTING 7
478 #define RDR_STARTED 8
480 nfs41_init_driver_state nfs41_init_state
= NFS41_INIT_DRIVER_STARTABLE
;
481 nfs41_start_driver_state nfs41_start_state
= NFS41_START_DRIVER_STARTABLE
;
483 NTSTATUS
map_readwrite_errors(DWORD status
);
485 void print_debug_header(
486 PRX_CONTEXT RxContext
)
489 PIO_STACK_LOCATION IrpSp
= RxContext
->CurrentIrpSp
;
492 DbgP("FileOject %p name %wZ access r=%d,w=%d,d=%d share r=%d,w=%d,d=%d\n",
493 IrpSp
->FileObject
, &IrpSp
->FileObject
->FileName
,
494 IrpSp
->FileObject
->ReadAccess
, IrpSp
->FileObject
->WriteAccess
,
495 IrpSp
->FileObject
->DeleteAccess
, IrpSp
->FileObject
->SharedRead
,
496 IrpSp
->FileObject
->SharedWrite
, IrpSp
->FileObject
->SharedDelete
);
497 print_file_object(0, IrpSp
->FileObject
);
498 print_irps_flags(0, RxContext
->CurrentIrpSp
);
500 DbgP("Couldn't print FileObject IrpSp is NULL\n");
502 print_fo_all(1, RxContext
);
503 if (RxContext
->CurrentIrp
)
504 print_irp_flags(0, RxContext
->CurrentIrp
);
507 /* convert strings from unicode -> ansi during marshalling to
508 * save space in the upcall buffers and avoid extra copies */
509 INLINE ULONG
length_as_utf8(
510 PCUNICODE_STRING str
)
512 ULONG ActualCount
= 0;
513 RtlUnicodeToUTF8N(NULL
, 0xffff, &ActualCount
, str
->Buffer
, str
->Length
);
514 return sizeof(str
->MaximumLength
) + ActualCount
+ sizeof(UNICODE_NULL
);
517 NTSTATUS
marshall_unicode_as_utf8(
518 IN OUT
unsigned char **pos
,
519 IN PCUNICODE_STRING str
)
525 if (str
->Length
== 0) {
526 status
= STATUS_SUCCESS
;
528 ansi
.MaximumLength
= 1;
532 /* query the number of bytes required for the utf8 encoding */
533 status
= RtlUnicodeToUTF8N(NULL
, 0xffff,
534 &ActualCount
, str
->Buffer
, str
->Length
);
536 print_error("RtlUnicodeToUTF8N('%wZ') failed with 0x%08X\n",
541 /* convert the string directly into the upcall buffer */
542 ansi
.Buffer
= (PCHAR
)*pos
+ sizeof(ansi
.MaximumLength
);
543 ansi
.MaximumLength
= (USHORT
)ActualCount
+ sizeof(UNICODE_NULL
);
544 status
= RtlUnicodeToUTF8N(ansi
.Buffer
, ansi
.MaximumLength
,
545 &ActualCount
, str
->Buffer
, str
->Length
);
547 print_error("RtlUnicodeToUTF8N(%hu, '%wZ', %hu) failed with 0x%08X\n",
548 ansi
.MaximumLength
, str
, str
->Length
, status
);
553 RtlCopyMemory(*pos
, &ansi
.MaximumLength
, sizeof(ansi
.MaximumLength
));
554 *pos
+= sizeof(ansi
.MaximumLength
);
555 (*pos
)[ActualCount
] = '\0';
556 *pos
+= ansi
.MaximumLength
;
561 NTSTATUS
marshal_nfs41_header(
562 nfs41_updowncall_entry
*entry
,
567 NTSTATUS status
= STATUS_SUCCESS
;
568 ULONG header_len
= 0;
569 unsigned char *tmp
= buf
;
571 header_len
= sizeof(entry
->version
) + sizeof(entry
->xid
) +
572 sizeof(entry
->opcode
) + 2 * sizeof(HANDLE
);
573 if (header_len
> buf_len
) {
574 status
= STATUS_INSUFFICIENT_RESOURCES
;
579 RtlCopyMemory(tmp
, &entry
->version
, sizeof(entry
->version
));
580 tmp
+= sizeof(entry
->version
);
581 RtlCopyMemory(tmp
, &entry
->xid
, sizeof(entry
->xid
));
582 tmp
+= sizeof(entry
->xid
);
583 RtlCopyMemory(tmp
, &entry
->opcode
, sizeof(entry
->opcode
));
584 tmp
+= sizeof(entry
->opcode
);
585 RtlCopyMemory(tmp
, &entry
->session
, sizeof(HANDLE
));
586 tmp
+= sizeof(HANDLE
);
587 RtlCopyMemory(tmp
, &entry
->open_state
, sizeof(HANDLE
));
588 tmp
+= sizeof(HANDLE
);
590 #ifdef DEBUG_MARSHAL_HEADER
591 if (MmIsAddressValid(entry
->filename
))
592 DbgP("[upcall header] xid=%lld opcode=%s filename=%wZ version=%d "
593 "session=0x%x open_state=0x%x\n", entry
->xid
,
594 opcode2string(entry
->opcode
), entry
->filename
,
595 entry
->version
, entry
->session
, entry
->open_state
);
597 status
= STATUS_INTERNAL_ERROR
;
603 const char* secflavorop2name(
607 case RPCSEC_AUTH_SYS
: return "AUTH_SYS";
608 case RPCSEC_AUTHGSS_KRB5
: return "AUTHGSS_KRB5";
609 case RPCSEC_AUTHGSS_KRB5I
: return "AUTHGSS_KRB5I";
610 case RPCSEC_AUTHGSS_KRB5P
: return "AUTHGSS_KRB5P";
613 return "UNKNOWN FLAVOR";
615 NTSTATUS
marshal_nfs41_mount(
616 nfs41_updowncall_entry
*entry
,
621 NTSTATUS status
= STATUS_SUCCESS
;
622 ULONG header_len
= 0;
623 unsigned char *tmp
= buf
;
625 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
626 if (status
) goto out
;
629 /* 03/25/2011: Kernel crash to nfsd not running but mount upcall cued up */
630 if (!MmIsAddressValid(entry
->u
.Mount
.srv_name
) ||
631 !MmIsAddressValid(entry
->u
.Mount
.root
)) {
632 status
= STATUS_INTERNAL_ERROR
;
635 header_len
= *len
+ length_as_utf8(entry
->u
.Mount
.srv_name
) +
636 length_as_utf8(entry
->u
.Mount
.root
) + 3 * sizeof(DWORD
);
637 if (header_len
> buf_len
) {
638 status
= STATUS_INSUFFICIENT_RESOURCES
;
641 status
= marshall_unicode_as_utf8(&tmp
, entry
->u
.Mount
.srv_name
);
642 if (status
) goto out
;
643 status
= marshall_unicode_as_utf8(&tmp
, entry
->u
.Mount
.root
);
644 if (status
) goto out
;
645 RtlCopyMemory(tmp
, &entry
->u
.Mount
.sec_flavor
, sizeof(DWORD
));
646 tmp
+= sizeof(DWORD
);
647 RtlCopyMemory(tmp
, &entry
->u
.Mount
.rsize
, sizeof(DWORD
));
648 tmp
+= sizeof(DWORD
);
649 RtlCopyMemory(tmp
, &entry
->u
.Mount
.wsize
, sizeof(DWORD
));
653 #ifdef DEBUG_MARSHAL_DETAIL
654 DbgP("marshal_nfs41_mount: server name=%wZ mount point=%wZ sec_flavor=%s "
655 "rsize=%d wsize=%d\n", entry
->u
.Mount
.srv_name
, entry
->u
.Mount
.root
,
656 secflavorop2name(entry
->u
.Mount
.sec_flavor
), entry
->u
.Mount
.rsize
,
657 entry
->u
.Mount
.wsize
);
663 NTSTATUS
marshal_nfs41_unmount(
664 nfs41_updowncall_entry
*entry
,
669 return marshal_nfs41_header(entry
, buf
, buf_len
, len
);
672 NTSTATUS
marshal_nfs41_open(
673 nfs41_updowncall_entry
*entry
,
678 NTSTATUS status
= STATUS_SUCCESS
;
679 ULONG header_len
= 0;
680 unsigned char *tmp
= buf
;
682 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
683 if (status
) goto out
;
686 header_len
= *len
+ length_as_utf8(entry
->filename
) +
687 7 * sizeof(ULONG
) + 2 * sizeof(HANDLE
) +
688 length_as_utf8(&entry
->u
.Open
.symlink
);
689 if (header_len
> buf_len
) {
690 status
= STATUS_INSUFFICIENT_RESOURCES
;
693 status
= marshall_unicode_as_utf8(&tmp
, entry
->filename
);
694 if (status
) goto out
;
695 RtlCopyMemory(tmp
, &entry
->u
.Open
.access_mask
,
696 sizeof(entry
->u
.Open
.access_mask
));
697 tmp
+= sizeof(entry
->u
.Open
.access_mask
);
698 RtlCopyMemory(tmp
, &entry
->u
.Open
.access_mode
,
699 sizeof(entry
->u
.Open
.access_mode
));
700 tmp
+= sizeof(entry
->u
.Open
.access_mode
);
701 RtlCopyMemory(tmp
, &entry
->u
.Open
.attrs
, sizeof(entry
->u
.Open
.attrs
));
702 tmp
+= sizeof(entry
->u
.Open
.attrs
);
703 RtlCopyMemory(tmp
, &entry
->u
.Open
.copts
, sizeof(entry
->u
.Open
.copts
));
704 tmp
+= sizeof(entry
->u
.Open
.copts
);
705 RtlCopyMemory(tmp
, &entry
->u
.Open
.disp
, sizeof(entry
->u
.Open
.disp
));
706 tmp
+= sizeof(entry
->u
.Open
.disp
);
707 RtlCopyMemory(tmp
, &entry
->u
.Open
.open_owner_id
,
708 sizeof(entry
->u
.Open
.open_owner_id
));
709 tmp
+= sizeof(entry
->u
.Open
.open_owner_id
);
710 RtlCopyMemory(tmp
, &entry
->u
.Open
.mode
, sizeof(DWORD
));
711 tmp
+= sizeof(DWORD
);
712 RtlCopyMemory(tmp
, &entry
->u
.Open
.srv_open
, sizeof(HANDLE
));
713 tmp
+= sizeof(HANDLE
);
714 status
= marshall_unicode_as_utf8(&tmp
, &entry
->u
.Open
.symlink
);
715 if (status
) goto out
;
718 if (entry
->u
.Open
.EaMdl
) {
719 entry
->u
.Open
.EaBuffer
=
720 MmMapLockedPagesSpecifyCache(entry
->u
.Open
.EaMdl
,
722 UserMode
, MmNonCached
, NULL
, TRUE
, NormalPagePriority
);
724 UserMode
, MmCached
, NULL
, TRUE
, NormalPagePriority
);
726 if (entry
->u
.Open
.EaBuffer
== NULL
) {
727 print_error("MmMapLockedPagesSpecifyCache failed to map pages\n");
728 status
= STATUS_INSUFFICIENT_RESOURCES
;
732 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
733 print_error("Call to MmMapLocked failed due to exception 0x%x\n", _SEH2_GetExceptionCode());
734 status
= STATUS_ACCESS_DENIED
;
737 RtlCopyMemory(tmp
, &entry
->u
.Open
.EaBuffer
, sizeof(HANDLE
));
740 #ifdef DEBUG_MARSHAL_DETAIL
741 DbgP("marshal_nfs41_open: name=%wZ mask=0x%x access=0x%x attrs=0x%x "
742 "opts=0x%x dispo=0x%x open_owner_id=0x%x mode=%o srv_open=%p ea=%p\n",
743 entry
->filename
, entry
->u
.Open
.access_mask
,
744 entry
->u
.Open
.access_mode
, entry
->u
.Open
.attrs
, entry
->u
.Open
.copts
,
745 entry
->u
.Open
.disp
, entry
->u
.Open
.open_owner_id
, entry
->u
.Open
.mode
,
746 entry
->u
.Open
.srv_open
, entry
->u
.Open
.EaBuffer
);
752 NTSTATUS
marshal_nfs41_rw(
753 nfs41_updowncall_entry
*entry
,
758 NTSTATUS status
= STATUS_SUCCESS
;
759 ULONG header_len
= 0;
760 unsigned char *tmp
= buf
;
762 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
763 if (status
) goto out
;
766 header_len
= *len
+ sizeof(entry
->buf_len
) +
767 sizeof(entry
->u
.ReadWrite
.offset
) + sizeof(HANDLE
);
768 if (header_len
> buf_len
) {
769 status
= STATUS_INSUFFICIENT_RESOURCES
;
773 RtlCopyMemory(tmp
, &entry
->buf_len
, sizeof(entry
->buf_len
));
774 tmp
+= sizeof(entry
->buf_len
);
775 RtlCopyMemory(tmp
, &entry
->u
.ReadWrite
.offset
,
776 sizeof(entry
->u
.ReadWrite
.offset
));
777 tmp
+= sizeof(entry
->u
.ReadWrite
.offset
);
779 entry
->u
.ReadWrite
.MdlAddress
->MdlFlags
|= MDL_MAPPING_CAN_FAIL
;
781 MmMapLockedPagesSpecifyCache(entry
->u
.ReadWrite
.MdlAddress
,
783 UserMode
, MmNonCached
, NULL
, TRUE
, NormalPagePriority
);
785 UserMode
, MmCached
, NULL
, TRUE
, NormalPagePriority
);
787 if (entry
->buf
== NULL
) {
788 print_error("MmMapLockedPagesSpecifyCache failed to map pages\n");
789 status
= STATUS_INSUFFICIENT_RESOURCES
;
792 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
794 code
= _SEH2_GetExceptionCode();
795 print_error("Call to MmMapLocked failed due to exception 0x%x\n", code
);
796 status
= STATUS_ACCESS_DENIED
;
799 RtlCopyMemory(tmp
, &entry
->buf
, sizeof(HANDLE
));
802 #ifdef DEBUG_MARSHAL_DETAIL
803 DbgP("marshal_nfs41_rw: len=%lu offset=%llu MdlAddress=%p Userspace=%p\n",
804 entry
->buf_len
, entry
->u
.ReadWrite
.offset
,
805 entry
->u
.ReadWrite
.MdlAddress
, entry
->buf
);
811 NTSTATUS
marshal_nfs41_lock(
812 nfs41_updowncall_entry
*entry
,
817 NTSTATUS status
= STATUS_SUCCESS
;
818 ULONG header_len
= 0;
819 unsigned char *tmp
= buf
;
821 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
822 if (status
) goto out
;
825 header_len
= *len
+ 2 * sizeof(LONGLONG
) + 2 * sizeof(BOOLEAN
);
826 if (header_len
> buf_len
) {
827 status
= STATUS_INSUFFICIENT_RESOURCES
;
830 RtlCopyMemory(tmp
, &entry
->u
.Lock
.offset
, sizeof(LONGLONG
));
831 tmp
+= sizeof(LONGLONG
);
832 RtlCopyMemory(tmp
, &entry
->u
.Lock
.length
, sizeof(LONGLONG
));
833 tmp
+= sizeof(LONGLONG
);
834 RtlCopyMemory(tmp
, &entry
->u
.Lock
.exclusive
, sizeof(BOOLEAN
));
835 tmp
+= sizeof(BOOLEAN
);
836 RtlCopyMemory(tmp
, &entry
->u
.Lock
.blocking
, sizeof(BOOLEAN
));
839 #ifdef DEBUG_MARSHAL_DETAIL
840 DbgP("marshal_nfs41_lock: offset=%llx length=%llx exclusive=%u "
841 "blocking=%u\n", entry
->u
.Lock
.offset
, entry
->u
.Lock
.length
,
842 entry
->u
.Lock
.exclusive
, entry
->u
.Lock
.blocking
);
848 NTSTATUS
marshal_nfs41_unlock(
849 nfs41_updowncall_entry
*entry
,
854 NTSTATUS status
= STATUS_SUCCESS
;
855 ULONG header_len
= 0;
856 unsigned char *tmp
= buf
;
857 PLOWIO_LOCK_LIST lock
;
859 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
860 if (status
) goto out
;
863 header_len
= *len
+ sizeof(ULONG
) +
864 entry
->u
.Unlock
.count
* 2 * sizeof(LONGLONG
);
865 if (header_len
> buf_len
) {
866 status
= STATUS_INSUFFICIENT_RESOURCES
;
869 RtlCopyMemory(tmp
, &entry
->u
.Unlock
.count
, sizeof(ULONG
));
870 tmp
+= sizeof(ULONG
);
872 lock
= &entry
->u
.Unlock
.locks
;
874 RtlCopyMemory(tmp
, &lock
->ByteOffset
, sizeof(LONGLONG
));
875 tmp
+= sizeof(LONGLONG
);
876 RtlCopyMemory(tmp
, &lock
->Length
, sizeof(LONGLONG
));
877 tmp
+= sizeof(LONGLONG
);
882 #ifdef DEBUG_MARSHAL_DETAIL
883 DbgP("marshal_nfs41_unlock: count=%u\n", entry
->u
.Unlock
.count
);
889 NTSTATUS
marshal_nfs41_close(
890 nfs41_updowncall_entry
*entry
,
895 NTSTATUS status
= STATUS_SUCCESS
;
896 ULONG header_len
= 0;
897 unsigned char *tmp
= buf
;
899 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
900 if (status
) goto out
;
903 header_len
= *len
+ sizeof(BOOLEAN
) + sizeof(HANDLE
);
904 if (entry
->u
.Close
.remove
)
905 header_len
+= length_as_utf8(entry
->filename
) +
908 if (header_len
> buf_len
) {
909 status
= STATUS_INSUFFICIENT_RESOURCES
;
912 RtlCopyMemory(tmp
, &entry
->u
.Close
.remove
, sizeof(BOOLEAN
));
913 tmp
+= sizeof(BOOLEAN
);
914 RtlCopyMemory(tmp
, &entry
->u
.Close
.srv_open
, sizeof(HANDLE
));
915 if (entry
->u
.Close
.remove
) {
916 tmp
+= sizeof(HANDLE
);
917 status
= marshall_unicode_as_utf8(&tmp
, entry
->filename
);
918 if (status
) goto out
;
919 RtlCopyMemory(tmp
, &entry
->u
.Close
.renamed
, sizeof(BOOLEAN
));
923 #ifdef DEBUG_MARSHAL_DETAIL
924 DbgP("marshal_nfs41_close: name=%wZ remove=%d srv_open=%p renamed=%d\n",
925 entry
->filename
->Length
?entry
->filename
:&SLASH
,
926 entry
->u
.Close
.remove
, entry
->u
.Close
.srv_open
, entry
->u
.Close
.renamed
);
932 NTSTATUS
marshal_nfs41_dirquery(
933 nfs41_updowncall_entry
*entry
,
938 NTSTATUS status
= STATUS_SUCCESS
;
939 ULONG header_len
= 0;
940 unsigned char *tmp
= buf
;
942 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
943 if (status
) goto out
;
946 header_len
= *len
+ 2 * sizeof(ULONG
) + sizeof(HANDLE
) +
947 length_as_utf8(entry
->u
.QueryFile
.filter
) + 3 * sizeof(BOOLEAN
);
948 if (header_len
> buf_len
) {
949 status
= STATUS_INSUFFICIENT_RESOURCES
;
953 RtlCopyMemory(tmp
, &entry
->u
.QueryFile
.InfoClass
, sizeof(ULONG
));
954 tmp
+= sizeof(ULONG
);
955 RtlCopyMemory(tmp
, &entry
->buf_len
, sizeof(ULONG
));
956 tmp
+= sizeof(ULONG
);
957 status
= marshall_unicode_as_utf8(&tmp
, entry
->u
.QueryFile
.filter
);
958 if (status
) goto out
;
959 RtlCopyMemory(tmp
, &entry
->u
.QueryFile
.initial_query
, sizeof(BOOLEAN
));
960 tmp
+= sizeof(BOOLEAN
);
961 RtlCopyMemory(tmp
, &entry
->u
.QueryFile
.restart_scan
, sizeof(BOOLEAN
));
962 tmp
+= sizeof(BOOLEAN
);
963 RtlCopyMemory(tmp
, &entry
->u
.QueryFile
.return_single
, sizeof(BOOLEAN
));
964 tmp
+= sizeof(BOOLEAN
);
966 entry
->u
.QueryFile
.mdl_buf
=
967 MmMapLockedPagesSpecifyCache(entry
->u
.QueryFile
.mdl
,
969 UserMode
, MmNonCached
, NULL
, TRUE
, NormalPagePriority
);
971 UserMode
, MmCached
, NULL
, TRUE
, NormalPagePriority
);
973 if (entry
->u
.QueryFile
.mdl_buf
== NULL
) {
974 print_error("MmMapLockedPagesSpecifyCache failed to map pages\n");
975 status
= STATUS_INSUFFICIENT_RESOURCES
;
978 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
980 code
= _SEH2_GetExceptionCode();
981 print_error("Call to MmMapLocked failed due to exception 0x%x\n", code
);
982 status
= STATUS_ACCESS_DENIED
;
985 RtlCopyMemory(tmp
, &entry
->u
.QueryFile
.mdl_buf
, sizeof(HANDLE
));
988 #ifdef DEBUG_MARSHAL_DETAIL
989 DbgP("marshal_nfs41_dirquery: filter='%wZ'class=%d len=%d "
990 "1st\\restart\\single=%d\\%d\\%d\n", entry
->u
.QueryFile
.filter
,
991 entry
->u
.QueryFile
.InfoClass
, entry
->buf_len
,
992 entry
->u
.QueryFile
.initial_query
, entry
->u
.QueryFile
.restart_scan
,
993 entry
->u
.QueryFile
.return_single
);
999 NTSTATUS
marshal_nfs41_filequery(
1000 nfs41_updowncall_entry
*entry
,
1005 NTSTATUS status
= STATUS_SUCCESS
;
1006 ULONG header_len
= 0;
1007 unsigned char *tmp
= buf
;
1009 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
1010 if (status
) goto out
;
1013 header_len
= *len
+ 2 * sizeof(ULONG
);
1014 if (header_len
> buf_len
) {
1015 status
= STATUS_INSUFFICIENT_RESOURCES
;
1018 RtlCopyMemory(tmp
, &entry
->u
.QueryFile
.InfoClass
, sizeof(ULONG
));
1019 tmp
+= sizeof(ULONG
);
1020 RtlCopyMemory(tmp
, &entry
->buf_len
, sizeof(ULONG
));
1021 tmp
+= sizeof(ULONG
);
1022 RtlCopyMemory(tmp
, &entry
->session
, sizeof(HANDLE
));
1023 tmp
+= sizeof(HANDLE
);
1024 RtlCopyMemory(tmp
, &entry
->open_state
, sizeof(HANDLE
));
1027 #ifdef DEBUG_MARSHAL_DETAIL
1028 DbgP("marshal_nfs41_filequery: class=%d\n", entry
->u
.QueryFile
.InfoClass
);
1034 NTSTATUS
marshal_nfs41_fileset(
1035 nfs41_updowncall_entry
*entry
,
1040 NTSTATUS status
= STATUS_SUCCESS
;
1041 ULONG header_len
= 0;
1042 unsigned char *tmp
= buf
;
1044 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
1045 if (status
) goto out
;
1048 header_len
= *len
+ length_as_utf8(entry
->filename
) +
1049 2 * sizeof(ULONG
) + entry
->buf_len
;
1050 if (header_len
> buf_len
) {
1051 status
= STATUS_INSUFFICIENT_RESOURCES
;
1054 status
= marshall_unicode_as_utf8(&tmp
, entry
->filename
);
1055 if (status
) goto out
;
1056 RtlCopyMemory(tmp
, &entry
->u
.SetFile
.InfoClass
, sizeof(ULONG
));
1057 tmp
+= sizeof(ULONG
);
1058 RtlCopyMemory(tmp
, &entry
->buf_len
, sizeof(ULONG
));
1059 tmp
+= sizeof(ULONG
);
1060 RtlCopyMemory(tmp
, entry
->buf
, entry
->buf_len
);
1063 #ifdef DEBUG_MARSHAL_DETAIL
1064 DbgP("marshal_nfs41_fileset: filename='%wZ' class=%d\n",
1065 entry
->filename
, entry
->u
.SetFile
.InfoClass
);
1071 NTSTATUS
marshal_nfs41_easet(
1072 nfs41_updowncall_entry
*entry
,
1077 NTSTATUS status
= STATUS_SUCCESS
;
1078 ULONG header_len
= 0;
1079 unsigned char *tmp
= buf
;
1081 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
1082 if (status
) goto out
;
1085 header_len
= *len
+ length_as_utf8(entry
->filename
) +
1086 sizeof(ULONG
) + entry
->buf_len
+ sizeof(DWORD
);
1087 if (header_len
> buf_len
) {
1088 status
= STATUS_INSUFFICIENT_RESOURCES
;
1092 status
= marshall_unicode_as_utf8(&tmp
, entry
->filename
);
1093 if (status
) goto out
;
1094 RtlCopyMemory(tmp
, &entry
->u
.SetEa
.mode
, sizeof(DWORD
));
1095 tmp
+= sizeof(DWORD
);
1096 RtlCopyMemory(tmp
, &entry
->buf_len
, sizeof(ULONG
));
1097 tmp
+= sizeof(ULONG
);
1098 RtlCopyMemory(tmp
, entry
->buf
, entry
->buf_len
);
1101 #ifdef DEBUG_MARSHAL_DETAIL
1102 DbgP("marshal_nfs41_easet: filename=%wZ, buflen=%d mode=0x%x\n",
1103 entry
->filename
, entry
->buf_len
, entry
->u
.SetEa
.mode
);
1109 NTSTATUS
marshal_nfs41_eaget(
1110 nfs41_updowncall_entry
*entry
,
1115 NTSTATUS status
= STATUS_SUCCESS
;
1116 ULONG header_len
= 0;
1117 unsigned char *tmp
= buf
;
1119 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
1120 if (status
) goto out
;
1123 header_len
= *len
+ length_as_utf8(entry
->filename
) +
1124 3 * sizeof(ULONG
) + entry
->u
.QueryEa
.EaListLength
+ 2 * sizeof(BOOLEAN
);
1126 if (header_len
> buf_len
) {
1127 status
= STATUS_INSUFFICIENT_RESOURCES
;
1131 status
= marshall_unicode_as_utf8(&tmp
, entry
->filename
);
1132 if (status
) goto out
;
1133 RtlCopyMemory(tmp
, &entry
->u
.QueryEa
.EaIndex
, sizeof(ULONG
));
1134 tmp
+= sizeof(ULONG
);
1135 RtlCopyMemory(tmp
, &entry
->u
.QueryEa
.RestartScan
, sizeof(BOOLEAN
));
1136 tmp
+= sizeof(BOOLEAN
);
1137 RtlCopyMemory(tmp
, &entry
->u
.QueryEa
.ReturnSingleEntry
, sizeof(BOOLEAN
));
1138 tmp
+= sizeof(BOOLEAN
);
1139 RtlCopyMemory(tmp
, &entry
->buf_len
, sizeof(ULONG
));
1140 tmp
+= sizeof(ULONG
);
1141 RtlCopyMemory(tmp
, &entry
->u
.QueryEa
.EaListLength
, sizeof(ULONG
));
1142 tmp
+= sizeof(ULONG
);
1143 if (entry
->u
.QueryEa
.EaList
&& entry
->u
.QueryEa
.EaListLength
)
1144 RtlCopyMemory(tmp
, entry
->u
.QueryEa
.EaList
,
1145 entry
->u
.QueryEa
.EaListLength
);
1148 #ifdef DEBUG_MARSHAL_DETAIL
1149 DbgP("marshal_nfs41_eaget: filename=%wZ, index=%d list_len=%d "
1150 "rescan=%d single=%d\n", entry
->filename
,
1151 entry
->u
.QueryEa
.EaIndex
, entry
->u
.QueryEa
.EaListLength
,
1152 entry
->u
.QueryEa
.RestartScan
, entry
->u
.QueryEa
.ReturnSingleEntry
);
1158 NTSTATUS
marshal_nfs41_symlink(
1159 nfs41_updowncall_entry
*entry
,
1164 NTSTATUS status
= STATUS_SUCCESS
;
1165 ULONG header_len
= 0;
1166 unsigned char *tmp
= buf
;
1168 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
1169 if (status
) goto out
;
1172 header_len
= *len
+ sizeof(BOOLEAN
) + length_as_utf8(entry
->filename
);
1173 if (entry
->u
.Symlink
.set
)
1174 header_len
+= length_as_utf8(entry
->u
.Symlink
.target
);
1175 if (header_len
> buf_len
) {
1176 status
= STATUS_INSUFFICIENT_RESOURCES
;
1180 status
= marshall_unicode_as_utf8(&tmp
, entry
->filename
);
1181 if (status
) goto out
;
1182 RtlCopyMemory(tmp
, &entry
->u
.Symlink
.set
, sizeof(BOOLEAN
));
1183 tmp
+= sizeof(BOOLEAN
);
1184 if (entry
->u
.Symlink
.set
) {
1185 status
= marshall_unicode_as_utf8(&tmp
, entry
->u
.Symlink
.target
);
1186 if (status
) goto out
;
1190 #ifdef DEBUG_MARSHAL_DETAIL
1191 DbgP("marshal_nfs41_symlink: name %wZ symlink target %wZ\n",
1193 entry
->u
.Symlink
.set
?entry
->u
.Symlink
.target
: NULL
);
1199 NTSTATUS
marshal_nfs41_volume(
1200 nfs41_updowncall_entry
*entry
,
1205 NTSTATUS status
= STATUS_SUCCESS
;
1206 ULONG header_len
= 0;
1207 unsigned char *tmp
= buf
;
1209 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
1210 if (status
) goto out
;
1213 header_len
= *len
+ sizeof(FS_INFORMATION_CLASS
);
1214 if (header_len
> buf_len
) {
1215 status
= STATUS_INSUFFICIENT_RESOURCES
;
1219 RtlCopyMemory(tmp
, &entry
->u
.Volume
.query
, sizeof(FS_INFORMATION_CLASS
));
1222 #ifdef DEBUG_MARSHAL_DETAIL
1223 DbgP("marshal_nfs41_volume: class=%d\n", entry
->u
.Volume
.query
);
1229 NTSTATUS
marshal_nfs41_getacl(
1230 nfs41_updowncall_entry
*entry
,
1235 NTSTATUS status
= STATUS_SUCCESS
;
1236 ULONG header_len
= 0;
1237 unsigned char *tmp
= buf
;
1239 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
1240 if (status
) goto out
;
1243 header_len
= *len
+ sizeof(SECURITY_INFORMATION
);
1244 if (header_len
> buf_len
) {
1245 status
= STATUS_INSUFFICIENT_RESOURCES
;
1249 RtlCopyMemory(tmp
, &entry
->u
.Acl
.query
, sizeof(SECURITY_INFORMATION
));
1252 #ifdef DEBUG_MARSHAL_DETAIL
1253 DbgP("marshal_nfs41_getacl: class=0x%x\n", entry
->u
.Acl
.query
);
1259 NTSTATUS
marshal_nfs41_setacl(
1260 nfs41_updowncall_entry
*entry
,
1265 NTSTATUS status
= STATUS_SUCCESS
;
1266 ULONG header_len
= 0;
1267 unsigned char *tmp
= buf
;
1269 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
1270 if (status
) goto out
;
1273 header_len
= *len
+ sizeof(SECURITY_INFORMATION
) +
1274 sizeof(ULONG
) + entry
->buf_len
;
1275 if (header_len
> buf_len
) {
1276 status
= STATUS_INSUFFICIENT_RESOURCES
;
1280 RtlCopyMemory(tmp
, &entry
->u
.Acl
.query
, sizeof(SECURITY_INFORMATION
));
1281 tmp
+= sizeof(SECURITY_INFORMATION
);
1282 RtlCopyMemory(tmp
, &entry
->buf_len
, sizeof(ULONG
));
1283 tmp
+= sizeof(ULONG
);
1284 RtlCopyMemory(tmp
, entry
->buf
, entry
->buf_len
);
1287 #ifdef DEBUG_MARSHAL_DETAIL
1288 DbgP("marshal_nfs41_setacl: class=0x%x sec_desc_len=%lu\n",
1289 entry
->u
.Acl
.query
, entry
->buf_len
);
1295 NTSTATUS
marshal_nfs41_shutdown(
1296 nfs41_updowncall_entry
*entry
,
1301 return marshal_nfs41_header(entry
, buf
, buf_len
, len
);
1304 void nfs41_invalidate_cache (
1305 IN PRX_CONTEXT RxContext
)
1307 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
1308 unsigned char *buf
= LowIoContext
->ParamsFor
.IoCtl
.pInputBuffer
;
1309 ULONG flag
= DISABLE_CACHING
;
1310 PMRX_SRV_OPEN srv_open
;
1312 RtlCopyMemory(&srv_open
, buf
, sizeof(HANDLE
));
1313 #ifdef DEBUG_INVALIDATE_CACHE
1314 DbgP("nfs41_invalidate_cache: received srv_open=%p %wZ\n",
1315 srv_open
, srv_open
->pAlreadyPrefixedName
);
1317 if (MmIsAddressValid(srv_open
))
1318 RxIndicateChangeOfBufferingStateForSrvOpen(
1319 srv_open
->pFcb
->pNetRoot
->pSrvCall
, srv_open
,
1320 srv_open
->Key
, ULongToPtr(flag
));
1323 NTSTATUS
handle_upcall(
1324 IN PRX_CONTEXT RxContext
,
1325 IN nfs41_updowncall_entry
*entry
,
1328 NTSTATUS status
= STATUS_SUCCESS
;
1329 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
1330 ULONG cbOut
= LowIoContext
->ParamsFor
.IoCtl
.OutputBufferLength
;
1331 unsigned char *pbOut
= LowIoContext
->ParamsFor
.IoCtl
.pOutputBuffer
;
1333 status
= SeImpersonateClientEx(entry
->psec_ctx
, NULL
);
1334 if (status
!= STATUS_SUCCESS
) {
1335 print_error("SeImpersonateClientEx failed %x\n", status
);
1339 switch(entry
->opcode
) {
1340 case NFS41_SHUTDOWN
:
1341 status
= marshal_nfs41_shutdown(entry
, pbOut
, cbOut
, len
);
1342 KeSetEvent(&entry
->cond
, 0, FALSE
);
1345 status
= marshal_nfs41_mount(entry
, pbOut
, cbOut
, len
);
1348 status
= marshal_nfs41_unmount(entry
, pbOut
, cbOut
, len
);
1351 status
= marshal_nfs41_open(entry
, pbOut
, cbOut
, len
);
1354 status
= marshal_nfs41_rw(entry
, pbOut
, cbOut
, len
);
1357 status
= marshal_nfs41_rw(entry
, pbOut
, cbOut
, len
);
1360 status
= marshal_nfs41_lock(entry
, pbOut
, cbOut
, len
);
1363 status
= marshal_nfs41_unlock(entry
, pbOut
, cbOut
, len
);
1366 status
= marshal_nfs41_close(entry
, pbOut
, cbOut
, len
);
1368 case NFS41_DIR_QUERY
:
1369 status
= marshal_nfs41_dirquery(entry
, pbOut
, cbOut
, len
);
1371 case NFS41_FILE_QUERY
:
1372 status
= marshal_nfs41_filequery(entry
, pbOut
, cbOut
, len
);
1374 case NFS41_FILE_SET
:
1375 status
= marshal_nfs41_fileset(entry
, pbOut
, cbOut
, len
);
1378 status
= marshal_nfs41_easet(entry
, pbOut
, cbOut
, len
);
1381 status
= marshal_nfs41_eaget(entry
, pbOut
, cbOut
, len
);
1384 status
= marshal_nfs41_symlink(entry
, pbOut
, cbOut
, len
);
1386 case NFS41_VOLUME_QUERY
:
1387 status
= marshal_nfs41_volume(entry
, pbOut
, cbOut
, len
);
1389 case NFS41_ACL_QUERY
:
1390 status
= marshal_nfs41_getacl(entry
, pbOut
, cbOut
, len
);
1393 status
= marshal_nfs41_setacl(entry
, pbOut
, cbOut
, len
);
1396 status
= STATUS_INVALID_PARAMETER
;
1397 print_error("Unknown nfs41 ops %d\n", entry
->opcode
);
1400 if (status
== STATUS_SUCCESS
)
1401 print_hexbuf(0, (unsigned char *)"upcall buffer", pbOut
, *len
);
1407 NTSTATUS
nfs41_UpcallCreate(
1409 IN PSECURITY_CLIENT_CONTEXT clnt_sec_ctx
,
1411 IN HANDLE open_state
,
1413 IN PUNICODE_STRING filename
,
1414 OUT nfs41_updowncall_entry
**entry_out
)
1416 NTSTATUS status
= STATUS_SUCCESS
;
1417 nfs41_updowncall_entry
*entry
;
1418 SECURITY_SUBJECT_CONTEXT sec_ctx
;
1419 SECURITY_QUALITY_OF_SERVICE sec_qos
;
1421 entry
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(nfs41_updowncall_entry
),
1422 NFS41_MM_POOLTAG_UP
);
1423 if (entry
== NULL
) {
1424 status
= STATUS_INSUFFICIENT_RESOURCES
;
1428 RtlZeroMemory(entry
, sizeof(nfs41_updowncall_entry
));
1429 entry
->xid
= InterlockedIncrement64(&xid
);
1430 entry
->opcode
= opcode
;
1431 entry
->state
= NFS41_WAITING_FOR_UPCALL
;
1432 entry
->session
= session
;
1433 entry
->open_state
= open_state
;
1434 entry
->version
= version
;
1435 if (filename
&& filename
->Length
) entry
->filename
= filename
;
1436 else if (filename
&& !filename
->Length
) entry
->filename
= (PUNICODE_STRING
)&SLASH
;
1437 else entry
->filename
= (PUNICODE_STRING
)&EMPTY_STRING
;
1438 /*XXX KeInitializeEvent will bugcheck under verifier if allocated
1439 * from PagedPool? */
1440 KeInitializeEvent(&entry
->cond
, SynchronizationEvent
, FALSE
);
1441 ExInitializeFastMutex(&entry
->lock
);
1443 if (clnt_sec_ctx
== NULL
) {
1444 SeCaptureSubjectContext(&sec_ctx
);
1445 sec_qos
.ContextTrackingMode
= SECURITY_DYNAMIC_TRACKING
;
1446 sec_qos
.ImpersonationLevel
= SecurityImpersonation
;
1447 sec_qos
.Length
= sizeof(SECURITY_QUALITY_OF_SERVICE
);
1448 sec_qos
.EffectiveOnly
= 0;
1449 status
= SeCreateClientSecurityFromSubjectContext(&sec_ctx
, &sec_qos
,
1450 1, &entry
->sec_ctx
);
1451 if (status
!= STATUS_SUCCESS
) {
1452 print_error("nfs41_UpcallCreate: "
1453 "SeCreateClientSecurityFromSubjectContext failed with %x\n",
1457 entry
->psec_ctx
= &entry
->sec_ctx
;
1458 SeReleaseSubjectContext(&sec_ctx
);
1460 entry
->psec_ctx
= clnt_sec_ctx
;
1467 NTSTATUS
nfs41_UpcallWaitForReply(
1468 IN nfs41_updowncall_entry
*entry
,
1471 NTSTATUS status
= STATUS_SUCCESS
;
1473 nfs41_AddEntry(upcallLock
, upcall
, entry
);
1474 KeSetEvent(&upcallEvent
, 0, FALSE
);
1475 if (!entry
->async_op
) {
1476 LARGE_INTEGER timeout
;
1477 timeout
.QuadPart
= RELATIVE(SECONDS(secs
));
1478 /* 02/03/2011 AGLO: it is not clear what the "right" waiting design
1479 * should be. Having non-interruptable waiting seems to be the right
1480 * approach. However, when things go wrong, the only wait to proceed
1481 * is a reboot (since "waits" are not interruptable we can't stop a
1482 * hung task. Having interruptable wait causes issues with security
1483 * context. For now, I'm making CLOSE non-interruptable but keeping
1484 * the rest interruptable so that we don't have to reboot all the time
1486 /* 02/15/2011 cbodley: added NFS41_UNLOCK for the same reason. locking
1487 * tests were triggering an interrupted unlock, which led to a bugcheck
1488 * in CloseSrvOpen() */
1489 #define MAKE_WAITONCLOSE_NONITERRUPTABLE
1490 #ifdef MAKE_WAITONCLOSE_NONITERRUPTABLE
1491 if (entry
->opcode
== NFS41_CLOSE
|| entry
->opcode
== NFS41_UNLOCK
)
1492 status
= KeWaitForSingleObject(&entry
->cond
, Executive
,
1493 KernelMode
, FALSE
, &timeout
);
1495 status
= KeWaitForSingleObject(&entry
->cond
, Executive
,
1496 UserMode
, TRUE
, &timeout
);
1498 if (status
!= STATUS_SUCCESS
) {
1499 print_wait_status(1, "[downcall]", status
,
1500 opcode2string(entry
->opcode
), entry
, entry
->xid
);
1501 if (status
== STATUS_TIMEOUT
)
1502 status
= STATUS_NETWORK_UNREACHABLE
;
1506 status
= KeWaitForSingleObject(&entry
->cond
, Executive
, KernelMode
, FALSE
, NULL
);
1508 print_wait_status(0, "[downcall]", status
, opcode2string(entry
->opcode
),
1514 case STATUS_SUCCESS
: break;
1515 case STATUS_USER_APC
:
1516 case STATUS_ALERTED
:
1518 ExAcquireFastMutex(&entry
->lock
);
1519 if (entry
->state
== NFS41_DONE_PROCESSING
) {
1520 ExReleaseFastMutex(&entry
->lock
);
1523 DbgP("[upcall] abandoning %s entry=%p xid=%lld\n",
1524 opcode2string(entry
->opcode
), entry
, entry
->xid
);
1525 entry
->state
= NFS41_NOT_WAITING
;
1526 ExReleaseFastMutex(&entry
->lock
);
1529 nfs41_RemoveEntry(downcallLock
, entry
);
1534 NTSTATUS
nfs41_upcall(
1535 IN PRX_CONTEXT RxContext
)
1537 NTSTATUS status
= STATUS_SUCCESS
;
1538 nfs41_updowncall_entry
*entry
= NULL
;
1543 nfs41_RemoveFirst(upcallLock
, upcall
, pEntry
);
1545 entry
= (nfs41_updowncall_entry
*)CONTAINING_RECORD(pEntry
,
1546 nfs41_updowncall_entry
, next
);
1547 ExAcquireFastMutex(&entry
->lock
);
1548 nfs41_AddEntry(downcallLock
, downcall
, entry
);
1549 status
= handle_upcall(RxContext
, entry
, &len
);
1550 if (status
== STATUS_SUCCESS
&&
1551 entry
->state
== NFS41_WAITING_FOR_UPCALL
)
1552 entry
->state
= NFS41_WAITING_FOR_DOWNCALL
;
1553 ExReleaseFastMutex(&entry
->lock
);
1555 entry
->status
= status
;
1556 KeSetEvent(&entry
->cond
, 0, FALSE
);
1557 RxContext
->InformationToReturn
= 0;
1559 RxContext
->InformationToReturn
= len
;
1562 status
= KeWaitForSingleObject(&upcallEvent
, Executive
, UserMode
, TRUE
,
1563 (PLARGE_INTEGER
) NULL
);
1564 print_wait_status(0, "[upcall]", status
, NULL
, NULL
, 0);
1566 case STATUS_SUCCESS
: goto process_upcall
;
1567 case STATUS_USER_APC
:
1568 case STATUS_ALERTED
:
1576 void unmarshal_nfs41_header(
1577 nfs41_updowncall_entry
*tmp
,
1578 unsigned char **buf
)
1580 RtlZeroMemory(tmp
, sizeof(nfs41_updowncall_entry
));
1582 RtlCopyMemory(&tmp
->xid
, *buf
, sizeof(tmp
->xid
));
1583 *buf
+= sizeof(tmp
->xid
);
1584 RtlCopyMemory(&tmp
->opcode
, *buf
, sizeof(tmp
->opcode
));
1585 *buf
+= sizeof(tmp
->opcode
);
1586 RtlCopyMemory(&tmp
->status
, *buf
, sizeof(tmp
->status
));
1587 *buf
+= sizeof(tmp
->status
);
1588 RtlCopyMemory(&tmp
->errno
, *buf
, sizeof(tmp
->errno
));
1589 *buf
+= sizeof(tmp
->errno
);
1590 #ifdef DEBUG_MARSHAL_HEADER
1591 DbgP("[downcall header] xid=%lld opcode=%s status=%d errno=%d\n", tmp
->xid
,
1592 opcode2string(tmp
->opcode
), tmp
->status
, tmp
->errno
);
1596 void unmarshal_nfs41_mount(
1597 nfs41_updowncall_entry
*cur
,
1598 unsigned char **buf
)
1600 RtlCopyMemory(&cur
->session
, *buf
, sizeof(HANDLE
));
1601 *buf
+= sizeof(HANDLE
);
1602 RtlCopyMemory(&cur
->version
, *buf
, sizeof(DWORD
));
1603 *buf
+= sizeof(DWORD
);
1604 RtlCopyMemory(&cur
->u
.Mount
.lease_time
, *buf
, sizeof(DWORD
));
1605 *buf
+= sizeof(DWORD
);
1606 RtlCopyMemory(cur
->u
.Mount
.FsAttrs
, *buf
, sizeof(FILE_FS_ATTRIBUTE_INFORMATION
));
1607 #ifdef DEBUG_MARSHAL_DETAIL
1608 DbgP("unmarshal_nfs41_mount: session pointer 0x%x version %d lease_time "
1609 "%d\n", cur
->session
, cur
->version
, cur
->u
.Mount
.lease_time
);
1613 VOID
unmarshal_nfs41_setattr(
1614 nfs41_updowncall_entry
*cur
,
1615 PULONGLONG dest_buf
,
1616 unsigned char **buf
)
1618 RtlCopyMemory(dest_buf
, *buf
, sizeof(ULONGLONG
));
1619 #ifdef DEBUG_MARSHAL_DETAIL
1620 DbgP("unmarshal_nfs41_setattr: returned ChangeTime %llu\n", *dest_buf
);
1624 NTSTATUS
unmarshal_nfs41_rw(
1625 nfs41_updowncall_entry
*cur
,
1626 unsigned char **buf
)
1628 NTSTATUS status
= STATUS_SUCCESS
;
1630 RtlCopyMemory(&cur
->buf_len
, *buf
, sizeof(cur
->buf_len
));
1631 *buf
+= sizeof(cur
->buf_len
);
1632 RtlCopyMemory(&cur
->ChangeTime
, *buf
, sizeof(ULONGLONG
));
1633 #ifdef DEBUG_MARSHAL_DETAIL
1634 DbgP("unmarshal_nfs41_rw: returned len %lu ChangeTime %llu\n",
1635 cur
->buf_len
, cur
->ChangeTime
);
1638 /* 08/27/2010: it looks like we really don't need to call
1639 * MmUnmapLockedPages() eventhough we called
1640 * MmMapLockedPagesSpecifyCache() as the MDL passed to us
1641 * is already locked.
1644 MmUnmapLockedPages(cur
->buf
, cur
->u
.ReadWrite
.MdlAddress
);
1645 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
1647 code
= _SEH2_GetExceptionCode();
1648 print_error("Call to MmUnmapLockedPages failed due to"
1649 " exception 0x%0x\n", code
);
1650 status
= STATUS_ACCESS_DENIED
;
1656 NTSTATUS
unmarshal_nfs41_open(
1657 nfs41_updowncall_entry
*cur
,
1658 unsigned char **buf
)
1660 NTSTATUS status
= STATUS_SUCCESS
;
1663 if (cur
->u
.Open
.EaBuffer
)
1664 MmUnmapLockedPages(cur
->u
.Open
.EaBuffer
, cur
->u
.Open
.EaMdl
);
1665 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
1666 print_error("MmUnmapLockedPages thrown exception=0x%0x\n", _SEH2_GetExceptionCode());
1667 status
= cur
->status
= STATUS_ACCESS_DENIED
;
1671 RtlCopyMemory(&cur
->u
.Open
.binfo
, *buf
, sizeof(FILE_BASIC_INFORMATION
));
1672 *buf
+= sizeof(FILE_BASIC_INFORMATION
);
1673 RtlCopyMemory(&cur
->u
.Open
.sinfo
, *buf
, sizeof(FILE_STANDARD_INFORMATION
));
1674 *buf
+= sizeof(FILE_STANDARD_INFORMATION
);
1675 RtlCopyMemory(&cur
->open_state
, *buf
, sizeof(HANDLE
));
1676 *buf
+= sizeof(HANDLE
);
1677 RtlCopyMemory(&cur
->u
.Open
.mode
, *buf
, sizeof(DWORD
));
1678 *buf
+= sizeof(DWORD
);
1679 RtlCopyMemory(&cur
->ChangeTime
, *buf
, sizeof(ULONGLONG
));
1680 *buf
+= sizeof(ULONGLONG
);
1681 RtlCopyMemory(&cur
->u
.Open
.deleg_type
, *buf
, sizeof(DWORD
));
1682 *buf
+= sizeof(DWORD
);
1683 if (cur
->errno
== ERROR_REPARSE
) {
1684 RtlCopyMemory(&cur
->u
.Open
.symlink_embedded
, *buf
, sizeof(BOOLEAN
));
1685 *buf
+= sizeof(BOOLEAN
);
1686 RtlCopyMemory(&cur
->u
.Open
.symlink
.MaximumLength
, *buf
,
1688 *buf
+= sizeof(USHORT
);
1689 cur
->u
.Open
.symlink
.Length
= cur
->u
.Open
.symlink
.MaximumLength
-
1691 cur
->u
.Open
.symlink
.Buffer
= RxAllocatePoolWithTag(NonPagedPool
,
1692 cur
->u
.Open
.symlink
.MaximumLength
, NFS41_MM_POOLTAG
);
1693 if (cur
->u
.Open
.symlink
.Buffer
== NULL
) {
1694 cur
->status
= STATUS_INSUFFICIENT_RESOURCES
;
1695 status
= STATUS_UNSUCCESSFUL
;
1698 RtlCopyMemory(cur
->u
.Open
.symlink
.Buffer
, *buf
,
1699 cur
->u
.Open
.symlink
.MaximumLength
);
1700 #ifdef DEBUG_MARSHAL_DETAIL
1701 DbgP("unmarshal_nfs41_open: ERROR_REPARSE -> '%wZ'\n", &cur
->u
.Open
.symlink
);
1704 #ifdef DEBUG_MARSHAL_DETAIL
1705 DbgP("unmarshal_nfs41_open: open_state 0x%x mode %o changeattr %llu "
1706 "deleg_type %d\n", cur
->open_state
, cur
->u
.Open
.mode
,
1707 cur
->ChangeTime
, cur
->u
.Open
.deleg_type
);
1713 NTSTATUS
unmarshal_nfs41_dirquery(
1714 nfs41_updowncall_entry
*cur
,
1715 unsigned char **buf
)
1717 NTSTATUS status
= STATUS_SUCCESS
;
1720 RtlCopyMemory(&buf_len
, *buf
, sizeof(ULONG
));
1721 #ifdef DEBUG_MARSHAL_DETAIL
1722 DbgP("unmarshal_nfs41_dirquery: reply size %d\n", buf_len
);
1724 *buf
+= sizeof(ULONG
);
1726 MmUnmapLockedPages(cur
->u
.QueryFile
.mdl_buf
, cur
->u
.QueryFile
.mdl
);
1727 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
1729 code
= _SEH2_GetExceptionCode();
1730 print_error("MmUnmapLockedPages thrown exception=0x%0x\n", code
);
1731 status
= STATUS_ACCESS_DENIED
;
1733 if (buf_len
> cur
->buf_len
)
1734 cur
->status
= STATUS_BUFFER_TOO_SMALL
;
1735 cur
->buf_len
= buf_len
;
1740 void unmarshal_nfs41_attrget(
1741 nfs41_updowncall_entry
*cur
,
1744 unsigned char **buf
)
1747 RtlCopyMemory(&buf_len
, *buf
, sizeof(ULONG
));
1748 if (buf_len
> *attr_len
) {
1749 cur
->status
= STATUS_BUFFER_TOO_SMALL
;
1752 *buf
+= sizeof(ULONG
);
1753 *attr_len
= buf_len
;
1754 RtlCopyMemory(attr_value
, *buf
, buf_len
);
1758 void unmarshal_nfs41_eaget(
1759 nfs41_updowncall_entry
*cur
,
1760 unsigned char **buf
)
1762 RtlCopyMemory(&cur
->u
.QueryEa
.Overflow
, *buf
, sizeof(ULONG
));
1763 *buf
+= sizeof(ULONG
);
1764 RtlCopyMemory(&cur
->buf_len
, *buf
, sizeof(ULONG
));
1765 *buf
+= sizeof(ULONG
);
1766 if (cur
->u
.QueryEa
.Overflow
!= ERROR_INSUFFICIENT_BUFFER
) {
1767 RtlCopyMemory(cur
->buf
, *buf
, cur
->buf_len
);
1768 *buf
+= cur
->buf_len
;
1772 void unmarshal_nfs41_getattr(
1773 nfs41_updowncall_entry
*cur
,
1774 unsigned char **buf
)
1776 unmarshal_nfs41_attrget(cur
, cur
->buf
, &cur
->buf_len
, buf
);
1777 RtlCopyMemory(&cur
->ChangeTime
, *buf
, sizeof(LONGLONG
));
1778 #ifdef DEBUG_MARSHAL_DETAIL
1779 if (cur
->u
.QueryFile
.InfoClass
== FileBasicInformation
)
1780 DbgP("[unmarshal_nfs41_getattr] ChangeTime %llu\n", cur
->ChangeTime
);
1784 NTSTATUS
unmarshal_nfs41_getacl(
1785 nfs41_updowncall_entry
*cur
,
1786 unsigned char **buf
)
1788 NTSTATUS status
= STATUS_SUCCESS
;
1791 RtlCopyMemory(&buf_len
, *buf
, sizeof(DWORD
));
1792 *buf
+= sizeof(DWORD
);
1793 cur
->buf
= RxAllocatePoolWithTag(NonPagedPool
,
1794 buf_len
, NFS41_MM_POOLTAG_ACL
);
1795 if (cur
->buf
== NULL
) {
1796 cur
->status
= status
= STATUS_INSUFFICIENT_RESOURCES
;
1799 RtlCopyMemory(cur
->buf
, *buf
, buf_len
);
1800 if (buf_len
> cur
->buf_len
)
1801 cur
->status
= STATUS_BUFFER_TOO_SMALL
;
1802 cur
->buf_len
= buf_len
;
1808 void unmarshal_nfs41_symlink(
1809 nfs41_updowncall_entry
*cur
,
1810 unsigned char **buf
)
1812 if (cur
->u
.Symlink
.set
) return;
1814 RtlCopyMemory(&cur
->u
.Symlink
.target
->Length
, *buf
, sizeof(USHORT
));
1815 *buf
+= sizeof(USHORT
);
1816 if (cur
->u
.Symlink
.target
->Length
>
1817 cur
->u
.Symlink
.target
->MaximumLength
) {
1818 cur
->status
= STATUS_BUFFER_TOO_SMALL
;
1821 RtlCopyMemory(cur
->u
.Symlink
.target
->Buffer
, *buf
,
1822 cur
->u
.Symlink
.target
->Length
);
1823 cur
->u
.Symlink
.target
->Length
-= sizeof(UNICODE_NULL
);
1826 NTSTATUS
nfs41_downcall(
1827 IN PRX_CONTEXT RxContext
)
1829 NTSTATUS status
= STATUS_SUCCESS
;
1830 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
1831 ULONG in_len
= LowIoContext
->ParamsFor
.IoCtl
.InputBufferLength
;
1832 unsigned char *buf
= LowIoContext
->ParamsFor
.IoCtl
.pInputBuffer
;
1834 nfs41_updowncall_entry
*tmp
, *cur
= NULL
;
1837 print_hexbuf(0, (unsigned char *)"downcall buffer", buf
, in_len
);
1839 tmp
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(nfs41_updowncall_entry
),
1840 NFS41_MM_POOLTAG_DOWN
);
1841 if (tmp
== NULL
) goto out
;
1843 unmarshal_nfs41_header(tmp
, &buf
);
1845 ExAcquireFastMutex(&downcallLock
);
1846 pEntry
= &downcall
.head
;
1847 pEntry
= pEntry
->Flink
;
1848 while (pEntry
!= NULL
) {
1849 cur
= (nfs41_updowncall_entry
*)CONTAINING_RECORD(pEntry
,
1850 nfs41_updowncall_entry
, next
);
1851 if (cur
->xid
== tmp
->xid
) {
1855 if (pEntry
->Flink
== &downcall
.head
)
1857 pEntry
= pEntry
->Flink
;
1859 ExReleaseFastMutex(&downcallLock
);
1860 SeStopImpersonatingClient();
1862 print_error("Didn't find xid=%lld entry\n", tmp
->xid
);
1866 ExAcquireFastMutex(&cur
->lock
);
1867 if (cur
->state
== NFS41_NOT_WAITING
) {
1868 DbgP("[downcall] Nobody is waiting for this request!!!\n");
1869 switch(cur
->opcode
) {
1872 MmUnmapLockedPages(cur
->buf
, cur
->u
.ReadWrite
.MdlAddress
);
1874 case NFS41_DIR_QUERY
:
1875 MmUnmapLockedPages(cur
->u
.QueryFile
.mdl_buf
,
1876 cur
->u
.QueryFile
.mdl
);
1877 IoFreeMdl(cur
->u
.QueryFile
.mdl
);
1880 if (cur
->u
.Open
.EaMdl
) {
1881 MmUnmapLockedPages(cur
->u
.Open
.EaBuffer
,
1883 IoFreeMdl(cur
->u
.Open
.EaMdl
);
1887 ExReleaseFastMutex(&cur
->lock
);
1888 nfs41_RemoveEntry(downcallLock
, cur
);
1890 status
= STATUS_UNSUCCESSFUL
;
1893 cur
->state
= NFS41_DONE_PROCESSING
;
1894 cur
->status
= tmp
->status
;
1895 cur
->errno
= tmp
->errno
;
1896 status
= STATUS_SUCCESS
;
1899 switch (tmp
->opcode
) {
1901 unmarshal_nfs41_mount(cur
, &buf
);
1905 status
= unmarshal_nfs41_rw(cur
, &buf
);
1908 status
= unmarshal_nfs41_open(cur
, &buf
);
1910 case NFS41_DIR_QUERY
:
1911 status
= unmarshal_nfs41_dirquery(cur
, &buf
);
1913 case NFS41_FILE_QUERY
:
1914 unmarshal_nfs41_getattr(cur
, &buf
);
1917 unmarshal_nfs41_eaget(cur
, &buf
);
1920 unmarshal_nfs41_symlink(cur
, &buf
);
1922 case NFS41_VOLUME_QUERY
:
1923 unmarshal_nfs41_attrget(cur
, cur
->buf
, &cur
->buf_len
, &buf
);
1925 case NFS41_ACL_QUERY
:
1926 status
= unmarshal_nfs41_getacl(cur
, &buf
);
1928 case NFS41_FILE_SET
:
1929 unmarshal_nfs41_setattr(cur
, &cur
->ChangeTime
, &buf
);
1932 unmarshal_nfs41_setattr(cur
, &cur
->ChangeTime
, &buf
);
1935 unmarshal_nfs41_setattr(cur
, &cur
->ChangeTime
, &buf
);
1939 ExReleaseFastMutex(&cur
->lock
);
1940 if (cur
->async_op
) {
1941 if (cur
->status
== STATUS_SUCCESS
) {
1942 cur
->u
.ReadWrite
.rxcontext
->StoredStatus
= STATUS_SUCCESS
;
1943 cur
->u
.ReadWrite
.rxcontext
->InformationToReturn
=
1946 cur
->u
.ReadWrite
.rxcontext
->StoredStatus
=
1947 map_readwrite_errors(cur
->status
);
1948 cur
->u
.ReadWrite
.rxcontext
->InformationToReturn
= 0;
1950 nfs41_RemoveEntry(downcallLock
, cur
);
1951 RxLowIoCompletion(cur
->u
.ReadWrite
.rxcontext
);
1954 KeSetEvent(&cur
->cond
, 0, FALSE
);
1962 NTSTATUS
nfs41_shutdown_daemon(
1965 NTSTATUS status
= STATUS_SUCCESS
;
1966 nfs41_updowncall_entry
*entry
= NULL
;
1969 status
= nfs41_UpcallCreate(NFS41_SHUTDOWN
, NULL
, INVALID_HANDLE_VALUE
,
1970 INVALID_HANDLE_VALUE
, version
, NULL
, &entry
);
1971 if (status
) goto out
;
1973 status
= nfs41_UpcallWaitForReply(entry
, UPCALL_TIMEOUT_DEFAULT
);
1974 SeDeleteClientSecurity(&entry
->sec_ctx
);
1975 if (status
) goto out
;
1983 NTSTATUS
SharedMemoryInit(
1984 OUT PHANDLE phSection
)
1988 UNICODE_STRING SectionName
;
1989 SECURITY_DESCRIPTOR SecurityDesc
;
1990 OBJECT_ATTRIBUTES SectionAttrs
;
1991 LARGE_INTEGER nSectionSize
;
1995 RtlInitUnicodeString(&SectionName
, NFS41_SHARED_MEMORY_NAME
);
1997 /* XXX: setting dacl=NULL grants access to everyone */
1998 status
= RtlCreateSecurityDescriptor(&SecurityDesc
,
1999 SECURITY_DESCRIPTOR_REVISION
);
2001 print_error("RtlCreateSecurityDescriptor() failed with %08X\n", status
);
2004 status
= RtlSetDaclSecurityDescriptor(&SecurityDesc
, TRUE
, NULL
, FALSE
);
2006 print_error("RtlSetDaclSecurityDescriptor() failed with %08X\n", status
);
2010 InitializeObjectAttributes(&SectionAttrs
, &SectionName
,
2011 0, NULL
, &SecurityDesc
);
2013 nSectionSize
.QuadPart
= sizeof(NFS41NP_SHARED_MEMORY
);
2015 status
= ZwCreateSection(&hSection
, SECTION_MAP_READ
| SECTION_MAP_WRITE
,
2016 &SectionAttrs
, &nSectionSize
, PAGE_READWRITE
, SEC_COMMIT
, NULL
);
2018 case STATUS_SUCCESS
:
2020 case STATUS_OBJECT_NAME_COLLISION
:
2021 DbgP("section already created; returning success\n");
2022 status
= STATUS_SUCCESS
;
2025 DbgP("ZwCreateSection failed with %08X\n", status
);
2033 NTSTATUS
SharedMemoryFree(
2038 status
= ZwClose(hSection
);
2044 NTSTATUS NTAPI
nfs41_Start(
2046 NTSTATUS
nfs41_Start(
2048 IN OUT PRX_CONTEXT RxContext
,
2049 IN OUT PRDBSS_DEVICE_OBJECT dev
)
2052 NFS41GetDeviceExtension(RxContext
, DevExt
);
2056 status
= SharedMemoryInit(&DevExt
->SharedMemorySection
);
2058 print_error("InitSharedMemory failed with %08X\n", status
);
2059 status
= STATUS_INSUFFICIENT_RESOURCES
;
2063 InterlockedCompareExchange((PLONG
)&nfs41_start_state
,
2064 NFS41_START_DRIVER_STARTED
,
2065 NFS41_START_DRIVER_START_IN_PROGRESS
);
2072 NTSTATUS NTAPI
nfs41_Stop(
2074 NTSTATUS
nfs41_Stop(
2076 IN OUT PRX_CONTEXT RxContext
,
2077 IN OUT PRDBSS_DEVICE_OBJECT dev
)
2080 NFS41GetDeviceExtension(RxContext
, DevExt
);
2082 status
= SharedMemoryFree(DevExt
->SharedMemorySection
);
2087 NTSTATUS
GetConnectionHandle(
2088 IN PUNICODE_STRING ConnectionName
,
2094 IO_STATUS_BLOCK IoStatusBlock
;
2095 OBJECT_ATTRIBUTES ObjectAttributes
;
2100 InitializeObjectAttributes(&ObjectAttributes
, ConnectionName
,
2101 OBJ_CASE_INSENSITIVE
|OBJ_KERNEL_HANDLE
, NULL
, NULL
);
2103 print_error("Len %d Buf %p\n", EaLength
, EaBuffer
);
2105 status
= ZwCreateFile(Handle
, SYNCHRONIZE
, &ObjectAttributes
,
2106 &IoStatusBlock
, NULL
, FILE_ATTRIBUTE_NORMAL
,
2107 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
2109 FILE_CREATE_TREE_CONNECTION
| FILE_SYNCHRONOUS_IO_NONALERT
,
2110 EaBuffer
, EaLength
);
2118 NTSTATUS
nfs41_GetConnectionInfoFromBuffer(
2121 OUT PUNICODE_STRING pConnectionName
,
2122 OUT PVOID
*ppEaBuffer
,
2123 OUT PULONG pEaLength
)
2125 NTSTATUS status
= STATUS_SUCCESS
;
2126 USHORT NameLength
, EaPadding
;
2127 ULONG EaLength
, BufferLenExpected
;
2130 /* make sure buffer is at least big enough for header */
2131 if (BufferLen
< sizeof(USHORT
) + sizeof(USHORT
) + sizeof(ULONG
)) {
2132 status
= STATUS_BAD_NETWORK_NAME
;
2133 print_error("Invalid input buffer.\n");
2134 pConnectionName
->Length
= pConnectionName
->MaximumLength
= 0;
2141 NameLength
= *(PUSHORT
)ptr
;
2142 ptr
+= sizeof(USHORT
);
2143 EaPadding
= *(PUSHORT
)ptr
;
2144 ptr
+= sizeof(USHORT
);
2145 EaLength
= *(PULONG
)ptr
;
2146 ptr
+= sizeof(ULONG
);
2148 /* validate buffer length */
2149 BufferLenExpected
= sizeof(USHORT
) + sizeof(USHORT
) + sizeof(ULONG
) +
2150 NameLength
+ EaPadding
+ EaLength
;
2151 if (BufferLen
!= BufferLenExpected
) {
2152 status
= STATUS_BAD_NETWORK_NAME
;
2153 print_error("Received buffer of length %lu, but expected %lu bytes.\n",
2154 BufferLen
, BufferLenExpected
);
2155 pConnectionName
->Length
= pConnectionName
->MaximumLength
= 0;
2161 pConnectionName
->Buffer
= (PWCH
)ptr
;
2162 pConnectionName
->Length
= NameLength
- sizeof(WCHAR
);
2163 pConnectionName
->MaximumLength
= NameLength
;
2166 *ppEaBuffer
= ptr
+ NameLength
+ EaPadding
;
2169 *pEaLength
= EaLength
;
2175 NTSTATUS
nfs41_CreateConnection(
2176 IN PRX_CONTEXT RxContext
,
2177 OUT PBOOLEAN PostToFsp
)
2179 NTSTATUS status
= STATUS_SUCCESS
;
2180 HANDLE Handle
= INVALID_HANDLE_VALUE
;
2181 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
2182 PVOID Buffer
= LowIoContext
->ParamsFor
.IoCtl
.pInputBuffer
, EaBuffer
;
2183 ULONG BufferLen
= LowIoContext
->ParamsFor
.IoCtl
.InputBufferLength
, EaLength
;
2184 UNICODE_STRING FileName
;
2185 BOOLEAN Wait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
2192 //just post right now!
2193 DbgP("returning STATUS_PENDING\n");
2195 status
= STATUS_PENDING
;
2199 status
= nfs41_GetConnectionInfoFromBuffer(Buffer
, BufferLen
,
2200 &FileName
, &EaBuffer
, &EaLength
);
2201 if (status
!= STATUS_SUCCESS
)
2204 status
= GetConnectionHandle(&FileName
, EaBuffer
, EaLength
, &Handle
);
2205 if (!status
&& Handle
!= INVALID_HANDLE_VALUE
)
2214 #ifdef ENABLE_TIMINGS
2217 nfs41_timings
*time
, BOOLEAN clear
)
2219 DbgP("%-9s: num_ops=%-10d delta_ticks=%-10d size=%-10d\n", op_str
,
2220 time
->tops
, time
->tops
? time
->ticks
/time
->tops
: 0,
2221 time
->sops
? time
->size
/time
->sops
: 0);
2230 NTSTATUS
nfs41_unmount(
2235 NTSTATUS status
= STATUS_INSUFFICIENT_RESOURCES
;
2236 nfs41_updowncall_entry
*entry
;
2241 status
= nfs41_UpcallCreate(NFS41_UNMOUNT
, NULL
, session
,
2242 INVALID_HANDLE_VALUE
, version
, NULL
, &entry
);
2243 SeDeleteClientSecurity(&entry
->sec_ctx
);
2244 if (status
) goto out
;
2246 nfs41_UpcallWaitForReply(entry
, timeout
);
2249 #ifdef ENABLE_TIMINGS
2250 print_op_stat("lookup", &lookup
, 1);
2251 print_op_stat("open", &open
, 1);
2252 print_op_stat("close", &close
, 1);
2253 print_op_stat("volume", &volume
, 1);
2254 print_op_stat("getattr", &getattr
, 1);
2255 print_op_stat("setattr", &setattr
, 1);
2256 print_op_stat("getexattr", &getexattr
, 1);
2257 print_op_stat("setexattr", &setexattr
, 1);
2258 print_op_stat("readdir", &readdir
, 1);
2259 print_op_stat("getacl", &getacl
, 1);
2260 print_op_stat("setacl", &setacl
, 1);
2261 print_op_stat("read", &read
, 1);
2262 print_op_stat("write", &write
, 1);
2263 print_op_stat("lock", &lock
, 1);
2264 print_op_stat("unlock", &unlock
, 1);
2272 NTSTATUS
nfs41_DeleteConnection (
2273 IN PRX_CONTEXT RxContext
,
2274 OUT PBOOLEAN PostToFsp
)
2276 NTSTATUS status
= STATUS_INVALID_PARAMETER
;
2277 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
2278 PWCHAR ConnectName
= LowIoContext
->ParamsFor
.IoCtl
.pInputBuffer
;
2279 ULONG ConnectNameLen
= LowIoContext
->ParamsFor
.IoCtl
.InputBufferLength
;
2281 UNICODE_STRING FileName
;
2282 PFILE_OBJECT pFileObject
;
2283 BOOLEAN Wait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
2290 //just post right now!
2292 DbgP("returning STATUS_PENDING\n");
2293 status
= STATUS_PENDING
;
2297 FileName
.Buffer
= ConnectName
;
2298 FileName
.Length
= (USHORT
) ConnectNameLen
- sizeof(WCHAR
);
2299 FileName
.MaximumLength
= (USHORT
) ConnectNameLen
;
2301 status
= GetConnectionHandle(&FileName
, NULL
, 0, &Handle
);
2302 if (status
!= STATUS_SUCCESS
)
2305 status
= ObReferenceObjectByHandle(Handle
, 0L, NULL
, KernelMode
,
2306 (PVOID
*)&pFileObject
, NULL
);
2307 if (NT_SUCCESS(status
)) {
2308 PV_NET_ROOT VNetRoot
;
2310 // VNetRoot exists as FOBx in the FsContext2
2311 VNetRoot
= (PV_NET_ROOT
) pFileObject
->FsContext2
;
2312 // make sure the node looks right
2313 if (NodeType(VNetRoot
) == RDBSS_NTC_V_NETROOT
)
2316 DbgP("Calling RxFinalizeConnection for NetRoot %p from VNetRoot %p\n",
2317 VNetRoot
->NetRoot
, VNetRoot
);
2319 status
= RxFinalizeConnection(VNetRoot
->NetRoot
, VNetRoot
, TRUE
);
2322 status
= STATUS_BAD_NETWORK_NAME
;
2324 ObDereferenceObject(pFileObject
);
2335 NTSTATUS NTAPI
nfs41_DevFcbXXXControlFile(
2337 NTSTATUS
nfs41_DevFcbXXXControlFile(
2339 IN OUT PRX_CONTEXT RxContext
)
2341 NTSTATUS status
= STATUS_INVALID_DEVICE_REQUEST
;
2342 UCHAR op
= RxContext
->MajorFunction
;
2343 PLOWIO_CONTEXT io_ctx
= &RxContext
->LowIoContext
;
2344 ULONG fsop
= io_ctx
->ParamsFor
.FsCtl
.FsControlCode
, state
;
2345 ULONG in_len
= io_ctx
->ParamsFor
.IoCtl
.InputBufferLength
;
2346 DWORD
*buf
= io_ctx
->ParamsFor
.IoCtl
.pInputBuffer
;
2347 NFS41GetDeviceExtension(RxContext
, DevExt
);
2348 DWORD nfs41d_version
= 0;
2354 case IRP_MJ_FILE_SYSTEM_CONTROL
:
2355 status
= STATUS_INVALID_DEVICE_REQUEST
;
2357 case IRP_MJ_DEVICE_CONTROL
:
2358 case IRP_MJ_INTERNAL_DEVICE_CONTROL
:
2359 print_fs_ioctl(0, fsop
);
2361 case IOCTL_NFS41_INVALCACHE
:
2362 nfs41_invalidate_cache(RxContext
);
2363 status
= STATUS_SUCCESS
;
2365 case IOCTL_NFS41_READ
:
2366 status
= nfs41_upcall(RxContext
);
2368 case IOCTL_NFS41_WRITE
:
2369 status
= nfs41_downcall(RxContext
);
2371 case IOCTL_NFS41_ADDCONN
:
2372 status
= nfs41_CreateConnection(RxContext
, &RxContext
->PostRequest
);
2374 case IOCTL_NFS41_DELCONN
:
2375 if (RxContext
->RxDeviceObject
->NumberOfActiveFcbs
> 0) {
2376 DbgP("device has open handles %d\n",
2377 RxContext
->RxDeviceObject
->NumberOfActiveFcbs
);
2379 if (RxContext
->RxDeviceObject
->pRxNetNameTable
!= NULL
)
2381 #define DUMP_FCB_TABLE_FROM_NETROOT(N) \
2384 BOOLEAN Release2 = FALSE; \
2385 if (!RxIsFcbTableLockAcquired(&(N)->FcbTable)) \
2387 RxAcquireFcbTableLockExclusive(&(N)->FcbTable, TRUE); \
2390 for (Bucket2 = 0; Bucket2 < (N)->FcbTable.NumberOfBuckets; ++Bucket2) \
2392 PLIST_ENTRY Entry2; \
2393 for (Entry2 = (N)->FcbTable.HashBuckets[Bucket2].Flink; \
2394 Entry2 != &(N)->FcbTable.HashBuckets[Bucket2]; \
2395 Entry2 = Entry2->Flink) \
2398 Fcb = CONTAINING_RECORD(Entry2, FCB, FcbTableEntry.HashLinks); \
2399 DbgP("Fcb: %p still has %d references\n", Fcb, Fcb->NodeReferenceCount); \
2400 DbgP("It is for: %wZ\n", &Fcb->FcbTableEntry.Path); \
2405 RxReleaseFcbTableLock(&(N)->FcbTable); \
2409 BOOLEAN Release
= FALSE
;
2411 if (!RxIsPrefixTableLockAcquired(RxContext
->RxDeviceObject
->pRxNetNameTable
))
2413 RxAcquirePrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
2417 for (Bucket
= 0; Bucket
< RxContext
->RxDeviceObject
->pRxNetNameTable
->TableSize
; ++Bucket
)
2421 for (Entry
= RxContext
->RxDeviceObject
->pRxNetNameTable
->HashBuckets
[Bucket
].Flink
;
2422 Entry
!= &RxContext
->RxDeviceObject
->pRxNetNameTable
->HashBuckets
[Bucket
];
2423 Entry
= Entry
->Flink
)
2427 Container
= CONTAINING_RECORD(Entry
, RX_PREFIX_ENTRY
, HashLinks
)->ContainingRecord
;
2428 switch (NodeType(Container
) & ~RX_SCAVENGER_MASK
)
2430 case RDBSS_NTC_NETROOT
:
2434 NetRoot
= Container
;
2435 DUMP_FCB_TABLE_FROM_NETROOT(NetRoot
);
2439 case RDBSS_NTC_V_NETROOT
:
2441 PV_NET_ROOT VNetRoot
;
2443 VNetRoot
= Container
;
2444 if (VNetRoot
->NetRoot
!= NULL
)
2448 NetRoot
= VNetRoot
->NetRoot
;
2449 DUMP_FCB_TABLE_FROM_NETROOT(NetRoot
);
2459 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
2461 #undef DUMP_FCB_TABLE_FROM_NETROOT
2464 status
= STATUS_REDIRECTOR_HAS_OPEN_HANDLES
;
2467 status
= nfs41_DeleteConnection(RxContext
, &RxContext
->PostRequest
);
2469 case IOCTL_NFS41_GETSTATE
:
2470 state
= RDR_NULL_STATE
;
2472 if (io_ctx
->ParamsFor
.IoCtl
.OutputBufferLength
>= sizeof(ULONG
)) {
2473 // map the states to control app's equivalents
2474 print_driver_state(nfs41_start_state
);
2475 switch (nfs41_start_state
) {
2476 case NFS41_START_DRIVER_STARTABLE
:
2477 case NFS41_START_DRIVER_STOPPED
:
2478 state
= RDR_STOPPED
;
2480 case NFS41_START_DRIVER_START_IN_PROGRESS
:
2481 state
= RDR_STARTING
;
2483 case NFS41_START_DRIVER_STARTED
:
2484 state
= RDR_STARTED
;
2487 *(ULONG
*)io_ctx
->ParamsFor
.IoCtl
.pOutputBuffer
= state
;
2488 RxContext
->InformationToReturn
= sizeof(ULONG
);
2489 status
= STATUS_SUCCESS
;
2491 status
= STATUS_INVALID_PARAMETER
;
2493 case IOCTL_NFS41_START
:
2494 print_driver_state(nfs41_start_state
);
2495 if (in_len
>= sizeof(DWORD
)) {
2496 RtlCopyMemory(&nfs41d_version
, buf
, sizeof(DWORD
));
2497 DbgP("NFS41 Daemon sent start request with version %d\n",
2499 DbgP("Currently used NFS41 Daemon version is %d\n",
2500 DevExt
->nfs41d_version
);
2501 DevExt
->nfs41d_version
= nfs41d_version
;
2503 switch(nfs41_start_state
) {
2504 case NFS41_START_DRIVER_STARTABLE
:
2505 (nfs41_start_driver_state
)InterlockedCompareExchange(
2506 (PLONG
)&nfs41_start_state
,
2507 NFS41_START_DRIVER_START_IN_PROGRESS
,
2508 NFS41_START_DRIVER_STARTABLE
);
2509 //lack of break is intentional
2510 case NFS41_START_DRIVER_START_IN_PROGRESS
:
2511 status
= RxStartMinirdr(RxContext
, &RxContext
->PostRequest
);
2512 if (status
== STATUS_REDIRECTOR_STARTED
) {
2513 DbgP("redirector started\n");
2514 status
= STATUS_SUCCESS
;
2515 } else if (status
== STATUS_PENDING
&&
2516 RxContext
->PostRequest
== TRUE
) {
2517 DbgP("RxStartMinirdr pending %08lx\n", status
);
2518 status
= STATUS_MORE_PROCESSING_REQUIRED
;
2521 case NFS41_START_DRIVER_STARTED
:
2522 status
= STATUS_SUCCESS
;
2525 status
= STATUS_INVALID_PARAMETER
;
2528 case IOCTL_NFS41_STOP
:
2529 if (nfs41_start_state
== NFS41_START_DRIVER_STARTED
)
2530 nfs41_shutdown_daemon(DevExt
->nfs41d_version
);
2531 if (RxContext
->RxDeviceObject
->NumberOfActiveFcbs
> 0) {
2532 DbgP("device has open handles %d\n",
2533 RxContext
->RxDeviceObject
->NumberOfActiveFcbs
);
2534 status
= STATUS_REDIRECTOR_HAS_OPEN_HANDLES
;
2538 state
= (nfs41_start_driver_state
)InterlockedCompareExchange(
2539 (PLONG
)&nfs41_start_state
,
2540 NFS41_START_DRIVER_STARTABLE
,
2541 NFS41_START_DRIVER_STARTED
);
2543 status
= RxStopMinirdr(RxContext
, &RxContext
->PostRequest
);
2544 DbgP("RxStopMinirdr status %08lx\n", status
);
2545 if (status
== STATUS_PENDING
&& RxContext
->PostRequest
== TRUE
)
2546 status
= STATUS_MORE_PROCESSING_REQUIRED
;
2549 status
= STATUS_INVALID_DEVICE_REQUEST
;
2553 status
= STATUS_INVALID_DEVICE_REQUEST
;
2561 NTSTATUS
_nfs41_CreateSrvCall(
2562 PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext
)
2565 NTSTATUS NTAPI
_nfs41_CreateSrvCall(
2568 PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext
= pContext
;
2570 NTSTATUS status
= STATUS_SUCCESS
;
2571 PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC
= pCallbackContext
;
2572 PMRX_SRV_CALL pSrvCall
;
2573 PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure
=
2574 (PMRX_SRVCALLDOWN_STRUCTURE
)(SCCBC
->SrvCalldownStructure
);
2575 PNFS41_SERVER_ENTRY pServerEntry
= NULL
;
2581 pSrvCall
= SrvCalldownStructure
->SrvCall
;
2584 ASSERT( NodeType(pSrvCall
) == RDBSS_NTC_SRVCALL
);
2585 print_srv_call(0, pSrvCall
);
2587 // validate the server name with the test name of 'pnfs'
2589 DbgP("SrvCall: Connection Name Length: %d %wZ\n",
2590 pSrvCall
->pSrvCallName
->Length
, pSrvCall
->pSrvCallName
);
2593 if (pSrvCall
->pSrvCallName
->Length
> SERVER_NAME_BUFFER_SIZE
) {
2594 print_error("Server name '%wZ' too long for server entry (max %u)\n",
2595 pSrvCall
->pSrvCallName
, SERVER_NAME_BUFFER_SIZE
);
2596 status
= STATUS_NAME_TOO_LONG
;
2600 /* Let's create our own representation of the server */
2601 pServerEntry
= (PNFS41_SERVER_ENTRY
)RxAllocatePoolWithTag(PagedPool
,
2602 sizeof(NFS41_SERVER_ENTRY
), NFS41_MM_POOLTAG
);
2603 if (pServerEntry
== NULL
) {
2604 status
= STATUS_INSUFFICIENT_RESOURCES
;
2607 RtlZeroMemory(pServerEntry
, sizeof(NFS41_SERVER_ENTRY
));
2609 pServerEntry
->Name
.Buffer
= pServerEntry
->NameBuffer
;
2610 pServerEntry
->Name
.Length
= pSrvCall
->pSrvCallName
->Length
;
2611 pServerEntry
->Name
.MaximumLength
= SERVER_NAME_BUFFER_SIZE
;
2612 RtlCopyMemory(pServerEntry
->Name
.Buffer
, pSrvCall
->pSrvCallName
->Buffer
,
2613 pServerEntry
->Name
.Length
);
2615 pCallbackContext
->RecommunicateContext
= pServerEntry
;
2617 InterlockedExchangePointer((void * volatile *)&pServerEntry
->pRdbssSrvCall
, pSrvCall
);
2619 InterlockedExchangePointer(&pServerEntry
->pRdbssSrvCall
, pSrvCall
);
2623 SCCBC
->Status
= status
;
2624 SrvCalldownStructure
->CallBack(SCCBC
);
2633 VOID NTAPI
_nfs41_CreateSrvCall_v(
2634 PVOID pCallbackContext
)
2636 _nfs41_CreateSrvCall(pCallbackContext
);
2641 NTSTATUS NTAPI
nfs41_CreateSrvCall(
2643 NTSTATUS
nfs41_CreateSrvCall(
2645 PMRX_SRV_CALL pSrvCall
,
2646 PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext
)
2651 ASSERT( NodeType(pSrvCall
) == RDBSS_NTC_SRVCALL
);
2653 if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
2654 DbgP("executing with RDBSS context\n");
2655 status
= _nfs41_CreateSrvCall(pCallbackContext
);
2657 status
= RxDispatchToWorkerThread(nfs41_dev
, DelayedWorkQueue
,
2659 _nfs41_CreateSrvCall_v
, pCallbackContext
);
2661 _nfs41_CreateSrvCall
, pCallbackContext
);
2663 if (status
!= STATUS_SUCCESS
) {
2664 print_error("RxDispatchToWorkerThread returned status %08lx\n",
2666 pCallbackContext
->Status
= status
;
2667 pCallbackContext
->SrvCalldownStructure
->CallBack(pCallbackContext
);
2668 status
= STATUS_PENDING
;
2671 /* RDBSS expects MRxCreateSrvCall to return STATUS_PENDING */
2672 if (status
== STATUS_SUCCESS
)
2673 status
= STATUS_PENDING
;
2679 NTSTATUS NTAPI
nfs41_SrvCallWinnerNotify(
2681 NTSTATUS
nfs41_SrvCallWinnerNotify(
2683 IN OUT PMRX_SRV_CALL pSrvCall
,
2684 IN BOOLEAN ThisMinirdrIsTheWinner
,
2685 IN OUT PVOID pSrvCallContext
)
2687 NTSTATUS status
= STATUS_SUCCESS
;
2688 PNFS41_SERVER_ENTRY pServerEntry
;
2690 pServerEntry
= (PNFS41_SERVER_ENTRY
)pSrvCallContext
;
2692 if (!ThisMinirdrIsTheWinner
) {
2697 pSrvCall
->Context
= pServerEntry
;
2702 NTSTATUS
map_mount_errors(
2706 case NO_ERROR
: return STATUS_SUCCESS
;
2707 case ERROR_NETWORK_UNREACHABLE
: return STATUS_NETWORK_UNREACHABLE
;
2708 case ERROR_BAD_NET_RESP
: return STATUS_UNEXPECTED_NETWORK_ERROR
;
2709 case ERROR_BAD_NET_NAME
: return STATUS_BAD_NETWORK_NAME
;
2710 case ERROR_BAD_NETPATH
: return STATUS_BAD_NETWORK_PATH
;
2712 print_error("failed to map windows error %d to NTSTATUS; "
2713 "defaulting to STATUS_INSUFFICIENT_RESOURCES\n", status
);
2714 return STATUS_INSUFFICIENT_RESOURCES
;
2718 NTSTATUS
nfs41_mount(
2719 PNFS41_MOUNT_CONFIG config
,
2723 PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs
)
2725 NTSTATUS status
= STATUS_INSUFFICIENT_RESOURCES
;
2726 nfs41_updowncall_entry
*entry
;
2730 DbgP("Server Name %wZ Mount Point %wZ SecFlavor %d\n",
2731 &config
->SrvName
, &config
->MntPt
, sec_flavor
);
2733 status
= nfs41_UpcallCreate(NFS41_MOUNT
, NULL
, *session
,
2734 INVALID_HANDLE_VALUE
, *version
, &config
->MntPt
, &entry
);
2735 if (status
) goto out
;
2737 entry
->u
.Mount
.srv_name
= &config
->SrvName
;
2738 entry
->u
.Mount
.root
= &config
->MntPt
;
2739 entry
->u
.Mount
.rsize
= config
->ReadSize
;
2740 entry
->u
.Mount
.wsize
= config
->WriteSize
;
2741 entry
->u
.Mount
.sec_flavor
= sec_flavor
;
2742 entry
->u
.Mount
.FsAttrs
= FsAttrs
;
2744 status
= nfs41_UpcallWaitForReply(entry
, config
->timeout
);
2745 SeDeleteClientSecurity(&entry
->sec_ctx
);
2746 if (status
) goto out
;
2747 *session
= entry
->session
;
2748 if (entry
->u
.Mount
.lease_time
> config
->timeout
)
2749 config
->timeout
= entry
->u
.Mount
.lease_time
;
2751 /* map windows ERRORs to NTSTATUS */
2752 status
= map_mount_errors(entry
->status
);
2753 if (status
== STATUS_SUCCESS
)
2754 *version
= entry
->version
;
2763 /* TODO: move mount config stuff to another file -cbodley */
2765 void nfs41_MountConfig_InitDefaults(
2766 OUT PNFS41_MOUNT_CONFIG Config
)
2768 RtlZeroMemory(Config
, sizeof(NFS41_MOUNT_CONFIG
));
2770 Config
->ReadSize
= MOUNT_CONFIG_RW_SIZE_DEFAULT
;
2771 Config
->WriteSize
= MOUNT_CONFIG_RW_SIZE_DEFAULT
;
2772 Config
->ReadOnly
= FALSE
;
2773 Config
->write_thru
= FALSE
;
2774 Config
->nocache
= FALSE
;
2775 Config
->SrvName
.Length
= 0;
2776 Config
->SrvName
.MaximumLength
= SERVER_NAME_BUFFER_SIZE
;
2777 Config
->SrvName
.Buffer
= Config
->srv_buffer
;
2778 Config
->MntPt
.Length
= 0;
2779 Config
->MntPt
.MaximumLength
= MAX_PATH
;
2780 Config
->MntPt
.Buffer
= Config
->mntpt_buffer
;
2781 Config
->SecFlavor
.Length
= 0;
2782 Config
->SecFlavor
.MaximumLength
= MAX_SEC_FLAVOR_LEN
;
2783 Config
->SecFlavor
.Buffer
= Config
->sec_flavor
;
2784 RtlCopyUnicodeString(&Config
->SecFlavor
, &AUTH_SYS_NAME
);
2785 Config
->timeout
= UPCALL_TIMEOUT_DEFAULT
;
2788 NTSTATUS
nfs41_MountConfig_ParseBoolean(
2789 IN PFILE_FULL_EA_INFORMATION Option
,
2790 IN PUNICODE_STRING usValue
,
2793 NTSTATUS status
= STATUS_SUCCESS
;
2795 /* if no value is specified, assume TRUE
2796 * if a value is specified, it must be a '1' */
2797 if (Option
->EaValueLength
== 0 || *usValue
->Buffer
== L
'1')
2802 DbgP(" '%ls' -> '%wZ' -> %u\n",
2803 (LPWSTR
)Option
->EaName
, usValue
, *Value
);
2807 NTSTATUS
nfs41_MountConfig_ParseDword(
2808 IN PFILE_FULL_EA_INFORMATION Option
,
2809 IN PUNICODE_STRING usValue
,
2814 NTSTATUS status
= STATUS_INVALID_PARAMETER
;
2815 LPWSTR Name
= (LPWSTR
)Option
->EaName
;
2817 if (Option
->EaValueLength
) {
2818 status
= RtlUnicodeStringToInteger(usValue
, 0, Value
);
2819 if (status
== STATUS_SUCCESS
) {
2820 #ifdef IMPOSE_MINMAX_RWSIZES
2821 if (*Value
< Minimum
)
2823 if (*Value
> Maximum
)
2825 DbgP(" '%ls' -> '%wZ' -> %lu\n", Name
, usValue
, *Value
);
2829 print_error("Failed to convert %s='%wZ' to unsigned long.\n",
2836 NTSTATUS
nfs41_MountConfig_ParseOptions(
2837 IN PFILE_FULL_EA_INFORMATION EaBuffer
,
2839 IN OUT PNFS41_MOUNT_CONFIG Config
)
2841 NTSTATUS status
= STATUS_SUCCESS
;
2842 PFILE_FULL_EA_INFORMATION Option
;
2845 UNICODE_STRING usValue
;
2847 while (status
== STATUS_SUCCESS
) {
2848 Name
= (LPWSTR
)Option
->EaName
;
2849 NameLen
= Option
->EaNameLength
/sizeof(WCHAR
);
2851 usValue
.Length
= usValue
.MaximumLength
= Option
->EaValueLength
;
2852 usValue
.Buffer
= (PWCH
)(Option
->EaName
+
2853 Option
->EaNameLength
+ sizeof(WCHAR
));
2855 if (wcsncmp(L
"ro", Name
, NameLen
) == 0) {
2856 status
= nfs41_MountConfig_ParseBoolean(Option
, &usValue
,
2859 else if (wcsncmp(L
"writethru", Name
, NameLen
) == 0) {
2860 status
= nfs41_MountConfig_ParseBoolean(Option
, &usValue
,
2861 &Config
->write_thru
);
2863 else if (wcsncmp(L
"nocache", Name
, NameLen
) == 0) {
2864 status
= nfs41_MountConfig_ParseBoolean(Option
, &usValue
,
2867 else if (wcsncmp(L
"timeout", Name
, NameLen
) == 0) {
2868 status
= nfs41_MountConfig_ParseDword(Option
, &usValue
,
2869 &Config
->timeout
, UPCALL_TIMEOUT_DEFAULT
,
2870 UPCALL_TIMEOUT_DEFAULT
);
2872 else if (wcsncmp(L
"rsize", Name
, NameLen
) == 0) {
2873 status
= nfs41_MountConfig_ParseDword(Option
, &usValue
,
2874 &Config
->ReadSize
, MOUNT_CONFIG_RW_SIZE_MIN
,
2875 MOUNT_CONFIG_RW_SIZE_MAX
);
2877 else if (wcsncmp(L
"wsize", Name
, NameLen
) == 0) {
2878 status
= nfs41_MountConfig_ParseDword(Option
, &usValue
,
2879 &Config
->WriteSize
, MOUNT_CONFIG_RW_SIZE_MIN
,
2880 MOUNT_CONFIG_RW_SIZE_MAX
);
2882 else if (wcsncmp(L
"srvname", Name
, NameLen
) == 0) {
2883 if (usValue
.Length
> Config
->SrvName
.MaximumLength
)
2884 status
= STATUS_NAME_TOO_LONG
;
2886 RtlCopyUnicodeString(&Config
->SrvName
, &usValue
);
2888 else if (wcsncmp(L
"mntpt", Name
, NameLen
) == 0) {
2889 if (usValue
.Length
> Config
->MntPt
.MaximumLength
)
2890 status
= STATUS_NAME_TOO_LONG
;
2892 RtlCopyUnicodeString(&Config
->MntPt
, &usValue
);
2894 else if (wcsncmp(L
"sec", Name
, NameLen
) == 0) {
2895 if (usValue
.Length
> Config
->SecFlavor
.MaximumLength
)
2896 status
= STATUS_NAME_TOO_LONG
;
2898 RtlCopyUnicodeString(&Config
->SecFlavor
, &usValue
);
2901 status
= STATUS_INVALID_PARAMETER
;
2902 print_error("Unrecognized option '%ls' -> '%wZ'\n",
2906 if (Option
->NextEntryOffset
== 0)
2909 Option
= (PFILE_FULL_EA_INFORMATION
)
2910 ((PBYTE
)Option
+ Option
->NextEntryOffset
);
2916 NTSTATUS
has_nfs_prefix(
2917 IN PUNICODE_STRING SrvCallName
,
2918 IN PUNICODE_STRING NetRootName
)
2920 NTSTATUS status
= STATUS_BAD_NETWORK_NAME
;
2922 if (NetRootName
->Length
== SrvCallName
->Length
+ NfsPrefix
.Length
) {
2923 const UNICODE_STRING NetRootPrefix
= {
2925 NetRootName
->MaximumLength
- SrvCallName
->Length
,
2926 &NetRootName
->Buffer
[SrvCallName
->Length
/2]
2928 if (RtlCompareUnicodeString(&NetRootPrefix
, &NfsPrefix
, FALSE
) == 0)
2929 status
= STATUS_SUCCESS
;
2934 NTSTATUS
map_sec_flavor(
2935 IN PUNICODE_STRING sec_flavor_name
,
2936 OUT PDWORD sec_flavor
)
2938 if (RtlCompareUnicodeString(sec_flavor_name
, &AUTH_SYS_NAME
, FALSE
) == 0)
2939 *sec_flavor
= RPCSEC_AUTH_SYS
;
2940 else if (RtlCompareUnicodeString(sec_flavor_name
, &AUTHGSS_KRB5_NAME
, FALSE
) == 0)
2941 *sec_flavor
= RPCSEC_AUTHGSS_KRB5
;
2942 else if (RtlCompareUnicodeString(sec_flavor_name
, &AUTHGSS_KRB5I_NAME
, FALSE
) == 0)
2943 *sec_flavor
= RPCSEC_AUTHGSS_KRB5I
;
2944 else if (RtlCompareUnicodeString(sec_flavor_name
, &AUTHGSS_KRB5P_NAME
, FALSE
) == 0)
2945 *sec_flavor
= RPCSEC_AUTHGSS_KRB5P
;
2946 else return STATUS_INVALID_PARAMETER
;
2947 return STATUS_SUCCESS
;
2950 NTSTATUS
nfs41_GetLUID(
2953 NTSTATUS status
= STATUS_SUCCESS
;
2954 SECURITY_SUBJECT_CONTEXT sec_ctx
;
2955 SECURITY_QUALITY_OF_SERVICE sec_qos
;
2956 SECURITY_CLIENT_CONTEXT clnt_sec_ctx
;
2958 SeCaptureSubjectContext(&sec_ctx
);
2959 sec_qos
.ContextTrackingMode
= SECURITY_DYNAMIC_TRACKING
;
2960 sec_qos
.ImpersonationLevel
= SecurityIdentification
;
2961 sec_qos
.Length
= sizeof(SECURITY_QUALITY_OF_SERVICE
);
2962 sec_qos
.EffectiveOnly
= 0;
2963 status
= SeCreateClientSecurityFromSubjectContext(&sec_ctx
, &sec_qos
, 1,
2966 print_error("nfs41_GetLUID: SeCreateClientSecurityFromSubjectContext "
2967 "failed %x\n", status
);
2968 goto release_sec_ctx
;
2970 status
= SeQueryAuthenticationIdToken(clnt_sec_ctx
.ClientToken
, id
);
2972 print_error("SeQueryAuthenticationIdToken failed %x\n", status
);
2973 goto release_clnt_sec_ctx
;
2975 release_clnt_sec_ctx
:
2976 SeDeleteClientSecurity(&clnt_sec_ctx
);
2978 SeReleaseSubjectContext(&sec_ctx
);
2983 NTSTATUS
nfs41_get_sec_ctx(
2984 IN
enum _SECURITY_IMPERSONATION_LEVEL level
,
2985 OUT PSECURITY_CLIENT_CONTEXT out_ctx
)
2988 SECURITY_SUBJECT_CONTEXT ctx
;
2989 SECURITY_QUALITY_OF_SERVICE sec_qos
;
2991 SeCaptureSubjectContext(&ctx
);
2992 sec_qos
.ContextTrackingMode
= SECURITY_STATIC_TRACKING
;
2993 sec_qos
.ImpersonationLevel
= level
;
2994 sec_qos
.Length
= sizeof(SECURITY_QUALITY_OF_SERVICE
);
2995 sec_qos
.EffectiveOnly
= 0;
2996 status
= SeCreateClientSecurityFromSubjectContext(&ctx
, &sec_qos
, 1, out_ctx
);
2997 if (status
!= STATUS_SUCCESS
) {
2998 print_error("SeCreateClientSecurityFromSubjectContext "
2999 "failed with %x\n", status
);
3002 DbgP("Created client security token %p\n", out_ctx
->ClientToken
);
3004 SeReleaseSubjectContext(&ctx
);
3010 NTSTATUS NTAPI
nfs41_CreateVNetRoot(
3012 NTSTATUS
nfs41_CreateVNetRoot(
3014 IN OUT PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext
)
3016 NTSTATUS status
= STATUS_SUCCESS
;
3017 NFS41_MOUNT_CONFIG
*Config
;
3018 __notnull PMRX_V_NET_ROOT pVNetRoot
= (PMRX_V_NET_ROOT
)
3019 pCreateNetRootContext
->pVNetRoot
;
3020 __notnull PMRX_NET_ROOT pNetRoot
= pVNetRoot
->pNetRoot
;
3021 __notnull PMRX_SRV_CALL pSrvCall
= pNetRoot
->pSrvCall
;
3022 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
3023 NFS41GetVNetRootExtension(pVNetRoot
);
3024 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
3025 NFS41GetNetRootExtension(pNetRoot
);
3026 NFS41GetDeviceExtension(pCreateNetRootContext
->RxContext
,DevExt
);
3027 DWORD nfs41d_version
= DevExt
->nfs41d_version
;
3028 nfs41_mount_entry
*existing_mount
= NULL
;
3030 BOOLEAN found_existing_mount
= FALSE
, found_matching_flavor
= FALSE
;
3032 ASSERT((NodeType(pNetRoot
) == RDBSS_NTC_NETROOT
) &&
3033 (NodeType(pNetRoot
->pSrvCall
) == RDBSS_NTC_SRVCALL
));
3037 print_srv_call(0, pSrvCall
);
3038 print_net_root(0, pNetRoot
);
3039 print_v_net_root(0, pVNetRoot
);
3041 DbgP("pVNetRoot=%p pNetRoot=%p pSrvCall=%p\n", pVNetRoot
, pNetRoot
, pSrvCall
);
3042 DbgP("pNetRoot=%wZ Type=%d pSrvCallName=%wZ VirtualNetRootStatus=0x%x "
3043 "NetRootStatus=0x%x\n", pNetRoot
->pNetRootName
,
3044 pNetRoot
->Type
, pSrvCall
->pSrvCallName
,
3045 pCreateNetRootContext
->VirtualNetRootStatus
,
3046 pCreateNetRootContext
->NetRootStatus
);
3049 if (pNetRoot
->Type
!= NET_ROOT_DISK
&& pNetRoot
->Type
!= NET_ROOT_WILD
) {
3050 print_error("nfs41_CreateVNetRoot: Unsupported NetRoot Type %u\n",
3052 status
= STATUS_NOT_SUPPORTED
;
3056 pVNetRootContext
->session
= INVALID_HANDLE_VALUE
;
3058 /* In order to cooperate with other network providers, we must
3059 * only claim paths of the form '\\server\nfs4\path' */
3060 status
= has_nfs_prefix(pSrvCall
->pSrvCallName
, pNetRoot
->pNetRootName
);
3062 print_error("nfs41_CreateVNetRoot: NetRootName %wZ doesn't match "
3063 "'\\nfs4'!\n", pNetRoot
->pNetRootName
);
3066 pNetRoot
->MRxNetRootState
= MRX_NET_ROOT_STATE_GOOD
;
3067 pNetRoot
->DeviceType
= FILE_DEVICE_DISK
;
3069 Config
= RxAllocatePoolWithTag(NonPagedPool
,
3070 sizeof(NFS41_MOUNT_CONFIG
), NFS41_MM_POOLTAG
);
3071 if (Config
== NULL
) {
3072 status
= STATUS_INSUFFICIENT_RESOURCES
;
3075 nfs41_MountConfig_InitDefaults(Config
);
3077 if (pCreateNetRootContext
->RxContext
->Create
.EaLength
) {
3078 /* parse the extended attributes for mount options */
3079 status
= nfs41_MountConfig_ParseOptions(
3080 pCreateNetRootContext
->RxContext
->Create
.EaBuffer
,
3081 pCreateNetRootContext
->RxContext
->Create
.EaLength
,
3083 if (status
!= STATUS_SUCCESS
)
3085 pVNetRootContext
->read_only
= Config
->ReadOnly
;
3086 pVNetRootContext
->write_thru
= Config
->write_thru
;
3087 pVNetRootContext
->nocache
= Config
->nocache
;
3089 /* use the SRV_CALL name (without leading \) as the hostname */
3090 Config
->SrvName
.Buffer
= pSrvCall
->pSrvCallName
->Buffer
+ 1;
3091 Config
->SrvName
.Length
=
3092 pSrvCall
->pSrvCallName
->Length
- sizeof(WCHAR
);
3093 Config
->SrvName
.MaximumLength
=
3094 pSrvCall
->pSrvCallName
->MaximumLength
- sizeof(WCHAR
);
3096 pVNetRootContext
->MountPathLen
= Config
->MntPt
.Length
;
3097 pVNetRootContext
->timeout
= Config
->timeout
;
3099 status
= map_sec_flavor(&Config
->SecFlavor
, &pVNetRootContext
->sec_flavor
);
3100 if (status
!= STATUS_SUCCESS
) {
3101 DbgP("Invalid rpcsec security flavor %wZ\n", &Config
->SecFlavor
);
3105 status
= nfs41_GetLUID(&luid
);
3109 if (!pNetRootContext
->mounts_init
) {
3111 DbgP("Initializing mount array\n");
3113 ExInitializeFastMutex(&pNetRootContext
->mountLock
);
3114 InitializeListHead(&pNetRootContext
->mounts
.head
);
3115 pNetRootContext
->mounts_init
= TRUE
;
3119 ExAcquireFastMutex(&pNetRootContext
->mountLock
);
3120 pEntry
= &pNetRootContext
->mounts
.head
;
3121 pEntry
= pEntry
->Flink
;
3122 while (pEntry
!= NULL
) {
3123 existing_mount
= (nfs41_mount_entry
*)CONTAINING_RECORD(pEntry
,
3124 nfs41_mount_entry
, next
);
3126 DbgP("comparing %x.%x with %x.%x\n", luid
.HighPart
, luid
.LowPart
,
3127 existing_mount
->login_id
.HighPart
, existing_mount
->login_id
.LowPart
);
3129 if (RtlEqualLuid(&luid
, &existing_mount
->login_id
)) {
3131 DbgP("Found a matching LUID entry\n");
3133 found_existing_mount
= TRUE
;
3134 switch(pVNetRootContext
->sec_flavor
) {
3135 case RPCSEC_AUTH_SYS
:
3136 if (existing_mount
->authsys_session
!= INVALID_HANDLE_VALUE
)
3137 pVNetRootContext
->session
=
3138 existing_mount
->authsys_session
;
3140 case RPCSEC_AUTHGSS_KRB5
:
3141 if (existing_mount
->gssi_session
!= INVALID_HANDLE_VALUE
)
3142 pVNetRootContext
->session
= existing_mount
->gss_session
;
3144 case RPCSEC_AUTHGSS_KRB5I
:
3145 if (existing_mount
->gss_session
!= INVALID_HANDLE_VALUE
)
3146 pVNetRootContext
->session
= existing_mount
->gssi_session
;
3148 case RPCSEC_AUTHGSS_KRB5P
:
3149 if (existing_mount
->gssp_session
!= INVALID_HANDLE_VALUE
)
3150 pVNetRootContext
->session
= existing_mount
->gssp_session
;
3153 if (pVNetRootContext
->session
&&
3154 pVNetRootContext
->session
!= INVALID_HANDLE_VALUE
)
3155 found_matching_flavor
= 1;
3158 if (pEntry
->Flink
== &pNetRootContext
->mounts
.head
)
3160 pEntry
= pEntry
->Flink
;
3162 ExReleaseFastMutex(&pNetRootContext
->mountLock
);
3164 if (!found_matching_flavor
)
3165 DbgP("Didn't find matching security flavor\n");
3169 /* send the mount upcall */
3170 status
= nfs41_mount(Config
, pVNetRootContext
->sec_flavor
,
3171 &pVNetRootContext
->session
, &nfs41d_version
,
3172 &pVNetRootContext
->FsAttrs
);
3173 if (status
!= STATUS_SUCCESS
) {
3174 BOOLEAN MountsEmpty
;
3175 nfs41_IsListEmpty(pNetRootContext
->mountLock
,
3176 pNetRootContext
->mounts
, MountsEmpty
);
3177 if (!found_existing_mount
&& MountsEmpty
)
3178 pNetRootContext
->mounts_init
= FALSE
;
3179 pVNetRootContext
->session
= INVALID_HANDLE_VALUE
;
3182 pVNetRootContext
->timeout
= Config
->timeout
;
3184 if (!found_existing_mount
) {
3185 /* create a new mount entry and add it to the list */
3186 nfs41_mount_entry
*entry
;
3187 entry
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(nfs41_mount_entry
),
3188 NFS41_MM_POOLTAG_MOUNT
);
3189 if (entry
== NULL
) {
3190 status
= STATUS_INSUFFICIENT_RESOURCES
;
3193 entry
->authsys_session
= entry
->gss_session
=
3194 entry
->gssi_session
= entry
->gssp_session
= INVALID_HANDLE_VALUE
;
3195 switch (pVNetRootContext
->sec_flavor
) {
3196 case RPCSEC_AUTH_SYS
:
3197 entry
->authsys_session
= pVNetRootContext
->session
; break;
3198 case RPCSEC_AUTHGSS_KRB5
:
3199 entry
->gss_session
= pVNetRootContext
->session
; break;
3200 case RPCSEC_AUTHGSS_KRB5I
:
3201 entry
->gssi_session
= pVNetRootContext
->session
; break;
3202 case RPCSEC_AUTHGSS_KRB5P
:
3203 entry
->gssp_session
= pVNetRootContext
->session
; break;
3205 RtlCopyLuid(&entry
->login_id
, &luid
);
3206 nfs41_AddEntry(pNetRootContext
->mountLock
,
3207 pNetRootContext
->mounts
, entry
);
3208 } else if (!found_matching_flavor
) {
3209 ASSERT(existing_mount
!= NULL
);
3210 /* modify existing mount entry */
3212 DbgP("Using existing %d flavor session 0x%x\n",
3213 pVNetRootContext
->sec_flavor
);
3215 switch (pVNetRootContext
->sec_flavor
) {
3216 case RPCSEC_AUTH_SYS
:
3217 existing_mount
->authsys_session
= pVNetRootContext
->session
; break;
3218 case RPCSEC_AUTHGSS_KRB5
:
3219 existing_mount
->gss_session
= pVNetRootContext
->session
; break;
3220 case RPCSEC_AUTHGSS_KRB5I
:
3221 existing_mount
->gssi_session
= pVNetRootContext
->session
; break;
3222 case RPCSEC_AUTHGSS_KRB5P
:
3223 existing_mount
->gssp_session
= pVNetRootContext
->session
; break;
3226 pNetRootContext
->nfs41d_version
= nfs41d_version
;
3228 DbgP("Saving new session 0x%x\n", pVNetRootContext
->session
);
3230 #ifdef STORE_MOUNT_SEC_CONTEXT
3231 status
= nfs41_get_sec_ctx(SecurityImpersonation
,
3232 &pVNetRootContext
->mount_sec_ctx
);
3238 pCreateNetRootContext
->VirtualNetRootStatus
= status
;
3239 if (pNetRoot
->Context
== NULL
)
3240 pCreateNetRootContext
->NetRootStatus
= status
;
3241 pCreateNetRootContext
->Callback(pCreateNetRootContext
);
3243 /* RDBSS expects that MRxCreateVNetRoot returns STATUS_PENDING
3244 * on success or failure */
3245 status
= STATUS_PENDING
;
3253 VOID NTAPI
nfs41_ExtractNetRootName(
3255 VOID
nfs41_ExtractNetRootName(
3257 IN PUNICODE_STRING FilePathName
,
3258 IN PMRX_SRV_CALL SrvCall
,
3259 OUT PUNICODE_STRING NetRootName
,
3260 OUT PUNICODE_STRING RestOfName OPTIONAL
)
3262 ULONG length
= FilePathName
->Length
;
3263 PWCH w
= FilePathName
->Buffer
;
3264 PWCH wlimit
= (PWCH
)(((PCHAR
)w
)+length
);
3267 w
+= (SrvCall
->pSrvCallName
->Length
/sizeof(WCHAR
));
3268 NetRootName
->Buffer
= wlow
= w
;
3269 /* parse the entire path into NetRootName */
3276 if ((*w
== OBJ_NAME_PATH_SEPARATOR
) && (w
!= wlow
))
3281 NetRootName
->Length
= NetRootName
->MaximumLength
3282 = (USHORT
)((PCHAR
)w
- (PCHAR
)wlow
);
3284 DbgP("In: pSrvCall %p PathName=%wZ SrvCallName=%wZ Out: NetRootName=%wZ\n",
3285 SrvCall
, FilePathName
, SrvCall
->pSrvCallName
, NetRootName
);
3292 NTSTATUS NTAPI
nfs41_FinalizeSrvCall(
3294 NTSTATUS
nfs41_FinalizeSrvCall(
3296 PMRX_SRV_CALL pSrvCall
,
3299 NTSTATUS status
= STATUS_SUCCESS
;
3300 PNFS41_SERVER_ENTRY pServerEntry
= (PNFS41_SERVER_ENTRY
)(pSrvCall
->Context
);
3305 print_srv_call(0, pSrvCall
);
3307 if (pSrvCall
->Context
== NULL
)
3311 InterlockedCompareExchangePointer(&pServerEntry
->pRdbssSrvCall
,
3314 InterlockedCompareExchangePointer((void * volatile *)&pServerEntry
->pRdbssSrvCall
,
3317 RxFreePool(pServerEntry
);
3319 pSrvCall
->Context
= NULL
;
3328 NTSTATUS NTAPI
nfs41_FinalizeNetRoot(
3330 NTSTATUS
nfs41_FinalizeNetRoot(
3332 IN OUT PMRX_NET_ROOT pNetRoot
,
3333 IN PBOOLEAN ForceDisconnect
)
3335 NTSTATUS status
= STATUS_SUCCESS
;
3336 PNFS41_NETROOT_EXTENSION pNetRootContext
=
3337 NFS41GetNetRootExtension((PMRX_NET_ROOT
)pNetRoot
);
3338 nfs41_updowncall_entry
*tmp
;
3339 nfs41_mount_entry
*mount_tmp
;
3343 print_net_root(1, pNetRoot
);
3346 if (pNetRoot
->Type
!= NET_ROOT_DISK
&& pNetRoot
->Type
!= NET_ROOT_WILD
) {
3347 status
= STATUS_NOT_SUPPORTED
;
3351 if (pNetRootContext
== NULL
|| !pNetRootContext
->mounts_init
) {
3352 print_error("nfs41_FinalizeNetRoot: No valid session established\n");
3356 if (pNetRoot
->NumberOfFcbs
> 0 || pNetRoot
->NumberOfSrvOpens
> 0) {
3357 print_error("%d open Fcbs %d open SrvOpens\n", pNetRoot
->NumberOfFcbs
,
3358 pNetRoot
->NumberOfSrvOpens
);
3363 nfs41_GetFirstMountEntry(pNetRootContext
->mountLock
,
3364 pNetRootContext
->mounts
, mount_tmp
);
3365 if (mount_tmp
== NULL
)
3368 DbgP("Removing entry luid %x.%x from mount list\n",
3369 mount_tmp
->login_id
.HighPart
, mount_tmp
->login_id
.LowPart
);
3371 if (mount_tmp
->authsys_session
!= INVALID_HANDLE_VALUE
) {
3372 status
= nfs41_unmount(mount_tmp
->authsys_session
,
3373 pNetRootContext
->nfs41d_version
, UPCALL_TIMEOUT_DEFAULT
);
3375 print_error("nfs41_unmount AUTH_SYS failed with %d\n", status
);
3377 if (mount_tmp
->gss_session
!= INVALID_HANDLE_VALUE
) {
3378 status
= nfs41_unmount(mount_tmp
->gss_session
,
3379 pNetRootContext
->nfs41d_version
, UPCALL_TIMEOUT_DEFAULT
);
3381 print_error("nfs41_unmount RPCSEC_GSS_KRB5 failed with %d\n",
3384 if (mount_tmp
->gssi_session
!= INVALID_HANDLE_VALUE
) {
3385 status
= nfs41_unmount(mount_tmp
->gssi_session
,
3386 pNetRootContext
->nfs41d_version
, UPCALL_TIMEOUT_DEFAULT
);
3388 print_error("nfs41_unmount RPCSEC_GSS_KRB5I failed with %d\n",
3391 if (mount_tmp
->gssp_session
!= INVALID_HANDLE_VALUE
) {
3392 status
= nfs41_unmount(mount_tmp
->gssp_session
,
3393 pNetRootContext
->nfs41d_version
, UPCALL_TIMEOUT_DEFAULT
);
3395 print_error("nfs41_unmount RPCSEC_GSS_KRB5P failed with %d\n",
3398 nfs41_RemoveEntry(pNetRootContext
->mountLock
, mount_tmp
);
3399 RxFreePool(mount_tmp
);
3401 /* ignore any errors from unmount */
3402 status
= STATUS_SUCCESS
;
3404 // check if there is anything waiting in the upcall or downcall queue
3406 nfs41_GetFirstEntry(upcallLock
, upcall
, tmp
);
3408 DbgP("Removing entry from upcall list\n");
3409 nfs41_RemoveEntry(upcallLock
, tmp
);
3410 tmp
->status
= STATUS_INSUFFICIENT_RESOURCES
;
3411 KeSetEvent(&tmp
->cond
, 0, FALSE
);
3417 nfs41_GetFirstEntry(downcallLock
, downcall
, tmp
);
3419 DbgP("Removing entry from downcall list\n");
3420 nfs41_RemoveEntry(downcallLock
, tmp
);
3421 tmp
->status
= STATUS_INSUFFICIENT_RESOURCES
;
3422 KeSetEvent(&tmp
->cond
, 0, FALSE
);
3434 NTSTATUS NTAPI
nfs41_FinalizeVNetRoot(
3436 NTSTATUS
nfs41_FinalizeVNetRoot(
3438 IN OUT PMRX_V_NET_ROOT pVNetRoot
,
3439 IN PBOOLEAN ForceDisconnect
)
3441 NTSTATUS status
= STATUS_SUCCESS
;
3442 PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
3443 NFS41GetVNetRootExtension(pVNetRoot
);
3446 print_v_net_root(1, pVNetRoot
);
3448 if (pVNetRoot
->pNetRoot
->Type
!= NET_ROOT_DISK
&&
3449 pVNetRoot
->pNetRoot
->Type
!= NET_ROOT_WILD
)
3450 status
= STATUS_NOT_SUPPORTED
;
3451 #ifdef STORE_MOUNT_SEC_CONTEXT
3452 else if (pVNetRootContext
->session
!= INVALID_HANDLE_VALUE
) {
3454 DbgP("nfs41_FinalizeVNetRoot: deleting security context: %p\n",
3455 pVNetRootContext
->mount_sec_ctx
.ClientToken
);
3457 SeDeleteClientSecurity(&pVNetRootContext
->mount_sec_ctx
);
3466 BOOLEAN
isDataAccess(
3469 if (mask
& (FILE_READ_DATA
| FILE_WRITE_DATA
| FILE_APPEND_DATA
))
3474 BOOLEAN
isOpen2Create(
3477 if (disposition
== FILE_CREATE
|| disposition
== FILE_OPEN_IF
||
3478 disposition
== FILE_OVERWRITE_IF
|| disposition
== FILE_SUPERSEDE
)
3483 BOOLEAN
isFilenameTooLong(
3484 PUNICODE_STRING name
,
3485 PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
)
3487 PFILE_FS_ATTRIBUTE_INFORMATION attrs
= &pVNetRootContext
->FsAttrs
;
3488 LONG len
= attrs
->MaximumComponentNameLength
, count
= 1, i
;
3489 PWCH p
= name
->Buffer
;
3490 for (i
= 0; i
< name
->Length
/ 2; i
++) {
3491 if (p
[0] == L
'\\') count
= 1;
3493 if (p
[0] == L
'\0') return FALSE
;
3494 if (count
> len
) return TRUE
;
3503 PUNICODE_STRING name
)
3506 PWCH p
= name
->Buffer
;
3507 for (i
= 0; i
< name
->Length
/ 2; i
++) {
3508 if (p
[0] == L
':') return TRUE
;
3509 else if (p
[0] == L
'\0') return FALSE
;
3515 BOOLEAN
areOpenParamsValid(NT_CREATE_PARAMETERS
*params
)
3517 /* from ms-fsa page 52 */
3518 if ((params
->CreateOptions
& FILE_DELETE_ON_CLOSE
) &&
3519 !(params
->DesiredAccess
& DELETE
))
3521 if ((params
->CreateOptions
& FILE_DIRECTORY_FILE
) &&
3522 (params
->Disposition
== FILE_SUPERSEDE
||
3523 params
->Disposition
== FILE_OVERWRITE
||
3524 params
->Disposition
== FILE_OVERWRITE_IF
))
3526 if ((params
->CreateOptions
& FILE_NO_INTERMEDIATE_BUFFERING
) &&
3527 (params
->DesiredAccess
& FILE_APPEND_DATA
) &&
3528 !(params
->DesiredAccess
& FILE_WRITE_DATA
))
3530 /* from ms-fsa 3.1.5.1.1 page 56 */
3531 if ((params
->CreateOptions
& FILE_DIRECTORY_FILE
) &&
3532 (params
->FileAttributes
& FILE_ATTRIBUTE_TEMPORARY
))
3537 NTSTATUS
map_open_errors(
3542 case NO_ERROR
: return STATUS_SUCCESS
;
3543 case ERROR_ACCESS_DENIED
:
3544 if (len
> 0) return STATUS_ACCESS_DENIED
;
3545 else return STATUS_SUCCESS
;
3546 case ERROR_INVALID_REPARSE_DATA
:
3547 case ERROR_INVALID_NAME
: return STATUS_OBJECT_NAME_INVALID
;
3548 case ERROR_FILE_EXISTS
: return STATUS_OBJECT_NAME_COLLISION
;
3549 case ERROR_FILE_INVALID
: return STATUS_FILE_INVALID
;
3550 case ERROR_FILE_NOT_FOUND
: return STATUS_OBJECT_NAME_NOT_FOUND
;
3551 case ERROR_FILENAME_EXCED_RANGE
: return STATUS_NAME_TOO_LONG
;
3552 case ERROR_NETWORK_ACCESS_DENIED
: return STATUS_NETWORK_ACCESS_DENIED
;
3553 case ERROR_PATH_NOT_FOUND
: return STATUS_OBJECT_PATH_NOT_FOUND
;
3554 case ERROR_BAD_NETPATH
: return STATUS_BAD_NETWORK_PATH
;
3555 case ERROR_SHARING_VIOLATION
: return STATUS_SHARING_VIOLATION
;
3556 case ERROR_REPARSE
: return STATUS_REPARSE
;
3557 case ERROR_TOO_MANY_LINKS
: return STATUS_TOO_MANY_LINKS
;
3558 case ERROR_DIRECTORY
: return STATUS_FILE_IS_A_DIRECTORY
;
3559 case ERROR_BAD_FILE_TYPE
: return STATUS_NOT_A_DIRECTORY
;
3561 print_error("[ERROR] nfs41_Create: upcall returned %d returning "
3562 "STATUS_INSUFFICIENT_RESOURCES\n", status
);
3563 case ERROR_OUTOFMEMORY
: return STATUS_INSUFFICIENT_RESOURCES
;
3567 DWORD
map_disposition_to_create_retval(
3571 switch(disposition
) {
3572 case FILE_SUPERSEDE
:
3573 if (errno
== ERROR_FILE_NOT_FOUND
) return FILE_CREATED
;
3574 else return FILE_SUPERSEDED
;
3575 case FILE_CREATE
: return FILE_CREATED
;
3576 case FILE_OPEN
: return FILE_OPENED
;
3578 if (errno
== ERROR_FILE_NOT_FOUND
) return FILE_CREATED
;
3579 else return FILE_OPENED
;
3580 case FILE_OVERWRITE
: return FILE_OVERWRITTEN
;
3581 case FILE_OVERWRITE_IF
:
3582 if (errno
== ERROR_FILE_NOT_FOUND
) return FILE_CREATED
;
3583 else return FILE_OVERWRITTEN
;
3585 print_error("unknown disposition %d\n", disposition
);
3590 static BOOLEAN
create_should_pass_ea(
3591 IN PFILE_FULL_EA_INFORMATION ea
,
3592 IN ULONG disposition
)
3594 /* don't pass cygwin EAs */
3595 if (AnsiStrEq(&NfsV3Attributes
, ea
->EaName
, ea
->EaNameLength
)
3596 || AnsiStrEq(&NfsActOnLink
, ea
->EaName
, ea
->EaNameLength
)
3597 || AnsiStrEq(&NfsSymlinkTargetName
, ea
->EaName
, ea
->EaNameLength
))
3599 /* only set EAs on file creation */
3600 return disposition
== FILE_SUPERSEDE
|| disposition
== FILE_CREATE
3601 || disposition
== FILE_OPEN_IF
|| disposition
== FILE_OVERWRITE
3602 || disposition
== FILE_OVERWRITE_IF
;
3605 NTSTATUS
check_nfs41_create_args(
3606 IN PRX_CONTEXT RxContext
)
3608 NTSTATUS status
= STATUS_SUCCESS
;
3609 PNT_CREATE_PARAMETERS params
= &RxContext
->Create
.NtCreateParameters
;
3610 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
3611 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
3612 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
3613 __notnull PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs
=
3614 &pVNetRootContext
->FsAttrs
;
3615 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
3616 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
3617 __notnull PMRX_FCB Fcb
= RxContext
->pFcb
;
3618 __notnull PNFS41_FCB nfs41_fcb
= (PNFS41_FCB
)Fcb
->Context
;
3619 PFILE_FULL_EA_INFORMATION ea
= (PFILE_FULL_EA_INFORMATION
)
3620 RxContext
->CurrentIrp
->AssociatedIrp
.SystemBuffer
;
3622 if (Fcb
->pNetRoot
->Type
!= NET_ROOT_DISK
&&
3623 Fcb
->pNetRoot
->Type
!= NET_ROOT_WILD
) {
3624 print_error("nfs41_Create: Unsupported NetRoot Type %u\n",
3625 Fcb
->pNetRoot
->Type
);
3626 status
= STATUS_NOT_SUPPORTED
;
3630 if (FlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
)) {
3631 print_error("FCB_STATE_PAGING_FILE not implemented\n");
3632 status
= STATUS_NOT_IMPLEMENTED
;
3636 if (!pNetRootContext
->mounts_init
) {
3637 print_error("nfs41_Create: No valid session established\n");
3638 status
= STATUS_INSUFFICIENT_RESOURCES
;
3642 if (isStream(SrvOpen
->pAlreadyPrefixedName
)) {
3643 status
= STATUS_NOT_SUPPORTED
;
3647 if (pVNetRootContext
->read_only
&&
3648 (params
->DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
))) {
3649 status
= STATUS_NETWORK_ACCESS_DENIED
;
3653 /* if FCB was marked for deletion and opened multiple times, as soon
3654 * as first close happen, FCB transitions into delete_pending state
3655 * no more opens allowed
3657 if (Fcb
->OpenCount
&& nfs41_fcb
->DeletePending
) {
3658 status
= STATUS_DELETE_PENDING
;
3662 /* ms-fsa: 3.1.5.1.2.1 page 68 */
3663 if (Fcb
->OpenCount
&& nfs41_fcb
->StandardInfo
.DeletePending
&&
3664 !(params
->ShareAccess
& FILE_SHARE_DELETE
) &&
3665 (params
->DesiredAccess
& (FILE_EXECUTE
| FILE_READ_DATA
|
3666 FILE_WRITE_DATA
| FILE_APPEND_DATA
))) {
3667 status
= STATUS_SHARING_VIOLATION
;
3671 /* rdbss seems miss this sharing_violation check */
3672 if (Fcb
->OpenCount
&& params
->Disposition
== FILE_SUPERSEDE
) {
3674 if ((!RxContext
->CurrentIrpSp
->FileObject
->SharedRead
&&
3675 (params
->DesiredAccess
& FILE_READ_DATA
)) ||
3676 ((!RxContext
->CurrentIrpSp
->FileObject
->SharedWrite
&&
3677 (params
->DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
|
3678 FILE_WRITE_ATTRIBUTES
))) ||
3679 (!RxContext
->CurrentIrpSp
->FileObject
->SharedDelete
&&
3680 (params
->DesiredAccess
& DELETE
)))) {
3682 if ((!RxContext
->CurrentIrpSp
->FileObject
->SharedRead
&&
3683 (params
->DesiredAccess
& FILE_READ_DATA
)) ||
3684 (!RxContext
->CurrentIrpSp
->FileObject
->SharedWrite
&&
3685 (params
->DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
|
3686 FILE_WRITE_ATTRIBUTES
)) ||
3687 (!RxContext
->CurrentIrpSp
->FileObject
->SharedDelete
&&
3688 (params
->DesiredAccess
& DELETE
)))) {
3690 status
= STATUS_SHARING_VIOLATION
;
3694 if (isFilenameTooLong(SrvOpen
->pAlreadyPrefixedName
, pVNetRootContext
)) {
3695 status
= STATUS_OBJECT_NAME_INVALID
;
3699 if (!areOpenParamsValid(params
)) {
3700 status
= STATUS_INVALID_PARAMETER
;
3704 /* from ms-fsa 3.1.5.1.1 page 56 */
3705 if ((params
->CreateOptions
& FILE_DELETE_ON_CLOSE
) &&
3706 (params
->FileAttributes
& FILE_ATTRIBUTE_READONLY
)) {
3707 status
= STATUS_CANNOT_DELETE
;
3712 /* ignore cygwin EAs when checking support and access */
3713 if (!AnsiStrEq(&NfsV3Attributes
, ea
->EaName
, ea
->EaNameLength
) &&
3714 !AnsiStrEq(&NfsActOnLink
, ea
->EaName
, ea
->EaNameLength
) &&
3715 !AnsiStrEq(&NfsSymlinkTargetName
, ea
->EaName
, ea
->EaNameLength
)) {
3716 if (!(FsAttrs
->FileSystemAttributes
& FILE_SUPPORTS_EXTENDED_ATTRIBUTES
)) {
3717 status
= STATUS_EAS_NOT_SUPPORTED
;
3721 } else if (RxContext
->CurrentIrpSp
->Parameters
.Create
.EaLength
) {
3722 status
= STATUS_INVALID_PARAMETER
;
3731 NTSTATUS NTAPI
nfs41_Create(
3733 NTSTATUS
nfs41_Create(
3735 IN OUT PRX_CONTEXT RxContext
)
3737 NTSTATUS status
= STATUS_INSUFFICIENT_RESOURCES
;
3738 nfs41_updowncall_entry
*entry
= NULL
;
3739 PNT_CREATE_PARAMETERS params
= &RxContext
->Create
.NtCreateParameters
;
3740 PFILE_FULL_EA_INFORMATION ea
= (PFILE_FULL_EA_INFORMATION
)
3741 RxContext
->CurrentIrp
->AssociatedIrp
.SystemBuffer
;
3742 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
3743 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
3744 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
3745 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
3746 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
3747 __notnull PMRX_FCB Fcb
= RxContext
->pFcb
;
3748 __notnull PNFS41_FCB nfs41_fcb
= (PNFS41_FCB
)Fcb
->Context
;
3749 PNFS41_FOBX nfs41_fobx
= NULL
;
3750 BOOLEAN oldDeletePending
= nfs41_fcb
->StandardInfo
.DeletePending
;
3751 #ifdef ENABLE_TIMINGS
3752 LARGE_INTEGER t1
, t2
;
3753 t1
= KeQueryPerformanceCounter(NULL
);
3756 ASSERT( NodeType(SrvOpen
) == RDBSS_NTC_SRVOPEN
);
3760 print_debug_header(RxContext
);
3761 print_nt_create_params(1, RxContext
->Create
.NtCreateParameters
);
3762 if (ea
) print_ea_info(0, ea
);
3765 status
= check_nfs41_create_args(RxContext
);
3766 if (status
) goto out
;
3768 #if defined(STORE_MOUNT_SEC_CONTEXT) && defined (USE_MOUNT_SEC_CONTEXT)
3769 status
= nfs41_UpcallCreate(NFS41_OPEN
, &pVNetRootContext
->mount_sec_ctx
,
3771 status
= nfs41_UpcallCreate(NFS41_OPEN
, NULL
,
3773 pVNetRootContext
->session
, INVALID_HANDLE_VALUE
,
3774 pNetRootContext
->nfs41d_version
,
3775 SrvOpen
->pAlreadyPrefixedName
, &entry
);
3776 if (status
) goto out
;
3778 entry
->u
.Open
.access_mask
= params
->DesiredAccess
;
3779 entry
->u
.Open
.access_mode
= params
->ShareAccess
;
3780 entry
->u
.Open
.attrs
= params
->FileAttributes
;
3781 if (!(params
->CreateOptions
& FILE_DIRECTORY_FILE
))
3782 entry
->u
.Open
.attrs
|= FILE_ATTRIBUTE_ARCHIVE
;
3783 entry
->u
.Open
.disp
= params
->Disposition
;
3784 entry
->u
.Open
.copts
= params
->CreateOptions
;
3785 entry
->u
.Open
.srv_open
= SrvOpen
;
3786 /* treat the NfsActOnLink ea as FILE_OPEN_REPARSE_POINT */
3787 if ((ea
&& AnsiStrEq(&NfsActOnLink
, ea
->EaName
, ea
->EaNameLength
)) ||
3788 (entry
->u
.Open
.access_mask
& DELETE
))
3789 entry
->u
.Open
.copts
|= FILE_OPEN_REPARSE_POINT
;
3790 if (isDataAccess(params
->DesiredAccess
) || isOpen2Create(params
->Disposition
))
3791 entry
->u
.Open
.open_owner_id
= InterlockedIncrement(&open_owner_id
);
3792 // if we are creating a file check if nfsv3attributes were passed in
3793 if (params
->Disposition
!= FILE_OPEN
&& params
->Disposition
!= FILE_OVERWRITE
) {
3794 entry
->u
.Open
.mode
= 0777;
3795 if (ea
&& AnsiStrEq(&NfsV3Attributes
, ea
->EaName
, ea
->EaNameLength
)) {
3796 nfs3_attrs
*attrs
= (nfs3_attrs
*)(ea
->EaName
+ ea
->EaNameLength
+ 1);
3798 DbgP("creating file with mode %o\n", attrs
->mode
);
3800 entry
->u
.Open
.mode
= attrs
->mode
;
3802 if (params
->FileAttributes
& FILE_ATTRIBUTE_READONLY
)
3803 entry
->u
.Open
.mode
= 0444;
3805 if (entry
->u
.Open
.disp
== FILE_CREATE
&& ea
&&
3806 AnsiStrEq(&NfsSymlinkTargetName
, ea
->EaName
, ea
->EaNameLength
)) {
3807 /* for a cygwin symlink, given as a unicode string */
3808 entry
->u
.Open
.symlink
.Buffer
= (PWCH
)(ea
->EaName
+ ea
->EaNameLength
+ 1);
3809 entry
->u
.Open
.symlink
.MaximumLength
= entry
->u
.Open
.symlink
.Length
= ea
->EaValueLength
;
3812 if (ea
&& create_should_pass_ea(ea
, params
->Disposition
)) {
3813 /* lock the extended attribute buffer for read access in user space */
3814 entry
->u
.Open
.EaMdl
= IoAllocateMdl(ea
,
3815 RxContext
->CurrentIrpSp
->Parameters
.Create
.EaLength
,
3816 FALSE
, FALSE
, NULL
);
3817 if (entry
->u
.Open
.EaMdl
== NULL
) {
3818 status
= STATUS_INTERNAL_ERROR
;
3822 entry
->u
.Open
.EaMdl
->MdlFlags
|= MDL_MAPPING_CAN_FAIL
;
3823 MmProbeAndLockPages(entry
->u
.Open
.EaMdl
, KernelMode
, IoModifyAccess
);
3826 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
3827 #ifndef USE_MOUNT_SEC_CONTEXT
3828 SeDeleteClientSecurity(&entry
->sec_ctx
);
3830 if (status
) goto out
;
3832 if (entry
->u
.Open
.EaMdl
) {
3833 MmUnlockPages(entry
->u
.Open
.EaMdl
);
3834 IoFreeMdl(entry
->u
.Open
.EaMdl
);
3837 if (entry
->status
== NO_ERROR
&& entry
->errno
== ERROR_REPARSE
) {
3838 /* symbolic link handling. when attempting to open a symlink when the
3839 * FILE_OPEN_REPARSE_POINT flag is not set, replace the filename with
3840 * the symlink target's by calling RxPrepareToReparseSymbolicLink()
3841 * and returning STATUS_REPARSE. the object manager will attempt to
3842 * open the new path, and return its handle for the original open */
3843 PRDBSS_DEVICE_OBJECT DeviceObject
= RxContext
->RxDeviceObject
;
3844 PV_NET_ROOT VNetRoot
= (PV_NET_ROOT
)
3845 RxContext
->pRelevantSrvOpen
->pVNetRoot
;
3846 PUNICODE_STRING VNetRootPrefix
= &VNetRoot
->PrefixEntry
.Prefix
;
3847 UNICODE_STRING AbsPath
;
3849 BOOLEAN ReparseRequired
;
3851 /* allocate the string for RxPrepareToReparseSymbolicLink(), and
3852 * format an absolute path "DeviceName+VNetRootName+symlink" */
3853 AbsPath
.Length
= DeviceObject
->DeviceName
.Length
+
3854 VNetRootPrefix
->Length
+ entry
->u
.Open
.symlink
.Length
;
3855 AbsPath
.MaximumLength
= AbsPath
.Length
+ sizeof(UNICODE_NULL
);
3856 AbsPath
.Buffer
= RxAllocatePoolWithTag(NonPagedPool
,
3857 AbsPath
.MaximumLength
, NFS41_MM_POOLTAG
);
3858 if (AbsPath
.Buffer
== NULL
) {
3859 status
= STATUS_INSUFFICIENT_RESOURCES
;
3863 buf
= (PCHAR
)AbsPath
.Buffer
;
3864 RtlCopyMemory(buf
, DeviceObject
->DeviceName
.Buffer
,
3865 DeviceObject
->DeviceName
.Length
);
3866 buf
+= DeviceObject
->DeviceName
.Length
;
3867 RtlCopyMemory(buf
, VNetRootPrefix
->Buffer
, VNetRootPrefix
->Length
);
3868 buf
+= VNetRootPrefix
->Length
;
3869 RtlCopyMemory(buf
, entry
->u
.Open
.symlink
.Buffer
,
3870 entry
->u
.Open
.symlink
.Length
);
3871 RxFreePool(entry
->u
.Open
.symlink
.Buffer
);
3872 buf
+= entry
->u
.Open
.symlink
.Length
;
3873 *(PWCHAR
)buf
= UNICODE_NULL
;
3875 status
= RxPrepareToReparseSymbolicLink(RxContext
,
3876 entry
->u
.Open
.symlink_embedded
, &AbsPath
, TRUE
, &ReparseRequired
);
3878 DbgP("RxPrepareToReparseSymbolicLink(%u, '%wZ') returned %08lX, "
3879 "FileName is '%wZ'\n", entry
->u
.Open
.symlink_embedded
,
3880 &AbsPath
, status
, &RxContext
->CurrentIrpSp
->FileObject
->FileName
);
3882 if (status
== STATUS_SUCCESS
) {
3883 /* if a reparse is not required, reopen the link itself. this
3884 * happens with operations on cygwin symlinks, where the reparse
3885 * flag is not set */
3886 if (!ReparseRequired
) {
3887 entry
->u
.Open
.symlink
.Length
= 0;
3888 entry
->u
.Open
.copts
|= FILE_OPEN_REPARSE_POINT
;
3891 status
= STATUS_REPARSE
;
3896 status
= map_open_errors(entry
->status
,
3897 SrvOpen
->pAlreadyPrefixedName
->Length
);
3900 print_open_error(1, status
);
3905 if (!RxIsFcbAcquiredExclusive(Fcb
)) {
3906 ASSERT(!RxIsFcbAcquiredShared(Fcb
));
3907 RxAcquireExclusiveFcbResourceInMRx(Fcb
);
3910 RxContext
->pFobx
= RxCreateNetFobx(RxContext
, SrvOpen
);
3911 if (RxContext
->pFobx
== NULL
) {
3912 status
= STATUS_INSUFFICIENT_RESOURCES
;
3916 DbgP("nfs41_Create: created FOBX %p\n", RxContext
->pFobx
);
3918 nfs41_fobx
= (PNFS41_FOBX
)(RxContext
->pFobx
)->Context
;
3919 nfs41_fobx
->nfs41_open_state
= entry
->open_state
;
3920 #ifndef USE_MOUNT_SEC_CONTEXT
3921 status
= nfs41_get_sec_ctx(SecurityImpersonation
, &nfs41_fobx
->sec_ctx
);
3925 RtlCopyMemory(&nfs41_fobx
->sec_ctx
, &pVNetRootContext
->mount_sec_ctx
,
3926 sizeof(nfs41_fobx
->sec_ctx
));
3929 // we get attributes only for data access and file (not directories)
3930 if (Fcb
->OpenCount
== 0 ||
3931 (Fcb
->OpenCount
> 0 &&
3932 nfs41_fcb
->changeattr
!= entry
->ChangeTime
)) {
3933 FCB_INIT_PACKET InitPacket
;
3934 RX_FILE_TYPE StorageType
= FileTypeNotYetKnown
;
3935 RtlCopyMemory(&nfs41_fcb
->BasicInfo
, &entry
->u
.Open
.binfo
,
3936 sizeof(entry
->u
.Open
.binfo
));
3937 RtlCopyMemory(&nfs41_fcb
->StandardInfo
, &entry
->u
.Open
.sinfo
,
3938 sizeof(entry
->u
.Open
.sinfo
));
3939 nfs41_fcb
->mode
= entry
->u
.Open
.mode
;
3940 nfs41_fcb
->changeattr
= entry
->ChangeTime
;
3941 if (((params
->CreateOptions
& FILE_DELETE_ON_CLOSE
) &&
3942 !pVNetRootContext
->read_only
) || oldDeletePending
)
3943 nfs41_fcb
->StandardInfo
.DeletePending
= TRUE
;
3945 RxFormInitPacket(InitPacket
,
3946 &entry
->u
.Open
.binfo
.FileAttributes
,
3947 &entry
->u
.Open
.sinfo
.NumberOfLinks
,
3948 &entry
->u
.Open
.binfo
.CreationTime
,
3949 &entry
->u
.Open
.binfo
.LastAccessTime
,
3950 &entry
->u
.Open
.binfo
.LastWriteTime
,
3951 &entry
->u
.Open
.binfo
.ChangeTime
,
3952 &entry
->u
.Open
.sinfo
.AllocationSize
,
3953 &entry
->u
.Open
.sinfo
.EndOfFile
,
3954 &entry
->u
.Open
.sinfo
.EndOfFile
);
3956 if (entry
->u
.Open
.sinfo
.Directory
)
3957 StorageType
= FileTypeDirectory
;
3959 StorageType
= FileTypeFile
;
3961 RxFinishFcbInitialization(Fcb
, RDBSS_STORAGE_NTC(StorageType
),
3966 DbgP("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
3968 print_basic_info(1, &nfs41_fcb
->BasicInfo
);
3969 print_std_info(1, &nfs41_fcb
->StandardInfo
);
3972 /* aglo: 05/10/2012. it seems like always have to invalid the cache if the
3973 * file has been opened before and being opened again for data access.
3974 * If the file was opened before, RDBSS might have cached (unflushed) data
3975 * and by opening it again, we will not have the correct representation of
3976 * the file size and data content. fileio tests 208, 219, 221.
3978 if (Fcb
->OpenCount
> 0 && (isDataAccess(params
->DesiredAccess
) ||
3979 nfs41_fcb
->changeattr
!= entry
->ChangeTime
) &&
3980 !nfs41_fcb
->StandardInfo
.Directory
) {
3981 ULONG flag
= DISABLE_CACHING
;
3983 DbgP("nfs41_Create: reopening (changed) file %wZ\n",
3984 SrvOpen
->pAlreadyPrefixedName
);
3986 RxChangeBufferingState((PSRV_OPEN
)SrvOpen
, ULongToPtr(flag
), 1);
3988 if (!nfs41_fcb
->StandardInfo
.Directory
&&
3989 isDataAccess(params
->DesiredAccess
)) {
3990 nfs41_fobx
->deleg_type
= entry
->u
.Open
.deleg_type
;
3992 DbgP("nfs41_Create: received delegation %d\n", entry
->u
.Open
.deleg_type
);
3994 if (!(params
->CreateOptions
& FILE_WRITE_THROUGH
) &&
3995 !pVNetRootContext
->write_thru
&&
3996 (entry
->u
.Open
.deleg_type
== 2 ||
3997 (params
->DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)))) {
3999 DbgP("nfs41_Create: enabling write buffering\n");
4001 SrvOpen
->BufferingFlags
|=
4002 (FCB_STATE_WRITECACHING_ENABLED
|
4003 FCB_STATE_WRITEBUFFERING_ENABLED
);
4004 } else if (params
->CreateOptions
& FILE_WRITE_THROUGH
||
4005 pVNetRootContext
->write_thru
)
4006 nfs41_fobx
->write_thru
= TRUE
;
4007 if (entry
->u
.Open
.deleg_type
>= 1 ||
4008 params
->DesiredAccess
& FILE_READ_DATA
) {
4010 DbgP("nfs41_Create: enabling read buffering\n");
4012 SrvOpen
->BufferingFlags
|=
4013 (FCB_STATE_READBUFFERING_ENABLED
|
4014 FCB_STATE_READCACHING_ENABLED
);
4016 if (pVNetRootContext
->nocache
||
4017 (params
->CreateOptions
& FILE_NO_INTERMEDIATE_BUFFERING
)) {
4019 DbgP("nfs41_Create: disabling buffering\n");
4021 SrvOpen
->BufferingFlags
= FCB_STATE_DISABLE_LOCAL_BUFFERING
;
4022 nfs41_fobx
->nocache
= TRUE
;
4023 } else if (!entry
->u
.Open
.deleg_type
&& !Fcb
->OpenCount
) {
4024 nfs41_fcb_list_entry
*oentry
;
4026 DbgP("nfs41_Create: received no delegations: srv_open=%p "
4027 "ctime=%llu\n", SrvOpen
, entry
->ChangeTime
);
4029 oentry
= RxAllocatePoolWithTag(NonPagedPool
,
4030 sizeof(nfs41_fcb_list_entry
), NFS41_MM_POOLTAG_OPEN
);
4031 if (oentry
== NULL
) {
4032 status
= STATUS_INSUFFICIENT_RESOURCES
;
4035 oentry
->fcb
= RxContext
->pFcb
;
4036 oentry
->nfs41_fobx
= nfs41_fobx
;
4037 oentry
->session
= pVNetRootContext
->session
;
4038 oentry
->ChangeTime
= entry
->ChangeTime
;
4039 oentry
->skip
= FALSE
;
4040 nfs41_AddEntry(fcblistLock
, openlist
, oentry
);
4044 if ((params
->CreateOptions
& FILE_DELETE_ON_CLOSE
) &&
4045 !pVNetRootContext
->read_only
)
4046 nfs41_fcb
->StandardInfo
.DeletePending
= TRUE
;
4048 RxContext
->Create
.ReturnedCreateInformation
=
4049 map_disposition_to_create_retval(params
->Disposition
, entry
->errno
);
4051 RxContext
->pFobx
->OffsetOfNextEaToReturn
= 1;
4053 RxContext
->CurrentIrp
->IoStatus
.Information
=
4054 RxContext
->Create
.ReturnedCreateInformation
;
4056 status
= RxContext
->CurrentIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
4062 #ifdef ENABLE_TIMINGS
4063 t2
= KeQueryPerformanceCounter(NULL
);
4064 if ((params
->DesiredAccess
& FILE_READ_DATA
) ||
4065 (params
->DesiredAccess
& FILE_WRITE_DATA
) ||
4066 (params
->DesiredAccess
& FILE_APPEND_DATA
) ||
4067 (params
->DesiredAccess
& FILE_EXECUTE
)) {
4068 InterlockedIncrement(&open
.tops
);
4069 InterlockedAdd64(&open
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
4070 #ifdef ENABLE_INDV_TIMINGS
4071 DbgP("nfs41_Create open delta = %d op=%d sum=%d\n",
4072 t2
.QuadPart
- t1
.QuadPart
, open
.tops
, open
.ticks
);
4075 InterlockedIncrement(&lookup
.tops
);
4076 InterlockedAdd64(&lookup
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
4077 #ifdef ENABLE_INDV_TIMINGS
4078 DbgP("nfs41_Create lookup delta = %d op=%d sum=%d\n",
4079 t2
.QuadPart
- t1
.QuadPart
, lookup
.tops
, lookup
.ticks
);
4090 NTSTATUS NTAPI
nfs41_CollapseOpen(
4092 NTSTATUS
nfs41_CollapseOpen(
4094 IN OUT PRX_CONTEXT RxContext
)
4096 NTSTATUS status
= STATUS_MORE_PROCESSING_REQUIRED
;
4103 NTSTATUS NTAPI
nfs41_ShouldTryToCollapseThisOpen(
4105 NTSTATUS
nfs41_ShouldTryToCollapseThisOpen(
4107 IN OUT PRX_CONTEXT RxContext
)
4109 if (RxContext
->pRelevantSrvOpen
== NULL
)
4110 return STATUS_SUCCESS
;
4111 else return STATUS_MORE_PROCESSING_REQUIRED
;
4115 ULONG NTAPI
nfs41_ExtendForCache(
4117 ULONG
nfs41_ExtendForCache(
4119 IN OUT PRX_CONTEXT RxContext
,
4120 IN PLARGE_INTEGER pNewFileSize
,
4121 OUT PLARGE_INTEGER pNewAllocationSize
)
4123 NTSTATUS status
= STATUS_SUCCESS
;
4124 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
4126 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
4128 print_debug_header(RxContext
);
4129 DbgP("input: byte count 0x%x filesize 0x%x alloc size 0x%x\n",
4130 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
, *pNewFileSize
,
4131 *pNewAllocationSize
);
4133 pNewAllocationSize
->QuadPart
= pNewFileSize
->QuadPart
+ 8192;
4134 nfs41_fcb
->StandardInfo
.AllocationSize
.QuadPart
=
4135 pNewAllocationSize
->QuadPart
;
4136 nfs41_fcb
->StandardInfo
.EndOfFile
.QuadPart
= pNewFileSize
->QuadPart
;
4138 DbgP("new filesize 0x%x new allocation size 0x%x\n", *pNewFileSize
,
4139 *pNewAllocationSize
);
4147 VOID
nfs41_remove_fcb_entry(
4151 nfs41_fcb_list_entry
*cur
;
4152 ExAcquireFastMutex(&fcblistLock
);
4154 pEntry
= openlist
.head
.Flink
;
4155 while (!IsListEmpty(&openlist
.head
)) {
4156 cur
= (nfs41_fcb_list_entry
*)CONTAINING_RECORD(pEntry
,
4157 nfs41_fcb_list_entry
, next
);
4158 if (cur
->fcb
== fcb
) {
4160 DbgP("nfs41_remove_srvopen_entry: Found match for fcb=%p\n", fcb
);
4162 RemoveEntryList(pEntry
);
4166 if (pEntry
->Flink
== &openlist
.head
) {
4168 DbgP("nfs41_remove_srvopen_entry: reached EOL looking for fcb "
4173 pEntry
= pEntry
->Flink
;
4175 ExReleaseFastMutex(&fcblistLock
);
4178 NTSTATUS
map_close_errors(
4182 case NO_ERROR
: return STATUS_SUCCESS
;
4183 case ERROR_NETNAME_DELETED
: return STATUS_NETWORK_NAME_DELETED
;
4184 case ERROR_NOT_EMPTY
: return STATUS_DIRECTORY_NOT_EMPTY
;
4185 case ERROR_FILE_INVALID
: return STATUS_FILE_INVALID
;
4187 print_error("failed to map windows error %d to NTSTATUS; "
4188 "defaulting to STATUS_INTERNAL_ERROR\n", status
);
4189 case ERROR_INTERNAL_ERROR
: return STATUS_INTERNAL_ERROR
;
4194 NTSTATUS NTAPI
nfs41_CloseSrvOpen(
4196 NTSTATUS
nfs41_CloseSrvOpen(
4198 IN OUT PRX_CONTEXT RxContext
)
4200 NTSTATUS status
= STATUS_INSUFFICIENT_RESOURCES
;
4201 nfs41_updowncall_entry
*entry
;
4202 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
4203 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
4204 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
4205 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
4206 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
4207 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
4208 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
4209 #ifdef ENABLE_TIMINGS
4210 LARGE_INTEGER t1
, t2
;
4211 t1
= KeQueryPerformanceCounter(NULL
);
4216 print_debug_header(RxContext
);
4219 if (!nfs41_fobx
->deleg_type
&& !nfs41_fcb
->StandardInfo
.Directory
&&
4220 !RxContext
->pFcb
->OpenCount
) {
4221 nfs41_remove_fcb_entry(RxContext
->pFcb
);
4224 status
= nfs41_UpcallCreate(NFS41_CLOSE
, &nfs41_fobx
->sec_ctx
,
4225 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
4226 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
4227 if (status
) goto out
;
4229 entry
->u
.Close
.srv_open
= SrvOpen
;
4230 if (nfs41_fcb
->StandardInfo
.DeletePending
)
4231 nfs41_fcb
->DeletePending
= TRUE
;
4232 if (!RxContext
->pFcb
->OpenCount
||
4233 (nfs41_fcb
->StandardInfo
.DeletePending
&&
4234 nfs41_fcb
->StandardInfo
.Directory
))
4235 entry
->u
.Close
.remove
= nfs41_fcb
->StandardInfo
.DeletePending
;
4236 if (!RxContext
->pFcb
->OpenCount
)
4237 entry
->u
.Close
.renamed
= nfs41_fcb
->Renamed
;
4239 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
4240 #ifndef USE_MOUNT_SEC_CONTEXT
4241 SeDeleteClientSecurity(&nfs41_fobx
->sec_ctx
);
4243 if (status
) goto out
;
4245 /* map windows ERRORs to NTSTATUS */
4246 status
= map_close_errors(entry
->status
);
4249 #ifdef ENABLE_TIMINGS
4250 t2
= KeQueryPerformanceCounter(NULL
);
4251 InterlockedIncrement(&close
.tops
);
4252 InterlockedAdd64(&close
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
4253 #ifdef ENABLE_INDV_TIMINGS
4254 DbgP("nfs41_CloseSrvOpen delta = %d op=%d sum=%d\n",
4255 t2
.QuadPart
- t1
.QuadPart
, close
.tops
, close
.ticks
);
4265 NTSTATUS NTAPI
nfs41_Flush(
4267 NTSTATUS
nfs41_Flush(
4269 IN OUT PRX_CONTEXT RxContext
)
4271 return STATUS_SUCCESS
;
4275 NTSTATUS NTAPI
nfs41_DeallocateForFcb(
4277 NTSTATUS
nfs41_DeallocateForFcb(
4279 IN OUT PMRX_FCB pFcb
)
4281 return STATUS_SUCCESS
;
4285 NTSTATUS NTAPI
nfs41_DeallocateForFobx(
4287 NTSTATUS
nfs41_DeallocateForFobx(
4289 IN OUT PMRX_FOBX pFobx
)
4291 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(pFobx
);
4292 if (nfs41_fobx
->acl
)
4293 RxFreePool(nfs41_fobx
->acl
);
4294 return STATUS_SUCCESS
;
4297 void print_debug_filedirquery_header(
4298 PRX_CONTEXT RxContext
)
4300 print_debug_header(RxContext
);
4301 DbgP("FileName='%wZ', InfoClass = %s\n",
4302 GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext
),
4303 print_file_information_class(RxContext
->Info
.FileInformationClass
));
4306 void print_querydir_args(
4307 PRX_CONTEXT RxContext
)
4309 print_debug_filedirquery_header(RxContext
);
4310 DbgP("Filter='%wZ', Index=%d, Restart/Single/Specified/Init=%d/%d/%d/%d\n",
4311 &RxContext
->pFobx
->UnicodeQueryTemplate
,
4312 RxContext
->QueryDirectory
.FileIndex
,
4313 RxContext
->QueryDirectory
.RestartScan
,
4314 RxContext
->QueryDirectory
.ReturnSingleEntry
,
4315 RxContext
->QueryDirectory
.IndexSpecified
,
4316 RxContext
->QueryDirectory
.InitialQuery
);
4319 NTSTATUS
map_querydir_errors(
4323 case ERROR_ACCESS_DENIED
: return STATUS_ACCESS_DENIED
;
4324 case ERROR_BUFFER_OVERFLOW
: return STATUS_BUFFER_OVERFLOW
;
4325 case ERROR_FILE_NOT_FOUND
: return STATUS_NO_SUCH_FILE
;
4326 case ERROR_NETNAME_DELETED
: return STATUS_NETWORK_NAME_DELETED
;
4327 case ERROR_INVALID_PARAMETER
: return STATUS_INVALID_PARAMETER
;
4328 case ERROR_NO_MORE_FILES
: return STATUS_NO_MORE_FILES
;
4329 case ERROR_OUTOFMEMORY
: return STATUS_INSUFFICIENT_RESOURCES
;
4330 case ERROR_FILENAME_EXCED_RANGE
: return STATUS_NAME_TOO_LONG
;
4332 print_error("failed to map windows error %d to NTSTATUS; "
4333 "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", status
);
4334 case ERROR_BAD_NET_RESP
: return STATUS_INVALID_NETWORK_RESPONSE
;
4338 NTSTATUS
check_nfs41_dirquery_args(
4339 IN PRX_CONTEXT RxContext
)
4341 if (RxContext
->Info
.Buffer
== NULL
)
4342 return STATUS_INVALID_USER_BUFFER
;
4343 return STATUS_SUCCESS
;
4347 NTSTATUS NTAPI
nfs41_QueryDirectory(
4349 NTSTATUS
nfs41_QueryDirectory(
4351 IN OUT PRX_CONTEXT RxContext
)
4353 NTSTATUS status
= STATUS_INVALID_PARAMETER
;
4354 nfs41_updowncall_entry
*entry
;
4355 FILE_INFORMATION_CLASS InfoClass
= RxContext
->Info
.FileInformationClass
;
4356 PUNICODE_STRING Filter
= &RxContext
->pFobx
->UnicodeQueryTemplate
;
4357 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
4358 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
4359 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
4360 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
4361 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
4362 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
4363 #ifdef ENABLE_TIMINGS
4364 LARGE_INTEGER t1
, t2
;
4365 t1
= KeQueryPerformanceCounter(NULL
);
4368 #ifdef DEBUG_DIR_QUERY
4370 print_querydir_args(RxContext
);
4373 status
= check_nfs41_dirquery_args(RxContext
);
4374 if (status
) goto out
;
4376 switch (InfoClass
) {
4377 /* classes handled in readdir_copy_entry() and readdir_size_for_entry() */
4378 case FileNamesInformation
:
4379 case FileDirectoryInformation
:
4380 case FileFullDirectoryInformation
:
4381 case FileIdFullDirectoryInformation
:
4382 case FileBothDirectoryInformation
:
4383 case FileIdBothDirectoryInformation
:
4386 print_error("nfs41_QueryDirectory: unhandled dir query class %d\n",
4388 status
= STATUS_NOT_SUPPORTED
;
4391 status
= nfs41_UpcallCreate(NFS41_DIR_QUERY
, &nfs41_fobx
->sec_ctx
,
4392 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
4393 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
4394 if (status
) goto out
;
4396 entry
->u
.QueryFile
.InfoClass
= InfoClass
;
4397 entry
->buf_len
= RxContext
->Info
.LengthRemaining
;
4398 entry
->buf
= RxContext
->Info
.Buffer
;
4399 entry
->u
.QueryFile
.mdl
= IoAllocateMdl(RxContext
->Info
.Buffer
,
4400 RxContext
->Info
.LengthRemaining
, FALSE
, FALSE
, NULL
);
4401 if (entry
->u
.QueryFile
.mdl
== NULL
) {
4402 status
= STATUS_INTERNAL_ERROR
;
4406 entry
->u
.QueryFile
.mdl
->MdlFlags
|= MDL_MAPPING_CAN_FAIL
;
4407 MmProbeAndLockPages(entry
->u
.QueryFile
.mdl
, KernelMode
, IoModifyAccess
);
4409 entry
->u
.QueryFile
.filter
= Filter
;
4410 entry
->u
.QueryFile
.initial_query
= RxContext
->QueryDirectory
.InitialQuery
;
4411 entry
->u
.QueryFile
.restart_scan
= RxContext
->QueryDirectory
.RestartScan
;
4412 entry
->u
.QueryFile
.return_single
= RxContext
->QueryDirectory
.ReturnSingleEntry
;
4414 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
4415 if (status
) goto out
;
4416 MmUnlockPages(entry
->u
.QueryFile
.mdl
);
4418 if (entry
->status
== STATUS_BUFFER_TOO_SMALL
) {
4419 DbgP("nfs41_QueryDirectory: buffer too small provided %d need %lu\n",
4420 RxContext
->Info
.LengthRemaining
, entry
->buf_len
);
4421 RxContext
->InformationToReturn
= entry
->buf_len
;
4422 status
= STATUS_BUFFER_TOO_SMALL
;
4423 } else if (entry
->status
== STATUS_SUCCESS
) {
4424 #ifdef ENABLE_TIMINGS
4425 InterlockedIncrement(&readdir
.sops
);
4426 InterlockedAdd64(&readdir
.size
, entry
->u
.QueryFile
.buf_len
);
4428 RxContext
->Info
.LengthRemaining
-= entry
->buf_len
;
4429 status
= STATUS_SUCCESS
;
4431 /* map windows ERRORs to NTSTATUS */
4432 status
= map_querydir_errors(entry
->status
);
4434 IoFreeMdl(entry
->u
.QueryFile
.mdl
);
4437 #ifdef ENABLE_TIMINGS
4438 t2
= KeQueryPerformanceCounter(NULL
);
4439 InterlockedIncrement(&readdir
.tops
);
4440 InterlockedAdd64(&readdir
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
4441 #ifdef ENABLE_INDV_TIMINGS
4442 DbgP("nfs41_QueryDirectory delta = %d ops=%d sum=%d\n",
4443 t2
.QuadPart
- t1
.QuadPart
, readdir
.tops
, readdir
.ticks
);
4446 #ifdef DEBUG_DIR_QUERY
4452 void print_queryvolume_args(
4453 PRX_CONTEXT RxContext
)
4455 print_debug_header(RxContext
);
4456 DbgP("FileName='%wZ', InfoClass = %s BufferLen = %d\n",
4457 GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext
),
4458 print_fs_information_class(RxContext
->Info
.FileInformationClass
),
4459 RxContext
->Info
.LengthRemaining
);
4462 NTSTATUS
map_volume_errors(
4466 case ERROR_ACCESS_DENIED
: return STATUS_ACCESS_DENIED
;
4467 case ERROR_VC_DISCONNECTED
: return STATUS_CONNECTION_DISCONNECTED
;
4468 case ERROR_NETNAME_DELETED
: return STATUS_NETWORK_NAME_DELETED
;
4469 case ERROR_INVALID_PARAMETER
: return STATUS_INVALID_PARAMETER
;
4470 case ERROR_OUTOFMEMORY
: return STATUS_INSUFFICIENT_RESOURCES
;
4472 print_error("failed to map windows error %d to NTSTATUS; "
4473 "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", status
);
4474 case ERROR_BAD_NET_RESP
: return STATUS_INVALID_NETWORK_RESPONSE
;
4478 void nfs41_create_volume_info(PFILE_FS_VOLUME_INFORMATION pVolInfo
, DWORD
*len
)
4480 DECLARE_CONST_UNICODE_STRING(VolName
, VOL_NAME
);
4482 RtlZeroMemory(pVolInfo
, sizeof(FILE_FS_VOLUME_INFORMATION
));
4483 pVolInfo
->VolumeSerialNumber
= 0xBABAFACE;
4484 pVolInfo
->VolumeLabelLength
= VolName
.Length
;
4485 RtlCopyMemory(&pVolInfo
->VolumeLabel
[0], (PVOID
)VolName
.Buffer
,
4486 VolName
.MaximumLength
);
4487 *len
= sizeof(FILE_FS_VOLUME_INFORMATION
) + VolName
.Length
;
4490 static BOOLEAN
is_root_directory(
4491 PRX_CONTEXT RxContext
)
4493 __notnull PV_NET_ROOT VNetRoot
= (PV_NET_ROOT
)
4494 RxContext
->pRelevantSrvOpen
->pVNetRoot
;
4495 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
4496 NFS41GetVNetRootExtension(RxContext
->pRelevantSrvOpen
->pVNetRoot
);
4498 /* calculate the root directory's length, including vnetroot prefix,
4499 * mount path, and a trailing \ */
4500 const USHORT RootPathLen
= VNetRoot
->PrefixEntry
.Prefix
.Length
+
4501 pVNetRootContext
->MountPathLen
+ sizeof(WCHAR
);
4503 return RxContext
->CurrentIrpSp
->FileObject
->FileName
.Length
<= RootPathLen
;
4507 NTSTATUS NTAPI
nfs41_QueryVolumeInformation(
4509 NTSTATUS
nfs41_QueryVolumeInformation(
4511 IN OUT PRX_CONTEXT RxContext
)
4513 NTSTATUS status
= STATUS_INVALID_PARAMETER
;
4514 nfs41_updowncall_entry
*entry
;
4515 ULONG RemainingLength
= RxContext
->Info
.LengthRemaining
, SizeUsed
;
4516 FS_INFORMATION_CLASS InfoClass
= RxContext
->Info
.FsInformationClass
;
4517 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
4518 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
4519 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
4520 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
4521 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
4522 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
4523 NFS41GetDeviceExtension(RxContext
, DevExt
);
4525 #ifdef ENABLE_TIMINGS
4526 LARGE_INTEGER t1
, t2
;
4527 t1
= KeQueryPerformanceCounter(NULL
);
4530 #ifdef DEBUG_VOLUME_QUERY
4532 print_queryvolume_args(RxContext
);
4535 status
= check_nfs41_dirquery_args(RxContext
);
4536 if (status
) goto out
;
4538 switch (InfoClass
) {
4539 case FileFsVolumeInformation
:
4540 if ((ULONG
)RxContext
->Info
.LengthRemaining
>= DevExt
->VolAttrsLen
) {
4541 RtlCopyMemory(RxContext
->Info
.Buffer
, DevExt
->VolAttrs
,
4542 DevExt
->VolAttrsLen
);
4543 RxContext
->Info
.LengthRemaining
-= DevExt
->VolAttrsLen
;
4544 status
= STATUS_SUCCESS
;
4546 RtlCopyMemory(RxContext
->Info
.Buffer
, DevExt
->VolAttrs
,
4547 RxContext
->Info
.LengthRemaining
);
4548 status
= STATUS_BUFFER_OVERFLOW
;
4551 case FileFsDeviceInformation
:
4553 PFILE_FS_DEVICE_INFORMATION pDevInfo
= RxContext
->Info
.Buffer
;
4555 SizeUsed
= sizeof(FILE_FS_DEVICE_INFORMATION
);
4556 if (RemainingLength
< SizeUsed
) {
4557 status
= STATUS_BUFFER_TOO_SMALL
;
4558 RxContext
->InformationToReturn
= SizeUsed
;
4561 pDevInfo
->DeviceType
= RxContext
->pFcb
->pNetRoot
->DeviceType
;
4562 pDevInfo
->Characteristics
= FILE_REMOTE_DEVICE
| FILE_DEVICE_IS_MOUNTED
;
4563 RxContext
->Info
.LengthRemaining
-= SizeUsed
;
4564 status
= STATUS_SUCCESS
;
4567 case FileAccessInformation
:
4568 status
= STATUS_NOT_SUPPORTED
;
4571 case FileFsAttributeInformation
:
4572 if (RxContext
->Info
.LengthRemaining
< FS_ATTR_LEN
) {
4573 RxContext
->InformationToReturn
= FS_ATTR_LEN
;
4574 status
= STATUS_BUFFER_TOO_SMALL
;
4578 /* on attribute queries for the root directory,
4579 * use cached volume attributes from mount */
4580 if (is_root_directory(RxContext
)) {
4581 PFILE_FS_ATTRIBUTE_INFORMATION attrs
=
4582 (PFILE_FS_ATTRIBUTE_INFORMATION
)RxContext
->Info
.Buffer
;
4583 DECLARE_CONST_UNICODE_STRING(FsName
, FS_NAME
);
4585 RtlCopyMemory(attrs
, &pVNetRootContext
->FsAttrs
,
4586 sizeof(pVNetRootContext
->FsAttrs
));
4588 /* fill in the FileSystemName */
4589 RtlCopyMemory(attrs
->FileSystemName
, FsName
.Buffer
,
4590 FsName
.MaximumLength
); /* 'MaximumLength' to include null */
4591 attrs
->FileSystemNameLength
= FsName
.Length
;
4593 RxContext
->Info
.LengthRemaining
-= FS_ATTR_LEN
;
4596 /* else fall through and send the upcall */
4597 case FileFsSizeInformation
:
4598 case FileFsFullSizeInformation
:
4602 print_error("nfs41_QueryVolumeInformation: unhandled class %d\n", InfoClass
);
4603 status
= STATUS_NOT_SUPPORTED
;
4606 status
= nfs41_UpcallCreate(NFS41_VOLUME_QUERY
, &nfs41_fobx
->sec_ctx
,
4607 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
4608 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
4609 if (status
) goto out
;
4611 entry
->u
.Volume
.query
= InfoClass
;
4612 entry
->buf
= RxContext
->Info
.Buffer
;
4613 entry
->buf_len
= RxContext
->Info
.LengthRemaining
;
4615 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
4616 if (status
) goto out
;
4618 if (entry
->status
== STATUS_BUFFER_TOO_SMALL
) {
4619 RxContext
->InformationToReturn
= entry
->buf_len
;
4620 status
= STATUS_BUFFER_TOO_SMALL
;
4621 } else if (entry
->status
== STATUS_SUCCESS
) {
4622 if (InfoClass
== FileFsAttributeInformation
) {
4623 /* fill in the FileSystemName */
4624 PFILE_FS_ATTRIBUTE_INFORMATION attrs
=
4625 (PFILE_FS_ATTRIBUTE_INFORMATION
)RxContext
->Info
.Buffer
;
4626 DECLARE_CONST_UNICODE_STRING(FsName
, FS_NAME
);
4628 RtlCopyMemory(attrs
->FileSystemName
, FsName
.Buffer
,
4629 FsName
.MaximumLength
); /* 'MaximumLength' to include null */
4630 attrs
->FileSystemNameLength
= FsName
.Length
;
4632 entry
->buf_len
= FS_ATTR_LEN
;
4634 #ifdef ENABLE_TIMINGS
4635 InterlockedIncrement(&volume
.sops
);
4636 InterlockedAdd64(&volume
.size
, entry
->u
.Volume
.buf_len
);
4638 RxContext
->Info
.LengthRemaining
-= entry
->buf_len
;
4639 status
= STATUS_SUCCESS
;
4641 status
= map_volume_errors(entry
->status
);
4645 #ifdef ENABLE_TIMINGS
4646 t2
= KeQueryPerformanceCounter(NULL
);
4647 InterlockedIncrement(&volume
.tops
);
4648 InterlockedAdd64(&volume
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
4649 #ifdef ENABLE_INDV_TIMINGS
4650 DbgP("nfs41_QueryVolumeInformation delta = %d op=%d sum=%d\n",
4651 t2
.QuadPart
- t1
.QuadPart
, volume
.tops
, volume
.ticks
);
4654 #ifdef DEBUG_VOLUME_QUERY
4660 VOID
nfs41_update_fcb_list(
4662 ULONGLONG ChangeTime
)
4665 nfs41_fcb_list_entry
*cur
;
4666 ExAcquireFastMutex(&fcblistLock
);
4667 pEntry
= openlist
.head
.Flink
;
4668 while (!IsListEmpty(&openlist
.head
)) {
4669 cur
= (nfs41_fcb_list_entry
*)CONTAINING_RECORD(pEntry
,
4670 nfs41_fcb_list_entry
, next
);
4671 if (cur
->fcb
== fcb
&&
4672 cur
->ChangeTime
!= ChangeTime
) {
4673 #if defined(DEBUG_FILE_SET) || defined(DEBUG_ACL_SET) || \
4674 defined(DEBUG_WRITE) || defined(DEBUG_EA_SET)
4675 DbgP("nfs41_update_fcb_list: Found match for fcb %p: updating "
4676 "%llu to %llu\n", fcb
, cur
->ChangeTime
, ChangeTime
);
4678 cur
->ChangeTime
= ChangeTime
;
4681 /* place an upcall for this srv_open */
4682 if (pEntry
->Flink
== &openlist
.head
) {
4683 #if defined(DEBUG_FILE_SET) || defined(DEBUG_ACL_SET) || \
4684 defined(DEBUG_WRITE) || defined(DEBUG_EA_SET)
4685 DbgP("nfs41_update_fcb_list: reached EOL loooking for "
4690 pEntry
= pEntry
->Flink
;
4692 ExReleaseFastMutex(&fcblistLock
);
4695 void print_nfs3_attrs(
4698 DbgP("type=%d mode=%o nlink=%d size=%d atime=%x mtime=%x ctime=%x\n",
4699 attrs
->type
, attrs
->mode
, attrs
->nlink
, attrs
->size
, attrs
->atime
,
4700 attrs
->mtime
, attrs
->ctime
);
4703 void file_time_to_nfs_time(
4704 IN
const PLARGE_INTEGER file_time
,
4705 OUT LONGLONG
*nfs_time
)
4707 LARGE_INTEGER diff
= unix_time_diff
;
4708 diff
.QuadPart
= file_time
->QuadPart
- diff
.QuadPart
;
4709 *nfs_time
= diff
.QuadPart
/ 10000000;
4712 void create_nfs3_attrs(
4714 PNFS41_FCB nfs41_fcb
)
4716 RtlZeroMemory(attrs
, sizeof(nfs3_attrs
));
4717 if (nfs41_fcb
->BasicInfo
.FileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
)
4718 attrs
->type
= NF3LNK
;
4719 else if (nfs41_fcb
->StandardInfo
.Directory
)
4720 attrs
->type
= NF3DIR
;
4722 attrs
->type
= NF3REG
;
4723 attrs
->mode
= nfs41_fcb
->mode
;
4724 attrs
->nlink
= nfs41_fcb
->StandardInfo
.NumberOfLinks
;
4725 attrs
->size
.QuadPart
= attrs
->used
.QuadPart
=
4726 nfs41_fcb
->StandardInfo
.EndOfFile
.QuadPart
;
4727 file_time_to_nfs_time(&nfs41_fcb
->BasicInfo
.LastAccessTime
, &attrs
->atime
);
4728 file_time_to_nfs_time(&nfs41_fcb
->BasicInfo
.ChangeTime
, &attrs
->mtime
);
4729 file_time_to_nfs_time(&nfs41_fcb
->BasicInfo
.CreationTime
, &attrs
->ctime
);
4733 NTSTATUS
map_setea_error(
4737 case NO_ERROR
: return STATUS_SUCCESS
;
4738 case ERROR_FILE_NOT_FOUND
: return STATUS_NO_EAS_ON_FILE
;
4739 case ERROR_ACCESS_DENIED
: return STATUS_ACCESS_DENIED
;
4740 case ERROR_NETWORK_ACCESS_DENIED
: return STATUS_NETWORK_ACCESS_DENIED
;
4741 case ERROR_NETNAME_DELETED
: return STATUS_NETWORK_NAME_DELETED
;
4742 case ERROR_FILE_TOO_LARGE
: return STATUS_EA_TOO_LARGE
;
4743 case ERROR_BUFFER_OVERFLOW
: return STATUS_BUFFER_OVERFLOW
;
4744 case STATUS_BUFFER_TOO_SMALL
:
4745 case ERROR_INSUFFICIENT_BUFFER
: return STATUS_BUFFER_TOO_SMALL
;
4746 case ERROR_INVALID_EA_HANDLE
: return STATUS_NONEXISTENT_EA_ENTRY
;
4747 case ERROR_NO_MORE_FILES
: return STATUS_NO_MORE_EAS
;
4748 case ERROR_EA_FILE_CORRUPT
: return STATUS_EA_CORRUPT_ERROR
;
4750 print_error("failed to map windows error %d to NTSTATUS; "
4751 "defaulting to STATUS_INVALID_PARAMETER\n", error
);
4752 case ERROR_INVALID_PARAMETER
: return STATUS_INVALID_PARAMETER
;
4756 NTSTATUS
check_nfs41_setea_args(
4757 IN PRX_CONTEXT RxContext
)
4760 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
4761 NFS41GetVNetRootExtension(RxContext
->pRelevantSrvOpen
->pVNetRoot
);
4762 __notnull PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs
=
4763 &pVNetRootContext
->FsAttrs
;
4764 __notnull PFILE_FULL_EA_INFORMATION ea
=
4765 (PFILE_FULL_EA_INFORMATION
)RxContext
->Info
.Buffer
;
4767 status
= check_nfs41_dirquery_args(RxContext
);
4768 if (status
) goto out
;
4771 status
= STATUS_INVALID_PARAMETER
;
4774 if (AnsiStrEq(&NfsActOnLink
, ea
->EaName
, ea
->EaNameLength
) ||
4775 AnsiStrEq(&NfsSymlinkTargetName
, ea
->EaName
, ea
->EaNameLength
)) {
4776 status
= STATUS_INVALID_PARAMETER
; /* only allowed on create */
4779 /* ignore cygwin EAs when checking support */
4780 if (!(FsAttrs
->FileSystemAttributes
& FILE_SUPPORTS_EXTENDED_ATTRIBUTES
)
4781 && !AnsiStrEq(&NfsV3Attributes
, ea
->EaName
, ea
->EaNameLength
)) {
4782 status
= STATUS_EAS_NOT_SUPPORTED
;
4785 if ((RxContext
->pRelevantSrvOpen
->DesiredAccess
& FILE_WRITE_EA
) == 0) {
4786 status
= STATUS_ACCESS_DENIED
;
4789 if (pVNetRootContext
->read_only
) {
4790 print_error("check_nfs41_setattr_args: Read-only mount\n");
4791 status
= STATUS_ACCESS_DENIED
;
4799 NTSTATUS NTAPI
nfs41_SetEaInformation(
4801 NTSTATUS
nfs41_SetEaInformation(
4803 IN OUT PRX_CONTEXT RxContext
)
4805 NTSTATUS status
= STATUS_EAS_NOT_SUPPORTED
;
4806 nfs41_updowncall_entry
*entry
;
4807 __notnull PFILE_FULL_EA_INFORMATION eainfo
=
4808 (PFILE_FULL_EA_INFORMATION
)RxContext
->Info
.Buffer
;
4809 nfs3_attrs
*attrs
= NULL
;
4810 ULONG buflen
= RxContext
->CurrentIrpSp
->Parameters
.SetEa
.Length
, error_offset
;
4811 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
4812 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
4813 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
4814 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
4815 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
4816 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
4817 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
4818 #ifdef ENABLE_TIMINGS
4819 LARGE_INTEGER t1
, t2
;
4820 t1
= KeQueryPerformanceCounter(NULL
);
4825 print_debug_header(RxContext
);
4826 print_ea_info(1, eainfo
);
4829 status
= check_nfs41_setea_args(RxContext
);
4830 if (status
) goto out
;
4832 status
= nfs41_UpcallCreate(NFS41_EA_SET
, &nfs41_fobx
->sec_ctx
,
4833 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
4834 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
4835 if (status
) goto out
;
4837 if (AnsiStrEq(&NfsV3Attributes
, eainfo
->EaName
, eainfo
->EaNameLength
)) {
4838 attrs
= (nfs3_attrs
*)(eainfo
->EaName
+ eainfo
->EaNameLength
+ 1);
4840 print_nfs3_attrs(attrs
);
4841 DbgP("old mode is %o new mode is %o\n", nfs41_fcb
->mode
, attrs
->mode
);
4843 entry
->u
.SetEa
.mode
= attrs
->mode
;
4845 entry
->u
.SetEa
.mode
= 0;
4846 status
= IoCheckEaBufferValidity(eainfo
, buflen
, &error_offset
);
4852 entry
->buf
= eainfo
;
4853 entry
->buf_len
= buflen
;
4855 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
4856 if (status
) goto out
;
4857 #ifdef ENABLE_TIMINGS
4858 if (entry
->status
== STATUS_SUCCESS
) {
4859 InterlockedIncrement(&setexattr
.sops
);
4860 InterlockedAdd64(&setexattr
.size
, entry
->u
.SetEa
.buf_len
);
4863 status
= map_setea_error(entry
->status
);
4865 if (!nfs41_fobx
->deleg_type
&& entry
->ChangeTime
&&
4866 (SrvOpen
->DesiredAccess
&
4867 (FILE_READ_DATA
| FILE_WRITE_DATA
| FILE_APPEND_DATA
)))
4868 nfs41_update_fcb_list(RxContext
->pFcb
, entry
->ChangeTime
);
4869 nfs41_fcb
->changeattr
= entry
->ChangeTime
;
4870 nfs41_fcb
->mode
= entry
->u
.SetEa
.mode
;
4874 #ifdef ENABLE_TIMINGS
4875 t2
= KeQueryPerformanceCounter(NULL
);
4876 InterlockedIncrement(&setexattr
.tops
);
4877 InterlockedAdd64(&setexattr
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
4878 #ifdef ENABLE_INDV_TIMINGS
4879 DbgP("nfs41_SetEaInformation delta = %d op=%d sum=%d\n",
4880 t2
.QuadPart
- t1
.QuadPart
, setexattr
.tops
, setexattr
.ticks
);
4889 NTSTATUS
check_nfs41_queryea_args(
4890 IN PRX_CONTEXT RxContext
)
4893 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
4894 NFS41GetVNetRootExtension(RxContext
->pRelevantSrvOpen
->pVNetRoot
);
4895 __notnull PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs
=
4896 &pVNetRootContext
->FsAttrs
;
4897 PFILE_GET_EA_INFORMATION ea
= (PFILE_GET_EA_INFORMATION
)
4898 RxContext
->CurrentIrpSp
->Parameters
.QueryEa
.EaList
;
4900 status
= check_nfs41_dirquery_args(RxContext
);
4901 if (status
) goto out
;
4903 if (!(FsAttrs
->FileSystemAttributes
& FILE_SUPPORTS_EXTENDED_ATTRIBUTES
)) {
4905 status
= STATUS_EAS_NOT_SUPPORTED
;
4908 /* ignore cygwin EAs when checking support */
4909 if (!AnsiStrEq(&NfsV3Attributes
, ea
->EaName
, ea
->EaNameLength
) &&
4910 !AnsiStrEq(&NfsActOnLink
, ea
->EaName
, ea
->EaNameLength
) &&
4911 !AnsiStrEq(&NfsSymlinkTargetName
, ea
->EaName
, ea
->EaNameLength
)) {
4912 status
= STATUS_EAS_NOT_SUPPORTED
;
4916 if ((RxContext
->pRelevantSrvOpen
->DesiredAccess
& FILE_READ_EA
) == 0) {
4917 status
= STATUS_ACCESS_DENIED
;
4924 static NTSTATUS
QueryCygwinSymlink(
4925 IN OUT PRX_CONTEXT RxContext
,
4926 IN PFILE_GET_EA_INFORMATION query
,
4927 OUT PFILE_FULL_EA_INFORMATION info
)
4929 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
4930 __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext
=
4931 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
4932 __notnull PNFS41_NETROOT_EXTENSION NetRootContext
=
4933 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
4934 __notnull PNFS41_FOBX Fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
4935 nfs41_updowncall_entry
*entry
;
4936 UNICODE_STRING TargetName
;
4937 const USHORT HeaderLen
= FIELD_OFFSET(FILE_FULL_EA_INFORMATION
, EaName
) +
4938 query
->EaNameLength
+ 1;
4941 if (RxContext
->Info
.LengthRemaining
< HeaderLen
) {
4942 status
= STATUS_BUFFER_TOO_SMALL
;
4943 RxContext
->InformationToReturn
= HeaderLen
;
4947 TargetName
.Buffer
= (PWCH
)(info
->EaName
+ query
->EaNameLength
+ 1);
4948 TargetName
.MaximumLength
= (USHORT
)min(RxContext
->Info
.LengthRemaining
-
4951 status
= nfs41_UpcallCreate(NFS41_SYMLINK
, &Fobx
->sec_ctx
,
4952 VNetRootContext
->session
, Fobx
->nfs41_open_state
,
4953 NetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
4954 if (status
) goto out
;
4956 entry
->u
.Symlink
.target
= &TargetName
;
4957 entry
->u
.Symlink
.set
= FALSE
;
4959 status
= nfs41_UpcallWaitForReply(entry
, VNetRootContext
->timeout
);
4960 if (status
) goto out
;
4962 status
= map_setea_error(entry
->status
);
4963 if (status
== STATUS_SUCCESS
) {
4964 info
->NextEntryOffset
= 0;
4966 info
->EaNameLength
= query
->EaNameLength
;
4967 info
->EaValueLength
= TargetName
.Length
- sizeof(UNICODE_NULL
);
4968 TargetName
.Buffer
[TargetName
.Length
/sizeof(WCHAR
)] = UNICODE_NULL
;
4969 RtlCopyMemory(info
->EaName
, query
->EaName
, query
->EaNameLength
);
4970 RxContext
->Info
.LengthRemaining
= HeaderLen
+ info
->EaValueLength
;
4971 } else if (status
== STATUS_BUFFER_TOO_SMALL
) {
4972 RxContext
->InformationToReturn
= HeaderLen
+
4973 entry
->u
.Symlink
.target
->Length
;
4980 static NTSTATUS
QueryCygwinEA(
4981 IN OUT PRX_CONTEXT RxContext
,
4982 IN PFILE_GET_EA_INFORMATION query
,
4983 OUT PFILE_FULL_EA_INFORMATION info
)
4985 NTSTATUS status
= STATUS_NONEXISTENT_EA_ENTRY
;
4990 if (AnsiStrEq(&NfsSymlinkTargetName
, query
->EaName
, query
->EaNameLength
)) {
4991 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
4992 if (nfs41_fcb
->BasicInfo
.FileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) {
4993 status
= QueryCygwinSymlink(RxContext
, query
, info
);
4996 const LONG LengthRequired
= sizeof(FILE_FULL_EA_INFORMATION
) +
4997 NfsSymlinkTargetName
.Length
- sizeof(CHAR
);
4998 if (LengthRequired
> RxContext
->Info
.LengthRemaining
) {
4999 status
= STATUS_BUFFER_TOO_SMALL
;
5000 RxContext
->InformationToReturn
= LengthRequired
;
5003 info
->NextEntryOffset
= 0;
5005 info
->EaValueLength
= 0;
5006 info
->EaNameLength
= (UCHAR
)NfsActOnLink
.Length
;
5007 RtlCopyMemory(info
->EaName
, NfsSymlinkTargetName
.Buffer
,
5008 NfsSymlinkTargetName
.Length
);
5009 RxContext
->Info
.LengthRemaining
= LengthRequired
;
5010 status
= STATUS_SUCCESS
;
5015 if (AnsiStrEq(&NfsV3Attributes
, query
->EaName
, query
->EaNameLength
)) {
5018 const LONG LengthRequired
= sizeof(FILE_FULL_EA_INFORMATION
) +
5019 NfsV3Attributes
.Length
+ sizeof(nfs3_attrs
) - sizeof(CHAR
);
5020 if (LengthRequired
> RxContext
->Info
.LengthRemaining
) {
5021 status
= STATUS_BUFFER_TOO_SMALL
;
5022 RxContext
->InformationToReturn
= LengthRequired
;
5026 create_nfs3_attrs(&attrs
, NFS41GetFcbExtension(RxContext
->pFcb
));
5027 #ifdef DEBUG_EA_QUERY
5028 print_nfs3_attrs(&attrs
);
5031 info
->NextEntryOffset
= 0;
5033 info
->EaNameLength
= (UCHAR
)NfsV3Attributes
.Length
;
5034 info
->EaValueLength
= sizeof(nfs3_attrs
);
5035 RtlCopyMemory(info
->EaName
, NfsV3Attributes
.Buffer
,
5036 NfsV3Attributes
.Length
);
5037 RtlCopyMemory(info
->EaName
+ info
->EaNameLength
+ 1, &attrs
,
5038 sizeof(nfs3_attrs
));
5039 RxContext
->Info
.LengthRemaining
= LengthRequired
;
5040 status
= STATUS_SUCCESS
;
5044 if (AnsiStrEq(&NfsActOnLink
, query
->EaName
, query
->EaNameLength
)) {
5046 const LONG LengthRequired
= sizeof(FILE_FULL_EA_INFORMATION
) +
5047 query
->EaNameLength
- sizeof(CHAR
);
5048 if (LengthRequired
> RxContext
->Info
.LengthRemaining
) {
5049 status
= STATUS_BUFFER_TOO_SMALL
;
5050 RxContext
->InformationToReturn
= LengthRequired
;
5054 info
->NextEntryOffset
= 0;
5056 info
->EaNameLength
= query
->EaNameLength
;
5057 info
->EaValueLength
= 0;
5058 RtlCopyMemory(info
->EaName
, query
->EaName
, query
->EaNameLength
);
5059 RxContext
->Info
.LengthRemaining
= LengthRequired
;
5060 status
= STATUS_SUCCESS
;
5068 NTSTATUS NTAPI
nfs41_QueryEaInformation(
5070 NTSTATUS
nfs41_QueryEaInformation(
5072 IN OUT PRX_CONTEXT RxContext
)
5074 NTSTATUS status
= STATUS_EAS_NOT_SUPPORTED
;
5075 nfs41_updowncall_entry
*entry
;
5076 PFILE_GET_EA_INFORMATION query
= (PFILE_GET_EA_INFORMATION
)
5077 RxContext
->CurrentIrpSp
->Parameters
.QueryEa
.EaList
;
5078 ULONG buflen
= RxContext
->CurrentIrpSp
->Parameters
.QueryEa
.Length
;
5079 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
5080 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
5081 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
5082 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
5083 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
5084 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
5085 #ifdef ENABLE_TIMINGS
5086 LARGE_INTEGER t1
, t2
;
5087 t1
= KeQueryPerformanceCounter(NULL
);
5090 #ifdef DEBUG_EA_QUERY
5092 print_debug_header(RxContext
);
5093 print_get_ea(1, query
);
5095 status
= check_nfs41_queryea_args(RxContext
);
5096 if (status
) goto out
;
5098 /* handle queries for cygwin EAs */
5099 status
= QueryCygwinEA(RxContext
, query
,
5100 (PFILE_FULL_EA_INFORMATION
)RxContext
->Info
.Buffer
);
5101 if (status
!= STATUS_NONEXISTENT_EA_ENTRY
)
5104 status
= nfs41_UpcallCreate(NFS41_EA_GET
, &nfs41_fobx
->sec_ctx
,
5105 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
5106 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
5107 if (status
) goto out
;
5109 entry
->buf_len
= buflen
;
5110 entry
->buf
= RxContext
->Info
.Buffer
;
5111 entry
->u
.QueryEa
.EaList
= query
;
5112 entry
->u
.QueryEa
.EaListLength
= query
== NULL
? 0 :
5113 RxContext
->QueryEa
.UserEaListLength
;
5114 entry
->u
.QueryEa
.EaIndex
= RxContext
->QueryEa
.IndexSpecified
?
5115 RxContext
->QueryEa
.UserEaIndex
: 0;
5116 entry
->u
.QueryEa
.RestartScan
= RxContext
->QueryEa
.RestartScan
;
5117 entry
->u
.QueryEa
.ReturnSingleEntry
= RxContext
->QueryEa
.ReturnSingleEntry
;
5119 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
5120 if (status
) goto out
;
5122 if (entry
->status
== STATUS_SUCCESS
) {
5123 switch (entry
->u
.QueryEa
.Overflow
) {
5124 case ERROR_INSUFFICIENT_BUFFER
:
5125 status
= STATUS_BUFFER_TOO_SMALL
;
5127 case ERROR_BUFFER_OVERFLOW
:
5128 status
= RxContext
->IoStatusBlock
.Status
= STATUS_BUFFER_OVERFLOW
;
5131 RxContext
->IoStatusBlock
.Status
= STATUS_SUCCESS
;
5134 RxContext
->InformationToReturn
= entry
->buf_len
;
5135 #ifdef ENABLE_TIMINGS
5136 InterlockedIncrement(&getexattr
.sops
);
5137 InterlockedAdd64(&getexattr
.size
, entry
->u
.QueryEa
.buf_len
);
5140 status
= map_setea_error(entry
->status
);
5144 #ifdef ENABLE_TIMINGS
5145 t2
= KeQueryPerformanceCounter(NULL
);
5146 InterlockedIncrement(&getexattr
.tops
);
5147 InterlockedAdd64(&getexattr
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
5148 #ifdef ENABLE_INDV_TIMINGS
5149 DbgP("nfs41_QueryEaInformation delta = %d op=%d sum=%d\n",
5150 t2
.QuadPart
- t1
.QuadPart
, getexattr
.tops
, getexattr
.ticks
);
5153 #ifdef DEBUG_EA_QUERY
5159 NTSTATUS
map_query_acl_error(
5163 case NO_ERROR
: return STATUS_SUCCESS
;
5164 case ERROR_NOT_SUPPORTED
: return STATUS_NOT_SUPPORTED
;
5165 case ERROR_ACCESS_DENIED
: return STATUS_ACCESS_DENIED
;
5166 case ERROR_FILE_NOT_FOUND
: return STATUS_OBJECT_NAME_NOT_FOUND
;
5167 case ERROR_INVALID_PARAMETER
: return STATUS_INVALID_PARAMETER
;
5169 print_error("failed to map windows error %d to NTSTATUS; "
5170 "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", error
);
5171 case ERROR_BAD_NET_RESP
: return STATUS_INVALID_NETWORK_RESPONSE
;
5175 NTSTATUS
check_nfs41_getacl_args(
5176 PRX_CONTEXT RxContext
)
5178 NTSTATUS status
= STATUS_SUCCESS
;
5179 SECURITY_INFORMATION info_class
=
5180 RxContext
->CurrentIrpSp
->Parameters
.QuerySecurity
.SecurityInformation
;
5182 /* we don't support sacls */
5183 if (info_class
== SACL_SECURITY_INFORMATION
||
5184 info_class
== LABEL_SECURITY_INFORMATION
) {
5185 status
= STATUS_NOT_SUPPORTED
;
5188 if (RxContext
->CurrentIrp
->UserBuffer
== NULL
&&
5189 RxContext
->CurrentIrpSp
->Parameters
.QuerySecurity
.Length
)
5190 status
= STATUS_INVALID_USER_BUFFER
;
5196 NTSTATUS NTAPI
nfs41_QuerySecurityInformation(
5198 NTSTATUS
nfs41_QuerySecurityInformation(
5200 IN OUT PRX_CONTEXT RxContext
)
5202 NTSTATUS status
= STATUS_NOT_SUPPORTED
;
5203 nfs41_updowncall_entry
*entry
;
5204 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
5205 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
5206 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
5207 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
5208 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
5209 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
5210 SECURITY_INFORMATION info_class
=
5211 RxContext
->CurrentIrpSp
->Parameters
.QuerySecurity
.SecurityInformation
;
5212 #ifdef ENABLE_TIMINGS
5213 LARGE_INTEGER t1
, t2
;
5214 t1
= KeQueryPerformanceCounter(NULL
);
5217 #ifdef DEBUG_ACL_QUERY
5219 print_debug_header(RxContext
);
5220 print_acl_args(info_class
);
5223 status
= check_nfs41_getacl_args(RxContext
);
5224 if (status
) goto out
;
5226 if (nfs41_fobx
->acl
&& nfs41_fobx
->acl_len
) {
5227 LARGE_INTEGER current_time
;
5228 KeQuerySystemTime(¤t_time
);
5229 #ifdef DEBUG_ACL_QUERY
5230 DbgP("CurrentTime %lx Saved Acl time %lx\n",
5231 current_time
.QuadPart
, nfs41_fobx
->time
.QuadPart
);
5233 if (current_time
.QuadPart
- nfs41_fobx
->time
.QuadPart
<= 20*1000) {
5234 PSECURITY_DESCRIPTOR sec_desc
= (PSECURITY_DESCRIPTOR
)
5235 RxContext
->CurrentIrp
->UserBuffer
;
5236 RtlCopyMemory(sec_desc
, nfs41_fobx
->acl
, nfs41_fobx
->acl_len
);
5237 RxContext
->IoStatusBlock
.Information
=
5238 RxContext
->InformationToReturn
= nfs41_fobx
->acl_len
;
5239 RxContext
->IoStatusBlock
.Status
= status
= STATUS_SUCCESS
;
5240 #ifdef ENABLE_TIMINGS
5241 InterlockedIncrement(&getacl
.sops
);
5242 InterlockedAdd64(&getacl
.size
, nfs41_fobx
->acl_len
);
5245 RxFreePool(nfs41_fobx
->acl
);
5246 nfs41_fobx
->acl
= NULL
;
5247 nfs41_fobx
->acl_len
= 0;
5252 status
= nfs41_UpcallCreate(NFS41_ACL_QUERY
, &nfs41_fobx
->sec_ctx
,
5253 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
5254 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
5255 if (status
) goto out
;
5257 entry
->u
.Acl
.query
= info_class
;
5258 /* we can't provide RxContext->CurrentIrp->UserBuffer to the upcall thread
5259 * because it becomes an invalid pointer with that execution context
5261 entry
->buf_len
= RxContext
->CurrentIrpSp
->Parameters
.QuerySecurity
.Length
;
5263 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
5264 if (status
) goto out
;
5266 if (entry
->status
== STATUS_BUFFER_TOO_SMALL
) {
5267 #ifdef DEBUG_ACL_QUERY
5268 DbgP("nfs41_QuerySecurityInformation: provided buffer size=%d but we "
5270 RxContext
->CurrentIrpSp
->Parameters
.QuerySecurity
.Length
,
5273 status
= STATUS_BUFFER_OVERFLOW
;
5274 RxContext
->InformationToReturn
= entry
->buf_len
;
5276 /* Save ACL buffer */
5277 nfs41_fobx
->acl
= entry
->buf
;
5278 nfs41_fobx
->acl_len
= entry
->buf_len
;
5279 KeQuerySystemTime(&nfs41_fobx
->time
);
5280 } else if (entry
->status
== STATUS_SUCCESS
) {
5281 PSECURITY_DESCRIPTOR sec_desc
= (PSECURITY_DESCRIPTOR
)
5282 RxContext
->CurrentIrp
->UserBuffer
;
5283 RtlCopyMemory(sec_desc
, entry
->buf
, entry
->buf_len
);
5284 #ifdef ENABLE_TIMINGS
5285 InterlockedIncrement(&getacl
.sops
);
5286 InterlockedAdd64(&getacl
.size
, entry
->u
.Acl
.buf_len
);
5288 RxFreePool(entry
->buf
);
5289 nfs41_fobx
->acl
= NULL
;
5290 nfs41_fobx
->acl_len
= 0;
5291 RxContext
->IoStatusBlock
.Information
= RxContext
->InformationToReturn
=
5293 RxContext
->IoStatusBlock
.Status
= status
= STATUS_SUCCESS
;
5295 status
= map_query_acl_error(entry
->status
);
5299 #ifdef ENABLE_TIMINGS
5300 t2
= KeQueryPerformanceCounter(NULL
);
5301 /* only count getacl that we made an upcall for */
5302 if (status
== STATUS_BUFFER_OVERFLOW
) {
5303 InterlockedIncrement(&getacl
.tops
);
5304 InterlockedAdd64(&getacl
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
5306 #ifdef ENABLE_INDV_TIMINGS
5307 DbgP("nfs41_QuerySecurityInformation: delta = %d op=%d sum=%d\n",
5308 t2
.QuadPart
- t1
.QuadPart
, getacl
.tops
, getacl
.ticks
);
5311 #ifdef DEBUG_ACL_QUERY
5317 NTSTATUS
check_nfs41_setacl_args(
5318 PRX_CONTEXT RxContext
)
5320 NTSTATUS status
= STATUS_SUCCESS
;
5321 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
5322 NFS41GetVNetRootExtension(RxContext
->pRelevantSrvOpen
->pVNetRoot
);
5323 SECURITY_INFORMATION info_class
=
5324 RxContext
->CurrentIrpSp
->Parameters
.SetSecurity
.SecurityInformation
;
5326 if (pVNetRootContext
->read_only
) {
5327 print_error("check_nfs41_setacl_args: Read-only mount\n");
5328 status
= STATUS_ACCESS_DENIED
;
5331 /* we don't support sacls */
5332 if (info_class
== SACL_SECURITY_INFORMATION
||
5333 info_class
== LABEL_SECURITY_INFORMATION
) {
5334 status
= STATUS_NOT_SUPPORTED
;
5342 NTSTATUS NTAPI
nfs41_SetSecurityInformation(
5344 NTSTATUS
nfs41_SetSecurityInformation(
5346 IN OUT PRX_CONTEXT RxContext
)
5348 NTSTATUS status
= STATUS_NOT_SUPPORTED
;
5349 nfs41_updowncall_entry
*entry
;
5350 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
5351 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
5352 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
5353 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
5354 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
5355 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
5356 __notnull PSECURITY_DESCRIPTOR sec_desc
=
5357 RxContext
->CurrentIrpSp
->Parameters
.SetSecurity
.SecurityDescriptor
;
5358 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
5359 SECURITY_INFORMATION info_class
=
5360 RxContext
->CurrentIrpSp
->Parameters
.SetSecurity
.SecurityInformation
;
5361 #ifdef ENABLE_TIMINGS
5362 LARGE_INTEGER t1
, t2
;
5363 t1
= KeQueryPerformanceCounter(NULL
);
5366 #ifdef DEBUG_ACL_SET
5368 print_debug_header(RxContext
);
5369 print_acl_args(info_class
);
5372 status
= check_nfs41_setacl_args(RxContext
);
5373 if (status
) goto out
;
5375 /* check that ACL is present */
5376 if (info_class
& DACL_SECURITY_INFORMATION
) {
5378 BOOLEAN present
, dacl_default
;
5379 status
= RtlGetDaclSecurityDescriptor(sec_desc
, &present
, &acl
,
5382 DbgP("RtlGetDaclSecurityDescriptor failed %x\n", status
);
5385 if (present
== FALSE
) {
5386 DbgP("NO ACL present\n");
5391 status
= nfs41_UpcallCreate(NFS41_ACL_SET
, &nfs41_fobx
->sec_ctx
,
5392 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
5393 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
5394 if (status
) goto out
;
5396 entry
->u
.Acl
.query
= info_class
;
5397 entry
->buf
= sec_desc
;
5398 entry
->buf_len
= RtlLengthSecurityDescriptor(sec_desc
);
5399 #ifdef ENABLE_TIMINGS
5400 InterlockedIncrement(&setacl
.sops
);
5401 InterlockedAdd64(&setacl
.size
, entry
->u
.Acl
.buf_len
);
5404 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
5405 if (status
) goto out
;
5407 status
= map_query_acl_error(entry
->status
);
5409 if (!nfs41_fobx
->deleg_type
&& entry
->ChangeTime
&&
5410 (SrvOpen
->DesiredAccess
&
5411 (FILE_READ_DATA
| FILE_WRITE_DATA
| FILE_APPEND_DATA
)))
5412 nfs41_update_fcb_list(RxContext
->pFcb
, entry
->ChangeTime
);
5413 nfs41_fcb
->changeattr
= entry
->ChangeTime
;
5417 #ifdef ENABLE_TIMINGS
5418 t2
= KeQueryPerformanceCounter(NULL
);
5419 InterlockedIncrement(&setacl
.tops
);
5420 InterlockedAdd64(&setacl
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
5421 #ifdef ENABLE_INDV_TIMINGS
5422 DbgP("nfs41_SetSecurityInformation delta = %d op=%d sum=%d\n",
5423 t2
.QuadPart
- t1
.QuadPart
, setacl
.tops
, setacl
.ticks
);
5426 #ifdef DEBUG_ACL_SET
5432 NTSTATUS
map_queryfile_error(
5436 case ERROR_ACCESS_DENIED
: return STATUS_ACCESS_DENIED
;
5437 case ERROR_NETNAME_DELETED
: return STATUS_NETWORK_NAME_DELETED
;
5438 case ERROR_INVALID_PARAMETER
: return STATUS_INVALID_PARAMETER
;
5440 print_error("failed to map windows error %d to NTSTATUS; "
5441 "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", error
);
5442 case ERROR_BAD_NET_RESP
: return STATUS_INVALID_NETWORK_RESPONSE
;
5447 NTSTATUS NTAPI
nfs41_QueryFileInformation(
5449 NTSTATUS
nfs41_QueryFileInformation(
5451 IN OUT PRX_CONTEXT RxContext
)
5453 NTSTATUS status
= STATUS_OBJECT_NAME_NOT_FOUND
;
5454 FILE_INFORMATION_CLASS InfoClass
= RxContext
->Info
.FileInformationClass
;
5455 nfs41_updowncall_entry
*entry
;
5456 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
5457 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
5458 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
5459 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
5460 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
5461 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
5462 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
5463 #ifdef ENABLE_TIMINGS
5464 LARGE_INTEGER t1
, t2
;
5465 t1
= KeQueryPerformanceCounter(NULL
);
5468 #ifdef DEBUG_FILE_QUERY
5470 print_debug_filedirquery_header(RxContext
);
5473 status
= check_nfs41_dirquery_args(RxContext
);
5474 if (status
) goto out
;
5476 switch (InfoClass
) {
5477 case FileEaInformation
:
5479 PFILE_EA_INFORMATION info
=
5480 (PFILE_EA_INFORMATION
)RxContext
->Info
.Buffer
;
5482 RxContext
->Info
.LengthRemaining
-= sizeof(FILE_EA_INFORMATION
);
5483 status
= STATUS_SUCCESS
;
5486 case FileBasicInformation
:
5487 case FileStandardInformation
:
5488 case FileInternalInformation
:
5489 case FileAttributeTagInformation
:
5490 case FileNetworkOpenInformation
:
5493 print_error("nfs41_QueryFileInformation: unhandled class %d\n", InfoClass
);
5494 status
= STATUS_NOT_SUPPORTED
;
5498 status
= nfs41_UpcallCreate(NFS41_FILE_QUERY
, &nfs41_fobx
->sec_ctx
,
5499 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
5500 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
5501 if (status
) goto out
;
5503 entry
->u
.QueryFile
.InfoClass
= InfoClass
;
5504 entry
->buf
= RxContext
->Info
.Buffer
;
5505 entry
->buf_len
= RxContext
->Info
.LengthRemaining
;
5507 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
5508 if (status
) goto out
;
5510 if (entry
->status
== STATUS_BUFFER_TOO_SMALL
) {
5511 RxContext
->InformationToReturn
= entry
->buf_len
;
5512 status
= STATUS_BUFFER_TOO_SMALL
;
5513 } else if (entry
->status
== STATUS_SUCCESS
) {
5514 BOOLEAN DeletePending
= FALSE
;
5515 #ifdef ENABLE_TIMINGS
5516 InterlockedIncrement(&getattr
.sops
);
5517 InterlockedAdd64(&getattr
.size
, entry
->u
.QueryFile
.buf_len
);
5519 RxContext
->Info
.LengthRemaining
-= entry
->buf_len
;
5520 status
= STATUS_SUCCESS
;
5522 switch (InfoClass
) {
5523 case FileBasicInformation
:
5524 RtlCopyMemory(&nfs41_fcb
->BasicInfo
, RxContext
->Info
.Buffer
,
5525 sizeof(nfs41_fcb
->BasicInfo
));
5526 #ifdef DEBUG_FILE_QUERY
5527 print_basic_info(1, &nfs41_fcb
->BasicInfo
);
5530 case FileStandardInformation
:
5531 /* this a fix for RDBSS behaviour when it first calls ExtendForCache,
5532 * then it sends a file query irp for standard attributes and
5533 * expects to receive EndOfFile of value set by the ExtendForCache.
5534 * It seems to cache the filesize based on that instead of sending
5535 * a file size query for after doing the write.
5538 PFILE_STANDARD_INFORMATION std_info
;
5539 std_info
= (PFILE_STANDARD_INFORMATION
)RxContext
->Info
.Buffer
;
5540 if (nfs41_fcb
->StandardInfo
.AllocationSize
.QuadPart
>
5541 std_info
->AllocationSize
.QuadPart
) {
5542 #ifdef DEBUG_FILE_QUERY
5543 DbgP("Old AllocationSize is bigger: saving %x\n",
5544 nfs41_fcb
->StandardInfo
.AllocationSize
.QuadPart
);
5546 std_info
->AllocationSize
.QuadPart
=
5547 nfs41_fcb
->StandardInfo
.AllocationSize
.QuadPart
;
5549 if (nfs41_fcb
->StandardInfo
.EndOfFile
.QuadPart
>
5550 std_info
->EndOfFile
.QuadPart
) {
5551 #ifdef DEBUG_FILE_QUERY
5552 DbgP("Old EndOfFile is bigger: saving %x\n",
5553 nfs41_fcb
->StandardInfo
.EndOfFile
);
5555 std_info
->EndOfFile
.QuadPart
=
5556 nfs41_fcb
->StandardInfo
.EndOfFile
.QuadPart
;
5558 std_info
->DeletePending
= nfs41_fcb
->DeletePending
;
5560 if (nfs41_fcb
->StandardInfo
.DeletePending
)
5561 DeletePending
= TRUE
;
5562 RtlCopyMemory(&nfs41_fcb
->StandardInfo
, RxContext
->Info
.Buffer
,
5563 sizeof(nfs41_fcb
->StandardInfo
));
5564 nfs41_fcb
->StandardInfo
.DeletePending
= DeletePending
;
5565 #ifdef DEBUG_FILE_QUERY
5566 print_std_info(1, &nfs41_fcb
->StandardInfo
);
5571 status
= map_queryfile_error(entry
->status
);
5575 #ifdef ENABLE_TIMINGS
5576 t2
= KeQueryPerformanceCounter(NULL
);
5577 InterlockedIncrement(&getattr
.tops
);
5578 InterlockedAdd64(&getattr
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
5579 #ifdef ENABLE_INDV_TIMINGS
5580 DbgP("nfs41_QueryFileInformation delta = %d op=%d sum=%d\n",
5581 t2
.QuadPart
- t1
.QuadPart
, getattr
.tops
, getattr
.ticks
);
5584 #ifdef DEBUG_FILE_QUERY
5590 NTSTATUS
map_setfile_error(
5594 case NO_ERROR
: return STATUS_SUCCESS
;
5595 case ERROR_NOT_EMPTY
: return STATUS_DIRECTORY_NOT_EMPTY
;
5596 case ERROR_FILE_EXISTS
: return STATUS_OBJECT_NAME_COLLISION
;
5597 case ERROR_FILE_NOT_FOUND
: return STATUS_OBJECT_NAME_NOT_FOUND
;
5598 case ERROR_PATH_NOT_FOUND
: return STATUS_OBJECT_PATH_NOT_FOUND
;
5599 case ERROR_ACCESS_DENIED
: return STATUS_ACCESS_DENIED
;
5600 case ERROR_FILE_INVALID
: return STATUS_FILE_INVALID
;
5601 case ERROR_NOT_SAME_DEVICE
: return STATUS_NOT_SAME_DEVICE
;
5602 case ERROR_NOT_SUPPORTED
: return STATUS_NOT_IMPLEMENTED
;
5603 case ERROR_NETWORK_ACCESS_DENIED
: return STATUS_NETWORK_ACCESS_DENIED
;
5604 case ERROR_NETNAME_DELETED
: return STATUS_NETWORK_NAME_DELETED
;
5605 case ERROR_BUFFER_OVERFLOW
: return STATUS_INSUFFICIENT_RESOURCES
;
5607 print_error("failed to map windows error %d to NTSTATUS; "
5608 "defaulting to STATUS_INVALID_PARAMETER\n", error
);
5609 case ERROR_INVALID_PARAMETER
: return STATUS_INVALID_PARAMETER
;
5613 NTSTATUS
check_nfs41_setattr_args(
5614 IN PRX_CONTEXT RxContext
)
5616 NTSTATUS status
= STATUS_SUCCESS
;
5617 FILE_INFORMATION_CLASS InfoClass
= RxContext
->Info
.FileInformationClass
;
5618 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
5619 NFS41GetVNetRootExtension(RxContext
->pRelevantSrvOpen
->pVNetRoot
);
5621 if (pVNetRootContext
->read_only
) {
5622 print_error("check_nfs41_setattr_args: Read-only mount\n");
5623 status
= STATUS_ACCESS_DENIED
;
5627 /* http://msdn.microsoft.com/en-us/library/ff469355(v=PROT.10).aspx
5628 * http://msdn.microsoft.com/en-us/library/ff469424(v=PROT.10).aspx
5629 * If Open.GrantedAccess does not contain FILE_WRITE_DATA, the operation
5630 * MUST be failed with STATUS_ACCESS_DENIED.
5632 if (InfoClass
== FileAllocationInformation
||
5633 InfoClass
== FileEndOfFileInformation
) {
5634 if (!(RxContext
->pRelevantSrvOpen
->DesiredAccess
& FILE_WRITE_DATA
)) {
5635 status
= STATUS_ACCESS_DENIED
;
5639 status
= check_nfs41_dirquery_args(RxContext
);
5640 if (status
) goto out
;
5642 switch (InfoClass
) {
5643 case FileRenameInformation
:
5645 PFILE_RENAME_INFORMATION rinfo
=
5646 (PFILE_RENAME_INFORMATION
)RxContext
->Info
.Buffer
;
5647 UNICODE_STRING dst
= { (USHORT
)rinfo
->FileNameLength
,
5648 (USHORT
)rinfo
->FileNameLength
, rinfo
->FileName
};
5649 #ifdef DEBUG_FILE_SET
5650 DbgP("Attempting to rename to '%wZ'\n", &dst
);
5652 if (isFilenameTooLong(&dst
, pVNetRootContext
)) {
5653 status
= STATUS_OBJECT_NAME_INVALID
;
5656 if (rinfo
->RootDirectory
) {
5657 status
= STATUS_INVALID_PARAMETER
;
5662 case FileLinkInformation
:
5664 PFILE_LINK_INFORMATION linfo
=
5665 (PFILE_LINK_INFORMATION
)RxContext
->Info
.Buffer
;
5666 UNICODE_STRING dst
= { (USHORT
)linfo
->FileNameLength
,
5667 (USHORT
)linfo
->FileNameLength
, linfo
->FileName
};
5668 #ifdef DEBUG_FILE_SET
5669 DbgP("Attempting to add link as '%wZ'\n", &dst
);
5671 if (isFilenameTooLong(&dst
, pVNetRootContext
)) {
5672 status
= STATUS_OBJECT_NAME_INVALID
;
5675 if (linfo
->RootDirectory
) {
5676 status
= STATUS_INVALID_PARAMETER
;
5681 case FileDispositionInformation
:
5683 PFILE_DISPOSITION_INFORMATION dinfo
=
5684 (PFILE_DISPOSITION_INFORMATION
)RxContext
->Info
.Buffer
;
5685 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
5686 if (dinfo
->DeleteFile
&& nfs41_fcb
->DeletePending
) {
5687 status
= STATUS_DELETE_PENDING
;
5692 case FileBasicInformation
:
5693 case FileAllocationInformation
:
5694 case FileEndOfFileInformation
:
5697 print_error("nfs41_SetFileInformation: unhandled class %d\n", InfoClass
);
5698 status
= STATUS_NOT_SUPPORTED
;
5706 NTSTATUS NTAPI
nfs41_SetFileInformation(
5708 NTSTATUS
nfs41_SetFileInformation(
5710 IN OUT PRX_CONTEXT RxContext
)
5712 NTSTATUS status
= STATUS_INVALID_PARAMETER
;
5713 nfs41_updowncall_entry
*entry
;
5714 FILE_INFORMATION_CLASS InfoClass
= RxContext
->Info
.FileInformationClass
;
5715 FILE_RENAME_INFORMATION rinfo
;
5716 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
5717 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
5718 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
5719 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
5720 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
5721 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
5722 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
5723 #ifdef ENABLE_TIMINGS
5724 LARGE_INTEGER t1
, t2
;
5725 t1
= KeQueryPerformanceCounter(NULL
);
5728 #ifdef DEBUG_FILE_SET
5730 print_debug_filedirquery_header(RxContext
);
5733 status
= check_nfs41_setattr_args(RxContext
);
5734 if (status
) goto out
;
5736 switch (InfoClass
) {
5737 case FileDispositionInformation
:
5739 PFILE_DISPOSITION_INFORMATION dinfo
=
5740 (PFILE_DISPOSITION_INFORMATION
)RxContext
->Info
.Buffer
;
5741 if (dinfo
->DeleteFile
) {
5742 nfs41_fcb
->DeletePending
= TRUE
;
5743 // we can delete directories right away
5744 if (nfs41_fcb
->StandardInfo
.Directory
)
5746 nfs41_fcb
->StandardInfo
.DeletePending
= TRUE
;
5747 if (RxContext
->pFcb
->OpenCount
> 1) {
5748 rinfo
.ReplaceIfExists
= 0;
5749 rinfo
.RootDirectory
= INVALID_HANDLE_VALUE
;
5750 rinfo
.FileNameLength
= 0;
5751 rinfo
.FileName
[0] = L
'\0';
5752 InfoClass
= FileRenameInformation
;
5753 nfs41_fcb
->Renamed
= TRUE
;
5757 /* section 4.3.3 of [FSBO]
5758 * "file system behavior in the microsoft windows environment"
5760 if (nfs41_fcb
->DeletePending
) {
5761 nfs41_fcb
->DeletePending
= 0;
5762 nfs41_fcb
->StandardInfo
.DeletePending
= 0;
5765 status
= STATUS_SUCCESS
;
5768 case FileEndOfFileInformation
:
5770 PFILE_END_OF_FILE_INFORMATION info
=
5771 (PFILE_END_OF_FILE_INFORMATION
)RxContext
->Info
.Buffer
;
5772 nfs41_fcb
->StandardInfo
.AllocationSize
=
5773 nfs41_fcb
->StandardInfo
.EndOfFile
= info
->EndOfFile
;
5776 case FileRenameInformation
:
5778 /* noop if filename and destination are the same */
5779 PFILE_RENAME_INFORMATION prinfo
=
5780 (PFILE_RENAME_INFORMATION
)RxContext
->Info
.Buffer
;
5781 const UNICODE_STRING dst
= { (USHORT
)prinfo
->FileNameLength
,
5782 (USHORT
)prinfo
->FileNameLength
, prinfo
->FileName
};
5783 if (RtlCompareUnicodeString(&dst
,
5784 SrvOpen
->pAlreadyPrefixedName
, FALSE
) == 0) {
5785 status
= STATUS_SUCCESS
;
5791 status
= nfs41_UpcallCreate(NFS41_FILE_SET
, &nfs41_fobx
->sec_ctx
,
5792 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
5793 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
5794 if (status
) goto out
;
5796 entry
->u
.SetFile
.InfoClass
= InfoClass
;
5798 /* original irp has infoclass for remove but we need to rename instead,
5799 * thus we changed the local variable infoclass */
5800 if (RxContext
->Info
.FileInformationClass
== FileDispositionInformation
&&
5801 InfoClass
== FileRenameInformation
) {
5802 entry
->buf
= &rinfo
;
5803 entry
->buf_len
= sizeof(rinfo
);
5805 entry
->buf
= RxContext
->Info
.Buffer
;
5806 entry
->buf_len
= RxContext
->Info
.Length
;
5808 #ifdef ENABLE_TIMINGS
5809 InterlockedIncrement(&setattr
.sops
);
5810 InterlockedAdd64(&setattr
.size
, entry
->u
.SetFile
.buf_len
);
5813 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
5814 if (status
) goto out
;
5816 status
= map_setfile_error(entry
->status
);
5818 if (!nfs41_fobx
->deleg_type
&& entry
->ChangeTime
&&
5819 (SrvOpen
->DesiredAccess
&
5820 (FILE_READ_DATA
| FILE_WRITE_DATA
| FILE_APPEND_DATA
)))
5821 nfs41_update_fcb_list(RxContext
->pFcb
, entry
->ChangeTime
);
5822 nfs41_fcb
->changeattr
= entry
->ChangeTime
;
5826 #ifdef ENABLE_TIMINGS
5827 t2
= KeQueryPerformanceCounter(NULL
);
5828 InterlockedIncrement(&setattr
.tops
);
5829 InterlockedAdd64(&setattr
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
5830 #ifdef ENABLE_INDV_TIMINGS
5831 DbgP("nfs41_SetFileInformation delta = %d op=%d sum=%d\n",
5832 t2
.QuadPart
- t1
.QuadPart
, setattr
.tops
, setattr
.ticks
);
5835 #ifdef DEBUG_FILE_SET
5841 NTSTATUS
nfs41_SetFileInformationAtCleanup(
5842 IN OUT PRX_CONTEXT RxContext
)
5846 status
= nfs41_SetFileInformation(RxContext
);
5852 NTSTATUS NTAPI
nfs41_IsValidDirectory (
5854 NTSTATUS
nfs41_IsValidDirectory (
5856 IN OUT PRX_CONTEXT RxContext
,
5857 IN PUNICODE_STRING DirectoryName
)
5859 return STATUS_SUCCESS
;
5863 NTSTATUS NTAPI
nfs41_ComputeNewBufferingState(
5865 NTSTATUS
nfs41_ComputeNewBufferingState(
5867 IN OUT PMRX_SRV_OPEN pSrvOpen
,
5868 IN PVOID pMRxContext
,
5869 OUT ULONG
*pNewBufferingState
)
5871 NTSTATUS status
= STATUS_SUCCESS
;
5872 ULONG flag
= PtrToUlong(pMRxContext
), oldFlags
= pSrvOpen
->BufferingFlags
;
5875 case DISABLE_CACHING
:
5876 if (pSrvOpen
->BufferingFlags
&
5877 (FCB_STATE_READBUFFERING_ENABLED
| FCB_STATE_READCACHING_ENABLED
))
5878 pSrvOpen
->BufferingFlags
&=
5879 ~(FCB_STATE_READBUFFERING_ENABLED
|
5880 FCB_STATE_READCACHING_ENABLED
);
5881 if (pSrvOpen
->BufferingFlags
&
5882 (FCB_STATE_WRITECACHING_ENABLED
| FCB_STATE_WRITEBUFFERING_ENABLED
))
5883 pSrvOpen
->BufferingFlags
&=
5884 ~(FCB_STATE_WRITECACHING_ENABLED
|
5885 FCB_STATE_WRITEBUFFERING_ENABLED
);
5886 pSrvOpen
->BufferingFlags
|= FCB_STATE_DISABLE_LOCAL_BUFFERING
;
5888 case ENABLE_READ_CACHING
:
5889 pSrvOpen
->BufferingFlags
|=
5890 (FCB_STATE_READBUFFERING_ENABLED
| FCB_STATE_READCACHING_ENABLED
);
5892 case ENABLE_WRITE_CACHING
:
5893 pSrvOpen
->BufferingFlags
|=
5894 (FCB_STATE_WRITECACHING_ENABLED
| FCB_STATE_WRITEBUFFERING_ENABLED
);
5896 case ENABLE_READWRITE_CACHING
:
5897 pSrvOpen
->BufferingFlags
=
5898 (FCB_STATE_READBUFFERING_ENABLED
| FCB_STATE_READCACHING_ENABLED
|
5899 FCB_STATE_WRITECACHING_ENABLED
| FCB_STATE_WRITEBUFFERING_ENABLED
);
5901 #ifdef DEBUG_TIME_BASED_COHERENCY
5902 DbgP("nfs41_ComputeNewBufferingState: %wZ pSrvOpen %p Old %08x New %08x\n",
5903 pSrvOpen
->pAlreadyPrefixedName
, pSrvOpen
, oldFlags
,
5904 pSrvOpen
->BufferingFlags
);
5905 *pNewBufferingState
= pSrvOpen
->BufferingFlags
;
5910 void print_readwrite_args(
5911 PRX_CONTEXT RxContext
)
5913 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
5915 print_debug_header(RxContext
);
5916 DbgP("Bytecount 0x%x Byteoffset 0x%x Buffer %p\n",
5917 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
,
5918 LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
,
5919 LowIoContext
->ParamsFor
.ReadWrite
.Buffer
);
5922 void enable_caching(
5923 PMRX_SRV_OPEN SrvOpen
,
5924 PNFS41_FOBX nfs41_fobx
,
5925 ULONGLONG ChangeTime
,
5930 nfs41_fcb_list_entry
*cur
;
5931 BOOLEAN found
= FALSE
;
5933 if (SrvOpen
->DesiredAccess
& FILE_READ_DATA
)
5934 flag
= ENABLE_READ_CACHING
;
5935 if ((SrvOpen
->DesiredAccess
& FILE_WRITE_DATA
) &&
5936 !nfs41_fobx
->write_thru
)
5937 flag
= ENABLE_WRITE_CACHING
;
5938 if ((SrvOpen
->DesiredAccess
& FILE_READ_DATA
) &&
5939 (SrvOpen
->DesiredAccess
& FILE_WRITE_DATA
) &&
5940 !nfs41_fobx
->write_thru
)
5941 flag
= ENABLE_READWRITE_CACHING
;
5943 #if defined(DEBUG_TIME_BASED_COHERENCY) || \
5944 defined(DEBUG_WRITE) || defined(DEBUG_READ)
5945 print_caching_level(1, flag
, SrvOpen
->pAlreadyPrefixedName
);
5951 RxChangeBufferingState((PSRV_OPEN
)SrvOpen
, ULongToPtr(flag
), 1);
5953 ExAcquireFastMutex(&fcblistLock
);
5954 pEntry
= openlist
.head
.Flink
;
5955 while (!IsListEmpty(&openlist
.head
)) {
5956 cur
= (nfs41_fcb_list_entry
*)CONTAINING_RECORD(pEntry
,
5957 nfs41_fcb_list_entry
, next
);
5958 if (cur
->fcb
== SrvOpen
->pFcb
) {
5959 #ifdef DEBUG_TIME_BASED_COHERENCY
5960 DbgP("enable_caching: Looked&Found match for fcb=%p %wZ\n",
5961 SrvOpen
->pFcb
, SrvOpen
->pAlreadyPrefixedName
);
5967 if (pEntry
->Flink
== &openlist
.head
) {
5968 #ifdef DEBUG_TIME_BASED_COHERENCY
5969 DbgP("enable_caching: reached EOL looking for fcb=%p %wZ\n",
5970 SrvOpen
->pFcb
, SrvOpen
->pAlreadyPrefixedName
);
5974 pEntry
= pEntry
->Flink
;
5976 if (!found
&& nfs41_fobx
->deleg_type
) {
5977 nfs41_fcb_list_entry
*oentry
;
5978 #ifdef DEBUG_TIME_BASED_COHERENCY
5979 DbgP("enable_caching: delegation recalled: srv_open=%p\n", SrvOpen
);
5981 oentry
= RxAllocatePoolWithTag(NonPagedPool
,
5982 sizeof(nfs41_fcb_list_entry
), NFS41_MM_POOLTAG_OPEN
);
5983 if (oentry
== NULL
) return;
5984 oentry
->fcb
= SrvOpen
->pFcb
;
5985 oentry
->session
= session
;
5986 oentry
->nfs41_fobx
= nfs41_fobx
;
5987 oentry
->ChangeTime
= ChangeTime
;
5988 oentry
->skip
= FALSE
;
5989 InsertTailList(&openlist
.head
, &oentry
->next
);
5990 nfs41_fobx
->deleg_type
= 0;
5992 ExReleaseFastMutex(&fcblistLock
);
5995 NTSTATUS
map_readwrite_errors(
5999 case ERROR_ACCESS_DENIED
: return STATUS_ACCESS_DENIED
;
6000 case ERROR_HANDLE_EOF
: return STATUS_END_OF_FILE
;
6001 case ERROR_FILE_INVALID
: return STATUS_FILE_INVALID
;
6002 case ERROR_INVALID_PARAMETER
: return STATUS_INVALID_PARAMETER
;
6003 case ERROR_LOCK_VIOLATION
: return STATUS_FILE_LOCK_CONFLICT
;
6004 case ERROR_NETWORK_ACCESS_DENIED
: return STATUS_NETWORK_ACCESS_DENIED
;
6005 case ERROR_NETNAME_DELETED
: return STATUS_NETWORK_NAME_DELETED
;
6007 print_error("failed to map windows error %d to NTSTATUS; "
6008 "defaulting to STATUS_NET_WRITE_FAULT\n", status
);
6009 case ERROR_NET_WRITE_FAULT
: return STATUS_NET_WRITE_FAULT
;
6013 NTSTATUS
check_nfs41_read_args(
6014 IN PRX_CONTEXT RxContext
)
6016 if (!RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Buffer
)
6017 return STATUS_INVALID_USER_BUFFER
;
6018 return STATUS_SUCCESS
;
6022 NTSTATUS NTAPI
nfs41_Read(
6024 NTSTATUS
nfs41_Read(
6026 IN OUT PRX_CONTEXT RxContext
)
6028 NTSTATUS status
= STATUS_INSUFFICIENT_RESOURCES
;
6029 nfs41_updowncall_entry
*entry
;
6030 BOOLEAN async
= FALSE
;
6031 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
6032 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
6033 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
6034 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
6035 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
6036 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
6037 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
6038 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
6040 #ifdef ENABLE_TIMINGS
6041 LARGE_INTEGER t1
, t2
;
6042 t1
= KeQueryPerformanceCounter(NULL
);
6047 print_readwrite_args(RxContext
);
6049 status
= check_nfs41_read_args(RxContext
);
6050 if (status
) goto out
;
6052 status
= nfs41_UpcallCreate(NFS41_READ
, &nfs41_fobx
->sec_ctx
,
6053 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
6054 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
6055 if (status
) goto out
;
6057 entry
->u
.ReadWrite
.MdlAddress
= LowIoContext
->ParamsFor
.ReadWrite
.Buffer
;
6058 entry
->buf_len
= LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
;
6059 entry
->u
.ReadWrite
.offset
= LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
;
6060 if (FlagOn(RxContext
->CurrentIrpSp
->FileObject
->Flags
,
6061 FO_SYNCHRONOUS_IO
) == FALSE
) {
6062 entry
->u
.ReadWrite
.rxcontext
= RxContext
;
6063 async
= entry
->async_op
= TRUE
;
6066 /* assume network speed is 100MB/s and disk speed is 100MB/s so add
6067 * time to transfer requested bytes over the network and read from disk
6069 io_delay
= pVNetRootContext
->timeout
+ 2 * entry
->buf_len
/ 104857600;
6070 status
= nfs41_UpcallWaitForReply(entry
, io_delay
);
6071 if (status
) goto out
;
6075 DbgP("This is asynchronous read, returning control back to the user\n");
6077 status
= STATUS_PENDING
;
6081 if (entry
->status
== NO_ERROR
) {
6082 #ifdef ENABLE_TIMINGS
6083 InterlockedIncrement(&read
.sops
);
6084 InterlockedAdd64(&read
.size
, entry
->u
.ReadWrite
.len
);
6086 status
= RxContext
->CurrentIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
6087 RxContext
->IoStatusBlock
.Information
= entry
->buf_len
;
6089 if ((!BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
,
6090 LOWIO_READWRITEFLAG_PAGING_IO
) &&
6091 (SrvOpen
->DesiredAccess
& FILE_READ_DATA
) &&
6092 !pVNetRootContext
->nocache
&& !nfs41_fobx
->nocache
&&
6093 !(SrvOpen
->BufferingFlags
&
6094 (FCB_STATE_READBUFFERING_ENABLED
|
6095 FCB_STATE_READCACHING_ENABLED
)))) {
6096 enable_caching(SrvOpen
, nfs41_fobx
, nfs41_fcb
->changeattr
,
6097 pVNetRootContext
->session
);
6100 status
= map_readwrite_errors(entry
->status
);
6101 RxContext
->CurrentIrp
->IoStatus
.Status
= status
;
6102 RxContext
->IoStatusBlock
.Information
= 0;
6106 #ifdef ENABLE_TIMINGS
6107 t2
= KeQueryPerformanceCounter(NULL
);
6108 InterlockedIncrement(&read
.tops
);
6109 InterlockedAdd64(&read
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
6110 #ifdef ENABLE_INDV_TIMINGS
6111 DbgP("nfs41_Read delta = %d op=%d sum=%d\n", t2
.QuadPart
- t1
.QuadPart
,
6112 read
.tops
, read
.ticks
);
6121 NTSTATUS
check_nfs41_write_args(
6122 IN PRX_CONTEXT RxContext
)
6124 NTSTATUS status
= STATUS_SUCCESS
;
6125 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
6126 NFS41GetVNetRootExtension(RxContext
->pRelevantSrvOpen
->pVNetRoot
);
6128 if (!RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Buffer
) {
6129 status
= STATUS_INVALID_USER_BUFFER
;
6133 if (pVNetRootContext
->read_only
) {
6134 print_error("check_nfs41_write_args: Read-only mount\n");
6135 status
= STATUS_ACCESS_DENIED
;
6143 NTSTATUS NTAPI
nfs41_Write(
6145 NTSTATUS
nfs41_Write(
6147 IN OUT PRX_CONTEXT RxContext
)
6149 NTSTATUS status
= STATUS_INSUFFICIENT_RESOURCES
;
6150 nfs41_updowncall_entry
*entry
;
6151 BOOLEAN async
= FALSE
;
6152 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
6153 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
6154 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
6155 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
6156 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
6157 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
6158 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
6159 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
6161 #ifdef ENABLE_TIMINGS
6162 LARGE_INTEGER t1
, t2
;
6163 t1
= KeQueryPerformanceCounter(NULL
);
6168 print_readwrite_args(RxContext
);
6171 status
= check_nfs41_write_args(RxContext
);
6172 if (status
) goto out
;
6174 status
= nfs41_UpcallCreate(NFS41_WRITE
, &nfs41_fobx
->sec_ctx
,
6175 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
6176 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
6177 if (status
) goto out
;
6179 entry
->u
.ReadWrite
.MdlAddress
= LowIoContext
->ParamsFor
.ReadWrite
.Buffer
;
6180 entry
->buf_len
= LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
;
6181 entry
->u
.ReadWrite
.offset
= LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
;
6183 if (FlagOn(RxContext
->CurrentIrpSp
->FileObject
->Flags
,
6184 FO_SYNCHRONOUS_IO
) == FALSE
) {
6185 entry
->u
.ReadWrite
.rxcontext
= RxContext
;
6186 async
= entry
->async_op
= TRUE
;
6189 /* assume network speed is 100MB/s and disk speed is 100MB/s so add
6190 * time to transfer requested bytes over the network and write to disk
6192 io_delay
= pVNetRootContext
->timeout
+ 2 * entry
->buf_len
/ 104857600;
6193 status
= nfs41_UpcallWaitForReply(entry
, io_delay
);
6194 if (status
) goto out
;
6198 DbgP("This is asynchronous write, returning control back to the user\n");
6200 status
= STATUS_PENDING
;
6204 if (entry
->status
== NO_ERROR
) {
6205 //update cached file attributes
6206 #ifdef ENABLE_TIMINGS
6207 InterlockedIncrement(&write
.sops
);
6208 InterlockedAdd64(&write
.size
, entry
->u
.ReadWrite
.len
);
6210 nfs41_fcb
->StandardInfo
.EndOfFile
.QuadPart
= entry
->buf_len
+
6211 entry
->u
.ReadWrite
.offset
;
6212 status
= RxContext
->CurrentIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
6213 RxContext
->IoStatusBlock
.Information
= entry
->buf_len
;
6214 nfs41_fcb
->changeattr
= entry
->ChangeTime
;
6216 //re-enable write buffering
6217 if (!BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
,
6218 LOWIO_READWRITEFLAG_PAGING_IO
) &&
6219 (SrvOpen
->DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) &&
6220 !pVNetRootContext
->write_thru
&&
6221 !pVNetRootContext
->nocache
&&
6222 !nfs41_fobx
->write_thru
&& !nfs41_fobx
->nocache
&&
6223 !(SrvOpen
->BufferingFlags
&
6224 (FCB_STATE_WRITEBUFFERING_ENABLED
|
6225 FCB_STATE_WRITECACHING_ENABLED
))) {
6226 enable_caching(SrvOpen
, nfs41_fobx
, nfs41_fcb
->changeattr
,
6227 pVNetRootContext
->session
);
6228 } else if (!nfs41_fobx
->deleg_type
)
6229 nfs41_update_fcb_list(RxContext
->pFcb
, entry
->ChangeTime
);
6232 status
= map_readwrite_errors(entry
->status
);
6233 RxContext
->CurrentIrp
->IoStatus
.Status
= status
;
6234 RxContext
->IoStatusBlock
.Information
= 0;
6238 #ifdef ENABLE_TIMINGS
6239 t2
= KeQueryPerformanceCounter(NULL
);
6240 InterlockedIncrement(&write
.tops
);
6241 InterlockedAdd64(&write
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
6242 #ifdef ENABLE_INDV_TIMINGS
6243 DbgP("nfs41_Write delta = %d op=%d sum=%d\n", t2
.QuadPart
- t1
.QuadPart
,
6244 write
.tops
, write
.ticks
);
6254 NTSTATUS NTAPI
nfs41_IsLockRealizable(
6256 NTSTATUS
nfs41_IsLockRealizable(
6258 IN OUT PMRX_FCB pFcb
,
6259 IN PLARGE_INTEGER ByteOffset
,
6260 IN PLARGE_INTEGER Length
,
6261 IN ULONG LowIoLockFlags
)
6263 NTSTATUS status
= STATUS_SUCCESS
;
6266 DbgP("offset 0x%llx, length 0x%llx, exclusive=%u, blocking=%u\n",
6267 ByteOffset
->QuadPart
,Length
->QuadPart
,
6268 BooleanFlagOn(LowIoLockFlags
, SL_EXCLUSIVE_LOCK
),
6269 !BooleanFlagOn(LowIoLockFlags
, SL_FAIL_IMMEDIATELY
));
6272 /* NFS lock operations with length=0 MUST fail with NFS4ERR_INVAL */
6273 if (Length
->QuadPart
== 0)
6274 status
= STATUS_NOT_SUPPORTED
;
6282 NTSTATUS
map_lock_errors(
6286 case NO_ERROR
: return STATUS_SUCCESS
;
6287 case ERROR_NETNAME_DELETED
: return STATUS_NETWORK_NAME_DELETED
;
6288 case ERROR_LOCK_FAILED
: return STATUS_LOCK_NOT_GRANTED
;
6289 case ERROR_NOT_LOCKED
: return STATUS_RANGE_NOT_LOCKED
;
6290 case ERROR_ATOMIC_LOCKS_NOT_SUPPORTED
: return STATUS_UNSUCCESSFUL
;
6291 case ERROR_OUTOFMEMORY
: return STATUS_INSUFFICIENT_RESOURCES
;
6292 case ERROR_SHARING_VIOLATION
: return STATUS_SHARING_VIOLATION
;
6293 case ERROR_FILE_INVALID
: return STATUS_FILE_INVALID
;
6294 /* if we return ERROR_INVALID_PARAMETER, Windows translates that to
6296 case ERROR_INVALID_PARAMETER
: return STATUS_LOCK_NOT_GRANTED
;
6298 print_error("failed to map windows error %d to NTSTATUS; "
6299 "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", status
);
6300 case ERROR_BAD_NET_RESP
: return STATUS_INVALID_NETWORK_RESPONSE
;
6304 void print_lock_args(
6305 PRX_CONTEXT RxContext
)
6307 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
6308 const ULONG flags
= LowIoContext
->ParamsFor
.Locks
.Flags
;
6309 print_debug_header(RxContext
);
6310 DbgP("offset 0x%llx, length 0x%llx, exclusive=%u, blocking=%u\n",
6311 LowIoContext
->ParamsFor
.Locks
.ByteOffset
,
6312 LowIoContext
->ParamsFor
.Locks
.Length
,
6313 BooleanFlagOn(flags
, SL_EXCLUSIVE_LOCK
),
6314 !BooleanFlagOn(flags
, SL_FAIL_IMMEDIATELY
));
6318 /* use exponential backoff between polls for blocking locks */
6319 #define MSEC_TO_RELATIVE_WAIT (-10000)
6320 #define MIN_LOCK_POLL_WAIT (500 * MSEC_TO_RELATIVE_WAIT) /* 500ms */
6321 #define MAX_LOCK_POLL_WAIT (30000 * MSEC_TO_RELATIVE_WAIT) /* 30s */
6323 void denied_lock_backoff(
6324 IN OUT PLARGE_INTEGER delay
)
6326 if (delay
->QuadPart
== 0)
6327 delay
->QuadPart
= MIN_LOCK_POLL_WAIT
;
6329 delay
->QuadPart
<<= 1;
6331 if (delay
->QuadPart
< MAX_LOCK_POLL_WAIT
)
6332 delay
->QuadPart
= MAX_LOCK_POLL_WAIT
;
6336 NTSTATUS NTAPI
nfs41_Lock(
6338 NTSTATUS
nfs41_Lock(
6340 IN OUT PRX_CONTEXT RxContext
)
6342 NTSTATUS status
= STATUS_SUCCESS
;
6343 nfs41_updowncall_entry
*entry
;
6344 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
6345 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
6346 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
6347 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
6348 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
6349 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
6350 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
6351 const ULONG flags
= LowIoContext
->ParamsFor
.Locks
.Flags
;
6353 LARGE_INTEGER poll_delay
= {0};
6355 LARGE_INTEGER poll_delay
;
6357 #ifdef ENABLE_TIMINGS
6358 LARGE_INTEGER t1
, t2
;
6359 t1
= KeQueryPerformanceCounter(NULL
);
6363 poll_delay
.QuadPart
= 0;
6368 print_lock_args(RxContext
);
6371 /* RxReleaseFcbResourceForThreadInMRx(RxContext, RxContext->pFcb,
6372 LowIoContext->ResourceThreadId); */
6374 status
= nfs41_UpcallCreate(NFS41_LOCK
, &nfs41_fobx
->sec_ctx
,
6375 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
6376 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
6377 if (status
) goto out
;
6379 entry
->u
.Lock
.offset
= LowIoContext
->ParamsFor
.Locks
.ByteOffset
;
6380 entry
->u
.Lock
.length
= LowIoContext
->ParamsFor
.Locks
.Length
;
6381 entry
->u
.Lock
.exclusive
= BooleanFlagOn(flags
, SL_EXCLUSIVE_LOCK
);
6382 entry
->u
.Lock
.blocking
= !BooleanFlagOn(flags
, SL_FAIL_IMMEDIATELY
);
6385 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
6386 if (status
) goto out
;
6388 /* blocking locks keep trying until it succeeds */
6389 if (entry
->status
== ERROR_LOCK_FAILED
&& entry
->u
.Lock
.blocking
) {
6390 denied_lock_backoff(&poll_delay
);
6391 DbgP("returned ERROR_LOCK_FAILED; retrying in %llums\n",
6392 poll_delay
.QuadPart
/ MSEC_TO_RELATIVE_WAIT
);
6393 KeDelayExecutionThread(KernelMode
, FALSE
, &poll_delay
);
6394 entry
->state
= NFS41_WAITING_FOR_UPCALL
;
6398 status
= map_lock_errors(entry
->status
);
6399 RxContext
->CurrentIrp
->IoStatus
.Status
= status
;
6403 #ifdef ENABLE_TIMINGS
6404 t2
= KeQueryPerformanceCounter(NULL
);
6405 InterlockedIncrement(&lock
.tops
);
6406 InterlockedAdd64(&lock
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
6407 #ifdef ENABLE_INDV_TIMINGS
6408 DbgP("nfs41_Lock delta = %d op=%d sum=%d\n", t2
.QuadPart
- t1
.QuadPart
,
6409 lock
.tops
, lock
.ticks
);
6418 void print_unlock_args(
6419 PRX_CONTEXT RxContext
)
6421 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
6422 print_debug_header(RxContext
);
6423 if (LowIoContext
->Operation
== LOWIO_OP_UNLOCK_MULTIPLE
) {
6424 PLOWIO_LOCK_LIST lock
= LowIoContext
->ParamsFor
.Locks
.LockList
;
6425 DbgP("LOWIO_OP_UNLOCK_MULTIPLE:");
6427 DbgP(" (offset=%llu, length=%llu)", lock
->ByteOffset
, lock
->Length
);
6432 DbgP("LOWIO_OP_UNLOCK: offset=%llu, length=%llu\n",
6433 LowIoContext
->ParamsFor
.Locks
.ByteOffset
,
6434 LowIoContext
->ParamsFor
.Locks
.Length
);
6438 __inline ULONG
unlock_list_count(
6439 PLOWIO_LOCK_LIST lock
)
6450 NTSTATUS NTAPI
nfs41_Unlock(
6452 NTSTATUS
nfs41_Unlock(
6454 IN OUT PRX_CONTEXT RxContext
)
6456 NTSTATUS status
= STATUS_SUCCESS
;
6457 nfs41_updowncall_entry
*entry
;
6458 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
6459 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
6460 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
6461 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
6462 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
6463 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
6464 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
6465 #ifdef ENABLE_TIMINGS
6466 LARGE_INTEGER t1
, t2
;
6467 t1
= KeQueryPerformanceCounter(NULL
);
6471 print_lock_args(RxContext
);
6474 /* RxReleaseFcbResourceForThreadInMRx(RxContext, RxContext->pFcb,
6475 LowIoContext->ResourceThreadId); */
6477 status
= nfs41_UpcallCreate(NFS41_UNLOCK
, &nfs41_fobx
->sec_ctx
,
6478 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
6479 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
6480 if (status
) goto out
;
6482 if (LowIoContext
->Operation
== LOWIO_OP_UNLOCK_MULTIPLE
) {
6483 entry
->u
.Unlock
.count
= unlock_list_count(
6484 LowIoContext
->ParamsFor
.Locks
.LockList
);
6485 RtlCopyMemory(&entry
->u
.Unlock
.locks
,
6486 LowIoContext
->ParamsFor
.Locks
.LockList
,
6487 sizeof(LOWIO_LOCK_LIST
));
6489 entry
->u
.Unlock
.count
= 1;
6490 entry
->u
.Unlock
.locks
.ByteOffset
=
6491 LowIoContext
->ParamsFor
.Locks
.ByteOffset
;
6492 entry
->u
.Unlock
.locks
.Length
=
6493 LowIoContext
->ParamsFor
.Locks
.Length
;
6496 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
6497 if (status
) goto out
;
6499 status
= map_lock_errors(entry
->status
);
6500 RxContext
->CurrentIrp
->IoStatus
.Status
= status
;
6503 #ifdef ENABLE_TIMINGS
6504 t2
= KeQueryPerformanceCounter(NULL
);
6505 InterlockedIncrement(&unlock
.tops
);
6506 InterlockedAdd64(&unlock
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
6507 #ifdef ENABLE_INDV_TIMINGS
6508 DbgP("nfs41_Unlock delta = %d op=%d sum=%d\n", t2
.QuadPart
- t1
.QuadPart
,
6509 unlock
.tops
, unlock
.ticks
);
6518 NTSTATUS
map_symlink_errors(
6522 case NO_ERROR
: return STATUS_SUCCESS
;
6523 case ERROR_INVALID_REPARSE_DATA
: return STATUS_IO_REPARSE_DATA_INVALID
;
6524 case ERROR_NOT_A_REPARSE_POINT
: return STATUS_NOT_A_REPARSE_POINT
;
6525 case ERROR_ACCESS_DENIED
: return STATUS_ACCESS_DENIED
;
6526 case ERROR_NOT_EMPTY
: return STATUS_DIRECTORY_NOT_EMPTY
;
6527 case ERROR_OUTOFMEMORY
: return STATUS_INSUFFICIENT_RESOURCES
;
6528 case ERROR_INSUFFICIENT_BUFFER
: return STATUS_BUFFER_TOO_SMALL
;
6529 case STATUS_BUFFER_TOO_SMALL
:
6530 case ERROR_BUFFER_OVERFLOW
: return STATUS_BUFFER_OVERFLOW
;
6532 print_error("failed to map windows error %d to NTSTATUS; "
6533 "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", status
);
6534 case ERROR_BAD_NET_RESP
: return STATUS_INVALID_NETWORK_RESPONSE
;
6538 void print_reparse_buffer(
6539 PREPARSE_DATA_BUFFER Reparse
)
6541 UNICODE_STRING name
;
6542 DbgP("ReparseTag: %08X\n", Reparse
->ReparseTag
);
6543 DbgP("ReparseDataLength: %8u\n", Reparse
->ReparseDataLength
);
6544 DbgP("Reserved: %8u\n", Reparse
->Reserved
);
6545 DbgP("SubstituteNameOffset: %8u\n",
6546 Reparse
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
);
6547 DbgP("SubstituteNameLength: %8u\n",
6548 Reparse
->SymbolicLinkReparseBuffer
.SubstituteNameLength
);
6549 DbgP("PrintNameOffset: %8u\n",
6550 Reparse
->SymbolicLinkReparseBuffer
.PrintNameOffset
);
6551 DbgP("PrintNameLength: %8u\n",
6552 Reparse
->SymbolicLinkReparseBuffer
.PrintNameLength
);
6553 DbgP("Flags: %08X\n",
6554 Reparse
->SymbolicLinkReparseBuffer
.Flags
);
6556 name
.Buffer
= &Reparse
->SymbolicLinkReparseBuffer
.PathBuffer
[
6557 Reparse
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
/sizeof(WCHAR
)];
6558 name
.MaximumLength
= name
.Length
=
6559 Reparse
->SymbolicLinkReparseBuffer
.SubstituteNameLength
;
6560 DbgP("SubstituteName: %wZ\n", &name
);
6562 name
.Buffer
= &Reparse
->SymbolicLinkReparseBuffer
.PathBuffer
[
6563 Reparse
->SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(WCHAR
)];
6564 name
.MaximumLength
= name
.Length
=
6565 Reparse
->SymbolicLinkReparseBuffer
.PrintNameLength
;
6566 DbgP("PrintName: %wZ\n", &name
);
6569 NTSTATUS
check_nfs41_setreparse_args(
6570 IN PRX_CONTEXT RxContext
)
6572 NTSTATUS status
= STATUS_SUCCESS
;
6573 __notnull XXCTL_LOWIO_COMPONENT
*FsCtl
= &RxContext
->LowIoContext
.ParamsFor
.FsCtl
;
6574 __notnull PREPARSE_DATA_BUFFER Reparse
= (PREPARSE_DATA_BUFFER
)FsCtl
->pInputBuffer
;
6575 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
6576 __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext
=
6577 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
6578 const ULONG HeaderLen
= REPARSE_DATA_BUFFER_HEADER_SIZE
;
6581 if (VNetRootContext
->read_only
) {
6582 status
= STATUS_MEDIA_WRITE_PROTECTED
;
6585 if (!(SrvOpen
->DesiredAccess
& (FILE_WRITE_DATA
|FILE_WRITE_ATTRIBUTES
))) {
6586 status
= STATUS_ACCESS_DENIED
;
6590 /* must have a filename longer than vnetroot name,
6591 * or it's trying to operate on the volume itself */
6592 if (is_root_directory(RxContext
)) {
6593 status
= STATUS_INVALID_PARAMETER
;
6596 if (FsCtl
->pOutputBuffer
!= NULL
) {
6597 status
= STATUS_INVALID_PARAMETER
;
6601 /* validate input buffer and length */
6603 status
= STATUS_INVALID_BUFFER_SIZE
;
6607 if (FsCtl
->InputBufferLength
< HeaderLen
||
6608 FsCtl
->InputBufferLength
> MAXIMUM_REPARSE_DATA_BUFFER_SIZE
) {
6609 status
= STATUS_IO_REPARSE_DATA_INVALID
;
6612 if (FsCtl
->InputBufferLength
!= HeaderLen
+ Reparse
->ReparseDataLength
) {
6613 status
= STATUS_IO_REPARSE_DATA_INVALID
;
6617 /* validate reparse tag */
6618 if (!IsReparseTagValid(Reparse
->ReparseTag
)) {
6619 status
= STATUS_IO_REPARSE_TAG_INVALID
;
6622 if (Reparse
->ReparseTag
!= IO_REPARSE_TAG_SYMLINK
) {
6623 status
= STATUS_IO_REPARSE_TAG_MISMATCH
;
6630 NTSTATUS
nfs41_SetReparsePoint(
6631 IN OUT PRX_CONTEXT RxContext
)
6634 UNICODE_STRING TargetName
;
6635 __notnull XXCTL_LOWIO_COMPONENT
*FsCtl
= &RxContext
->LowIoContext
.ParamsFor
.FsCtl
;
6636 __notnull PREPARSE_DATA_BUFFER Reparse
= (PREPARSE_DATA_BUFFER
)FsCtl
->pInputBuffer
;
6637 __notnull PNFS41_FOBX Fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
6638 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
6639 __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext
=
6640 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
6641 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
6642 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
6643 nfs41_updowncall_entry
*entry
;
6645 #ifdef DEBUG_SYMLINK
6647 print_debug_header(RxContext
);
6648 print_reparse_buffer(Reparse
);
6650 status
= check_nfs41_setreparse_args(RxContext
);
6651 if (status
) goto out
;
6653 TargetName
.MaximumLength
= TargetName
.Length
=
6654 Reparse
->SymbolicLinkReparseBuffer
.PrintNameLength
;
6655 TargetName
.Buffer
= &Reparse
->SymbolicLinkReparseBuffer
.PathBuffer
[
6656 Reparse
->SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(WCHAR
)];
6658 status
= nfs41_UpcallCreate(NFS41_SYMLINK
, &Fobx
->sec_ctx
,
6659 VNetRootContext
->session
, Fobx
->nfs41_open_state
,
6660 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
6661 if (status
) goto out
;
6663 entry
->u
.Symlink
.target
= &TargetName
;
6664 entry
->u
.Symlink
.set
= TRUE
;
6666 status
= nfs41_UpcallWaitForReply(entry
, VNetRootContext
->timeout
);
6667 if (status
) goto out
;
6669 status
= map_symlink_errors(entry
->status
);
6672 #ifdef DEBUG_SYMLINK
6678 NTSTATUS
check_nfs41_getreparse_args(
6679 PRX_CONTEXT RxContext
)
6681 NTSTATUS status
= STATUS_SUCCESS
;
6682 XXCTL_LOWIO_COMPONENT
*FsCtl
= &RxContext
->LowIoContext
.ParamsFor
.FsCtl
;
6683 const USHORT HeaderLen
= FIELD_OFFSET(REPARSE_DATA_BUFFER
,
6684 SymbolicLinkReparseBuffer
.PathBuffer
);
6686 /* must have a filename longer than vnetroot name,
6687 * or it's trying to operate on the volume itself */
6688 if (is_root_directory(RxContext
)) {
6689 status
= STATUS_INVALID_PARAMETER
;
6692 /* ifs reparse tests expect STATUS_INVALID_PARAMETER,
6693 * but 'dir' passes a buffer here when querying symlinks
6694 if (FsCtl->pInputBuffer != NULL) {
6695 status = STATUS_INVALID_PARAMETER;
6698 if (!FsCtl
->pOutputBuffer
) {
6699 status
= STATUS_INVALID_USER_BUFFER
;
6702 if (!BooleanFlagOn(RxContext
->pFcb
->Attributes
,
6703 FILE_ATTRIBUTE_REPARSE_POINT
)) {
6704 status
= STATUS_NOT_A_REPARSE_POINT
;
6705 DbgP("FILE_ATTRIBUTE_REPARSE_POINT is not set!\n");
6709 if (FsCtl
->OutputBufferLength
< HeaderLen
) {
6710 RxContext
->InformationToReturn
= HeaderLen
;
6711 status
= STATUS_BUFFER_TOO_SMALL
;
6718 NTSTATUS
nfs41_GetReparsePoint(
6719 IN OUT PRX_CONTEXT RxContext
)
6722 UNICODE_STRING TargetName
;
6723 XXCTL_LOWIO_COMPONENT
*FsCtl
= &RxContext
->LowIoContext
.ParamsFor
.FsCtl
;
6724 __notnull PNFS41_FOBX Fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
6725 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
6726 __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext
=
6727 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
6728 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
6729 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
6730 nfs41_updowncall_entry
*entry
;
6731 const USHORT HeaderLen
= FIELD_OFFSET(REPARSE_DATA_BUFFER
,
6732 SymbolicLinkReparseBuffer
.PathBuffer
);
6734 #ifdef DEBUG_SYMLINK
6737 status
= check_nfs41_getreparse_args(RxContext
);
6738 if (status
) goto out
;
6740 TargetName
.Buffer
= (PWCH
)((PBYTE
)FsCtl
->pOutputBuffer
+ HeaderLen
);
6741 TargetName
.MaximumLength
= (USHORT
)min(FsCtl
->OutputBufferLength
-
6744 status
= nfs41_UpcallCreate(NFS41_SYMLINK
, &Fobx
->sec_ctx
,
6745 VNetRootContext
->session
, Fobx
->nfs41_open_state
,
6746 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
6747 if (status
) goto out
;
6749 entry
->u
.Symlink
.target
= &TargetName
;
6750 entry
->u
.Symlink
.set
= FALSE
;
6752 status
= nfs41_UpcallWaitForReply(entry
, VNetRootContext
->timeout
);
6753 if (status
) goto out
;
6755 status
= map_symlink_errors(entry
->status
);
6756 if (status
== STATUS_SUCCESS
) {
6757 /* fill in the output buffer */
6758 PREPARSE_DATA_BUFFER Reparse
= (PREPARSE_DATA_BUFFER
)
6759 FsCtl
->pOutputBuffer
;
6760 Reparse
->ReparseTag
= IO_REPARSE_TAG_SYMLINK
;
6761 Reparse
->ReparseDataLength
= HeaderLen
+ TargetName
.Length
-
6762 REPARSE_DATA_BUFFER_HEADER_SIZE
;
6763 Reparse
->Reserved
= 0;
6764 Reparse
->SymbolicLinkReparseBuffer
.Flags
= SYMLINK_FLAG_RELATIVE
;
6765 /* PrintName and SubstituteName point to the same string */
6766 Reparse
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
= 0;
6767 Reparse
->SymbolicLinkReparseBuffer
.SubstituteNameLength
=
6769 Reparse
->SymbolicLinkReparseBuffer
.PrintNameOffset
= 0;
6770 Reparse
->SymbolicLinkReparseBuffer
.PrintNameLength
= TargetName
.Length
;
6771 print_reparse_buffer(Reparse
);
6773 RxContext
->IoStatusBlock
.Information
= HeaderLen
+ TargetName
.Length
;
6774 } else if (status
== STATUS_BUFFER_TOO_SMALL
) {
6775 RxContext
->InformationToReturn
= HeaderLen
+ TargetName
.Length
;
6779 #ifdef DEBUG_SYMLINK
6786 NTSTATUS NTAPI
nfs41_FsCtl(
6788 NTSTATUS
nfs41_FsCtl(
6790 IN OUT PRX_CONTEXT RxContext
)
6792 NTSTATUS status
= STATUS_INVALID_DEVICE_REQUEST
;
6795 print_debug_header(RxContext
);
6797 switch (RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
) {
6798 case FSCTL_SET_REPARSE_POINT
:
6799 status
= nfs41_SetReparsePoint(RxContext
);
6802 case FSCTL_GET_REPARSE_POINT
:
6803 status
= nfs41_GetReparsePoint(RxContext
);
6807 DbgP("FsControlCode: %d\n",
6808 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
);
6818 NTSTATUS NTAPI
nfs41_CompleteBufferingStateChangeRequest(
6820 NTSTATUS
nfs41_CompleteBufferingStateChangeRequest(
6822 IN OUT PRX_CONTEXT RxContext
,
6823 IN OUT PMRX_SRV_OPEN SrvOpen
,
6826 return STATUS_SUCCESS
;
6830 NTSTATUS NTAPI
nfs41_FsdDispatch (
6832 NTSTATUS
nfs41_FsdDispatch (
6834 IN PDEVICE_OBJECT dev
,
6837 #ifdef DEBUG_FSDDISPATCH
6838 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
6842 #ifdef DEBUG_FSDDISPATCH
6844 DbgP("CURRENT IRP = %d.%d\n", IrpSp
->MajorFunction
, IrpSp
->MinorFunction
);
6845 if(IrpSp
->FileObject
)
6846 DbgP("FileOject %p Filename %wZ\n", IrpSp
->FileObject
,
6847 &IrpSp
->FileObject
->FileName
);
6850 if (dev
!= (PDEVICE_OBJECT
)nfs41_dev
) {
6851 print_error("*** not ours ***\n");
6852 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
6853 Irp
->IoStatus
.Information
= 0;
6854 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6855 status
= STATUS_INVALID_DEVICE_REQUEST
;
6859 status
= RxFsdDispatch((PRDBSS_DEVICE_OBJECT
)dev
,Irp
);
6860 /* AGLO: 08/05/2009 - looks like RxFsdDispatch frees IrpSp */
6863 #ifdef DEBUG_FSDDISPATCH
6864 DbgP("IoStatus status = 0x%x info = 0x%x\n", Irp
->IoStatus
.Status
,
6865 Irp
->IoStatus
.Information
);
6872 NTSTATUS NTAPI
nfs41_Unimplemented(
6874 NTSTATUS
nfs41_Unimplemented(
6876 PRX_CONTEXT RxContext
)
6878 return STATUS_NOT_IMPLEMENTED
;
6882 NTSTATUS NTAPI
nfs41_AreFilesAliased(
6884 NTSTATUS
nfs41_AreFilesAliased(
6889 return STATUS_NOT_IMPLEMENTED
;
6892 NTSTATUS
nfs41_init_ops()
6896 ZeroAndInitializeNodeType(&nfs41_ops
, RDBSS_NTC_MINIRDR_DISPATCH
,
6897 sizeof(MINIRDR_DISPATCH
));
6899 nfs41_ops
.MRxFlags
= (RDBSS_MANAGE_NET_ROOT_EXTENSION
|
6900 RDBSS_MANAGE_V_NET_ROOT_EXTENSION
|
6901 RDBSS_MANAGE_FCB_EXTENSION
|
6902 RDBSS_MANAGE_FOBX_EXTENSION
);
6904 nfs41_ops
.MRxSrvCallSize
= 0; // srvcall extension is not handled in rdbss
6905 nfs41_ops
.MRxNetRootSize
= sizeof(NFS41_NETROOT_EXTENSION
);
6906 nfs41_ops
.MRxVNetRootSize
= sizeof(NFS41_V_NET_ROOT_EXTENSION
);
6907 nfs41_ops
.MRxFcbSize
= sizeof(NFS41_FCB
);
6908 nfs41_ops
.MRxFobxSize
= sizeof(NFS41_FOBX
);
6910 // Mini redirector cancel routine ..
6912 nfs41_ops
.MRxCancel
= NULL
;
6915 // Mini redirector Start/Stop. Each mini-rdr can be started or stopped
6916 // while the others continue to operate.
6919 nfs41_ops
.MRxStart
= nfs41_Start
;
6920 nfs41_ops
.MRxStop
= nfs41_Stop
;
6921 nfs41_ops
.MRxDevFcbXXXControlFile
= nfs41_DevFcbXXXControlFile
;
6924 // Mini redirector name resolution.
6927 nfs41_ops
.MRxCreateSrvCall
= nfs41_CreateSrvCall
;
6928 nfs41_ops
.MRxSrvCallWinnerNotify
= nfs41_SrvCallWinnerNotify
;
6929 nfs41_ops
.MRxCreateVNetRoot
= nfs41_CreateVNetRoot
;
6930 nfs41_ops
.MRxExtractNetRootName
= nfs41_ExtractNetRootName
;
6931 nfs41_ops
.MRxFinalizeSrvCall
= nfs41_FinalizeSrvCall
;
6932 nfs41_ops
.MRxFinalizeNetRoot
= nfs41_FinalizeNetRoot
;
6933 nfs41_ops
.MRxFinalizeVNetRoot
= nfs41_FinalizeVNetRoot
;
6936 // File System Object Creation/Deletion.
6939 nfs41_ops
.MRxCreate
= nfs41_Create
;
6940 nfs41_ops
.MRxCollapseOpen
= nfs41_CollapseOpen
;
6941 nfs41_ops
.MRxShouldTryToCollapseThisOpen
= nfs41_ShouldTryToCollapseThisOpen
;
6942 nfs41_ops
.MRxExtendForCache
= nfs41_ExtendForCache
;
6943 nfs41_ops
.MRxExtendForNonCache
= nfs41_ExtendForCache
;
6944 nfs41_ops
.MRxCloseSrvOpen
= nfs41_CloseSrvOpen
;
6945 nfs41_ops
.MRxFlush
= nfs41_Flush
;
6946 nfs41_ops
.MRxDeallocateForFcb
= nfs41_DeallocateForFcb
;
6947 nfs41_ops
.MRxDeallocateForFobx
= nfs41_DeallocateForFobx
;
6948 nfs41_ops
.MRxIsLockRealizable
= nfs41_IsLockRealizable
;
6951 // File System Objects query/Set
6954 nfs41_ops
.MRxQueryDirectory
= nfs41_QueryDirectory
;
6955 nfs41_ops
.MRxQueryVolumeInfo
= nfs41_QueryVolumeInformation
;
6956 nfs41_ops
.MRxQueryEaInfo
= nfs41_QueryEaInformation
;
6957 nfs41_ops
.MRxSetEaInfo
= nfs41_SetEaInformation
;
6958 nfs41_ops
.MRxQuerySdInfo
= nfs41_QuerySecurityInformation
;
6959 nfs41_ops
.MRxSetSdInfo
= nfs41_SetSecurityInformation
;
6960 nfs41_ops
.MRxQueryFileInfo
= nfs41_QueryFileInformation
;
6961 nfs41_ops
.MRxSetFileInfo
= nfs41_SetFileInformation
;
6964 // Buffering state change
6967 nfs41_ops
.MRxComputeNewBufferingState
= nfs41_ComputeNewBufferingState
;
6970 // File System Object I/O
6973 nfs41_ops
.MRxLowIOSubmit
[LOWIO_OP_READ
] = nfs41_Read
;
6974 nfs41_ops
.MRxLowIOSubmit
[LOWIO_OP_WRITE
] = nfs41_Write
;
6975 nfs41_ops
.MRxLowIOSubmit
[LOWIO_OP_SHAREDLOCK
] = nfs41_Lock
;
6976 nfs41_ops
.MRxLowIOSubmit
[LOWIO_OP_EXCLUSIVELOCK
] = nfs41_Lock
;
6977 nfs41_ops
.MRxLowIOSubmit
[LOWIO_OP_UNLOCK
] = nfs41_Unlock
;
6978 nfs41_ops
.MRxLowIOSubmit
[LOWIO_OP_UNLOCK_MULTIPLE
] = nfs41_Unlock
;
6979 nfs41_ops
.MRxLowIOSubmit
[LOWIO_OP_FSCTL
] = nfs41_FsCtl
;
6985 nfs41_ops
.MRxCompleteBufferingStateChangeRequest
=
6986 nfs41_CompleteBufferingStateChangeRequest
;
6987 nfs41_ops
.MRxIsValidDirectory
= nfs41_IsValidDirectory
;
6989 nfs41_ops
.MRxTruncate
= nfs41_Unimplemented
;
6990 nfs41_ops
.MRxZeroExtend
= nfs41_Unimplemented
;
6991 nfs41_ops
.MRxAreFilesAliased
= nfs41_AreFilesAliased
;
6992 nfs41_ops
.MRxQueryQuotaInfo
= nfs41_Unimplemented
;
6993 nfs41_ops
.MRxSetQuotaInfo
= nfs41_Unimplemented
;
6994 nfs41_ops
.MRxSetVolumeInfo
= nfs41_Unimplemented
;
6997 return(STATUS_SUCCESS
);
7000 KSTART_ROUTINE fcbopen_main
;
7002 VOID NTAPI
fcbopen_main(PVOID ctx
)
7004 VOID
fcbopen_main(PVOID ctx
)
7008 LARGE_INTEGER timeout
;
7011 timeout
.QuadPart
= RELATIVE(SECONDS(30));
7014 nfs41_fcb_list_entry
*cur
;
7015 status
= KeDelayExecutionThread(KernelMode
, TRUE
, &timeout
);
7016 ExAcquireFastMutex(&fcblistLock
);
7017 pEntry
= openlist
.head
.Flink
;
7018 while (!IsListEmpty(&openlist
.head
)) {
7019 PNFS41_NETROOT_EXTENSION pNetRootContext
;
7020 nfs41_updowncall_entry
*entry
;
7021 FILE_BASIC_INFORMATION binfo
;
7022 PNFS41_FCB nfs41_fcb
;
7023 cur
= (nfs41_fcb_list_entry
*)CONTAINING_RECORD(pEntry
,
7024 nfs41_fcb_list_entry
, next
);
7026 #ifdef DEBUG_TIME_BASED_COHERENCY
7027 DbgP("fcbopen_main: Checking attributes for fcb=%p "
7028 "change_time=%llu skipping=%d\n", cur
->fcb
,
7029 cur
->ChangeTime
, cur
->skip
);
7031 if (cur
->skip
) goto out
;
7033 NFS41GetNetRootExtension(cur
->fcb
->pNetRoot
);
7034 /* place an upcall for this srv_open */
7035 status
= nfs41_UpcallCreate(NFS41_FILE_QUERY
,
7036 &cur
->nfs41_fobx
->sec_ctx
, cur
->session
,
7037 cur
->nfs41_fobx
->nfs41_open_state
,
7038 pNetRootContext
->nfs41d_version
, NULL
, &entry
);
7039 if (status
) goto out
;
7041 entry
->u
.QueryFile
.InfoClass
= FileBasicInformation
;
7042 entry
->buf
= &binfo
;
7043 entry
->buf_len
= sizeof(binfo
);
7045 status
= nfs41_UpcallWaitForReply(entry
, UPCALL_TIMEOUT_DEFAULT
);
7046 if (status
) goto out
;
7048 if (cur
->ChangeTime
!= entry
->ChangeTime
) {
7049 ULONG flag
= DISABLE_CACHING
;
7050 PMRX_SRV_OPEN srv_open
;
7051 PLIST_ENTRY psrvEntry
;
7052 #ifdef DEBUG_TIME_BASED_COHERENCY
7053 DbgP("fcbopen_main: old ctime=%llu new_ctime=%llu\n",
7054 cur
->ChangeTime
, entry
->ChangeTime
);
7056 cur
->ChangeTime
= entry
->ChangeTime
;
7058 psrvEntry
= &cur
->fcb
->SrvOpenList
;
7059 psrvEntry
= psrvEntry
->Flink
;
7060 while (!IsListEmpty(&cur
->fcb
->SrvOpenList
)) {
7061 srv_open
= (PMRX_SRV_OPEN
)CONTAINING_RECORD(psrvEntry
,
7062 MRX_SRV_OPEN
, SrvOpenQLinks
);
7063 if (srv_open
->DesiredAccess
&
7064 (FILE_READ_DATA
| FILE_WRITE_DATA
| FILE_APPEND_DATA
)) {
7065 #ifdef DEBUG_TIME_BASED_COHERENCY
7066 DbgP("fcbopen_main: ************ Invalidate the cache %wZ"
7067 "************\n", srv_open
->pAlreadyPrefixedName
);
7069 RxIndicateChangeOfBufferingStateForSrvOpen(
7070 cur
->fcb
->pNetRoot
->pSrvCall
, srv_open
,
7071 srv_open
->Key
, ULongToPtr(flag
));
7073 if (psrvEntry
->Flink
== &cur
->fcb
->SrvOpenList
) {
7074 #ifdef DEBUG_TIME_BASED_COHERENCY
7075 DbgP("fcbopen_main: reached end of srvopen for fcb %p\n",
7080 psrvEntry
= psrvEntry
->Flink
;
7083 nfs41_fcb
= (PNFS41_FCB
)cur
->fcb
->Context
;
7084 nfs41_fcb
->changeattr
= entry
->ChangeTime
;
7087 if (pEntry
->Flink
== &openlist
.head
) {
7088 #ifdef DEBUG_TIME_BASED_COHERENCY
7089 DbgP("fcbopen_main: reached end of the fcb list\n");
7093 pEntry
= pEntry
->Flink
;
7095 ExReleaseFastMutex(&fcblistLock
);
7101 NTSTATUS NTAPI
DriverEntry(
7103 NTSTATUS
DriverEntry(
7105 IN PDRIVER_OBJECT drv
,
7106 IN PUNICODE_STRING path
)
7110 UNICODE_STRING dev_name
, user_dev_name
;
7111 PNFS41_DEVICE_EXTENSION dev_exts
;
7112 TIME_FIELDS jan_1_1970
= {1970, 1, 1, 0, 0, 0, 0, 0};
7113 ACCESS_MASK mask
= 0;
7114 OBJECT_ATTRIBUTES oattrs
;
7118 status
= RxDriverEntry(drv
, path
);
7119 if (status
!= STATUS_SUCCESS
) {
7120 print_error("RxDriverEntry failed: %08lx\n", status
);
7124 RtlInitUnicodeString(&dev_name
, NFS41_DEVICE_NAME
);
7125 SetFlag(flags
, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS
);
7127 status
= nfs41_init_ops();
7128 if (status
!= STATUS_SUCCESS
) {
7129 print_error("nfs41_init_ops failed to initialize dispatch table\n");
7133 DbgP("calling RxRegisterMinirdr\n");
7134 status
= RxRegisterMinirdr(&nfs41_dev
, drv
, &nfs41_ops
, flags
, &dev_name
,
7135 sizeof(NFS41_DEVICE_EXTENSION
),
7136 FILE_DEVICE_NETWORK_FILE_SYSTEM
, FILE_REMOTE_DEVICE
);
7137 if (status
!= STATUS_SUCCESS
) {
7138 print_error("RxRegisterMinirdr failed: %08lx\n", status
);
7142 nfs41_dev
->Flags
|= DO_BUFFERED_IO
;
7145 dev_exts
= (PNFS41_DEVICE_EXTENSION
)
7146 ((PBYTE
)(nfs41_dev
) + sizeof(RDBSS_DEVICE_OBJECT
));
7148 RxDefineNode(dev_exts
, NFS41_DEVICE_EXTENSION
);
7149 dev_exts
->DeviceObject
= nfs41_dev
;
7150 nfs41_create_volume_info((PFILE_FS_VOLUME_INFORMATION
)dev_exts
->VolAttrs
,
7151 &dev_exts
->VolAttrsLen
);
7153 RtlInitUnicodeString(&user_dev_name
, NFS41_SHADOW_DEVICE_NAME
);
7154 DbgP("calling IoCreateSymbolicLink %wZ %wZ\n", &user_dev_name
, &dev_name
);
7155 status
= IoCreateSymbolicLink(&user_dev_name
, &dev_name
);
7156 if (status
!= STATUS_SUCCESS
) {
7157 print_error("Device name IoCreateSymbolicLink failed: %08lx\n", status
);
7158 goto out_unregister
;
7161 KeInitializeEvent(&upcallEvent
, SynchronizationEvent
, FALSE
);
7162 ExInitializeFastMutex(&upcallLock
);
7163 ExInitializeFastMutex(&downcallLock
);
7164 ExInitializeFastMutex(&xidLock
);
7165 ExInitializeFastMutex(&openOwnerLock
);
7166 ExInitializeFastMutex(&fcblistLock
);
7167 InitializeListHead(&upcall
.head
);
7168 InitializeListHead(&downcall
.head
);
7169 InitializeListHead(&openlist
.head
);
7170 InitializeObjectAttributes(&oattrs
, NULL
, OBJ_KERNEL_HANDLE
, NULL
, NULL
);
7171 status
= PsCreateSystemThread(&dev_exts
->openlistHandle
, mask
,
7172 &oattrs
, NULL
, NULL
, &fcbopen_main
, NULL
);
7173 if (status
!= STATUS_SUCCESS
)
7174 goto out_unregister
;
7176 drv
->DriverUnload
= nfs41_driver_unload
;
7178 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
7179 drv
->MajorFunction
[i
] = (PDRIVER_DISPATCH
)nfs41_FsdDispatch
;
7181 RtlTimeFieldsToTime(&jan_1_1970
, &unix_time_diff
);
7184 if (status
!= STATUS_SUCCESS
)
7185 RxUnregisterMinirdr(nfs41_dev
);
7192 VOID NTAPI
nfs41_driver_unload(IN PDRIVER_OBJECT drv
)
7194 VOID
nfs41_driver_unload(IN PDRIVER_OBJECT drv
)
7197 PRX_CONTEXT RxContext
;
7199 UNICODE_STRING dev_name
, pipe_name
;
7203 RxContext
= RxCreateRxContext(NULL
, nfs41_dev
, RX_CONTEXT_FLAG_IN_FSP
);
7204 if (RxContext
== NULL
) {
7205 status
= STATUS_INSUFFICIENT_RESOURCES
;
7208 status
= RxStopMinirdr(RxContext
, &RxContext
->PostRequest
);
7209 RxDereferenceAndDeleteRxContext(RxContext
);
7212 RtlInitUnicodeString(&dev_name
, NFS41_SHADOW_DEVICE_NAME
);
7213 status
= IoDeleteSymbolicLink(&dev_name
);
7214 if (status
!= STATUS_SUCCESS
) {
7215 print_error("couldn't delete device symbolic link\n");
7217 RtlInitUnicodeString(&pipe_name
, NFS41_SHADOW_PIPE_NAME
);
7218 status
= IoDeleteSymbolicLink(&pipe_name
);
7219 if (status
!= STATUS_SUCCESS
) {
7220 print_error("couldn't delete pipe symbolic link\n");
7224 DbgP("driver unloaded %p\n", drv
);