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_FSDDISPATCH
50 #define DEBUG_MARSHAL_HEADER
51 #define DEBUG_MARSHAL_DETAIL
55 #define DEBUG_INVALIDATE_CACHE
58 //#define DEBUG_DIR_QUERY
59 //#define DEBUG_FILE_QUERY
60 //#define DEBUG_FILE_SET
61 //#define DEBUG_ACL_QUERY
62 //#define DEBUG_ACL_SET
63 //#define DEBUG_EA_QUERY
64 //#define DEBUG_EA_SET
67 #define DEBUG_TIME_BASED_COHERENCY
69 //#define DEBUG_VOLUME_QUERY
71 //#define ENABLE_TIMINGS
72 //#define ENABLE_INDV_TIMINGS
74 typedef struct __nfs41_timings
{
79 nfs41_timings lookup
, readdir
, open
, close
, getattr
, setattr
, getacl
, setacl
, volume
,
80 read
, write
, lock
, unlock
, setexattr
, getexattr
;
82 DRIVER_INITIALIZE DriverEntry
;
83 DRIVER_UNLOAD nfs41_driver_unload
;
84 DRIVER_DISPATCH ( nfs41_FsdDispatch
);
86 struct _MINIRDR_DISPATCH nfs41_ops
;
87 PRDBSS_DEVICE_OBJECT nfs41_dev
;
89 #define DISABLE_CACHING 0
90 #define ENABLE_READ_CACHING 1
91 #define ENABLE_WRITE_CACHING 2
92 #define ENABLE_READWRITE_CACHING 3
94 #define NFS41_MM_POOLTAG ('nfs4')
95 #define NFS41_MM_POOLTAG_ACL ('acls')
96 #define NFS41_MM_POOLTAG_MOUNT ('mnts')
97 #define NFS41_MM_POOLTAG_OPEN ('open')
98 #define NFS41_MM_POOLTAG_UP ('upca')
99 #define NFS41_MM_POOLTAG_DOWN ('down')
102 FAST_MUTEX upcallLock
, downcallLock
, fcblistLock
;
104 FAST_MUTEX openOwnerLock
;
107 LONG open_owner_id
= 1;
109 #define DECLARE_CONST_ANSI_STRING(_var, _string) \
110 const CHAR _var ## _buffer[] = _string; \
111 const ANSI_STRING _var = { sizeof(_string) - sizeof(CHAR), \
112 sizeof(_string), (PCH) _var ## _buffer }
113 #define RELATIVE(wait) (-(wait))
114 #define NANOSECONDS(nanos) (((signed __int64)(nanos)) / 100L)
115 #define MICROSECONDS(micros) (((signed __int64)(micros)) * NANOSECONDS(1000L))
116 #define MILLISECONDS(milli) (((signed __int64)(milli)) * MICROSECONDS(1000L))
117 #define SECONDS(seconds) (((signed __int64)(seconds)) * MILLISECONDS(1000L))
119 DECLARE_CONST_ANSI_STRING(NfsV3Attributes
, "NfsV3Attributes");
120 DECLARE_CONST_ANSI_STRING(NfsSymlinkTargetName
, "NfsSymlinkTargetName");
121 DECLARE_CONST_ANSI_STRING(NfsActOnLink
, "NfsActOnLink");
123 INLINE BOOL
AnsiStrEq(
124 IN
const ANSI_STRING
*lhs
,
126 IN
const UCHAR rhs_len
)
128 return lhs
->Length
== rhs_len
&&
129 RtlCompareMemory(lhs
->Buffer
, rhs
, rhs_len
) == rhs_len
;
132 typedef struct _nfs3_attrs
{
133 DWORD type
, mode
, nlink
, uid
, gid
, filler1
;
134 LARGE_INTEGER size
, used
;
139 LONGLONG fsid
, fileid
;
140 LONGLONG atime
, mtime
, ctime
;
142 LARGE_INTEGER unix_time_diff
; //needed to convert windows time to unix
154 typedef enum _nfs41_updowncall_state
{
155 NFS41_WAITING_FOR_UPCALL
,
156 NFS41_WAITING_FOR_DOWNCALL
,
157 NFS41_DONE_PROCESSING
,
159 } nfs41_updowncall_state
;
166 typedef struct _updowncall_entry
{
171 nfs41_updowncall_state state
;
177 SECURITY_CLIENT_CONTEXT sec_ctx
;
178 PSECURITY_CLIENT_CONTEXT psec_ctx
;
181 PUNICODE_STRING filename
;
184 ULONGLONG ChangeTime
;
187 PUNICODE_STRING srv_name
;
188 PUNICODE_STRING root
;
189 PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs
;
198 PRX_CONTEXT rxcontext
;
208 LOWIO_LOCK_LIST locks
;
211 FILE_BASIC_INFORMATION binfo
;
212 FILE_STANDARD_INFORMATION sinfo
;
213 UNICODE_STRING symlink
;
224 BOOLEAN symlink_embedded
;
234 PUNICODE_STRING filter
;
235 FILE_INFORMATION_CLASS InfoClass
;
236 BOOLEAN restart_scan
;
237 BOOLEAN return_single
;
238 BOOLEAN initial_query
;
243 FILE_INFORMATION_CLASS InfoClass
;
253 BOOLEAN ReturnSingleEntry
;
257 PUNICODE_STRING target
;
261 FS_INFORMATION_CLASS query
;
264 SECURITY_INFORMATION query
;
268 } nfs41_updowncall_entry
;
270 typedef struct _updowncall_list
{
272 } nfs41_updowncall_list
;
273 nfs41_updowncall_list upcall
, downcall
;
275 typedef struct _nfs41_mount_entry
{
278 HANDLE authsys_session
;
284 typedef struct _nfs41_mount_list
{
288 #define nfs41_AddEntry(lock,list,pEntry) \
289 ExAcquireFastMutex(&lock); \
290 InsertTailList(&(list).head, &(pEntry)->next); \
291 ExReleaseFastMutex(&lock);
292 #define nfs41_RemoveFirst(lock,list,pEntry) \
293 ExAcquireFastMutex(&lock); \
294 pEntry = (IsListEmpty(&(list).head) \
296 : RemoveHeadList(&(list).head)); \
297 ExReleaseFastMutex(&lock);
298 #define nfs41_RemoveEntry(lock,pEntry) \
299 ExAcquireFastMutex(&lock); \
300 RemoveEntryList(&pEntry->next); \
301 ExReleaseFastMutex(&lock);
302 #define nfs41_IsListEmpty(lock,list,flag) \
303 ExAcquireFastMutex(&lock); \
304 flag = IsListEmpty(&(list).head); \
305 ExReleaseFastMutex(&lock);
306 #define nfs41_GetFirstEntry(lock,list,pEntry) \
307 ExAcquireFastMutex(&lock); \
308 pEntry = (IsListEmpty(&(list).head) \
310 : (nfs41_updowncall_entry *) \
311 (CONTAINING_RECORD((list).head.Flink, \
312 nfs41_updowncall_entry, \
314 ExReleaseFastMutex(&lock);
315 #define nfs41_GetFirstMountEntry(lock,list,pEntry) \
316 ExAcquireFastMutex(&lock); \
317 pEntry = (IsListEmpty(&(list).head) \
319 : (nfs41_mount_entry *) \
320 (CONTAINING_RECORD((list).head.Flink, \
323 ExReleaseFastMutex(&lock);
325 /* In order to cooperate with other network providers,
326 * we only claim paths of the format '\\server\nfs4\path' */
327 DECLARE_CONST_UNICODE_STRING(NfsPrefix
, L
"\\nfs4");
328 DECLARE_CONST_UNICODE_STRING(AUTH_SYS_NAME
, L
"sys");
329 DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5_NAME
, L
"krb5");
330 DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5I_NAME
, L
"krb5i");
331 DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5P_NAME
, L
"krb5p");
332 DECLARE_CONST_UNICODE_STRING(SLASH
, L
"\\");
333 DECLARE_CONST_UNICODE_STRING(EMPTY_STRING
, L
"");
335 #define SERVER_NAME_BUFFER_SIZE 1024
336 #define MOUNT_CONFIG_RW_SIZE_MIN 1024
337 #define MOUNT_CONFIG_RW_SIZE_DEFAULT 1048576
338 #define MOUNT_CONFIG_RW_SIZE_MAX 1048576
339 #define MAX_SEC_FLAVOR_LEN 12
340 #define UPCALL_TIMEOUT_DEFAULT 50 /* in seconds */
342 typedef struct _NFS41_MOUNT_CONFIG
{
348 WCHAR srv_buffer
[SERVER_NAME_BUFFER_SIZE
];
349 UNICODE_STRING SrvName
;
350 WCHAR mntpt_buffer
[MAX_PATH
];
351 UNICODE_STRING MntPt
;
352 WCHAR sec_flavor
[MAX_SEC_FLAVOR_LEN
];
353 UNICODE_STRING SecFlavor
;
355 } NFS41_MOUNT_CONFIG
, *PNFS41_MOUNT_CONFIG
;
357 typedef struct _NFS41_NETROOT_EXTENSION
{
358 NODE_TYPE_CODE NodeTypeCode
;
359 NODE_BYTE_SIZE NodeByteSize
;
360 DWORD nfs41d_version
;
362 FAST_MUTEX mountLock
;
363 nfs41_mount_list mounts
;
364 } NFS41_NETROOT_EXTENSION
, *PNFS41_NETROOT_EXTENSION
;
365 #define NFS41GetNetRootExtension(pNetRoot) \
366 (((pNetRoot) == NULL) ? NULL : \
367 (PNFS41_NETROOT_EXTENSION)((pNetRoot)->Context))
369 /* FileSystemName as reported by FileFsAttributeInfo query */
370 #define FS_NAME L"NFS"
371 #define FS_NAME_LEN (sizeof(FS_NAME) - sizeof(WCHAR))
372 #define FS_ATTR_LEN (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + FS_NAME_LEN)
374 /* FileSystemName as reported by FileFsAttributeInfo query */
375 #define VOL_NAME L"PnfsVolume"
376 #define VOL_NAME_LEN (sizeof(VOL_NAME) - sizeof(WCHAR))
377 #define VOL_ATTR_LEN (sizeof(FILE_FS_VOLUME_INFORMATION) + VOL_NAME_LEN)
379 typedef struct _NFS41_V_NET_ROOT_EXTENSION
{
380 NODE_TYPE_CODE NodeTypeCode
;
381 NODE_BYTE_SIZE NodeByteSize
;
383 FILE_FS_ATTRIBUTE_INFORMATION FsAttrs
;
390 #define STORE_MOUNT_SEC_CONTEXT
391 #ifdef STORE_MOUNT_SEC_CONTEXT
392 SECURITY_CLIENT_CONTEXT mount_sec_ctx
;
394 } NFS41_V_NET_ROOT_EXTENSION
, *PNFS41_V_NET_ROOT_EXTENSION
;
395 #define NFS41GetVNetRootExtension(pVNetRoot) \
396 (((pVNetRoot) == NULL) ? NULL : \
397 (PNFS41_V_NET_ROOT_EXTENSION)((pVNetRoot)->Context))
399 typedef struct _NFS41_FCB
{
400 NODE_TYPE_CODE NodeTypeCode
;
401 NODE_BYTE_SIZE NodeByteSize
;
402 FILE_BASIC_INFORMATION BasicInfo
;
403 FILE_STANDARD_INFORMATION StandardInfo
;
405 BOOLEAN DeletePending
;
407 ULONGLONG changeattr
;
408 } NFS41_FCB
, *PNFS41_FCB
;
409 #define NFS41GetFcbExtension(pFcb) \
410 (((pFcb) == NULL) ? NULL : (PNFS41_FCB)((pFcb)->Context))
412 typedef struct _NFS41_FOBX
{
413 NODE_TYPE_CODE NodeTypeCode
;
414 NODE_BYTE_SIZE NodeByteSize
;
416 HANDLE nfs41_open_state
;
417 SECURITY_CLIENT_CONTEXT sec_ctx
;
424 } NFS41_FOBX
, *PNFS41_FOBX
;
425 #define NFS41GetFobxExtension(pFobx) \
426 (((pFobx) == NULL) ? NULL : (PNFS41_FOBX)((pFobx)->Context))
428 typedef struct _NFS41_SERVER_ENTRY
{
429 PMRX_SRV_CALL pRdbssSrvCall
;
430 WCHAR NameBuffer
[SERVER_NAME_BUFFER_SIZE
];
431 UNICODE_STRING Name
; // the server name.
432 } NFS41_SERVER_ENTRY
, *PNFS41_SERVER_ENTRY
;
434 typedef struct _NFS41_DEVICE_EXTENSION
{
435 NODE_TYPE_CODE NodeTypeCode
;
436 NODE_BYTE_SIZE NodeByteSize
;
437 PRDBSS_DEVICE_OBJECT DeviceObject
;
439 HANDLE SharedMemorySection
;
440 DWORD nfs41d_version
;
441 BYTE VolAttrs
[VOL_ATTR_LEN
];
443 HANDLE openlistHandle
;
444 } NFS41_DEVICE_EXTENSION
, *PNFS41_DEVICE_EXTENSION
;
446 #define NFS41GetDeviceExtension(RxContext,pExt) \
447 PNFS41_DEVICE_EXTENSION pExt = (PNFS41_DEVICE_EXTENSION) \
448 ((PBYTE)(RxContext->RxDeviceObject) + sizeof(RDBSS_DEVICE_OBJECT))
450 typedef struct _nfs41_fcb_list_entry
{
454 PNFS41_FOBX nfs41_fobx
;
455 ULONGLONG ChangeTime
;
457 } nfs41_fcb_list_entry
;
459 typedef struct _nfs41_fcb_list
{
462 nfs41_fcb_list openlist
;
464 typedef enum _NULMRX_STORAGE_TYPE_CODES
{
465 NTC_NFS41_DEVICE_EXTENSION
= (NODE_TYPE_CODE
)0xFC00,
466 } NFS41_STORAGE_TYPE_CODES
;
467 #define RxDefineNode( node, type ) \
468 node->NodeTypeCode = NTC_##type; \
469 node->NodeByteSize = sizeof(type);
471 #define RDR_NULL_STATE 0
472 #define RDR_UNLOADED 1
473 #define RDR_UNLOADING 2
474 #define RDR_LOADING 3
476 #define RDR_STOPPED 5
477 #define RDR_STOPPING 6
478 #define RDR_STARTING 7
479 #define RDR_STARTED 8
481 nfs41_init_driver_state nfs41_init_state
= NFS41_INIT_DRIVER_STARTABLE
;
482 nfs41_start_driver_state nfs41_start_state
= NFS41_START_DRIVER_STARTABLE
;
484 NTSTATUS
map_readwrite_errors(DWORD status
);
486 void print_debug_header(
487 PRX_CONTEXT RxContext
)
490 PIO_STACK_LOCATION IrpSp
= RxContext
->CurrentIrpSp
;
493 DbgP("FileOject %p name %wZ access r=%d,w=%d,d=%d share r=%d,w=%d,d=%d\n",
494 IrpSp
->FileObject
, &IrpSp
->FileObject
->FileName
,
495 IrpSp
->FileObject
->ReadAccess
, IrpSp
->FileObject
->WriteAccess
,
496 IrpSp
->FileObject
->DeleteAccess
, IrpSp
->FileObject
->SharedRead
,
497 IrpSp
->FileObject
->SharedWrite
, IrpSp
->FileObject
->SharedDelete
);
498 print_file_object(0, IrpSp
->FileObject
);
499 print_irps_flags(0, RxContext
->CurrentIrpSp
);
501 DbgP("Couldn't print FileObject IrpSp is NULL\n");
503 print_fo_all(1, RxContext
);
504 if (RxContext
->CurrentIrp
)
505 print_irp_flags(0, RxContext
->CurrentIrp
);
508 /* convert strings from unicode -> ansi during marshalling to
509 * save space in the upcall buffers and avoid extra copies */
510 INLINE ULONG
length_as_utf8(
511 PCUNICODE_STRING str
)
513 ULONG ActualCount
= 0;
514 RtlUnicodeToUTF8N(NULL
, 0xffff, &ActualCount
, str
->Buffer
, str
->Length
);
515 return sizeof(str
->MaximumLength
) + ActualCount
+ sizeof(UNICODE_NULL
);
518 NTSTATUS
marshall_unicode_as_utf8(
519 IN OUT
unsigned char **pos
,
520 IN PCUNICODE_STRING str
)
526 if (str
->Length
== 0) {
527 status
= STATUS_SUCCESS
;
529 ansi
.MaximumLength
= 1;
533 /* query the number of bytes required for the utf8 encoding */
534 status
= RtlUnicodeToUTF8N(NULL
, 0xffff,
535 &ActualCount
, str
->Buffer
, str
->Length
);
537 print_error("RtlUnicodeToUTF8N('%wZ') failed with 0x%08X\n",
542 /* convert the string directly into the upcall buffer */
543 ansi
.Buffer
= (PCHAR
)*pos
+ sizeof(ansi
.MaximumLength
);
544 ansi
.MaximumLength
= (USHORT
)ActualCount
+ sizeof(UNICODE_NULL
);
545 status
= RtlUnicodeToUTF8N(ansi
.Buffer
, ansi
.MaximumLength
,
546 &ActualCount
, str
->Buffer
, str
->Length
);
548 print_error("RtlUnicodeToUTF8N(%hu, '%wZ', %hu) failed with 0x%08X\n",
549 ansi
.MaximumLength
, str
, str
->Length
, status
);
554 RtlCopyMemory(*pos
, &ansi
.MaximumLength
, sizeof(ansi
.MaximumLength
));
555 *pos
+= sizeof(ansi
.MaximumLength
);
556 (*pos
)[ActualCount
] = '\0';
557 *pos
+= ansi
.MaximumLength
;
562 NTSTATUS
marshal_nfs41_header(
563 nfs41_updowncall_entry
*entry
,
568 NTSTATUS status
= STATUS_SUCCESS
;
569 ULONG header_len
= 0;
570 unsigned char *tmp
= buf
;
572 header_len
= sizeof(entry
->version
) + sizeof(entry
->xid
) +
573 sizeof(entry
->opcode
) + 2 * sizeof(HANDLE
);
574 if (header_len
> buf_len
) {
575 status
= STATUS_INSUFFICIENT_RESOURCES
;
580 RtlCopyMemory(tmp
, &entry
->version
, sizeof(entry
->version
));
581 tmp
+= sizeof(entry
->version
);
582 RtlCopyMemory(tmp
, &entry
->xid
, sizeof(entry
->xid
));
583 tmp
+= sizeof(entry
->xid
);
584 RtlCopyMemory(tmp
, &entry
->opcode
, sizeof(entry
->opcode
));
585 tmp
+= sizeof(entry
->opcode
);
586 RtlCopyMemory(tmp
, &entry
->session
, sizeof(HANDLE
));
587 tmp
+= sizeof(HANDLE
);
588 RtlCopyMemory(tmp
, &entry
->open_state
, sizeof(HANDLE
));
589 tmp
+= sizeof(HANDLE
);
591 #ifdef DEBUG_MARSHAL_HEADER
592 if (MmIsAddressValid(entry
->filename
))
593 DbgP("[upcall header] xid=%lld opcode=%s filename=%wZ version=%d "
594 "session=0x%x open_state=0x%x\n", entry
->xid
,
595 opcode2string(entry
->opcode
), entry
->filename
,
596 entry
->version
, entry
->session
, entry
->open_state
);
598 status
= STATUS_INTERNAL_ERROR
;
604 const char* secflavorop2name(
608 case RPCSEC_AUTH_SYS
: return "AUTH_SYS";
609 case RPCSEC_AUTHGSS_KRB5
: return "AUTHGSS_KRB5";
610 case RPCSEC_AUTHGSS_KRB5I
: return "AUTHGSS_KRB5I";
611 case RPCSEC_AUTHGSS_KRB5P
: return "AUTHGSS_KRB5P";
614 return "UNKNOWN FLAVOR";
616 NTSTATUS
marshal_nfs41_mount(
617 nfs41_updowncall_entry
*entry
,
622 NTSTATUS status
= STATUS_SUCCESS
;
623 ULONG header_len
= 0;
624 unsigned char *tmp
= buf
;
626 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
627 if (status
) goto out
;
630 /* 03/25/2011: Kernel crash to nfsd not running but mount upcall cued up */
631 if (!MmIsAddressValid(entry
->u
.Mount
.srv_name
) ||
632 !MmIsAddressValid(entry
->u
.Mount
.root
)) {
633 status
= STATUS_INTERNAL_ERROR
;
636 header_len
= *len
+ length_as_utf8(entry
->u
.Mount
.srv_name
) +
637 length_as_utf8(entry
->u
.Mount
.root
) + 3 * sizeof(DWORD
);
638 if (header_len
> buf_len
) {
639 status
= STATUS_INSUFFICIENT_RESOURCES
;
642 status
= marshall_unicode_as_utf8(&tmp
, entry
->u
.Mount
.srv_name
);
643 if (status
) goto out
;
644 status
= marshall_unicode_as_utf8(&tmp
, entry
->u
.Mount
.root
);
645 if (status
) goto out
;
646 RtlCopyMemory(tmp
, &entry
->u
.Mount
.sec_flavor
, sizeof(DWORD
));
647 tmp
+= sizeof(DWORD
);
648 RtlCopyMemory(tmp
, &entry
->u
.Mount
.rsize
, sizeof(DWORD
));
649 tmp
+= sizeof(DWORD
);
650 RtlCopyMemory(tmp
, &entry
->u
.Mount
.wsize
, sizeof(DWORD
));
654 #ifdef DEBUG_MARSHAL_DETAIL
655 DbgP("marshal_nfs41_mount: server name=%wZ mount point=%wZ sec_flavor=%s "
656 "rsize=%d wsize=%d\n", entry
->u
.Mount
.srv_name
, entry
->u
.Mount
.root
,
657 secflavorop2name(entry
->u
.Mount
.sec_flavor
), entry
->u
.Mount
.rsize
,
658 entry
->u
.Mount
.wsize
);
664 NTSTATUS
marshal_nfs41_unmount(
665 nfs41_updowncall_entry
*entry
,
670 return marshal_nfs41_header(entry
, buf
, buf_len
, len
);
673 NTSTATUS
marshal_nfs41_open(
674 nfs41_updowncall_entry
*entry
,
679 NTSTATUS status
= STATUS_SUCCESS
;
680 ULONG header_len
= 0;
681 unsigned char *tmp
= buf
;
683 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
684 if (status
) goto out
;
687 header_len
= *len
+ length_as_utf8(entry
->filename
) +
688 7 * sizeof(ULONG
) + 2 * sizeof(HANDLE
) +
689 length_as_utf8(&entry
->u
.Open
.symlink
);
690 if (header_len
> buf_len
) {
691 status
= STATUS_INSUFFICIENT_RESOURCES
;
694 status
= marshall_unicode_as_utf8(&tmp
, entry
->filename
);
695 if (status
) goto out
;
696 RtlCopyMemory(tmp
, &entry
->u
.Open
.access_mask
,
697 sizeof(entry
->u
.Open
.access_mask
));
698 tmp
+= sizeof(entry
->u
.Open
.access_mask
);
699 RtlCopyMemory(tmp
, &entry
->u
.Open
.access_mode
,
700 sizeof(entry
->u
.Open
.access_mode
));
701 tmp
+= sizeof(entry
->u
.Open
.access_mode
);
702 RtlCopyMemory(tmp
, &entry
->u
.Open
.attrs
, sizeof(entry
->u
.Open
.attrs
));
703 tmp
+= sizeof(entry
->u
.Open
.attrs
);
704 RtlCopyMemory(tmp
, &entry
->u
.Open
.copts
, sizeof(entry
->u
.Open
.copts
));
705 tmp
+= sizeof(entry
->u
.Open
.copts
);
706 RtlCopyMemory(tmp
, &entry
->u
.Open
.disp
, sizeof(entry
->u
.Open
.disp
));
707 tmp
+= sizeof(entry
->u
.Open
.disp
);
708 RtlCopyMemory(tmp
, &entry
->u
.Open
.open_owner_id
,
709 sizeof(entry
->u
.Open
.open_owner_id
));
710 tmp
+= sizeof(entry
->u
.Open
.open_owner_id
);
711 RtlCopyMemory(tmp
, &entry
->u
.Open
.mode
, sizeof(DWORD
));
712 tmp
+= sizeof(DWORD
);
713 RtlCopyMemory(tmp
, &entry
->u
.Open
.srv_open
, sizeof(HANDLE
));
714 tmp
+= sizeof(HANDLE
);
715 status
= marshall_unicode_as_utf8(&tmp
, &entry
->u
.Open
.symlink
);
716 if (status
) goto out
;
719 if (entry
->u
.Open
.EaMdl
) {
720 entry
->u
.Open
.EaBuffer
=
721 MmMapLockedPagesSpecifyCache(entry
->u
.Open
.EaMdl
,
723 UserMode
, MmNonCached
, NULL
, TRUE
, NormalPagePriority
);
725 UserMode
, MmCached
, NULL
, TRUE
, NormalPagePriority
);
727 if (entry
->u
.Open
.EaBuffer
== NULL
) {
728 print_error("MmMapLockedPagesSpecifyCache failed to map pages\n");
729 status
= STATUS_INSUFFICIENT_RESOURCES
;
733 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
734 print_error("Call to MmMapLocked failed due to exception 0x%x\n", _SEH2_GetExceptionCode());
735 status
= STATUS_ACCESS_DENIED
;
738 RtlCopyMemory(tmp
, &entry
->u
.Open
.EaBuffer
, sizeof(HANDLE
));
741 #ifdef DEBUG_MARSHAL_DETAIL
742 DbgP("marshal_nfs41_open: name=%wZ mask=0x%x access=0x%x attrs=0x%x "
743 "opts=0x%x dispo=0x%x open_owner_id=0x%x mode=%o srv_open=%p ea=%p\n",
744 entry
->filename
, entry
->u
.Open
.access_mask
,
745 entry
->u
.Open
.access_mode
, entry
->u
.Open
.attrs
, entry
->u
.Open
.copts
,
746 entry
->u
.Open
.disp
, entry
->u
.Open
.open_owner_id
, entry
->u
.Open
.mode
,
747 entry
->u
.Open
.srv_open
, entry
->u
.Open
.EaBuffer
);
753 NTSTATUS
marshal_nfs41_rw(
754 nfs41_updowncall_entry
*entry
,
759 NTSTATUS status
= STATUS_SUCCESS
;
760 ULONG header_len
= 0;
761 unsigned char *tmp
= buf
;
763 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
764 if (status
) goto out
;
767 header_len
= *len
+ sizeof(entry
->buf_len
) +
768 sizeof(entry
->u
.ReadWrite
.offset
) + sizeof(HANDLE
);
769 if (header_len
> buf_len
) {
770 status
= STATUS_INSUFFICIENT_RESOURCES
;
774 RtlCopyMemory(tmp
, &entry
->buf_len
, sizeof(entry
->buf_len
));
775 tmp
+= sizeof(entry
->buf_len
);
776 RtlCopyMemory(tmp
, &entry
->u
.ReadWrite
.offset
,
777 sizeof(entry
->u
.ReadWrite
.offset
));
778 tmp
+= sizeof(entry
->u
.ReadWrite
.offset
);
780 entry
->u
.ReadWrite
.MdlAddress
->MdlFlags
|= MDL_MAPPING_CAN_FAIL
;
782 MmMapLockedPagesSpecifyCache(entry
->u
.ReadWrite
.MdlAddress
,
784 UserMode
, MmNonCached
, NULL
, TRUE
, NormalPagePriority
);
786 UserMode
, MmCached
, NULL
, TRUE
, NormalPagePriority
);
788 if (entry
->buf
== NULL
) {
789 print_error("MmMapLockedPagesSpecifyCache failed to map pages\n");
790 status
= STATUS_INSUFFICIENT_RESOURCES
;
793 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
795 code
= _SEH2_GetExceptionCode();
796 print_error("Call to MmMapLocked failed due to exception 0x%x\n", code
);
797 status
= STATUS_ACCESS_DENIED
;
800 RtlCopyMemory(tmp
, &entry
->buf
, sizeof(HANDLE
));
803 #ifdef DEBUG_MARSHAL_DETAIL
804 DbgP("marshal_nfs41_rw: len=%lu offset=%llu MdlAddress=%p Userspace=%p\n",
805 entry
->buf_len
, entry
->u
.ReadWrite
.offset
,
806 entry
->u
.ReadWrite
.MdlAddress
, entry
->buf
);
812 NTSTATUS
marshal_nfs41_lock(
813 nfs41_updowncall_entry
*entry
,
818 NTSTATUS status
= STATUS_SUCCESS
;
819 ULONG header_len
= 0;
820 unsigned char *tmp
= buf
;
822 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
823 if (status
) goto out
;
826 header_len
= *len
+ 2 * sizeof(LONGLONG
) + 2 * sizeof(BOOLEAN
);
827 if (header_len
> buf_len
) {
828 status
= STATUS_INSUFFICIENT_RESOURCES
;
831 RtlCopyMemory(tmp
, &entry
->u
.Lock
.offset
, sizeof(LONGLONG
));
832 tmp
+= sizeof(LONGLONG
);
833 RtlCopyMemory(tmp
, &entry
->u
.Lock
.length
, sizeof(LONGLONG
));
834 tmp
+= sizeof(LONGLONG
);
835 RtlCopyMemory(tmp
, &entry
->u
.Lock
.exclusive
, sizeof(BOOLEAN
));
836 tmp
+= sizeof(BOOLEAN
);
837 RtlCopyMemory(tmp
, &entry
->u
.Lock
.blocking
, sizeof(BOOLEAN
));
840 #ifdef DEBUG_MARSHAL_DETAIL
841 DbgP("marshal_nfs41_lock: offset=%llx length=%llx exclusive=%u "
842 "blocking=%u\n", entry
->u
.Lock
.offset
, entry
->u
.Lock
.length
,
843 entry
->u
.Lock
.exclusive
, entry
->u
.Lock
.blocking
);
849 NTSTATUS
marshal_nfs41_unlock(
850 nfs41_updowncall_entry
*entry
,
855 NTSTATUS status
= STATUS_SUCCESS
;
856 ULONG header_len
= 0;
857 unsigned char *tmp
= buf
;
858 PLOWIO_LOCK_LIST lock
;
860 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
861 if (status
) goto out
;
864 header_len
= *len
+ sizeof(ULONG
) +
865 entry
->u
.Unlock
.count
* 2 * sizeof(LONGLONG
);
866 if (header_len
> buf_len
) {
867 status
= STATUS_INSUFFICIENT_RESOURCES
;
870 RtlCopyMemory(tmp
, &entry
->u
.Unlock
.count
, sizeof(ULONG
));
871 tmp
+= sizeof(ULONG
);
873 lock
= &entry
->u
.Unlock
.locks
;
875 RtlCopyMemory(tmp
, &lock
->ByteOffset
, sizeof(LONGLONG
));
876 tmp
+= sizeof(LONGLONG
);
877 RtlCopyMemory(tmp
, &lock
->Length
, sizeof(LONGLONG
));
878 tmp
+= sizeof(LONGLONG
);
883 #ifdef DEBUG_MARSHAL_DETAIL
884 DbgP("marshal_nfs41_unlock: count=%u\n", entry
->u
.Unlock
.count
);
890 NTSTATUS
marshal_nfs41_close(
891 nfs41_updowncall_entry
*entry
,
896 NTSTATUS status
= STATUS_SUCCESS
;
897 ULONG header_len
= 0;
898 unsigned char *tmp
= buf
;
900 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
901 if (status
) goto out
;
904 header_len
= *len
+ sizeof(BOOLEAN
) + sizeof(HANDLE
);
905 if (entry
->u
.Close
.remove
)
906 header_len
+= length_as_utf8(entry
->filename
) +
909 if (header_len
> buf_len
) {
910 status
= STATUS_INSUFFICIENT_RESOURCES
;
913 RtlCopyMemory(tmp
, &entry
->u
.Close
.remove
, sizeof(BOOLEAN
));
914 tmp
+= sizeof(BOOLEAN
);
915 RtlCopyMemory(tmp
, &entry
->u
.Close
.srv_open
, sizeof(HANDLE
));
916 if (entry
->u
.Close
.remove
) {
917 tmp
+= sizeof(HANDLE
);
918 status
= marshall_unicode_as_utf8(&tmp
, entry
->filename
);
919 if (status
) goto out
;
920 RtlCopyMemory(tmp
, &entry
->u
.Close
.renamed
, sizeof(BOOLEAN
));
924 #ifdef DEBUG_MARSHAL_DETAIL
925 DbgP("marshal_nfs41_close: name=%wZ remove=%d srv_open=%p renamed=%d\n",
926 entry
->filename
->Length
?entry
->filename
:&SLASH
,
927 entry
->u
.Close
.remove
, entry
->u
.Close
.srv_open
, entry
->u
.Close
.renamed
);
933 NTSTATUS
marshal_nfs41_dirquery(
934 nfs41_updowncall_entry
*entry
,
939 NTSTATUS status
= STATUS_SUCCESS
;
940 ULONG header_len
= 0;
941 unsigned char *tmp
= buf
;
943 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
944 if (status
) goto out
;
947 header_len
= *len
+ 2 * sizeof(ULONG
) + sizeof(HANDLE
) +
948 length_as_utf8(entry
->u
.QueryFile
.filter
) + 3 * sizeof(BOOLEAN
);
949 if (header_len
> buf_len
) {
950 status
= STATUS_INSUFFICIENT_RESOURCES
;
954 RtlCopyMemory(tmp
, &entry
->u
.QueryFile
.InfoClass
, sizeof(ULONG
));
955 tmp
+= sizeof(ULONG
);
956 RtlCopyMemory(tmp
, &entry
->buf_len
, sizeof(ULONG
));
957 tmp
+= sizeof(ULONG
);
958 status
= marshall_unicode_as_utf8(&tmp
, entry
->u
.QueryFile
.filter
);
959 if (status
) goto out
;
960 RtlCopyMemory(tmp
, &entry
->u
.QueryFile
.initial_query
, sizeof(BOOLEAN
));
961 tmp
+= sizeof(BOOLEAN
);
962 RtlCopyMemory(tmp
, &entry
->u
.QueryFile
.restart_scan
, sizeof(BOOLEAN
));
963 tmp
+= sizeof(BOOLEAN
);
964 RtlCopyMemory(tmp
, &entry
->u
.QueryFile
.return_single
, sizeof(BOOLEAN
));
965 tmp
+= sizeof(BOOLEAN
);
967 entry
->u
.QueryFile
.mdl_buf
=
968 MmMapLockedPagesSpecifyCache(entry
->u
.QueryFile
.mdl
,
970 UserMode
, MmNonCached
, NULL
, TRUE
, NormalPagePriority
);
972 UserMode
, MmCached
, NULL
, TRUE
, NormalPagePriority
);
974 if (entry
->u
.QueryFile
.mdl_buf
== NULL
) {
975 print_error("MmMapLockedPagesSpecifyCache failed to map pages\n");
976 status
= STATUS_INSUFFICIENT_RESOURCES
;
979 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
981 code
= _SEH2_GetExceptionCode();
982 print_error("Call to MmMapLocked failed due to exception 0x%x\n", code
);
983 status
= STATUS_ACCESS_DENIED
;
986 RtlCopyMemory(tmp
, &entry
->u
.QueryFile
.mdl_buf
, sizeof(HANDLE
));
989 #ifdef DEBUG_MARSHAL_DETAIL
990 DbgP("marshal_nfs41_dirquery: filter='%wZ'class=%d len=%d "
991 "1st\\restart\\single=%d\\%d\\%d\n", entry
->u
.QueryFile
.filter
,
992 entry
->u
.QueryFile
.InfoClass
, entry
->buf_len
,
993 entry
->u
.QueryFile
.initial_query
, entry
->u
.QueryFile
.restart_scan
,
994 entry
->u
.QueryFile
.return_single
);
1000 NTSTATUS
marshal_nfs41_filequery(
1001 nfs41_updowncall_entry
*entry
,
1006 NTSTATUS status
= STATUS_SUCCESS
;
1007 ULONG header_len
= 0;
1008 unsigned char *tmp
= buf
;
1010 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
1011 if (status
) goto out
;
1014 header_len
= *len
+ 2 * sizeof(ULONG
);
1015 if (header_len
> buf_len
) {
1016 status
= STATUS_INSUFFICIENT_RESOURCES
;
1019 RtlCopyMemory(tmp
, &entry
->u
.QueryFile
.InfoClass
, sizeof(ULONG
));
1020 tmp
+= sizeof(ULONG
);
1021 RtlCopyMemory(tmp
, &entry
->buf_len
, sizeof(ULONG
));
1022 tmp
+= sizeof(ULONG
);
1023 RtlCopyMemory(tmp
, &entry
->session
, sizeof(HANDLE
));
1024 tmp
+= sizeof(HANDLE
);
1025 RtlCopyMemory(tmp
, &entry
->open_state
, sizeof(HANDLE
));
1028 #ifdef DEBUG_MARSHAL_DETAIL
1029 DbgP("marshal_nfs41_filequery: class=%d\n", entry
->u
.QueryFile
.InfoClass
);
1035 NTSTATUS
marshal_nfs41_fileset(
1036 nfs41_updowncall_entry
*entry
,
1041 NTSTATUS status
= STATUS_SUCCESS
;
1042 ULONG header_len
= 0;
1043 unsigned char *tmp
= buf
;
1045 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
1046 if (status
) goto out
;
1049 header_len
= *len
+ length_as_utf8(entry
->filename
) +
1050 2 * sizeof(ULONG
) + entry
->buf_len
;
1051 if (header_len
> buf_len
) {
1052 status
= STATUS_INSUFFICIENT_RESOURCES
;
1055 status
= marshall_unicode_as_utf8(&tmp
, entry
->filename
);
1056 if (status
) goto out
;
1057 RtlCopyMemory(tmp
, &entry
->u
.SetFile
.InfoClass
, sizeof(ULONG
));
1058 tmp
+= sizeof(ULONG
);
1059 RtlCopyMemory(tmp
, &entry
->buf_len
, sizeof(ULONG
));
1060 tmp
+= sizeof(ULONG
);
1061 RtlCopyMemory(tmp
, entry
->buf
, entry
->buf_len
);
1064 #ifdef DEBUG_MARSHAL_DETAIL
1065 DbgP("marshal_nfs41_fileset: filename='%wZ' class=%d\n",
1066 entry
->filename
, entry
->u
.SetFile
.InfoClass
);
1072 NTSTATUS
marshal_nfs41_easet(
1073 nfs41_updowncall_entry
*entry
,
1078 NTSTATUS status
= STATUS_SUCCESS
;
1079 ULONG header_len
= 0;
1080 unsigned char *tmp
= buf
;
1082 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
1083 if (status
) goto out
;
1086 header_len
= *len
+ length_as_utf8(entry
->filename
) +
1087 sizeof(ULONG
) + entry
->buf_len
+ sizeof(DWORD
);
1088 if (header_len
> buf_len
) {
1089 status
= STATUS_INSUFFICIENT_RESOURCES
;
1093 status
= marshall_unicode_as_utf8(&tmp
, entry
->filename
);
1094 if (status
) goto out
;
1095 RtlCopyMemory(tmp
, &entry
->u
.SetEa
.mode
, sizeof(DWORD
));
1096 tmp
+= sizeof(DWORD
);
1097 RtlCopyMemory(tmp
, &entry
->buf_len
, sizeof(ULONG
));
1098 tmp
+= sizeof(ULONG
);
1099 RtlCopyMemory(tmp
, entry
->buf
, entry
->buf_len
);
1102 #ifdef DEBUG_MARSHAL_DETAIL
1103 DbgP("marshal_nfs41_easet: filename=%wZ, buflen=%d mode=0x%x\n",
1104 entry
->filename
, entry
->buf_len
, entry
->u
.SetEa
.mode
);
1110 NTSTATUS
marshal_nfs41_eaget(
1111 nfs41_updowncall_entry
*entry
,
1116 NTSTATUS status
= STATUS_SUCCESS
;
1117 ULONG header_len
= 0;
1118 unsigned char *tmp
= buf
;
1120 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
1121 if (status
) goto out
;
1124 header_len
= *len
+ length_as_utf8(entry
->filename
) +
1125 3 * sizeof(ULONG
) + entry
->u
.QueryEa
.EaListLength
+ 2 * sizeof(BOOLEAN
);
1127 if (header_len
> buf_len
) {
1128 status
= STATUS_INSUFFICIENT_RESOURCES
;
1132 status
= marshall_unicode_as_utf8(&tmp
, entry
->filename
);
1133 if (status
) goto out
;
1134 RtlCopyMemory(tmp
, &entry
->u
.QueryEa
.EaIndex
, sizeof(ULONG
));
1135 tmp
+= sizeof(ULONG
);
1136 RtlCopyMemory(tmp
, &entry
->u
.QueryEa
.RestartScan
, sizeof(BOOLEAN
));
1137 tmp
+= sizeof(BOOLEAN
);
1138 RtlCopyMemory(tmp
, &entry
->u
.QueryEa
.ReturnSingleEntry
, sizeof(BOOLEAN
));
1139 tmp
+= sizeof(BOOLEAN
);
1140 RtlCopyMemory(tmp
, &entry
->buf_len
, sizeof(ULONG
));
1141 tmp
+= sizeof(ULONG
);
1142 RtlCopyMemory(tmp
, &entry
->u
.QueryEa
.EaListLength
, sizeof(ULONG
));
1143 tmp
+= sizeof(ULONG
);
1144 if (entry
->u
.QueryEa
.EaList
&& entry
->u
.QueryEa
.EaListLength
)
1145 RtlCopyMemory(tmp
, entry
->u
.QueryEa
.EaList
,
1146 entry
->u
.QueryEa
.EaListLength
);
1149 #ifdef DEBUG_MARSHAL_DETAIL
1150 DbgP("marshal_nfs41_eaget: filename=%wZ, index=%d list_len=%d "
1151 "rescan=%d single=%d\n", entry
->filename
,
1152 entry
->u
.QueryEa
.EaIndex
, entry
->u
.QueryEa
.EaListLength
,
1153 entry
->u
.QueryEa
.RestartScan
, entry
->u
.QueryEa
.ReturnSingleEntry
);
1159 NTSTATUS
marshal_nfs41_symlink(
1160 nfs41_updowncall_entry
*entry
,
1165 NTSTATUS status
= STATUS_SUCCESS
;
1166 ULONG header_len
= 0;
1167 unsigned char *tmp
= buf
;
1169 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
1170 if (status
) goto out
;
1173 header_len
= *len
+ sizeof(BOOLEAN
) + length_as_utf8(entry
->filename
);
1174 if (entry
->u
.Symlink
.set
)
1175 header_len
+= length_as_utf8(entry
->u
.Symlink
.target
);
1176 if (header_len
> buf_len
) {
1177 status
= STATUS_INSUFFICIENT_RESOURCES
;
1181 status
= marshall_unicode_as_utf8(&tmp
, entry
->filename
);
1182 if (status
) goto out
;
1183 RtlCopyMemory(tmp
, &entry
->u
.Symlink
.set
, sizeof(BOOLEAN
));
1184 tmp
+= sizeof(BOOLEAN
);
1185 if (entry
->u
.Symlink
.set
) {
1186 status
= marshall_unicode_as_utf8(&tmp
, entry
->u
.Symlink
.target
);
1187 if (status
) goto out
;
1191 #ifdef DEBUG_MARSHAL_DETAIL
1192 DbgP("marshal_nfs41_symlink: name %wZ symlink target %wZ\n",
1194 entry
->u
.Symlink
.set
?entry
->u
.Symlink
.target
: NULL
);
1200 NTSTATUS
marshal_nfs41_volume(
1201 nfs41_updowncall_entry
*entry
,
1206 NTSTATUS status
= STATUS_SUCCESS
;
1207 ULONG header_len
= 0;
1208 unsigned char *tmp
= buf
;
1210 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
1211 if (status
) goto out
;
1214 header_len
= *len
+ sizeof(FS_INFORMATION_CLASS
);
1215 if (header_len
> buf_len
) {
1216 status
= STATUS_INSUFFICIENT_RESOURCES
;
1220 RtlCopyMemory(tmp
, &entry
->u
.Volume
.query
, sizeof(FS_INFORMATION_CLASS
));
1223 #ifdef DEBUG_MARSHAL_DETAIL
1224 DbgP("marshal_nfs41_volume: class=%d\n", entry
->u
.Volume
.query
);
1230 NTSTATUS
marshal_nfs41_getacl(
1231 nfs41_updowncall_entry
*entry
,
1236 NTSTATUS status
= STATUS_SUCCESS
;
1237 ULONG header_len
= 0;
1238 unsigned char *tmp
= buf
;
1240 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
1241 if (status
) goto out
;
1244 header_len
= *len
+ sizeof(SECURITY_INFORMATION
);
1245 if (header_len
> buf_len
) {
1246 status
= STATUS_INSUFFICIENT_RESOURCES
;
1250 RtlCopyMemory(tmp
, &entry
->u
.Acl
.query
, sizeof(SECURITY_INFORMATION
));
1253 #ifdef DEBUG_MARSHAL_DETAIL
1254 DbgP("marshal_nfs41_getacl: class=0x%x\n", entry
->u
.Acl
.query
);
1260 NTSTATUS
marshal_nfs41_setacl(
1261 nfs41_updowncall_entry
*entry
,
1266 NTSTATUS status
= STATUS_SUCCESS
;
1267 ULONG header_len
= 0;
1268 unsigned char *tmp
= buf
;
1270 status
= marshal_nfs41_header(entry
, tmp
, buf_len
, len
);
1271 if (status
) goto out
;
1274 header_len
= *len
+ sizeof(SECURITY_INFORMATION
) +
1275 sizeof(ULONG
) + entry
->buf_len
;
1276 if (header_len
> buf_len
) {
1277 status
= STATUS_INSUFFICIENT_RESOURCES
;
1281 RtlCopyMemory(tmp
, &entry
->u
.Acl
.query
, sizeof(SECURITY_INFORMATION
));
1282 tmp
+= sizeof(SECURITY_INFORMATION
);
1283 RtlCopyMemory(tmp
, &entry
->buf_len
, sizeof(ULONG
));
1284 tmp
+= sizeof(ULONG
);
1285 RtlCopyMemory(tmp
, entry
->buf
, entry
->buf_len
);
1288 #ifdef DEBUG_MARSHAL_DETAIL
1289 DbgP("marshal_nfs41_setacl: class=0x%x sec_desc_len=%lu\n",
1290 entry
->u
.Acl
.query
, entry
->buf_len
);
1296 NTSTATUS
marshal_nfs41_shutdown(
1297 nfs41_updowncall_entry
*entry
,
1302 return marshal_nfs41_header(entry
, buf
, buf_len
, len
);
1305 void nfs41_invalidate_cache (
1306 IN PRX_CONTEXT RxContext
)
1308 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
1309 unsigned char *buf
= LowIoContext
->ParamsFor
.IoCtl
.pInputBuffer
;
1310 ULONG flag
= DISABLE_CACHING
;
1311 PMRX_SRV_OPEN srv_open
;
1313 RtlCopyMemory(&srv_open
, buf
, sizeof(HANDLE
));
1314 #ifdef DEBUG_INVALIDATE_CACHE
1315 DbgP("nfs41_invalidate_cache: received srv_open=%p %wZ\n",
1316 srv_open
, srv_open
->pAlreadyPrefixedName
);
1318 if (MmIsAddressValid(srv_open
))
1319 RxIndicateChangeOfBufferingStateForSrvOpen(
1320 srv_open
->pFcb
->pNetRoot
->pSrvCall
, srv_open
,
1321 srv_open
->Key
, ULongToPtr(flag
));
1324 NTSTATUS
handle_upcall(
1325 IN PRX_CONTEXT RxContext
,
1326 IN nfs41_updowncall_entry
*entry
,
1329 NTSTATUS status
= STATUS_SUCCESS
;
1330 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
1331 ULONG cbOut
= LowIoContext
->ParamsFor
.IoCtl
.OutputBufferLength
;
1332 unsigned char *pbOut
= LowIoContext
->ParamsFor
.IoCtl
.pOutputBuffer
;
1334 status
= SeImpersonateClientEx(entry
->psec_ctx
, NULL
);
1335 if (status
!= STATUS_SUCCESS
) {
1336 print_error("SeImpersonateClientEx failed %x\n", status
);
1340 switch(entry
->opcode
) {
1341 case NFS41_SHUTDOWN
:
1342 status
= marshal_nfs41_shutdown(entry
, pbOut
, cbOut
, len
);
1343 KeSetEvent(&entry
->cond
, 0, FALSE
);
1346 status
= marshal_nfs41_mount(entry
, pbOut
, cbOut
, len
);
1349 status
= marshal_nfs41_unmount(entry
, pbOut
, cbOut
, len
);
1352 status
= marshal_nfs41_open(entry
, pbOut
, cbOut
, len
);
1355 status
= marshal_nfs41_rw(entry
, pbOut
, cbOut
, len
);
1358 status
= marshal_nfs41_rw(entry
, pbOut
, cbOut
, len
);
1361 status
= marshal_nfs41_lock(entry
, pbOut
, cbOut
, len
);
1364 status
= marshal_nfs41_unlock(entry
, pbOut
, cbOut
, len
);
1367 status
= marshal_nfs41_close(entry
, pbOut
, cbOut
, len
);
1369 case NFS41_DIR_QUERY
:
1370 status
= marshal_nfs41_dirquery(entry
, pbOut
, cbOut
, len
);
1372 case NFS41_FILE_QUERY
:
1373 status
= marshal_nfs41_filequery(entry
, pbOut
, cbOut
, len
);
1375 case NFS41_FILE_SET
:
1376 status
= marshal_nfs41_fileset(entry
, pbOut
, cbOut
, len
);
1379 status
= marshal_nfs41_easet(entry
, pbOut
, cbOut
, len
);
1382 status
= marshal_nfs41_eaget(entry
, pbOut
, cbOut
, len
);
1385 status
= marshal_nfs41_symlink(entry
, pbOut
, cbOut
, len
);
1387 case NFS41_VOLUME_QUERY
:
1388 status
= marshal_nfs41_volume(entry
, pbOut
, cbOut
, len
);
1390 case NFS41_ACL_QUERY
:
1391 status
= marshal_nfs41_getacl(entry
, pbOut
, cbOut
, len
);
1394 status
= marshal_nfs41_setacl(entry
, pbOut
, cbOut
, len
);
1397 status
= STATUS_INVALID_PARAMETER
;
1398 print_error("Unknown nfs41 ops %d\n", entry
->opcode
);
1401 if (status
== STATUS_SUCCESS
)
1402 print_hexbuf(0, (unsigned char *)"upcall buffer", pbOut
, *len
);
1408 NTSTATUS
nfs41_UpcallCreate(
1410 IN PSECURITY_CLIENT_CONTEXT clnt_sec_ctx
,
1412 IN HANDLE open_state
,
1414 IN PUNICODE_STRING filename
,
1415 OUT nfs41_updowncall_entry
**entry_out
)
1417 NTSTATUS status
= STATUS_SUCCESS
;
1418 nfs41_updowncall_entry
*entry
;
1419 SECURITY_SUBJECT_CONTEXT sec_ctx
;
1420 SECURITY_QUALITY_OF_SERVICE sec_qos
;
1422 entry
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(nfs41_updowncall_entry
),
1423 NFS41_MM_POOLTAG_UP
);
1424 if (entry
== NULL
) {
1425 status
= STATUS_INSUFFICIENT_RESOURCES
;
1429 RtlZeroMemory(entry
, sizeof(nfs41_updowncall_entry
));
1430 entry
->xid
= InterlockedIncrement64(&xid
);
1431 entry
->opcode
= opcode
;
1432 entry
->state
= NFS41_WAITING_FOR_UPCALL
;
1433 entry
->session
= session
;
1434 entry
->open_state
= open_state
;
1435 entry
->version
= version
;
1436 if (filename
&& filename
->Length
) entry
->filename
= filename
;
1437 else if (filename
&& !filename
->Length
) entry
->filename
= (PUNICODE_STRING
)&SLASH
;
1438 else entry
->filename
= (PUNICODE_STRING
)&EMPTY_STRING
;
1439 /*XXX KeInitializeEvent will bugcheck under verifier if allocated
1440 * from PagedPool? */
1441 KeInitializeEvent(&entry
->cond
, SynchronizationEvent
, FALSE
);
1442 ExInitializeFastMutex(&entry
->lock
);
1444 if (clnt_sec_ctx
== NULL
) {
1445 SeCaptureSubjectContext(&sec_ctx
);
1446 sec_qos
.ContextTrackingMode
= SECURITY_DYNAMIC_TRACKING
;
1447 sec_qos
.ImpersonationLevel
= SecurityImpersonation
;
1448 sec_qos
.Length
= sizeof(SECURITY_QUALITY_OF_SERVICE
);
1449 sec_qos
.EffectiveOnly
= 0;
1450 status
= SeCreateClientSecurityFromSubjectContext(&sec_ctx
, &sec_qos
,
1451 1, &entry
->sec_ctx
);
1452 if (status
!= STATUS_SUCCESS
) {
1453 print_error("nfs41_UpcallCreate: "
1454 "SeCreateClientSecurityFromSubjectContext failed with %x\n",
1458 entry
->psec_ctx
= &entry
->sec_ctx
;
1459 SeReleaseSubjectContext(&sec_ctx
);
1461 entry
->psec_ctx
= clnt_sec_ctx
;
1468 NTSTATUS
nfs41_UpcallWaitForReply(
1469 IN nfs41_updowncall_entry
*entry
,
1472 NTSTATUS status
= STATUS_SUCCESS
;
1474 nfs41_AddEntry(upcallLock
, upcall
, entry
);
1475 KeSetEvent(&upcallEvent
, 0, FALSE
);
1476 if (!entry
->async_op
) {
1477 LARGE_INTEGER timeout
;
1478 timeout
.QuadPart
= RELATIVE(SECONDS(secs
));
1479 /* 02/03/2011 AGLO: it is not clear what the "right" waiting design
1480 * should be. Having non-interruptable waiting seems to be the right
1481 * approach. However, when things go wrong, the only wait to proceed
1482 * is a reboot (since "waits" are not interruptable we can't stop a
1483 * hung task. Having interruptable wait causes issues with security
1484 * context. For now, I'm making CLOSE non-interruptable but keeping
1485 * the rest interruptable so that we don't have to reboot all the time
1487 /* 02/15/2011 cbodley: added NFS41_UNLOCK for the same reason. locking
1488 * tests were triggering an interrupted unlock, which led to a bugcheck
1489 * in CloseSrvOpen() */
1490 #define MAKE_WAITONCLOSE_NONITERRUPTABLE
1491 #ifdef MAKE_WAITONCLOSE_NONITERRUPTABLE
1492 if (entry
->opcode
== NFS41_CLOSE
|| entry
->opcode
== NFS41_UNLOCK
)
1493 status
= KeWaitForSingleObject(&entry
->cond
, Executive
,
1494 KernelMode
, FALSE
, &timeout
);
1496 status
= KeWaitForSingleObject(&entry
->cond
, Executive
,
1497 UserMode
, TRUE
, &timeout
);
1499 if (status
!= STATUS_SUCCESS
) {
1500 print_wait_status(1, "[downcall]", status
,
1501 opcode2string(entry
->opcode
), entry
, entry
->xid
);
1502 if (status
== STATUS_TIMEOUT
)
1503 status
= STATUS_NETWORK_UNREACHABLE
;
1507 status
= KeWaitForSingleObject(&entry
->cond
, Executive
, KernelMode
, FALSE
, NULL
);
1509 print_wait_status(0, "[downcall]", status
, opcode2string(entry
->opcode
),
1515 case STATUS_SUCCESS
: break;
1516 case STATUS_USER_APC
:
1517 case STATUS_ALERTED
:
1519 ExAcquireFastMutex(&entry
->lock
);
1520 if (entry
->state
== NFS41_DONE_PROCESSING
) {
1521 ExReleaseFastMutex(&entry
->lock
);
1524 DbgP("[upcall] abandoning %s entry=%p xid=%lld\n",
1525 opcode2string(entry
->opcode
), entry
, entry
->xid
);
1526 entry
->state
= NFS41_NOT_WAITING
;
1527 ExReleaseFastMutex(&entry
->lock
);
1530 nfs41_RemoveEntry(downcallLock
, entry
);
1535 NTSTATUS
nfs41_upcall(
1536 IN PRX_CONTEXT RxContext
)
1538 NTSTATUS status
= STATUS_SUCCESS
;
1539 nfs41_updowncall_entry
*entry
= NULL
;
1544 nfs41_RemoveFirst(upcallLock
, upcall
, pEntry
);
1546 entry
= (nfs41_updowncall_entry
*)CONTAINING_RECORD(pEntry
,
1547 nfs41_updowncall_entry
, next
);
1548 ExAcquireFastMutex(&entry
->lock
);
1549 nfs41_AddEntry(downcallLock
, downcall
, entry
);
1550 status
= handle_upcall(RxContext
, entry
, &len
);
1551 if (status
== STATUS_SUCCESS
&&
1552 entry
->state
== NFS41_WAITING_FOR_UPCALL
)
1553 entry
->state
= NFS41_WAITING_FOR_DOWNCALL
;
1554 ExReleaseFastMutex(&entry
->lock
);
1556 entry
->status
= status
;
1557 KeSetEvent(&entry
->cond
, 0, FALSE
);
1558 RxContext
->InformationToReturn
= 0;
1560 RxContext
->InformationToReturn
= len
;
1563 status
= KeWaitForSingleObject(&upcallEvent
, Executive
, UserMode
, TRUE
,
1564 (PLARGE_INTEGER
) NULL
);
1565 print_wait_status(0, "[upcall]", status
, NULL
, NULL
, 0);
1567 case STATUS_SUCCESS
: goto process_upcall
;
1568 case STATUS_USER_APC
:
1569 case STATUS_ALERTED
:
1577 void unmarshal_nfs41_header(
1578 nfs41_updowncall_entry
*tmp
,
1579 unsigned char **buf
)
1581 RtlZeroMemory(tmp
, sizeof(nfs41_updowncall_entry
));
1583 RtlCopyMemory(&tmp
->xid
, *buf
, sizeof(tmp
->xid
));
1584 *buf
+= sizeof(tmp
->xid
);
1585 RtlCopyMemory(&tmp
->opcode
, *buf
, sizeof(tmp
->opcode
));
1586 *buf
+= sizeof(tmp
->opcode
);
1587 RtlCopyMemory(&tmp
->status
, *buf
, sizeof(tmp
->status
));
1588 *buf
+= sizeof(tmp
->status
);
1589 RtlCopyMemory(&tmp
->errno
, *buf
, sizeof(tmp
->errno
));
1590 *buf
+= sizeof(tmp
->errno
);
1591 #ifdef DEBUG_MARSHAL_HEADER
1592 DbgP("[downcall header] xid=%lld opcode=%s status=%d errno=%d\n", tmp
->xid
,
1593 opcode2string(tmp
->opcode
), tmp
->status
, tmp
->errno
);
1597 void unmarshal_nfs41_mount(
1598 nfs41_updowncall_entry
*cur
,
1599 unsigned char **buf
)
1601 RtlCopyMemory(&cur
->session
, *buf
, sizeof(HANDLE
));
1602 *buf
+= sizeof(HANDLE
);
1603 RtlCopyMemory(&cur
->version
, *buf
, sizeof(DWORD
));
1604 *buf
+= sizeof(DWORD
);
1605 RtlCopyMemory(&cur
->u
.Mount
.lease_time
, *buf
, sizeof(DWORD
));
1606 *buf
+= sizeof(DWORD
);
1607 RtlCopyMemory(cur
->u
.Mount
.FsAttrs
, *buf
, sizeof(FILE_FS_ATTRIBUTE_INFORMATION
));
1608 #ifdef DEBUG_MARSHAL_DETAIL
1609 DbgP("unmarshal_nfs41_mount: session pointer 0x%x version %d lease_time "
1610 "%d\n", cur
->session
, cur
->version
, cur
->u
.Mount
.lease_time
);
1614 VOID
unmarshal_nfs41_setattr(
1615 nfs41_updowncall_entry
*cur
,
1616 PULONGLONG dest_buf
,
1617 unsigned char **buf
)
1619 RtlCopyMemory(dest_buf
, *buf
, sizeof(ULONGLONG
));
1620 #ifdef DEBUG_MARSHAL_DETAIL
1621 DbgP("unmarshal_nfs41_setattr: returned ChangeTime %llu\n", *dest_buf
);
1625 NTSTATUS
unmarshal_nfs41_rw(
1626 nfs41_updowncall_entry
*cur
,
1627 unsigned char **buf
)
1629 NTSTATUS status
= STATUS_SUCCESS
;
1631 RtlCopyMemory(&cur
->buf_len
, *buf
, sizeof(cur
->buf_len
));
1632 *buf
+= sizeof(cur
->buf_len
);
1633 RtlCopyMemory(&cur
->ChangeTime
, *buf
, sizeof(ULONGLONG
));
1634 #ifdef DEBUG_MARSHAL_DETAIL
1635 DbgP("unmarshal_nfs41_rw: returned len %lu ChangeTime %llu\n",
1636 cur
->buf_len
, cur
->ChangeTime
);
1639 /* 08/27/2010: it looks like we really don't need to call
1640 * MmUnmapLockedPages() eventhough we called
1641 * MmMapLockedPagesSpecifyCache() as the MDL passed to us
1642 * is already locked.
1645 MmUnmapLockedPages(cur
->buf
, cur
->u
.ReadWrite
.MdlAddress
);
1646 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
1648 code
= _SEH2_GetExceptionCode();
1649 print_error("Call to MmUnmapLockedPages failed due to"
1650 " exception 0x%0x\n", code
);
1651 status
= STATUS_ACCESS_DENIED
;
1657 NTSTATUS
unmarshal_nfs41_open(
1658 nfs41_updowncall_entry
*cur
,
1659 unsigned char **buf
)
1661 NTSTATUS status
= STATUS_SUCCESS
;
1664 if (cur
->u
.Open
.EaBuffer
)
1665 MmUnmapLockedPages(cur
->u
.Open
.EaBuffer
, cur
->u
.Open
.EaMdl
);
1666 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
1667 print_error("MmUnmapLockedPages thrown exception=0x%0x\n", _SEH2_GetExceptionCode());
1668 status
= cur
->status
= STATUS_ACCESS_DENIED
;
1672 RtlCopyMemory(&cur
->u
.Open
.binfo
, *buf
, sizeof(FILE_BASIC_INFORMATION
));
1673 *buf
+= sizeof(FILE_BASIC_INFORMATION
);
1674 RtlCopyMemory(&cur
->u
.Open
.sinfo
, *buf
, sizeof(FILE_STANDARD_INFORMATION
));
1675 *buf
+= sizeof(FILE_STANDARD_INFORMATION
);
1676 RtlCopyMemory(&cur
->open_state
, *buf
, sizeof(HANDLE
));
1677 *buf
+= sizeof(HANDLE
);
1678 RtlCopyMemory(&cur
->u
.Open
.mode
, *buf
, sizeof(DWORD
));
1679 *buf
+= sizeof(DWORD
);
1680 RtlCopyMemory(&cur
->ChangeTime
, *buf
, sizeof(ULONGLONG
));
1681 *buf
+= sizeof(ULONGLONG
);
1682 RtlCopyMemory(&cur
->u
.Open
.deleg_type
, *buf
, sizeof(DWORD
));
1683 *buf
+= sizeof(DWORD
);
1684 if (cur
->errno
== ERROR_REPARSE
) {
1685 RtlCopyMemory(&cur
->u
.Open
.symlink_embedded
, *buf
, sizeof(BOOLEAN
));
1686 *buf
+= sizeof(BOOLEAN
);
1687 RtlCopyMemory(&cur
->u
.Open
.symlink
.MaximumLength
, *buf
,
1689 *buf
+= sizeof(USHORT
);
1690 cur
->u
.Open
.symlink
.Length
= cur
->u
.Open
.symlink
.MaximumLength
-
1692 cur
->u
.Open
.symlink
.Buffer
= RxAllocatePoolWithTag(NonPagedPool
,
1693 cur
->u
.Open
.symlink
.MaximumLength
, NFS41_MM_POOLTAG
);
1694 if (cur
->u
.Open
.symlink
.Buffer
== NULL
) {
1695 cur
->status
= STATUS_INSUFFICIENT_RESOURCES
;
1696 status
= STATUS_UNSUCCESSFUL
;
1699 RtlCopyMemory(cur
->u
.Open
.symlink
.Buffer
, *buf
,
1700 cur
->u
.Open
.symlink
.MaximumLength
);
1701 #ifdef DEBUG_MARSHAL_DETAIL
1702 DbgP("unmarshal_nfs41_open: ERROR_REPARSE -> '%wZ'\n", &cur
->u
.Open
.symlink
);
1705 #ifdef DEBUG_MARSHAL_DETAIL
1706 DbgP("unmarshal_nfs41_open: open_state 0x%x mode %o changeattr %llu "
1707 "deleg_type %d\n", cur
->open_state
, cur
->u
.Open
.mode
,
1708 cur
->ChangeTime
, cur
->u
.Open
.deleg_type
);
1714 NTSTATUS
unmarshal_nfs41_dirquery(
1715 nfs41_updowncall_entry
*cur
,
1716 unsigned char **buf
)
1718 NTSTATUS status
= STATUS_SUCCESS
;
1721 RtlCopyMemory(&buf_len
, *buf
, sizeof(ULONG
));
1722 #ifdef DEBUG_MARSHAL_DETAIL
1723 DbgP("unmarshal_nfs41_dirquery: reply size %d\n", buf_len
);
1725 *buf
+= sizeof(ULONG
);
1727 MmUnmapLockedPages(cur
->u
.QueryFile
.mdl_buf
, cur
->u
.QueryFile
.mdl
);
1728 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
1730 code
= _SEH2_GetExceptionCode();
1731 print_error("MmUnmapLockedPages thrown exception=0x%0x\n", code
);
1732 status
= STATUS_ACCESS_DENIED
;
1734 if (buf_len
> cur
->buf_len
)
1735 cur
->status
= STATUS_BUFFER_TOO_SMALL
;
1736 cur
->buf_len
= buf_len
;
1741 void unmarshal_nfs41_attrget(
1742 nfs41_updowncall_entry
*cur
,
1745 unsigned char **buf
)
1748 RtlCopyMemory(&buf_len
, *buf
, sizeof(ULONG
));
1749 if (buf_len
> *attr_len
) {
1750 cur
->status
= STATUS_BUFFER_TOO_SMALL
;
1753 *buf
+= sizeof(ULONG
);
1754 *attr_len
= buf_len
;
1755 RtlCopyMemory(attr_value
, *buf
, buf_len
);
1759 void unmarshal_nfs41_eaget(
1760 nfs41_updowncall_entry
*cur
,
1761 unsigned char **buf
)
1763 RtlCopyMemory(&cur
->u
.QueryEa
.Overflow
, *buf
, sizeof(ULONG
));
1764 *buf
+= sizeof(ULONG
);
1765 RtlCopyMemory(&cur
->buf_len
, *buf
, sizeof(ULONG
));
1766 *buf
+= sizeof(ULONG
);
1767 if (cur
->u
.QueryEa
.Overflow
!= ERROR_INSUFFICIENT_BUFFER
) {
1768 RtlCopyMemory(cur
->buf
, *buf
, cur
->buf_len
);
1769 *buf
+= cur
->buf_len
;
1773 void unmarshal_nfs41_getattr(
1774 nfs41_updowncall_entry
*cur
,
1775 unsigned char **buf
)
1777 unmarshal_nfs41_attrget(cur
, cur
->buf
, &cur
->buf_len
, buf
);
1778 RtlCopyMemory(&cur
->ChangeTime
, *buf
, sizeof(LONGLONG
));
1779 #ifdef DEBUG_MARSHAL_DETAIL
1780 if (cur
->u
.QueryFile
.InfoClass
== FileBasicInformation
)
1781 DbgP("[unmarshal_nfs41_getattr] ChangeTime %llu\n", cur
->ChangeTime
);
1785 NTSTATUS
unmarshal_nfs41_getacl(
1786 nfs41_updowncall_entry
*cur
,
1787 unsigned char **buf
)
1789 NTSTATUS status
= STATUS_SUCCESS
;
1792 RtlCopyMemory(&buf_len
, *buf
, sizeof(DWORD
));
1793 *buf
+= sizeof(DWORD
);
1794 cur
->buf
= RxAllocatePoolWithTag(NonPagedPool
,
1795 buf_len
, NFS41_MM_POOLTAG_ACL
);
1796 if (cur
->buf
== NULL
) {
1797 cur
->status
= status
= STATUS_INSUFFICIENT_RESOURCES
;
1800 RtlCopyMemory(cur
->buf
, *buf
, buf_len
);
1801 if (buf_len
> cur
->buf_len
)
1802 cur
->status
= STATUS_BUFFER_TOO_SMALL
;
1803 cur
->buf_len
= buf_len
;
1809 void unmarshal_nfs41_symlink(
1810 nfs41_updowncall_entry
*cur
,
1811 unsigned char **buf
)
1813 if (cur
->u
.Symlink
.set
) return;
1815 RtlCopyMemory(&cur
->u
.Symlink
.target
->Length
, *buf
, sizeof(USHORT
));
1816 *buf
+= sizeof(USHORT
);
1817 if (cur
->u
.Symlink
.target
->Length
>
1818 cur
->u
.Symlink
.target
->MaximumLength
) {
1819 cur
->status
= STATUS_BUFFER_TOO_SMALL
;
1822 RtlCopyMemory(cur
->u
.Symlink
.target
->Buffer
, *buf
,
1823 cur
->u
.Symlink
.target
->Length
);
1824 cur
->u
.Symlink
.target
->Length
-= sizeof(UNICODE_NULL
);
1827 NTSTATUS
nfs41_downcall(
1828 IN PRX_CONTEXT RxContext
)
1830 NTSTATUS status
= STATUS_SUCCESS
;
1831 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
1832 ULONG in_len
= LowIoContext
->ParamsFor
.IoCtl
.InputBufferLength
;
1833 unsigned char *buf
= LowIoContext
->ParamsFor
.IoCtl
.pInputBuffer
;
1835 nfs41_updowncall_entry
*tmp
, *cur
= NULL
;
1838 print_hexbuf(0, (unsigned char *)"downcall buffer", buf
, in_len
);
1840 tmp
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(nfs41_updowncall_entry
),
1841 NFS41_MM_POOLTAG_DOWN
);
1842 if (tmp
== NULL
) goto out
;
1844 unmarshal_nfs41_header(tmp
, &buf
);
1846 ExAcquireFastMutex(&downcallLock
);
1847 pEntry
= &downcall
.head
;
1848 pEntry
= pEntry
->Flink
;
1849 while (pEntry
!= NULL
) {
1850 cur
= (nfs41_updowncall_entry
*)CONTAINING_RECORD(pEntry
,
1851 nfs41_updowncall_entry
, next
);
1852 if (cur
->xid
== tmp
->xid
) {
1856 if (pEntry
->Flink
== &downcall
.head
)
1858 pEntry
= pEntry
->Flink
;
1860 ExReleaseFastMutex(&downcallLock
);
1861 SeStopImpersonatingClient();
1863 print_error("Didn't find xid=%lld entry\n", tmp
->xid
);
1867 ExAcquireFastMutex(&cur
->lock
);
1868 if (cur
->state
== NFS41_NOT_WAITING
) {
1869 DbgP("[downcall] Nobody is waiting for this request!!!\n");
1870 switch(cur
->opcode
) {
1873 MmUnmapLockedPages(cur
->buf
, cur
->u
.ReadWrite
.MdlAddress
);
1875 case NFS41_DIR_QUERY
:
1876 MmUnmapLockedPages(cur
->u
.QueryFile
.mdl_buf
,
1877 cur
->u
.QueryFile
.mdl
);
1878 IoFreeMdl(cur
->u
.QueryFile
.mdl
);
1881 if (cur
->u
.Open
.EaMdl
) {
1882 MmUnmapLockedPages(cur
->u
.Open
.EaBuffer
,
1884 IoFreeMdl(cur
->u
.Open
.EaMdl
);
1888 ExReleaseFastMutex(&cur
->lock
);
1889 nfs41_RemoveEntry(downcallLock
, cur
);
1891 status
= STATUS_UNSUCCESSFUL
;
1894 cur
->state
= NFS41_DONE_PROCESSING
;
1895 cur
->status
= tmp
->status
;
1896 cur
->errno
= tmp
->errno
;
1897 status
= STATUS_SUCCESS
;
1900 switch (tmp
->opcode
) {
1902 unmarshal_nfs41_mount(cur
, &buf
);
1906 status
= unmarshal_nfs41_rw(cur
, &buf
);
1909 status
= unmarshal_nfs41_open(cur
, &buf
);
1911 case NFS41_DIR_QUERY
:
1912 status
= unmarshal_nfs41_dirquery(cur
, &buf
);
1914 case NFS41_FILE_QUERY
:
1915 unmarshal_nfs41_getattr(cur
, &buf
);
1918 unmarshal_nfs41_eaget(cur
, &buf
);
1921 unmarshal_nfs41_symlink(cur
, &buf
);
1923 case NFS41_VOLUME_QUERY
:
1924 unmarshal_nfs41_attrget(cur
, cur
->buf
, &cur
->buf_len
, &buf
);
1926 case NFS41_ACL_QUERY
:
1927 status
= unmarshal_nfs41_getacl(cur
, &buf
);
1929 case NFS41_FILE_SET
:
1930 unmarshal_nfs41_setattr(cur
, &cur
->ChangeTime
, &buf
);
1933 unmarshal_nfs41_setattr(cur
, &cur
->ChangeTime
, &buf
);
1936 unmarshal_nfs41_setattr(cur
, &cur
->ChangeTime
, &buf
);
1940 ExReleaseFastMutex(&cur
->lock
);
1941 if (cur
->async_op
) {
1942 if (cur
->status
== STATUS_SUCCESS
) {
1943 cur
->u
.ReadWrite
.rxcontext
->StoredStatus
= STATUS_SUCCESS
;
1944 cur
->u
.ReadWrite
.rxcontext
->InformationToReturn
=
1947 cur
->u
.ReadWrite
.rxcontext
->StoredStatus
=
1948 map_readwrite_errors(cur
->status
);
1949 cur
->u
.ReadWrite
.rxcontext
->InformationToReturn
= 0;
1951 nfs41_RemoveEntry(downcallLock
, cur
);
1952 RxLowIoCompletion(cur
->u
.ReadWrite
.rxcontext
);
1955 KeSetEvent(&cur
->cond
, 0, FALSE
);
1963 NTSTATUS
nfs41_shutdown_daemon(
1966 NTSTATUS status
= STATUS_SUCCESS
;
1967 nfs41_updowncall_entry
*entry
= NULL
;
1970 status
= nfs41_UpcallCreate(NFS41_SHUTDOWN
, NULL
, INVALID_HANDLE_VALUE
,
1971 INVALID_HANDLE_VALUE
, version
, NULL
, &entry
);
1972 if (status
) goto out
;
1974 status
= nfs41_UpcallWaitForReply(entry
, UPCALL_TIMEOUT_DEFAULT
);
1975 SeDeleteClientSecurity(&entry
->sec_ctx
);
1976 if (status
) goto out
;
1984 NTSTATUS
SharedMemoryInit(
1985 OUT PHANDLE phSection
)
1989 UNICODE_STRING SectionName
;
1990 SECURITY_DESCRIPTOR SecurityDesc
;
1991 OBJECT_ATTRIBUTES SectionAttrs
;
1992 LARGE_INTEGER nSectionSize
;
1996 RtlInitUnicodeString(&SectionName
, NFS41_SHARED_MEMORY_NAME
);
1998 /* XXX: setting dacl=NULL grants access to everyone */
1999 status
= RtlCreateSecurityDescriptor(&SecurityDesc
,
2000 SECURITY_DESCRIPTOR_REVISION
);
2002 print_error("RtlCreateSecurityDescriptor() failed with %08X\n", status
);
2005 status
= RtlSetDaclSecurityDescriptor(&SecurityDesc
, TRUE
, NULL
, FALSE
);
2007 print_error("RtlSetDaclSecurityDescriptor() failed with %08X\n", status
);
2011 InitializeObjectAttributes(&SectionAttrs
, &SectionName
,
2012 0, NULL
, &SecurityDesc
);
2014 nSectionSize
.QuadPart
= sizeof(NFS41NP_SHARED_MEMORY
);
2016 status
= ZwCreateSection(&hSection
, SECTION_MAP_READ
| SECTION_MAP_WRITE
,
2017 &SectionAttrs
, &nSectionSize
, PAGE_READWRITE
, SEC_COMMIT
, NULL
);
2019 case STATUS_SUCCESS
:
2021 case STATUS_OBJECT_NAME_COLLISION
:
2022 DbgP("section already created; returning success\n");
2023 status
= STATUS_SUCCESS
;
2026 DbgP("ZwCreateSection failed with %08X\n", status
);
2034 NTSTATUS
SharedMemoryFree(
2039 status
= ZwClose(hSection
);
2045 NTSTATUS NTAPI
nfs41_Start(
2047 NTSTATUS
nfs41_Start(
2049 IN OUT PRX_CONTEXT RxContext
,
2050 IN OUT PRDBSS_DEVICE_OBJECT dev
)
2053 NFS41GetDeviceExtension(RxContext
, DevExt
);
2057 status
= SharedMemoryInit(&DevExt
->SharedMemorySection
);
2059 print_error("InitSharedMemory failed with %08X\n", status
);
2060 status
= STATUS_INSUFFICIENT_RESOURCES
;
2064 InterlockedCompareExchange((PLONG
)&nfs41_start_state
,
2065 NFS41_START_DRIVER_STARTED
,
2066 NFS41_START_DRIVER_START_IN_PROGRESS
);
2073 NTSTATUS NTAPI
nfs41_Stop(
2075 NTSTATUS
nfs41_Stop(
2077 IN OUT PRX_CONTEXT RxContext
,
2078 IN OUT PRDBSS_DEVICE_OBJECT dev
)
2081 NFS41GetDeviceExtension(RxContext
, DevExt
);
2083 status
= SharedMemoryFree(DevExt
->SharedMemorySection
);
2088 NTSTATUS
GetConnectionHandle(
2089 IN PUNICODE_STRING ConnectionName
,
2095 IO_STATUS_BLOCK IoStatusBlock
;
2096 OBJECT_ATTRIBUTES ObjectAttributes
;
2101 InitializeObjectAttributes(&ObjectAttributes
, ConnectionName
,
2102 OBJ_CASE_INSENSITIVE
|OBJ_KERNEL_HANDLE
, NULL
, NULL
);
2104 print_error("Len %d Buf %p\n", EaLength
, EaBuffer
);
2106 status
= ZwCreateFile(Handle
, SYNCHRONIZE
, &ObjectAttributes
,
2107 &IoStatusBlock
, NULL
, FILE_ATTRIBUTE_NORMAL
,
2108 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
2110 FILE_CREATE_TREE_CONNECTION
| FILE_SYNCHRONOUS_IO_NONALERT
,
2111 EaBuffer
, EaLength
);
2119 NTSTATUS
nfs41_GetConnectionInfoFromBuffer(
2122 OUT PUNICODE_STRING pConnectionName
,
2123 OUT PVOID
*ppEaBuffer
,
2124 OUT PULONG pEaLength
)
2126 NTSTATUS status
= STATUS_SUCCESS
;
2127 USHORT NameLength
, EaPadding
;
2128 ULONG EaLength
, BufferLenExpected
;
2131 /* make sure buffer is at least big enough for header */
2132 if (BufferLen
< sizeof(USHORT
) + sizeof(USHORT
) + sizeof(ULONG
)) {
2133 status
= STATUS_BAD_NETWORK_NAME
;
2134 print_error("Invalid input buffer.\n");
2135 pConnectionName
->Length
= pConnectionName
->MaximumLength
= 0;
2142 NameLength
= *(PUSHORT
)ptr
;
2143 ptr
+= sizeof(USHORT
);
2144 EaPadding
= *(PUSHORT
)ptr
;
2145 ptr
+= sizeof(USHORT
);
2146 EaLength
= *(PULONG
)ptr
;
2147 ptr
+= sizeof(ULONG
);
2149 /* validate buffer length */
2150 BufferLenExpected
= sizeof(USHORT
) + sizeof(USHORT
) + sizeof(ULONG
) +
2151 NameLength
+ EaPadding
+ EaLength
;
2152 if (BufferLen
!= BufferLenExpected
) {
2153 status
= STATUS_BAD_NETWORK_NAME
;
2154 print_error("Received buffer of length %lu, but expected %lu bytes.\n",
2155 BufferLen
, BufferLenExpected
);
2156 pConnectionName
->Length
= pConnectionName
->MaximumLength
= 0;
2162 pConnectionName
->Buffer
= (PWCH
)ptr
;
2163 pConnectionName
->Length
= NameLength
- sizeof(WCHAR
);
2164 pConnectionName
->MaximumLength
= NameLength
;
2167 *ppEaBuffer
= ptr
+ NameLength
+ EaPadding
;
2170 *pEaLength
= EaLength
;
2176 NTSTATUS
nfs41_CreateConnection(
2177 IN PRX_CONTEXT RxContext
,
2178 OUT PBOOLEAN PostToFsp
)
2180 NTSTATUS status
= STATUS_SUCCESS
;
2181 HANDLE Handle
= INVALID_HANDLE_VALUE
;
2182 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
2183 PVOID Buffer
= LowIoContext
->ParamsFor
.IoCtl
.pInputBuffer
, EaBuffer
;
2184 ULONG BufferLen
= LowIoContext
->ParamsFor
.IoCtl
.InputBufferLength
, EaLength
;
2185 UNICODE_STRING FileName
;
2186 BOOLEAN Wait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
2193 //just post right now!
2194 DbgP("returning STATUS_PENDING\n");
2196 status
= STATUS_PENDING
;
2200 status
= nfs41_GetConnectionInfoFromBuffer(Buffer
, BufferLen
,
2201 &FileName
, &EaBuffer
, &EaLength
);
2202 if (status
!= STATUS_SUCCESS
)
2205 status
= GetConnectionHandle(&FileName
, EaBuffer
, EaLength
, &Handle
);
2206 if (!status
&& Handle
!= INVALID_HANDLE_VALUE
)
2215 #ifdef ENABLE_TIMINGS
2218 nfs41_timings
*time
, BOOLEAN clear
)
2220 DbgP("%-9s: num_ops=%-10d delta_ticks=%-10d size=%-10d\n", op_str
,
2221 time
->tops
, time
->tops
? time
->ticks
/time
->tops
: 0,
2222 time
->sops
? time
->size
/time
->sops
: 0);
2231 NTSTATUS
nfs41_unmount(
2236 NTSTATUS status
= STATUS_INSUFFICIENT_RESOURCES
;
2237 nfs41_updowncall_entry
*entry
;
2242 status
= nfs41_UpcallCreate(NFS41_UNMOUNT
, NULL
, session
,
2243 INVALID_HANDLE_VALUE
, version
, NULL
, &entry
);
2244 SeDeleteClientSecurity(&entry
->sec_ctx
);
2245 if (status
) goto out
;
2247 nfs41_UpcallWaitForReply(entry
, timeout
);
2250 #ifdef ENABLE_TIMINGS
2251 print_op_stat("lookup", &lookup
, 1);
2252 print_op_stat("open", &open
, 1);
2253 print_op_stat("close", &close
, 1);
2254 print_op_stat("volume", &volume
, 1);
2255 print_op_stat("getattr", &getattr
, 1);
2256 print_op_stat("setattr", &setattr
, 1);
2257 print_op_stat("getexattr", &getexattr
, 1);
2258 print_op_stat("setexattr", &setexattr
, 1);
2259 print_op_stat("readdir", &readdir
, 1);
2260 print_op_stat("getacl", &getacl
, 1);
2261 print_op_stat("setacl", &setacl
, 1);
2262 print_op_stat("read", &read
, 1);
2263 print_op_stat("write", &write
, 1);
2264 print_op_stat("lock", &lock
, 1);
2265 print_op_stat("unlock", &unlock
, 1);
2273 NTSTATUS
nfs41_DeleteConnection (
2274 IN PRX_CONTEXT RxContext
,
2275 OUT PBOOLEAN PostToFsp
)
2277 NTSTATUS status
= STATUS_INVALID_PARAMETER
;
2278 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
2279 PWCHAR ConnectName
= LowIoContext
->ParamsFor
.IoCtl
.pInputBuffer
;
2280 ULONG ConnectNameLen
= LowIoContext
->ParamsFor
.IoCtl
.InputBufferLength
;
2282 UNICODE_STRING FileName
;
2283 PFILE_OBJECT pFileObject
;
2284 BOOLEAN Wait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
2291 //just post right now!
2293 DbgP("returning STATUS_PENDING\n");
2294 status
= STATUS_PENDING
;
2298 FileName
.Buffer
= ConnectName
;
2299 FileName
.Length
= (USHORT
) ConnectNameLen
- sizeof(WCHAR
);
2300 FileName
.MaximumLength
= (USHORT
) ConnectNameLen
;
2302 status
= GetConnectionHandle(&FileName
, NULL
, 0, &Handle
);
2303 if (status
!= STATUS_SUCCESS
)
2306 status
= ObReferenceObjectByHandle(Handle
, 0L, NULL
, KernelMode
,
2307 (PVOID
*)&pFileObject
, NULL
);
2308 if (NT_SUCCESS(status
)) {
2309 PV_NET_ROOT VNetRoot
;
2311 // VNetRoot exists as FOBx in the FsContext2
2312 VNetRoot
= (PV_NET_ROOT
) pFileObject
->FsContext2
;
2313 // make sure the node looks right
2314 if (NodeType(VNetRoot
) == RDBSS_NTC_V_NETROOT
)
2317 DbgP("Calling RxFinalizeConnection for NetRoot %p from VNetRoot %p\n",
2318 VNetRoot
->NetRoot
, VNetRoot
);
2320 status
= RxFinalizeConnection(VNetRoot
->NetRoot
, VNetRoot
, TRUE
);
2323 status
= STATUS_BAD_NETWORK_NAME
;
2325 ObDereferenceObject(pFileObject
);
2336 NTSTATUS NTAPI
nfs41_DevFcbXXXControlFile(
2338 NTSTATUS
nfs41_DevFcbXXXControlFile(
2340 IN OUT PRX_CONTEXT RxContext
)
2342 NTSTATUS status
= STATUS_INVALID_DEVICE_REQUEST
;
2343 UCHAR op
= RxContext
->MajorFunction
;
2344 PLOWIO_CONTEXT io_ctx
= &RxContext
->LowIoContext
;
2345 ULONG fsop
= io_ctx
->ParamsFor
.FsCtl
.FsControlCode
, state
;
2346 ULONG in_len
= io_ctx
->ParamsFor
.IoCtl
.InputBufferLength
;
2347 DWORD
*buf
= io_ctx
->ParamsFor
.IoCtl
.pInputBuffer
;
2348 NFS41GetDeviceExtension(RxContext
, DevExt
);
2349 DWORD nfs41d_version
= 0;
2355 case IRP_MJ_FILE_SYSTEM_CONTROL
:
2356 status
= STATUS_INVALID_DEVICE_REQUEST
;
2358 case IRP_MJ_DEVICE_CONTROL
:
2359 case IRP_MJ_INTERNAL_DEVICE_CONTROL
:
2360 print_fs_ioctl(0, fsop
);
2362 case IOCTL_NFS41_INVALCACHE
:
2363 nfs41_invalidate_cache(RxContext
);
2364 status
= STATUS_SUCCESS
;
2366 case IOCTL_NFS41_READ
:
2367 status
= nfs41_upcall(RxContext
);
2369 case IOCTL_NFS41_WRITE
:
2370 status
= nfs41_downcall(RxContext
);
2372 case IOCTL_NFS41_ADDCONN
:
2373 status
= nfs41_CreateConnection(RxContext
, &RxContext
->PostRequest
);
2375 case IOCTL_NFS41_DELCONN
:
2376 if (RxContext
->RxDeviceObject
->NumberOfActiveFcbs
> 0) {
2377 DbgP("device has open handles %d\n",
2378 RxContext
->RxDeviceObject
->NumberOfActiveFcbs
);
2380 if (RxContext
->RxDeviceObject
->pRxNetNameTable
!= NULL
)
2382 #define DUMP_FCB_TABLE_FROM_NETROOT(N) \
2385 BOOLEAN Release2 = FALSE; \
2386 if (!RxIsFcbTableLockAcquired(&(N)->FcbTable)) \
2388 RxAcquireFcbTableLockExclusive(&(N)->FcbTable, TRUE); \
2391 for (Bucket2 = 0; Bucket2 < (N)->FcbTable.NumberOfBuckets; ++Bucket2) \
2393 PLIST_ENTRY Entry2; \
2394 for (Entry2 = (N)->FcbTable.HashBuckets[Bucket2].Flink; \
2395 Entry2 != &(N)->FcbTable.HashBuckets[Bucket2]; \
2396 Entry2 = Entry2->Flink) \
2399 Fcb = CONTAINING_RECORD(Entry2, FCB, FcbTableEntry.HashLinks); \
2400 DbgP("Fcb: %p still has %d references\n", Fcb, Fcb->NodeReferenceCount); \
2401 DbgP("It is for: %wZ\n", &Fcb->FcbTableEntry.Path); \
2406 RxReleaseFcbTableLock(&(N)->FcbTable); \
2410 BOOLEAN Release
= FALSE
;
2412 if (!RxIsPrefixTableLockAcquired(RxContext
->RxDeviceObject
->pRxNetNameTable
))
2414 RxAcquirePrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
, TRUE
);
2418 for (Bucket
= 0; Bucket
< RxContext
->RxDeviceObject
->pRxNetNameTable
->TableSize
; ++Bucket
)
2422 for (Entry
= RxContext
->RxDeviceObject
->pRxNetNameTable
->HashBuckets
[Bucket
].Flink
;
2423 Entry
!= &RxContext
->RxDeviceObject
->pRxNetNameTable
->HashBuckets
[Bucket
];
2424 Entry
= Entry
->Flink
)
2428 Container
= CONTAINING_RECORD(Entry
, RX_PREFIX_ENTRY
, HashLinks
)->ContainingRecord
;
2429 switch (NodeType(Container
) & ~RX_SCAVENGER_MASK
)
2431 case RDBSS_NTC_NETROOT
:
2435 NetRoot
= Container
;
2436 DUMP_FCB_TABLE_FROM_NETROOT(NetRoot
);
2440 case RDBSS_NTC_V_NETROOT
:
2442 PV_NET_ROOT VNetRoot
;
2444 VNetRoot
= Container
;
2445 if (VNetRoot
->NetRoot
!= NULL
)
2449 NetRoot
= VNetRoot
->NetRoot
;
2450 DUMP_FCB_TABLE_FROM_NETROOT(NetRoot
);
2457 DbgP("Other node found: %x\n", NodeType(Container
));
2466 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
2468 #undef DUMP_FCB_TABLE_FROM_NETROOT
2472 DbgP("RxNetNameTable is NULL for: %p\n", RxContext
->RxDeviceObject
);
2475 status
= STATUS_REDIRECTOR_HAS_OPEN_HANDLES
;
2478 status
= nfs41_DeleteConnection(RxContext
, &RxContext
->PostRequest
);
2480 case IOCTL_NFS41_GETSTATE
:
2481 state
= RDR_NULL_STATE
;
2483 if (io_ctx
->ParamsFor
.IoCtl
.OutputBufferLength
>= sizeof(ULONG
)) {
2484 // map the states to control app's equivalents
2485 print_driver_state(nfs41_start_state
);
2486 switch (nfs41_start_state
) {
2487 case NFS41_START_DRIVER_STARTABLE
:
2488 case NFS41_START_DRIVER_STOPPED
:
2489 state
= RDR_STOPPED
;
2491 case NFS41_START_DRIVER_START_IN_PROGRESS
:
2492 state
= RDR_STARTING
;
2494 case NFS41_START_DRIVER_STARTED
:
2495 state
= RDR_STARTED
;
2498 *(ULONG
*)io_ctx
->ParamsFor
.IoCtl
.pOutputBuffer
= state
;
2499 RxContext
->InformationToReturn
= sizeof(ULONG
);
2500 status
= STATUS_SUCCESS
;
2502 status
= STATUS_INVALID_PARAMETER
;
2504 case IOCTL_NFS41_START
:
2505 print_driver_state(nfs41_start_state
);
2506 if (in_len
>= sizeof(DWORD
)) {
2507 RtlCopyMemory(&nfs41d_version
, buf
, sizeof(DWORD
));
2508 DbgP("NFS41 Daemon sent start request with version %d\n",
2510 DbgP("Currently used NFS41 Daemon version is %d\n",
2511 DevExt
->nfs41d_version
);
2512 DevExt
->nfs41d_version
= nfs41d_version
;
2514 switch(nfs41_start_state
) {
2515 case NFS41_START_DRIVER_STARTABLE
:
2516 (nfs41_start_driver_state
)InterlockedCompareExchange(
2517 (PLONG
)&nfs41_start_state
,
2518 NFS41_START_DRIVER_START_IN_PROGRESS
,
2519 NFS41_START_DRIVER_STARTABLE
);
2520 //lack of break is intentional
2521 case NFS41_START_DRIVER_START_IN_PROGRESS
:
2522 status
= RxStartMinirdr(RxContext
, &RxContext
->PostRequest
);
2523 if (status
== STATUS_REDIRECTOR_STARTED
) {
2524 DbgP("redirector started\n");
2525 status
= STATUS_SUCCESS
;
2526 } else if (status
== STATUS_PENDING
&&
2527 RxContext
->PostRequest
== TRUE
) {
2528 DbgP("RxStartMinirdr pending %08lx\n", status
);
2529 status
= STATUS_MORE_PROCESSING_REQUIRED
;
2532 case NFS41_START_DRIVER_STARTED
:
2533 status
= STATUS_SUCCESS
;
2536 status
= STATUS_INVALID_PARAMETER
;
2539 case IOCTL_NFS41_STOP
:
2540 if (nfs41_start_state
== NFS41_START_DRIVER_STARTED
)
2541 nfs41_shutdown_daemon(DevExt
->nfs41d_version
);
2542 if (RxContext
->RxDeviceObject
->NumberOfActiveFcbs
> 0) {
2543 DbgP("device has open handles %d\n",
2544 RxContext
->RxDeviceObject
->NumberOfActiveFcbs
);
2545 status
= STATUS_REDIRECTOR_HAS_OPEN_HANDLES
;
2549 state
= (nfs41_start_driver_state
)InterlockedCompareExchange(
2550 (PLONG
)&nfs41_start_state
,
2551 NFS41_START_DRIVER_STARTABLE
,
2552 NFS41_START_DRIVER_STARTED
);
2554 status
= RxStopMinirdr(RxContext
, &RxContext
->PostRequest
);
2555 DbgP("RxStopMinirdr status %08lx\n", status
);
2556 if (status
== STATUS_PENDING
&& RxContext
->PostRequest
== TRUE
)
2557 status
= STATUS_MORE_PROCESSING_REQUIRED
;
2560 status
= STATUS_INVALID_DEVICE_REQUEST
;
2564 status
= STATUS_INVALID_DEVICE_REQUEST
;
2572 NTSTATUS
_nfs41_CreateSrvCall(
2573 PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext
)
2576 NTSTATUS NTAPI
_nfs41_CreateSrvCall(
2579 PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext
= pContext
;
2581 NTSTATUS status
= STATUS_SUCCESS
;
2582 PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC
= pCallbackContext
;
2583 PMRX_SRV_CALL pSrvCall
;
2584 PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure
=
2585 (PMRX_SRVCALLDOWN_STRUCTURE
)(SCCBC
->SrvCalldownStructure
);
2586 PNFS41_SERVER_ENTRY pServerEntry
= NULL
;
2592 pSrvCall
= SrvCalldownStructure
->SrvCall
;
2595 ASSERT( NodeType(pSrvCall
) == RDBSS_NTC_SRVCALL
);
2596 print_srv_call(0, pSrvCall
);
2598 // validate the server name with the test name of 'pnfs'
2600 DbgP("SrvCall: Connection Name Length: %d %wZ\n",
2601 pSrvCall
->pSrvCallName
->Length
, pSrvCall
->pSrvCallName
);
2604 if (pSrvCall
->pSrvCallName
->Length
> SERVER_NAME_BUFFER_SIZE
) {
2605 print_error("Server name '%wZ' too long for server entry (max %u)\n",
2606 pSrvCall
->pSrvCallName
, SERVER_NAME_BUFFER_SIZE
);
2607 status
= STATUS_NAME_TOO_LONG
;
2611 /* Let's create our own representation of the server */
2612 pServerEntry
= (PNFS41_SERVER_ENTRY
)RxAllocatePoolWithTag(PagedPool
,
2613 sizeof(NFS41_SERVER_ENTRY
), NFS41_MM_POOLTAG
);
2614 if (pServerEntry
== NULL
) {
2615 status
= STATUS_INSUFFICIENT_RESOURCES
;
2618 RtlZeroMemory(pServerEntry
, sizeof(NFS41_SERVER_ENTRY
));
2620 pServerEntry
->Name
.Buffer
= pServerEntry
->NameBuffer
;
2621 pServerEntry
->Name
.Length
= pSrvCall
->pSrvCallName
->Length
;
2622 pServerEntry
->Name
.MaximumLength
= SERVER_NAME_BUFFER_SIZE
;
2623 RtlCopyMemory(pServerEntry
->Name
.Buffer
, pSrvCall
->pSrvCallName
->Buffer
,
2624 pServerEntry
->Name
.Length
);
2626 pCallbackContext
->RecommunicateContext
= pServerEntry
;
2628 InterlockedExchangePointer((void * volatile *)&pServerEntry
->pRdbssSrvCall
, pSrvCall
);
2630 InterlockedExchangePointer(&pServerEntry
->pRdbssSrvCall
, pSrvCall
);
2634 SCCBC
->Status
= status
;
2635 SrvCalldownStructure
->CallBack(SCCBC
);
2644 VOID NTAPI
_nfs41_CreateSrvCall_v(
2645 PVOID pCallbackContext
)
2647 _nfs41_CreateSrvCall(pCallbackContext
);
2652 NTSTATUS NTAPI
nfs41_CreateSrvCall(
2654 NTSTATUS
nfs41_CreateSrvCall(
2656 PMRX_SRV_CALL pSrvCall
,
2657 PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext
)
2662 ASSERT( NodeType(pSrvCall
) == RDBSS_NTC_SRVCALL
);
2664 if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
2665 DbgP("executing with RDBSS context\n");
2666 status
= _nfs41_CreateSrvCall(pCallbackContext
);
2668 status
= RxDispatchToWorkerThread(nfs41_dev
, DelayedWorkQueue
,
2670 _nfs41_CreateSrvCall_v
, pCallbackContext
);
2672 _nfs41_CreateSrvCall
, pCallbackContext
);
2674 if (status
!= STATUS_SUCCESS
) {
2675 print_error("RxDispatchToWorkerThread returned status %08lx\n",
2677 pCallbackContext
->Status
= status
;
2678 pCallbackContext
->SrvCalldownStructure
->CallBack(pCallbackContext
);
2679 status
= STATUS_PENDING
;
2682 /* RDBSS expects MRxCreateSrvCall to return STATUS_PENDING */
2683 if (status
== STATUS_SUCCESS
)
2684 status
= STATUS_PENDING
;
2690 NTSTATUS NTAPI
nfs41_SrvCallWinnerNotify(
2692 NTSTATUS
nfs41_SrvCallWinnerNotify(
2694 IN OUT PMRX_SRV_CALL pSrvCall
,
2695 IN BOOLEAN ThisMinirdrIsTheWinner
,
2696 IN OUT PVOID pSrvCallContext
)
2698 NTSTATUS status
= STATUS_SUCCESS
;
2699 PNFS41_SERVER_ENTRY pServerEntry
;
2701 pServerEntry
= (PNFS41_SERVER_ENTRY
)pSrvCallContext
;
2703 if (!ThisMinirdrIsTheWinner
) {
2708 pSrvCall
->Context
= pServerEntry
;
2713 NTSTATUS
map_mount_errors(
2717 case NO_ERROR
: return STATUS_SUCCESS
;
2718 case ERROR_NETWORK_UNREACHABLE
: return STATUS_NETWORK_UNREACHABLE
;
2719 case ERROR_BAD_NET_RESP
: return STATUS_UNEXPECTED_NETWORK_ERROR
;
2720 case ERROR_BAD_NET_NAME
: return STATUS_BAD_NETWORK_NAME
;
2721 case ERROR_BAD_NETPATH
: return STATUS_BAD_NETWORK_PATH
;
2723 print_error("failed to map windows error %d to NTSTATUS; "
2724 "defaulting to STATUS_INSUFFICIENT_RESOURCES\n", status
);
2725 return STATUS_INSUFFICIENT_RESOURCES
;
2729 NTSTATUS
nfs41_mount(
2730 PNFS41_MOUNT_CONFIG config
,
2734 PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs
)
2736 NTSTATUS status
= STATUS_INSUFFICIENT_RESOURCES
;
2737 nfs41_updowncall_entry
*entry
;
2741 DbgP("Server Name %wZ Mount Point %wZ SecFlavor %d\n",
2742 &config
->SrvName
, &config
->MntPt
, sec_flavor
);
2744 status
= nfs41_UpcallCreate(NFS41_MOUNT
, NULL
, *session
,
2745 INVALID_HANDLE_VALUE
, *version
, &config
->MntPt
, &entry
);
2746 if (status
) goto out
;
2748 entry
->u
.Mount
.srv_name
= &config
->SrvName
;
2749 entry
->u
.Mount
.root
= &config
->MntPt
;
2750 entry
->u
.Mount
.rsize
= config
->ReadSize
;
2751 entry
->u
.Mount
.wsize
= config
->WriteSize
;
2752 entry
->u
.Mount
.sec_flavor
= sec_flavor
;
2753 entry
->u
.Mount
.FsAttrs
= FsAttrs
;
2755 status
= nfs41_UpcallWaitForReply(entry
, config
->timeout
);
2756 SeDeleteClientSecurity(&entry
->sec_ctx
);
2757 if (status
) goto out
;
2758 *session
= entry
->session
;
2759 if (entry
->u
.Mount
.lease_time
> config
->timeout
)
2760 config
->timeout
= entry
->u
.Mount
.lease_time
;
2762 /* map windows ERRORs to NTSTATUS */
2763 status
= map_mount_errors(entry
->status
);
2764 if (status
== STATUS_SUCCESS
)
2765 *version
= entry
->version
;
2774 /* TODO: move mount config stuff to another file -cbodley */
2776 void nfs41_MountConfig_InitDefaults(
2777 OUT PNFS41_MOUNT_CONFIG Config
)
2779 RtlZeroMemory(Config
, sizeof(NFS41_MOUNT_CONFIG
));
2781 Config
->ReadSize
= MOUNT_CONFIG_RW_SIZE_DEFAULT
;
2782 Config
->WriteSize
= MOUNT_CONFIG_RW_SIZE_DEFAULT
;
2783 Config
->ReadOnly
= FALSE
;
2784 Config
->write_thru
= FALSE
;
2785 Config
->nocache
= FALSE
;
2786 Config
->SrvName
.Length
= 0;
2787 Config
->SrvName
.MaximumLength
= SERVER_NAME_BUFFER_SIZE
;
2788 Config
->SrvName
.Buffer
= Config
->srv_buffer
;
2789 Config
->MntPt
.Length
= 0;
2790 Config
->MntPt
.MaximumLength
= MAX_PATH
;
2791 Config
->MntPt
.Buffer
= Config
->mntpt_buffer
;
2792 Config
->SecFlavor
.Length
= 0;
2793 Config
->SecFlavor
.MaximumLength
= MAX_SEC_FLAVOR_LEN
;
2794 Config
->SecFlavor
.Buffer
= Config
->sec_flavor
;
2795 RtlCopyUnicodeString(&Config
->SecFlavor
, &AUTH_SYS_NAME
);
2796 Config
->timeout
= UPCALL_TIMEOUT_DEFAULT
;
2799 NTSTATUS
nfs41_MountConfig_ParseBoolean(
2800 IN PFILE_FULL_EA_INFORMATION Option
,
2801 IN PUNICODE_STRING usValue
,
2804 NTSTATUS status
= STATUS_SUCCESS
;
2806 /* if no value is specified, assume TRUE
2807 * if a value is specified, it must be a '1' */
2808 if (Option
->EaValueLength
== 0 || *usValue
->Buffer
== L
'1')
2813 DbgP(" '%ls' -> '%wZ' -> %u\n",
2814 (LPWSTR
)Option
->EaName
, usValue
, *Value
);
2818 NTSTATUS
nfs41_MountConfig_ParseDword(
2819 IN PFILE_FULL_EA_INFORMATION Option
,
2820 IN PUNICODE_STRING usValue
,
2825 NTSTATUS status
= STATUS_INVALID_PARAMETER
;
2826 LPWSTR Name
= (LPWSTR
)Option
->EaName
;
2828 if (Option
->EaValueLength
) {
2829 status
= RtlUnicodeStringToInteger(usValue
, 0, Value
);
2830 if (status
== STATUS_SUCCESS
) {
2831 #ifdef IMPOSE_MINMAX_RWSIZES
2832 if (*Value
< Minimum
)
2834 if (*Value
> Maximum
)
2836 DbgP(" '%ls' -> '%wZ' -> %lu\n", Name
, usValue
, *Value
);
2840 print_error("Failed to convert %s='%wZ' to unsigned long.\n",
2847 NTSTATUS
nfs41_MountConfig_ParseOptions(
2848 IN PFILE_FULL_EA_INFORMATION EaBuffer
,
2850 IN OUT PNFS41_MOUNT_CONFIG Config
)
2852 NTSTATUS status
= STATUS_SUCCESS
;
2853 PFILE_FULL_EA_INFORMATION Option
;
2856 UNICODE_STRING usValue
;
2858 while (status
== STATUS_SUCCESS
) {
2859 Name
= (LPWSTR
)Option
->EaName
;
2860 NameLen
= Option
->EaNameLength
/sizeof(WCHAR
);
2862 usValue
.Length
= usValue
.MaximumLength
= Option
->EaValueLength
;
2863 usValue
.Buffer
= (PWCH
)(Option
->EaName
+
2864 Option
->EaNameLength
+ sizeof(WCHAR
));
2866 if (wcsncmp(L
"ro", Name
, NameLen
) == 0) {
2867 status
= nfs41_MountConfig_ParseBoolean(Option
, &usValue
,
2870 else if (wcsncmp(L
"writethru", Name
, NameLen
) == 0) {
2871 status
= nfs41_MountConfig_ParseBoolean(Option
, &usValue
,
2872 &Config
->write_thru
);
2874 else if (wcsncmp(L
"nocache", Name
, NameLen
) == 0) {
2875 status
= nfs41_MountConfig_ParseBoolean(Option
, &usValue
,
2878 else if (wcsncmp(L
"timeout", Name
, NameLen
) == 0) {
2879 status
= nfs41_MountConfig_ParseDword(Option
, &usValue
,
2880 &Config
->timeout
, UPCALL_TIMEOUT_DEFAULT
,
2881 UPCALL_TIMEOUT_DEFAULT
);
2883 else if (wcsncmp(L
"rsize", Name
, NameLen
) == 0) {
2884 status
= nfs41_MountConfig_ParseDword(Option
, &usValue
,
2885 &Config
->ReadSize
, MOUNT_CONFIG_RW_SIZE_MIN
,
2886 MOUNT_CONFIG_RW_SIZE_MAX
);
2888 else if (wcsncmp(L
"wsize", Name
, NameLen
) == 0) {
2889 status
= nfs41_MountConfig_ParseDword(Option
, &usValue
,
2890 &Config
->WriteSize
, MOUNT_CONFIG_RW_SIZE_MIN
,
2891 MOUNT_CONFIG_RW_SIZE_MAX
);
2893 else if (wcsncmp(L
"srvname", Name
, NameLen
) == 0) {
2894 if (usValue
.Length
> Config
->SrvName
.MaximumLength
)
2895 status
= STATUS_NAME_TOO_LONG
;
2897 RtlCopyUnicodeString(&Config
->SrvName
, &usValue
);
2899 else if (wcsncmp(L
"mntpt", Name
, NameLen
) == 0) {
2900 if (usValue
.Length
> Config
->MntPt
.MaximumLength
)
2901 status
= STATUS_NAME_TOO_LONG
;
2903 RtlCopyUnicodeString(&Config
->MntPt
, &usValue
);
2905 else if (wcsncmp(L
"sec", Name
, NameLen
) == 0) {
2906 if (usValue
.Length
> Config
->SecFlavor
.MaximumLength
)
2907 status
= STATUS_NAME_TOO_LONG
;
2909 RtlCopyUnicodeString(&Config
->SecFlavor
, &usValue
);
2912 status
= STATUS_INVALID_PARAMETER
;
2913 print_error("Unrecognized option '%ls' -> '%wZ'\n",
2917 if (Option
->NextEntryOffset
== 0)
2920 Option
= (PFILE_FULL_EA_INFORMATION
)
2921 ((PBYTE
)Option
+ Option
->NextEntryOffset
);
2927 NTSTATUS
has_nfs_prefix(
2928 IN PUNICODE_STRING SrvCallName
,
2929 IN PUNICODE_STRING NetRootName
)
2931 NTSTATUS status
= STATUS_BAD_NETWORK_NAME
;
2933 if (NetRootName
->Length
== SrvCallName
->Length
+ NfsPrefix
.Length
) {
2934 const UNICODE_STRING NetRootPrefix
= {
2936 NetRootName
->MaximumLength
- SrvCallName
->Length
,
2937 &NetRootName
->Buffer
[SrvCallName
->Length
/2]
2939 if (RtlCompareUnicodeString(&NetRootPrefix
, &NfsPrefix
, FALSE
) == 0)
2940 status
= STATUS_SUCCESS
;
2945 NTSTATUS
map_sec_flavor(
2946 IN PUNICODE_STRING sec_flavor_name
,
2947 OUT PDWORD sec_flavor
)
2949 if (RtlCompareUnicodeString(sec_flavor_name
, &AUTH_SYS_NAME
, FALSE
) == 0)
2950 *sec_flavor
= RPCSEC_AUTH_SYS
;
2951 else if (RtlCompareUnicodeString(sec_flavor_name
, &AUTHGSS_KRB5_NAME
, FALSE
) == 0)
2952 *sec_flavor
= RPCSEC_AUTHGSS_KRB5
;
2953 else if (RtlCompareUnicodeString(sec_flavor_name
, &AUTHGSS_KRB5I_NAME
, FALSE
) == 0)
2954 *sec_flavor
= RPCSEC_AUTHGSS_KRB5I
;
2955 else if (RtlCompareUnicodeString(sec_flavor_name
, &AUTHGSS_KRB5P_NAME
, FALSE
) == 0)
2956 *sec_flavor
= RPCSEC_AUTHGSS_KRB5P
;
2957 else return STATUS_INVALID_PARAMETER
;
2958 return STATUS_SUCCESS
;
2961 NTSTATUS
nfs41_GetLUID(
2964 NTSTATUS status
= STATUS_SUCCESS
;
2965 SECURITY_SUBJECT_CONTEXT sec_ctx
;
2966 SECURITY_QUALITY_OF_SERVICE sec_qos
;
2967 SECURITY_CLIENT_CONTEXT clnt_sec_ctx
;
2969 SeCaptureSubjectContext(&sec_ctx
);
2970 sec_qos
.ContextTrackingMode
= SECURITY_DYNAMIC_TRACKING
;
2971 sec_qos
.ImpersonationLevel
= SecurityIdentification
;
2972 sec_qos
.Length
= sizeof(SECURITY_QUALITY_OF_SERVICE
);
2973 sec_qos
.EffectiveOnly
= 0;
2974 status
= SeCreateClientSecurityFromSubjectContext(&sec_ctx
, &sec_qos
, 1,
2977 print_error("nfs41_GetLUID: SeCreateClientSecurityFromSubjectContext "
2978 "failed %x\n", status
);
2979 goto release_sec_ctx
;
2981 status
= SeQueryAuthenticationIdToken(clnt_sec_ctx
.ClientToken
, id
);
2983 print_error("SeQueryAuthenticationIdToken failed %x\n", status
);
2984 goto release_clnt_sec_ctx
;
2986 release_clnt_sec_ctx
:
2987 SeDeleteClientSecurity(&clnt_sec_ctx
);
2989 SeReleaseSubjectContext(&sec_ctx
);
2994 NTSTATUS
nfs41_get_sec_ctx(
2995 IN
enum _SECURITY_IMPERSONATION_LEVEL level
,
2996 OUT PSECURITY_CLIENT_CONTEXT out_ctx
)
2999 SECURITY_SUBJECT_CONTEXT ctx
;
3000 SECURITY_QUALITY_OF_SERVICE sec_qos
;
3002 SeCaptureSubjectContext(&ctx
);
3003 sec_qos
.ContextTrackingMode
= SECURITY_STATIC_TRACKING
;
3004 sec_qos
.ImpersonationLevel
= level
;
3005 sec_qos
.Length
= sizeof(SECURITY_QUALITY_OF_SERVICE
);
3006 sec_qos
.EffectiveOnly
= 0;
3007 status
= SeCreateClientSecurityFromSubjectContext(&ctx
, &sec_qos
, 1, out_ctx
);
3008 if (status
!= STATUS_SUCCESS
) {
3009 print_error("SeCreateClientSecurityFromSubjectContext "
3010 "failed with %x\n", status
);
3013 DbgP("Created client security token %p\n", out_ctx
->ClientToken
);
3015 SeReleaseSubjectContext(&ctx
);
3021 NTSTATUS NTAPI
nfs41_CreateVNetRoot(
3023 NTSTATUS
nfs41_CreateVNetRoot(
3025 IN OUT PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext
)
3027 NTSTATUS status
= STATUS_SUCCESS
;
3028 NFS41_MOUNT_CONFIG
*Config
;
3029 __notnull PMRX_V_NET_ROOT pVNetRoot
= (PMRX_V_NET_ROOT
)
3030 pCreateNetRootContext
->pVNetRoot
;
3031 __notnull PMRX_NET_ROOT pNetRoot
= pVNetRoot
->pNetRoot
;
3032 __notnull PMRX_SRV_CALL pSrvCall
= pNetRoot
->pSrvCall
;
3033 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
3034 NFS41GetVNetRootExtension(pVNetRoot
);
3035 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
3036 NFS41GetNetRootExtension(pNetRoot
);
3037 NFS41GetDeviceExtension(pCreateNetRootContext
->RxContext
,DevExt
);
3038 DWORD nfs41d_version
= DevExt
->nfs41d_version
;
3039 nfs41_mount_entry
*existing_mount
= NULL
;
3041 BOOLEAN found_existing_mount
= FALSE
, found_matching_flavor
= FALSE
;
3043 ASSERT((NodeType(pNetRoot
) == RDBSS_NTC_NETROOT
) &&
3044 (NodeType(pNetRoot
->pSrvCall
) == RDBSS_NTC_SRVCALL
));
3048 print_srv_call(0, pSrvCall
);
3049 print_net_root(0, pNetRoot
);
3050 print_v_net_root(0, pVNetRoot
);
3052 DbgP("pVNetRoot=%p pNetRoot=%p pSrvCall=%p\n", pVNetRoot
, pNetRoot
, pSrvCall
);
3053 DbgP("pNetRoot=%wZ Type=%d pSrvCallName=%wZ VirtualNetRootStatus=0x%x "
3054 "NetRootStatus=0x%x\n", pNetRoot
->pNetRootName
,
3055 pNetRoot
->Type
, pSrvCall
->pSrvCallName
,
3056 pCreateNetRootContext
->VirtualNetRootStatus
,
3057 pCreateNetRootContext
->NetRootStatus
);
3060 if (pNetRoot
->Type
!= NET_ROOT_DISK
&& pNetRoot
->Type
!= NET_ROOT_WILD
) {
3061 print_error("nfs41_CreateVNetRoot: Unsupported NetRoot Type %u\n",
3063 status
= STATUS_NOT_SUPPORTED
;
3067 pVNetRootContext
->session
= INVALID_HANDLE_VALUE
;
3069 /* In order to cooperate with other network providers, we must
3070 * only claim paths of the form '\\server\nfs4\path' */
3071 status
= has_nfs_prefix(pSrvCall
->pSrvCallName
, pNetRoot
->pNetRootName
);
3073 print_error("nfs41_CreateVNetRoot: NetRootName %wZ doesn't match "
3074 "'\\nfs4'!\n", pNetRoot
->pNetRootName
);
3077 pNetRoot
->MRxNetRootState
= MRX_NET_ROOT_STATE_GOOD
;
3078 pNetRoot
->DeviceType
= FILE_DEVICE_DISK
;
3080 Config
= RxAllocatePoolWithTag(NonPagedPool
,
3081 sizeof(NFS41_MOUNT_CONFIG
), NFS41_MM_POOLTAG
);
3082 if (Config
== NULL
) {
3083 status
= STATUS_INSUFFICIENT_RESOURCES
;
3086 nfs41_MountConfig_InitDefaults(Config
);
3088 if (pCreateNetRootContext
->RxContext
->Create
.EaLength
) {
3089 /* parse the extended attributes for mount options */
3090 status
= nfs41_MountConfig_ParseOptions(
3091 pCreateNetRootContext
->RxContext
->Create
.EaBuffer
,
3092 pCreateNetRootContext
->RxContext
->Create
.EaLength
,
3094 if (status
!= STATUS_SUCCESS
)
3096 pVNetRootContext
->read_only
= Config
->ReadOnly
;
3097 pVNetRootContext
->write_thru
= Config
->write_thru
;
3098 pVNetRootContext
->nocache
= Config
->nocache
;
3100 /* use the SRV_CALL name (without leading \) as the hostname */
3101 Config
->SrvName
.Buffer
= pSrvCall
->pSrvCallName
->Buffer
+ 1;
3102 Config
->SrvName
.Length
=
3103 pSrvCall
->pSrvCallName
->Length
- sizeof(WCHAR
);
3104 Config
->SrvName
.MaximumLength
=
3105 pSrvCall
->pSrvCallName
->MaximumLength
- sizeof(WCHAR
);
3107 pVNetRootContext
->MountPathLen
= Config
->MntPt
.Length
;
3108 pVNetRootContext
->timeout
= Config
->timeout
;
3110 status
= map_sec_flavor(&Config
->SecFlavor
, &pVNetRootContext
->sec_flavor
);
3111 if (status
!= STATUS_SUCCESS
) {
3112 DbgP("Invalid rpcsec security flavor %wZ\n", &Config
->SecFlavor
);
3116 status
= nfs41_GetLUID(&luid
);
3120 if (!pNetRootContext
->mounts_init
) {
3122 DbgP("Initializing mount array\n");
3124 ExInitializeFastMutex(&pNetRootContext
->mountLock
);
3125 InitializeListHead(&pNetRootContext
->mounts
.head
);
3126 pNetRootContext
->mounts_init
= TRUE
;
3130 ExAcquireFastMutex(&pNetRootContext
->mountLock
);
3131 pEntry
= &pNetRootContext
->mounts
.head
;
3132 pEntry
= pEntry
->Flink
;
3133 while (pEntry
!= NULL
) {
3134 existing_mount
= (nfs41_mount_entry
*)CONTAINING_RECORD(pEntry
,
3135 nfs41_mount_entry
, next
);
3137 DbgP("comparing %x.%x with %x.%x\n", luid
.HighPart
, luid
.LowPart
,
3138 existing_mount
->login_id
.HighPart
, existing_mount
->login_id
.LowPart
);
3140 if (RtlEqualLuid(&luid
, &existing_mount
->login_id
)) {
3142 DbgP("Found a matching LUID entry\n");
3144 found_existing_mount
= TRUE
;
3145 switch(pVNetRootContext
->sec_flavor
) {
3146 case RPCSEC_AUTH_SYS
:
3147 if (existing_mount
->authsys_session
!= INVALID_HANDLE_VALUE
)
3148 pVNetRootContext
->session
=
3149 existing_mount
->authsys_session
;
3151 case RPCSEC_AUTHGSS_KRB5
:
3152 if (existing_mount
->gssi_session
!= INVALID_HANDLE_VALUE
)
3153 pVNetRootContext
->session
= existing_mount
->gss_session
;
3155 case RPCSEC_AUTHGSS_KRB5I
:
3156 if (existing_mount
->gss_session
!= INVALID_HANDLE_VALUE
)
3157 pVNetRootContext
->session
= existing_mount
->gssi_session
;
3159 case RPCSEC_AUTHGSS_KRB5P
:
3160 if (existing_mount
->gssp_session
!= INVALID_HANDLE_VALUE
)
3161 pVNetRootContext
->session
= existing_mount
->gssp_session
;
3164 if (pVNetRootContext
->session
&&
3165 pVNetRootContext
->session
!= INVALID_HANDLE_VALUE
)
3166 found_matching_flavor
= 1;
3169 if (pEntry
->Flink
== &pNetRootContext
->mounts
.head
)
3171 pEntry
= pEntry
->Flink
;
3173 ExReleaseFastMutex(&pNetRootContext
->mountLock
);
3175 if (!found_matching_flavor
)
3176 DbgP("Didn't find matching security flavor\n");
3180 /* send the mount upcall */
3181 status
= nfs41_mount(Config
, pVNetRootContext
->sec_flavor
,
3182 &pVNetRootContext
->session
, &nfs41d_version
,
3183 &pVNetRootContext
->FsAttrs
);
3184 if (status
!= STATUS_SUCCESS
) {
3185 BOOLEAN MountsEmpty
;
3186 nfs41_IsListEmpty(pNetRootContext
->mountLock
,
3187 pNetRootContext
->mounts
, MountsEmpty
);
3188 if (!found_existing_mount
&& MountsEmpty
)
3189 pNetRootContext
->mounts_init
= FALSE
;
3190 pVNetRootContext
->session
= INVALID_HANDLE_VALUE
;
3193 pVNetRootContext
->timeout
= Config
->timeout
;
3195 if (!found_existing_mount
) {
3196 /* create a new mount entry and add it to the list */
3197 nfs41_mount_entry
*entry
;
3198 entry
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(nfs41_mount_entry
),
3199 NFS41_MM_POOLTAG_MOUNT
);
3200 if (entry
== NULL
) {
3201 status
= STATUS_INSUFFICIENT_RESOURCES
;
3204 entry
->authsys_session
= entry
->gss_session
=
3205 entry
->gssi_session
= entry
->gssp_session
= INVALID_HANDLE_VALUE
;
3206 switch (pVNetRootContext
->sec_flavor
) {
3207 case RPCSEC_AUTH_SYS
:
3208 entry
->authsys_session
= pVNetRootContext
->session
; break;
3209 case RPCSEC_AUTHGSS_KRB5
:
3210 entry
->gss_session
= pVNetRootContext
->session
; break;
3211 case RPCSEC_AUTHGSS_KRB5I
:
3212 entry
->gssi_session
= pVNetRootContext
->session
; break;
3213 case RPCSEC_AUTHGSS_KRB5P
:
3214 entry
->gssp_session
= pVNetRootContext
->session
; break;
3216 RtlCopyLuid(&entry
->login_id
, &luid
);
3217 nfs41_AddEntry(pNetRootContext
->mountLock
,
3218 pNetRootContext
->mounts
, entry
);
3219 } else if (!found_matching_flavor
) {
3220 ASSERT(existing_mount
!= NULL
);
3221 /* modify existing mount entry */
3223 DbgP("Using existing %d flavor session 0x%x\n",
3224 pVNetRootContext
->sec_flavor
);
3226 switch (pVNetRootContext
->sec_flavor
) {
3227 case RPCSEC_AUTH_SYS
:
3228 existing_mount
->authsys_session
= pVNetRootContext
->session
; break;
3229 case RPCSEC_AUTHGSS_KRB5
:
3230 existing_mount
->gss_session
= pVNetRootContext
->session
; break;
3231 case RPCSEC_AUTHGSS_KRB5I
:
3232 existing_mount
->gssi_session
= pVNetRootContext
->session
; break;
3233 case RPCSEC_AUTHGSS_KRB5P
:
3234 existing_mount
->gssp_session
= pVNetRootContext
->session
; break;
3237 pNetRootContext
->nfs41d_version
= nfs41d_version
;
3239 DbgP("Saving new session 0x%x\n", pVNetRootContext
->session
);
3241 #ifdef STORE_MOUNT_SEC_CONTEXT
3242 status
= nfs41_get_sec_ctx(SecurityImpersonation
,
3243 &pVNetRootContext
->mount_sec_ctx
);
3249 pCreateNetRootContext
->VirtualNetRootStatus
= status
;
3250 if (pNetRoot
->Context
== NULL
)
3251 pCreateNetRootContext
->NetRootStatus
= status
;
3252 pCreateNetRootContext
->Callback(pCreateNetRootContext
);
3254 /* RDBSS expects that MRxCreateVNetRoot returns STATUS_PENDING
3255 * on success or failure */
3256 status
= STATUS_PENDING
;
3264 VOID NTAPI
nfs41_ExtractNetRootName(
3266 VOID
nfs41_ExtractNetRootName(
3268 IN PUNICODE_STRING FilePathName
,
3269 IN PMRX_SRV_CALL SrvCall
,
3270 OUT PUNICODE_STRING NetRootName
,
3271 OUT PUNICODE_STRING RestOfName OPTIONAL
)
3273 ULONG length
= FilePathName
->Length
;
3274 PWCH w
= FilePathName
->Buffer
;
3275 PWCH wlimit
= (PWCH
)(((PCHAR
)w
)+length
);
3278 w
+= (SrvCall
->pSrvCallName
->Length
/sizeof(WCHAR
));
3279 NetRootName
->Buffer
= wlow
= w
;
3280 /* parse the entire path into NetRootName */
3287 if ((*w
== OBJ_NAME_PATH_SEPARATOR
) && (w
!= wlow
))
3292 NetRootName
->Length
= NetRootName
->MaximumLength
3293 = (USHORT
)((PCHAR
)w
- (PCHAR
)wlow
);
3295 DbgP("In: pSrvCall %p PathName=%wZ SrvCallName=%wZ Out: NetRootName=%wZ\n",
3296 SrvCall
, FilePathName
, SrvCall
->pSrvCallName
, NetRootName
);
3303 NTSTATUS NTAPI
nfs41_FinalizeSrvCall(
3305 NTSTATUS
nfs41_FinalizeSrvCall(
3307 PMRX_SRV_CALL pSrvCall
,
3310 NTSTATUS status
= STATUS_SUCCESS
;
3311 PNFS41_SERVER_ENTRY pServerEntry
= (PNFS41_SERVER_ENTRY
)(pSrvCall
->Context
);
3316 print_srv_call(0, pSrvCall
);
3318 if (pSrvCall
->Context
== NULL
)
3322 InterlockedCompareExchangePointer(&pServerEntry
->pRdbssSrvCall
,
3325 InterlockedCompareExchangePointer((void * volatile *)&pServerEntry
->pRdbssSrvCall
,
3328 RxFreePool(pServerEntry
);
3330 pSrvCall
->Context
= NULL
;
3339 NTSTATUS NTAPI
nfs41_FinalizeNetRoot(
3341 NTSTATUS
nfs41_FinalizeNetRoot(
3343 IN OUT PMRX_NET_ROOT pNetRoot
,
3344 IN PBOOLEAN ForceDisconnect
)
3346 NTSTATUS status
= STATUS_SUCCESS
;
3347 PNFS41_NETROOT_EXTENSION pNetRootContext
=
3348 NFS41GetNetRootExtension((PMRX_NET_ROOT
)pNetRoot
);
3349 nfs41_updowncall_entry
*tmp
;
3350 nfs41_mount_entry
*mount_tmp
;
3354 print_net_root(1, pNetRoot
);
3357 if (pNetRoot
->Type
!= NET_ROOT_DISK
&& pNetRoot
->Type
!= NET_ROOT_WILD
) {
3358 status
= STATUS_NOT_SUPPORTED
;
3362 if (pNetRootContext
== NULL
|| !pNetRootContext
->mounts_init
) {
3363 print_error("nfs41_FinalizeNetRoot: No valid session established\n");
3367 if (pNetRoot
->NumberOfFcbs
> 0 || pNetRoot
->NumberOfSrvOpens
> 0) {
3368 print_error("%d open Fcbs %d open SrvOpens\n", pNetRoot
->NumberOfFcbs
,
3369 pNetRoot
->NumberOfSrvOpens
);
3374 nfs41_GetFirstMountEntry(pNetRootContext
->mountLock
,
3375 pNetRootContext
->mounts
, mount_tmp
);
3376 if (mount_tmp
== NULL
)
3379 DbgP("Removing entry luid %x.%x from mount list\n",
3380 mount_tmp
->login_id
.HighPart
, mount_tmp
->login_id
.LowPart
);
3382 if (mount_tmp
->authsys_session
!= INVALID_HANDLE_VALUE
) {
3383 status
= nfs41_unmount(mount_tmp
->authsys_session
,
3384 pNetRootContext
->nfs41d_version
, UPCALL_TIMEOUT_DEFAULT
);
3386 print_error("nfs41_unmount AUTH_SYS failed with %d\n", status
);
3388 if (mount_tmp
->gss_session
!= INVALID_HANDLE_VALUE
) {
3389 status
= nfs41_unmount(mount_tmp
->gss_session
,
3390 pNetRootContext
->nfs41d_version
, UPCALL_TIMEOUT_DEFAULT
);
3392 print_error("nfs41_unmount RPCSEC_GSS_KRB5 failed with %d\n",
3395 if (mount_tmp
->gssi_session
!= INVALID_HANDLE_VALUE
) {
3396 status
= nfs41_unmount(mount_tmp
->gssi_session
,
3397 pNetRootContext
->nfs41d_version
, UPCALL_TIMEOUT_DEFAULT
);
3399 print_error("nfs41_unmount RPCSEC_GSS_KRB5I failed with %d\n",
3402 if (mount_tmp
->gssp_session
!= INVALID_HANDLE_VALUE
) {
3403 status
= nfs41_unmount(mount_tmp
->gssp_session
,
3404 pNetRootContext
->nfs41d_version
, UPCALL_TIMEOUT_DEFAULT
);
3406 print_error("nfs41_unmount RPCSEC_GSS_KRB5P failed with %d\n",
3409 nfs41_RemoveEntry(pNetRootContext
->mountLock
, mount_tmp
);
3410 RxFreePool(mount_tmp
);
3412 /* ignore any errors from unmount */
3413 status
= STATUS_SUCCESS
;
3415 // check if there is anything waiting in the upcall or downcall queue
3417 nfs41_GetFirstEntry(upcallLock
, upcall
, tmp
);
3419 DbgP("Removing entry from upcall list\n");
3420 nfs41_RemoveEntry(upcallLock
, tmp
);
3421 tmp
->status
= STATUS_INSUFFICIENT_RESOURCES
;
3422 KeSetEvent(&tmp
->cond
, 0, FALSE
);
3428 nfs41_GetFirstEntry(downcallLock
, downcall
, tmp
);
3430 DbgP("Removing entry from downcall list\n");
3431 nfs41_RemoveEntry(downcallLock
, tmp
);
3432 tmp
->status
= STATUS_INSUFFICIENT_RESOURCES
;
3433 KeSetEvent(&tmp
->cond
, 0, FALSE
);
3445 NTSTATUS NTAPI
nfs41_FinalizeVNetRoot(
3447 NTSTATUS
nfs41_FinalizeVNetRoot(
3449 IN OUT PMRX_V_NET_ROOT pVNetRoot
,
3450 IN PBOOLEAN ForceDisconnect
)
3452 NTSTATUS status
= STATUS_SUCCESS
;
3453 PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
3454 NFS41GetVNetRootExtension(pVNetRoot
);
3457 print_v_net_root(1, pVNetRoot
);
3459 if (pVNetRoot
->pNetRoot
->Type
!= NET_ROOT_DISK
&&
3460 pVNetRoot
->pNetRoot
->Type
!= NET_ROOT_WILD
)
3461 status
= STATUS_NOT_SUPPORTED
;
3462 #ifdef STORE_MOUNT_SEC_CONTEXT
3463 else if (pVNetRootContext
->session
!= INVALID_HANDLE_VALUE
) {
3465 DbgP("nfs41_FinalizeVNetRoot: deleting security context: %p\n",
3466 pVNetRootContext
->mount_sec_ctx
.ClientToken
);
3468 SeDeleteClientSecurity(&pVNetRootContext
->mount_sec_ctx
);
3477 BOOLEAN
isDataAccess(
3480 if (mask
& (FILE_READ_DATA
| FILE_WRITE_DATA
| FILE_APPEND_DATA
))
3485 BOOLEAN
isOpen2Create(
3488 if (disposition
== FILE_CREATE
|| disposition
== FILE_OPEN_IF
||
3489 disposition
== FILE_OVERWRITE_IF
|| disposition
== FILE_SUPERSEDE
)
3494 BOOLEAN
isFilenameTooLong(
3495 PUNICODE_STRING name
,
3496 PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
)
3498 PFILE_FS_ATTRIBUTE_INFORMATION attrs
= &pVNetRootContext
->FsAttrs
;
3499 LONG len
= attrs
->MaximumComponentNameLength
, count
= 1, i
;
3500 PWCH p
= name
->Buffer
;
3501 for (i
= 0; i
< name
->Length
/ 2; i
++) {
3502 if (p
[0] == L
'\\') count
= 1;
3504 if (p
[0] == L
'\0') return FALSE
;
3505 if (count
> len
) return TRUE
;
3514 PUNICODE_STRING name
)
3517 PWCH p
= name
->Buffer
;
3518 for (i
= 0; i
< name
->Length
/ 2; i
++) {
3519 if (p
[0] == L
':') return TRUE
;
3520 else if (p
[0] == L
'\0') return FALSE
;
3526 BOOLEAN
areOpenParamsValid(NT_CREATE_PARAMETERS
*params
)
3528 /* from ms-fsa page 52 */
3529 if ((params
->CreateOptions
& FILE_DELETE_ON_CLOSE
) &&
3530 !(params
->DesiredAccess
& DELETE
))
3532 if ((params
->CreateOptions
& FILE_DIRECTORY_FILE
) &&
3533 (params
->Disposition
== FILE_SUPERSEDE
||
3534 params
->Disposition
== FILE_OVERWRITE
||
3535 params
->Disposition
== FILE_OVERWRITE_IF
))
3537 if ((params
->CreateOptions
& FILE_NO_INTERMEDIATE_BUFFERING
) &&
3538 (params
->DesiredAccess
& FILE_APPEND_DATA
) &&
3539 !(params
->DesiredAccess
& FILE_WRITE_DATA
))
3541 /* from ms-fsa 3.1.5.1.1 page 56 */
3542 if ((params
->CreateOptions
& FILE_DIRECTORY_FILE
) &&
3543 (params
->FileAttributes
& FILE_ATTRIBUTE_TEMPORARY
))
3548 NTSTATUS
map_open_errors(
3553 case NO_ERROR
: return STATUS_SUCCESS
;
3554 case ERROR_ACCESS_DENIED
:
3555 if (len
> 0) return STATUS_ACCESS_DENIED
;
3556 else return STATUS_SUCCESS
;
3557 case ERROR_INVALID_REPARSE_DATA
:
3558 case ERROR_INVALID_NAME
: return STATUS_OBJECT_NAME_INVALID
;
3559 case ERROR_FILE_EXISTS
: return STATUS_OBJECT_NAME_COLLISION
;
3560 case ERROR_FILE_INVALID
: return STATUS_FILE_INVALID
;
3561 case ERROR_FILE_NOT_FOUND
: return STATUS_OBJECT_NAME_NOT_FOUND
;
3562 case ERROR_FILENAME_EXCED_RANGE
: return STATUS_NAME_TOO_LONG
;
3563 case ERROR_NETWORK_ACCESS_DENIED
: return STATUS_NETWORK_ACCESS_DENIED
;
3564 case ERROR_PATH_NOT_FOUND
: return STATUS_OBJECT_PATH_NOT_FOUND
;
3565 case ERROR_BAD_NETPATH
: return STATUS_BAD_NETWORK_PATH
;
3566 case ERROR_SHARING_VIOLATION
: return STATUS_SHARING_VIOLATION
;
3567 case ERROR_REPARSE
: return STATUS_REPARSE
;
3568 case ERROR_TOO_MANY_LINKS
: return STATUS_TOO_MANY_LINKS
;
3569 case ERROR_DIRECTORY
: return STATUS_FILE_IS_A_DIRECTORY
;
3570 case ERROR_BAD_FILE_TYPE
: return STATUS_NOT_A_DIRECTORY
;
3572 print_error("[ERROR] nfs41_Create: upcall returned %d returning "
3573 "STATUS_INSUFFICIENT_RESOURCES\n", status
);
3574 case ERROR_OUTOFMEMORY
: return STATUS_INSUFFICIENT_RESOURCES
;
3578 DWORD
map_disposition_to_create_retval(
3582 switch(disposition
) {
3583 case FILE_SUPERSEDE
:
3584 if (errno
== ERROR_FILE_NOT_FOUND
) return FILE_CREATED
;
3585 else return FILE_SUPERSEDED
;
3586 case FILE_CREATE
: return FILE_CREATED
;
3587 case FILE_OPEN
: return FILE_OPENED
;
3589 if (errno
== ERROR_FILE_NOT_FOUND
) return FILE_CREATED
;
3590 else return FILE_OPENED
;
3591 case FILE_OVERWRITE
: return FILE_OVERWRITTEN
;
3592 case FILE_OVERWRITE_IF
:
3593 if (errno
== ERROR_FILE_NOT_FOUND
) return FILE_CREATED
;
3594 else return FILE_OVERWRITTEN
;
3596 print_error("unknown disposition %d\n", disposition
);
3601 static BOOLEAN
create_should_pass_ea(
3602 IN PFILE_FULL_EA_INFORMATION ea
,
3603 IN ULONG disposition
)
3605 /* don't pass cygwin EAs */
3606 if (AnsiStrEq(&NfsV3Attributes
, ea
->EaName
, ea
->EaNameLength
)
3607 || AnsiStrEq(&NfsActOnLink
, ea
->EaName
, ea
->EaNameLength
)
3608 || AnsiStrEq(&NfsSymlinkTargetName
, ea
->EaName
, ea
->EaNameLength
))
3610 /* only set EAs on file creation */
3611 return disposition
== FILE_SUPERSEDE
|| disposition
== FILE_CREATE
3612 || disposition
== FILE_OPEN_IF
|| disposition
== FILE_OVERWRITE
3613 || disposition
== FILE_OVERWRITE_IF
;
3616 NTSTATUS
check_nfs41_create_args(
3617 IN PRX_CONTEXT RxContext
)
3619 NTSTATUS status
= STATUS_SUCCESS
;
3620 PNT_CREATE_PARAMETERS params
= &RxContext
->Create
.NtCreateParameters
;
3621 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
3622 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
3623 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
3624 __notnull PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs
=
3625 &pVNetRootContext
->FsAttrs
;
3626 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
3627 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
3628 __notnull PMRX_FCB Fcb
= RxContext
->pFcb
;
3629 __notnull PNFS41_FCB nfs41_fcb
= (PNFS41_FCB
)Fcb
->Context
;
3630 PFILE_FULL_EA_INFORMATION ea
= (PFILE_FULL_EA_INFORMATION
)
3631 RxContext
->CurrentIrp
->AssociatedIrp
.SystemBuffer
;
3633 if (Fcb
->pNetRoot
->Type
!= NET_ROOT_DISK
&&
3634 Fcb
->pNetRoot
->Type
!= NET_ROOT_WILD
) {
3635 print_error("nfs41_Create: Unsupported NetRoot Type %u\n",
3636 Fcb
->pNetRoot
->Type
);
3637 status
= STATUS_NOT_SUPPORTED
;
3641 if (FlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
)) {
3642 print_error("FCB_STATE_PAGING_FILE not implemented\n");
3643 status
= STATUS_NOT_IMPLEMENTED
;
3647 if (!pNetRootContext
->mounts_init
) {
3648 print_error("nfs41_Create: No valid session established\n");
3649 status
= STATUS_INSUFFICIENT_RESOURCES
;
3653 if (isStream(SrvOpen
->pAlreadyPrefixedName
)) {
3654 status
= STATUS_NOT_SUPPORTED
;
3658 if (pVNetRootContext
->read_only
&&
3659 (params
->DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
))) {
3660 status
= STATUS_NETWORK_ACCESS_DENIED
;
3664 /* if FCB was marked for deletion and opened multiple times, as soon
3665 * as first close happen, FCB transitions into delete_pending state
3666 * no more opens allowed
3668 if (Fcb
->OpenCount
&& nfs41_fcb
->DeletePending
) {
3669 status
= STATUS_DELETE_PENDING
;
3673 /* ms-fsa: 3.1.5.1.2.1 page 68 */
3674 if (Fcb
->OpenCount
&& nfs41_fcb
->StandardInfo
.DeletePending
&&
3675 !(params
->ShareAccess
& FILE_SHARE_DELETE
) &&
3676 (params
->DesiredAccess
& (FILE_EXECUTE
| FILE_READ_DATA
|
3677 FILE_WRITE_DATA
| FILE_APPEND_DATA
))) {
3678 status
= STATUS_SHARING_VIOLATION
;
3682 /* rdbss seems miss this sharing_violation check */
3683 if (Fcb
->OpenCount
&& params
->Disposition
== FILE_SUPERSEDE
) {
3685 if ((!RxContext
->CurrentIrpSp
->FileObject
->SharedRead
&&
3686 (params
->DesiredAccess
& FILE_READ_DATA
)) ||
3687 ((!RxContext
->CurrentIrpSp
->FileObject
->SharedWrite
&&
3688 (params
->DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
|
3689 FILE_WRITE_ATTRIBUTES
))) ||
3690 (!RxContext
->CurrentIrpSp
->FileObject
->SharedDelete
&&
3691 (params
->DesiredAccess
& DELETE
)))) {
3693 if ((!RxContext
->CurrentIrpSp
->FileObject
->SharedRead
&&
3694 (params
->DesiredAccess
& FILE_READ_DATA
)) ||
3695 (!RxContext
->CurrentIrpSp
->FileObject
->SharedWrite
&&
3696 (params
->DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
|
3697 FILE_WRITE_ATTRIBUTES
)) ||
3698 (!RxContext
->CurrentIrpSp
->FileObject
->SharedDelete
&&
3699 (params
->DesiredAccess
& DELETE
)))) {
3701 status
= STATUS_SHARING_VIOLATION
;
3705 if (isFilenameTooLong(SrvOpen
->pAlreadyPrefixedName
, pVNetRootContext
)) {
3706 status
= STATUS_OBJECT_NAME_INVALID
;
3710 if (!areOpenParamsValid(params
)) {
3711 status
= STATUS_INVALID_PARAMETER
;
3715 /* from ms-fsa 3.1.5.1.1 page 56 */
3716 if ((params
->CreateOptions
& FILE_DELETE_ON_CLOSE
) &&
3717 (params
->FileAttributes
& FILE_ATTRIBUTE_READONLY
)) {
3718 status
= STATUS_CANNOT_DELETE
;
3723 /* ignore cygwin EAs when checking support and access */
3724 if (!AnsiStrEq(&NfsV3Attributes
, ea
->EaName
, ea
->EaNameLength
) &&
3725 !AnsiStrEq(&NfsActOnLink
, ea
->EaName
, ea
->EaNameLength
) &&
3726 !AnsiStrEq(&NfsSymlinkTargetName
, ea
->EaName
, ea
->EaNameLength
)) {
3727 if (!(FsAttrs
->FileSystemAttributes
& FILE_SUPPORTS_EXTENDED_ATTRIBUTES
)) {
3728 status
= STATUS_EAS_NOT_SUPPORTED
;
3732 } else if (RxContext
->CurrentIrpSp
->Parameters
.Create
.EaLength
) {
3733 status
= STATUS_INVALID_PARAMETER
;
3742 NTSTATUS NTAPI
nfs41_Create(
3744 NTSTATUS
nfs41_Create(
3746 IN OUT PRX_CONTEXT RxContext
)
3748 NTSTATUS status
= STATUS_INSUFFICIENT_RESOURCES
;
3749 nfs41_updowncall_entry
*entry
= NULL
;
3750 PNT_CREATE_PARAMETERS params
= &RxContext
->Create
.NtCreateParameters
;
3751 PFILE_FULL_EA_INFORMATION ea
= (PFILE_FULL_EA_INFORMATION
)
3752 RxContext
->CurrentIrp
->AssociatedIrp
.SystemBuffer
;
3753 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
3754 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
3755 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
3756 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
3757 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
3758 __notnull PMRX_FCB Fcb
= RxContext
->pFcb
;
3759 __notnull PNFS41_FCB nfs41_fcb
= (PNFS41_FCB
)Fcb
->Context
;
3760 PNFS41_FOBX nfs41_fobx
= NULL
;
3761 BOOLEAN oldDeletePending
= nfs41_fcb
->StandardInfo
.DeletePending
;
3762 #ifdef ENABLE_TIMINGS
3763 LARGE_INTEGER t1
, t2
;
3764 t1
= KeQueryPerformanceCounter(NULL
);
3767 ASSERT( NodeType(SrvOpen
) == RDBSS_NTC_SRVOPEN
);
3771 print_debug_header(RxContext
);
3772 print_nt_create_params(1, RxContext
->Create
.NtCreateParameters
);
3773 if (ea
) print_ea_info(0, ea
);
3776 status
= check_nfs41_create_args(RxContext
);
3777 if (status
) goto out
;
3779 #if defined(STORE_MOUNT_SEC_CONTEXT) && defined (USE_MOUNT_SEC_CONTEXT)
3780 status
= nfs41_UpcallCreate(NFS41_OPEN
, &pVNetRootContext
->mount_sec_ctx
,
3782 status
= nfs41_UpcallCreate(NFS41_OPEN
, NULL
,
3784 pVNetRootContext
->session
, INVALID_HANDLE_VALUE
,
3785 pNetRootContext
->nfs41d_version
,
3786 SrvOpen
->pAlreadyPrefixedName
, &entry
);
3787 if (status
) goto out
;
3789 entry
->u
.Open
.access_mask
= params
->DesiredAccess
;
3790 entry
->u
.Open
.access_mode
= params
->ShareAccess
;
3791 entry
->u
.Open
.attrs
= params
->FileAttributes
;
3792 if (!(params
->CreateOptions
& FILE_DIRECTORY_FILE
))
3793 entry
->u
.Open
.attrs
|= FILE_ATTRIBUTE_ARCHIVE
;
3794 entry
->u
.Open
.disp
= params
->Disposition
;
3795 entry
->u
.Open
.copts
= params
->CreateOptions
;
3796 entry
->u
.Open
.srv_open
= SrvOpen
;
3797 /* treat the NfsActOnLink ea as FILE_OPEN_REPARSE_POINT */
3798 if ((ea
&& AnsiStrEq(&NfsActOnLink
, ea
->EaName
, ea
->EaNameLength
)) ||
3799 (entry
->u
.Open
.access_mask
& DELETE
))
3800 entry
->u
.Open
.copts
|= FILE_OPEN_REPARSE_POINT
;
3801 if (isDataAccess(params
->DesiredAccess
) || isOpen2Create(params
->Disposition
))
3802 entry
->u
.Open
.open_owner_id
= InterlockedIncrement(&open_owner_id
);
3803 // if we are creating a file check if nfsv3attributes were passed in
3804 if (params
->Disposition
!= FILE_OPEN
&& params
->Disposition
!= FILE_OVERWRITE
) {
3805 entry
->u
.Open
.mode
= 0777;
3806 if (ea
&& AnsiStrEq(&NfsV3Attributes
, ea
->EaName
, ea
->EaNameLength
)) {
3807 nfs3_attrs
*attrs
= (nfs3_attrs
*)(ea
->EaName
+ ea
->EaNameLength
+ 1);
3809 DbgP("creating file with mode %o\n", attrs
->mode
);
3811 entry
->u
.Open
.mode
= attrs
->mode
;
3813 if (params
->FileAttributes
& FILE_ATTRIBUTE_READONLY
)
3814 entry
->u
.Open
.mode
= 0444;
3816 if (entry
->u
.Open
.disp
== FILE_CREATE
&& ea
&&
3817 AnsiStrEq(&NfsSymlinkTargetName
, ea
->EaName
, ea
->EaNameLength
)) {
3818 /* for a cygwin symlink, given as a unicode string */
3819 entry
->u
.Open
.symlink
.Buffer
= (PWCH
)(ea
->EaName
+ ea
->EaNameLength
+ 1);
3820 entry
->u
.Open
.symlink
.MaximumLength
= entry
->u
.Open
.symlink
.Length
= ea
->EaValueLength
;
3823 if (ea
&& create_should_pass_ea(ea
, params
->Disposition
)) {
3824 /* lock the extended attribute buffer for read access in user space */
3825 entry
->u
.Open
.EaMdl
= IoAllocateMdl(ea
,
3826 RxContext
->CurrentIrpSp
->Parameters
.Create
.EaLength
,
3827 FALSE
, FALSE
, NULL
);
3828 if (entry
->u
.Open
.EaMdl
== NULL
) {
3829 status
= STATUS_INTERNAL_ERROR
;
3833 entry
->u
.Open
.EaMdl
->MdlFlags
|= MDL_MAPPING_CAN_FAIL
;
3834 MmProbeAndLockPages(entry
->u
.Open
.EaMdl
, KernelMode
, IoModifyAccess
);
3837 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
3838 #ifndef USE_MOUNT_SEC_CONTEXT
3839 SeDeleteClientSecurity(&entry
->sec_ctx
);
3841 if (status
) goto out
;
3843 if (entry
->u
.Open
.EaMdl
) {
3844 MmUnlockPages(entry
->u
.Open
.EaMdl
);
3845 IoFreeMdl(entry
->u
.Open
.EaMdl
);
3848 if (entry
->status
== NO_ERROR
&& entry
->errno
== ERROR_REPARSE
) {
3849 /* symbolic link handling. when attempting to open a symlink when the
3850 * FILE_OPEN_REPARSE_POINT flag is not set, replace the filename with
3851 * the symlink target's by calling RxPrepareToReparseSymbolicLink()
3852 * and returning STATUS_REPARSE. the object manager will attempt to
3853 * open the new path, and return its handle for the original open */
3854 PRDBSS_DEVICE_OBJECT DeviceObject
= RxContext
->RxDeviceObject
;
3855 PV_NET_ROOT VNetRoot
= (PV_NET_ROOT
)
3856 RxContext
->pRelevantSrvOpen
->pVNetRoot
;
3857 PUNICODE_STRING VNetRootPrefix
= &VNetRoot
->PrefixEntry
.Prefix
;
3858 UNICODE_STRING AbsPath
;
3860 BOOLEAN ReparseRequired
;
3862 /* allocate the string for RxPrepareToReparseSymbolicLink(), and
3863 * format an absolute path "DeviceName+VNetRootName+symlink" */
3864 AbsPath
.Length
= DeviceObject
->DeviceName
.Length
+
3865 VNetRootPrefix
->Length
+ entry
->u
.Open
.symlink
.Length
;
3866 AbsPath
.MaximumLength
= AbsPath
.Length
+ sizeof(UNICODE_NULL
);
3867 AbsPath
.Buffer
= RxAllocatePoolWithTag(NonPagedPool
,
3868 AbsPath
.MaximumLength
, NFS41_MM_POOLTAG
);
3869 if (AbsPath
.Buffer
== NULL
) {
3870 status
= STATUS_INSUFFICIENT_RESOURCES
;
3874 buf
= (PCHAR
)AbsPath
.Buffer
;
3875 RtlCopyMemory(buf
, DeviceObject
->DeviceName
.Buffer
,
3876 DeviceObject
->DeviceName
.Length
);
3877 buf
+= DeviceObject
->DeviceName
.Length
;
3878 RtlCopyMemory(buf
, VNetRootPrefix
->Buffer
, VNetRootPrefix
->Length
);
3879 buf
+= VNetRootPrefix
->Length
;
3880 RtlCopyMemory(buf
, entry
->u
.Open
.symlink
.Buffer
,
3881 entry
->u
.Open
.symlink
.Length
);
3882 RxFreePool(entry
->u
.Open
.symlink
.Buffer
);
3883 buf
+= entry
->u
.Open
.symlink
.Length
;
3884 *(PWCHAR
)buf
= UNICODE_NULL
;
3886 status
= RxPrepareToReparseSymbolicLink(RxContext
,
3887 entry
->u
.Open
.symlink_embedded
, &AbsPath
, TRUE
, &ReparseRequired
);
3889 DbgP("RxPrepareToReparseSymbolicLink(%u, '%wZ') returned %08lX, "
3890 "FileName is '%wZ'\n", entry
->u
.Open
.symlink_embedded
,
3891 &AbsPath
, status
, &RxContext
->CurrentIrpSp
->FileObject
->FileName
);
3893 if (status
== STATUS_SUCCESS
) {
3894 /* if a reparse is not required, reopen the link itself. this
3895 * happens with operations on cygwin symlinks, where the reparse
3896 * flag is not set */
3897 if (!ReparseRequired
) {
3898 entry
->u
.Open
.symlink
.Length
= 0;
3899 entry
->u
.Open
.copts
|= FILE_OPEN_REPARSE_POINT
;
3902 status
= STATUS_REPARSE
;
3907 status
= map_open_errors(entry
->status
,
3908 SrvOpen
->pAlreadyPrefixedName
->Length
);
3911 print_open_error(1, status
);
3916 if (!RxIsFcbAcquiredExclusive(Fcb
)) {
3917 ASSERT(!RxIsFcbAcquiredShared(Fcb
));
3918 RxAcquireExclusiveFcbResourceInMRx(Fcb
);
3921 RxContext
->pFobx
= RxCreateNetFobx(RxContext
, SrvOpen
);
3922 if (RxContext
->pFobx
== NULL
) {
3923 status
= STATUS_INSUFFICIENT_RESOURCES
;
3927 DbgP("nfs41_Create: created FOBX %p\n", RxContext
->pFobx
);
3929 nfs41_fobx
= (PNFS41_FOBX
)(RxContext
->pFobx
)->Context
;
3930 nfs41_fobx
->nfs41_open_state
= entry
->open_state
;
3931 #ifndef USE_MOUNT_SEC_CONTEXT
3932 status
= nfs41_get_sec_ctx(SecurityImpersonation
, &nfs41_fobx
->sec_ctx
);
3936 RtlCopyMemory(&nfs41_fobx
->sec_ctx
, &pVNetRootContext
->mount_sec_ctx
,
3937 sizeof(nfs41_fobx
->sec_ctx
));
3940 // we get attributes only for data access and file (not directories)
3941 if (Fcb
->OpenCount
== 0 ||
3942 (Fcb
->OpenCount
> 0 &&
3943 nfs41_fcb
->changeattr
!= entry
->ChangeTime
)) {
3944 FCB_INIT_PACKET InitPacket
;
3945 RX_FILE_TYPE StorageType
= FileTypeNotYetKnown
;
3946 RtlCopyMemory(&nfs41_fcb
->BasicInfo
, &entry
->u
.Open
.binfo
,
3947 sizeof(entry
->u
.Open
.binfo
));
3948 RtlCopyMemory(&nfs41_fcb
->StandardInfo
, &entry
->u
.Open
.sinfo
,
3949 sizeof(entry
->u
.Open
.sinfo
));
3950 nfs41_fcb
->mode
= entry
->u
.Open
.mode
;
3951 nfs41_fcb
->changeattr
= entry
->ChangeTime
;
3952 if (((params
->CreateOptions
& FILE_DELETE_ON_CLOSE
) &&
3953 !pVNetRootContext
->read_only
) || oldDeletePending
)
3954 nfs41_fcb
->StandardInfo
.DeletePending
= TRUE
;
3956 RxFormInitPacket(InitPacket
,
3957 &entry
->u
.Open
.binfo
.FileAttributes
,
3958 &entry
->u
.Open
.sinfo
.NumberOfLinks
,
3959 &entry
->u
.Open
.binfo
.CreationTime
,
3960 &entry
->u
.Open
.binfo
.LastAccessTime
,
3961 &entry
->u
.Open
.binfo
.LastWriteTime
,
3962 &entry
->u
.Open
.binfo
.ChangeTime
,
3963 &entry
->u
.Open
.sinfo
.AllocationSize
,
3964 &entry
->u
.Open
.sinfo
.EndOfFile
,
3965 &entry
->u
.Open
.sinfo
.EndOfFile
);
3967 if (entry
->u
.Open
.sinfo
.Directory
)
3968 StorageType
= FileTypeDirectory
;
3970 StorageType
= FileTypeFile
;
3972 RxFinishFcbInitialization(Fcb
, RDBSS_STORAGE_NTC(StorageType
),
3977 DbgP("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
3979 print_basic_info(1, &nfs41_fcb
->BasicInfo
);
3980 print_std_info(1, &nfs41_fcb
->StandardInfo
);
3983 /* aglo: 05/10/2012. it seems like always have to invalid the cache if the
3984 * file has been opened before and being opened again for data access.
3985 * If the file was opened before, RDBSS might have cached (unflushed) data
3986 * and by opening it again, we will not have the correct representation of
3987 * the file size and data content. fileio tests 208, 219, 221.
3989 if (Fcb
->OpenCount
> 0 && (isDataAccess(params
->DesiredAccess
) ||
3990 nfs41_fcb
->changeattr
!= entry
->ChangeTime
) &&
3991 !nfs41_fcb
->StandardInfo
.Directory
) {
3992 ULONG flag
= DISABLE_CACHING
;
3994 DbgP("nfs41_Create: reopening (changed) file %wZ\n",
3995 SrvOpen
->pAlreadyPrefixedName
);
3997 RxChangeBufferingState((PSRV_OPEN
)SrvOpen
, ULongToPtr(flag
), 1);
3999 if (!nfs41_fcb
->StandardInfo
.Directory
&&
4000 isDataAccess(params
->DesiredAccess
)) {
4001 nfs41_fobx
->deleg_type
= entry
->u
.Open
.deleg_type
;
4003 DbgP("nfs41_Create: received delegation %d\n", entry
->u
.Open
.deleg_type
);
4005 if (!(params
->CreateOptions
& FILE_WRITE_THROUGH
) &&
4006 !pVNetRootContext
->write_thru
&&
4007 (entry
->u
.Open
.deleg_type
== 2 ||
4008 (params
->DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)))) {
4010 DbgP("nfs41_Create: enabling write buffering\n");
4012 SrvOpen
->BufferingFlags
|=
4013 (FCB_STATE_WRITECACHING_ENABLED
|
4014 FCB_STATE_WRITEBUFFERING_ENABLED
);
4015 } else if (params
->CreateOptions
& FILE_WRITE_THROUGH
||
4016 pVNetRootContext
->write_thru
)
4017 nfs41_fobx
->write_thru
= TRUE
;
4018 if (entry
->u
.Open
.deleg_type
>= 1 ||
4019 params
->DesiredAccess
& FILE_READ_DATA
) {
4021 DbgP("nfs41_Create: enabling read buffering\n");
4023 SrvOpen
->BufferingFlags
|=
4024 (FCB_STATE_READBUFFERING_ENABLED
|
4025 FCB_STATE_READCACHING_ENABLED
);
4027 if (pVNetRootContext
->nocache
||
4028 (params
->CreateOptions
& FILE_NO_INTERMEDIATE_BUFFERING
)) {
4030 DbgP("nfs41_Create: disabling buffering\n");
4032 SrvOpen
->BufferingFlags
= FCB_STATE_DISABLE_LOCAL_BUFFERING
;
4033 nfs41_fobx
->nocache
= TRUE
;
4034 } else if (!entry
->u
.Open
.deleg_type
&& !Fcb
->OpenCount
) {
4035 nfs41_fcb_list_entry
*oentry
;
4037 DbgP("nfs41_Create: received no delegations: srv_open=%p "
4038 "ctime=%llu\n", SrvOpen
, entry
->ChangeTime
);
4040 oentry
= RxAllocatePoolWithTag(NonPagedPool
,
4041 sizeof(nfs41_fcb_list_entry
), NFS41_MM_POOLTAG_OPEN
);
4042 if (oentry
== NULL
) {
4043 status
= STATUS_INSUFFICIENT_RESOURCES
;
4046 oentry
->fcb
= RxContext
->pFcb
;
4047 oentry
->nfs41_fobx
= nfs41_fobx
;
4048 oentry
->session
= pVNetRootContext
->session
;
4049 oentry
->ChangeTime
= entry
->ChangeTime
;
4050 oentry
->skip
= FALSE
;
4051 nfs41_AddEntry(fcblistLock
, openlist
, oentry
);
4055 if ((params
->CreateOptions
& FILE_DELETE_ON_CLOSE
) &&
4056 !pVNetRootContext
->read_only
)
4057 nfs41_fcb
->StandardInfo
.DeletePending
= TRUE
;
4059 RxContext
->Create
.ReturnedCreateInformation
=
4060 map_disposition_to_create_retval(params
->Disposition
, entry
->errno
);
4062 RxContext
->pFobx
->OffsetOfNextEaToReturn
= 1;
4064 RxContext
->CurrentIrp
->IoStatus
.Information
=
4065 RxContext
->Create
.ReturnedCreateInformation
;
4067 status
= RxContext
->CurrentIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
4073 #ifdef ENABLE_TIMINGS
4074 t2
= KeQueryPerformanceCounter(NULL
);
4075 if ((params
->DesiredAccess
& FILE_READ_DATA
) ||
4076 (params
->DesiredAccess
& FILE_WRITE_DATA
) ||
4077 (params
->DesiredAccess
& FILE_APPEND_DATA
) ||
4078 (params
->DesiredAccess
& FILE_EXECUTE
)) {
4079 InterlockedIncrement(&open
.tops
);
4080 InterlockedAdd64(&open
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
4081 #ifdef ENABLE_INDV_TIMINGS
4082 DbgP("nfs41_Create open delta = %d op=%d sum=%d\n",
4083 t2
.QuadPart
- t1
.QuadPart
, open
.tops
, open
.ticks
);
4086 InterlockedIncrement(&lookup
.tops
);
4087 InterlockedAdd64(&lookup
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
4088 #ifdef ENABLE_INDV_TIMINGS
4089 DbgP("nfs41_Create lookup delta = %d op=%d sum=%d\n",
4090 t2
.QuadPart
- t1
.QuadPart
, lookup
.tops
, lookup
.ticks
);
4101 NTSTATUS NTAPI
nfs41_CollapseOpen(
4103 NTSTATUS
nfs41_CollapseOpen(
4105 IN OUT PRX_CONTEXT RxContext
)
4107 NTSTATUS status
= STATUS_MORE_PROCESSING_REQUIRED
;
4114 NTSTATUS NTAPI
nfs41_ShouldTryToCollapseThisOpen(
4116 NTSTATUS
nfs41_ShouldTryToCollapseThisOpen(
4118 IN OUT PRX_CONTEXT RxContext
)
4120 if (RxContext
->pRelevantSrvOpen
== NULL
)
4121 return STATUS_SUCCESS
;
4122 else return STATUS_MORE_PROCESSING_REQUIRED
;
4126 ULONG NTAPI
nfs41_ExtendForCache(
4128 ULONG
nfs41_ExtendForCache(
4130 IN OUT PRX_CONTEXT RxContext
,
4131 IN PLARGE_INTEGER pNewFileSize
,
4132 OUT PLARGE_INTEGER pNewAllocationSize
)
4134 NTSTATUS status
= STATUS_SUCCESS
;
4135 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
4137 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
4139 print_debug_header(RxContext
);
4140 DbgP("input: byte count 0x%x filesize 0x%x alloc size 0x%x\n",
4141 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
, *pNewFileSize
,
4142 *pNewAllocationSize
);
4144 pNewAllocationSize
->QuadPart
= pNewFileSize
->QuadPart
+ 8192;
4145 nfs41_fcb
->StandardInfo
.AllocationSize
.QuadPart
=
4146 pNewAllocationSize
->QuadPart
;
4147 nfs41_fcb
->StandardInfo
.EndOfFile
.QuadPart
= pNewFileSize
->QuadPart
;
4149 DbgP("new filesize 0x%x new allocation size 0x%x\n", *pNewFileSize
,
4150 *pNewAllocationSize
);
4158 VOID
nfs41_remove_fcb_entry(
4162 nfs41_fcb_list_entry
*cur
;
4163 ExAcquireFastMutex(&fcblistLock
);
4165 pEntry
= openlist
.head
.Flink
;
4166 while (!IsListEmpty(&openlist
.head
)) {
4167 cur
= (nfs41_fcb_list_entry
*)CONTAINING_RECORD(pEntry
,
4168 nfs41_fcb_list_entry
, next
);
4169 if (cur
->fcb
== fcb
) {
4171 DbgP("nfs41_remove_srvopen_entry: Found match for fcb=%p\n", fcb
);
4173 RemoveEntryList(pEntry
);
4177 if (pEntry
->Flink
== &openlist
.head
) {
4179 DbgP("nfs41_remove_srvopen_entry: reached EOL looking for fcb "
4184 pEntry
= pEntry
->Flink
;
4186 ExReleaseFastMutex(&fcblistLock
);
4189 NTSTATUS
map_close_errors(
4193 case NO_ERROR
: return STATUS_SUCCESS
;
4194 case ERROR_NETNAME_DELETED
: return STATUS_NETWORK_NAME_DELETED
;
4195 case ERROR_NOT_EMPTY
: return STATUS_DIRECTORY_NOT_EMPTY
;
4196 case ERROR_FILE_INVALID
: return STATUS_FILE_INVALID
;
4198 print_error("failed to map windows error %d to NTSTATUS; "
4199 "defaulting to STATUS_INTERNAL_ERROR\n", status
);
4200 case ERROR_INTERNAL_ERROR
: return STATUS_INTERNAL_ERROR
;
4205 NTSTATUS NTAPI
nfs41_CloseSrvOpen(
4207 NTSTATUS
nfs41_CloseSrvOpen(
4209 IN OUT PRX_CONTEXT RxContext
)
4211 NTSTATUS status
= STATUS_INSUFFICIENT_RESOURCES
;
4212 nfs41_updowncall_entry
*entry
;
4213 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
4214 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
4215 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
4216 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
4217 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
4218 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
4219 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
4220 #ifdef ENABLE_TIMINGS
4221 LARGE_INTEGER t1
, t2
;
4222 t1
= KeQueryPerformanceCounter(NULL
);
4227 print_debug_header(RxContext
);
4230 if (!nfs41_fobx
->deleg_type
&& !nfs41_fcb
->StandardInfo
.Directory
&&
4231 !RxContext
->pFcb
->OpenCount
) {
4232 nfs41_remove_fcb_entry(RxContext
->pFcb
);
4235 status
= nfs41_UpcallCreate(NFS41_CLOSE
, &nfs41_fobx
->sec_ctx
,
4236 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
4237 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
4238 if (status
) goto out
;
4240 entry
->u
.Close
.srv_open
= SrvOpen
;
4241 if (nfs41_fcb
->StandardInfo
.DeletePending
)
4242 nfs41_fcb
->DeletePending
= TRUE
;
4243 if (!RxContext
->pFcb
->OpenCount
||
4244 (nfs41_fcb
->StandardInfo
.DeletePending
&&
4245 nfs41_fcb
->StandardInfo
.Directory
))
4246 entry
->u
.Close
.remove
= nfs41_fcb
->StandardInfo
.DeletePending
;
4247 if (!RxContext
->pFcb
->OpenCount
)
4248 entry
->u
.Close
.renamed
= nfs41_fcb
->Renamed
;
4250 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
4251 #ifndef USE_MOUNT_SEC_CONTEXT
4252 SeDeleteClientSecurity(&nfs41_fobx
->sec_ctx
);
4254 if (status
) goto out
;
4256 /* map windows ERRORs to NTSTATUS */
4257 status
= map_close_errors(entry
->status
);
4260 #ifdef ENABLE_TIMINGS
4261 t2
= KeQueryPerformanceCounter(NULL
);
4262 InterlockedIncrement(&close
.tops
);
4263 InterlockedAdd64(&close
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
4264 #ifdef ENABLE_INDV_TIMINGS
4265 DbgP("nfs41_CloseSrvOpen delta = %d op=%d sum=%d\n",
4266 t2
.QuadPart
- t1
.QuadPart
, close
.tops
, close
.ticks
);
4276 NTSTATUS NTAPI
nfs41_Flush(
4278 NTSTATUS
nfs41_Flush(
4280 IN OUT PRX_CONTEXT RxContext
)
4282 return STATUS_SUCCESS
;
4286 NTSTATUS NTAPI
nfs41_DeallocateForFcb(
4288 NTSTATUS
nfs41_DeallocateForFcb(
4290 IN OUT PMRX_FCB pFcb
)
4292 return STATUS_SUCCESS
;
4296 NTSTATUS NTAPI
nfs41_DeallocateForFobx(
4298 NTSTATUS
nfs41_DeallocateForFobx(
4300 IN OUT PMRX_FOBX pFobx
)
4302 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(pFobx
);
4303 if (nfs41_fobx
->acl
)
4304 RxFreePool(nfs41_fobx
->acl
);
4305 return STATUS_SUCCESS
;
4308 void print_debug_filedirquery_header(
4309 PRX_CONTEXT RxContext
)
4311 print_debug_header(RxContext
);
4312 DbgP("FileName='%wZ', InfoClass = %s\n",
4313 GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext
),
4314 print_file_information_class(RxContext
->Info
.FileInformationClass
));
4317 void print_querydir_args(
4318 PRX_CONTEXT RxContext
)
4320 print_debug_filedirquery_header(RxContext
);
4321 DbgP("Filter='%wZ', Index=%d, Restart/Single/Specified/Init=%d/%d/%d/%d\n",
4322 &RxContext
->pFobx
->UnicodeQueryTemplate
,
4323 RxContext
->QueryDirectory
.FileIndex
,
4324 RxContext
->QueryDirectory
.RestartScan
,
4325 RxContext
->QueryDirectory
.ReturnSingleEntry
,
4326 RxContext
->QueryDirectory
.IndexSpecified
,
4327 RxContext
->QueryDirectory
.InitialQuery
);
4330 NTSTATUS
map_querydir_errors(
4334 case ERROR_ACCESS_DENIED
: return STATUS_ACCESS_DENIED
;
4335 case ERROR_BUFFER_OVERFLOW
: return STATUS_BUFFER_OVERFLOW
;
4336 case ERROR_FILE_NOT_FOUND
: return STATUS_NO_SUCH_FILE
;
4337 case ERROR_NETNAME_DELETED
: return STATUS_NETWORK_NAME_DELETED
;
4338 case ERROR_INVALID_PARAMETER
: return STATUS_INVALID_PARAMETER
;
4339 case ERROR_NO_MORE_FILES
: return STATUS_NO_MORE_FILES
;
4340 case ERROR_OUTOFMEMORY
: return STATUS_INSUFFICIENT_RESOURCES
;
4341 case ERROR_FILENAME_EXCED_RANGE
: return STATUS_NAME_TOO_LONG
;
4343 print_error("failed to map windows error %d to NTSTATUS; "
4344 "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", status
);
4345 case ERROR_BAD_NET_RESP
: return STATUS_INVALID_NETWORK_RESPONSE
;
4349 NTSTATUS
check_nfs41_dirquery_args(
4350 IN PRX_CONTEXT RxContext
)
4352 if (RxContext
->Info
.Buffer
== NULL
)
4353 return STATUS_INVALID_USER_BUFFER
;
4354 return STATUS_SUCCESS
;
4358 NTSTATUS NTAPI
nfs41_QueryDirectory(
4360 NTSTATUS
nfs41_QueryDirectory(
4362 IN OUT PRX_CONTEXT RxContext
)
4364 NTSTATUS status
= STATUS_INVALID_PARAMETER
;
4365 nfs41_updowncall_entry
*entry
;
4366 FILE_INFORMATION_CLASS InfoClass
= RxContext
->Info
.FileInformationClass
;
4367 PUNICODE_STRING Filter
= &RxContext
->pFobx
->UnicodeQueryTemplate
;
4368 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
4369 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
4370 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
4371 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
4372 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
4373 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
4374 #ifdef ENABLE_TIMINGS
4375 LARGE_INTEGER t1
, t2
;
4376 t1
= KeQueryPerformanceCounter(NULL
);
4379 #ifdef DEBUG_DIR_QUERY
4381 print_querydir_args(RxContext
);
4384 status
= check_nfs41_dirquery_args(RxContext
);
4385 if (status
) goto out
;
4387 switch (InfoClass
) {
4388 /* classes handled in readdir_copy_entry() and readdir_size_for_entry() */
4389 case FileNamesInformation
:
4390 case FileDirectoryInformation
:
4391 case FileFullDirectoryInformation
:
4392 case FileIdFullDirectoryInformation
:
4393 case FileBothDirectoryInformation
:
4394 case FileIdBothDirectoryInformation
:
4397 print_error("nfs41_QueryDirectory: unhandled dir query class %d\n",
4399 status
= STATUS_NOT_SUPPORTED
;
4402 status
= nfs41_UpcallCreate(NFS41_DIR_QUERY
, &nfs41_fobx
->sec_ctx
,
4403 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
4404 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
4405 if (status
) goto out
;
4407 entry
->u
.QueryFile
.InfoClass
= InfoClass
;
4408 entry
->buf_len
= RxContext
->Info
.LengthRemaining
;
4409 entry
->buf
= RxContext
->Info
.Buffer
;
4410 entry
->u
.QueryFile
.mdl
= IoAllocateMdl(RxContext
->Info
.Buffer
,
4411 RxContext
->Info
.LengthRemaining
, FALSE
, FALSE
, NULL
);
4412 if (entry
->u
.QueryFile
.mdl
== NULL
) {
4413 status
= STATUS_INTERNAL_ERROR
;
4417 entry
->u
.QueryFile
.mdl
->MdlFlags
|= MDL_MAPPING_CAN_FAIL
;
4418 MmProbeAndLockPages(entry
->u
.QueryFile
.mdl
, KernelMode
, IoModifyAccess
);
4420 entry
->u
.QueryFile
.filter
= Filter
;
4421 entry
->u
.QueryFile
.initial_query
= RxContext
->QueryDirectory
.InitialQuery
;
4422 entry
->u
.QueryFile
.restart_scan
= RxContext
->QueryDirectory
.RestartScan
;
4423 entry
->u
.QueryFile
.return_single
= RxContext
->QueryDirectory
.ReturnSingleEntry
;
4425 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
4426 if (status
) goto out
;
4427 MmUnlockPages(entry
->u
.QueryFile
.mdl
);
4429 if (entry
->status
== STATUS_BUFFER_TOO_SMALL
) {
4430 DbgP("nfs41_QueryDirectory: buffer too small provided %d need %lu\n",
4431 RxContext
->Info
.LengthRemaining
, entry
->buf_len
);
4432 RxContext
->InformationToReturn
= entry
->buf_len
;
4433 status
= STATUS_BUFFER_TOO_SMALL
;
4434 } else if (entry
->status
== STATUS_SUCCESS
) {
4435 #ifdef ENABLE_TIMINGS
4436 InterlockedIncrement(&readdir
.sops
);
4437 InterlockedAdd64(&readdir
.size
, entry
->u
.QueryFile
.buf_len
);
4439 RxContext
->Info
.LengthRemaining
-= entry
->buf_len
;
4440 status
= STATUS_SUCCESS
;
4442 /* map windows ERRORs to NTSTATUS */
4443 status
= map_querydir_errors(entry
->status
);
4445 IoFreeMdl(entry
->u
.QueryFile
.mdl
);
4448 #ifdef ENABLE_TIMINGS
4449 t2
= KeQueryPerformanceCounter(NULL
);
4450 InterlockedIncrement(&readdir
.tops
);
4451 InterlockedAdd64(&readdir
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
4452 #ifdef ENABLE_INDV_TIMINGS
4453 DbgP("nfs41_QueryDirectory delta = %d ops=%d sum=%d\n",
4454 t2
.QuadPart
- t1
.QuadPart
, readdir
.tops
, readdir
.ticks
);
4457 #ifdef DEBUG_DIR_QUERY
4463 void print_queryvolume_args(
4464 PRX_CONTEXT RxContext
)
4466 print_debug_header(RxContext
);
4467 DbgP("FileName='%wZ', InfoClass = %s BufferLen = %d\n",
4468 GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext
),
4469 print_fs_information_class(RxContext
->Info
.FileInformationClass
),
4470 RxContext
->Info
.LengthRemaining
);
4473 NTSTATUS
map_volume_errors(
4477 case ERROR_ACCESS_DENIED
: return STATUS_ACCESS_DENIED
;
4478 case ERROR_VC_DISCONNECTED
: return STATUS_CONNECTION_DISCONNECTED
;
4479 case ERROR_NETNAME_DELETED
: return STATUS_NETWORK_NAME_DELETED
;
4480 case ERROR_INVALID_PARAMETER
: return STATUS_INVALID_PARAMETER
;
4481 case ERROR_OUTOFMEMORY
: return STATUS_INSUFFICIENT_RESOURCES
;
4483 print_error("failed to map windows error %d to NTSTATUS; "
4484 "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", status
);
4485 case ERROR_BAD_NET_RESP
: return STATUS_INVALID_NETWORK_RESPONSE
;
4489 void nfs41_create_volume_info(PFILE_FS_VOLUME_INFORMATION pVolInfo
, DWORD
*len
)
4491 DECLARE_CONST_UNICODE_STRING(VolName
, VOL_NAME
);
4493 RtlZeroMemory(pVolInfo
, sizeof(FILE_FS_VOLUME_INFORMATION
));
4494 pVolInfo
->VolumeSerialNumber
= 0xBABAFACE;
4495 pVolInfo
->VolumeLabelLength
= VolName
.Length
;
4496 RtlCopyMemory(&pVolInfo
->VolumeLabel
[0], (PVOID
)VolName
.Buffer
,
4497 VolName
.MaximumLength
);
4498 *len
= sizeof(FILE_FS_VOLUME_INFORMATION
) + VolName
.Length
;
4501 static BOOLEAN
is_root_directory(
4502 PRX_CONTEXT RxContext
)
4504 __notnull PV_NET_ROOT VNetRoot
= (PV_NET_ROOT
)
4505 RxContext
->pRelevantSrvOpen
->pVNetRoot
;
4506 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
4507 NFS41GetVNetRootExtension(RxContext
->pRelevantSrvOpen
->pVNetRoot
);
4509 /* calculate the root directory's length, including vnetroot prefix,
4510 * mount path, and a trailing \ */
4511 const USHORT RootPathLen
= VNetRoot
->PrefixEntry
.Prefix
.Length
+
4512 pVNetRootContext
->MountPathLen
+ sizeof(WCHAR
);
4514 return RxContext
->CurrentIrpSp
->FileObject
->FileName
.Length
<= RootPathLen
;
4518 NTSTATUS NTAPI
nfs41_QueryVolumeInformation(
4520 NTSTATUS
nfs41_QueryVolumeInformation(
4522 IN OUT PRX_CONTEXT RxContext
)
4524 NTSTATUS status
= STATUS_INVALID_PARAMETER
;
4525 nfs41_updowncall_entry
*entry
;
4526 ULONG RemainingLength
= RxContext
->Info
.LengthRemaining
, SizeUsed
;
4527 FS_INFORMATION_CLASS InfoClass
= RxContext
->Info
.FsInformationClass
;
4528 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
4529 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
4530 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
4531 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
4532 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
4533 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
4534 NFS41GetDeviceExtension(RxContext
, DevExt
);
4536 #ifdef ENABLE_TIMINGS
4537 LARGE_INTEGER t1
, t2
;
4538 t1
= KeQueryPerformanceCounter(NULL
);
4541 #ifdef DEBUG_VOLUME_QUERY
4543 print_queryvolume_args(RxContext
);
4546 status
= check_nfs41_dirquery_args(RxContext
);
4547 if (status
) goto out
;
4549 switch (InfoClass
) {
4550 case FileFsVolumeInformation
:
4551 if ((ULONG
)RxContext
->Info
.LengthRemaining
>= DevExt
->VolAttrsLen
) {
4552 RtlCopyMemory(RxContext
->Info
.Buffer
, DevExt
->VolAttrs
,
4553 DevExt
->VolAttrsLen
);
4554 RxContext
->Info
.LengthRemaining
-= DevExt
->VolAttrsLen
;
4555 status
= STATUS_SUCCESS
;
4557 RtlCopyMemory(RxContext
->Info
.Buffer
, DevExt
->VolAttrs
,
4558 RxContext
->Info
.LengthRemaining
);
4559 status
= STATUS_BUFFER_OVERFLOW
;
4562 case FileFsDeviceInformation
:
4564 PFILE_FS_DEVICE_INFORMATION pDevInfo
= RxContext
->Info
.Buffer
;
4566 SizeUsed
= sizeof(FILE_FS_DEVICE_INFORMATION
);
4567 if (RemainingLength
< SizeUsed
) {
4568 status
= STATUS_BUFFER_TOO_SMALL
;
4569 RxContext
->InformationToReturn
= SizeUsed
;
4572 pDevInfo
->DeviceType
= RxContext
->pFcb
->pNetRoot
->DeviceType
;
4573 pDevInfo
->Characteristics
= FILE_REMOTE_DEVICE
| FILE_DEVICE_IS_MOUNTED
;
4574 RxContext
->Info
.LengthRemaining
-= SizeUsed
;
4575 status
= STATUS_SUCCESS
;
4578 case FileAccessInformation
:
4579 status
= STATUS_NOT_SUPPORTED
;
4582 case FileFsAttributeInformation
:
4583 if (RxContext
->Info
.LengthRemaining
< FS_ATTR_LEN
) {
4584 RxContext
->InformationToReturn
= FS_ATTR_LEN
;
4585 status
= STATUS_BUFFER_TOO_SMALL
;
4589 /* on attribute queries for the root directory,
4590 * use cached volume attributes from mount */
4591 if (is_root_directory(RxContext
)) {
4592 PFILE_FS_ATTRIBUTE_INFORMATION attrs
=
4593 (PFILE_FS_ATTRIBUTE_INFORMATION
)RxContext
->Info
.Buffer
;
4594 DECLARE_CONST_UNICODE_STRING(FsName
, FS_NAME
);
4596 RtlCopyMemory(attrs
, &pVNetRootContext
->FsAttrs
,
4597 sizeof(pVNetRootContext
->FsAttrs
));
4599 /* fill in the FileSystemName */
4600 RtlCopyMemory(attrs
->FileSystemName
, FsName
.Buffer
,
4601 FsName
.MaximumLength
); /* 'MaximumLength' to include null */
4602 attrs
->FileSystemNameLength
= FsName
.Length
;
4604 RxContext
->Info
.LengthRemaining
-= FS_ATTR_LEN
;
4607 /* else fall through and send the upcall */
4608 case FileFsSizeInformation
:
4609 case FileFsFullSizeInformation
:
4613 print_error("nfs41_QueryVolumeInformation: unhandled class %d\n", InfoClass
);
4614 status
= STATUS_NOT_SUPPORTED
;
4617 status
= nfs41_UpcallCreate(NFS41_VOLUME_QUERY
, &nfs41_fobx
->sec_ctx
,
4618 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
4619 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
4620 if (status
) goto out
;
4622 entry
->u
.Volume
.query
= InfoClass
;
4623 entry
->buf
= RxContext
->Info
.Buffer
;
4624 entry
->buf_len
= RxContext
->Info
.LengthRemaining
;
4626 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
4627 if (status
) goto out
;
4629 if (entry
->status
== STATUS_BUFFER_TOO_SMALL
) {
4630 RxContext
->InformationToReturn
= entry
->buf_len
;
4631 status
= STATUS_BUFFER_TOO_SMALL
;
4632 } else if (entry
->status
== STATUS_SUCCESS
) {
4633 if (InfoClass
== FileFsAttributeInformation
) {
4634 /* fill in the FileSystemName */
4635 PFILE_FS_ATTRIBUTE_INFORMATION attrs
=
4636 (PFILE_FS_ATTRIBUTE_INFORMATION
)RxContext
->Info
.Buffer
;
4637 DECLARE_CONST_UNICODE_STRING(FsName
, FS_NAME
);
4639 RtlCopyMemory(attrs
->FileSystemName
, FsName
.Buffer
,
4640 FsName
.MaximumLength
); /* 'MaximumLength' to include null */
4641 attrs
->FileSystemNameLength
= FsName
.Length
;
4643 entry
->buf_len
= FS_ATTR_LEN
;
4645 #ifdef ENABLE_TIMINGS
4646 InterlockedIncrement(&volume
.sops
);
4647 InterlockedAdd64(&volume
.size
, entry
->u
.Volume
.buf_len
);
4649 RxContext
->Info
.LengthRemaining
-= entry
->buf_len
;
4650 status
= STATUS_SUCCESS
;
4652 status
= map_volume_errors(entry
->status
);
4656 #ifdef ENABLE_TIMINGS
4657 t2
= KeQueryPerformanceCounter(NULL
);
4658 InterlockedIncrement(&volume
.tops
);
4659 InterlockedAdd64(&volume
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
4660 #ifdef ENABLE_INDV_TIMINGS
4661 DbgP("nfs41_QueryVolumeInformation delta = %d op=%d sum=%d\n",
4662 t2
.QuadPart
- t1
.QuadPart
, volume
.tops
, volume
.ticks
);
4665 #ifdef DEBUG_VOLUME_QUERY
4671 VOID
nfs41_update_fcb_list(
4673 ULONGLONG ChangeTime
)
4676 nfs41_fcb_list_entry
*cur
;
4677 ExAcquireFastMutex(&fcblistLock
);
4678 pEntry
= openlist
.head
.Flink
;
4679 while (!IsListEmpty(&openlist
.head
)) {
4680 cur
= (nfs41_fcb_list_entry
*)CONTAINING_RECORD(pEntry
,
4681 nfs41_fcb_list_entry
, next
);
4682 if (cur
->fcb
== fcb
&&
4683 cur
->ChangeTime
!= ChangeTime
) {
4684 #if defined(DEBUG_FILE_SET) || defined(DEBUG_ACL_SET) || \
4685 defined(DEBUG_WRITE) || defined(DEBUG_EA_SET)
4686 DbgP("nfs41_update_fcb_list: Found match for fcb %p: updating "
4687 "%llu to %llu\n", fcb
, cur
->ChangeTime
, ChangeTime
);
4689 cur
->ChangeTime
= ChangeTime
;
4692 /* place an upcall for this srv_open */
4693 if (pEntry
->Flink
== &openlist
.head
) {
4694 #if defined(DEBUG_FILE_SET) || defined(DEBUG_ACL_SET) || \
4695 defined(DEBUG_WRITE) || defined(DEBUG_EA_SET)
4696 DbgP("nfs41_update_fcb_list: reached EOL loooking for "
4701 pEntry
= pEntry
->Flink
;
4703 ExReleaseFastMutex(&fcblistLock
);
4706 void print_nfs3_attrs(
4709 DbgP("type=%d mode=%o nlink=%d size=%d atime=%x mtime=%x ctime=%x\n",
4710 attrs
->type
, attrs
->mode
, attrs
->nlink
, attrs
->size
, attrs
->atime
,
4711 attrs
->mtime
, attrs
->ctime
);
4714 void file_time_to_nfs_time(
4715 IN
const PLARGE_INTEGER file_time
,
4716 OUT LONGLONG
*nfs_time
)
4718 LARGE_INTEGER diff
= unix_time_diff
;
4719 diff
.QuadPart
= file_time
->QuadPart
- diff
.QuadPart
;
4720 *nfs_time
= diff
.QuadPart
/ 10000000;
4723 void create_nfs3_attrs(
4725 PNFS41_FCB nfs41_fcb
)
4727 RtlZeroMemory(attrs
, sizeof(nfs3_attrs
));
4728 if (nfs41_fcb
->BasicInfo
.FileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
)
4729 attrs
->type
= NF3LNK
;
4730 else if (nfs41_fcb
->StandardInfo
.Directory
)
4731 attrs
->type
= NF3DIR
;
4733 attrs
->type
= NF3REG
;
4734 attrs
->mode
= nfs41_fcb
->mode
;
4735 attrs
->nlink
= nfs41_fcb
->StandardInfo
.NumberOfLinks
;
4736 attrs
->size
.QuadPart
= attrs
->used
.QuadPart
=
4737 nfs41_fcb
->StandardInfo
.EndOfFile
.QuadPart
;
4738 file_time_to_nfs_time(&nfs41_fcb
->BasicInfo
.LastAccessTime
, &attrs
->atime
);
4739 file_time_to_nfs_time(&nfs41_fcb
->BasicInfo
.ChangeTime
, &attrs
->mtime
);
4740 file_time_to_nfs_time(&nfs41_fcb
->BasicInfo
.CreationTime
, &attrs
->ctime
);
4744 NTSTATUS
map_setea_error(
4748 case NO_ERROR
: return STATUS_SUCCESS
;
4749 case ERROR_FILE_NOT_FOUND
: return STATUS_NO_EAS_ON_FILE
;
4750 case ERROR_ACCESS_DENIED
: return STATUS_ACCESS_DENIED
;
4751 case ERROR_NETWORK_ACCESS_DENIED
: return STATUS_NETWORK_ACCESS_DENIED
;
4752 case ERROR_NETNAME_DELETED
: return STATUS_NETWORK_NAME_DELETED
;
4753 case ERROR_FILE_TOO_LARGE
: return STATUS_EA_TOO_LARGE
;
4754 case ERROR_BUFFER_OVERFLOW
: return STATUS_BUFFER_OVERFLOW
;
4755 case STATUS_BUFFER_TOO_SMALL
:
4756 case ERROR_INSUFFICIENT_BUFFER
: return STATUS_BUFFER_TOO_SMALL
;
4757 case ERROR_INVALID_EA_HANDLE
: return STATUS_NONEXISTENT_EA_ENTRY
;
4758 case ERROR_NO_MORE_FILES
: return STATUS_NO_MORE_EAS
;
4759 case ERROR_EA_FILE_CORRUPT
: return STATUS_EA_CORRUPT_ERROR
;
4761 print_error("failed to map windows error %d to NTSTATUS; "
4762 "defaulting to STATUS_INVALID_PARAMETER\n", error
);
4763 case ERROR_INVALID_PARAMETER
: return STATUS_INVALID_PARAMETER
;
4767 NTSTATUS
check_nfs41_setea_args(
4768 IN PRX_CONTEXT RxContext
)
4771 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
4772 NFS41GetVNetRootExtension(RxContext
->pRelevantSrvOpen
->pVNetRoot
);
4773 __notnull PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs
=
4774 &pVNetRootContext
->FsAttrs
;
4775 __notnull PFILE_FULL_EA_INFORMATION ea
=
4776 (PFILE_FULL_EA_INFORMATION
)RxContext
->Info
.Buffer
;
4778 status
= check_nfs41_dirquery_args(RxContext
);
4779 if (status
) goto out
;
4782 status
= STATUS_INVALID_PARAMETER
;
4785 if (AnsiStrEq(&NfsActOnLink
, ea
->EaName
, ea
->EaNameLength
) ||
4786 AnsiStrEq(&NfsSymlinkTargetName
, ea
->EaName
, ea
->EaNameLength
)) {
4787 status
= STATUS_INVALID_PARAMETER
; /* only allowed on create */
4790 /* ignore cygwin EAs when checking support */
4791 if (!(FsAttrs
->FileSystemAttributes
& FILE_SUPPORTS_EXTENDED_ATTRIBUTES
)
4792 && !AnsiStrEq(&NfsV3Attributes
, ea
->EaName
, ea
->EaNameLength
)) {
4793 status
= STATUS_EAS_NOT_SUPPORTED
;
4796 if ((RxContext
->pRelevantSrvOpen
->DesiredAccess
& FILE_WRITE_EA
) == 0) {
4797 status
= STATUS_ACCESS_DENIED
;
4800 if (pVNetRootContext
->read_only
) {
4801 print_error("check_nfs41_setattr_args: Read-only mount\n");
4802 status
= STATUS_ACCESS_DENIED
;
4810 NTSTATUS NTAPI
nfs41_SetEaInformation(
4812 NTSTATUS
nfs41_SetEaInformation(
4814 IN OUT PRX_CONTEXT RxContext
)
4816 NTSTATUS status
= STATUS_EAS_NOT_SUPPORTED
;
4817 nfs41_updowncall_entry
*entry
;
4818 __notnull PFILE_FULL_EA_INFORMATION eainfo
=
4819 (PFILE_FULL_EA_INFORMATION
)RxContext
->Info
.Buffer
;
4820 nfs3_attrs
*attrs
= NULL
;
4821 ULONG buflen
= RxContext
->CurrentIrpSp
->Parameters
.SetEa
.Length
, error_offset
;
4822 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
4823 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
4824 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
4825 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
4826 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
4827 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
4828 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
4829 #ifdef ENABLE_TIMINGS
4830 LARGE_INTEGER t1
, t2
;
4831 t1
= KeQueryPerformanceCounter(NULL
);
4836 print_debug_header(RxContext
);
4837 print_ea_info(1, eainfo
);
4840 status
= check_nfs41_setea_args(RxContext
);
4841 if (status
) goto out
;
4843 status
= nfs41_UpcallCreate(NFS41_EA_SET
, &nfs41_fobx
->sec_ctx
,
4844 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
4845 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
4846 if (status
) goto out
;
4848 if (AnsiStrEq(&NfsV3Attributes
, eainfo
->EaName
, eainfo
->EaNameLength
)) {
4849 attrs
= (nfs3_attrs
*)(eainfo
->EaName
+ eainfo
->EaNameLength
+ 1);
4851 print_nfs3_attrs(attrs
);
4852 DbgP("old mode is %o new mode is %o\n", nfs41_fcb
->mode
, attrs
->mode
);
4854 entry
->u
.SetEa
.mode
= attrs
->mode
;
4856 entry
->u
.SetEa
.mode
= 0;
4857 status
= IoCheckEaBufferValidity(eainfo
, buflen
, &error_offset
);
4863 entry
->buf
= eainfo
;
4864 entry
->buf_len
= buflen
;
4866 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
4867 if (status
) goto out
;
4868 #ifdef ENABLE_TIMINGS
4869 if (entry
->status
== STATUS_SUCCESS
) {
4870 InterlockedIncrement(&setexattr
.sops
);
4871 InterlockedAdd64(&setexattr
.size
, entry
->u
.SetEa
.buf_len
);
4874 status
= map_setea_error(entry
->status
);
4876 if (!nfs41_fobx
->deleg_type
&& entry
->ChangeTime
&&
4877 (SrvOpen
->DesiredAccess
&
4878 (FILE_READ_DATA
| FILE_WRITE_DATA
| FILE_APPEND_DATA
)))
4879 nfs41_update_fcb_list(RxContext
->pFcb
, entry
->ChangeTime
);
4880 nfs41_fcb
->changeattr
= entry
->ChangeTime
;
4881 nfs41_fcb
->mode
= entry
->u
.SetEa
.mode
;
4885 #ifdef ENABLE_TIMINGS
4886 t2
= KeQueryPerformanceCounter(NULL
);
4887 InterlockedIncrement(&setexattr
.tops
);
4888 InterlockedAdd64(&setexattr
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
4889 #ifdef ENABLE_INDV_TIMINGS
4890 DbgP("nfs41_SetEaInformation delta = %d op=%d sum=%d\n",
4891 t2
.QuadPart
- t1
.QuadPart
, setexattr
.tops
, setexattr
.ticks
);
4900 NTSTATUS
check_nfs41_queryea_args(
4901 IN PRX_CONTEXT RxContext
)
4904 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
4905 NFS41GetVNetRootExtension(RxContext
->pRelevantSrvOpen
->pVNetRoot
);
4906 __notnull PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs
=
4907 &pVNetRootContext
->FsAttrs
;
4908 PFILE_GET_EA_INFORMATION ea
= (PFILE_GET_EA_INFORMATION
)
4909 RxContext
->CurrentIrpSp
->Parameters
.QueryEa
.EaList
;
4911 status
= check_nfs41_dirquery_args(RxContext
);
4912 if (status
) goto out
;
4914 if (!(FsAttrs
->FileSystemAttributes
& FILE_SUPPORTS_EXTENDED_ATTRIBUTES
)) {
4916 status
= STATUS_EAS_NOT_SUPPORTED
;
4919 /* ignore cygwin EAs when checking support */
4920 if (!AnsiStrEq(&NfsV3Attributes
, ea
->EaName
, ea
->EaNameLength
) &&
4921 !AnsiStrEq(&NfsActOnLink
, ea
->EaName
, ea
->EaNameLength
) &&
4922 !AnsiStrEq(&NfsSymlinkTargetName
, ea
->EaName
, ea
->EaNameLength
)) {
4923 status
= STATUS_EAS_NOT_SUPPORTED
;
4927 if ((RxContext
->pRelevantSrvOpen
->DesiredAccess
& FILE_READ_EA
) == 0) {
4928 status
= STATUS_ACCESS_DENIED
;
4935 static NTSTATUS
QueryCygwinSymlink(
4936 IN OUT PRX_CONTEXT RxContext
,
4937 IN PFILE_GET_EA_INFORMATION query
,
4938 OUT PFILE_FULL_EA_INFORMATION info
)
4940 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
4941 __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext
=
4942 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
4943 __notnull PNFS41_NETROOT_EXTENSION NetRootContext
=
4944 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
4945 __notnull PNFS41_FOBX Fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
4946 nfs41_updowncall_entry
*entry
;
4947 UNICODE_STRING TargetName
;
4948 const USHORT HeaderLen
= FIELD_OFFSET(FILE_FULL_EA_INFORMATION
, EaName
) +
4949 query
->EaNameLength
+ 1;
4952 if (RxContext
->Info
.LengthRemaining
< HeaderLen
) {
4953 status
= STATUS_BUFFER_TOO_SMALL
;
4954 RxContext
->InformationToReturn
= HeaderLen
;
4958 TargetName
.Buffer
= (PWCH
)(info
->EaName
+ query
->EaNameLength
+ 1);
4959 TargetName
.MaximumLength
= (USHORT
)min(RxContext
->Info
.LengthRemaining
-
4962 status
= nfs41_UpcallCreate(NFS41_SYMLINK
, &Fobx
->sec_ctx
,
4963 VNetRootContext
->session
, Fobx
->nfs41_open_state
,
4964 NetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
4965 if (status
) goto out
;
4967 entry
->u
.Symlink
.target
= &TargetName
;
4968 entry
->u
.Symlink
.set
= FALSE
;
4970 status
= nfs41_UpcallWaitForReply(entry
, VNetRootContext
->timeout
);
4971 if (status
) goto out
;
4973 status
= map_setea_error(entry
->status
);
4974 if (status
== STATUS_SUCCESS
) {
4975 info
->NextEntryOffset
= 0;
4977 info
->EaNameLength
= query
->EaNameLength
;
4978 info
->EaValueLength
= TargetName
.Length
- sizeof(UNICODE_NULL
);
4979 TargetName
.Buffer
[TargetName
.Length
/sizeof(WCHAR
)] = UNICODE_NULL
;
4980 RtlCopyMemory(info
->EaName
, query
->EaName
, query
->EaNameLength
);
4981 RxContext
->Info
.LengthRemaining
= HeaderLen
+ info
->EaValueLength
;
4982 } else if (status
== STATUS_BUFFER_TOO_SMALL
) {
4983 RxContext
->InformationToReturn
= HeaderLen
+
4984 entry
->u
.Symlink
.target
->Length
;
4991 static NTSTATUS
QueryCygwinEA(
4992 IN OUT PRX_CONTEXT RxContext
,
4993 IN PFILE_GET_EA_INFORMATION query
,
4994 OUT PFILE_FULL_EA_INFORMATION info
)
4996 NTSTATUS status
= STATUS_NONEXISTENT_EA_ENTRY
;
5001 if (AnsiStrEq(&NfsSymlinkTargetName
, query
->EaName
, query
->EaNameLength
)) {
5002 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
5003 if (nfs41_fcb
->BasicInfo
.FileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
) {
5004 status
= QueryCygwinSymlink(RxContext
, query
, info
);
5007 const LONG LengthRequired
= sizeof(FILE_FULL_EA_INFORMATION
) +
5008 NfsSymlinkTargetName
.Length
- sizeof(CHAR
);
5009 if (LengthRequired
> RxContext
->Info
.LengthRemaining
) {
5010 status
= STATUS_BUFFER_TOO_SMALL
;
5011 RxContext
->InformationToReturn
= LengthRequired
;
5014 info
->NextEntryOffset
= 0;
5016 info
->EaValueLength
= 0;
5017 info
->EaNameLength
= (UCHAR
)NfsActOnLink
.Length
;
5018 RtlCopyMemory(info
->EaName
, NfsSymlinkTargetName
.Buffer
,
5019 NfsSymlinkTargetName
.Length
);
5020 RxContext
->Info
.LengthRemaining
= LengthRequired
;
5021 status
= STATUS_SUCCESS
;
5026 if (AnsiStrEq(&NfsV3Attributes
, query
->EaName
, query
->EaNameLength
)) {
5029 const LONG LengthRequired
= sizeof(FILE_FULL_EA_INFORMATION
) +
5030 NfsV3Attributes
.Length
+ sizeof(nfs3_attrs
) - sizeof(CHAR
);
5031 if (LengthRequired
> RxContext
->Info
.LengthRemaining
) {
5032 status
= STATUS_BUFFER_TOO_SMALL
;
5033 RxContext
->InformationToReturn
= LengthRequired
;
5037 create_nfs3_attrs(&attrs
, NFS41GetFcbExtension(RxContext
->pFcb
));
5038 #ifdef DEBUG_EA_QUERY
5039 print_nfs3_attrs(&attrs
);
5042 info
->NextEntryOffset
= 0;
5044 info
->EaNameLength
= (UCHAR
)NfsV3Attributes
.Length
;
5045 info
->EaValueLength
= sizeof(nfs3_attrs
);
5046 RtlCopyMemory(info
->EaName
, NfsV3Attributes
.Buffer
,
5047 NfsV3Attributes
.Length
);
5048 RtlCopyMemory(info
->EaName
+ info
->EaNameLength
+ 1, &attrs
,
5049 sizeof(nfs3_attrs
));
5050 RxContext
->Info
.LengthRemaining
= LengthRequired
;
5051 status
= STATUS_SUCCESS
;
5055 if (AnsiStrEq(&NfsActOnLink
, query
->EaName
, query
->EaNameLength
)) {
5057 const LONG LengthRequired
= sizeof(FILE_FULL_EA_INFORMATION
) +
5058 query
->EaNameLength
- sizeof(CHAR
);
5059 if (LengthRequired
> RxContext
->Info
.LengthRemaining
) {
5060 status
= STATUS_BUFFER_TOO_SMALL
;
5061 RxContext
->InformationToReturn
= LengthRequired
;
5065 info
->NextEntryOffset
= 0;
5067 info
->EaNameLength
= query
->EaNameLength
;
5068 info
->EaValueLength
= 0;
5069 RtlCopyMemory(info
->EaName
, query
->EaName
, query
->EaNameLength
);
5070 RxContext
->Info
.LengthRemaining
= LengthRequired
;
5071 status
= STATUS_SUCCESS
;
5079 NTSTATUS NTAPI
nfs41_QueryEaInformation(
5081 NTSTATUS
nfs41_QueryEaInformation(
5083 IN OUT PRX_CONTEXT RxContext
)
5085 NTSTATUS status
= STATUS_EAS_NOT_SUPPORTED
;
5086 nfs41_updowncall_entry
*entry
;
5087 PFILE_GET_EA_INFORMATION query
= (PFILE_GET_EA_INFORMATION
)
5088 RxContext
->CurrentIrpSp
->Parameters
.QueryEa
.EaList
;
5089 ULONG buflen
= RxContext
->CurrentIrpSp
->Parameters
.QueryEa
.Length
;
5090 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
5091 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
5092 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
5093 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
5094 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
5095 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
5096 #ifdef ENABLE_TIMINGS
5097 LARGE_INTEGER t1
, t2
;
5098 t1
= KeQueryPerformanceCounter(NULL
);
5101 #ifdef DEBUG_EA_QUERY
5103 print_debug_header(RxContext
);
5104 print_get_ea(1, query
);
5106 status
= check_nfs41_queryea_args(RxContext
);
5107 if (status
) goto out
;
5109 /* handle queries for cygwin EAs */
5110 status
= QueryCygwinEA(RxContext
, query
,
5111 (PFILE_FULL_EA_INFORMATION
)RxContext
->Info
.Buffer
);
5112 if (status
!= STATUS_NONEXISTENT_EA_ENTRY
)
5115 status
= nfs41_UpcallCreate(NFS41_EA_GET
, &nfs41_fobx
->sec_ctx
,
5116 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
5117 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
5118 if (status
) goto out
;
5120 entry
->buf_len
= buflen
;
5121 entry
->buf
= RxContext
->Info
.Buffer
;
5122 entry
->u
.QueryEa
.EaList
= query
;
5123 entry
->u
.QueryEa
.EaListLength
= query
== NULL
? 0 :
5124 RxContext
->QueryEa
.UserEaListLength
;
5125 entry
->u
.QueryEa
.EaIndex
= RxContext
->QueryEa
.IndexSpecified
?
5126 RxContext
->QueryEa
.UserEaIndex
: 0;
5127 entry
->u
.QueryEa
.RestartScan
= RxContext
->QueryEa
.RestartScan
;
5128 entry
->u
.QueryEa
.ReturnSingleEntry
= RxContext
->QueryEa
.ReturnSingleEntry
;
5130 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
5131 if (status
) goto out
;
5133 if (entry
->status
== STATUS_SUCCESS
) {
5134 switch (entry
->u
.QueryEa
.Overflow
) {
5135 case ERROR_INSUFFICIENT_BUFFER
:
5136 status
= STATUS_BUFFER_TOO_SMALL
;
5138 case ERROR_BUFFER_OVERFLOW
:
5139 status
= RxContext
->IoStatusBlock
.Status
= STATUS_BUFFER_OVERFLOW
;
5142 RxContext
->IoStatusBlock
.Status
= STATUS_SUCCESS
;
5145 RxContext
->InformationToReturn
= entry
->buf_len
;
5146 #ifdef ENABLE_TIMINGS
5147 InterlockedIncrement(&getexattr
.sops
);
5148 InterlockedAdd64(&getexattr
.size
, entry
->u
.QueryEa
.buf_len
);
5151 status
= map_setea_error(entry
->status
);
5155 #ifdef ENABLE_TIMINGS
5156 t2
= KeQueryPerformanceCounter(NULL
);
5157 InterlockedIncrement(&getexattr
.tops
);
5158 InterlockedAdd64(&getexattr
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
5159 #ifdef ENABLE_INDV_TIMINGS
5160 DbgP("nfs41_QueryEaInformation delta = %d op=%d sum=%d\n",
5161 t2
.QuadPart
- t1
.QuadPart
, getexattr
.tops
, getexattr
.ticks
);
5164 #ifdef DEBUG_EA_QUERY
5170 NTSTATUS
map_query_acl_error(
5174 case NO_ERROR
: return STATUS_SUCCESS
;
5175 case ERROR_NOT_SUPPORTED
: return STATUS_NOT_SUPPORTED
;
5176 case ERROR_ACCESS_DENIED
: return STATUS_ACCESS_DENIED
;
5177 case ERROR_FILE_NOT_FOUND
: return STATUS_OBJECT_NAME_NOT_FOUND
;
5178 case ERROR_INVALID_PARAMETER
: return STATUS_INVALID_PARAMETER
;
5180 print_error("failed to map windows error %d to NTSTATUS; "
5181 "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", error
);
5182 case ERROR_BAD_NET_RESP
: return STATUS_INVALID_NETWORK_RESPONSE
;
5186 NTSTATUS
check_nfs41_getacl_args(
5187 PRX_CONTEXT RxContext
)
5189 NTSTATUS status
= STATUS_SUCCESS
;
5190 SECURITY_INFORMATION info_class
=
5191 RxContext
->CurrentIrpSp
->Parameters
.QuerySecurity
.SecurityInformation
;
5193 /* we don't support sacls */
5194 if (info_class
== SACL_SECURITY_INFORMATION
||
5195 info_class
== LABEL_SECURITY_INFORMATION
) {
5196 status
= STATUS_NOT_SUPPORTED
;
5199 if (RxContext
->CurrentIrp
->UserBuffer
== NULL
&&
5200 RxContext
->CurrentIrpSp
->Parameters
.QuerySecurity
.Length
)
5201 status
= STATUS_INVALID_USER_BUFFER
;
5207 NTSTATUS NTAPI
nfs41_QuerySecurityInformation(
5209 NTSTATUS
nfs41_QuerySecurityInformation(
5211 IN OUT PRX_CONTEXT RxContext
)
5213 NTSTATUS status
= STATUS_NOT_SUPPORTED
;
5214 nfs41_updowncall_entry
*entry
;
5215 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
5216 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
5217 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
5218 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
5219 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
5220 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
5221 SECURITY_INFORMATION info_class
=
5222 RxContext
->CurrentIrpSp
->Parameters
.QuerySecurity
.SecurityInformation
;
5223 #ifdef ENABLE_TIMINGS
5224 LARGE_INTEGER t1
, t2
;
5225 t1
= KeQueryPerformanceCounter(NULL
);
5228 #ifdef DEBUG_ACL_QUERY
5230 print_debug_header(RxContext
);
5231 print_acl_args(info_class
);
5234 status
= check_nfs41_getacl_args(RxContext
);
5235 if (status
) goto out
;
5237 if (nfs41_fobx
->acl
&& nfs41_fobx
->acl_len
) {
5238 LARGE_INTEGER current_time
;
5239 KeQuerySystemTime(¤t_time
);
5240 #ifdef DEBUG_ACL_QUERY
5241 DbgP("CurrentTime %lx Saved Acl time %lx\n",
5242 current_time
.QuadPart
, nfs41_fobx
->time
.QuadPart
);
5244 if (current_time
.QuadPart
- nfs41_fobx
->time
.QuadPart
<= 20*1000) {
5245 PSECURITY_DESCRIPTOR sec_desc
= (PSECURITY_DESCRIPTOR
)
5246 RxContext
->CurrentIrp
->UserBuffer
;
5247 RtlCopyMemory(sec_desc
, nfs41_fobx
->acl
, nfs41_fobx
->acl_len
);
5248 RxContext
->IoStatusBlock
.Information
=
5249 RxContext
->InformationToReturn
= nfs41_fobx
->acl_len
;
5250 RxContext
->IoStatusBlock
.Status
= status
= STATUS_SUCCESS
;
5251 #ifdef ENABLE_TIMINGS
5252 InterlockedIncrement(&getacl
.sops
);
5253 InterlockedAdd64(&getacl
.size
, nfs41_fobx
->acl_len
);
5256 RxFreePool(nfs41_fobx
->acl
);
5257 nfs41_fobx
->acl
= NULL
;
5258 nfs41_fobx
->acl_len
= 0;
5263 status
= nfs41_UpcallCreate(NFS41_ACL_QUERY
, &nfs41_fobx
->sec_ctx
,
5264 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
5265 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
5266 if (status
) goto out
;
5268 entry
->u
.Acl
.query
= info_class
;
5269 /* we can't provide RxContext->CurrentIrp->UserBuffer to the upcall thread
5270 * because it becomes an invalid pointer with that execution context
5272 entry
->buf_len
= RxContext
->CurrentIrpSp
->Parameters
.QuerySecurity
.Length
;
5274 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
5275 if (status
) goto out
;
5277 if (entry
->status
== STATUS_BUFFER_TOO_SMALL
) {
5278 #ifdef DEBUG_ACL_QUERY
5279 DbgP("nfs41_QuerySecurityInformation: provided buffer size=%d but we "
5281 RxContext
->CurrentIrpSp
->Parameters
.QuerySecurity
.Length
,
5284 status
= STATUS_BUFFER_OVERFLOW
;
5285 RxContext
->InformationToReturn
= entry
->buf_len
;
5287 /* Save ACL buffer */
5288 nfs41_fobx
->acl
= entry
->buf
;
5289 nfs41_fobx
->acl_len
= entry
->buf_len
;
5290 KeQuerySystemTime(&nfs41_fobx
->time
);
5291 } else if (entry
->status
== STATUS_SUCCESS
) {
5292 PSECURITY_DESCRIPTOR sec_desc
= (PSECURITY_DESCRIPTOR
)
5293 RxContext
->CurrentIrp
->UserBuffer
;
5294 RtlCopyMemory(sec_desc
, entry
->buf
, entry
->buf_len
);
5295 #ifdef ENABLE_TIMINGS
5296 InterlockedIncrement(&getacl
.sops
);
5297 InterlockedAdd64(&getacl
.size
, entry
->u
.Acl
.buf_len
);
5299 RxFreePool(entry
->buf
);
5300 nfs41_fobx
->acl
= NULL
;
5301 nfs41_fobx
->acl_len
= 0;
5302 RxContext
->IoStatusBlock
.Information
= RxContext
->InformationToReturn
=
5304 RxContext
->IoStatusBlock
.Status
= status
= STATUS_SUCCESS
;
5306 status
= map_query_acl_error(entry
->status
);
5310 #ifdef ENABLE_TIMINGS
5311 t2
= KeQueryPerformanceCounter(NULL
);
5312 /* only count getacl that we made an upcall for */
5313 if (status
== STATUS_BUFFER_OVERFLOW
) {
5314 InterlockedIncrement(&getacl
.tops
);
5315 InterlockedAdd64(&getacl
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
5317 #ifdef ENABLE_INDV_TIMINGS
5318 DbgP("nfs41_QuerySecurityInformation: delta = %d op=%d sum=%d\n",
5319 t2
.QuadPart
- t1
.QuadPart
, getacl
.tops
, getacl
.ticks
);
5322 #ifdef DEBUG_ACL_QUERY
5328 NTSTATUS
check_nfs41_setacl_args(
5329 PRX_CONTEXT RxContext
)
5331 NTSTATUS status
= STATUS_SUCCESS
;
5332 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
5333 NFS41GetVNetRootExtension(RxContext
->pRelevantSrvOpen
->pVNetRoot
);
5334 SECURITY_INFORMATION info_class
=
5335 RxContext
->CurrentIrpSp
->Parameters
.SetSecurity
.SecurityInformation
;
5337 if (pVNetRootContext
->read_only
) {
5338 print_error("check_nfs41_setacl_args: Read-only mount\n");
5339 status
= STATUS_ACCESS_DENIED
;
5342 /* we don't support sacls */
5343 if (info_class
== SACL_SECURITY_INFORMATION
||
5344 info_class
== LABEL_SECURITY_INFORMATION
) {
5345 status
= STATUS_NOT_SUPPORTED
;
5353 NTSTATUS NTAPI
nfs41_SetSecurityInformation(
5355 NTSTATUS
nfs41_SetSecurityInformation(
5357 IN OUT PRX_CONTEXT RxContext
)
5359 NTSTATUS status
= STATUS_NOT_SUPPORTED
;
5360 nfs41_updowncall_entry
*entry
;
5361 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
5362 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
5363 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
5364 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
5365 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
5366 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
5367 __notnull PSECURITY_DESCRIPTOR sec_desc
=
5368 RxContext
->CurrentIrpSp
->Parameters
.SetSecurity
.SecurityDescriptor
;
5369 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
5370 SECURITY_INFORMATION info_class
=
5371 RxContext
->CurrentIrpSp
->Parameters
.SetSecurity
.SecurityInformation
;
5372 #ifdef ENABLE_TIMINGS
5373 LARGE_INTEGER t1
, t2
;
5374 t1
= KeQueryPerformanceCounter(NULL
);
5377 #ifdef DEBUG_ACL_SET
5379 print_debug_header(RxContext
);
5380 print_acl_args(info_class
);
5383 status
= check_nfs41_setacl_args(RxContext
);
5384 if (status
) goto out
;
5386 /* check that ACL is present */
5387 if (info_class
& DACL_SECURITY_INFORMATION
) {
5389 BOOLEAN present
, dacl_default
;
5390 status
= RtlGetDaclSecurityDescriptor(sec_desc
, &present
, &acl
,
5393 DbgP("RtlGetDaclSecurityDescriptor failed %x\n", status
);
5396 if (present
== FALSE
) {
5397 DbgP("NO ACL present\n");
5402 status
= nfs41_UpcallCreate(NFS41_ACL_SET
, &nfs41_fobx
->sec_ctx
,
5403 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
5404 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
5405 if (status
) goto out
;
5407 entry
->u
.Acl
.query
= info_class
;
5408 entry
->buf
= sec_desc
;
5409 entry
->buf_len
= RtlLengthSecurityDescriptor(sec_desc
);
5410 #ifdef ENABLE_TIMINGS
5411 InterlockedIncrement(&setacl
.sops
);
5412 InterlockedAdd64(&setacl
.size
, entry
->u
.Acl
.buf_len
);
5415 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
5416 if (status
) goto out
;
5418 status
= map_query_acl_error(entry
->status
);
5420 if (!nfs41_fobx
->deleg_type
&& entry
->ChangeTime
&&
5421 (SrvOpen
->DesiredAccess
&
5422 (FILE_READ_DATA
| FILE_WRITE_DATA
| FILE_APPEND_DATA
)))
5423 nfs41_update_fcb_list(RxContext
->pFcb
, entry
->ChangeTime
);
5424 nfs41_fcb
->changeattr
= entry
->ChangeTime
;
5428 #ifdef ENABLE_TIMINGS
5429 t2
= KeQueryPerformanceCounter(NULL
);
5430 InterlockedIncrement(&setacl
.tops
);
5431 InterlockedAdd64(&setacl
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
5432 #ifdef ENABLE_INDV_TIMINGS
5433 DbgP("nfs41_SetSecurityInformation delta = %d op=%d sum=%d\n",
5434 t2
.QuadPart
- t1
.QuadPart
, setacl
.tops
, setacl
.ticks
);
5437 #ifdef DEBUG_ACL_SET
5443 NTSTATUS
map_queryfile_error(
5447 case ERROR_ACCESS_DENIED
: return STATUS_ACCESS_DENIED
;
5448 case ERROR_NETNAME_DELETED
: return STATUS_NETWORK_NAME_DELETED
;
5449 case ERROR_INVALID_PARAMETER
: return STATUS_INVALID_PARAMETER
;
5451 print_error("failed to map windows error %d to NTSTATUS; "
5452 "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", error
);
5453 case ERROR_BAD_NET_RESP
: return STATUS_INVALID_NETWORK_RESPONSE
;
5458 NTSTATUS NTAPI
nfs41_QueryFileInformation(
5460 NTSTATUS
nfs41_QueryFileInformation(
5462 IN OUT PRX_CONTEXT RxContext
)
5464 NTSTATUS status
= STATUS_OBJECT_NAME_NOT_FOUND
;
5465 FILE_INFORMATION_CLASS InfoClass
= RxContext
->Info
.FileInformationClass
;
5466 nfs41_updowncall_entry
*entry
;
5467 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
5468 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
5469 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
5470 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
5471 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
5472 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
5473 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
5474 #ifdef ENABLE_TIMINGS
5475 LARGE_INTEGER t1
, t2
;
5476 t1
= KeQueryPerformanceCounter(NULL
);
5479 #ifdef DEBUG_FILE_QUERY
5481 print_debug_filedirquery_header(RxContext
);
5484 status
= check_nfs41_dirquery_args(RxContext
);
5485 if (status
) goto out
;
5487 switch (InfoClass
) {
5488 case FileEaInformation
:
5490 PFILE_EA_INFORMATION info
=
5491 (PFILE_EA_INFORMATION
)RxContext
->Info
.Buffer
;
5493 RxContext
->Info
.LengthRemaining
-= sizeof(FILE_EA_INFORMATION
);
5494 status
= STATUS_SUCCESS
;
5497 case FileBasicInformation
:
5498 case FileStandardInformation
:
5499 case FileInternalInformation
:
5500 case FileAttributeTagInformation
:
5501 case FileNetworkOpenInformation
:
5504 print_error("nfs41_QueryFileInformation: unhandled class %d\n", InfoClass
);
5505 status
= STATUS_NOT_SUPPORTED
;
5509 status
= nfs41_UpcallCreate(NFS41_FILE_QUERY
, &nfs41_fobx
->sec_ctx
,
5510 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
5511 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
5512 if (status
) goto out
;
5514 entry
->u
.QueryFile
.InfoClass
= InfoClass
;
5515 entry
->buf
= RxContext
->Info
.Buffer
;
5516 entry
->buf_len
= RxContext
->Info
.LengthRemaining
;
5518 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
5519 if (status
) goto out
;
5521 if (entry
->status
== STATUS_BUFFER_TOO_SMALL
) {
5522 RxContext
->InformationToReturn
= entry
->buf_len
;
5523 status
= STATUS_BUFFER_TOO_SMALL
;
5524 } else if (entry
->status
== STATUS_SUCCESS
) {
5525 BOOLEAN DeletePending
= FALSE
;
5526 #ifdef ENABLE_TIMINGS
5527 InterlockedIncrement(&getattr
.sops
);
5528 InterlockedAdd64(&getattr
.size
, entry
->u
.QueryFile
.buf_len
);
5530 RxContext
->Info
.LengthRemaining
-= entry
->buf_len
;
5531 status
= STATUS_SUCCESS
;
5533 switch (InfoClass
) {
5534 case FileBasicInformation
:
5535 RtlCopyMemory(&nfs41_fcb
->BasicInfo
, RxContext
->Info
.Buffer
,
5536 sizeof(nfs41_fcb
->BasicInfo
));
5537 #ifdef DEBUG_FILE_QUERY
5538 print_basic_info(1, &nfs41_fcb
->BasicInfo
);
5541 case FileStandardInformation
:
5542 /* this a fix for RDBSS behaviour when it first calls ExtendForCache,
5543 * then it sends a file query irp for standard attributes and
5544 * expects to receive EndOfFile of value set by the ExtendForCache.
5545 * It seems to cache the filesize based on that instead of sending
5546 * a file size query for after doing the write.
5549 PFILE_STANDARD_INFORMATION std_info
;
5550 std_info
= (PFILE_STANDARD_INFORMATION
)RxContext
->Info
.Buffer
;
5551 if (nfs41_fcb
->StandardInfo
.AllocationSize
.QuadPart
>
5552 std_info
->AllocationSize
.QuadPart
) {
5553 #ifdef DEBUG_FILE_QUERY
5554 DbgP("Old AllocationSize is bigger: saving %x\n",
5555 nfs41_fcb
->StandardInfo
.AllocationSize
.QuadPart
);
5557 std_info
->AllocationSize
.QuadPart
=
5558 nfs41_fcb
->StandardInfo
.AllocationSize
.QuadPart
;
5560 if (nfs41_fcb
->StandardInfo
.EndOfFile
.QuadPart
>
5561 std_info
->EndOfFile
.QuadPart
) {
5562 #ifdef DEBUG_FILE_QUERY
5563 DbgP("Old EndOfFile is bigger: saving %x\n",
5564 nfs41_fcb
->StandardInfo
.EndOfFile
);
5566 std_info
->EndOfFile
.QuadPart
=
5567 nfs41_fcb
->StandardInfo
.EndOfFile
.QuadPart
;
5569 std_info
->DeletePending
= nfs41_fcb
->DeletePending
;
5571 if (nfs41_fcb
->StandardInfo
.DeletePending
)
5572 DeletePending
= TRUE
;
5573 RtlCopyMemory(&nfs41_fcb
->StandardInfo
, RxContext
->Info
.Buffer
,
5574 sizeof(nfs41_fcb
->StandardInfo
));
5575 nfs41_fcb
->StandardInfo
.DeletePending
= DeletePending
;
5576 #ifdef DEBUG_FILE_QUERY
5577 print_std_info(1, &nfs41_fcb
->StandardInfo
);
5582 status
= map_queryfile_error(entry
->status
);
5586 #ifdef ENABLE_TIMINGS
5587 t2
= KeQueryPerformanceCounter(NULL
);
5588 InterlockedIncrement(&getattr
.tops
);
5589 InterlockedAdd64(&getattr
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
5590 #ifdef ENABLE_INDV_TIMINGS
5591 DbgP("nfs41_QueryFileInformation delta = %d op=%d sum=%d\n",
5592 t2
.QuadPart
- t1
.QuadPart
, getattr
.tops
, getattr
.ticks
);
5595 #ifdef DEBUG_FILE_QUERY
5601 NTSTATUS
map_setfile_error(
5605 case NO_ERROR
: return STATUS_SUCCESS
;
5606 case ERROR_NOT_EMPTY
: return STATUS_DIRECTORY_NOT_EMPTY
;
5607 case ERROR_FILE_EXISTS
: return STATUS_OBJECT_NAME_COLLISION
;
5608 case ERROR_FILE_NOT_FOUND
: return STATUS_OBJECT_NAME_NOT_FOUND
;
5609 case ERROR_PATH_NOT_FOUND
: return STATUS_OBJECT_PATH_NOT_FOUND
;
5610 case ERROR_ACCESS_DENIED
: return STATUS_ACCESS_DENIED
;
5611 case ERROR_FILE_INVALID
: return STATUS_FILE_INVALID
;
5612 case ERROR_NOT_SAME_DEVICE
: return STATUS_NOT_SAME_DEVICE
;
5613 case ERROR_NOT_SUPPORTED
: return STATUS_NOT_IMPLEMENTED
;
5614 case ERROR_NETWORK_ACCESS_DENIED
: return STATUS_NETWORK_ACCESS_DENIED
;
5615 case ERROR_NETNAME_DELETED
: return STATUS_NETWORK_NAME_DELETED
;
5616 case ERROR_BUFFER_OVERFLOW
: return STATUS_INSUFFICIENT_RESOURCES
;
5618 print_error("failed to map windows error %d to NTSTATUS; "
5619 "defaulting to STATUS_INVALID_PARAMETER\n", error
);
5620 case ERROR_INVALID_PARAMETER
: return STATUS_INVALID_PARAMETER
;
5624 NTSTATUS
check_nfs41_setattr_args(
5625 IN PRX_CONTEXT RxContext
)
5627 NTSTATUS status
= STATUS_SUCCESS
;
5628 FILE_INFORMATION_CLASS InfoClass
= RxContext
->Info
.FileInformationClass
;
5629 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
5630 NFS41GetVNetRootExtension(RxContext
->pRelevantSrvOpen
->pVNetRoot
);
5632 if (pVNetRootContext
->read_only
) {
5633 print_error("check_nfs41_setattr_args: Read-only mount\n");
5634 status
= STATUS_ACCESS_DENIED
;
5638 /* http://msdn.microsoft.com/en-us/library/ff469355(v=PROT.10).aspx
5639 * http://msdn.microsoft.com/en-us/library/ff469424(v=PROT.10).aspx
5640 * If Open.GrantedAccess does not contain FILE_WRITE_DATA, the operation
5641 * MUST be failed with STATUS_ACCESS_DENIED.
5643 if (InfoClass
== FileAllocationInformation
||
5644 InfoClass
== FileEndOfFileInformation
) {
5645 if (!(RxContext
->pRelevantSrvOpen
->DesiredAccess
& FILE_WRITE_DATA
)) {
5646 status
= STATUS_ACCESS_DENIED
;
5650 status
= check_nfs41_dirquery_args(RxContext
);
5651 if (status
) goto out
;
5653 switch (InfoClass
) {
5654 case FileRenameInformation
:
5656 PFILE_RENAME_INFORMATION rinfo
=
5657 (PFILE_RENAME_INFORMATION
)RxContext
->Info
.Buffer
;
5658 UNICODE_STRING dst
= { (USHORT
)rinfo
->FileNameLength
,
5659 (USHORT
)rinfo
->FileNameLength
, rinfo
->FileName
};
5660 #ifdef DEBUG_FILE_SET
5661 DbgP("Attempting to rename to '%wZ'\n", &dst
);
5663 if (isFilenameTooLong(&dst
, pVNetRootContext
)) {
5664 status
= STATUS_OBJECT_NAME_INVALID
;
5667 if (rinfo
->RootDirectory
) {
5668 status
= STATUS_INVALID_PARAMETER
;
5673 case FileLinkInformation
:
5675 PFILE_LINK_INFORMATION linfo
=
5676 (PFILE_LINK_INFORMATION
)RxContext
->Info
.Buffer
;
5677 UNICODE_STRING dst
= { (USHORT
)linfo
->FileNameLength
,
5678 (USHORT
)linfo
->FileNameLength
, linfo
->FileName
};
5679 #ifdef DEBUG_FILE_SET
5680 DbgP("Attempting to add link as '%wZ'\n", &dst
);
5682 if (isFilenameTooLong(&dst
, pVNetRootContext
)) {
5683 status
= STATUS_OBJECT_NAME_INVALID
;
5686 if (linfo
->RootDirectory
) {
5687 status
= STATUS_INVALID_PARAMETER
;
5692 case FileDispositionInformation
:
5694 PFILE_DISPOSITION_INFORMATION dinfo
=
5695 (PFILE_DISPOSITION_INFORMATION
)RxContext
->Info
.Buffer
;
5696 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
5697 if (dinfo
->DeleteFile
&& nfs41_fcb
->DeletePending
) {
5698 status
= STATUS_DELETE_PENDING
;
5703 case FileBasicInformation
:
5704 case FileAllocationInformation
:
5705 case FileEndOfFileInformation
:
5708 print_error("nfs41_SetFileInformation: unhandled class %d\n", InfoClass
);
5709 status
= STATUS_NOT_SUPPORTED
;
5717 NTSTATUS NTAPI
nfs41_SetFileInformation(
5719 NTSTATUS
nfs41_SetFileInformation(
5721 IN OUT PRX_CONTEXT RxContext
)
5723 NTSTATUS status
= STATUS_INVALID_PARAMETER
;
5724 nfs41_updowncall_entry
*entry
;
5725 FILE_INFORMATION_CLASS InfoClass
= RxContext
->Info
.FileInformationClass
;
5726 FILE_RENAME_INFORMATION rinfo
;
5727 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
5728 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
5729 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
5730 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
5731 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
5732 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
5733 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
5734 #ifdef ENABLE_TIMINGS
5735 LARGE_INTEGER t1
, t2
;
5736 t1
= KeQueryPerformanceCounter(NULL
);
5739 #ifdef DEBUG_FILE_SET
5741 print_debug_filedirquery_header(RxContext
);
5744 status
= check_nfs41_setattr_args(RxContext
);
5745 if (status
) goto out
;
5747 switch (InfoClass
) {
5748 case FileDispositionInformation
:
5750 PFILE_DISPOSITION_INFORMATION dinfo
=
5751 (PFILE_DISPOSITION_INFORMATION
)RxContext
->Info
.Buffer
;
5752 if (dinfo
->DeleteFile
) {
5753 nfs41_fcb
->DeletePending
= TRUE
;
5754 // we can delete directories right away
5755 if (nfs41_fcb
->StandardInfo
.Directory
)
5757 nfs41_fcb
->StandardInfo
.DeletePending
= TRUE
;
5758 if (RxContext
->pFcb
->OpenCount
> 1) {
5759 rinfo
.ReplaceIfExists
= 0;
5760 rinfo
.RootDirectory
= INVALID_HANDLE_VALUE
;
5761 rinfo
.FileNameLength
= 0;
5762 rinfo
.FileName
[0] = L
'\0';
5763 InfoClass
= FileRenameInformation
;
5764 nfs41_fcb
->Renamed
= TRUE
;
5768 /* section 4.3.3 of [FSBO]
5769 * "file system behavior in the microsoft windows environment"
5771 if (nfs41_fcb
->DeletePending
) {
5772 nfs41_fcb
->DeletePending
= 0;
5773 nfs41_fcb
->StandardInfo
.DeletePending
= 0;
5776 status
= STATUS_SUCCESS
;
5779 case FileEndOfFileInformation
:
5781 PFILE_END_OF_FILE_INFORMATION info
=
5782 (PFILE_END_OF_FILE_INFORMATION
)RxContext
->Info
.Buffer
;
5783 nfs41_fcb
->StandardInfo
.AllocationSize
=
5784 nfs41_fcb
->StandardInfo
.EndOfFile
= info
->EndOfFile
;
5787 case FileRenameInformation
:
5789 /* noop if filename and destination are the same */
5790 PFILE_RENAME_INFORMATION prinfo
=
5791 (PFILE_RENAME_INFORMATION
)RxContext
->Info
.Buffer
;
5792 const UNICODE_STRING dst
= { (USHORT
)prinfo
->FileNameLength
,
5793 (USHORT
)prinfo
->FileNameLength
, prinfo
->FileName
};
5794 if (RtlCompareUnicodeString(&dst
,
5795 SrvOpen
->pAlreadyPrefixedName
, FALSE
) == 0) {
5796 status
= STATUS_SUCCESS
;
5802 status
= nfs41_UpcallCreate(NFS41_FILE_SET
, &nfs41_fobx
->sec_ctx
,
5803 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
5804 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
5805 if (status
) goto out
;
5807 entry
->u
.SetFile
.InfoClass
= InfoClass
;
5809 /* original irp has infoclass for remove but we need to rename instead,
5810 * thus we changed the local variable infoclass */
5811 if (RxContext
->Info
.FileInformationClass
== FileDispositionInformation
&&
5812 InfoClass
== FileRenameInformation
) {
5813 entry
->buf
= &rinfo
;
5814 entry
->buf_len
= sizeof(rinfo
);
5816 entry
->buf
= RxContext
->Info
.Buffer
;
5817 entry
->buf_len
= RxContext
->Info
.Length
;
5819 #ifdef ENABLE_TIMINGS
5820 InterlockedIncrement(&setattr
.sops
);
5821 InterlockedAdd64(&setattr
.size
, entry
->u
.SetFile
.buf_len
);
5824 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
5825 if (status
) goto out
;
5827 status
= map_setfile_error(entry
->status
);
5829 if (!nfs41_fobx
->deleg_type
&& entry
->ChangeTime
&&
5830 (SrvOpen
->DesiredAccess
&
5831 (FILE_READ_DATA
| FILE_WRITE_DATA
| FILE_APPEND_DATA
)))
5832 nfs41_update_fcb_list(RxContext
->pFcb
, entry
->ChangeTime
);
5833 nfs41_fcb
->changeattr
= entry
->ChangeTime
;
5837 #ifdef ENABLE_TIMINGS
5838 t2
= KeQueryPerformanceCounter(NULL
);
5839 InterlockedIncrement(&setattr
.tops
);
5840 InterlockedAdd64(&setattr
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
5841 #ifdef ENABLE_INDV_TIMINGS
5842 DbgP("nfs41_SetFileInformation delta = %d op=%d sum=%d\n",
5843 t2
.QuadPart
- t1
.QuadPart
, setattr
.tops
, setattr
.ticks
);
5846 #ifdef DEBUG_FILE_SET
5852 NTSTATUS
nfs41_SetFileInformationAtCleanup(
5853 IN OUT PRX_CONTEXT RxContext
)
5857 status
= nfs41_SetFileInformation(RxContext
);
5863 NTSTATUS NTAPI
nfs41_IsValidDirectory (
5865 NTSTATUS
nfs41_IsValidDirectory (
5867 IN OUT PRX_CONTEXT RxContext
,
5868 IN PUNICODE_STRING DirectoryName
)
5870 return STATUS_SUCCESS
;
5874 NTSTATUS NTAPI
nfs41_ComputeNewBufferingState(
5876 NTSTATUS
nfs41_ComputeNewBufferingState(
5878 IN OUT PMRX_SRV_OPEN pSrvOpen
,
5879 IN PVOID pMRxContext
,
5880 OUT ULONG
*pNewBufferingState
)
5882 NTSTATUS status
= STATUS_SUCCESS
;
5883 ULONG flag
= PtrToUlong(pMRxContext
), oldFlags
= pSrvOpen
->BufferingFlags
;
5886 case DISABLE_CACHING
:
5887 if (pSrvOpen
->BufferingFlags
&
5888 (FCB_STATE_READBUFFERING_ENABLED
| FCB_STATE_READCACHING_ENABLED
))
5889 pSrvOpen
->BufferingFlags
&=
5890 ~(FCB_STATE_READBUFFERING_ENABLED
|
5891 FCB_STATE_READCACHING_ENABLED
);
5892 if (pSrvOpen
->BufferingFlags
&
5893 (FCB_STATE_WRITECACHING_ENABLED
| FCB_STATE_WRITEBUFFERING_ENABLED
))
5894 pSrvOpen
->BufferingFlags
&=
5895 ~(FCB_STATE_WRITECACHING_ENABLED
|
5896 FCB_STATE_WRITEBUFFERING_ENABLED
);
5897 pSrvOpen
->BufferingFlags
|= FCB_STATE_DISABLE_LOCAL_BUFFERING
;
5899 case ENABLE_READ_CACHING
:
5900 pSrvOpen
->BufferingFlags
|=
5901 (FCB_STATE_READBUFFERING_ENABLED
| FCB_STATE_READCACHING_ENABLED
);
5903 case ENABLE_WRITE_CACHING
:
5904 pSrvOpen
->BufferingFlags
|=
5905 (FCB_STATE_WRITECACHING_ENABLED
| FCB_STATE_WRITEBUFFERING_ENABLED
);
5907 case ENABLE_READWRITE_CACHING
:
5908 pSrvOpen
->BufferingFlags
=
5909 (FCB_STATE_READBUFFERING_ENABLED
| FCB_STATE_READCACHING_ENABLED
|
5910 FCB_STATE_WRITECACHING_ENABLED
| FCB_STATE_WRITEBUFFERING_ENABLED
);
5912 #ifdef DEBUG_TIME_BASED_COHERENCY
5913 DbgP("nfs41_ComputeNewBufferingState: %wZ pSrvOpen %p Old %08x New %08x\n",
5914 pSrvOpen
->pAlreadyPrefixedName
, pSrvOpen
, oldFlags
,
5915 pSrvOpen
->BufferingFlags
);
5916 *pNewBufferingState
= pSrvOpen
->BufferingFlags
;
5921 void print_readwrite_args(
5922 PRX_CONTEXT RxContext
)
5924 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
5926 print_debug_header(RxContext
);
5927 DbgP("Bytecount 0x%x Byteoffset 0x%x Buffer %p\n",
5928 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
,
5929 LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
,
5930 LowIoContext
->ParamsFor
.ReadWrite
.Buffer
);
5933 void enable_caching(
5934 PMRX_SRV_OPEN SrvOpen
,
5935 PNFS41_FOBX nfs41_fobx
,
5936 ULONGLONG ChangeTime
,
5941 nfs41_fcb_list_entry
*cur
;
5942 BOOLEAN found
= FALSE
;
5944 if (SrvOpen
->DesiredAccess
& FILE_READ_DATA
)
5945 flag
= ENABLE_READ_CACHING
;
5946 if ((SrvOpen
->DesiredAccess
& FILE_WRITE_DATA
) &&
5947 !nfs41_fobx
->write_thru
)
5948 flag
= ENABLE_WRITE_CACHING
;
5949 if ((SrvOpen
->DesiredAccess
& FILE_READ_DATA
) &&
5950 (SrvOpen
->DesiredAccess
& FILE_WRITE_DATA
) &&
5951 !nfs41_fobx
->write_thru
)
5952 flag
= ENABLE_READWRITE_CACHING
;
5954 #if defined(DEBUG_TIME_BASED_COHERENCY) || \
5955 defined(DEBUG_WRITE) || defined(DEBUG_READ)
5956 print_caching_level(1, flag
, SrvOpen
->pAlreadyPrefixedName
);
5962 RxChangeBufferingState((PSRV_OPEN
)SrvOpen
, ULongToPtr(flag
), 1);
5964 ExAcquireFastMutex(&fcblistLock
);
5965 pEntry
= openlist
.head
.Flink
;
5966 while (!IsListEmpty(&openlist
.head
)) {
5967 cur
= (nfs41_fcb_list_entry
*)CONTAINING_RECORD(pEntry
,
5968 nfs41_fcb_list_entry
, next
);
5969 if (cur
->fcb
== SrvOpen
->pFcb
) {
5970 #ifdef DEBUG_TIME_BASED_COHERENCY
5971 DbgP("enable_caching: Looked&Found match for fcb=%p %wZ\n",
5972 SrvOpen
->pFcb
, SrvOpen
->pAlreadyPrefixedName
);
5978 if (pEntry
->Flink
== &openlist
.head
) {
5979 #ifdef DEBUG_TIME_BASED_COHERENCY
5980 DbgP("enable_caching: reached EOL looking for fcb=%p %wZ\n",
5981 SrvOpen
->pFcb
, SrvOpen
->pAlreadyPrefixedName
);
5985 pEntry
= pEntry
->Flink
;
5987 if (!found
&& nfs41_fobx
->deleg_type
) {
5988 nfs41_fcb_list_entry
*oentry
;
5989 #ifdef DEBUG_TIME_BASED_COHERENCY
5990 DbgP("enable_caching: delegation recalled: srv_open=%p\n", SrvOpen
);
5992 oentry
= RxAllocatePoolWithTag(NonPagedPool
,
5993 sizeof(nfs41_fcb_list_entry
), NFS41_MM_POOLTAG_OPEN
);
5994 if (oentry
== NULL
) return;
5995 oentry
->fcb
= SrvOpen
->pFcb
;
5996 oentry
->session
= session
;
5997 oentry
->nfs41_fobx
= nfs41_fobx
;
5998 oentry
->ChangeTime
= ChangeTime
;
5999 oentry
->skip
= FALSE
;
6000 InsertTailList(&openlist
.head
, &oentry
->next
);
6001 nfs41_fobx
->deleg_type
= 0;
6003 ExReleaseFastMutex(&fcblistLock
);
6006 NTSTATUS
map_readwrite_errors(
6010 case ERROR_ACCESS_DENIED
: return STATUS_ACCESS_DENIED
;
6011 case ERROR_HANDLE_EOF
: return STATUS_END_OF_FILE
;
6012 case ERROR_FILE_INVALID
: return STATUS_FILE_INVALID
;
6013 case ERROR_INVALID_PARAMETER
: return STATUS_INVALID_PARAMETER
;
6014 case ERROR_LOCK_VIOLATION
: return STATUS_FILE_LOCK_CONFLICT
;
6015 case ERROR_NETWORK_ACCESS_DENIED
: return STATUS_NETWORK_ACCESS_DENIED
;
6016 case ERROR_NETNAME_DELETED
: return STATUS_NETWORK_NAME_DELETED
;
6018 print_error("failed to map windows error %d to NTSTATUS; "
6019 "defaulting to STATUS_NET_WRITE_FAULT\n", status
);
6020 case ERROR_NET_WRITE_FAULT
: return STATUS_NET_WRITE_FAULT
;
6024 NTSTATUS
check_nfs41_read_args(
6025 IN PRX_CONTEXT RxContext
)
6027 if (!RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Buffer
)
6028 return STATUS_INVALID_USER_BUFFER
;
6029 return STATUS_SUCCESS
;
6033 NTSTATUS NTAPI
nfs41_Read(
6035 NTSTATUS
nfs41_Read(
6037 IN OUT PRX_CONTEXT RxContext
)
6039 NTSTATUS status
= STATUS_INSUFFICIENT_RESOURCES
;
6040 nfs41_updowncall_entry
*entry
;
6041 BOOLEAN async
= FALSE
;
6042 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
6043 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
6044 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
6045 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
6046 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
6047 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
6048 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
6049 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
6051 #ifdef ENABLE_TIMINGS
6052 LARGE_INTEGER t1
, t2
;
6053 t1
= KeQueryPerformanceCounter(NULL
);
6058 print_readwrite_args(RxContext
);
6060 status
= check_nfs41_read_args(RxContext
);
6061 if (status
) goto out
;
6063 status
= nfs41_UpcallCreate(NFS41_READ
, &nfs41_fobx
->sec_ctx
,
6064 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
6065 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
6066 if (status
) goto out
;
6068 entry
->u
.ReadWrite
.MdlAddress
= LowIoContext
->ParamsFor
.ReadWrite
.Buffer
;
6069 entry
->buf_len
= LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
;
6070 entry
->u
.ReadWrite
.offset
= LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
;
6071 if (FlagOn(RxContext
->CurrentIrpSp
->FileObject
->Flags
,
6072 FO_SYNCHRONOUS_IO
) == FALSE
) {
6073 entry
->u
.ReadWrite
.rxcontext
= RxContext
;
6074 async
= entry
->async_op
= TRUE
;
6077 /* assume network speed is 100MB/s and disk speed is 100MB/s so add
6078 * time to transfer requested bytes over the network and read from disk
6080 io_delay
= pVNetRootContext
->timeout
+ 2 * entry
->buf_len
/ 104857600;
6081 status
= nfs41_UpcallWaitForReply(entry
, io_delay
);
6082 if (status
) goto out
;
6086 DbgP("This is asynchronous read, returning control back to the user\n");
6088 status
= STATUS_PENDING
;
6092 if (entry
->status
== NO_ERROR
) {
6093 #ifdef ENABLE_TIMINGS
6094 InterlockedIncrement(&read
.sops
);
6095 InterlockedAdd64(&read
.size
, entry
->u
.ReadWrite
.len
);
6097 status
= RxContext
->CurrentIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
6098 RxContext
->IoStatusBlock
.Information
= entry
->buf_len
;
6100 if ((!BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
,
6101 LOWIO_READWRITEFLAG_PAGING_IO
) &&
6102 (SrvOpen
->DesiredAccess
& FILE_READ_DATA
) &&
6103 !pVNetRootContext
->nocache
&& !nfs41_fobx
->nocache
&&
6104 !(SrvOpen
->BufferingFlags
&
6105 (FCB_STATE_READBUFFERING_ENABLED
|
6106 FCB_STATE_READCACHING_ENABLED
)))) {
6107 enable_caching(SrvOpen
, nfs41_fobx
, nfs41_fcb
->changeattr
,
6108 pVNetRootContext
->session
);
6111 status
= map_readwrite_errors(entry
->status
);
6112 RxContext
->CurrentIrp
->IoStatus
.Status
= status
;
6113 RxContext
->IoStatusBlock
.Information
= 0;
6117 #ifdef ENABLE_TIMINGS
6118 t2
= KeQueryPerformanceCounter(NULL
);
6119 InterlockedIncrement(&read
.tops
);
6120 InterlockedAdd64(&read
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
6121 #ifdef ENABLE_INDV_TIMINGS
6122 DbgP("nfs41_Read delta = %d op=%d sum=%d\n", t2
.QuadPart
- t1
.QuadPart
,
6123 read
.tops
, read
.ticks
);
6132 NTSTATUS
check_nfs41_write_args(
6133 IN PRX_CONTEXT RxContext
)
6135 NTSTATUS status
= STATUS_SUCCESS
;
6136 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
6137 NFS41GetVNetRootExtension(RxContext
->pRelevantSrvOpen
->pVNetRoot
);
6139 if (!RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Buffer
) {
6140 status
= STATUS_INVALID_USER_BUFFER
;
6144 if (pVNetRootContext
->read_only
) {
6145 print_error("check_nfs41_write_args: Read-only mount\n");
6146 status
= STATUS_ACCESS_DENIED
;
6154 NTSTATUS NTAPI
nfs41_Write(
6156 NTSTATUS
nfs41_Write(
6158 IN OUT PRX_CONTEXT RxContext
)
6160 NTSTATUS status
= STATUS_INSUFFICIENT_RESOURCES
;
6161 nfs41_updowncall_entry
*entry
;
6162 BOOLEAN async
= FALSE
;
6163 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
6164 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
6165 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
6166 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
6167 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
6168 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
6169 __notnull PNFS41_FCB nfs41_fcb
= NFS41GetFcbExtension(RxContext
->pFcb
);
6170 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
6172 #ifdef ENABLE_TIMINGS
6173 LARGE_INTEGER t1
, t2
;
6174 t1
= KeQueryPerformanceCounter(NULL
);
6179 print_readwrite_args(RxContext
);
6182 status
= check_nfs41_write_args(RxContext
);
6183 if (status
) goto out
;
6185 status
= nfs41_UpcallCreate(NFS41_WRITE
, &nfs41_fobx
->sec_ctx
,
6186 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
6187 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
6188 if (status
) goto out
;
6190 entry
->u
.ReadWrite
.MdlAddress
= LowIoContext
->ParamsFor
.ReadWrite
.Buffer
;
6191 entry
->buf_len
= LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
;
6192 entry
->u
.ReadWrite
.offset
= LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
;
6194 if (FlagOn(RxContext
->CurrentIrpSp
->FileObject
->Flags
,
6195 FO_SYNCHRONOUS_IO
) == FALSE
) {
6196 entry
->u
.ReadWrite
.rxcontext
= RxContext
;
6197 async
= entry
->async_op
= TRUE
;
6200 /* assume network speed is 100MB/s and disk speed is 100MB/s so add
6201 * time to transfer requested bytes over the network and write to disk
6203 io_delay
= pVNetRootContext
->timeout
+ 2 * entry
->buf_len
/ 104857600;
6204 status
= nfs41_UpcallWaitForReply(entry
, io_delay
);
6205 if (status
) goto out
;
6209 DbgP("This is asynchronous write, returning control back to the user\n");
6211 status
= STATUS_PENDING
;
6215 if (entry
->status
== NO_ERROR
) {
6216 //update cached file attributes
6217 #ifdef ENABLE_TIMINGS
6218 InterlockedIncrement(&write
.sops
);
6219 InterlockedAdd64(&write
.size
, entry
->u
.ReadWrite
.len
);
6221 nfs41_fcb
->StandardInfo
.EndOfFile
.QuadPart
= entry
->buf_len
+
6222 entry
->u
.ReadWrite
.offset
;
6223 status
= RxContext
->CurrentIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
6224 RxContext
->IoStatusBlock
.Information
= entry
->buf_len
;
6225 nfs41_fcb
->changeattr
= entry
->ChangeTime
;
6227 //re-enable write buffering
6228 if (!BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
,
6229 LOWIO_READWRITEFLAG_PAGING_IO
) &&
6230 (SrvOpen
->DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) &&
6231 !pVNetRootContext
->write_thru
&&
6232 !pVNetRootContext
->nocache
&&
6233 !nfs41_fobx
->write_thru
&& !nfs41_fobx
->nocache
&&
6234 !(SrvOpen
->BufferingFlags
&
6235 (FCB_STATE_WRITEBUFFERING_ENABLED
|
6236 FCB_STATE_WRITECACHING_ENABLED
))) {
6237 enable_caching(SrvOpen
, nfs41_fobx
, nfs41_fcb
->changeattr
,
6238 pVNetRootContext
->session
);
6239 } else if (!nfs41_fobx
->deleg_type
)
6240 nfs41_update_fcb_list(RxContext
->pFcb
, entry
->ChangeTime
);
6243 status
= map_readwrite_errors(entry
->status
);
6244 RxContext
->CurrentIrp
->IoStatus
.Status
= status
;
6245 RxContext
->IoStatusBlock
.Information
= 0;
6249 #ifdef ENABLE_TIMINGS
6250 t2
= KeQueryPerformanceCounter(NULL
);
6251 InterlockedIncrement(&write
.tops
);
6252 InterlockedAdd64(&write
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
6253 #ifdef ENABLE_INDV_TIMINGS
6254 DbgP("nfs41_Write delta = %d op=%d sum=%d\n", t2
.QuadPart
- t1
.QuadPart
,
6255 write
.tops
, write
.ticks
);
6265 NTSTATUS NTAPI
nfs41_IsLockRealizable(
6267 NTSTATUS
nfs41_IsLockRealizable(
6269 IN OUT PMRX_FCB pFcb
,
6270 IN PLARGE_INTEGER ByteOffset
,
6271 IN PLARGE_INTEGER Length
,
6272 IN ULONG LowIoLockFlags
)
6274 NTSTATUS status
= STATUS_SUCCESS
;
6277 DbgP("offset 0x%llx, length 0x%llx, exclusive=%u, blocking=%u\n",
6278 ByteOffset
->QuadPart
,Length
->QuadPart
,
6279 BooleanFlagOn(LowIoLockFlags
, SL_EXCLUSIVE_LOCK
),
6280 !BooleanFlagOn(LowIoLockFlags
, SL_FAIL_IMMEDIATELY
));
6283 /* NFS lock operations with length=0 MUST fail with NFS4ERR_INVAL */
6284 if (Length
->QuadPart
== 0)
6285 status
= STATUS_NOT_SUPPORTED
;
6293 NTSTATUS
map_lock_errors(
6297 case NO_ERROR
: return STATUS_SUCCESS
;
6298 case ERROR_NETNAME_DELETED
: return STATUS_NETWORK_NAME_DELETED
;
6299 case ERROR_LOCK_FAILED
: return STATUS_LOCK_NOT_GRANTED
;
6300 case ERROR_NOT_LOCKED
: return STATUS_RANGE_NOT_LOCKED
;
6301 case ERROR_ATOMIC_LOCKS_NOT_SUPPORTED
: return STATUS_UNSUCCESSFUL
;
6302 case ERROR_OUTOFMEMORY
: return STATUS_INSUFFICIENT_RESOURCES
;
6303 case ERROR_SHARING_VIOLATION
: return STATUS_SHARING_VIOLATION
;
6304 case ERROR_FILE_INVALID
: return STATUS_FILE_INVALID
;
6305 /* if we return ERROR_INVALID_PARAMETER, Windows translates that to
6307 case ERROR_INVALID_PARAMETER
: return STATUS_LOCK_NOT_GRANTED
;
6309 print_error("failed to map windows error %d to NTSTATUS; "
6310 "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", status
);
6311 case ERROR_BAD_NET_RESP
: return STATUS_INVALID_NETWORK_RESPONSE
;
6315 void print_lock_args(
6316 PRX_CONTEXT RxContext
)
6318 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
6319 const ULONG flags
= LowIoContext
->ParamsFor
.Locks
.Flags
;
6320 print_debug_header(RxContext
);
6321 DbgP("offset 0x%llx, length 0x%llx, exclusive=%u, blocking=%u\n",
6322 LowIoContext
->ParamsFor
.Locks
.ByteOffset
,
6323 LowIoContext
->ParamsFor
.Locks
.Length
,
6324 BooleanFlagOn(flags
, SL_EXCLUSIVE_LOCK
),
6325 !BooleanFlagOn(flags
, SL_FAIL_IMMEDIATELY
));
6329 /* use exponential backoff between polls for blocking locks */
6330 #define MSEC_TO_RELATIVE_WAIT (-10000)
6331 #define MIN_LOCK_POLL_WAIT (500 * MSEC_TO_RELATIVE_WAIT) /* 500ms */
6332 #define MAX_LOCK_POLL_WAIT (30000 * MSEC_TO_RELATIVE_WAIT) /* 30s */
6334 void denied_lock_backoff(
6335 IN OUT PLARGE_INTEGER delay
)
6337 if (delay
->QuadPart
== 0)
6338 delay
->QuadPart
= MIN_LOCK_POLL_WAIT
;
6340 delay
->QuadPart
<<= 1;
6342 if (delay
->QuadPart
< MAX_LOCK_POLL_WAIT
)
6343 delay
->QuadPart
= MAX_LOCK_POLL_WAIT
;
6347 NTSTATUS NTAPI
nfs41_Lock(
6349 NTSTATUS
nfs41_Lock(
6351 IN OUT PRX_CONTEXT RxContext
)
6353 NTSTATUS status
= STATUS_SUCCESS
;
6354 nfs41_updowncall_entry
*entry
;
6355 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
6356 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
6357 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
6358 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
6359 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
6360 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
6361 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
6362 const ULONG flags
= LowIoContext
->ParamsFor
.Locks
.Flags
;
6364 LARGE_INTEGER poll_delay
= {0};
6366 LARGE_INTEGER poll_delay
;
6368 #ifdef ENABLE_TIMINGS
6369 LARGE_INTEGER t1
, t2
;
6370 t1
= KeQueryPerformanceCounter(NULL
);
6374 poll_delay
.QuadPart
= 0;
6379 print_lock_args(RxContext
);
6382 /* RxReleaseFcbResourceForThreadInMRx(RxContext, RxContext->pFcb,
6383 LowIoContext->ResourceThreadId); */
6385 status
= nfs41_UpcallCreate(NFS41_LOCK
, &nfs41_fobx
->sec_ctx
,
6386 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
6387 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
6388 if (status
) goto out
;
6390 entry
->u
.Lock
.offset
= LowIoContext
->ParamsFor
.Locks
.ByteOffset
;
6391 entry
->u
.Lock
.length
= LowIoContext
->ParamsFor
.Locks
.Length
;
6392 entry
->u
.Lock
.exclusive
= BooleanFlagOn(flags
, SL_EXCLUSIVE_LOCK
);
6393 entry
->u
.Lock
.blocking
= !BooleanFlagOn(flags
, SL_FAIL_IMMEDIATELY
);
6396 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
6397 if (status
) goto out
;
6399 /* blocking locks keep trying until it succeeds */
6400 if (entry
->status
== ERROR_LOCK_FAILED
&& entry
->u
.Lock
.blocking
) {
6401 denied_lock_backoff(&poll_delay
);
6402 DbgP("returned ERROR_LOCK_FAILED; retrying in %llums\n",
6403 poll_delay
.QuadPart
/ MSEC_TO_RELATIVE_WAIT
);
6404 KeDelayExecutionThread(KernelMode
, FALSE
, &poll_delay
);
6405 entry
->state
= NFS41_WAITING_FOR_UPCALL
;
6409 status
= map_lock_errors(entry
->status
);
6410 RxContext
->CurrentIrp
->IoStatus
.Status
= status
;
6414 #ifdef ENABLE_TIMINGS
6415 t2
= KeQueryPerformanceCounter(NULL
);
6416 InterlockedIncrement(&lock
.tops
);
6417 InterlockedAdd64(&lock
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
6418 #ifdef ENABLE_INDV_TIMINGS
6419 DbgP("nfs41_Lock delta = %d op=%d sum=%d\n", t2
.QuadPart
- t1
.QuadPart
,
6420 lock
.tops
, lock
.ticks
);
6429 void print_unlock_args(
6430 PRX_CONTEXT RxContext
)
6432 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
6433 print_debug_header(RxContext
);
6434 if (LowIoContext
->Operation
== LOWIO_OP_UNLOCK_MULTIPLE
) {
6435 PLOWIO_LOCK_LIST lock
= LowIoContext
->ParamsFor
.Locks
.LockList
;
6436 DbgP("LOWIO_OP_UNLOCK_MULTIPLE:");
6438 DbgP(" (offset=%llu, length=%llu)", lock
->ByteOffset
, lock
->Length
);
6443 DbgP("LOWIO_OP_UNLOCK: offset=%llu, length=%llu\n",
6444 LowIoContext
->ParamsFor
.Locks
.ByteOffset
,
6445 LowIoContext
->ParamsFor
.Locks
.Length
);
6449 __inline ULONG
unlock_list_count(
6450 PLOWIO_LOCK_LIST lock
)
6461 NTSTATUS NTAPI
nfs41_Unlock(
6463 NTSTATUS
nfs41_Unlock(
6465 IN OUT PRX_CONTEXT RxContext
)
6467 NTSTATUS status
= STATUS_SUCCESS
;
6468 nfs41_updowncall_entry
*entry
;
6469 PLOWIO_CONTEXT LowIoContext
= &RxContext
->LowIoContext
;
6470 __notnull PNFS41_FOBX nfs41_fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
6471 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
6472 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext
=
6473 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
6474 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
6475 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
6476 #ifdef ENABLE_TIMINGS
6477 LARGE_INTEGER t1
, t2
;
6478 t1
= KeQueryPerformanceCounter(NULL
);
6482 print_lock_args(RxContext
);
6485 /* RxReleaseFcbResourceForThreadInMRx(RxContext, RxContext->pFcb,
6486 LowIoContext->ResourceThreadId); */
6488 status
= nfs41_UpcallCreate(NFS41_UNLOCK
, &nfs41_fobx
->sec_ctx
,
6489 pVNetRootContext
->session
, nfs41_fobx
->nfs41_open_state
,
6490 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
6491 if (status
) goto out
;
6493 if (LowIoContext
->Operation
== LOWIO_OP_UNLOCK_MULTIPLE
) {
6494 entry
->u
.Unlock
.count
= unlock_list_count(
6495 LowIoContext
->ParamsFor
.Locks
.LockList
);
6496 RtlCopyMemory(&entry
->u
.Unlock
.locks
,
6497 LowIoContext
->ParamsFor
.Locks
.LockList
,
6498 sizeof(LOWIO_LOCK_LIST
));
6500 entry
->u
.Unlock
.count
= 1;
6501 entry
->u
.Unlock
.locks
.ByteOffset
=
6502 LowIoContext
->ParamsFor
.Locks
.ByteOffset
;
6503 entry
->u
.Unlock
.locks
.Length
=
6504 LowIoContext
->ParamsFor
.Locks
.Length
;
6507 status
= nfs41_UpcallWaitForReply(entry
, pVNetRootContext
->timeout
);
6508 if (status
) goto out
;
6510 status
= map_lock_errors(entry
->status
);
6511 RxContext
->CurrentIrp
->IoStatus
.Status
= status
;
6514 #ifdef ENABLE_TIMINGS
6515 t2
= KeQueryPerformanceCounter(NULL
);
6516 InterlockedIncrement(&unlock
.tops
);
6517 InterlockedAdd64(&unlock
.ticks
, t2
.QuadPart
- t1
.QuadPart
);
6518 #ifdef ENABLE_INDV_TIMINGS
6519 DbgP("nfs41_Unlock delta = %d op=%d sum=%d\n", t2
.QuadPart
- t1
.QuadPart
,
6520 unlock
.tops
, unlock
.ticks
);
6529 NTSTATUS
map_symlink_errors(
6533 case NO_ERROR
: return STATUS_SUCCESS
;
6534 case ERROR_INVALID_REPARSE_DATA
: return STATUS_IO_REPARSE_DATA_INVALID
;
6535 case ERROR_NOT_A_REPARSE_POINT
: return STATUS_NOT_A_REPARSE_POINT
;
6536 case ERROR_ACCESS_DENIED
: return STATUS_ACCESS_DENIED
;
6537 case ERROR_NOT_EMPTY
: return STATUS_DIRECTORY_NOT_EMPTY
;
6538 case ERROR_OUTOFMEMORY
: return STATUS_INSUFFICIENT_RESOURCES
;
6539 case ERROR_INSUFFICIENT_BUFFER
: return STATUS_BUFFER_TOO_SMALL
;
6540 case STATUS_BUFFER_TOO_SMALL
:
6541 case ERROR_BUFFER_OVERFLOW
: return STATUS_BUFFER_OVERFLOW
;
6543 print_error("failed to map windows error %d to NTSTATUS; "
6544 "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", status
);
6545 case ERROR_BAD_NET_RESP
: return STATUS_INVALID_NETWORK_RESPONSE
;
6549 void print_reparse_buffer(
6550 PREPARSE_DATA_BUFFER Reparse
)
6552 UNICODE_STRING name
;
6553 DbgP("ReparseTag: %08X\n", Reparse
->ReparseTag
);
6554 DbgP("ReparseDataLength: %8u\n", Reparse
->ReparseDataLength
);
6555 DbgP("Reserved: %8u\n", Reparse
->Reserved
);
6556 DbgP("SubstituteNameOffset: %8u\n",
6557 Reparse
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
);
6558 DbgP("SubstituteNameLength: %8u\n",
6559 Reparse
->SymbolicLinkReparseBuffer
.SubstituteNameLength
);
6560 DbgP("PrintNameOffset: %8u\n",
6561 Reparse
->SymbolicLinkReparseBuffer
.PrintNameOffset
);
6562 DbgP("PrintNameLength: %8u\n",
6563 Reparse
->SymbolicLinkReparseBuffer
.PrintNameLength
);
6564 DbgP("Flags: %08X\n",
6565 Reparse
->SymbolicLinkReparseBuffer
.Flags
);
6567 name
.Buffer
= &Reparse
->SymbolicLinkReparseBuffer
.PathBuffer
[
6568 Reparse
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
/sizeof(WCHAR
)];
6569 name
.MaximumLength
= name
.Length
=
6570 Reparse
->SymbolicLinkReparseBuffer
.SubstituteNameLength
;
6571 DbgP("SubstituteName: %wZ\n", &name
);
6573 name
.Buffer
= &Reparse
->SymbolicLinkReparseBuffer
.PathBuffer
[
6574 Reparse
->SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(WCHAR
)];
6575 name
.MaximumLength
= name
.Length
=
6576 Reparse
->SymbolicLinkReparseBuffer
.PrintNameLength
;
6577 DbgP("PrintName: %wZ\n", &name
);
6580 NTSTATUS
check_nfs41_setreparse_args(
6581 IN PRX_CONTEXT RxContext
)
6583 NTSTATUS status
= STATUS_SUCCESS
;
6584 __notnull XXCTL_LOWIO_COMPONENT
*FsCtl
= &RxContext
->LowIoContext
.ParamsFor
.FsCtl
;
6585 __notnull PREPARSE_DATA_BUFFER Reparse
= (PREPARSE_DATA_BUFFER
)FsCtl
->pInputBuffer
;
6586 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
6587 __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext
=
6588 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
6589 const ULONG HeaderLen
= REPARSE_DATA_BUFFER_HEADER_SIZE
;
6592 if (VNetRootContext
->read_only
) {
6593 status
= STATUS_MEDIA_WRITE_PROTECTED
;
6596 if (!(SrvOpen
->DesiredAccess
& (FILE_WRITE_DATA
|FILE_WRITE_ATTRIBUTES
))) {
6597 status
= STATUS_ACCESS_DENIED
;
6601 /* must have a filename longer than vnetroot name,
6602 * or it's trying to operate on the volume itself */
6603 if (is_root_directory(RxContext
)) {
6604 status
= STATUS_INVALID_PARAMETER
;
6607 if (FsCtl
->pOutputBuffer
!= NULL
) {
6608 status
= STATUS_INVALID_PARAMETER
;
6612 /* validate input buffer and length */
6614 status
= STATUS_INVALID_BUFFER_SIZE
;
6618 if (FsCtl
->InputBufferLength
< HeaderLen
||
6619 FsCtl
->InputBufferLength
> MAXIMUM_REPARSE_DATA_BUFFER_SIZE
) {
6620 status
= STATUS_IO_REPARSE_DATA_INVALID
;
6623 if (FsCtl
->InputBufferLength
!= HeaderLen
+ Reparse
->ReparseDataLength
) {
6624 status
= STATUS_IO_REPARSE_DATA_INVALID
;
6628 /* validate reparse tag */
6629 if (!IsReparseTagValid(Reparse
->ReparseTag
)) {
6630 status
= STATUS_IO_REPARSE_TAG_INVALID
;
6633 if (Reparse
->ReparseTag
!= IO_REPARSE_TAG_SYMLINK
) {
6634 status
= STATUS_IO_REPARSE_TAG_MISMATCH
;
6641 NTSTATUS
nfs41_SetReparsePoint(
6642 IN OUT PRX_CONTEXT RxContext
)
6645 UNICODE_STRING TargetName
;
6646 __notnull XXCTL_LOWIO_COMPONENT
*FsCtl
= &RxContext
->LowIoContext
.ParamsFor
.FsCtl
;
6647 __notnull PREPARSE_DATA_BUFFER Reparse
= (PREPARSE_DATA_BUFFER
)FsCtl
->pInputBuffer
;
6648 __notnull PNFS41_FOBX Fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
6649 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
6650 __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext
=
6651 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
6652 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
6653 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
6654 nfs41_updowncall_entry
*entry
;
6656 #ifdef DEBUG_SYMLINK
6658 print_debug_header(RxContext
);
6659 print_reparse_buffer(Reparse
);
6661 status
= check_nfs41_setreparse_args(RxContext
);
6662 if (status
) goto out
;
6664 TargetName
.MaximumLength
= TargetName
.Length
=
6665 Reparse
->SymbolicLinkReparseBuffer
.PrintNameLength
;
6666 TargetName
.Buffer
= &Reparse
->SymbolicLinkReparseBuffer
.PathBuffer
[
6667 Reparse
->SymbolicLinkReparseBuffer
.PrintNameOffset
/sizeof(WCHAR
)];
6669 status
= nfs41_UpcallCreate(NFS41_SYMLINK
, &Fobx
->sec_ctx
,
6670 VNetRootContext
->session
, Fobx
->nfs41_open_state
,
6671 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
6672 if (status
) goto out
;
6674 entry
->u
.Symlink
.target
= &TargetName
;
6675 entry
->u
.Symlink
.set
= TRUE
;
6677 status
= nfs41_UpcallWaitForReply(entry
, VNetRootContext
->timeout
);
6678 if (status
) goto out
;
6680 status
= map_symlink_errors(entry
->status
);
6683 #ifdef DEBUG_SYMLINK
6689 NTSTATUS
check_nfs41_getreparse_args(
6690 PRX_CONTEXT RxContext
)
6692 NTSTATUS status
= STATUS_SUCCESS
;
6693 XXCTL_LOWIO_COMPONENT
*FsCtl
= &RxContext
->LowIoContext
.ParamsFor
.FsCtl
;
6694 const USHORT HeaderLen
= FIELD_OFFSET(REPARSE_DATA_BUFFER
,
6695 SymbolicLinkReparseBuffer
.PathBuffer
);
6697 /* must have a filename longer than vnetroot name,
6698 * or it's trying to operate on the volume itself */
6699 if (is_root_directory(RxContext
)) {
6700 status
= STATUS_INVALID_PARAMETER
;
6703 /* ifs reparse tests expect STATUS_INVALID_PARAMETER,
6704 * but 'dir' passes a buffer here when querying symlinks
6705 if (FsCtl->pInputBuffer != NULL) {
6706 status = STATUS_INVALID_PARAMETER;
6709 if (!FsCtl
->pOutputBuffer
) {
6710 status
= STATUS_INVALID_USER_BUFFER
;
6713 if (!BooleanFlagOn(RxContext
->pFcb
->Attributes
,
6714 FILE_ATTRIBUTE_REPARSE_POINT
)) {
6715 status
= STATUS_NOT_A_REPARSE_POINT
;
6716 DbgP("FILE_ATTRIBUTE_REPARSE_POINT is not set!\n");
6720 if (FsCtl
->OutputBufferLength
< HeaderLen
) {
6721 RxContext
->InformationToReturn
= HeaderLen
;
6722 status
= STATUS_BUFFER_TOO_SMALL
;
6729 NTSTATUS
nfs41_GetReparsePoint(
6730 IN OUT PRX_CONTEXT RxContext
)
6733 UNICODE_STRING TargetName
;
6734 XXCTL_LOWIO_COMPONENT
*FsCtl
= &RxContext
->LowIoContext
.ParamsFor
.FsCtl
;
6735 __notnull PNFS41_FOBX Fobx
= NFS41GetFobxExtension(RxContext
->pFobx
);
6736 __notnull PMRX_SRV_OPEN SrvOpen
= RxContext
->pRelevantSrvOpen
;
6737 __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext
=
6738 NFS41GetVNetRootExtension(SrvOpen
->pVNetRoot
);
6739 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext
=
6740 NFS41GetNetRootExtension(SrvOpen
->pVNetRoot
->pNetRoot
);
6741 nfs41_updowncall_entry
*entry
;
6742 const USHORT HeaderLen
= FIELD_OFFSET(REPARSE_DATA_BUFFER
,
6743 SymbolicLinkReparseBuffer
.PathBuffer
);
6745 #ifdef DEBUG_SYMLINK
6748 status
= check_nfs41_getreparse_args(RxContext
);
6749 if (status
) goto out
;
6751 TargetName
.Buffer
= (PWCH
)((PBYTE
)FsCtl
->pOutputBuffer
+ HeaderLen
);
6752 TargetName
.MaximumLength
= (USHORT
)min(FsCtl
->OutputBufferLength
-
6755 status
= nfs41_UpcallCreate(NFS41_SYMLINK
, &Fobx
->sec_ctx
,
6756 VNetRootContext
->session
, Fobx
->nfs41_open_state
,
6757 pNetRootContext
->nfs41d_version
, SrvOpen
->pAlreadyPrefixedName
, &entry
);
6758 if (status
) goto out
;
6760 entry
->u
.Symlink
.target
= &TargetName
;
6761 entry
->u
.Symlink
.set
= FALSE
;
6763 status
= nfs41_UpcallWaitForReply(entry
, VNetRootContext
->timeout
);
6764 if (status
) goto out
;
6766 status
= map_symlink_errors(entry
->status
);
6767 if (status
== STATUS_SUCCESS
) {
6768 /* fill in the output buffer */
6769 PREPARSE_DATA_BUFFER Reparse
= (PREPARSE_DATA_BUFFER
)
6770 FsCtl
->pOutputBuffer
;
6771 Reparse
->ReparseTag
= IO_REPARSE_TAG_SYMLINK
;
6772 Reparse
->ReparseDataLength
= HeaderLen
+ TargetName
.Length
-
6773 REPARSE_DATA_BUFFER_HEADER_SIZE
;
6774 Reparse
->Reserved
= 0;
6775 Reparse
->SymbolicLinkReparseBuffer
.Flags
= SYMLINK_FLAG_RELATIVE
;
6776 /* PrintName and SubstituteName point to the same string */
6777 Reparse
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
= 0;
6778 Reparse
->SymbolicLinkReparseBuffer
.SubstituteNameLength
=
6780 Reparse
->SymbolicLinkReparseBuffer
.PrintNameOffset
= 0;
6781 Reparse
->SymbolicLinkReparseBuffer
.PrintNameLength
= TargetName
.Length
;
6782 print_reparse_buffer(Reparse
);
6784 RxContext
->IoStatusBlock
.Information
= HeaderLen
+ TargetName
.Length
;
6785 } else if (status
== STATUS_BUFFER_TOO_SMALL
) {
6786 RxContext
->InformationToReturn
= HeaderLen
+ TargetName
.Length
;
6790 #ifdef DEBUG_SYMLINK
6797 NTSTATUS NTAPI
nfs41_FsCtl(
6799 NTSTATUS
nfs41_FsCtl(
6801 IN OUT PRX_CONTEXT RxContext
)
6803 NTSTATUS status
= STATUS_INVALID_DEVICE_REQUEST
;
6806 print_debug_header(RxContext
);
6808 switch (RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
) {
6809 case FSCTL_SET_REPARSE_POINT
:
6810 status
= nfs41_SetReparsePoint(RxContext
);
6813 case FSCTL_GET_REPARSE_POINT
:
6814 status
= nfs41_GetReparsePoint(RxContext
);
6818 DbgP("FsControlCode: %d\n",
6819 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
);
6829 NTSTATUS NTAPI
nfs41_CompleteBufferingStateChangeRequest(
6831 NTSTATUS
nfs41_CompleteBufferingStateChangeRequest(
6833 IN OUT PRX_CONTEXT RxContext
,
6834 IN OUT PMRX_SRV_OPEN SrvOpen
,
6837 return STATUS_SUCCESS
;
6841 NTSTATUS NTAPI
nfs41_FsdDispatch (
6843 NTSTATUS
nfs41_FsdDispatch (
6845 IN PDEVICE_OBJECT dev
,
6848 #ifdef DEBUG_FSDDISPATCH
6849 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
6853 #ifdef DEBUG_FSDDISPATCH
6855 DbgP("CURRENT IRP = %d.%d\n", IrpSp
->MajorFunction
, IrpSp
->MinorFunction
);
6856 if(IrpSp
->FileObject
)
6857 DbgP("FileOject %p Filename %wZ\n", IrpSp
->FileObject
,
6858 &IrpSp
->FileObject
->FileName
);
6861 if (dev
!= (PDEVICE_OBJECT
)nfs41_dev
) {
6862 print_error("*** not ours ***\n");
6863 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
6864 Irp
->IoStatus
.Information
= 0;
6865 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
6866 status
= STATUS_INVALID_DEVICE_REQUEST
;
6870 status
= RxFsdDispatch((PRDBSS_DEVICE_OBJECT
)dev
,Irp
);
6871 /* AGLO: 08/05/2009 - looks like RxFsdDispatch frees IrpSp */
6874 #ifdef DEBUG_FSDDISPATCH
6875 DbgP("IoStatus status = 0x%x info = 0x%x\n", Irp
->IoStatus
.Status
,
6876 Irp
->IoStatus
.Information
);
6883 NTSTATUS NTAPI
nfs41_Unimplemented(
6885 NTSTATUS
nfs41_Unimplemented(
6887 PRX_CONTEXT RxContext
)
6889 return STATUS_NOT_IMPLEMENTED
;
6893 NTSTATUS NTAPI
nfs41_AreFilesAliased(
6895 NTSTATUS
nfs41_AreFilesAliased(
6900 return STATUS_NOT_IMPLEMENTED
;
6903 NTSTATUS
nfs41_init_ops()
6907 ZeroAndInitializeNodeType(&nfs41_ops
, RDBSS_NTC_MINIRDR_DISPATCH
,
6908 sizeof(MINIRDR_DISPATCH
));
6910 nfs41_ops
.MRxFlags
= (RDBSS_MANAGE_NET_ROOT_EXTENSION
|
6911 RDBSS_MANAGE_V_NET_ROOT_EXTENSION
|
6912 RDBSS_MANAGE_FCB_EXTENSION
|
6913 RDBSS_MANAGE_FOBX_EXTENSION
);
6915 nfs41_ops
.MRxSrvCallSize
= 0; // srvcall extension is not handled in rdbss
6916 nfs41_ops
.MRxNetRootSize
= sizeof(NFS41_NETROOT_EXTENSION
);
6917 nfs41_ops
.MRxVNetRootSize
= sizeof(NFS41_V_NET_ROOT_EXTENSION
);
6918 nfs41_ops
.MRxFcbSize
= sizeof(NFS41_FCB
);
6919 nfs41_ops
.MRxFobxSize
= sizeof(NFS41_FOBX
);
6921 // Mini redirector cancel routine ..
6923 nfs41_ops
.MRxCancel
= NULL
;
6926 // Mini redirector Start/Stop. Each mini-rdr can be started or stopped
6927 // while the others continue to operate.
6930 nfs41_ops
.MRxStart
= nfs41_Start
;
6931 nfs41_ops
.MRxStop
= nfs41_Stop
;
6932 nfs41_ops
.MRxDevFcbXXXControlFile
= nfs41_DevFcbXXXControlFile
;
6935 // Mini redirector name resolution.
6938 nfs41_ops
.MRxCreateSrvCall
= nfs41_CreateSrvCall
;
6939 nfs41_ops
.MRxSrvCallWinnerNotify
= nfs41_SrvCallWinnerNotify
;
6940 nfs41_ops
.MRxCreateVNetRoot
= nfs41_CreateVNetRoot
;
6941 nfs41_ops
.MRxExtractNetRootName
= nfs41_ExtractNetRootName
;
6942 nfs41_ops
.MRxFinalizeSrvCall
= nfs41_FinalizeSrvCall
;
6943 nfs41_ops
.MRxFinalizeNetRoot
= nfs41_FinalizeNetRoot
;
6944 nfs41_ops
.MRxFinalizeVNetRoot
= nfs41_FinalizeVNetRoot
;
6947 // File System Object Creation/Deletion.
6950 nfs41_ops
.MRxCreate
= nfs41_Create
;
6951 nfs41_ops
.MRxCollapseOpen
= nfs41_CollapseOpen
;
6952 nfs41_ops
.MRxShouldTryToCollapseThisOpen
= nfs41_ShouldTryToCollapseThisOpen
;
6953 nfs41_ops
.MRxExtendForCache
= nfs41_ExtendForCache
;
6954 nfs41_ops
.MRxExtendForNonCache
= nfs41_ExtendForCache
;
6955 nfs41_ops
.MRxCloseSrvOpen
= nfs41_CloseSrvOpen
;
6956 nfs41_ops
.MRxFlush
= nfs41_Flush
;
6957 nfs41_ops
.MRxDeallocateForFcb
= nfs41_DeallocateForFcb
;
6958 nfs41_ops
.MRxDeallocateForFobx
= nfs41_DeallocateForFobx
;
6959 nfs41_ops
.MRxIsLockRealizable
= nfs41_IsLockRealizable
;
6962 // File System Objects query/Set
6965 nfs41_ops
.MRxQueryDirectory
= nfs41_QueryDirectory
;
6966 nfs41_ops
.MRxQueryVolumeInfo
= nfs41_QueryVolumeInformation
;
6967 nfs41_ops
.MRxQueryEaInfo
= nfs41_QueryEaInformation
;
6968 nfs41_ops
.MRxSetEaInfo
= nfs41_SetEaInformation
;
6969 nfs41_ops
.MRxQuerySdInfo
= nfs41_QuerySecurityInformation
;
6970 nfs41_ops
.MRxSetSdInfo
= nfs41_SetSecurityInformation
;
6971 nfs41_ops
.MRxQueryFileInfo
= nfs41_QueryFileInformation
;
6972 nfs41_ops
.MRxSetFileInfo
= nfs41_SetFileInformation
;
6975 // Buffering state change
6978 nfs41_ops
.MRxComputeNewBufferingState
= nfs41_ComputeNewBufferingState
;
6981 // File System Object I/O
6984 nfs41_ops
.MRxLowIOSubmit
[LOWIO_OP_READ
] = nfs41_Read
;
6985 nfs41_ops
.MRxLowIOSubmit
[LOWIO_OP_WRITE
] = nfs41_Write
;
6986 nfs41_ops
.MRxLowIOSubmit
[LOWIO_OP_SHAREDLOCK
] = nfs41_Lock
;
6987 nfs41_ops
.MRxLowIOSubmit
[LOWIO_OP_EXCLUSIVELOCK
] = nfs41_Lock
;
6988 nfs41_ops
.MRxLowIOSubmit
[LOWIO_OP_UNLOCK
] = nfs41_Unlock
;
6989 nfs41_ops
.MRxLowIOSubmit
[LOWIO_OP_UNLOCK_MULTIPLE
] = nfs41_Unlock
;
6990 nfs41_ops
.MRxLowIOSubmit
[LOWIO_OP_FSCTL
] = nfs41_FsCtl
;
6996 nfs41_ops
.MRxCompleteBufferingStateChangeRequest
=
6997 nfs41_CompleteBufferingStateChangeRequest
;
6998 nfs41_ops
.MRxIsValidDirectory
= nfs41_IsValidDirectory
;
7000 nfs41_ops
.MRxTruncate
= nfs41_Unimplemented
;
7001 nfs41_ops
.MRxZeroExtend
= nfs41_Unimplemented
;
7002 nfs41_ops
.MRxAreFilesAliased
= nfs41_AreFilesAliased
;
7003 nfs41_ops
.MRxQueryQuotaInfo
= nfs41_Unimplemented
;
7004 nfs41_ops
.MRxSetQuotaInfo
= nfs41_Unimplemented
;
7005 nfs41_ops
.MRxSetVolumeInfo
= nfs41_Unimplemented
;
7008 return(STATUS_SUCCESS
);
7011 KSTART_ROUTINE fcbopen_main
;
7013 VOID NTAPI
fcbopen_main(PVOID ctx
)
7015 VOID
fcbopen_main(PVOID ctx
)
7019 LARGE_INTEGER timeout
;
7022 timeout
.QuadPart
= RELATIVE(SECONDS(30));
7025 nfs41_fcb_list_entry
*cur
;
7026 status
= KeDelayExecutionThread(KernelMode
, TRUE
, &timeout
);
7027 ExAcquireFastMutex(&fcblistLock
);
7028 pEntry
= openlist
.head
.Flink
;
7029 while (!IsListEmpty(&openlist
.head
)) {
7030 PNFS41_NETROOT_EXTENSION pNetRootContext
;
7031 nfs41_updowncall_entry
*entry
;
7032 FILE_BASIC_INFORMATION binfo
;
7033 PNFS41_FCB nfs41_fcb
;
7034 cur
= (nfs41_fcb_list_entry
*)CONTAINING_RECORD(pEntry
,
7035 nfs41_fcb_list_entry
, next
);
7037 #ifdef DEBUG_TIME_BASED_COHERENCY
7038 DbgP("fcbopen_main: Checking attributes for fcb=%p "
7039 "change_time=%llu skipping=%d\n", cur
->fcb
,
7040 cur
->ChangeTime
, cur
->skip
);
7042 if (cur
->skip
) goto out
;
7044 NFS41GetNetRootExtension(cur
->fcb
->pNetRoot
);
7045 /* place an upcall for this srv_open */
7046 status
= nfs41_UpcallCreate(NFS41_FILE_QUERY
,
7047 &cur
->nfs41_fobx
->sec_ctx
, cur
->session
,
7048 cur
->nfs41_fobx
->nfs41_open_state
,
7049 pNetRootContext
->nfs41d_version
, NULL
, &entry
);
7050 if (status
) goto out
;
7052 entry
->u
.QueryFile
.InfoClass
= FileBasicInformation
;
7053 entry
->buf
= &binfo
;
7054 entry
->buf_len
= sizeof(binfo
);
7056 status
= nfs41_UpcallWaitForReply(entry
, UPCALL_TIMEOUT_DEFAULT
);
7057 if (status
) goto out
;
7059 if (cur
->ChangeTime
!= entry
->ChangeTime
) {
7060 ULONG flag
= DISABLE_CACHING
;
7061 PMRX_SRV_OPEN srv_open
;
7062 PLIST_ENTRY psrvEntry
;
7063 #ifdef DEBUG_TIME_BASED_COHERENCY
7064 DbgP("fcbopen_main: old ctime=%llu new_ctime=%llu\n",
7065 cur
->ChangeTime
, entry
->ChangeTime
);
7067 cur
->ChangeTime
= entry
->ChangeTime
;
7069 psrvEntry
= &cur
->fcb
->SrvOpenList
;
7070 psrvEntry
= psrvEntry
->Flink
;
7071 while (!IsListEmpty(&cur
->fcb
->SrvOpenList
)) {
7072 srv_open
= (PMRX_SRV_OPEN
)CONTAINING_RECORD(psrvEntry
,
7073 MRX_SRV_OPEN
, SrvOpenQLinks
);
7074 if (srv_open
->DesiredAccess
&
7075 (FILE_READ_DATA
| FILE_WRITE_DATA
| FILE_APPEND_DATA
)) {
7076 #ifdef DEBUG_TIME_BASED_COHERENCY
7077 DbgP("fcbopen_main: ************ Invalidate the cache %wZ"
7078 "************\n", srv_open
->pAlreadyPrefixedName
);
7080 RxIndicateChangeOfBufferingStateForSrvOpen(
7081 cur
->fcb
->pNetRoot
->pSrvCall
, srv_open
,
7082 srv_open
->Key
, ULongToPtr(flag
));
7084 if (psrvEntry
->Flink
== &cur
->fcb
->SrvOpenList
) {
7085 #ifdef DEBUG_TIME_BASED_COHERENCY
7086 DbgP("fcbopen_main: reached end of srvopen for fcb %p\n",
7091 psrvEntry
= psrvEntry
->Flink
;
7094 nfs41_fcb
= (PNFS41_FCB
)cur
->fcb
->Context
;
7095 nfs41_fcb
->changeattr
= entry
->ChangeTime
;
7098 if (pEntry
->Flink
== &openlist
.head
) {
7099 #ifdef DEBUG_TIME_BASED_COHERENCY
7100 DbgP("fcbopen_main: reached end of the fcb list\n");
7104 pEntry
= pEntry
->Flink
;
7106 ExReleaseFastMutex(&fcblistLock
);
7112 NTSTATUS NTAPI
DriverEntry(
7114 NTSTATUS
DriverEntry(
7116 IN PDRIVER_OBJECT drv
,
7117 IN PUNICODE_STRING path
)
7121 UNICODE_STRING dev_name
, user_dev_name
;
7122 PNFS41_DEVICE_EXTENSION dev_exts
;
7123 TIME_FIELDS jan_1_1970
= {1970, 1, 1, 0, 0, 0, 0, 0};
7124 ACCESS_MASK mask
= 0;
7125 OBJECT_ATTRIBUTES oattrs
;
7129 status
= RxDriverEntry(drv
, path
);
7130 if (status
!= STATUS_SUCCESS
) {
7131 print_error("RxDriverEntry failed: %08lx\n", status
);
7135 RtlInitUnicodeString(&dev_name
, NFS41_DEVICE_NAME
);
7136 SetFlag(flags
, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS
);
7138 status
= nfs41_init_ops();
7139 if (status
!= STATUS_SUCCESS
) {
7140 print_error("nfs41_init_ops failed to initialize dispatch table\n");
7144 DbgP("calling RxRegisterMinirdr\n");
7145 status
= RxRegisterMinirdr(&nfs41_dev
, drv
, &nfs41_ops
, flags
, &dev_name
,
7146 sizeof(NFS41_DEVICE_EXTENSION
),
7147 FILE_DEVICE_NETWORK_FILE_SYSTEM
, FILE_REMOTE_DEVICE
);
7148 if (status
!= STATUS_SUCCESS
) {
7149 print_error("RxRegisterMinirdr failed: %08lx\n", status
);
7153 nfs41_dev
->Flags
|= DO_BUFFERED_IO
;
7156 dev_exts
= (PNFS41_DEVICE_EXTENSION
)
7157 ((PBYTE
)(nfs41_dev
) + sizeof(RDBSS_DEVICE_OBJECT
));
7159 RxDefineNode(dev_exts
, NFS41_DEVICE_EXTENSION
);
7160 dev_exts
->DeviceObject
= nfs41_dev
;
7161 nfs41_create_volume_info((PFILE_FS_VOLUME_INFORMATION
)dev_exts
->VolAttrs
,
7162 &dev_exts
->VolAttrsLen
);
7164 RtlInitUnicodeString(&user_dev_name
, NFS41_SHADOW_DEVICE_NAME
);
7165 DbgP("calling IoCreateSymbolicLink %wZ %wZ\n", &user_dev_name
, &dev_name
);
7166 status
= IoCreateSymbolicLink(&user_dev_name
, &dev_name
);
7167 if (status
!= STATUS_SUCCESS
) {
7168 print_error("Device name IoCreateSymbolicLink failed: %08lx\n", status
);
7169 goto out_unregister
;
7172 KeInitializeEvent(&upcallEvent
, SynchronizationEvent
, FALSE
);
7173 ExInitializeFastMutex(&upcallLock
);
7174 ExInitializeFastMutex(&downcallLock
);
7175 ExInitializeFastMutex(&xidLock
);
7176 ExInitializeFastMutex(&openOwnerLock
);
7177 ExInitializeFastMutex(&fcblistLock
);
7178 InitializeListHead(&upcall
.head
);
7179 InitializeListHead(&downcall
.head
);
7180 InitializeListHead(&openlist
.head
);
7181 InitializeObjectAttributes(&oattrs
, NULL
, OBJ_KERNEL_HANDLE
, NULL
, NULL
);
7182 status
= PsCreateSystemThread(&dev_exts
->openlistHandle
, mask
,
7183 &oattrs
, NULL
, NULL
, &fcbopen_main
, NULL
);
7184 if (status
!= STATUS_SUCCESS
)
7185 goto out_unregister
;
7187 drv
->DriverUnload
= nfs41_driver_unload
;
7189 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
7190 drv
->MajorFunction
[i
] = (PDRIVER_DISPATCH
)nfs41_FsdDispatch
;
7192 RtlTimeFieldsToTime(&jan_1_1970
, &unix_time_diff
);
7195 if (status
!= STATUS_SUCCESS
)
7196 RxUnregisterMinirdr(nfs41_dev
);
7203 VOID NTAPI
nfs41_driver_unload(IN PDRIVER_OBJECT drv
)
7205 VOID
nfs41_driver_unload(IN PDRIVER_OBJECT drv
)
7208 PRX_CONTEXT RxContext
;
7210 UNICODE_STRING dev_name
, pipe_name
;
7214 RxContext
= RxCreateRxContext(NULL
, nfs41_dev
, RX_CONTEXT_FLAG_IN_FSP
);
7215 if (RxContext
== NULL
) {
7216 status
= STATUS_INSUFFICIENT_RESOURCES
;
7219 status
= RxStopMinirdr(RxContext
, &RxContext
->PostRequest
);
7220 RxDereferenceAndDeleteRxContext(RxContext
);
7223 RtlInitUnicodeString(&dev_name
, NFS41_SHADOW_DEVICE_NAME
);
7224 status
= IoDeleteSymbolicLink(&dev_name
);
7225 if (status
!= STATUS_SUCCESS
) {
7226 print_error("couldn't delete device symbolic link\n");
7228 RtlInitUnicodeString(&pipe_name
, NFS41_SHADOW_PIPE_NAME
);
7229 status
= IoDeleteSymbolicLink(&pipe_name
);
7230 if (status
!= STATUS_SUCCESS
) {
7231 print_error("couldn't delete pipe symbolic link\n");
7235 DbgP("driver unloaded %p\n", drv
);