1 /* NFSv4.1 client for Windows
2  * Copyright © 2012 The Regents of the University of Michigan
3  *
4  * Olga Kornievskaia <aglo@umich.edu>
5  * Casey Bodley <cbodley@umich.edu>
6  *
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.
11  *
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.
16  *
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
20  */
21 
22 #define MINIRDR__NAME "Value is ignored, only fact of definition"
23 #include <rx.h>
24 #include <windef.h>
25 #include <winerror.h>
26 
27 #include <ntstrsafe.h>
28 
29 #ifdef __REACTOS__
30 #include <pseh/pseh2.h>
31 #endif
32 
33 #include "nfs41_driver.h"
34 #include "nfs41_np.h"
35 #include "nfs41_debug.h"
36 
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) */
45 
46 #define USE_MOUNT_SEC_CONTEXT
47 
48 /* debugging printout defines */
49 //#define DEBUG_FSDDISPATCH
50 #define DEBUG_MARSHAL_HEADER
51 #define DEBUG_MARSHAL_DETAIL
52 //#define DEBUG_OPEN
53 //#define DEBUG_CLOSE
54 //#define DEBUG_CACHE
55 #define DEBUG_INVALIDATE_CACHE
56 //#define DEBUG_READ
57 //#define DEBUG_WRITE
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
65 //#define DEBUG_LOCK
66 //#define DEBUG_MISC
67 #define DEBUG_TIME_BASED_COHERENCY
68 #define DEBUG_MOUNT
69 //#define DEBUG_VOLUME_QUERY
70 
71 //#define ENABLE_TIMINGS
72 //#define ENABLE_INDV_TIMINGS
73 #ifdef ENABLE_TIMINGS
74 typedef struct __nfs41_timings {
75     LONG tops, sops;
76     LONGLONG ticks, size;
77 } nfs41_timings;
78 
79 nfs41_timings lookup, readdir, open, close, getattr, setattr, getacl, setacl, volume,
80     read, write, lock, unlock, setexattr, getexattr;
81 #endif
82 DRIVER_INITIALIZE DriverEntry;
83 DRIVER_UNLOAD nfs41_driver_unload;
84 DRIVER_DISPATCH ( nfs41_FsdDispatch );
85 
86 struct _MINIRDR_DISPATCH nfs41_ops;
87 PRDBSS_DEVICE_OBJECT nfs41_dev;
88 
89 #define DISABLE_CACHING 0
90 #define ENABLE_READ_CACHING 1
91 #define ENABLE_WRITE_CACHING 2
92 #define ENABLE_READWRITE_CACHING 3
93 
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')
100 
101 KEVENT upcallEvent;
102 FAST_MUTEX upcallLock, downcallLock, fcblistLock;
103 FAST_MUTEX xidLock;
104 FAST_MUTEX openOwnerLock;
105 
106 LONGLONG xid = 0;
107 LONG open_owner_id = 1;
108 
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))
118 
119 DECLARE_CONST_ANSI_STRING(NfsV3Attributes, "NfsV3Attributes");
120 DECLARE_CONST_ANSI_STRING(NfsSymlinkTargetName, "NfsSymlinkTargetName");
121 DECLARE_CONST_ANSI_STRING(NfsActOnLink, "NfsActOnLink");
122 
AnsiStrEq(IN const ANSI_STRING * lhs,IN const CHAR * rhs,IN const UCHAR rhs_len)123 INLINE BOOL AnsiStrEq(
124     IN const ANSI_STRING *lhs,
125     IN const CHAR *rhs,
126     IN const UCHAR rhs_len)
127 {
128     return lhs->Length == rhs_len &&
129         RtlCompareMemory(lhs->Buffer, rhs, rhs_len) == rhs_len;
130 }
131 
132 typedef struct _nfs3_attrs {
133     DWORD type, mode, nlink, uid, gid, filler1;
134     LARGE_INTEGER size, used;
135     struct {
136         DWORD specdata1;
137         DWORD specdata2;
138     } rdev;
139     LONGLONG fsid, fileid;
140     LONGLONG atime, mtime, ctime;
141 } nfs3_attrs;
142 LARGE_INTEGER unix_time_diff; //needed to convert windows time to unix
143 
144 enum ftype3 {
145     NF3REG = 1,
146     NF3DIR,
147     NF3BLK,
148     NF3CHR,
149     NF3LNK,
150     NF3SOCK,
151     NF3FIFO
152 };
153 
154 typedef enum _nfs41_updowncall_state {
155     NFS41_WAITING_FOR_UPCALL,
156     NFS41_WAITING_FOR_DOWNCALL,
157     NFS41_DONE_PROCESSING,
158     NFS41_NOT_WAITING
159 } nfs41_updowncall_state;
160 
161 #ifdef __REACTOS__
162 #undef _errno
163 #undef errno
164 #endif
165 
166 typedef struct _updowncall_entry {
167     DWORD version;
168     LONGLONG xid;
169     DWORD opcode;
170     NTSTATUS status;
171     nfs41_updowncall_state state;
172     FAST_MUTEX lock;
173     LIST_ENTRY next;
174     KEVENT cond;
175     DWORD errno;
176     BOOLEAN async_op;
177     SECURITY_CLIENT_CONTEXT sec_ctx;
178     PSECURITY_CLIENT_CONTEXT psec_ctx;
179     HANDLE open_state;
180     HANDLE session;
181     PUNICODE_STRING filename;
182     PVOID buf;
183     ULONG buf_len;
184     ULONGLONG ChangeTime;
185     union {
186         struct {
187             PUNICODE_STRING srv_name;
188             PUNICODE_STRING root;
189             PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs;
190             DWORD sec_flavor;
191             DWORD rsize;
192             DWORD wsize;
193             DWORD lease_time;
194         } Mount;
195         struct {
196             PMDL MdlAddress;
197             ULONGLONG offset;
198             PRX_CONTEXT rxcontext;
199         } ReadWrite;
200         struct {
201             LONGLONG offset;
202             LONGLONG length;
203             BOOLEAN exclusive;
204             BOOLEAN blocking;
205         } Lock;
206         struct {
207             ULONG count;
208             LOWIO_LOCK_LIST locks;
209         } Unlock;
210         struct {
211             FILE_BASIC_INFORMATION binfo;
212             FILE_STANDARD_INFORMATION sinfo;
213             UNICODE_STRING symlink;
214             ULONG access_mask;
215             ULONG access_mode;
216             ULONG attrs;
217             ULONG copts;
218             ULONG disp;
219             ULONG cattrs;
220             LONG open_owner_id;
221             DWORD mode;
222             HANDLE srv_open;
223             DWORD deleg_type;
224             BOOLEAN symlink_embedded;
225             PMDL EaMdl;
226             PVOID EaBuffer;
227         } Open;
228         struct {
229             HANDLE srv_open;
230             BOOLEAN remove;
231             BOOLEAN renamed;
232         } Close;
233         struct {
234             PUNICODE_STRING filter;
235             FILE_INFORMATION_CLASS InfoClass;
236             BOOLEAN restart_scan;
237             BOOLEAN return_single;
238             BOOLEAN initial_query;
239             PMDL mdl;
240             PVOID mdl_buf;
241         } QueryFile;
242         struct {
243             FILE_INFORMATION_CLASS InfoClass;
244         } SetFile;
245         struct {
246             DWORD mode;
247         } SetEa;
248         struct {
249             PVOID EaList;
250             ULONG EaListLength;
251             ULONG Overflow;
252             ULONG EaIndex;
253             BOOLEAN ReturnSingleEntry;
254             BOOLEAN RestartScan;
255         } QueryEa;
256         struct {
257             PUNICODE_STRING target;
258             BOOLEAN set;
259         } Symlink;
260         struct {
261             FS_INFORMATION_CLASS query;
262         } Volume;
263         struct {
264             SECURITY_INFORMATION query;
265         } Acl;
266     } u;
267 
268 } nfs41_updowncall_entry;
269 
270 typedef struct _updowncall_list {
271     LIST_ENTRY head;
272 } nfs41_updowncall_list;
273 nfs41_updowncall_list upcall, downcall;
274 
275 typedef struct _nfs41_mount_entry {
276     LIST_ENTRY next;
277     LUID login_id;
278     HANDLE authsys_session;
279     HANDLE gss_session;
280     HANDLE gssi_session;
281     HANDLE gssp_session;
282 } nfs41_mount_entry;
283 
284 typedef struct _nfs41_mount_list {
285     LIST_ENTRY head;
286 } nfs41_mount_list;
287 
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)             \
295             ? NULL                                          \
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)             \
309              ? NULL                                         \
310              : (nfs41_updowncall_entry *)                   \
311                (CONTAINING_RECORD((list).head.Flink,        \
312                                   nfs41_updowncall_entry,   \
313                                   next)));                  \
314             ExReleaseFastMutex(&lock);
315 #define nfs41_GetFirstMountEntry(lock,list,pEntry)          \
316             ExAcquireFastMutex(&lock);                      \
317             pEntry = (IsListEmpty(&(list).head)             \
318              ? NULL                                         \
319              : (nfs41_mount_entry *)                        \
320                (CONTAINING_RECORD((list).head.Flink,        \
321                                   nfs41_mount_entry,        \
322                                   next)));                  \
323             ExReleaseFastMutex(&lock);
324 
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"");
334 
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 */
341 
342 typedef struct _NFS41_MOUNT_CONFIG {
343     DWORD ReadSize;
344     DWORD WriteSize;
345     BOOLEAN ReadOnly;
346     BOOLEAN write_thru;
347     BOOLEAN nocache;
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;
354     DWORD timeout;
355 } NFS41_MOUNT_CONFIG, *PNFS41_MOUNT_CONFIG;
356 
357 typedef struct _NFS41_NETROOT_EXTENSION {
358     NODE_TYPE_CODE          NodeTypeCode;
359     NODE_BYTE_SIZE          NodeByteSize;
360     DWORD                   nfs41d_version;
361     BOOLEAN                 mounts_init;
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))
368 
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)
373 
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)
378 
379 typedef struct _NFS41_V_NET_ROOT_EXTENSION {
380     NODE_TYPE_CODE          NodeTypeCode;
381     NODE_BYTE_SIZE          NodeByteSize;
382     HANDLE                  session;
383     FILE_FS_ATTRIBUTE_INFORMATION FsAttrs;
384     DWORD                   sec_flavor;
385     DWORD                   timeout;
386     USHORT                  MountPathLen;
387     BOOLEAN                 read_only;
388     BOOLEAN                 write_thru;
389     BOOLEAN                 nocache;
390 #define STORE_MOUNT_SEC_CONTEXT
391 #ifdef STORE_MOUNT_SEC_CONTEXT
392     SECURITY_CLIENT_CONTEXT mount_sec_ctx;
393 #endif
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))
398 
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;
404     BOOLEAN                 Renamed;
405     BOOLEAN                 DeletePending;
406     DWORD                   mode;
407     ULONGLONG               changeattr;
408 } NFS41_FCB, *PNFS41_FCB;
409 #define NFS41GetFcbExtension(pFcb)      \
410         (((pFcb) == NULL) ? NULL : (PNFS41_FCB)((pFcb)->Context))
411 
412 typedef struct _NFS41_FOBX {
413     NODE_TYPE_CODE          NodeTypeCode;
414     NODE_BYTE_SIZE          NodeByteSize;
415 
416     HANDLE nfs41_open_state;
417     SECURITY_CLIENT_CONTEXT sec_ctx;
418     PVOID acl;
419     DWORD acl_len;
420     LARGE_INTEGER time;
421     DWORD deleg_type;
422     BOOLEAN write_thru;
423     BOOLEAN nocache;
424 } NFS41_FOBX, *PNFS41_FOBX;
425 #define NFS41GetFobxExtension(pFobx)  \
426         (((pFobx) == NULL) ? NULL : (PNFS41_FOBX)((pFobx)->Context))
427 
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;
433 
434 typedef struct _NFS41_DEVICE_EXTENSION {
435     NODE_TYPE_CODE          NodeTypeCode;
436     NODE_BYTE_SIZE          NodeByteSize;
437     PRDBSS_DEVICE_OBJECT    DeviceObject;
438     ULONG                   ActiveNodes;
439     HANDLE                  SharedMemorySection;
440     DWORD                   nfs41d_version;
441     BYTE                    VolAttrs[VOL_ATTR_LEN];
442     DWORD                   VolAttrsLen;
443     HANDLE                  openlistHandle;
444 } NFS41_DEVICE_EXTENSION, *PNFS41_DEVICE_EXTENSION;
445 
446 #define NFS41GetDeviceExtension(RxContext,pExt)        \
447         PNFS41_DEVICE_EXTENSION pExt = (PNFS41_DEVICE_EXTENSION) \
448         ((PBYTE)(RxContext->RxDeviceObject) + sizeof(RDBSS_DEVICE_OBJECT))
449 
450 typedef struct _nfs41_fcb_list_entry {
451     LIST_ENTRY next;
452     PMRX_FCB fcb;
453     HANDLE session;
454     PNFS41_FOBX nfs41_fobx;
455     ULONGLONG ChangeTime;
456     BOOLEAN skip;
457 } nfs41_fcb_list_entry;
458 
459 typedef struct _nfs41_fcb_list {
460     LIST_ENTRY head;
461 } nfs41_fcb_list;
462 nfs41_fcb_list openlist;
463 
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);
470 
471 #define RDR_NULL_STATE  0
472 #define RDR_UNLOADED    1
473 #define RDR_UNLOADING   2
474 #define RDR_LOADING     3
475 #define RDR_LOADED      4
476 #define RDR_STOPPED     5
477 #define RDR_STOPPING    6
478 #define RDR_STARTING    7
479 #define RDR_STARTED     8
480 
481 nfs41_init_driver_state nfs41_init_state = NFS41_INIT_DRIVER_STARTABLE;
482 nfs41_start_driver_state nfs41_start_state = NFS41_START_DRIVER_STARTABLE;
483 
484 NTSTATUS map_readwrite_errors(DWORD status);
485 
print_debug_header(PRX_CONTEXT RxContext)486 void print_debug_header(
487     PRX_CONTEXT RxContext)
488 {
489 
490     PIO_STACK_LOCATION IrpSp = RxContext->CurrentIrpSp;
491 
492     if (IrpSp) {
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);
500     } else
501         DbgP("Couldn't print FileObject IrpSp is NULL\n");
502 
503     print_fo_all(1, RxContext);
504     if (RxContext->CurrentIrp)
505         print_irp_flags(0, RxContext->CurrentIrp);
506 }
507 
508 /* convert strings from unicode -> ansi during marshalling to
509  * save space in the upcall buffers and avoid extra copies */
length_as_utf8(PCUNICODE_STRING str)510 INLINE ULONG length_as_utf8(
511     PCUNICODE_STRING str)
512 {
513     ULONG ActualCount = 0;
514     RtlUnicodeToUTF8N(NULL, 0xffff, &ActualCount, str->Buffer, str->Length);
515     return sizeof(str->MaximumLength) + ActualCount + sizeof(UNICODE_NULL);
516 }
517 
marshall_unicode_as_utf8(IN OUT unsigned char ** pos,IN PCUNICODE_STRING str)518 NTSTATUS marshall_unicode_as_utf8(
519     IN OUT unsigned char **pos,
520     IN PCUNICODE_STRING str)
521 {
522     ANSI_STRING ansi;
523     ULONG ActualCount;
524     NTSTATUS status;
525 
526     if (str->Length == 0) {
527         status = STATUS_SUCCESS;
528         ActualCount = 0;
529         ansi.MaximumLength = 1;
530         goto out_copy;
531     }
532 
533     /* query the number of bytes required for the utf8 encoding */
534     status = RtlUnicodeToUTF8N(NULL, 0xffff,
535         &ActualCount, str->Buffer, str->Length);
536     if (status) {
537         print_error("RtlUnicodeToUTF8N('%wZ') failed with 0x%08X\n",
538             str, status);
539         goto out;
540     }
541 
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);
547     if (status) {
548         print_error("RtlUnicodeToUTF8N(%hu, '%wZ', %hu) failed with 0x%08X\n",
549             ansi.MaximumLength, str, str->Length, status);
550         goto out;
551     }
552 
553 out_copy:
554     RtlCopyMemory(*pos, &ansi.MaximumLength, sizeof(ansi.MaximumLength));
555     *pos += sizeof(ansi.MaximumLength);
556     (*pos)[ActualCount] = '\0';
557     *pos += ansi.MaximumLength;
558 out:
559     return status;
560 }
561 
marshal_nfs41_header(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)562 NTSTATUS marshal_nfs41_header(
563     nfs41_updowncall_entry *entry,
564     unsigned char *buf,
565     ULONG buf_len,
566     ULONG *len)
567 {
568     NTSTATUS status = STATUS_SUCCESS;
569     ULONG header_len = 0;
570     unsigned char *tmp = buf;
571 
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;
576         goto out;
577     }
578     else
579         *len = header_len;
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);
590 
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);
597     else
598         status = STATUS_INTERNAL_ERROR;
599 #endif
600 out:
601     return status;
602 }
603 
secflavorop2name(DWORD sec_flavor)604 const char* secflavorop2name(
605     DWORD sec_flavor)
606 {
607     switch(sec_flavor) {
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";
612     }
613 
614     return "UNKNOWN FLAVOR";
615 }
marshal_nfs41_mount(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)616 NTSTATUS marshal_nfs41_mount(
617     nfs41_updowncall_entry *entry,
618     unsigned char *buf,
619     ULONG buf_len,
620     ULONG *len)
621 {
622     NTSTATUS status = STATUS_SUCCESS;
623     ULONG header_len = 0;
624     unsigned char *tmp = buf;
625 
626     status = marshal_nfs41_header(entry, tmp, buf_len, len);
627     if (status) goto out;
628     else tmp += *len;
629 
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;
634         goto out;
635     }
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;
640         goto out;
641     }
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));
651 
652     *len = header_len;
653 
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);
659 #endif
660 out:
661     return status;
662 }
663 
marshal_nfs41_unmount(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)664 NTSTATUS marshal_nfs41_unmount(
665     nfs41_updowncall_entry *entry,
666     unsigned char *buf,
667     ULONG buf_len,
668     ULONG *len)
669 {
670     return marshal_nfs41_header(entry, buf, buf_len, len);
671 }
672 
marshal_nfs41_open(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)673 NTSTATUS marshal_nfs41_open(
674     nfs41_updowncall_entry *entry,
675     unsigned char *buf,
676     ULONG buf_len,
677     ULONG *len)
678 {
679     NTSTATUS status = STATUS_SUCCESS;
680     ULONG header_len = 0;
681     unsigned char *tmp = buf;
682 
683     status = marshal_nfs41_header(entry, tmp, buf_len, len);
684     if (status) goto out;
685     else tmp += *len;
686 
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;
692         goto out;
693     }
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;
717 
718     _SEH2_TRY {
719         if (entry->u.Open.EaMdl) {
720             entry->u.Open.EaBuffer =
721                 MmMapLockedPagesSpecifyCache(entry->u.Open.EaMdl,
722 #ifndef __REACTOS__
723                     UserMode, MmNonCached, NULL, TRUE, NormalPagePriority);
724 #else
725                     UserMode, MmCached, NULL, TRUE, NormalPagePriority);
726 #endif
727             if (entry->u.Open.EaBuffer == NULL) {
728                 print_error("MmMapLockedPagesSpecifyCache failed to map pages\n");
729                 status = STATUS_INSUFFICIENT_RESOURCES;
730                 goto out;
731             }
732         }
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;
736         goto out;
737     } _SEH2_END;
738     RtlCopyMemory(tmp, &entry->u.Open.EaBuffer, sizeof(HANDLE));
739     *len = header_len;
740 
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);
748 #endif
749 out:
750     return status;
751 }
752 
marshal_nfs41_rw(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)753 NTSTATUS marshal_nfs41_rw(
754     nfs41_updowncall_entry *entry,
755     unsigned char *buf,
756     ULONG buf_len,
757     ULONG *len)
758 {
759     NTSTATUS status = STATUS_SUCCESS;
760     ULONG header_len = 0;
761     unsigned char *tmp = buf;
762 
763     status = marshal_nfs41_header(entry, tmp, buf_len, len);
764     if (status) goto out;
765     else tmp += *len;
766 
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;
771         goto out;
772     }
773 
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);
779     _SEH2_TRY {
780         entry->u.ReadWrite.MdlAddress->MdlFlags |= MDL_MAPPING_CAN_FAIL;
781         entry->buf =
782             MmMapLockedPagesSpecifyCache(entry->u.ReadWrite.MdlAddress,
783 #ifndef __REACTOS__
784                 UserMode, MmNonCached, NULL, TRUE, NormalPagePriority);
785 #else
786                 UserMode, MmCached, NULL, TRUE, NormalPagePriority);
787 #endif
788         if (entry->buf == NULL) {
789             print_error("MmMapLockedPagesSpecifyCache failed to map pages\n");
790             status = STATUS_INSUFFICIENT_RESOURCES;
791             goto out;
792         }
793     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
794         NTSTATUS code;
795         code = _SEH2_GetExceptionCode();
796         print_error("Call to MmMapLocked failed due to exception 0x%x\n", code);
797         status = STATUS_ACCESS_DENIED;
798         goto out;
799     } _SEH2_END;
800     RtlCopyMemory(tmp, &entry->buf, sizeof(HANDLE));
801     *len = header_len;
802 
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);
807 #endif
808 out:
809     return status;
810 }
811 
marshal_nfs41_lock(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)812 NTSTATUS marshal_nfs41_lock(
813     nfs41_updowncall_entry *entry,
814     unsigned char *buf,
815     ULONG buf_len,
816     ULONG *len)
817 {
818     NTSTATUS status = STATUS_SUCCESS;
819     ULONG header_len = 0;
820     unsigned char *tmp = buf;
821 
822     status = marshal_nfs41_header(entry, tmp, buf_len, len);
823     if (status) goto out;
824     else tmp += *len;
825 
826     header_len = *len + 2 * sizeof(LONGLONG) + 2 * sizeof(BOOLEAN);
827     if (header_len > buf_len) {
828         status = STATUS_INSUFFICIENT_RESOURCES;
829         goto out;
830     }
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));
838     *len = header_len;
839 
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);
844 #endif
845 out:
846     return status;
847 }
848 
marshal_nfs41_unlock(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)849 NTSTATUS marshal_nfs41_unlock(
850     nfs41_updowncall_entry *entry,
851     unsigned char *buf,
852     ULONG buf_len,
853     ULONG *len)
854 {
855     NTSTATUS status = STATUS_SUCCESS;
856     ULONG header_len = 0;
857     unsigned char *tmp = buf;
858     PLOWIO_LOCK_LIST lock;
859 
860     status = marshal_nfs41_header(entry, tmp, buf_len, len);
861     if (status) goto out;
862     else tmp += *len;
863 
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;
868         goto out;
869     }
870     RtlCopyMemory(tmp, &entry->u.Unlock.count, sizeof(ULONG));
871     tmp += sizeof(ULONG);
872 
873     lock = &entry->u.Unlock.locks;
874     while (lock) {
875         RtlCopyMemory(tmp, &lock->ByteOffset, sizeof(LONGLONG));
876         tmp += sizeof(LONGLONG);
877         RtlCopyMemory(tmp, &lock->Length, sizeof(LONGLONG));
878         tmp += sizeof(LONGLONG);
879         lock = lock->Next;
880     }
881     *len = header_len;
882 
883 #ifdef DEBUG_MARSHAL_DETAIL
884     DbgP("marshal_nfs41_unlock: count=%u\n", entry->u.Unlock.count);
885 #endif
886 out:
887     return status;
888 }
889 
marshal_nfs41_close(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)890 NTSTATUS marshal_nfs41_close(
891     nfs41_updowncall_entry *entry,
892     unsigned char *buf,
893     ULONG buf_len,
894     ULONG *len)
895 {
896     NTSTATUS status = STATUS_SUCCESS;
897     ULONG header_len = 0;
898     unsigned char *tmp = buf;
899 
900     status = marshal_nfs41_header(entry, tmp, buf_len, len);
901     if (status) goto out;
902     else tmp += *len;
903 
904     header_len = *len + sizeof(BOOLEAN) + sizeof(HANDLE);
905     if (entry->u.Close.remove)
906         header_len += length_as_utf8(entry->filename) +
907             sizeof(BOOLEAN);
908 
909     if (header_len > buf_len) {
910         status = STATUS_INSUFFICIENT_RESOURCES;
911         goto out;
912     }
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));
921     }
922     *len = header_len;
923 
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);
928 #endif
929 out:
930     return status;
931 }
932 
marshal_nfs41_dirquery(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)933 NTSTATUS marshal_nfs41_dirquery(
934     nfs41_updowncall_entry *entry,
935     unsigned char *buf,
936     ULONG buf_len,
937     ULONG *len)
938 {
939     NTSTATUS status = STATUS_SUCCESS;
940     ULONG header_len = 0;
941     unsigned char *tmp = buf;
942 
943     status = marshal_nfs41_header(entry, tmp, buf_len, len);
944     if (status) goto out;
945     else tmp += *len;
946 
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;
951         goto out;
952     }
953 
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);
966     _SEH2_TRY {
967         entry->u.QueryFile.mdl_buf =
968             MmMapLockedPagesSpecifyCache(entry->u.QueryFile.mdl,
969 #ifndef __REACTOS__
970                 UserMode, MmNonCached, NULL, TRUE, NormalPagePriority);
971 #else
972                 UserMode, MmCached, NULL, TRUE, NormalPagePriority);
973 #endif
974         if (entry->u.QueryFile.mdl_buf == NULL) {
975             print_error("MmMapLockedPagesSpecifyCache failed to map pages\n");
976             status = STATUS_INSUFFICIENT_RESOURCES;
977             goto out;
978         }
979     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
980         NTSTATUS code;
981         code = _SEH2_GetExceptionCode();
982         print_error("Call to MmMapLocked failed due to exception 0x%x\n", code);
983         status = STATUS_ACCESS_DENIED;
984         goto out;
985     } _SEH2_END;
986     RtlCopyMemory(tmp, &entry->u.QueryFile.mdl_buf, sizeof(HANDLE));
987     *len = header_len;
988 
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);
995 #endif
996 out:
997     return status;
998 }
999 
marshal_nfs41_filequery(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)1000 NTSTATUS marshal_nfs41_filequery(
1001     nfs41_updowncall_entry *entry,
1002     unsigned char *buf,
1003     ULONG buf_len,
1004     ULONG *len)
1005 {
1006     NTSTATUS status = STATUS_SUCCESS;
1007     ULONG header_len = 0;
1008     unsigned char *tmp = buf;
1009 
1010     status = marshal_nfs41_header(entry, tmp, buf_len, len);
1011     if (status) goto out;
1012     else tmp += *len;
1013 
1014     header_len = *len + 2 * sizeof(ULONG);
1015     if (header_len > buf_len) {
1016         status = STATUS_INSUFFICIENT_RESOURCES;
1017         goto out;
1018     }
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));
1026     *len = header_len;
1027 
1028 #ifdef DEBUG_MARSHAL_DETAIL
1029     DbgP("marshal_nfs41_filequery: class=%d\n", entry->u.QueryFile.InfoClass);
1030 #endif
1031 out:
1032     return status;
1033 }
1034 
marshal_nfs41_fileset(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)1035 NTSTATUS marshal_nfs41_fileset(
1036     nfs41_updowncall_entry *entry,
1037     unsigned char *buf,
1038     ULONG buf_len,
1039     ULONG *len)
1040 {
1041     NTSTATUS status = STATUS_SUCCESS;
1042     ULONG header_len = 0;
1043     unsigned char *tmp = buf;
1044 
1045     status = marshal_nfs41_header(entry, tmp, buf_len, len);
1046     if (status) goto out;
1047     else tmp += *len;
1048 
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;
1053         goto out;
1054     }
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);
1062     *len = header_len;
1063 
1064 #ifdef DEBUG_MARSHAL_DETAIL
1065     DbgP("marshal_nfs41_fileset: filename='%wZ' class=%d\n",
1066         entry->filename, entry->u.SetFile.InfoClass);
1067 #endif
1068 out:
1069     return status;
1070 }
1071 
marshal_nfs41_easet(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)1072 NTSTATUS marshal_nfs41_easet(
1073     nfs41_updowncall_entry *entry,
1074     unsigned char *buf,
1075     ULONG buf_len,
1076     ULONG *len)
1077 {
1078     NTSTATUS status = STATUS_SUCCESS;
1079     ULONG header_len = 0;
1080     unsigned char *tmp = buf;
1081 
1082     status = marshal_nfs41_header(entry, tmp, buf_len, len);
1083     if (status) goto out;
1084     else tmp += *len;
1085 
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;
1090         goto out;
1091     }
1092 
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);
1100     *len = header_len;
1101 
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);
1105 #endif
1106 out:
1107     return status;
1108 }
1109 
marshal_nfs41_eaget(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)1110 NTSTATUS marshal_nfs41_eaget(
1111     nfs41_updowncall_entry *entry,
1112     unsigned char *buf,
1113     ULONG buf_len,
1114     ULONG *len)
1115 {
1116     NTSTATUS status = STATUS_SUCCESS;
1117     ULONG header_len = 0;
1118     unsigned char *tmp = buf;
1119 
1120     status = marshal_nfs41_header(entry, tmp, buf_len, len);
1121     if (status) goto out;
1122     else tmp += *len;
1123 
1124     header_len = *len + length_as_utf8(entry->filename) +
1125         3 * sizeof(ULONG) + entry->u.QueryEa.EaListLength + 2 * sizeof(BOOLEAN);
1126 
1127     if (header_len > buf_len) {
1128         status = STATUS_INSUFFICIENT_RESOURCES;
1129         goto out;
1130     }
1131 
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);
1147     *len = header_len;
1148 
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);
1154 #endif
1155 out:
1156     return status;
1157 }
1158 
marshal_nfs41_symlink(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)1159 NTSTATUS marshal_nfs41_symlink(
1160     nfs41_updowncall_entry *entry,
1161     unsigned char *buf,
1162     ULONG buf_len,
1163     ULONG *len)
1164 {
1165     NTSTATUS status = STATUS_SUCCESS;
1166     ULONG header_len = 0;
1167     unsigned char *tmp = buf;
1168 
1169     status = marshal_nfs41_header(entry, tmp, buf_len, len);
1170     if (status) goto out;
1171     else tmp += *len;
1172 
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;
1178         goto out;
1179     }
1180 
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;
1188     }
1189     *len = header_len;
1190 
1191 #ifdef DEBUG_MARSHAL_DETAIL
1192     DbgP("marshal_nfs41_symlink: name %wZ symlink target %wZ\n",
1193          entry->filename,
1194          entry->u.Symlink.set?entry->u.Symlink.target : NULL);
1195 #endif
1196 out:
1197     return status;
1198 }
1199 
marshal_nfs41_volume(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)1200 NTSTATUS marshal_nfs41_volume(
1201     nfs41_updowncall_entry *entry,
1202     unsigned char *buf,
1203     ULONG buf_len,
1204     ULONG *len)
1205 {
1206     NTSTATUS status = STATUS_SUCCESS;
1207     ULONG header_len = 0;
1208     unsigned char *tmp = buf;
1209 
1210     status = marshal_nfs41_header(entry, tmp, buf_len, len);
1211     if (status) goto out;
1212     else tmp += *len;
1213 
1214     header_len = *len + sizeof(FS_INFORMATION_CLASS);
1215     if (header_len > buf_len) {
1216         status = STATUS_INSUFFICIENT_RESOURCES;
1217         goto out;
1218     }
1219 
1220     RtlCopyMemory(tmp, &entry->u.Volume.query, sizeof(FS_INFORMATION_CLASS));
1221     *len = header_len;
1222 
1223 #ifdef DEBUG_MARSHAL_DETAIL
1224     DbgP("marshal_nfs41_volume: class=%d\n", entry->u.Volume.query);
1225 #endif
1226 out:
1227     return status;
1228 }
1229 
marshal_nfs41_getacl(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)1230 NTSTATUS marshal_nfs41_getacl(
1231     nfs41_updowncall_entry *entry,
1232     unsigned char *buf,
1233     ULONG buf_len,
1234     ULONG *len)
1235 {
1236     NTSTATUS status = STATUS_SUCCESS;
1237     ULONG header_len = 0;
1238     unsigned char *tmp = buf;
1239 
1240     status = marshal_nfs41_header(entry, tmp, buf_len, len);
1241     if (status) goto out;
1242     else tmp += *len;
1243 
1244     header_len = *len + sizeof(SECURITY_INFORMATION);
1245     if (header_len > buf_len) {
1246         status = STATUS_INSUFFICIENT_RESOURCES;
1247         goto out;
1248     }
1249 
1250     RtlCopyMemory(tmp, &entry->u.Acl.query, sizeof(SECURITY_INFORMATION));
1251     *len = header_len;
1252 
1253 #ifdef DEBUG_MARSHAL_DETAIL
1254     DbgP("marshal_nfs41_getacl: class=0x%x\n", entry->u.Acl.query);
1255 #endif
1256 out:
1257     return status;
1258 }
1259 
marshal_nfs41_setacl(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)1260 NTSTATUS marshal_nfs41_setacl(
1261     nfs41_updowncall_entry *entry,
1262     unsigned char *buf,
1263     ULONG buf_len,
1264     ULONG *len)
1265 {
1266     NTSTATUS status = STATUS_SUCCESS;
1267     ULONG header_len = 0;
1268     unsigned char *tmp = buf;
1269 
1270     status = marshal_nfs41_header(entry, tmp, buf_len, len);
1271     if (status) goto out;
1272     else tmp += *len;
1273 
1274     header_len = *len + sizeof(SECURITY_INFORMATION) +
1275         sizeof(ULONG) + entry->buf_len;
1276     if (header_len > buf_len) {
1277         status = STATUS_INSUFFICIENT_RESOURCES;
1278         goto out;
1279     }
1280 
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);
1286     *len = header_len;
1287 
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);
1291 #endif
1292 out:
1293     return status;
1294 }
1295 
marshal_nfs41_shutdown(nfs41_updowncall_entry * entry,unsigned char * buf,ULONG buf_len,ULONG * len)1296 NTSTATUS marshal_nfs41_shutdown(
1297     nfs41_updowncall_entry *entry,
1298     unsigned char *buf,
1299     ULONG buf_len,
1300     ULONG *len)
1301 {
1302     return marshal_nfs41_header(entry, buf, buf_len, len);
1303 }
1304 
nfs41_invalidate_cache(IN PRX_CONTEXT RxContext)1305 void nfs41_invalidate_cache (
1306     IN PRX_CONTEXT RxContext)
1307 {
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;
1312 
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);
1317 #endif
1318     if (MmIsAddressValid(srv_open))
1319         RxIndicateChangeOfBufferingStateForSrvOpen(
1320             srv_open->pFcb->pNetRoot->pSrvCall, srv_open,
1321             srv_open->Key, ULongToPtr(flag));
1322 }
1323 
handle_upcall(IN PRX_CONTEXT RxContext,IN nfs41_updowncall_entry * entry,OUT ULONG * len)1324 NTSTATUS handle_upcall(
1325     IN PRX_CONTEXT RxContext,
1326     IN nfs41_updowncall_entry *entry,
1327     OUT ULONG *len)
1328 {
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;
1333 
1334     status = SeImpersonateClientEx(entry->psec_ctx, NULL);
1335     if (status != STATUS_SUCCESS) {
1336         print_error("SeImpersonateClientEx failed %x\n", status);
1337         goto out;
1338     }
1339 
1340     switch(entry->opcode) {
1341     case NFS41_SHUTDOWN:
1342         status = marshal_nfs41_shutdown(entry, pbOut, cbOut, len);
1343         KeSetEvent(&entry->cond, 0, FALSE);
1344         break;
1345     case NFS41_MOUNT:
1346         status = marshal_nfs41_mount(entry, pbOut, cbOut, len);
1347         break;
1348     case NFS41_UNMOUNT:
1349         status = marshal_nfs41_unmount(entry, pbOut, cbOut, len);
1350         break;
1351     case NFS41_OPEN:
1352         status = marshal_nfs41_open(entry, pbOut, cbOut, len);
1353         break;
1354     case NFS41_READ:
1355         status = marshal_nfs41_rw(entry, pbOut, cbOut, len);
1356         break;
1357     case NFS41_WRITE:
1358         status = marshal_nfs41_rw(entry, pbOut, cbOut, len);
1359         break;
1360     case NFS41_LOCK:
1361         status = marshal_nfs41_lock(entry, pbOut, cbOut, len);
1362         break;
1363     case NFS41_UNLOCK:
1364         status = marshal_nfs41_unlock(entry, pbOut, cbOut, len);
1365         break;
1366     case NFS41_CLOSE:
1367         status = marshal_nfs41_close(entry, pbOut, cbOut, len);
1368         break;
1369     case NFS41_DIR_QUERY:
1370         status = marshal_nfs41_dirquery(entry, pbOut, cbOut, len);
1371         break;
1372     case NFS41_FILE_QUERY:
1373         status = marshal_nfs41_filequery(entry, pbOut, cbOut, len);
1374         break;
1375     case NFS41_FILE_SET:
1376         status = marshal_nfs41_fileset(entry, pbOut, cbOut, len);
1377         break;
1378     case NFS41_EA_SET:
1379         status = marshal_nfs41_easet(entry, pbOut, cbOut, len);
1380         break;
1381     case NFS41_EA_GET:
1382         status = marshal_nfs41_eaget(entry, pbOut, cbOut, len);
1383         break;
1384     case NFS41_SYMLINK:
1385         status = marshal_nfs41_symlink(entry, pbOut, cbOut, len);
1386         break;
1387     case NFS41_VOLUME_QUERY:
1388         status = marshal_nfs41_volume(entry, pbOut, cbOut, len);
1389         break;
1390     case NFS41_ACL_QUERY:
1391         status = marshal_nfs41_getacl(entry, pbOut, cbOut, len);
1392         break;
1393     case NFS41_ACL_SET:
1394         status = marshal_nfs41_setacl(entry, pbOut, cbOut, len);
1395         break;
1396     default:
1397         status = STATUS_INVALID_PARAMETER;
1398         print_error("Unknown nfs41 ops %d\n", entry->opcode);
1399     }
1400 
1401     if (status == STATUS_SUCCESS)
1402         print_hexbuf(0, (unsigned char *)"upcall buffer", pbOut, *len);
1403 
1404 out:
1405     return status;
1406 }
1407 
nfs41_UpcallCreate(IN DWORD opcode,IN PSECURITY_CLIENT_CONTEXT clnt_sec_ctx,IN HANDLE session,IN HANDLE open_state,IN DWORD version,IN PUNICODE_STRING filename,OUT nfs41_updowncall_entry ** entry_out)1408 NTSTATUS nfs41_UpcallCreate(
1409     IN DWORD opcode,
1410     IN PSECURITY_CLIENT_CONTEXT clnt_sec_ctx,
1411     IN HANDLE session,
1412     IN HANDLE open_state,
1413     IN DWORD version,
1414     IN PUNICODE_STRING filename,
1415     OUT nfs41_updowncall_entry **entry_out)
1416 {
1417     NTSTATUS status = STATUS_SUCCESS;
1418     nfs41_updowncall_entry *entry;
1419     SECURITY_SUBJECT_CONTEXT sec_ctx;
1420     SECURITY_QUALITY_OF_SERVICE sec_qos;
1421 
1422     entry = RxAllocatePoolWithTag(NonPagedPool, sizeof(nfs41_updowncall_entry),
1423                 NFS41_MM_POOLTAG_UP);
1424     if (entry == NULL) {
1425         status = STATUS_INSUFFICIENT_RESOURCES;
1426         goto out;
1427     }
1428 
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);
1443 
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",
1455                 status);
1456             RxFreePool(entry);
1457         } else
1458             entry->psec_ctx = &entry->sec_ctx;
1459         SeReleaseSubjectContext(&sec_ctx);
1460     } else
1461         entry->psec_ctx = clnt_sec_ctx;
1462 
1463     *entry_out = entry;
1464 out:
1465     return status;
1466 }
1467 
nfs41_UpcallWaitForReply(IN nfs41_updowncall_entry * entry,IN DWORD secs)1468 NTSTATUS nfs41_UpcallWaitForReply(
1469     IN nfs41_updowncall_entry *entry,
1470     IN DWORD secs)
1471 {
1472     NTSTATUS status = STATUS_SUCCESS;
1473 
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
1486          */
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);
1495         else {
1496             status = KeWaitForSingleObject(&entry->cond, Executive,
1497                         UserMode, TRUE, &timeout);
1498         }
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;
1504         }
1505 #else
1506 
1507         status = KeWaitForSingleObject(&entry->cond, Executive, KernelMode, FALSE, NULL);
1508 #endif
1509         print_wait_status(0, "[downcall]", status, opcode2string(entry->opcode),
1510             entry, entry->xid);
1511     } else
1512         goto out;
1513 
1514     switch(status) {
1515     case STATUS_SUCCESS: break;
1516     case STATUS_USER_APC:
1517     case STATUS_ALERTED:
1518     default:
1519         ExAcquireFastMutex(&entry->lock);
1520         if (entry->state == NFS41_DONE_PROCESSING) {
1521             ExReleaseFastMutex(&entry->lock);
1522             break;
1523         }
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);
1528         goto out;
1529     }
1530     nfs41_RemoveEntry(downcallLock, entry);
1531 out:
1532     return status;
1533 }
1534 
nfs41_upcall(IN PRX_CONTEXT RxContext)1535 NTSTATUS nfs41_upcall(
1536     IN PRX_CONTEXT RxContext)
1537 {
1538     NTSTATUS status = STATUS_SUCCESS;
1539     nfs41_updowncall_entry *entry = NULL;
1540     ULONG len = 0;
1541     PLIST_ENTRY pEntry;
1542 
1543 process_upcall:
1544     nfs41_RemoveFirst(upcallLock, upcall, pEntry);
1545     if (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);
1555         if (status) {
1556             entry->status = status;
1557             KeSetEvent(&entry->cond, 0, FALSE);
1558             RxContext->InformationToReturn = 0;
1559         } else
1560             RxContext->InformationToReturn = len;
1561     }
1562     else {
1563         status = KeWaitForSingleObject(&upcallEvent, Executive, UserMode, TRUE,
1564             (PLARGE_INTEGER) NULL);
1565         print_wait_status(0, "[upcall]", status, NULL, NULL, 0);
1566         switch (status) {
1567         case STATUS_SUCCESS: goto process_upcall;
1568         case STATUS_USER_APC:
1569         case STATUS_ALERTED:
1570         default: goto out;
1571         }
1572     }
1573 out:
1574     return status;
1575 }
1576 
unmarshal_nfs41_header(nfs41_updowncall_entry * tmp,unsigned char ** buf)1577 void unmarshal_nfs41_header(
1578     nfs41_updowncall_entry *tmp,
1579     unsigned char **buf)
1580 {
1581     RtlZeroMemory(tmp, sizeof(nfs41_updowncall_entry));
1582 
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);
1594 #endif
1595 }
1596 
unmarshal_nfs41_mount(nfs41_updowncall_entry * cur,unsigned char ** buf)1597 void unmarshal_nfs41_mount(
1598     nfs41_updowncall_entry *cur,
1599     unsigned char **buf)
1600 {
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);
1611 #endif
1612 }
1613 
unmarshal_nfs41_setattr(nfs41_updowncall_entry * cur,PULONGLONG dest_buf,unsigned char ** buf)1614 VOID unmarshal_nfs41_setattr(
1615     nfs41_updowncall_entry *cur,
1616     PULONGLONG dest_buf,
1617     unsigned char **buf)
1618 {
1619     RtlCopyMemory(dest_buf, *buf, sizeof(ULONGLONG));
1620 #ifdef DEBUG_MARSHAL_DETAIL
1621     DbgP("unmarshal_nfs41_setattr: returned ChangeTime %llu\n", *dest_buf);
1622 #endif
1623 }
1624 
unmarshal_nfs41_rw(nfs41_updowncall_entry * cur,unsigned char ** buf)1625 NTSTATUS unmarshal_nfs41_rw(
1626     nfs41_updowncall_entry *cur,
1627     unsigned char **buf)
1628 {
1629     NTSTATUS status = STATUS_SUCCESS;
1630 
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);
1637 #endif
1638 #if 1
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.
1643         */
1644     _SEH2_TRY {
1645         MmUnmapLockedPages(cur->buf, cur->u.ReadWrite.MdlAddress);
1646     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
1647         NTSTATUS code;
1648         code = _SEH2_GetExceptionCode();
1649         print_error("Call to MmUnmapLockedPages failed due to"
1650             " exception 0x%0x\n", code);
1651         status = STATUS_ACCESS_DENIED;
1652     } _SEH2_END;
1653 #endif
1654     return status;
1655 }
1656 
unmarshal_nfs41_open(nfs41_updowncall_entry * cur,unsigned char ** buf)1657 NTSTATUS unmarshal_nfs41_open(
1658     nfs41_updowncall_entry *cur,
1659     unsigned char **buf)
1660 {
1661     NTSTATUS status = STATUS_SUCCESS;
1662 
1663     _SEH2_TRY {
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;
1669         goto out;
1670     } _SEH2_END;
1671 
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,
1688             sizeof(USHORT));
1689         *buf += sizeof(USHORT);
1690         cur->u.Open.symlink.Length = cur->u.Open.symlink.MaximumLength -
1691             sizeof(WCHAR);
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;
1697             goto out;
1698         }
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);
1703 #endif
1704     }
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);
1709 #endif
1710 out:
1711     return status;
1712 }
1713 
unmarshal_nfs41_dirquery(nfs41_updowncall_entry * cur,unsigned char ** buf)1714 NTSTATUS unmarshal_nfs41_dirquery(
1715     nfs41_updowncall_entry *cur,
1716     unsigned char **buf)
1717 {
1718     NTSTATUS status = STATUS_SUCCESS;
1719     ULONG buf_len;
1720 
1721     RtlCopyMemory(&buf_len, *buf, sizeof(ULONG));
1722 #ifdef DEBUG_MARSHAL_DETAIL
1723     DbgP("unmarshal_nfs41_dirquery: reply size %d\n", buf_len);
1724 #endif
1725     *buf += sizeof(ULONG);
1726     _SEH2_TRY {
1727         MmUnmapLockedPages(cur->u.QueryFile.mdl_buf, cur->u.QueryFile.mdl);
1728     } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
1729         NTSTATUS code;
1730         code = _SEH2_GetExceptionCode();
1731         print_error("MmUnmapLockedPages thrown exception=0x%0x\n", code);
1732         status = STATUS_ACCESS_DENIED;
1733     } _SEH2_END;
1734     if (buf_len > cur->buf_len)
1735         cur->status = STATUS_BUFFER_TOO_SMALL;
1736     cur->buf_len = buf_len;
1737 
1738     return status;
1739 }
1740 
unmarshal_nfs41_attrget(nfs41_updowncall_entry * cur,PVOID attr_value,ULONG * attr_len,unsigned char ** buf)1741 void unmarshal_nfs41_attrget(
1742     nfs41_updowncall_entry *cur,
1743     PVOID attr_value,
1744     ULONG *attr_len,
1745     unsigned char **buf)
1746 {
1747     ULONG buf_len;
1748     RtlCopyMemory(&buf_len, *buf, sizeof(ULONG));
1749     if (buf_len > *attr_len) {
1750         cur->status = STATUS_BUFFER_TOO_SMALL;
1751         return;
1752     }
1753     *buf += sizeof(ULONG);
1754     *attr_len = buf_len;
1755     RtlCopyMemory(attr_value, *buf, buf_len);
1756     *buf += buf_len;
1757 }
1758 
unmarshal_nfs41_eaget(nfs41_updowncall_entry * cur,unsigned char ** buf)1759 void unmarshal_nfs41_eaget(
1760     nfs41_updowncall_entry *cur,
1761     unsigned char **buf)
1762 {
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;
1770     }
1771 }
1772 
unmarshal_nfs41_getattr(nfs41_updowncall_entry * cur,unsigned char ** buf)1773 void unmarshal_nfs41_getattr(
1774     nfs41_updowncall_entry *cur,
1775     unsigned char **buf)
1776 {
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);
1782 #endif
1783 }
1784 
unmarshal_nfs41_getacl(nfs41_updowncall_entry * cur,unsigned char ** buf)1785 NTSTATUS unmarshal_nfs41_getacl(
1786     nfs41_updowncall_entry *cur,
1787     unsigned char **buf)
1788 {
1789     NTSTATUS status = STATUS_SUCCESS;
1790     DWORD buf_len;
1791 
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;
1798         goto out;
1799     }
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;
1804 
1805 out:
1806     return status;
1807 }
1808 
unmarshal_nfs41_symlink(nfs41_updowncall_entry * cur,unsigned char ** buf)1809 void unmarshal_nfs41_symlink(
1810     nfs41_updowncall_entry *cur,
1811     unsigned char **buf)
1812 {
1813     if (cur->u.Symlink.set) return;
1814 
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;
1820         return;
1821     }
1822     RtlCopyMemory(cur->u.Symlink.target->Buffer, *buf,
1823         cur->u.Symlink.target->Length);
1824     cur->u.Symlink.target->Length -= sizeof(UNICODE_NULL);
1825 }
1826 
nfs41_downcall(IN PRX_CONTEXT RxContext)1827 NTSTATUS nfs41_downcall(
1828     IN PRX_CONTEXT RxContext)
1829 {
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;
1834     PLIST_ENTRY pEntry;
1835     nfs41_updowncall_entry *tmp, *cur= NULL;
1836     BOOLEAN found = 0;
1837 
1838     print_hexbuf(0, (unsigned char *)"downcall buffer", buf, in_len);
1839 
1840     tmp = RxAllocatePoolWithTag(NonPagedPool, sizeof(nfs41_updowncall_entry),
1841             NFS41_MM_POOLTAG_DOWN);
1842     if (tmp == NULL) goto out;
1843 
1844     unmarshal_nfs41_header(tmp, &buf);
1845 
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) {
1853             found = 1;
1854             break;
1855         }
1856         if (pEntry->Flink == &downcall.head)
1857             break;
1858         pEntry = pEntry->Flink;
1859     }
1860     ExReleaseFastMutex(&downcallLock);
1861     SeStopImpersonatingClient();
1862     if (!found) {
1863         print_error("Didn't find xid=%lld entry\n", tmp->xid);
1864         goto out_free;
1865     }
1866 
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) {
1871         case NFS41_WRITE:
1872         case NFS41_READ:
1873             MmUnmapLockedPages(cur->buf, cur->u.ReadWrite.MdlAddress);
1874             break;
1875         case NFS41_DIR_QUERY:
1876             MmUnmapLockedPages(cur->u.QueryFile.mdl_buf,
1877                     cur->u.QueryFile.mdl);
1878             IoFreeMdl(cur->u.QueryFile.mdl);
1879             break;
1880         case NFS41_OPEN:
1881             if (cur->u.Open.EaMdl) {
1882                 MmUnmapLockedPages(cur->u.Open.EaBuffer,
1883                         cur->u.Open.EaMdl);
1884                 IoFreeMdl(cur->u.Open.EaMdl);
1885             }
1886             break;
1887         }
1888         ExReleaseFastMutex(&cur->lock);
1889         nfs41_RemoveEntry(downcallLock, cur);
1890         RxFreePool(cur);
1891         status = STATUS_UNSUCCESSFUL;
1892         goto out_free;
1893     }
1894     cur->state = NFS41_DONE_PROCESSING;
1895     cur->status = tmp->status;
1896     cur->errno = tmp->errno;
1897     status = STATUS_SUCCESS;
1898 
1899     if (!tmp->status) {
1900         switch (tmp->opcode) {
1901         case NFS41_MOUNT:
1902             unmarshal_nfs41_mount(cur, &buf);
1903             break;
1904         case NFS41_WRITE:
1905         case NFS41_READ:
1906             status = unmarshal_nfs41_rw(cur, &buf);
1907             break;
1908         case NFS41_OPEN:
1909             status = unmarshal_nfs41_open(cur, &buf);
1910             break;
1911         case NFS41_DIR_QUERY:
1912             status = unmarshal_nfs41_dirquery(cur, &buf);
1913             break;
1914         case NFS41_FILE_QUERY:
1915             unmarshal_nfs41_getattr(cur, &buf);
1916             break;
1917         case NFS41_EA_GET:
1918             unmarshal_nfs41_eaget(cur, &buf);
1919             break;
1920         case NFS41_SYMLINK:
1921             unmarshal_nfs41_symlink(cur, &buf);
1922             break;
1923         case NFS41_VOLUME_QUERY:
1924             unmarshal_nfs41_attrget(cur, cur->buf, &cur->buf_len, &buf);
1925             break;
1926         case NFS41_ACL_QUERY:
1927             status = unmarshal_nfs41_getacl(cur, &buf);
1928             break;
1929         case NFS41_FILE_SET:
1930             unmarshal_nfs41_setattr(cur, &cur->ChangeTime, &buf);
1931             break;
1932         case NFS41_EA_SET:
1933             unmarshal_nfs41_setattr(cur, &cur->ChangeTime, &buf);
1934             break;
1935         case NFS41_ACL_SET:
1936             unmarshal_nfs41_setattr(cur, &cur->ChangeTime, &buf);
1937             break;
1938         }
1939     }
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 =
1945                 cur->buf_len;
1946         } else {
1947             cur->u.ReadWrite.rxcontext->StoredStatus =
1948                 map_readwrite_errors(cur->status);
1949             cur->u.ReadWrite.rxcontext->InformationToReturn = 0;
1950         }
1951         nfs41_RemoveEntry(downcallLock, cur);
1952         RxLowIoCompletion(cur->u.ReadWrite.rxcontext);
1953         RxFreePool(cur);
1954     } else
1955         KeSetEvent(&cur->cond, 0, FALSE);
1956 
1957 out_free:
1958     RxFreePool(tmp);
1959 out:
1960     return status;
1961 }
1962 
nfs41_shutdown_daemon(DWORD version)1963 NTSTATUS nfs41_shutdown_daemon(
1964     DWORD version)
1965 {
1966     NTSTATUS status = STATUS_SUCCESS;
1967     nfs41_updowncall_entry *entry = NULL;
1968 
1969     DbgEn();
1970     status = nfs41_UpcallCreate(NFS41_SHUTDOWN, NULL, INVALID_HANDLE_VALUE,
1971         INVALID_HANDLE_VALUE, version, NULL, &entry);
1972     if (status) goto out;
1973 
1974     status = nfs41_UpcallWaitForReply(entry, UPCALL_TIMEOUT_DEFAULT);
1975     SeDeleteClientSecurity(&entry->sec_ctx);
1976     if (status) goto out;
1977 
1978     RxFreePool(entry);
1979 out:
1980     DbgEx();
1981     return status;
1982 }
1983 
SharedMemoryInit(OUT PHANDLE phSection)1984 NTSTATUS SharedMemoryInit(
1985     OUT PHANDLE phSection)
1986 {
1987     NTSTATUS status;
1988     HANDLE hSection;
1989     UNICODE_STRING SectionName;
1990     SECURITY_DESCRIPTOR SecurityDesc;
1991     OBJECT_ATTRIBUTES SectionAttrs;
1992     LARGE_INTEGER nSectionSize;
1993 
1994     DbgEn();
1995 
1996     RtlInitUnicodeString(&SectionName, NFS41_SHARED_MEMORY_NAME);
1997 
1998     /* XXX: setting dacl=NULL grants access to everyone */
1999     status = RtlCreateSecurityDescriptor(&SecurityDesc,
2000         SECURITY_DESCRIPTOR_REVISION);
2001     if (status) {
2002         print_error("RtlCreateSecurityDescriptor() failed with %08X\n", status);
2003         goto out;
2004     }
2005     status = RtlSetDaclSecurityDescriptor(&SecurityDesc, TRUE, NULL, FALSE);
2006     if (status) {
2007         print_error("RtlSetDaclSecurityDescriptor() failed with %08X\n", status);
2008         goto out;
2009     }
2010 
2011     InitializeObjectAttributes(&SectionAttrs, &SectionName,
2012         0, NULL, &SecurityDesc);
2013 
2014     nSectionSize.QuadPart = sizeof(NFS41NP_SHARED_MEMORY);
2015 
2016     status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE,
2017         &SectionAttrs, &nSectionSize, PAGE_READWRITE, SEC_COMMIT, NULL);
2018     switch (status) {
2019     case STATUS_SUCCESS:
2020         break;
2021     case STATUS_OBJECT_NAME_COLLISION:
2022         DbgP("section already created; returning success\n");
2023         status = STATUS_SUCCESS;
2024         goto out;
2025     default:
2026         DbgP("ZwCreateSection failed with %08X\n", status);
2027         goto out;
2028     }
2029 out:
2030     DbgEx();
2031     return status;
2032 }
2033 
SharedMemoryFree(IN HANDLE hSection)2034 NTSTATUS SharedMemoryFree(
2035     IN HANDLE hSection)
2036 {
2037     NTSTATUS status;
2038     DbgEn();
2039     status = ZwClose(hSection);
2040     DbgEx();
2041     return status;
2042 }
2043 
2044 #ifdef __REACTOS__
nfs41_Start(IN OUT PRX_CONTEXT RxContext,IN OUT PRDBSS_DEVICE_OBJECT dev)2045 NTSTATUS NTAPI nfs41_Start(
2046 #else
2047 NTSTATUS nfs41_Start(
2048 #endif
2049     IN OUT PRX_CONTEXT RxContext,
2050     IN OUT PRDBSS_DEVICE_OBJECT dev)
2051 {
2052     NTSTATUS status;
2053     NFS41GetDeviceExtension(RxContext, DevExt);
2054 
2055     DbgEn();
2056 
2057     status = SharedMemoryInit(&DevExt->SharedMemorySection);
2058     if (status) {
2059         print_error("InitSharedMemory failed with %08X\n", status);
2060         status = STATUS_INSUFFICIENT_RESOURCES;
2061         goto out;
2062     }
2063 
2064     InterlockedCompareExchange((PLONG)&nfs41_start_state,
2065         NFS41_START_DRIVER_STARTED,
2066         NFS41_START_DRIVER_START_IN_PROGRESS);
2067 out:
2068     DbgEx();
2069     return status;
2070 }
2071 
2072 #ifdef __REACTOS__
nfs41_Stop(IN OUT PRX_CONTEXT RxContext,IN OUT PRDBSS_DEVICE_OBJECT dev)2073 NTSTATUS NTAPI nfs41_Stop(
2074 #else
2075 NTSTATUS nfs41_Stop(
2076 #endif
2077     IN OUT PRX_CONTEXT RxContext,
2078     IN OUT PRDBSS_DEVICE_OBJECT dev)
2079 {
2080     NTSTATUS status;
2081     NFS41GetDeviceExtension(RxContext, DevExt);
2082     DbgEn();
2083     status = SharedMemoryFree(DevExt->SharedMemorySection);
2084     DbgEx();
2085     return status;
2086 }
2087 
GetConnectionHandle(IN PUNICODE_STRING ConnectionName,IN PVOID EaBuffer,IN ULONG EaLength,OUT PHANDLE Handle)2088 NTSTATUS GetConnectionHandle(
2089     IN PUNICODE_STRING ConnectionName,
2090     IN PVOID EaBuffer,
2091     IN ULONG EaLength,
2092     OUT PHANDLE Handle)
2093 {
2094     NTSTATUS status;
2095     IO_STATUS_BLOCK IoStatusBlock;
2096     OBJECT_ATTRIBUTES ObjectAttributes;
2097 
2098 #ifdef DEBUG_MOUNT
2099     DbgEn();
2100 #endif
2101     InitializeObjectAttributes(&ObjectAttributes, ConnectionName,
2102         OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
2103 
2104     print_error("Len %d Buf %p\n", EaLength, EaBuffer);
2105 
2106     status = ZwCreateFile(Handle, SYNCHRONIZE, &ObjectAttributes,
2107         &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL,
2108         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2109         FILE_OPEN_IF,
2110         FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT,
2111         EaBuffer, EaLength);
2112 
2113 #ifdef DEBUG_MOUNT
2114     DbgEx();
2115 #endif
2116     return status;
2117 }
2118 
nfs41_GetConnectionInfoFromBuffer(IN PVOID Buffer,IN ULONG BufferLen,OUT PUNICODE_STRING pConnectionName,OUT PVOID * ppEaBuffer,OUT PULONG pEaLength)2119 NTSTATUS nfs41_GetConnectionInfoFromBuffer(
2120     IN PVOID Buffer,
2121     IN ULONG BufferLen,
2122     OUT PUNICODE_STRING pConnectionName,
2123     OUT PVOID *ppEaBuffer,
2124     OUT PULONG pEaLength)
2125 {
2126     NTSTATUS status = STATUS_SUCCESS;
2127     USHORT NameLength, EaPadding;
2128     ULONG EaLength, BufferLenExpected;
2129     PBYTE ptr;
2130 
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;
2136         *ppEaBuffer = NULL;
2137         *pEaLength = 0;
2138         goto out;
2139     }
2140 
2141     ptr = Buffer;
2142     NameLength = *(PUSHORT)ptr;
2143     ptr += sizeof(USHORT);
2144     EaPadding = *(PUSHORT)ptr;
2145     ptr += sizeof(USHORT);
2146     EaLength = *(PULONG)ptr;
2147     ptr += sizeof(ULONG);
2148 
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;
2157         *ppEaBuffer = NULL;
2158         *pEaLength = 0;
2159         goto out;
2160     }
2161 
2162     pConnectionName->Buffer = (PWCH)ptr;
2163     pConnectionName->Length = NameLength - sizeof(WCHAR);
2164     pConnectionName->MaximumLength = NameLength;
2165 
2166     if (EaLength)
2167         *ppEaBuffer = ptr + NameLength + EaPadding;
2168     else
2169         *ppEaBuffer = NULL;
2170     *pEaLength = EaLength;
2171 
2172 out:
2173     return status;
2174 }
2175 
nfs41_CreateConnection(IN PRX_CONTEXT RxContext,OUT PBOOLEAN PostToFsp)2176 NTSTATUS nfs41_CreateConnection(
2177     IN PRX_CONTEXT RxContext,
2178     OUT PBOOLEAN PostToFsp)
2179 {
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);
2187 
2188 #ifdef DEBUG_MOUNT
2189     DbgEn();
2190 #endif
2191 
2192     if (!Wait) {
2193         //just post right now!
2194         DbgP("returning STATUS_PENDING\n");
2195         *PostToFsp = TRUE;
2196         status = STATUS_PENDING;
2197         goto out;
2198     }
2199 
2200     status = nfs41_GetConnectionInfoFromBuffer(Buffer, BufferLen,
2201         &FileName, &EaBuffer, &EaLength);
2202     if (status != STATUS_SUCCESS)
2203         goto out;
2204 
2205     status = GetConnectionHandle(&FileName, EaBuffer, EaLength, &Handle);
2206     if (!status && Handle != INVALID_HANDLE_VALUE)
2207         ZwClose(Handle);
2208 out:
2209 #ifdef DEBUG_MOUNT
2210     DbgEx();
2211 #endif
2212     return status;
2213 }
2214 
2215 #ifdef ENABLE_TIMINGS
print_op_stat(const char * op_str,nfs41_timings * time,BOOLEAN clear)2216 void print_op_stat(
2217     const char *op_str,
2218     nfs41_timings *time, BOOLEAN clear)
2219 {
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);
2223     if (clear) {
2224         time->tops = 0;
2225         time->ticks = 0;
2226         time->size = 0;
2227         time->sops = 0;
2228     }
2229 }
2230 #endif
nfs41_unmount(HANDLE session,DWORD version,DWORD timeout)2231 NTSTATUS nfs41_unmount(
2232     HANDLE session,
2233     DWORD version,
2234     DWORD timeout)
2235 {
2236     NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
2237     nfs41_updowncall_entry *entry;
2238 
2239 #ifdef DEBUG_MOUNT
2240     DbgEn();
2241 #endif
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;
2246 
2247     nfs41_UpcallWaitForReply(entry, timeout);
2248     RxFreePool(entry);
2249 out:
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);
2266 #endif
2267 #ifdef DEBUG_MOUNT
2268     DbgEx();
2269 #endif
2270     return status;
2271 }
2272 
nfs41_DeleteConnection(IN PRX_CONTEXT RxContext,OUT PBOOLEAN PostToFsp)2273 NTSTATUS nfs41_DeleteConnection (
2274     IN PRX_CONTEXT RxContext,
2275     OUT PBOOLEAN PostToFsp)
2276 {
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;
2281     HANDLE Handle;
2282     UNICODE_STRING FileName;
2283     PFILE_OBJECT pFileObject;
2284     BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
2285 
2286 #ifdef DEBUG_MOUNT
2287     DbgEn();
2288 #endif
2289 
2290     if (!Wait) {
2291         //just post right now!
2292         *PostToFsp = TRUE;
2293         DbgP("returning STATUS_PENDING\n");
2294         status = STATUS_PENDING;
2295         goto out;
2296     }
2297 
2298     FileName.Buffer = ConnectName;
2299     FileName.Length = (USHORT) ConnectNameLen - sizeof(WCHAR);
2300     FileName.MaximumLength = (USHORT) ConnectNameLen;
2301 
2302     status = GetConnectionHandle(&FileName, NULL, 0, &Handle);
2303     if (status != STATUS_SUCCESS)
2304         goto out;
2305 
2306     status = ObReferenceObjectByHandle(Handle, 0L, NULL, KernelMode,
2307                 (PVOID *)&pFileObject, NULL);
2308     if (NT_SUCCESS(status)) {
2309         PV_NET_ROOT VNetRoot;
2310 
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)
2315         {
2316 #ifdef DEBUG_MOUNT
2317             DbgP("Calling RxFinalizeConnection for NetRoot %p from VNetRoot %p\n",
2318                 VNetRoot->NetRoot, VNetRoot);
2319 #endif
2320             status = RxFinalizeConnection(VNetRoot->NetRoot, VNetRoot, TRUE);
2321         }
2322         else
2323             status = STATUS_BAD_NETWORK_NAME;
2324 
2325         ObDereferenceObject(pFileObject);
2326     }
2327     ZwClose(Handle);
2328 out:
2329 #ifdef DEBUG_MOUNT
2330     DbgEx();
2331 #endif
2332     return status;
2333 }
2334 
2335 #ifdef __REACTOS__
nfs41_DevFcbXXXControlFile(IN OUT PRX_CONTEXT RxContext)2336 NTSTATUS NTAPI nfs41_DevFcbXXXControlFile(
2337 #else
2338 NTSTATUS nfs41_DevFcbXXXControlFile(
2339 #endif
2340     IN OUT PRX_CONTEXT RxContext)
2341 {
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;
2350 
2351     //DbgEn();
2352 
2353     print_ioctl(0, op);
2354     switch(op) {
2355     case IRP_MJ_FILE_SYSTEM_CONTROL:
2356         status = STATUS_INVALID_DEVICE_REQUEST;
2357         break;
2358     case IRP_MJ_DEVICE_CONTROL:
2359     case IRP_MJ_INTERNAL_DEVICE_CONTROL:
2360         print_fs_ioctl(0, fsop);
2361         switch (fsop) {
2362         case IOCTL_NFS41_INVALCACHE:
2363             nfs41_invalidate_cache(RxContext);
2364             status = STATUS_SUCCESS;
2365             break;
2366         case IOCTL_NFS41_READ:
2367             status = nfs41_upcall(RxContext);
2368             break;
2369         case IOCTL_NFS41_WRITE:
2370             status = nfs41_downcall(RxContext);
2371             break;
2372         case IOCTL_NFS41_ADDCONN:
2373             status = nfs41_CreateConnection(RxContext, &RxContext->PostRequest);
2374             break;
2375         case IOCTL_NFS41_DELCONN:
2376             if (RxContext->RxDeviceObject->NumberOfActiveFcbs > 0) {
2377                 DbgP("device has open handles %d\n",
2378                     RxContext->RxDeviceObject->NumberOfActiveFcbs);
2379 #ifdef __REACTOS__
2380                 if (RxContext->RxDeviceObject->pRxNetNameTable != NULL)
2381                 {
2382 #define DUMP_FCB_TABLE_FROM_NETROOT(N)                                               \
2383 {                                                                                    \
2384     USHORT Bucket2;                                                                  \
2385     BOOLEAN Release2 = FALSE;                                                        \
2386     if (!RxIsFcbTableLockAcquired(&(N)->FcbTable))                                   \
2387     {                                                                                \
2388         RxAcquireFcbTableLockExclusive(&(N)->FcbTable, TRUE);                        \
2389         Release2 = TRUE;                                                             \
2390     }                                                                                \
2391     for (Bucket2 = 0; Bucket2 < (N)->FcbTable.NumberOfBuckets; ++Bucket2)            \
2392     {                                                                                \
2393         PLIST_ENTRY Entry2;                                                          \
2394         for (Entry2 = (N)->FcbTable.HashBuckets[Bucket2].Flink;                      \
2395              Entry2 != &(N)->FcbTable.HashBuckets[Bucket2];                          \
2396              Entry2 = Entry2->Flink)                                                 \
2397         {                                                                            \
2398             PFCB Fcb;                                                                \
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);                      \
2402         }                                                                            \
2403     }                                                                                \
2404     if (Release2)                                                                    \
2405     {                                                                                \
2406         RxReleaseFcbTableLock(&(N)->FcbTable);                                       \
2407     }                                                                                \
2408 }
2409                     USHORT Bucket;
2410                     BOOLEAN Release = FALSE;
2411 
2412                     if (!RxIsPrefixTableLockAcquired(RxContext->RxDeviceObject->pRxNetNameTable))
2413                     {
2414                         RxAcquirePrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable, TRUE);
2415                         Release = TRUE;
2416                     }
2417 
2418                     for (Bucket = 0; Bucket < RxContext->RxDeviceObject->pRxNetNameTable->TableSize; ++Bucket)
2419                     {
2420                         PLIST_ENTRY Entry;
2421 
2422                         for (Entry = RxContext->RxDeviceObject->pRxNetNameTable->HashBuckets[Bucket].Flink;
2423                              Entry != &RxContext->RxDeviceObject->pRxNetNameTable->HashBuckets[Bucket];
2424                              Entry = Entry->Flink)
2425                         {
2426                             PVOID Container;
2427 
2428                             Container = CONTAINING_RECORD(Entry, RX_PREFIX_ENTRY, HashLinks)->ContainingRecord;
2429                             switch (NodeType(Container) & ~RX_SCAVENGER_MASK)
2430                             {
2431                                 case RDBSS_NTC_NETROOT:
2432                                 {
2433                                     PNET_ROOT NetRoot;
2434 
2435                                     NetRoot = Container;
2436                                     DUMP_FCB_TABLE_FROM_NETROOT(NetRoot);
2437                                     break;
2438                                 }
2439 
2440                                 case RDBSS_NTC_V_NETROOT:
2441                                 {
2442                                     PV_NET_ROOT VNetRoot;
2443 
2444                                     VNetRoot = Container;
2445                                     if (VNetRoot->NetRoot != NULL)
2446                                     {
2447                                         PNET_ROOT NetRoot;
2448 
2449                                         NetRoot = VNetRoot->NetRoot;
2450                                         DUMP_FCB_TABLE_FROM_NETROOT(NetRoot);
2451                                     }
2452                                     break;
2453                                 }
2454 
2455                                 default:
2456                                 {
2457                                     DbgP("Other node found: %x\n", NodeType(Container));
2458                                     break;
2459                                 }
2460                             }
2461                         }
2462                     }
2463 
2464                     if (Release)
2465                     {
2466                         RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
2467                     }
2468 #undef DUMP_FCB_TABLE_FROM_NETROOT
2469                 }
2470                 else
2471                 {
2472                     DbgP("RxNetNameTable is NULL for: %p\n", RxContext->RxDeviceObject);
2473                 }
2474 #endif
2475                 status = STATUS_REDIRECTOR_HAS_OPEN_HANDLES;
2476                 break;
2477             }
2478             status = nfs41_DeleteConnection(RxContext, &RxContext->PostRequest);
2479             break;
2480         case IOCTL_NFS41_GETSTATE:
2481             state = RDR_NULL_STATE;
2482 
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;
2490                     break;
2491                 case NFS41_START_DRIVER_START_IN_PROGRESS:
2492                     state = RDR_STARTING;
2493                     break;
2494                 case NFS41_START_DRIVER_STARTED:
2495                     state = RDR_STARTED;
2496                     break;
2497                 }
2498                 *(ULONG *)io_ctx->ParamsFor.IoCtl.pOutputBuffer = state;
2499                 RxContext->InformationToReturn = sizeof(ULONG);
2500                 status = STATUS_SUCCESS;
2501             } else
2502                 status = STATUS_INVALID_PARAMETER;
2503             break;
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",
2509                     nfs41d_version);
2510                 DbgP("Currently used NFS41 Daemon version is %d\n",
2511                     DevExt->nfs41d_version);
2512                 DevExt->nfs41d_version = nfs41d_version;
2513             }
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;
2530                 }
2531                 break;
2532             case NFS41_START_DRIVER_STARTED:
2533                 status = STATUS_SUCCESS;
2534                 break;
2535             default:
2536                 status = STATUS_INVALID_PARAMETER;
2537             }
2538             break;
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;
2546                 break;
2547             }
2548 
2549             state = (nfs41_start_driver_state)InterlockedCompareExchange(
2550                         (PLONG)&nfs41_start_state,
2551                         NFS41_START_DRIVER_STARTABLE,
2552                         NFS41_START_DRIVER_STARTED);
2553 
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;
2558             break;
2559         default:
2560             status = STATUS_INVALID_DEVICE_REQUEST;
2561         };
2562         break;
2563     default:
2564         status = STATUS_INVALID_DEVICE_REQUEST;
2565     };
2566 
2567     //DbgEx();
2568     return status;
2569 }
2570 
2571 #ifndef __REACTOS__
_nfs41_CreateSrvCall(PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)2572 NTSTATUS _nfs41_CreateSrvCall(
2573     PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
2574 {
2575 #else
2576 NTSTATUS NTAPI _nfs41_CreateSrvCall(
2577     PVOID pContext)
2578 {
2579     PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext = pContext;
2580 #endif
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;
2587 
2588 #ifdef DEBUG_MOUNT
2589     DbgEn();
2590 #endif
2591 
2592     pSrvCall = SrvCalldownStructure->SrvCall;
2593 
2594     ASSERT( pSrvCall );
2595     ASSERT( NodeType(pSrvCall) == RDBSS_NTC_SRVCALL );
2596     print_srv_call(0, pSrvCall);
2597 
2598     // validate the server name with the test name of 'pnfs'
2599 #ifdef DEBUG_MOUNT
2600     DbgP("SrvCall: Connection Name Length: %d %wZ\n",
2601         pSrvCall->pSrvCallName->Length, pSrvCall->pSrvCallName);
2602 #endif
2603 
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;
2608         goto out;
2609     }
2610 
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;
2616         goto out;
2617     }
2618     RtlZeroMemory(pServerEntry, sizeof(NFS41_SERVER_ENTRY));
2619 
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);
2625 
2626     pCallbackContext->RecommunicateContext = pServerEntry;
2627 #ifdef __REACTOS__
2628     InterlockedExchangePointer((void * volatile *)&pServerEntry->pRdbssSrvCall, pSrvCall);
2629 #else
2630     InterlockedExchangePointer(&pServerEntry->pRdbssSrvCall, pSrvCall);
2631 #endif
2632 
2633 out:
2634     SCCBC->Status = status;
2635     SrvCalldownStructure->CallBack(SCCBC);
2636 
2637 #ifdef DEBUG_MOUNT
2638     DbgEx();
2639 #endif
2640     return status;
2641 }
2642 
2643 #ifdef __REACTOS__
2644 VOID NTAPI _nfs41_CreateSrvCall_v(
2645     PVOID pCallbackContext)
2646 {
2647     _nfs41_CreateSrvCall(pCallbackContext);
2648 }
2649 #endif
2650 
2651 #ifdef __REACTOS__
2652 NTSTATUS NTAPI nfs41_CreateSrvCall(
2653 #else
2654 NTSTATUS nfs41_CreateSrvCall(
2655 #endif
2656     PMRX_SRV_CALL pSrvCall,
2657     PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
2658 {
2659     NTSTATUS status;
2660 
2661     ASSERT( pSrvCall );
2662     ASSERT( NodeType(pSrvCall) == RDBSS_NTC_SRVCALL );
2663 
2664     if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
2665         DbgP("executing with RDBSS context\n");
2666         status = _nfs41_CreateSrvCall(pCallbackContext);
2667     } else {
2668         status = RxDispatchToWorkerThread(nfs41_dev, DelayedWorkQueue,
2669 #ifdef __REACTOS__
2670             _nfs41_CreateSrvCall_v, pCallbackContext);
2671 #else
2672             _nfs41_CreateSrvCall, pCallbackContext);
2673 #endif
2674         if (status != STATUS_SUCCESS) {
2675             print_error("RxDispatchToWorkerThread returned status %08lx\n",
2676                 status);
2677             pCallbackContext->Status = status;
2678             pCallbackContext->SrvCalldownStructure->CallBack(pCallbackContext);
2679             status = STATUS_PENDING;
2680         }
2681     }
2682     /* RDBSS expects MRxCreateSrvCall to return STATUS_PENDING */
2683     if (status == STATUS_SUCCESS)
2684         status = STATUS_PENDING;
2685 
2686     return status;
2687 }
2688 
2689 #ifdef __REACTOS__
2690 NTSTATUS NTAPI nfs41_SrvCallWinnerNotify(
2691 #else
2692 NTSTATUS nfs41_SrvCallWinnerNotify(
2693 #endif
2694     IN OUT PMRX_SRV_CALL pSrvCall,
2695     IN BOOLEAN ThisMinirdrIsTheWinner,
2696     IN OUT PVOID pSrvCallContext)
2697 {
2698     NTSTATUS status = STATUS_SUCCESS;
2699     PNFS41_SERVER_ENTRY pServerEntry;
2700 
2701     pServerEntry = (PNFS41_SERVER_ENTRY)pSrvCallContext;
2702 
2703     if (!ThisMinirdrIsTheWinner) {
2704         ASSERT(1);
2705         goto out;
2706     }
2707 
2708     pSrvCall->Context = pServerEntry;
2709 out:
2710     return status;
2711 }
2712 
2713 NTSTATUS map_mount_errors(
2714     DWORD status)
2715 {
2716     switch (status) {
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;
2722     default:
2723         print_error("failed to map windows error %d to NTSTATUS; "
2724             "defaulting to STATUS_INSUFFICIENT_RESOURCES\n", status);
2725         return STATUS_INSUFFICIENT_RESOURCES;
2726     }
2727 }
2728 
2729 NTSTATUS nfs41_mount(
2730     PNFS41_MOUNT_CONFIG config,
2731     DWORD sec_flavor,
2732     PHANDLE session,
2733     DWORD *version,
2734     PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs)
2735 {
2736     NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
2737     nfs41_updowncall_entry *entry;
2738 
2739 #ifdef DEBUG_MOUNT
2740     DbgEn();
2741     DbgP("Server Name %wZ Mount Point %wZ SecFlavor %d\n",
2742         &config->SrvName, &config->MntPt, sec_flavor);
2743 #endif
2744     status = nfs41_UpcallCreate(NFS41_MOUNT, NULL, *session,
2745         INVALID_HANDLE_VALUE, *version, &config->MntPt, &entry);
2746     if (status) goto out;
2747 
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;
2754 
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;
2761 
2762     /* map windows ERRORs to NTSTATUS */
2763     status = map_mount_errors(entry->status);
2764     if (status == STATUS_SUCCESS)
2765         *version = entry->version;
2766     RxFreePool(entry);
2767 out:
2768 #ifdef DEBUG_MOUNT
2769     DbgEx();
2770 #endif
2771     return status;
2772 }
2773 
2774 /* TODO: move mount config stuff to another file -cbodley */
2775 
2776 void nfs41_MountConfig_InitDefaults(
2777     OUT PNFS41_MOUNT_CONFIG Config)
2778 {
2779     RtlZeroMemory(Config, sizeof(NFS41_MOUNT_CONFIG));
2780 
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;
2797 }
2798 
2799 NTSTATUS nfs41_MountConfig_ParseBoolean(
2800     IN PFILE_FULL_EA_INFORMATION Option,
2801     IN PUNICODE_STRING usValue,
2802     OUT PBOOLEAN Value)
2803 {
2804     NTSTATUS status = STATUS_SUCCESS;
2805 
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')
2809         *Value = TRUE;
2810     else
2811         *Value = FALSE;
2812 
2813     DbgP("    '%ls' -> '%wZ' -> %u\n",
2814         (LPWSTR)Option->EaName, usValue, *Value);
2815     return status;
2816 }
2817 
2818 NTSTATUS nfs41_MountConfig_ParseDword(
2819     IN PFILE_FULL_EA_INFORMATION Option,
2820     IN PUNICODE_STRING usValue,
2821     OUT PDWORD Value,
2822     IN DWORD Minimum,
2823     IN DWORD Maximum)
2824 {
2825     NTSTATUS status = STATUS_INVALID_PARAMETER;
2826     LPWSTR Name = (LPWSTR)Option->EaName;
2827 
2828     if (Option->EaValueLength) {
2829         status = RtlUnicodeStringToInteger(usValue, 0, Value);
2830         if (status == STATUS_SUCCESS) {
2831 #ifdef IMPOSE_MINMAX_RWSIZES
2832             if (*Value < Minimum)
2833                 *Value = Minimum;
2834             if (*Value > Maximum)
2835                 *Value = Maximum;
2836             DbgP("    '%ls' -> '%wZ' -> %lu\n", Name, usValue, *Value);
2837 #endif
2838         }
2839         else
2840             print_error("Failed to convert %s='%wZ' to unsigned long.\n",
2841                 Name, usValue);
2842     }
2843 
2844     return status;
2845 }
2846 
2847 NTSTATUS nfs41_MountConfig_ParseOptions(
2848     IN PFILE_FULL_EA_INFORMATION EaBuffer,
2849     IN ULONG EaLength,
2850     IN OUT PNFS41_MOUNT_CONFIG Config)
2851 {
2852     NTSTATUS  status = STATUS_SUCCESS;
2853     PFILE_FULL_EA_INFORMATION Option;
2854     LPWSTR Name;
2855     size_t NameLen;
2856     UNICODE_STRING  usValue;
2857     Option = EaBuffer;
2858     while (status == STATUS_SUCCESS) {
2859         Name = (LPWSTR)Option->EaName;
2860         NameLen = Option->EaNameLength/sizeof(WCHAR);
2861 
2862         usValue.Length = usValue.MaximumLength = Option->EaValueLength;
2863         usValue.Buffer = (PWCH)(Option->EaName +
2864             Option->EaNameLength + sizeof(WCHAR));
2865 
2866         if (wcsncmp(L"ro", Name, NameLen) == 0) {
2867             status = nfs41_MountConfig_ParseBoolean(Option, &usValue,
2868                 &Config->ReadOnly);
2869         }
2870         else if (wcsncmp(L"writethru", Name, NameLen) == 0) {
2871             status = nfs41_MountConfig_ParseBoolean(Option, &usValue,
2872                 &Config->write_thru);
2873         }
2874         else if (wcsncmp(L"nocache", Name, NameLen) == 0) {
2875             status = nfs41_MountConfig_ParseBoolean(Option, &usValue,
2876                 &Config->nocache);
2877         }
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);
2882         }
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);
2887         }
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);
2892         }
2893         else if (wcsncmp(L"srvname", Name, NameLen) == 0) {
2894             if (usValue.Length > Config->SrvName.MaximumLength)
2895                 status = STATUS_NAME_TOO_LONG;
2896             else
2897                 RtlCopyUnicodeString(&Config->SrvName, &usValue);
2898         }
2899         else if (wcsncmp(L"mntpt", Name, NameLen) == 0) {
2900             if (usValue.Length > Config->MntPt.MaximumLength)
2901                 status = STATUS_NAME_TOO_LONG;
2902             else
2903                 RtlCopyUnicodeString(&Config->MntPt, &usValue);
2904         }
2905         else if (wcsncmp(L"sec", Name, NameLen) == 0) {
2906             if (usValue.Length > Config->SecFlavor.MaximumLength)
2907                 status = STATUS_NAME_TOO_LONG;
2908             else
2909                 RtlCopyUnicodeString(&Config->SecFlavor, &usValue);
2910         }
2911         else {
2912             status = STATUS_INVALID_PARAMETER;
2913             print_error("Unrecognized option '%ls' -> '%wZ'\n",
2914                 Name, usValue);
2915         }
2916 
2917         if (Option->NextEntryOffset == 0)
2918             break;
2919 
2920         Option = (PFILE_FULL_EA_INFORMATION)
2921             ((PBYTE)Option + Option->NextEntryOffset);
2922     }
2923 
2924     return status;
2925 }
2926 
2927 NTSTATUS has_nfs_prefix(
2928     IN PUNICODE_STRING SrvCallName,
2929     IN PUNICODE_STRING NetRootName)
2930 {
2931     NTSTATUS status = STATUS_BAD_NETWORK_NAME;
2932 
2933     if (NetRootName->Length == SrvCallName->Length + NfsPrefix.Length) {
2934         const UNICODE_STRING NetRootPrefix = {
2935             NfsPrefix.Length,
2936             NetRootName->MaximumLength - SrvCallName->Length,
2937             &NetRootName->Buffer[SrvCallName->Length/2]
2938         };
2939         if (RtlCompareUnicodeString(&NetRootPrefix, &NfsPrefix, FALSE) == 0)
2940             status = STATUS_SUCCESS;
2941     }
2942     return status;
2943 }
2944 
2945 NTSTATUS map_sec_flavor(
2946     IN PUNICODE_STRING sec_flavor_name,
2947     OUT PDWORD sec_flavor)
2948 {
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;
2959 }
2960 
2961 NTSTATUS nfs41_GetLUID(
2962     PLUID id)
2963 {
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;
2968 
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,
2975                 &clnt_sec_ctx);
2976     if (status) {
2977         print_error("nfs41_GetLUID: SeCreateClientSecurityFromSubjectContext "
2978              "failed %x\n", status);
2979         goto release_sec_ctx;
2980     }
2981     status = SeQueryAuthenticationIdToken(clnt_sec_ctx.ClientToken, id);
2982     if (status) {
2983         print_error("SeQueryAuthenticationIdToken failed %x\n", status);
2984         goto release_clnt_sec_ctx;
2985     }
2986 release_clnt_sec_ctx:
2987     SeDeleteClientSecurity(&clnt_sec_ctx);
2988 release_sec_ctx:
2989     SeReleaseSubjectContext(&sec_ctx);
2990 
2991     return status;
2992 }
2993 
2994 NTSTATUS nfs41_get_sec_ctx(
2995     IN enum _SECURITY_IMPERSONATION_LEVEL level,
2996     OUT PSECURITY_CLIENT_CONTEXT out_ctx)
2997 {
2998     NTSTATUS status;
2999     SECURITY_SUBJECT_CONTEXT ctx;
3000     SECURITY_QUALITY_OF_SERVICE sec_qos;
3001 
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);
3011     }
3012 #ifdef DEBUG_MOUNT
3013     DbgP("Created client security token %p\n", out_ctx->ClientToken);
3014 #endif
3015     SeReleaseSubjectContext(&ctx);
3016 
3017     return status;
3018 }
3019 
3020 #ifdef __REACTOS__
3021 NTSTATUS NTAPI nfs41_CreateVNetRoot(
3022 #else
3023 NTSTATUS nfs41_CreateVNetRoot(
3024 #endif
3025     IN OUT PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext)
3026 {
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;
3040     LUID luid;
3041     BOOLEAN found_existing_mount = FALSE, found_matching_flavor = FALSE;
3042 
3043     ASSERT((NodeType(pNetRoot) == RDBSS_NTC_NETROOT) &&
3044         (NodeType(pNetRoot->pSrvCall) == RDBSS_NTC_SRVCALL));
3045 
3046 #ifdef DEBUG_MOUNT
3047     DbgEn();
3048     print_srv_call(0, pSrvCall);
3049     print_net_root(0, pNetRoot);
3050     print_v_net_root(0, pVNetRoot);
3051 
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);
3058 #endif
3059 
3060     if (pNetRoot->Type != NET_ROOT_DISK && pNetRoot->Type != NET_ROOT_WILD) {
3061         print_error("nfs41_CreateVNetRoot: Unsupported NetRoot Type %u\n",
3062             pNetRoot->Type);
3063         status = STATUS_NOT_SUPPORTED;
3064         goto out;
3065     }
3066 
3067     pVNetRootContext->session = INVALID_HANDLE_VALUE;
3068 
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);
3072     if (status) {
3073         print_error("nfs41_CreateVNetRoot: NetRootName %wZ doesn't match "
3074             "'\\nfs4'!\n", pNetRoot->pNetRootName);
3075         goto out;
3076     }
3077     pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD;
3078     pNetRoot->DeviceType = FILE_DEVICE_DISK;
3079 
3080     Config = RxAllocatePoolWithTag(NonPagedPool,
3081             sizeof(NFS41_MOUNT_CONFIG), NFS41_MM_POOLTAG);
3082     if (Config == NULL) {
3083         status = STATUS_INSUFFICIENT_RESOURCES;
3084         goto out;
3085     }
3086     nfs41_MountConfig_InitDefaults(Config);
3087 
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,
3093             Config);
3094         if (status != STATUS_SUCCESS)
3095             goto out_free;
3096         pVNetRootContext->read_only = Config->ReadOnly;
3097         pVNetRootContext->write_thru = Config->write_thru;
3098         pVNetRootContext->nocache = Config->nocache;
3099     } else {
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);
3106     }
3107     pVNetRootContext->MountPathLen = Config->MntPt.Length;
3108     pVNetRootContext->timeout = Config->timeout;
3109 
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);
3113         goto out_free;
3114     }
3115 
3116     status = nfs41_GetLUID(&luid);
3117     if (status)
3118         goto out_free;
3119 
3120     if (!pNetRootContext->mounts_init) {
3121 #ifdef DEBUG_MOUNT
3122         DbgP("Initializing mount array\n");
3123 #endif
3124         ExInitializeFastMutex(&pNetRootContext->mountLock);
3125         InitializeListHead(&pNetRootContext->mounts.head);
3126         pNetRootContext->mounts_init = TRUE;
3127     } else {
3128         PLIST_ENTRY pEntry;
3129 
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);
3136 #ifdef DEBUG_MOUNT
3137             DbgP("comparing %x.%x with %x.%x\n", luid.HighPart, luid.LowPart,
3138                 existing_mount->login_id.HighPart, existing_mount->login_id.LowPart);
3139 #endif
3140             if (RtlEqualLuid(&luid, &existing_mount->login_id)) {
3141 #ifdef DEBUG_MOUNT
3142                 DbgP("Found a matching LUID entry\n");
3143 #endif
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;
3150                     break;
3151                 case RPCSEC_AUTHGSS_KRB5:
3152                     if (existing_mount->gssi_session != INVALID_HANDLE_VALUE)
3153                         pVNetRootContext->session = existing_mount->gss_session;
3154                     break;
3155                 case RPCSEC_AUTHGSS_KRB5I:
3156                     if (existing_mount->gss_session != INVALID_HANDLE_VALUE)
3157                         pVNetRootContext->session = existing_mount->gssi_session;
3158                     break;
3159                 case RPCSEC_AUTHGSS_KRB5P:
3160                     if (existing_mount->gssp_session != INVALID_HANDLE_VALUE)
3161                         pVNetRootContext->session = existing_mount->gssp_session;
3162                     break;
3163                 }
3164                 if (pVNetRootContext->session &&
3165                         pVNetRootContext->session != INVALID_HANDLE_VALUE)
3166                     found_matching_flavor = 1;
3167                 break;
3168             }
3169             if (pEntry->Flink == &pNetRootContext->mounts.head)
3170                 break;
3171             pEntry = pEntry->Flink;
3172         }
3173         ExReleaseFastMutex(&pNetRootContext->mountLock);
3174 #ifdef DEBUG_MOUNT
3175         if (!found_matching_flavor)
3176             DbgP("Didn't find matching security flavor\n");
3177 #endif
3178     }
3179 
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;
3191         goto out_free;
3192     }
3193     pVNetRootContext->timeout = Config->timeout;
3194 
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;
3202             goto out_free;
3203         }
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;
3215         }
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 */
3222 #ifdef DEBUG_MOUNT
3223         DbgP("Using existing %d flavor session 0x%x\n",
3224             pVNetRootContext->sec_flavor);
3225 #endif
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;
3235         }
3236     }
3237     pNetRootContext->nfs41d_version = nfs41d_version;
3238 #ifdef DEBUG_MOUNT
3239     DbgP("Saving new session 0x%x\n", pVNetRootContext->session);
3240 #endif
3241 #ifdef STORE_MOUNT_SEC_CONTEXT
3242     status = nfs41_get_sec_ctx(SecurityImpersonation,
3243         &pVNetRootContext->mount_sec_ctx);
3244 #endif
3245 
3246 out_free:
3247     RxFreePool(Config);
3248 out:
3249     pCreateNetRootContext->VirtualNetRootStatus = status;
3250     if (pNetRoot->Context == NULL)
3251         pCreateNetRootContext->NetRootStatus = status;
3252     pCreateNetRootContext->Callback(pCreateNetRootContext);
3253 
3254     /* RDBSS expects that MRxCreateVNetRoot returns STATUS_PENDING
3255      * on success or failure */
3256     status = STATUS_PENDING;
3257 #ifdef DEBUG_MOUNT
3258     DbgEx();
3259 #endif
3260     return status;
3261 }
3262 
3263 #ifdef __REACTOS__
3264 VOID NTAPI nfs41_ExtractNetRootName(
3265 #else
3266 VOID nfs41_ExtractNetRootName(
3267 #endif
3268     IN PUNICODE_STRING FilePathName,
3269     IN PMRX_SRV_CALL SrvCall,
3270     OUT PUNICODE_STRING NetRootName,
3271     OUT PUNICODE_STRING RestOfName OPTIONAL)
3272 {
3273     ULONG length = FilePathName->Length;
3274     PWCH w = FilePathName->Buffer;
3275     PWCH wlimit = (PWCH)(((PCHAR)w)+length);
3276     PWCH wlow;
3277 
3278     w += (SrvCall->pSrvCallName->Length/sizeof(WCHAR));
3279     NetRootName->Buffer = wlow = w;
3280     /* parse the entire path into NetRootName */
3281 #if USE_ENTIRE_PATH
3282     w = wlimit;
3283 #else
3284     for (;;) {
3285         if (w >= wlimit)
3286             break;
3287         if ((*w == OBJ_NAME_PATH_SEPARATOR) && (w != wlow))
3288             break;
3289         w++;
3290     }
3291 #endif
3292     NetRootName->Length = NetRootName->MaximumLength
3293                 = (USHORT)((PCHAR)w - (PCHAR)wlow);
3294 #ifdef DEBUG_MOUNT
3295     DbgP("In: pSrvCall %p PathName=%wZ SrvCallName=%wZ Out: NetRootName=%wZ\n",
3296         SrvCall, FilePathName, SrvCall->pSrvCallName, NetRootName);
3297 #endif
3298     return;
3299 
3300 }
3301 
3302 #ifdef __REACTOS__
3303 NTSTATUS NTAPI nfs41_FinalizeSrvCall(
3304 #else
3305 NTSTATUS nfs41_FinalizeSrvCall(
3306 #endif
3307     PMRX_SRV_CALL pSrvCall,
3308     BOOLEAN Force)
3309 {
3310     NTSTATUS status = STATUS_SUCCESS;
3311     PNFS41_SERVER_ENTRY pServerEntry = (PNFS41_SERVER_ENTRY)(pSrvCall->Context);
3312 
3313 #ifdef DEBUG_MOUNT
3314     DbgEn();
3315 #endif
3316     print_srv_call(0, pSrvCall);
3317 
3318     if (pSrvCall->Context == NULL)
3319         goto out;
3320 
3321 #ifndef __REACTOS__
3322     InterlockedCompareExchangePointer(&pServerEntry->pRdbssSrvCall,
3323         NULL, pSrvCall);
3324 #else
3325     InterlockedCompareExchangePointer((void * volatile *)&pServerEntry->pRdbssSrvCall,
3326         NULL, pSrvCall);
3327 #endif
3328     RxFreePool(pServerEntry);
3329 
3330     pSrvCall->Context = NULL;
3331 out:
3332 #ifdef DEBUG_MOUNT
3333     DbgEx();
3334 #endif
3335     return status;
3336 }
3337 
3338 #ifdef __REACTOS__
3339 NTSTATUS NTAPI nfs41_FinalizeNetRoot(
3340 #else
3341 NTSTATUS nfs41_FinalizeNetRoot(
3342 #endif
3343     IN OUT PMRX_NET_ROOT pNetRoot,
3344     IN PBOOLEAN ForceDisconnect)
3345 {
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;
3351 
3352 #ifdef DEBUG_MOUNT
3353     DbgEn();
3354     print_net_root(1, pNetRoot);
3355 #endif
3356 
3357     if (pNetRoot->Type != NET_ROOT_DISK && pNetRoot->Type != NET_ROOT_WILD) {
3358         status = STATUS_NOT_SUPPORTED;
3359         goto out;
3360     }
3361 
3362     if (pNetRootContext == NULL || !pNetRootContext->mounts_init) {
3363         print_error("nfs41_FinalizeNetRoot: No valid session established\n");
3364         goto out;
3365     }
3366 
3367     if (pNetRoot->NumberOfFcbs > 0 || pNetRoot->NumberOfSrvOpens > 0) {
3368         print_error("%d open Fcbs %d open SrvOpens\n", pNetRoot->NumberOfFcbs,
3369             pNetRoot->NumberOfSrvOpens);
3370         goto out;
3371     }
3372 
3373     do {
3374         nfs41_GetFirstMountEntry(pNetRootContext->mountLock,
3375             pNetRootContext->mounts, mount_tmp);
3376         if (mount_tmp == NULL)
3377             break;
3378 #ifdef DEBUG_MOUNT
3379         DbgP("Removing entry luid %x.%x from mount list\n",
3380             mount_tmp->login_id.HighPart, mount_tmp->login_id.LowPart);
3381 #endif
3382         if (mount_tmp->authsys_session != INVALID_HANDLE_VALUE) {
3383             status = nfs41_unmount(mount_tmp->authsys_session,
3384                 pNetRootContext->nfs41d_version, UPCALL_TIMEOUT_DEFAULT);
3385             if (status)
3386                 print_error("nfs41_unmount AUTH_SYS failed with %d\n", status);
3387         }
3388         if (mount_tmp->gss_session != INVALID_HANDLE_VALUE) {
3389             status = nfs41_unmount(mount_tmp->gss_session,
3390                 pNetRootContext->nfs41d_version, UPCALL_TIMEOUT_DEFAULT);
3391             if (status)
3392                 print_error("nfs41_unmount RPCSEC_GSS_KRB5 failed with %d\n",
3393                             status);
3394         }
3395         if (mount_tmp->gssi_session != INVALID_HANDLE_VALUE) {
3396             status = nfs41_unmount(mount_tmp->gssi_session,
3397                 pNetRootContext->nfs41d_version, UPCALL_TIMEOUT_DEFAULT);
3398             if (status)
3399                 print_error("nfs41_unmount RPCSEC_GSS_KRB5I failed with %d\n",
3400                             status);
3401         }
3402         if (mount_tmp->gssp_session != INVALID_HANDLE_VALUE) {
3403             status = nfs41_unmount(mount_tmp->gssp_session,
3404                 pNetRootContext->nfs41d_version, UPCALL_TIMEOUT_DEFAULT);
3405             if (status)
3406                 print_error("nfs41_unmount RPCSEC_GSS_KRB5P failed with %d\n",
3407                             status);
3408         }
3409         nfs41_RemoveEntry(pNetRootContext->mountLock, mount_tmp);
3410         RxFreePool(mount_tmp);
3411     } while (1);
3412     /* ignore any errors from unmount */
3413     status = STATUS_SUCCESS;
3414 
3415     // check if there is anything waiting in the upcall or downcall queue
3416     do {
3417         nfs41_GetFirstEntry(upcallLock, upcall, tmp);
3418         if (tmp != NULL) {
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);
3423         } else
3424             break;
3425     } while (1);
3426 
3427     do {
3428         nfs41_GetFirstEntry(downcallLock, downcall, tmp);
3429         if (tmp != NULL) {
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);
3434         } else
3435             break;
3436     } while (1);
3437 out:
3438 #ifdef DEBUG_MOUNT
3439     DbgEx();
3440 #endif
3441     return status;
3442 }
3443 
3444 #ifdef __REACTOS__
3445 NTSTATUS NTAPI nfs41_FinalizeVNetRoot(
3446 #else
3447 NTSTATUS nfs41_FinalizeVNetRoot(
3448 #endif
3449     IN OUT PMRX_V_NET_ROOT pVNetRoot,
3450     IN PBOOLEAN ForceDisconnect)
3451 {
3452     NTSTATUS status = STATUS_SUCCESS;
3453     PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
3454         NFS41GetVNetRootExtension(pVNetRoot);
3455 #ifdef DEBUG_MOUNT
3456     DbgEn();
3457     print_v_net_root(1, pVNetRoot);
3458 #endif
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) {
3464 #ifdef DEBUG_MOUNT
3465         DbgP("nfs41_FinalizeVNetRoot: deleting security context: %p\n",
3466             pVNetRootContext->mount_sec_ctx.ClientToken);
3467 #endif
3468         SeDeleteClientSecurity(&pVNetRootContext->mount_sec_ctx);
3469     }
3470 #endif
3471 #ifdef DEBUG_MOUNT
3472     DbgEx();
3473 #endif
3474     return status;
3475 }
3476 
3477 BOOLEAN isDataAccess(
3478     ACCESS_MASK mask)
3479 {
3480     if (mask & (FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA))
3481         return TRUE;
3482     return FALSE;
3483 }
3484 
3485 BOOLEAN isOpen2Create(
3486     ULONG disposition)
3487 {
3488     if (disposition == FILE_CREATE || disposition == FILE_OPEN_IF ||
3489             disposition == FILE_OVERWRITE_IF || disposition == FILE_SUPERSEDE)
3490         return TRUE;
3491     return FALSE;
3492 }
3493 
3494 BOOLEAN isFilenameTooLong(
3495     PUNICODE_STRING name,
3496     PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext)
3497 {
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;
3503         else {
3504             if (p[0] == L'\0') return FALSE;
3505             if (count > len) return TRUE;
3506             count++;
3507         }
3508         p++;
3509     }
3510     return FALSE;
3511 }
3512 
3513 BOOLEAN isStream(
3514     PUNICODE_STRING name)
3515 {
3516     LONG i;
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;
3521         p++;
3522     }
3523     return FALSE;
3524 }
3525 
3526 BOOLEAN areOpenParamsValid(NT_CREATE_PARAMETERS *params)
3527 {
3528     /* from ms-fsa page 52 */
3529     if ((params->CreateOptions & FILE_DELETE_ON_CLOSE) &&
3530             !(params->DesiredAccess & DELETE))
3531         return FALSE;
3532     if ((params->CreateOptions & FILE_DIRECTORY_FILE) &&
3533             (params->Disposition == FILE_SUPERSEDE ||
3534                 params->Disposition == FILE_OVERWRITE ||
3535                 params->Disposition == FILE_OVERWRITE_IF))
3536         return FALSE;
3537     if ((params->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) &&
3538             (params->DesiredAccess & FILE_APPEND_DATA) &&
3539             !(params->DesiredAccess & FILE_WRITE_DATA))
3540         return FALSE;
3541     /* from ms-fsa 3.1.5.1.1 page 56 */
3542     if ((params->CreateOptions & FILE_DIRECTORY_FILE) &&
3543             (params->FileAttributes & FILE_ATTRIBUTE_TEMPORARY))
3544         return FALSE;
3545     return TRUE;
3546 }
3547 
3548 NTSTATUS map_open_errors(
3549     DWORD status,
3550     USHORT len)
3551 {
3552     switch (status) {
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;
3571     default:
3572         print_error("[ERROR] nfs41_Create: upcall returned %d returning "
3573             "STATUS_INSUFFICIENT_RESOURCES\n", status);
3574     case ERROR_OUTOFMEMORY:             return STATUS_INSUFFICIENT_RESOURCES;
3575     }
3576 }
3577 
3578 DWORD map_disposition_to_create_retval(
3579     DWORD disposition,
3580     DWORD errno)
3581 {
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;
3588     case FILE_OPEN_IF:
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;
3595     default:
3596         print_error("unknown disposition %d\n", disposition);
3597         return FILE_OPENED;
3598     }
3599 }
3600 
3601 static BOOLEAN create_should_pass_ea(
3602     IN PFILE_FULL_EA_INFORMATION ea,
3603     IN ULONG disposition)
3604 {
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))
3609         return FALSE;
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;
3614 }
3615 
3616 NTSTATUS check_nfs41_create_args(
3617     IN PRX_CONTEXT RxContext)
3618 {
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;
3632 
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;
3638         goto out;
3639     }
3640 
3641     if (FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE )) {
3642         print_error("FCB_STATE_PAGING_FILE not implemented\n");
3643         status = STATUS_NOT_IMPLEMENTED;
3644         goto out;
3645     }
3646 
3647     if (!pNetRootContext->mounts_init) {
3648         print_error("nfs41_Create: No valid session established\n");
3649         status = STATUS_INSUFFICIENT_RESOURCES;
3650         goto out;
3651     }
3652 
3653     if (isStream(SrvOpen->pAlreadyPrefixedName)) {
3654         status = STATUS_NOT_SUPPORTED;
3655         goto out;
3656     }
3657 
3658     if (pVNetRootContext->read_only &&
3659             (params->DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA))) {
3660         status = STATUS_NETWORK_ACCESS_DENIED;
3661         goto out;
3662     }
3663 
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
3667      */
3668     if (Fcb->OpenCount && nfs41_fcb->DeletePending) {
3669         status = STATUS_DELETE_PENDING;
3670         goto out;
3671     }
3672 
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;
3679         goto out;
3680     }
3681 
3682     /* rdbss seems miss this sharing_violation check */
3683     if (Fcb->OpenCount && params->Disposition == FILE_SUPERSEDE) {
3684 #ifdef __REACTOS__
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)))) {
3692 #else
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)))) {
3700 #endif
3701             status = STATUS_SHARING_VIOLATION;
3702             goto out;
3703         }
3704     }
3705     if (isFilenameTooLong(SrvOpen->pAlreadyPrefixedName, pVNetRootContext)) {
3706         status = STATUS_OBJECT_NAME_INVALID;
3707         goto out;
3708     }
3709 
3710     if (!areOpenParamsValid(params)) {
3711         status = STATUS_INVALID_PARAMETER;
3712         goto out;
3713     }
3714 
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;
3719         goto out;
3720     }
3721 
3722     if (ea) {
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;
3729                 goto out;
3730             }
3731         }
3732     } else if (RxContext->CurrentIrpSp->Parameters.Create.EaLength) {
3733         status = STATUS_INVALID_PARAMETER;
3734         goto out;
3735     }
3736 
3737 out:
3738     return status;
3739 }
3740 
3741 #ifdef __REACTOS__
3742 NTSTATUS NTAPI nfs41_Create(
3743 #else
3744 NTSTATUS nfs41_Create(
3745 #endif
3746     IN OUT PRX_CONTEXT RxContext)
3747 {
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);
3765 #endif
3766 
3767     ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
3768 
3769 #ifdef DEBUG_OPEN
3770     DbgEn();
3771     print_debug_header(RxContext);
3772     print_nt_create_params(1, RxContext->Create.NtCreateParameters);
3773     if (ea) print_ea_info(0, ea);
3774 #endif
3775 
3776     status = check_nfs41_create_args(RxContext);
3777     if (status) goto out;
3778 
3779 #if defined(STORE_MOUNT_SEC_CONTEXT) && defined (USE_MOUNT_SEC_CONTEXT)
3780     status = nfs41_UpcallCreate(NFS41_OPEN, &pVNetRootContext->mount_sec_ctx,
3781 #else
3782     status = nfs41_UpcallCreate(NFS41_OPEN, NULL,
3783 #endif
3784         pVNetRootContext->session, INVALID_HANDLE_VALUE,
3785         pNetRootContext->nfs41d_version,
3786         SrvOpen->pAlreadyPrefixedName, &entry);
3787     if (status) goto out;
3788 
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);
3808 #ifdef DEBUG_OPEN
3809             DbgP("creating file with mode %o\n", attrs->mode);
3810 #endif
3811             entry->u.Open.mode = attrs->mode;
3812         }
3813         if (params->FileAttributes & FILE_ATTRIBUTE_READONLY)
3814             entry->u.Open.mode = 0444;
3815     }
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;
3821     }
3822 retry_on_link:
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;
3830             RxFreePool(entry);
3831             goto out;
3832         }
3833         entry->u.Open.EaMdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
3834         MmProbeAndLockPages(entry->u.Open.EaMdl, KernelMode, IoModifyAccess);
3835     }
3836 
3837     status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
3838 #ifndef USE_MOUNT_SEC_CONTEXT
3839     SeDeleteClientSecurity(&entry->sec_ctx);
3840 #endif
3841     if (status) goto out;
3842 
3843     if (entry->u.Open.EaMdl) {
3844         MmUnlockPages(entry->u.Open.EaMdl);
3845         IoFreeMdl(entry->u.Open.EaMdl);
3846     }
3847 
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;
3859         PCHAR buf;
3860         BOOLEAN ReparseRequired;
3861 
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;
3871             goto out_free;
3872         }
3873 
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;
3885 
3886         status = RxPrepareToReparseSymbolicLink(RxContext,
3887             entry->u.Open.symlink_embedded, &AbsPath, TRUE, &ReparseRequired);
3888 #ifdef DEBUG_OPEN
3889         DbgP("RxPrepareToReparseSymbolicLink(%u, '%wZ') returned %08lX, "
3890             "FileName is '%wZ'\n", entry->u.Open.symlink_embedded,
3891             &AbsPath, status, &RxContext->CurrentIrpSp->FileObject->FileName);
3892 #endif
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;
3900                 goto retry_on_link;
3901             }
3902             status = STATUS_REPARSE;
3903         }
3904         goto out_free;
3905     }
3906 
3907     status = map_open_errors(entry->status,
3908                 SrvOpen->pAlreadyPrefixedName->Length);
3909     if (status) {
3910 #ifdef DEBUG_OPEN
3911         print_open_error(1, status);
3912 #endif
3913         goto out_free;
3914     }
3915 
3916     if (!RxIsFcbAcquiredExclusive(Fcb)) {
3917         ASSERT(!RxIsFcbAcquiredShared(Fcb));
3918         RxAcquireExclusiveFcbResourceInMRx(Fcb);
3919     }
3920 
3921     RxContext->pFobx = RxCreateNetFobx(RxContext, SrvOpen);
3922     if (RxContext->pFobx == NULL) {
3923         status = STATUS_INSUFFICIENT_RESOURCES;
3924         goto out_free;
3925     }
3926 #ifdef DEBUG_OPEN
3927     DbgP("nfs41_Create: created FOBX %p\n", RxContext->pFobx);
3928 #endif
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);
3933     if (status)
3934         goto out_free;
3935 #else
3936     RtlCopyMemory(&nfs41_fobx->sec_ctx, &pVNetRootContext->mount_sec_ctx,
3937         sizeof(nfs41_fobx->sec_ctx));
3938 #endif
3939 
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;
3955 
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);
3966 
3967         if (entry->u.Open.sinfo.Directory)
3968             StorageType = FileTypeDirectory;
3969         else
3970             StorageType = FileTypeFile;
3971 
3972         RxFinishFcbInitialization(Fcb, RDBSS_STORAGE_NTC(StorageType),
3973                                     &InitPacket);
3974     }
3975 #ifdef DEBUG_OPEN
3976     else
3977         DbgP("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
3978 
3979     print_basic_info(1, &nfs41_fcb->BasicInfo);
3980     print_std_info(1, &nfs41_fcb->StandardInfo);
3981 #endif
3982 
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.
3988      */
3989     if (Fcb->OpenCount > 0 && (isDataAccess(params->DesiredAccess) ||
3990             nfs41_fcb->changeattr != entry->ChangeTime) &&
3991                 !nfs41_fcb->StandardInfo.Directory) {
3992         ULONG flag = DISABLE_CACHING;
3993 #ifdef DEBUG_OPEN
3994         DbgP("nfs41_Create: reopening (changed) file %wZ\n",
3995             SrvOpen->pAlreadyPrefixedName);
3996 #endif
3997         RxChangeBufferingState((PSRV_OPEN)SrvOpen, ULongToPtr(flag), 1);
3998     }
3999     if (!nfs41_fcb->StandardInfo.Directory &&
4000             isDataAccess(params->DesiredAccess)) {
4001         nfs41_fobx->deleg_type = entry->u.Open.deleg_type;
4002 #ifdef DEBUG_OPEN
4003         DbgP("nfs41_Create: received delegation %d\n", entry->u.Open.deleg_type);
4004 #endif
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)))) {
4009 #ifdef DEBUG_OPEN
4010             DbgP("nfs41_Create: enabling write buffering\n");
4011 #endif
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) {
4020 #ifdef DEBUG_OPEN
4021             DbgP("nfs41_Create: enabling read buffering\n");
4022 #endif
4023             SrvOpen->BufferingFlags |=
4024                 (FCB_STATE_READBUFFERING_ENABLED |
4025                 FCB_STATE_READCACHING_ENABLED);
4026         }
4027         if (pVNetRootContext->nocache ||
4028                 (params->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)) {
4029 #ifdef DEBUG_OPEN
4030             DbgP("nfs41_Create: disabling buffering\n");
4031 #endif
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;
4036 #ifdef DEBUG_OPEN
4037             DbgP("nfs41_Create: received no delegations: srv_open=%p "
4038                 "ctime=%llu\n", SrvOpen, entry->ChangeTime);
4039 #endif
4040             oentry = RxAllocatePoolWithTag(NonPagedPool,
4041                 sizeof(nfs41_fcb_list_entry), NFS41_MM_POOLTAG_OPEN);
4042             if (oentry == NULL) {
4043                 status = STATUS_INSUFFICIENT_RESOURCES;
4044                 goto out_free;
4045             }
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);
4052         }
4053     }
4054 
4055     if ((params->CreateOptions & FILE_DELETE_ON_CLOSE) &&
4056             !pVNetRootContext->read_only)
4057         nfs41_fcb->StandardInfo.DeletePending = TRUE;
4058 
4059     RxContext->Create.ReturnedCreateInformation =
4060         map_disposition_to_create_retval(params->Disposition, entry->errno);
4061 
4062     RxContext->pFobx->OffsetOfNextEaToReturn = 1;
4063 #ifndef __REACTOS__
4064     RxContext->CurrentIrp->IoStatus.Information =
4065         RxContext->Create.ReturnedCreateInformation;
4066 #endif
4067     status = RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
4068 
4069 out_free:
4070     if (entry)
4071         RxFreePool(entry);
4072 out:
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);
4084 #endif
4085     } else {
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);
4091 #endif
4092     }
4093 #endif
4094 #ifdef DEBUG_OPEN
4095     DbgEx();
4096 #endif
4097     return status;
4098 }
4099 
4100 #ifdef __REACTOS__
4101 NTSTATUS NTAPI nfs41_CollapseOpen(
4102 #else
4103 NTSTATUS nfs41_CollapseOpen(
4104 #endif
4105     IN OUT PRX_CONTEXT RxContext)
4106 {
4107     NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
4108     DbgEn();
4109     DbgEx();
4110     return status;
4111 }
4112 
4113 #ifdef __REACTOS__
4114 NTSTATUS NTAPI nfs41_ShouldTryToCollapseThisOpen(
4115 #else
4116 NTSTATUS nfs41_ShouldTryToCollapseThisOpen(
4117 #endif
4118     IN OUT PRX_CONTEXT RxContext)
4119 {
4120     if (RxContext->pRelevantSrvOpen == NULL)
4121         return STATUS_SUCCESS;
4122     else return STATUS_MORE_PROCESSING_REQUIRED;
4123 }
4124 
4125 #ifdef __REACTOS__
4126 ULONG NTAPI nfs41_ExtendForCache(
4127 #else
4128 ULONG nfs41_ExtendForCache(
4129 #endif
4130     IN OUT PRX_CONTEXT RxContext,
4131     IN PLARGE_INTEGER pNewFileSize,
4132     OUT PLARGE_INTEGER pNewAllocationSize)
4133 {
4134     NTSTATUS status = STATUS_SUCCESS;
4135     __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
4136 #ifdef DEBUG_CACHE
4137     PLOWIO_CONTEXT LowIoContext  = &RxContext->LowIoContext;
4138     DbgEn();
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);
4143 #endif
4144     pNewAllocationSize->QuadPart = pNewFileSize->QuadPart + 8192;
4145     nfs41_fcb->StandardInfo.AllocationSize.QuadPart =
4146         pNewAllocationSize->QuadPart;
4147     nfs41_fcb->StandardInfo.EndOfFile.QuadPart = pNewFileSize->QuadPart;
4148 #ifdef DEBUG_CACHE
4149     DbgP("new filesize 0x%x new allocation size 0x%x\n", *pNewFileSize,
4150         *pNewAllocationSize);
4151 #endif
4152 #ifdef DEBUG_CACHE
4153     DbgEx();
4154 #endif
4155     return status;
4156 }
4157 
4158 VOID nfs41_remove_fcb_entry(
4159     PMRX_FCB fcb)
4160 {
4161     PLIST_ENTRY pEntry;
4162     nfs41_fcb_list_entry *cur;
4163     ExAcquireFastMutex(&fcblistLock);
4164 
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) {
4170 #ifdef DEBUG_CLOSE
4171             DbgP("nfs41_remove_srvopen_entry: Found match for fcb=%p\n", fcb);
4172 #endif
4173             RemoveEntryList(pEntry);
4174             RxFreePool(cur);
4175             break;
4176         }
4177         if (pEntry->Flink == &openlist.head) {
4178 #ifdef DEBUG_CLOSE
4179             DbgP("nfs41_remove_srvopen_entry: reached EOL looking for fcb "
4180                 "%p\n", fcb);
4181 #endif
4182             break;
4183         }
4184         pEntry = pEntry->Flink;
4185     }
4186     ExReleaseFastMutex(&fcblistLock);
4187 }
4188 
4189 NTSTATUS map_close_errors(
4190     DWORD status)
4191 {
4192     switch (status) {
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;
4197     default:
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;
4201     }
4202 }
4203 
4204 #ifdef __REACTOS__
4205 NTSTATUS NTAPI nfs41_CloseSrvOpen(
4206 #else
4207 NTSTATUS nfs41_CloseSrvOpen(
4208 #endif
4209     IN OUT PRX_CONTEXT RxContext)
4210 {
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);
4223 #endif
4224 
4225 #ifdef DEBUG_CLOSE
4226     DbgEn();
4227     print_debug_header(RxContext);
4228 #endif
4229 
4230     if (!nfs41_fobx->deleg_type && !nfs41_fcb->StandardInfo.Directory &&
4231             !RxContext->pFcb->OpenCount) {
4232         nfs41_remove_fcb_entry(RxContext->pFcb);
4233     }
4234 
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;
4239 
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;
4249 
4250     status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
4251 #ifndef USE_MOUNT_SEC_CONTEXT
4252     SeDeleteClientSecurity(&nfs41_fobx->sec_ctx);
4253 #endif
4254     if (status) goto out;
4255 
4256     /* map windows ERRORs to NTSTATUS */
4257     status = map_close_errors(entry->status);
4258     RxFreePool(entry);
4259 out:
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);
4267 #endif
4268 #endif
4269 #ifdef DEBUG_CLOSE
4270     DbgEx();
4271 #endif
4272     return status;
4273 }
4274 
4275 #ifdef __REACTOS__
4276 NTSTATUS NTAPI nfs41_Flush(
4277 #else
4278 NTSTATUS nfs41_Flush(
4279 #endif
4280     IN OUT PRX_CONTEXT RxContext)
4281 {
4282     return STATUS_SUCCESS;
4283 }
4284 
4285 #ifdef __REACTOS__
4286 NTSTATUS NTAPI nfs41_DeallocateForFcb(
4287 #else
4288 NTSTATUS nfs41_DeallocateForFcb(
4289 #endif
4290     IN OUT PMRX_FCB pFcb)
4291 {
4292     return STATUS_SUCCESS;
4293 }
4294 
4295 #ifdef __REACTOS__
4296 NTSTATUS NTAPI nfs41_DeallocateForFobx(
4297 #else
4298 NTSTATUS nfs41_DeallocateForFobx(
4299 #endif
4300     IN OUT PMRX_FOBX pFobx)
4301 {
4302     __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(pFobx);
4303     if (nfs41_fobx->acl)
4304         RxFreePool(nfs41_fobx->acl);
4305     return STATUS_SUCCESS;
4306 }
4307 
4308 void print_debug_filedirquery_header(
4309     PRX_CONTEXT RxContext)
4310 {
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));
4315 }
4316 
4317 void print_querydir_args(
4318     PRX_CONTEXT RxContext)
4319 {
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);
4328 }
4329 
4330 NTSTATUS map_querydir_errors(
4331     DWORD status)
4332 {
4333     switch (status) {
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;
4342     default:
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;
4346     }
4347 }
4348 
4349 NTSTATUS check_nfs41_dirquery_args(
4350     IN PRX_CONTEXT RxContext)
4351 {
4352     if (RxContext->Info.Buffer == NULL)
4353         return STATUS_INVALID_USER_BUFFER;
4354     return STATUS_SUCCESS;
4355 }
4356 
4357 #ifdef __REACTOS__
4358 NTSTATUS NTAPI nfs41_QueryDirectory(
4359 #else
4360 NTSTATUS nfs41_QueryDirectory(
4361 #endif
4362     IN OUT PRX_CONTEXT RxContext)
4363 {
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);
4377 #endif
4378 
4379 #ifdef DEBUG_DIR_QUERY
4380     DbgEn();
4381     print_querydir_args(RxContext);
4382 #endif
4383 
4384     status = check_nfs41_dirquery_args(RxContext);
4385     if (status) goto out;
4386 
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:
4395         break;
4396     default:
4397         print_error("nfs41_QueryDirectory: unhandled dir query class %d\n",
4398             InfoClass);
4399         status = STATUS_NOT_SUPPORTED;
4400         goto out;
4401     }
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;
4406 
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;
4414         RxFreePool(entry);
4415         goto out;
4416     }
4417     entry->u.QueryFile.mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
4418     MmProbeAndLockPages(entry->u.QueryFile.mdl, KernelMode, IoModifyAccess);
4419 
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;
4424 
4425     status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
4426     if (status) goto out;
4427     MmUnlockPages(entry->u.QueryFile.mdl);
4428 
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);
4438 #endif
4439         RxContext->Info.LengthRemaining -= entry->buf_len;
4440         status = STATUS_SUCCESS;
4441     } else {
4442         /* map windows ERRORs to NTSTATUS */
4443         status = map_querydir_errors(entry->status);
4444     }
4445     IoFreeMdl(entry->u.QueryFile.mdl);
4446     RxFreePool(entry);
4447 out:
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);
4455 #endif
4456 #endif
4457 #ifdef DEBUG_DIR_QUERY
4458     DbgEx();
4459 #endif
4460     return status;
4461 }
4462 
4463 void print_queryvolume_args(
4464     PRX_CONTEXT RxContext)
4465 {
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);
4471 }
4472 
4473 NTSTATUS map_volume_errors(
4474     DWORD status)
4475 {
4476     switch (status) {
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;
4482     default:
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;
4486     }
4487 }
4488 
4489 void nfs41_create_volume_info(PFILE_FS_VOLUME_INFORMATION pVolInfo, DWORD *len)
4490 {
4491     DECLARE_CONST_UNICODE_STRING(VolName, VOL_NAME);
4492 
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;
4499 }
4500 
4501 static BOOLEAN is_root_directory(
4502     PRX_CONTEXT RxContext)
4503 {
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);
4508 
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);
4513 
4514     return RxContext->CurrentIrpSp->FileObject->FileName.Length <= RootPathLen;
4515 }
4516 
4517 #ifdef __REACTOS__
4518 NTSTATUS NTAPI nfs41_QueryVolumeInformation(
4519 #else
4520 NTSTATUS nfs41_QueryVolumeInformation(
4521 #endif
4522     IN OUT PRX_CONTEXT RxContext)
4523 {
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);
4535 
4536 #ifdef ENABLE_TIMINGS
4537     LARGE_INTEGER t1, t2;
4538     t1 = KeQueryPerformanceCounter(NULL);
4539 #endif
4540 
4541 #ifdef DEBUG_VOLUME_QUERY
4542     DbgEn();
4543     print_queryvolume_args(RxContext);
4544 #endif
4545 
4546     status = check_nfs41_dirquery_args(RxContext);
4547     if (status) goto out;
4548 
4549 #ifdef __REACTOS__
4550     RtlZeroMemory(RxContext->Info.Buffer, RxContext->Info.LengthRemaining);
4551 #endif // __REACTOS__
4552 
4553     switch (InfoClass) {
4554     case FileFsVolumeInformation:
4555         if ((ULONG)RxContext->Info.LengthRemaining >= DevExt->VolAttrsLen) {
4556             RtlCopyMemory(RxContext->Info.Buffer, DevExt->VolAttrs,
4557                 DevExt->VolAttrsLen);
4558             RxContext->Info.LengthRemaining -= DevExt->VolAttrsLen;
4559             status = STATUS_SUCCESS;
4560         } else {
4561             RtlCopyMemory(RxContext->Info.Buffer, DevExt->VolAttrs,
4562                 RxContext->Info.LengthRemaining);
4563             status = STATUS_BUFFER_OVERFLOW;
4564         }
4565         goto out;
4566     case FileFsDeviceInformation:
4567     {
4568         PFILE_FS_DEVICE_INFORMATION pDevInfo = RxContext->Info.Buffer;
4569 
4570         SizeUsed = sizeof(FILE_FS_DEVICE_INFORMATION);
4571         if (RemainingLength < SizeUsed) {
4572             status = STATUS_BUFFER_TOO_SMALL;
4573             RxContext->InformationToReturn = SizeUsed;
4574             goto out;
4575         }
4576         pDevInfo->DeviceType = RxContext->pFcb->pNetRoot->DeviceType;
4577         pDevInfo->Characteristics = FILE_REMOTE_DEVICE | FILE_DEVICE_IS_MOUNTED;
4578         RxContext->Info.LengthRemaining -= SizeUsed;
4579         status = STATUS_SUCCESS;
4580         goto out;
4581     }
4582     case FileAccessInformation:
4583         status = STATUS_NOT_SUPPORTED;
4584         goto out;
4585 
4586     case FileFsAttributeInformation:
4587         if (RxContext->Info.LengthRemaining < FS_ATTR_LEN) {
4588             RxContext->InformationToReturn = FS_ATTR_LEN;
4589             status = STATUS_BUFFER_TOO_SMALL;
4590             goto out;
4591         }
4592 
4593         /* on attribute queries for the root directory,
4594          * use cached volume attributes from mount */
4595         if (is_root_directory(RxContext)) {
4596             PFILE_FS_ATTRIBUTE_INFORMATION attrs =
4597                 (PFILE_FS_ATTRIBUTE_INFORMATION)RxContext->Info.Buffer;
4598             DECLARE_CONST_UNICODE_STRING(FsName, FS_NAME);
4599 
4600             RtlCopyMemory(attrs, &pVNetRootContext->FsAttrs,
4601                 sizeof(pVNetRootContext->FsAttrs));
4602 
4603             /* fill in the FileSystemName */
4604             RtlCopyMemory(attrs->FileSystemName, FsName.Buffer,
4605                 FsName.MaximumLength); /* 'MaximumLength' to include null */
4606             attrs->FileSystemNameLength = FsName.Length;
4607 
4608             RxContext->Info.LengthRemaining -= FS_ATTR_LEN;
4609             goto out;
4610         }
4611         /* else fall through and send the upcall */
4612     case FileFsSizeInformation:
4613     case FileFsFullSizeInformation:
4614         break;
4615 
4616     default:
4617         print_error("nfs41_QueryVolumeInformation: unhandled class %d\n", InfoClass);
4618         status = STATUS_NOT_SUPPORTED;
4619         goto out;
4620     }
4621     status = nfs41_UpcallCreate(NFS41_VOLUME_QUERY, &nfs41_fobx->sec_ctx,
4622         pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
4623         pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
4624     if (status) goto out;
4625 
4626     entry->u.Volume.query = InfoClass;
4627     entry->buf = RxContext->Info.Buffer;
4628     entry->buf_len = RxContext->Info.LengthRemaining;
4629 
4630     status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
4631     if (status) goto out;
4632 
4633     if (entry->status == STATUS_BUFFER_TOO_SMALL) {
4634         RxContext->InformationToReturn = entry->buf_len;
4635         status = STATUS_BUFFER_TOO_SMALL;
4636     } else if (entry->status == STATUS_SUCCESS) {
4637         if (InfoClass == FileFsAttributeInformation) {
4638             /* fill in the FileSystemName */
4639             PFILE_FS_ATTRIBUTE_INFORMATION attrs =
4640                 (PFILE_FS_ATTRIBUTE_INFORMATION)RxContext->Info.Buffer;
4641             DECLARE_CONST_UNICODE_STRING(FsName, FS_NAME);
4642 
4643             RtlCopyMemory(attrs->FileSystemName, FsName.Buffer,
4644                 FsName.MaximumLength); /* 'MaximumLength' to include null */
4645             attrs->FileSystemNameLength = FsName.Length;
4646 
4647             entry->buf_len = FS_ATTR_LEN;
4648         }
4649 #ifdef ENABLE_TIMINGS
4650         InterlockedIncrement(&volume.sops);
4651         InterlockedAdd64(&volume.size, entry->u.Volume.buf_len);
4652 #endif
4653         RxContext->Info.LengthRemaining -= entry->buf_len;
4654         status = STATUS_SUCCESS;
4655     } else {
4656         status = map_volume_errors(entry->status);
4657     }
4658     RxFreePool(entry);
4659 out:
4660 #ifdef ENABLE_TIMINGS
4661     t2 = KeQueryPerformanceCounter(NULL);
4662     InterlockedIncrement(&volume.tops);
4663     InterlockedAdd64(&volume.ticks, t2.QuadPart - t1.QuadPart);
4664 #ifdef ENABLE_INDV_TIMINGS
4665     DbgP("nfs41_QueryVolumeInformation delta = %d op=%d sum=%d\n",
4666         t2.QuadPart - t1.QuadPart, volume.tops, volume.ticks);
4667 #endif
4668 #endif
4669 #ifdef DEBUG_VOLUME_QUERY
4670     DbgEx();
4671 #endif
4672     return status;
4673 }
4674 
4675 VOID nfs41_update_fcb_list(
4676     PMRX_FCB fcb,
4677     ULONGLONG ChangeTime)
4678 {
4679     PLIST_ENTRY pEntry;
4680     nfs41_fcb_list_entry *cur;
4681     ExAcquireFastMutex(&fcblistLock);
4682     pEntry = openlist.head.Flink;
4683     while (!IsListEmpty(&openlist.head)) {
4684         cur = (nfs41_fcb_list_entry *)CONTAINING_RECORD(pEntry,
4685                 nfs41_fcb_list_entry, next);
4686         if (cur->fcb == fcb &&
4687                 cur->ChangeTime != ChangeTime) {
4688 #if defined(DEBUG_FILE_SET) || defined(DEBUG_ACL_SET) || \
4689     defined(DEBUG_WRITE) || defined(DEBUG_EA_SET)
4690             DbgP("nfs41_update_fcb_list: Found match for fcb %p: updating "
4691                 "%llu to %llu\n", fcb, cur->ChangeTime, ChangeTime);
4692 #endif
4693             cur->ChangeTime = ChangeTime;
4694             break;
4695         }
4696         /* place an upcall for this srv_open */
4697         if (pEntry->Flink == &openlist.head) {
4698 #if defined(DEBUG_FILE_SET) || defined(DEBUG_ACL_SET) || \
4699     defined(DEBUG_WRITE) || defined(DEBUG_EA_SET)
4700             DbgP("nfs41_update_fcb_list: reached EOL loooking for "
4701                 "fcb=%p\n", fcb);
4702 #endif
4703             break;
4704         }
4705         pEntry = pEntry->Flink;
4706     }
4707     ExReleaseFastMutex(&fcblistLock);
4708 }
4709 
4710 void print_nfs3_attrs(
4711     nfs3_attrs *attrs)
4712 {
4713     DbgP("type=%d mode=%o nlink=%d size=%d atime=%x mtime=%x ctime=%x\n",
4714         attrs->type, attrs->mode, attrs->nlink, attrs->size, attrs->atime,
4715         attrs->mtime, attrs->ctime);
4716 }
4717 
4718 void file_time_to_nfs_time(
4719     IN const PLARGE_INTEGER file_time,
4720     OUT LONGLONG *nfs_time)
4721 {
4722     LARGE_INTEGER diff = unix_time_diff;
4723     diff.QuadPart = file_time->QuadPart - diff.QuadPart;
4724     *nfs_time = diff.QuadPart / 10000000;
4725 }
4726 
4727 void create_nfs3_attrs(
4728     nfs3_attrs *attrs,
4729     PNFS41_FCB nfs41_fcb)
4730 {
4731     RtlZeroMemory(attrs, sizeof(nfs3_attrs));
4732     if (nfs41_fcb->BasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
4733         attrs->type = NF3LNK;
4734     else if (nfs41_fcb->StandardInfo.Directory)
4735         attrs->type = NF3DIR;
4736     else
4737         attrs->type = NF3REG;
4738     attrs->mode = nfs41_fcb->mode;
4739     attrs->nlink = nfs41_fcb->StandardInfo.NumberOfLinks;
4740     attrs->size.QuadPart = attrs->used.QuadPart =
4741         nfs41_fcb->StandardInfo.EndOfFile.QuadPart;
4742     file_time_to_nfs_time(&nfs41_fcb->BasicInfo.LastAccessTime, &attrs->atime);
4743     file_time_to_nfs_time(&nfs41_fcb->BasicInfo.ChangeTime, &attrs->mtime);
4744     file_time_to_nfs_time(&nfs41_fcb->BasicInfo.CreationTime, &attrs->ctime);
4745 }
4746 
4747 
4748 NTSTATUS map_setea_error(
4749     DWORD error)
4750 {
4751     switch (error) {
4752     case NO_ERROR:                      return STATUS_SUCCESS;
4753     case ERROR_FILE_NOT_FOUND:          return STATUS_NO_EAS_ON_FILE;
4754     case ERROR_ACCESS_DENIED:           return STATUS_ACCESS_DENIED;
4755     case ERROR_NETWORK_ACCESS_DENIED:   return STATUS_NETWORK_ACCESS_DENIED;
4756     case ERROR_NETNAME_DELETED:         return STATUS_NETWORK_NAME_DELETED;
4757     case ERROR_FILE_TOO_LARGE:          return STATUS_EA_TOO_LARGE;
4758     case ERROR_BUFFER_OVERFLOW:         return STATUS_BUFFER_OVERFLOW;
4759     case STATUS_BUFFER_TOO_SMALL:
4760     case ERROR_INSUFFICIENT_BUFFER:     return STATUS_BUFFER_TOO_SMALL;
4761     case ERROR_INVALID_EA_HANDLE:       return STATUS_NONEXISTENT_EA_ENTRY;
4762     case ERROR_NO_MORE_FILES:           return STATUS_NO_MORE_EAS;
4763     case ERROR_EA_FILE_CORRUPT:         return STATUS_EA_CORRUPT_ERROR;
4764     default:
4765         print_error("failed to map windows error %d to NTSTATUS; "
4766             "defaulting to STATUS_INVALID_PARAMETER\n", error);
4767     case ERROR_INVALID_PARAMETER:       return STATUS_INVALID_PARAMETER;
4768     }
4769 }
4770 
4771 NTSTATUS check_nfs41_setea_args(
4772     IN PRX_CONTEXT RxContext)
4773 {
4774     NTSTATUS status;
4775     __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
4776         NFS41GetVNetRootExtension(RxContext->pRelevantSrvOpen->pVNetRoot);
4777     __notnull PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs =
4778         &pVNetRootContext->FsAttrs;
4779     __notnull PFILE_FULL_EA_INFORMATION ea =
4780         (PFILE_FULL_EA_INFORMATION)RxContext->Info.Buffer;
4781 
4782     status = check_nfs41_dirquery_args(RxContext);
4783     if (status) goto out;
4784 
4785     if (ea == NULL) {
4786         status = STATUS_INVALID_PARAMETER;
4787         goto out;
4788     }
4789     if (AnsiStrEq(&NfsActOnLink, ea->EaName, ea->EaNameLength) ||
4790         AnsiStrEq(&NfsSymlinkTargetName, ea->EaName, ea->EaNameLength)) {
4791         status = STATUS_INVALID_PARAMETER; /* only allowed on create */
4792         goto out;
4793     }
4794     /* ignore cygwin EAs when checking support */
4795     if (!(FsAttrs->FileSystemAttributes & FILE_SUPPORTS_EXTENDED_ATTRIBUTES)
4796         && !AnsiStrEq(&NfsV3Attributes, ea->EaName, ea->EaNameLength)) {
4797         status = STATUS_EAS_NOT_SUPPORTED;
4798         goto out;
4799     }
4800     if ((RxContext->pRelevantSrvOpen->DesiredAccess & FILE_WRITE_EA) == 0) {
4801         status = STATUS_ACCESS_DENIED;
4802         goto out;
4803     }
4804     if (pVNetRootContext->read_only) {
4805         print_error("check_nfs41_setattr_args: Read-only mount\n");
4806         status = STATUS_ACCESS_DENIED;
4807         goto out;
4808     }
4809 out:
4810     return status;
4811 }
4812 
4813 #ifdef __REACTOS__
4814 NTSTATUS NTAPI nfs41_SetEaInformation(
4815 #else
4816 NTSTATUS nfs41_SetEaInformation(
4817 #endif
4818     IN OUT PRX_CONTEXT RxContext)
4819 {
4820     NTSTATUS status = STATUS_EAS_NOT_SUPPORTED;
4821     nfs41_updowncall_entry *entry;
4822     __notnull PFILE_FULL_EA_INFORMATION eainfo =
4823         (PFILE_FULL_EA_INFORMATION)RxContext->Info.Buffer;
4824     nfs3_attrs *attrs = NULL;
4825     ULONG buflen = RxContext->CurrentIrpSp->Parameters.SetEa.Length, error_offset;
4826     __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
4827     __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
4828         NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
4829     __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
4830         NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
4831     __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
4832     __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
4833 #ifdef ENABLE_TIMINGS
4834     LARGE_INTEGER t1, t2;
4835     t1 = KeQueryPerformanceCounter(NULL);
4836 #endif
4837 
4838 #ifdef DEBUG_EA_SET
4839     DbgEn();
4840     print_debug_header(RxContext);
4841     print_ea_info(1, eainfo);
4842 #endif
4843 
4844     status = check_nfs41_setea_args(RxContext);
4845     if (status) goto out;
4846 
4847     status = nfs41_UpcallCreate(NFS41_EA_SET, &nfs41_fobx->sec_ctx,
4848         pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
4849         pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
4850     if (status) goto out;
4851 
4852     if (AnsiStrEq(&NfsV3Attributes, eainfo->EaName, eainfo->EaNameLength)) {
4853         attrs = (nfs3_attrs *)(eainfo->EaName + eainfo->EaNameLength + 1);
4854 #ifdef DEBUG_EA_SET
4855         print_nfs3_attrs(attrs);
4856         DbgP("old mode is %o new mode is %o\n", nfs41_fcb->mode, attrs->mode);
4857 #endif
4858         entry->u.SetEa.mode = attrs->mode;
4859     } else {
4860         entry->u.SetEa.mode = 0;
4861         status = IoCheckEaBufferValidity(eainfo, buflen, &error_offset);
4862         if (status) {
4863             RxFreePool(entry);
4864             goto out;
4865         }
4866     }
4867     entry->buf = eainfo;
4868     entry->buf_len = buflen;
4869 
4870     status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
4871     if (status) goto out;
4872 #ifdef ENABLE_TIMINGS
4873     if (entry->status == STATUS_SUCCESS) {
4874         InterlockedIncrement(&setexattr.sops);
4875         InterlockedAdd64(&setexattr.size, entry->u.SetEa.buf_len);
4876     }
4877 #endif
4878     status = map_setea_error(entry->status);
4879     if (!status) {
4880         if (!nfs41_fobx->deleg_type && entry->ChangeTime &&
4881                 (SrvOpen->DesiredAccess &
4882                 (FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA)))
4883             nfs41_update_fcb_list(RxContext->pFcb, entry->ChangeTime);
4884         nfs41_fcb->changeattr = entry->ChangeTime;
4885         nfs41_fcb->mode = entry->u.SetEa.mode;
4886     }
4887     RxFreePool(entry);
4888 out:
4889 #ifdef ENABLE_TIMINGS
4890     t2 = KeQueryPerformanceCounter(NULL);
4891     InterlockedIncrement(&setexattr.tops);
4892     InterlockedAdd64(&setexattr.ticks, t2.QuadPart - t1.QuadPart);
4893 #ifdef ENABLE_INDV_TIMINGS
4894     DbgP("nfs41_SetEaInformation delta = %d op=%d sum=%d\n",
4895         t2.QuadPart - t1.QuadPart, setexattr.tops, setexattr.ticks);
4896 #endif
4897 #endif
4898 #ifdef DEBUG_EA_SET
4899     DbgEx();
4900 #endif
4901     return status;
4902 }
4903 
4904 NTSTATUS check_nfs41_queryea_args(
4905     IN PRX_CONTEXT RxContext)
4906 {
4907     NTSTATUS status;
4908     __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
4909         NFS41GetVNetRootExtension(RxContext->pRelevantSrvOpen->pVNetRoot);
4910     __notnull PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs =
4911         &pVNetRootContext->FsAttrs;
4912     PFILE_GET_EA_INFORMATION ea = (PFILE_GET_EA_INFORMATION)
4913             RxContext->CurrentIrpSp->Parameters.QueryEa.EaList;
4914 
4915     status = check_nfs41_dirquery_args(RxContext);
4916     if (status) goto out;
4917 
4918     if (!(FsAttrs->FileSystemAttributes & FILE_SUPPORTS_EXTENDED_ATTRIBUTES)) {
4919         if (ea == NULL) {
4920             status = STATUS_EAS_NOT_SUPPORTED;
4921             goto out;
4922         }
4923         /* ignore cygwin EAs when checking support */
4924         if (!AnsiStrEq(&NfsV3Attributes, ea->EaName, ea->EaNameLength) &&
4925             !AnsiStrEq(&NfsActOnLink, ea->EaName, ea->EaNameLength) &&
4926             !AnsiStrEq(&NfsSymlinkTargetName, ea->EaName, ea->EaNameLength)) {
4927             status = STATUS_EAS_NOT_SUPPORTED;
4928             goto out;
4929         }
4930     }
4931     if ((RxContext->pRelevantSrvOpen->DesiredAccess & FILE_READ_EA) == 0) {
4932         status = STATUS_ACCESS_DENIED;
4933         goto out;
4934     }
4935 out:
4936     return status;
4937 }
4938 
4939 static NTSTATUS QueryCygwinSymlink(
4940     IN OUT PRX_CONTEXT RxContext,
4941     IN PFILE_GET_EA_INFORMATION query,
4942     OUT PFILE_FULL_EA_INFORMATION info)
4943 {
4944     __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
4945     __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext =
4946             NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
4947     __notnull PNFS41_NETROOT_EXTENSION NetRootContext =
4948             NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
4949     __notnull PNFS41_FOBX Fobx = NFS41GetFobxExtension(RxContext->pFobx);
4950     nfs41_updowncall_entry *entry;
4951     UNICODE_STRING TargetName;
4952     const USHORT HeaderLen = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) +
4953         query->EaNameLength + 1;
4954     NTSTATUS status;
4955 
4956     if (RxContext->Info.LengthRemaining < HeaderLen) {
4957         status = STATUS_BUFFER_TOO_SMALL;
4958         RxContext->InformationToReturn = HeaderLen;
4959         goto out;
4960     }
4961 
4962     TargetName.Buffer = (PWCH)(info->EaName + query->EaNameLength + 1);
4963     TargetName.MaximumLength = (USHORT)min(RxContext->Info.LengthRemaining -
4964         HeaderLen, 0xFFFF);
4965 
4966     status = nfs41_UpcallCreate(NFS41_SYMLINK, &Fobx->sec_ctx,
4967         VNetRootContext->session, Fobx->nfs41_open_state,
4968         NetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
4969     if (status) goto out;
4970 
4971     entry->u.Symlink.target = &TargetName;
4972     entry->u.Symlink.set = FALSE;
4973 
4974     status = nfs41_UpcallWaitForReply(entry, VNetRootContext->timeout);
4975     if (status) goto out;
4976 
4977     status = map_setea_error(entry->status);
4978     if (status == STATUS_SUCCESS) {
4979         info->NextEntryOffset = 0;
4980         info->Flags = 0;
4981         info->EaNameLength = query->EaNameLength;
4982         info->EaValueLength = TargetName.Length - sizeof(UNICODE_NULL);
4983         TargetName.Buffer[TargetName.Length/sizeof(WCHAR)] = UNICODE_NULL;
4984         RtlCopyMemory(info->EaName, query->EaName, query->EaNameLength);
4985         RxContext->Info.LengthRemaining = HeaderLen + info->EaValueLength;
4986     } else if (status == STATUS_BUFFER_TOO_SMALL) {
4987         RxContext->InformationToReturn = HeaderLen +
4988             entry->u.Symlink.target->Length;
4989     }
4990     RxFreePool(entry);
4991 out:
4992     return status;
4993 }
4994 
4995 static NTSTATUS QueryCygwinEA(
4996     IN OUT PRX_CONTEXT RxContext,
4997     IN PFILE_GET_EA_INFORMATION query,
4998     OUT PFILE_FULL_EA_INFORMATION info)
4999 {
5000     NTSTATUS status = STATUS_NONEXISTENT_EA_ENTRY;
5001 
5002     if (query == NULL)
5003         goto out;
5004 
5005     if (AnsiStrEq(&NfsSymlinkTargetName, query->EaName, query->EaNameLength)) {
5006         __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
5007         if (nfs41_fcb->BasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
5008             status = QueryCygwinSymlink(RxContext, query, info);
5009             goto out;
5010         } else {
5011             const LONG LengthRequired = sizeof(FILE_FULL_EA_INFORMATION) +
5012                 NfsSymlinkTargetName.Length - sizeof(CHAR);
5013             if (LengthRequired > RxContext->Info.LengthRemaining) {
5014                 status = STATUS_BUFFER_TOO_SMALL;
5015                 RxContext->InformationToReturn = LengthRequired;
5016                 goto out;
5017             }
5018             info->NextEntryOffset = 0;
5019             info->Flags = 0;
5020             info->EaValueLength = 0;
5021             info->EaNameLength = (UCHAR)NfsActOnLink.Length;
5022             RtlCopyMemory(info->EaName, NfsSymlinkTargetName.Buffer,
5023                 NfsSymlinkTargetName.Length);
5024             RxContext->Info.LengthRemaining = LengthRequired;
5025             status = STATUS_SUCCESS;
5026             goto out;
5027         }
5028     }
5029 
5030     if (AnsiStrEq(&NfsV3Attributes, query->EaName, query->EaNameLength)) {
5031         nfs3_attrs attrs;
5032 
5033         const LONG LengthRequired = sizeof(FILE_FULL_EA_INFORMATION) +
5034             NfsV3Attributes.Length + sizeof(nfs3_attrs) - sizeof(CHAR);
5035         if (LengthRequired > RxContext->Info.LengthRemaining) {
5036             status = STATUS_BUFFER_TOO_SMALL;
5037             RxContext->InformationToReturn = LengthRequired;
5038             goto out;
5039         }
5040 
5041         create_nfs3_attrs(&attrs, NFS41GetFcbExtension(RxContext->pFcb));
5042 #ifdef DEBUG_EA_QUERY
5043         print_nfs3_attrs(&attrs);
5044 #endif
5045 
5046         info->NextEntryOffset = 0;
5047         info->Flags = 0;
5048         info->EaNameLength = (UCHAR)NfsV3Attributes.Length;
5049         info->EaValueLength = sizeof(nfs3_attrs);
5050         RtlCopyMemory(info->EaName, NfsV3Attributes.Buffer,
5051             NfsV3Attributes.Length);
5052         RtlCopyMemory(info->EaName + info->EaNameLength + 1, &attrs,
5053             sizeof(nfs3_attrs));
5054         RxContext->Info.LengthRemaining = LengthRequired;
5055         status = STATUS_SUCCESS;
5056         goto out;
5057     }
5058 
5059     if (AnsiStrEq(&NfsActOnLink, query->EaName, query->EaNameLength)) {
5060 
5061         const LONG LengthRequired = sizeof(FILE_FULL_EA_INFORMATION) +
5062             query->EaNameLength - sizeof(CHAR);
5063         if (LengthRequired > RxContext->Info.LengthRemaining) {
5064             status = STATUS_BUFFER_TOO_SMALL;
5065             RxContext->InformationToReturn = LengthRequired;
5066             goto out;
5067         }
5068 
5069         info->NextEntryOffset = 0;
5070         info->Flags = 0;
5071         info->EaNameLength = query->EaNameLength;
5072         info->EaValueLength = 0;
5073         RtlCopyMemory(info->EaName, query->EaName, query->EaNameLength);
5074         RxContext->Info.LengthRemaining = LengthRequired;
5075         status = STATUS_SUCCESS;
5076         goto out;
5077     }
5078 out:
5079     return status;
5080 }
5081 
5082 #ifdef __REACTOS__
5083 NTSTATUS NTAPI nfs41_QueryEaInformation(
5084 #else
5085 NTSTATUS nfs41_QueryEaInformation(
5086 #endif
5087     IN OUT PRX_CONTEXT RxContext)
5088 {
5089     NTSTATUS status = STATUS_EAS_NOT_SUPPORTED;
5090     nfs41_updowncall_entry *entry;
5091     PFILE_GET_EA_INFORMATION query = (PFILE_GET_EA_INFORMATION)
5092             RxContext->CurrentIrpSp->Parameters.QueryEa.EaList;
5093     ULONG buflen = RxContext->CurrentIrpSp->Parameters.QueryEa.Length;
5094     __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
5095     __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
5096             NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
5097     __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
5098             NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
5099     __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
5100 #ifdef ENABLE_TIMINGS
5101     LARGE_INTEGER t1, t2;
5102     t1 = KeQueryPerformanceCounter(NULL);
5103 #endif
5104 
5105 #ifdef DEBUG_EA_QUERY
5106     DbgEn();
5107     print_debug_header(RxContext);
5108     print_get_ea(1, query);
5109 #endif
5110     status = check_nfs41_queryea_args(RxContext);
5111     if (status) goto out;
5112 
5113     /* handle queries for cygwin EAs */
5114     status = QueryCygwinEA(RxContext, query,
5115         (PFILE_FULL_EA_INFORMATION)RxContext->Info.Buffer);
5116     if (status != STATUS_NONEXISTENT_EA_ENTRY)
5117         goto out;
5118 
5119     status = nfs41_UpcallCreate(NFS41_EA_GET, &nfs41_fobx->sec_ctx,
5120         pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
5121         pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
5122     if (status) goto out;
5123 
5124     entry->buf_len = buflen;
5125     entry->buf = RxContext->Info.Buffer;
5126     entry->u.QueryEa.EaList = query;
5127     entry->u.QueryEa.EaListLength = query == NULL ? 0 :
5128         RxContext->QueryEa.UserEaListLength;
5129     entry->u.QueryEa.EaIndex = RxContext->QueryEa.IndexSpecified ?
5130         RxContext->QueryEa.UserEaIndex : 0;
5131     entry->u.QueryEa.RestartScan = RxContext->QueryEa.RestartScan;
5132     entry->u.QueryEa.ReturnSingleEntry = RxContext->QueryEa.ReturnSingleEntry;
5133 
5134     status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
5135     if (status) goto out;
5136 
5137     if (entry->status == STATUS_SUCCESS) {
5138         switch (entry->u.QueryEa.Overflow) {
5139         case ERROR_INSUFFICIENT_BUFFER:
5140             status = STATUS_BUFFER_TOO_SMALL;
5141             break;
5142         case ERROR_BUFFER_OVERFLOW:
5143             status = RxContext->IoStatusBlock.Status = STATUS_BUFFER_OVERFLOW;
5144             break;
5145         default:
5146             RxContext->IoStatusBlock.Status = STATUS_SUCCESS;
5147             break;
5148         }
5149         RxContext->InformationToReturn = entry->buf_len;
5150 #ifdef ENABLE_TIMINGS
5151         InterlockedIncrement(&getexattr.sops);
5152         InterlockedAdd64(&getexattr.size, entry->u.QueryEa.buf_len);
5153 #endif
5154     } else {
5155         status = map_setea_error(entry->status);
5156     }
5157     RxFreePool(entry);
5158 out:
5159 #ifdef ENABLE_TIMINGS
5160     t2 = KeQueryPerformanceCounter(NULL);
5161     InterlockedIncrement(&getexattr.tops);
5162     InterlockedAdd64(&getexattr.ticks, t2.QuadPart - t1.QuadPart);
5163 #ifdef ENABLE_INDV_TIMINGS
5164     DbgP("nfs41_QueryEaInformation delta = %d op=%d sum=%d\n",
5165         t2.QuadPart - t1.QuadPart, getexattr.tops, getexattr.ticks);
5166 #endif
5167 #endif
5168 #ifdef DEBUG_EA_QUERY
5169     DbgEx();
5170 #endif
5171     return status;
5172 }
5173 
5174 NTSTATUS map_query_acl_error(
5175     DWORD error)
5176 {
5177     switch (error) {
5178     case NO_ERROR:                  return STATUS_SUCCESS;
5179     case ERROR_NOT_SUPPORTED:       return STATUS_NOT_SUPPORTED;
5180     case ERROR_ACCESS_DENIED:       return STATUS_ACCESS_DENIED;
5181     case ERROR_FILE_NOT_FOUND:      return STATUS_OBJECT_NAME_NOT_FOUND;
5182     case ERROR_INVALID_PARAMETER:   return STATUS_INVALID_PARAMETER;
5183     default:
5184         print_error("failed to map windows error %d to NTSTATUS; "
5185             "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", error);
5186     case ERROR_BAD_NET_RESP:        return STATUS_INVALID_NETWORK_RESPONSE;
5187     }
5188 }
5189 
5190 NTSTATUS check_nfs41_getacl_args(
5191     PRX_CONTEXT RxContext)
5192 {
5193     NTSTATUS status = STATUS_SUCCESS;
5194     SECURITY_INFORMATION info_class =
5195         RxContext->CurrentIrpSp->Parameters.QuerySecurity.SecurityInformation;
5196 
5197     /* we don't support sacls */
5198     if (info_class == SACL_SECURITY_INFORMATION ||
5199             info_class == LABEL_SECURITY_INFORMATION) {
5200         status = STATUS_NOT_SUPPORTED;
5201         goto out;
5202     }
5203     if (RxContext->CurrentIrp->UserBuffer == NULL &&
5204             RxContext->CurrentIrpSp->Parameters.QuerySecurity.Length)
5205         status = STATUS_INVALID_USER_BUFFER;
5206 out:
5207     return status;
5208 }
5209 
5210 #ifdef __REACTOS__
5211 NTSTATUS NTAPI nfs41_QuerySecurityInformation(
5212 #else
5213 NTSTATUS nfs41_QuerySecurityInformation(
5214 #endif
5215     IN OUT PRX_CONTEXT RxContext)
5216 {
5217     NTSTATUS status = STATUS_NOT_SUPPORTED;
5218     nfs41_updowncall_entry *entry;
5219     __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
5220     __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
5221     __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
5222         NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
5223     __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
5224         NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
5225     SECURITY_INFORMATION info_class =
5226         RxContext->CurrentIrpSp->Parameters.QuerySecurity.SecurityInformation;
5227 #ifdef ENABLE_TIMINGS
5228     LARGE_INTEGER t1, t2;
5229     t1 = KeQueryPerformanceCounter(NULL);
5230 #endif
5231 
5232 #ifdef DEBUG_ACL_QUERY
5233     DbgEn();
5234     print_debug_header(RxContext);
5235     print_acl_args(info_class);
5236 #endif
5237 
5238     status = check_nfs41_getacl_args(RxContext);
5239     if (status) goto out;
5240 
5241     if (nfs41_fobx->acl && nfs41_fobx->acl_len) {
5242         LARGE_INTEGER current_time;
5243         KeQuerySystemTime(&current_time);
5244 #ifdef DEBUG_ACL_QUERY
5245         DbgP("CurrentTime %lx Saved Acl time %lx\n",
5246             current_time.QuadPart, nfs41_fobx->time.QuadPart);
5247 #endif
5248         if (current_time.QuadPart - nfs41_fobx->time.QuadPart <= 20*1000) {
5249             PSECURITY_DESCRIPTOR sec_desc = (PSECURITY_DESCRIPTOR)
5250                 RxContext->CurrentIrp->UserBuffer;
5251             RtlCopyMemory(sec_desc, nfs41_fobx->acl, nfs41_fobx->acl_len);
5252             RxContext->IoStatusBlock.Information =
5253                 RxContext->InformationToReturn = nfs41_fobx->acl_len;
5254             RxContext->IoStatusBlock.Status = status = STATUS_SUCCESS;
5255 #ifdef ENABLE_TIMINGS
5256             InterlockedIncrement(&getacl.sops);
5257             InterlockedAdd64(&getacl.size, nfs41_fobx->acl_len);
5258 #endif
5259         } else status = 1;
5260         RxFreePool(nfs41_fobx->acl);
5261         nfs41_fobx->acl = NULL;
5262         nfs41_fobx->acl_len = 0;
5263         if (!status)
5264             goto out;
5265     }
5266 
5267     status = nfs41_UpcallCreate(NFS41_ACL_QUERY, &nfs41_fobx->sec_ctx,
5268         pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
5269         pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
5270     if (status) goto out;
5271 
5272     entry->u.Acl.query = info_class;
5273     /* we can't provide RxContext->CurrentIrp->UserBuffer to the upcall thread
5274      * because it becomes an invalid pointer with that execution context
5275      */
5276     entry->buf_len = RxContext->CurrentIrpSp->Parameters.QuerySecurity.Length;
5277 
5278     status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
5279     if (status) goto out;
5280 
5281     if (entry->status == STATUS_BUFFER_TOO_SMALL) {
5282 #ifdef DEBUG_ACL_QUERY
5283         DbgP("nfs41_QuerySecurityInformation: provided buffer size=%d but we "
5284              "need %lu\n",
5285              RxContext->CurrentIrpSp->Parameters.QuerySecurity.Length,
5286              entry->buf_len);
5287 #endif
5288         status = STATUS_BUFFER_OVERFLOW;
5289         RxContext->InformationToReturn = entry->buf_len;
5290 
5291         /* Save ACL buffer */
5292         nfs41_fobx->acl = entry->buf;
5293         nfs41_fobx->acl_len = entry->buf_len;
5294         KeQuerySystemTime(&nfs41_fobx->time);
5295     } else if (entry->status == STATUS_SUCCESS) {
5296         PSECURITY_DESCRIPTOR sec_desc = (PSECURITY_DESCRIPTOR)
5297             RxContext->CurrentIrp->UserBuffer;
5298         RtlCopyMemory(sec_desc, entry->buf, entry->buf_len);
5299 #ifdef ENABLE_TIMINGS
5300         InterlockedIncrement(&getacl.sops);
5301         InterlockedAdd64(&getacl.size, entry->u.Acl.buf_len);
5302 #endif
5303         RxFreePool(entry->buf);
5304         nfs41_fobx->acl = NULL;
5305         nfs41_fobx->acl_len = 0;
5306         RxContext->IoStatusBlock.Information = RxContext->InformationToReturn =
5307             entry->buf_len;
5308         RxContext->IoStatusBlock.Status = status = STATUS_SUCCESS;
5309     } else {
5310         status = map_query_acl_error(entry->status);
5311     }
5312     RxFreePool(entry);
5313 out:
5314 #ifdef ENABLE_TIMINGS
5315     t2 = KeQueryPerformanceCounter(NULL);
5316     /* only count getacl that we made an upcall for */
5317     if (status == STATUS_BUFFER_OVERFLOW) {
5318         InterlockedIncrement(&getacl.tops);
5319         InterlockedAdd64(&getacl.ticks, t2.QuadPart - t1.QuadPart);
5320     }
5321 #ifdef ENABLE_INDV_TIMINGS
5322     DbgP("nfs41_QuerySecurityInformation: delta = %d op=%d sum=%d\n",
5323         t2.QuadPart - t1.QuadPart, getacl.tops, getacl.ticks);
5324 #endif
5325 #endif
5326 #ifdef DEBUG_ACL_QUERY
5327     DbgEx();
5328 #endif
5329     return status;
5330 }
5331 
5332 NTSTATUS check_nfs41_setacl_args(
5333     PRX_CONTEXT RxContext)
5334 {
5335     NTSTATUS status = STATUS_SUCCESS;
5336     __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
5337         NFS41GetVNetRootExtension(RxContext->pRelevantSrvOpen->pVNetRoot);
5338     SECURITY_INFORMATION info_class =
5339         RxContext->CurrentIrpSp->Parameters.SetSecurity.SecurityInformation;
5340 
5341     if (pVNetRootContext->read_only) {
5342         print_error("check_nfs41_setacl_args: Read-only mount\n");
5343         status = STATUS_ACCESS_DENIED;
5344         goto out;
5345     }
5346     /* we don't support sacls */
5347     if (info_class == SACL_SECURITY_INFORMATION  ||
5348             info_class == LABEL_SECURITY_INFORMATION) {
5349         status = STATUS_NOT_SUPPORTED;
5350         goto out;
5351     }
5352 out:
5353     return status;
5354 }
5355 
5356 #ifdef __REACTOS__
5357 NTSTATUS NTAPI nfs41_SetSecurityInformation(
5358 #else
5359 NTSTATUS nfs41_SetSecurityInformation(
5360 #endif
5361     IN OUT PRX_CONTEXT RxContext)
5362 {
5363     NTSTATUS status = STATUS_NOT_SUPPORTED;
5364     nfs41_updowncall_entry *entry;
5365     __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
5366     __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
5367     __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
5368         NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
5369     __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
5370         NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
5371     __notnull PSECURITY_DESCRIPTOR sec_desc =
5372         RxContext->CurrentIrpSp->Parameters.SetSecurity.SecurityDescriptor;
5373     __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
5374     SECURITY_INFORMATION info_class =
5375         RxContext->CurrentIrpSp->Parameters.SetSecurity.SecurityInformation;
5376 #ifdef ENABLE_TIMINGS
5377     LARGE_INTEGER t1, t2;
5378     t1 = KeQueryPerformanceCounter(NULL);
5379 #endif
5380 
5381 #ifdef DEBUG_ACL_SET
5382     DbgEn();
5383     print_debug_header(RxContext);
5384     print_acl_args(info_class);
5385 #endif
5386 
5387     status = check_nfs41_setacl_args(RxContext);
5388     if (status) goto out;
5389 
5390     /* check that ACL is present */
5391     if (info_class & DACL_SECURITY_INFORMATION) {
5392         PACL acl;
5393         BOOLEAN present, dacl_default;
5394         status = RtlGetDaclSecurityDescriptor(sec_desc, &present, &acl,
5395                     &dacl_default);
5396         if (status) {
5397             DbgP("RtlGetDaclSecurityDescriptor failed %x\n", status);
5398             goto out;
5399         }
5400         if (present == FALSE) {
5401             DbgP("NO ACL present\n");
5402             goto out;
5403         }
5404     }
5405 
5406     status = nfs41_UpcallCreate(NFS41_ACL_SET, &nfs41_fobx->sec_ctx,
5407         pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
5408         pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
5409     if (status) goto out;
5410 
5411     entry->u.Acl.query = info_class;
5412     entry->buf = sec_desc;
5413     entry->buf_len = RtlLengthSecurityDescriptor(sec_desc);
5414 #ifdef ENABLE_TIMINGS
5415     InterlockedIncrement(&setacl.sops);
5416     InterlockedAdd64(&setacl.size, entry->u.Acl.buf_len);
5417 #endif
5418 
5419     status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
5420     if (status) goto out;
5421 
5422     status = map_query_acl_error(entry->status);
5423     if (!status) {
5424         if (!nfs41_fobx->deleg_type && entry->ChangeTime &&
5425                 (SrvOpen->DesiredAccess &
5426                 (FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA)))
5427             nfs41_update_fcb_list(RxContext->pFcb, entry->ChangeTime);
5428         nfs41_fcb->changeattr = entry->ChangeTime;
5429     }
5430     RxFreePool(entry);
5431 out:
5432 #ifdef ENABLE_TIMINGS
5433     t2 = KeQueryPerformanceCounter(NULL);
5434     InterlockedIncrement(&setacl.tops);
5435     InterlockedAdd64(&setacl.ticks, t2.QuadPart - t1.QuadPart);
5436 #ifdef ENABLE_INDV_TIMINGS
5437     DbgP("nfs41_SetSecurityInformation delta = %d op=%d sum=%d\n",
5438         t2.QuadPart - t1.QuadPart, setacl.tops, setacl.ticks);
5439 #endif
5440 #endif
5441 #ifdef DEBUG_ACL_SET
5442     DbgEx();
5443 #endif
5444     return status;
5445 }
5446 
5447 NTSTATUS map_queryfile_error(
5448     DWORD error)
5449 {
5450     switch (error) {
5451     case ERROR_ACCESS_DENIED:       return STATUS_ACCESS_DENIED;
5452     case ERROR_NETNAME_DELETED:     return STATUS_NETWORK_NAME_DELETED;
5453     case ERROR_INVALID_PARAMETER:   return STATUS_INVALID_PARAMETER;
5454     default:
5455         print_error("failed to map windows error %d to NTSTATUS; "
5456             "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", error);
5457     case ERROR_BAD_NET_RESP:        return STATUS_INVALID_NETWORK_RESPONSE;
5458     }
5459 }
5460 
5461 #ifdef __REACTOS__
5462 NTSTATUS NTAPI nfs41_QueryFileInformation(
5463 #else
5464 NTSTATUS nfs41_QueryFileInformation(
5465 #endif
5466     IN OUT PRX_CONTEXT RxContext)
5467 {
5468     NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
5469     FILE_INFORMATION_CLASS InfoClass = RxContext->Info.FileInformationClass;
5470     nfs41_updowncall_entry *entry;
5471     __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
5472     __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
5473         NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
5474     __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
5475         NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
5476     __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
5477     __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
5478 #ifdef ENABLE_TIMINGS
5479     LARGE_INTEGER t1, t2;
5480     t1 = KeQueryPerformanceCounter(NULL);
5481 #endif
5482 
5483 #ifdef DEBUG_FILE_QUERY
5484     DbgEn();
5485     print_debug_filedirquery_header(RxContext);
5486 #endif
5487 
5488     status = check_nfs41_dirquery_args(RxContext);
5489     if (status) goto out;
5490 
5491     switch (InfoClass) {
5492     case FileEaInformation:
5493     {
5494         PFILE_EA_INFORMATION info =
5495             (PFILE_EA_INFORMATION)RxContext->Info.Buffer;
5496         info->EaSize = 0;
5497         RxContext->Info.LengthRemaining -= sizeof(FILE_EA_INFORMATION);
5498         status = STATUS_SUCCESS;
5499         goto out;
5500     }
5501     case FileBasicInformation:
5502     case FileStandardInformation:
5503     case FileInternalInformation:
5504     case FileAttributeTagInformation:
5505     case FileNetworkOpenInformation:
5506         break;
5507     default:
5508         print_error("nfs41_QueryFileInformation: unhandled class %d\n", InfoClass);
5509         status = STATUS_NOT_SUPPORTED;
5510         goto out;
5511     }
5512 
5513     status = nfs41_UpcallCreate(NFS41_FILE_QUERY, &nfs41_fobx->sec_ctx,
5514         pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
5515         pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
5516     if (status) goto out;
5517 
5518     entry->u.QueryFile.InfoClass = InfoClass;
5519     entry->buf = RxContext->Info.Buffer;
5520     entry->buf_len = RxContext->Info.LengthRemaining;
5521 
5522     status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
5523     if (status) goto out;
5524 
5525     if (entry->status == STATUS_BUFFER_TOO_SMALL) {
5526         RxContext->InformationToReturn = entry->buf_len;
5527         status = STATUS_BUFFER_TOO_SMALL;
5528     } else if (entry->status == STATUS_SUCCESS) {
5529         BOOLEAN DeletePending = FALSE;
5530 #ifdef ENABLE_TIMINGS
5531         InterlockedIncrement(&getattr.sops);
5532         InterlockedAdd64(&getattr.size, entry->u.QueryFile.buf_len);
5533 #endif
5534         RxContext->Info.LengthRemaining -= entry->buf_len;
5535         status = STATUS_SUCCESS;
5536 
5537         switch (InfoClass) {
5538         case FileBasicInformation:
5539             RtlCopyMemory(&nfs41_fcb->BasicInfo, RxContext->Info.Buffer,
5540                 sizeof(nfs41_fcb->BasicInfo));
5541 #ifdef DEBUG_FILE_QUERY
5542             print_basic_info(1, &nfs41_fcb->BasicInfo);
5543 #endif
5544             break;
5545         case FileStandardInformation:
5546             /* this a fix for RDBSS behaviour when it first calls ExtendForCache,
5547              * then it sends a file query irp for standard attributes and
5548              * expects to receive EndOfFile of value set by the ExtendForCache.
5549              * It seems to cache the filesize based on that instead of sending
5550              * a file size query for after doing the write.
5551              */
5552         {
5553             PFILE_STANDARD_INFORMATION std_info;
5554             std_info = (PFILE_STANDARD_INFORMATION)RxContext->Info.Buffer;
5555             if (nfs41_fcb->StandardInfo.AllocationSize.QuadPart >
5556                     std_info->AllocationSize.QuadPart) {
5557 #ifdef DEBUG_FILE_QUERY
5558                 DbgP("Old AllocationSize is bigger: saving %x\n",
5559                     nfs41_fcb->StandardInfo.AllocationSize.QuadPart);
5560 #endif
5561                 std_info->AllocationSize.QuadPart =
5562                     nfs41_fcb->StandardInfo.AllocationSize.QuadPart;
5563             }
5564             if (nfs41_fcb->StandardInfo.EndOfFile.QuadPart >
5565                     std_info->EndOfFile.QuadPart) {
5566 #ifdef DEBUG_FILE_QUERY
5567                 DbgP("Old EndOfFile is bigger: saving %x\n",
5568                     nfs41_fcb->StandardInfo.EndOfFile);
5569 #endif
5570                 std_info->EndOfFile.QuadPart =
5571                     nfs41_fcb->StandardInfo.EndOfFile.QuadPart;
5572             }
5573             std_info->DeletePending = nfs41_fcb->DeletePending;
5574         }
5575             if (nfs41_fcb->StandardInfo.DeletePending)
5576                 DeletePending = TRUE;
5577             RtlCopyMemory(&nfs41_fcb->StandardInfo, RxContext->Info.Buffer,
5578                 sizeof(nfs41_fcb->StandardInfo));
5579             nfs41_fcb->StandardInfo.DeletePending = DeletePending;
5580 #ifdef DEBUG_FILE_QUERY
5581             print_std_info(1, &nfs41_fcb->StandardInfo);
5582 #endif
5583             break;
5584         }
5585     } else {
5586         status = map_queryfile_error(entry->status);
5587     }
5588     RxFreePool(entry);
5589 out:
5590 #ifdef ENABLE_TIMINGS
5591     t2 = KeQueryPerformanceCounter(NULL);
5592     InterlockedIncrement(&getattr.tops);
5593     InterlockedAdd64(&getattr.ticks, t2.QuadPart - t1.QuadPart);
5594 #ifdef ENABLE_INDV_TIMINGS
5595     DbgP("nfs41_QueryFileInformation delta = %d op=%d sum=%d\n",
5596         t2.QuadPart - t1.QuadPart, getattr.tops, getattr.ticks);
5597 #endif
5598 #endif
5599 #ifdef DEBUG_FILE_QUERY
5600     DbgEx();
5601 #endif
5602     return status;
5603 }
5604 
5605 NTSTATUS map_setfile_error(
5606     DWORD error)
5607 {
5608     switch (error) {
5609     case NO_ERROR:                      return STATUS_SUCCESS;
5610     case ERROR_NOT_EMPTY:               return STATUS_DIRECTORY_NOT_EMPTY;
5611     case ERROR_FILE_EXISTS:             return STATUS_OBJECT_NAME_COLLISION;
5612     case ERROR_FILE_NOT_FOUND:          return STATUS_OBJECT_NAME_NOT_FOUND;
5613     case ERROR_PATH_NOT_FOUND:          return STATUS_OBJECT_PATH_NOT_FOUND;
5614     case ERROR_ACCESS_DENIED:           return STATUS_ACCESS_DENIED;
5615     case ERROR_FILE_INVALID:            return STATUS_FILE_INVALID;
5616     case ERROR_NOT_SAME_DEVICE:         return STATUS_NOT_SAME_DEVICE;
5617     case ERROR_NOT_SUPPORTED:           return STATUS_NOT_IMPLEMENTED;
5618     case ERROR_NETWORK_ACCESS_DENIED:   return STATUS_NETWORK_ACCESS_DENIED;
5619     case ERROR_NETNAME_DELETED:         return STATUS_NETWORK_NAME_DELETED;
5620     case ERROR_BUFFER_OVERFLOW:         return STATUS_INSUFFICIENT_RESOURCES;
5621     default:
5622         print_error("failed to map windows error %d to NTSTATUS; "
5623             "defaulting to STATUS_INVALID_PARAMETER\n", error);
5624     case ERROR_INVALID_PARAMETER:       return STATUS_INVALID_PARAMETER;
5625     }
5626 }
5627 
5628 NTSTATUS check_nfs41_setattr_args(
5629     IN PRX_CONTEXT RxContext)
5630 {
5631     NTSTATUS status = STATUS_SUCCESS;
5632     FILE_INFORMATION_CLASS InfoClass = RxContext->Info.FileInformationClass;
5633     __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
5634         NFS41GetVNetRootExtension(RxContext->pRelevantSrvOpen->pVNetRoot);
5635 
5636     if (pVNetRootContext->read_only) {
5637         print_error("check_nfs41_setattr_args: Read-only mount\n");
5638         status = STATUS_ACCESS_DENIED;
5639         goto out;
5640     }
5641 
5642     /* http://msdn.microsoft.com/en-us/library/ff469355(v=PROT.10).aspx
5643      * http://msdn.microsoft.com/en-us/library/ff469424(v=PROT.10).aspx
5644      * If Open.GrantedAccess does not contain FILE_WRITE_DATA, the operation
5645      * MUST be failed with STATUS_ACCESS_DENIED.
5646      */
5647     if (InfoClass == FileAllocationInformation ||
5648             InfoClass == FileEndOfFileInformation) {
5649         if (!(RxContext->pRelevantSrvOpen->DesiredAccess & FILE_WRITE_DATA)) {
5650             status = STATUS_ACCESS_DENIED;
5651             goto out;
5652         }
5653     }
5654     status = check_nfs41_dirquery_args(RxContext);
5655     if (status) goto out;
5656 
5657     switch (InfoClass) {
5658     case FileRenameInformation:
5659     {
5660         PFILE_RENAME_INFORMATION rinfo =
5661             (PFILE_RENAME_INFORMATION)RxContext->Info.Buffer;
5662         UNICODE_STRING dst = { (USHORT)rinfo->FileNameLength,
5663             (USHORT)rinfo->FileNameLength, rinfo->FileName };
5664 #ifdef DEBUG_FILE_SET
5665         DbgP("Attempting to rename to '%wZ'\n", &dst);
5666 #endif
5667         if (isFilenameTooLong(&dst, pVNetRootContext)) {
5668             status = STATUS_OBJECT_NAME_INVALID;
5669             goto out;
5670         }
5671         if (rinfo->RootDirectory) {
5672             status = STATUS_INVALID_PARAMETER;
5673             goto out;
5674         }
5675         break;
5676     }
5677     case FileLinkInformation:
5678     {
5679         PFILE_LINK_INFORMATION linfo =
5680             (PFILE_LINK_INFORMATION)RxContext->Info.Buffer;
5681         UNICODE_STRING dst = { (USHORT)linfo->FileNameLength,
5682             (USHORT)linfo->FileNameLength, linfo->FileName };
5683 #ifdef DEBUG_FILE_SET
5684         DbgP("Attempting to add link as '%wZ'\n", &dst);
5685 #endif
5686         if (isFilenameTooLong(&dst, pVNetRootContext)) {
5687             status = STATUS_OBJECT_NAME_INVALID;
5688             goto out;
5689         }
5690         if (linfo->RootDirectory) {
5691             status = STATUS_INVALID_PARAMETER;
5692             goto out;
5693         }
5694         break;
5695     }
5696     case FileDispositionInformation:
5697     {
5698         PFILE_DISPOSITION_INFORMATION dinfo =
5699             (PFILE_DISPOSITION_INFORMATION)RxContext->Info.Buffer;
5700         __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
5701         if (dinfo->DeleteFile && nfs41_fcb->DeletePending) {
5702             status = STATUS_DELETE_PENDING;
5703             goto out;
5704         }
5705         break;
5706     }
5707     case FileBasicInformation:
5708     case FileAllocationInformation:
5709     case FileEndOfFileInformation:
5710         break;
5711     default:
5712         print_error("nfs41_SetFileInformation: unhandled class %d\n", InfoClass);
5713         status = STATUS_NOT_SUPPORTED;
5714     }
5715 
5716 out:
5717     return status;
5718 }
5719 
5720 #ifdef __REACTOS__
5721 NTSTATUS NTAPI nfs41_SetFileInformation(
5722 #else
5723 NTSTATUS nfs41_SetFileInformation(
5724 #endif
5725     IN OUT PRX_CONTEXT RxContext)
5726 {
5727     NTSTATUS status = STATUS_INVALID_PARAMETER;
5728     nfs41_updowncall_entry *entry;
5729     FILE_INFORMATION_CLASS InfoClass = RxContext->Info.FileInformationClass;
5730     FILE_RENAME_INFORMATION rinfo;
5731     __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
5732     __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
5733         NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
5734     __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
5735         NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
5736     __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
5737     __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
5738 #ifdef ENABLE_TIMINGS
5739     LARGE_INTEGER t1, t2;
5740     t1 = KeQueryPerformanceCounter(NULL);
5741 #endif
5742 
5743 #ifdef DEBUG_FILE_SET
5744     DbgEn();
5745     print_debug_filedirquery_header(RxContext);
5746 #endif
5747 
5748     status = check_nfs41_setattr_args(RxContext);
5749     if (status) goto out;
5750 
5751     switch (InfoClass) {
5752     case FileDispositionInformation:
5753         {
5754             PFILE_DISPOSITION_INFORMATION dinfo =
5755                 (PFILE_DISPOSITION_INFORMATION)RxContext->Info.Buffer;
5756             if (dinfo->DeleteFile) {
5757                 nfs41_fcb->DeletePending = TRUE;
5758                 // we can delete directories right away
5759                 if (nfs41_fcb->StandardInfo.Directory)
5760                     break;
5761                 nfs41_fcb->StandardInfo.DeletePending = TRUE;
5762                 if (RxContext->pFcb->OpenCount > 1) {
5763                     rinfo.ReplaceIfExists = 0;
5764                     rinfo.RootDirectory = INVALID_HANDLE_VALUE;
5765                     rinfo.FileNameLength = 0;
5766                     rinfo.FileName[0] = L'\0';
5767                     InfoClass = FileRenameInformation;
5768                     nfs41_fcb->Renamed = TRUE;
5769                     break;
5770                 }
5771             } else {
5772                 /* section 4.3.3 of [FSBO]
5773                  * "file system behavior in the microsoft windows environment"
5774                  */
5775                 if (nfs41_fcb->DeletePending) {
5776                     nfs41_fcb->DeletePending = 0;
5777                     nfs41_fcb->StandardInfo.DeletePending = 0;
5778                 }
5779             }
5780             status = STATUS_SUCCESS;
5781             goto out;
5782         }
5783     case FileEndOfFileInformation:
5784         {
5785             PFILE_END_OF_FILE_INFORMATION info =
5786                 (PFILE_END_OF_FILE_INFORMATION)RxContext->Info.Buffer;
5787             nfs41_fcb->StandardInfo.AllocationSize =
5788                 nfs41_fcb->StandardInfo.EndOfFile = info->EndOfFile;
5789             break;
5790         }
5791     case FileRenameInformation:
5792         {
5793             /* noop if filename and destination are the same */
5794             PFILE_RENAME_INFORMATION prinfo =
5795                 (PFILE_RENAME_INFORMATION)RxContext->Info.Buffer;
5796             const UNICODE_STRING dst = { (USHORT)prinfo->FileNameLength,
5797                 (USHORT)prinfo->FileNameLength, prinfo->FileName };
5798             if (RtlCompareUnicodeString(&dst,
5799                     SrvOpen->pAlreadyPrefixedName, FALSE) == 0) {
5800                 status = STATUS_SUCCESS;
5801                 goto out;
5802             }
5803         }
5804     }
5805 
5806     status = nfs41_UpcallCreate(NFS41_FILE_SET, &nfs41_fobx->sec_ctx,
5807         pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
5808         pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
5809     if (status) goto out;
5810 
5811     entry->u.SetFile.InfoClass = InfoClass;
5812 
5813     /* original irp has infoclass for remove but we need to rename instead,
5814      * thus we changed the local variable infoclass */
5815     if (RxContext->Info.FileInformationClass == FileDispositionInformation &&
5816             InfoClass == FileRenameInformation) {
5817         entry->buf = &rinfo;
5818         entry->buf_len = sizeof(rinfo);
5819     } else {
5820         entry->buf = RxContext->Info.Buffer;
5821         entry->buf_len = RxContext->Info.Length;
5822     }
5823 #ifdef ENABLE_TIMINGS
5824     InterlockedIncrement(&setattr.sops);
5825     InterlockedAdd64(&setattr.size, entry->u.SetFile.buf_len);
5826 #endif
5827 
5828     status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
5829     if (status) goto out;
5830 
5831     status = map_setfile_error(entry->status);
5832     if (!status) {
5833         if (!nfs41_fobx->deleg_type && entry->ChangeTime &&
5834                 (SrvOpen->DesiredAccess &
5835                 (FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA)))
5836             nfs41_update_fcb_list(RxContext->pFcb, entry->ChangeTime);
5837         nfs41_fcb->changeattr = entry->ChangeTime;
5838     }
5839     RxFreePool(entry);
5840 out:
5841 #ifdef ENABLE_TIMINGS
5842     t2 = KeQueryPerformanceCounter(NULL);
5843     InterlockedIncrement(&setattr.tops);
5844     InterlockedAdd64(&setattr.ticks, t2.QuadPart - t1.QuadPart);
5845 #ifdef ENABLE_INDV_TIMINGS
5846     DbgP("nfs41_SetFileInformation delta = %d op=%d sum=%d\n",
5847         t2.QuadPart - t1.QuadPart, setattr.tops, setattr.ticks);
5848 #endif
5849 #endif
5850 #ifdef DEBUG_FILE_SET
5851     DbgEx();
5852 #endif
5853     return status;
5854 }
5855 
5856 NTSTATUS nfs41_SetFileInformationAtCleanup(
5857       IN OUT PRX_CONTEXT RxContext)
5858 {
5859     NTSTATUS status;
5860     DbgEn();
5861     status = nfs41_SetFileInformation(RxContext);
5862     DbgEx();
5863     return status;
5864 }
5865 
5866 #ifdef __REACTOS__
5867 NTSTATUS NTAPI nfs41_IsValidDirectory (
5868 #else
5869 NTSTATUS nfs41_IsValidDirectory (
5870 #endif
5871     IN OUT PRX_CONTEXT RxContext,
5872     IN PUNICODE_STRING DirectoryName)
5873 {
5874     return STATUS_SUCCESS;
5875 }
5876 
5877 #ifdef __REACTOS__
5878 NTSTATUS NTAPI nfs41_ComputeNewBufferingState(
5879 #else
5880 NTSTATUS nfs41_ComputeNewBufferingState(
5881 #endif
5882     IN OUT PMRX_SRV_OPEN pSrvOpen,
5883     IN PVOID pMRxContext,
5884     OUT ULONG *pNewBufferingState)
5885 {
5886     NTSTATUS status = STATUS_SUCCESS;
5887     ULONG flag = PtrToUlong(pMRxContext), oldFlags = pSrvOpen->BufferingFlags;
5888 
5889     switch(flag) {
5890     case DISABLE_CACHING:
5891         if (pSrvOpen->BufferingFlags &
5892             (FCB_STATE_READBUFFERING_ENABLED | FCB_STATE_READCACHING_ENABLED))
5893             pSrvOpen->BufferingFlags &=
5894                 ~(FCB_STATE_READBUFFERING_ENABLED |
5895                   FCB_STATE_READCACHING_ENABLED);
5896         if (pSrvOpen->BufferingFlags &
5897             (FCB_STATE_WRITECACHING_ENABLED | FCB_STATE_WRITEBUFFERING_ENABLED))
5898             pSrvOpen->BufferingFlags &=
5899                 ~(FCB_STATE_WRITECACHING_ENABLED |
5900                   FCB_STATE_WRITEBUFFERING_ENABLED);
5901         pSrvOpen->BufferingFlags |= FCB_STATE_DISABLE_LOCAL_BUFFERING;
5902         break;
5903     case ENABLE_READ_CACHING:
5904         pSrvOpen->BufferingFlags |=
5905             (FCB_STATE_READBUFFERING_ENABLED | FCB_STATE_READCACHING_ENABLED);
5906         break;
5907     case ENABLE_WRITE_CACHING:
5908         pSrvOpen->BufferingFlags |=
5909             (FCB_STATE_WRITECACHING_ENABLED | FCB_STATE_WRITEBUFFERING_ENABLED);
5910         break;
5911     case ENABLE_READWRITE_CACHING:
5912         pSrvOpen->BufferingFlags =
5913             (FCB_STATE_READBUFFERING_ENABLED | FCB_STATE_READCACHING_ENABLED |
5914             FCB_STATE_WRITECACHING_ENABLED | FCB_STATE_WRITEBUFFERING_ENABLED);
5915     }
5916 #ifdef DEBUG_TIME_BASED_COHERENCY
5917     DbgP("nfs41_ComputeNewBufferingState: %wZ pSrvOpen %p Old %08x New %08x\n",
5918          pSrvOpen->pAlreadyPrefixedName, pSrvOpen, oldFlags,
5919          pSrvOpen->BufferingFlags);
5920     *pNewBufferingState = pSrvOpen->BufferingFlags;
5921 #endif
5922     return status;
5923 }
5924 
5925 void print_readwrite_args(
5926     PRX_CONTEXT RxContext)
5927 {
5928     PLOWIO_CONTEXT LowIoContext  = &RxContext->LowIoContext;
5929 
5930     print_debug_header(RxContext);
5931     DbgP("Bytecount 0x%x Byteoffset 0x%x Buffer %p\n",
5932         LowIoContext->ParamsFor.ReadWrite.ByteCount,
5933         LowIoContext->ParamsFor.ReadWrite.ByteOffset,
5934         LowIoContext->ParamsFor.ReadWrite.Buffer);
5935 }
5936 
5937 void enable_caching(
5938     PMRX_SRV_OPEN SrvOpen,
5939     PNFS41_FOBX nfs41_fobx,
5940     ULONGLONG ChangeTime,
5941     HANDLE session)
5942 {
5943     ULONG flag = 0;
5944     PLIST_ENTRY pEntry;
5945     nfs41_fcb_list_entry *cur;
5946     BOOLEAN found = FALSE;
5947 
5948     if (SrvOpen->DesiredAccess & FILE_READ_DATA)
5949         flag = ENABLE_READ_CACHING;
5950     if ((SrvOpen->DesiredAccess & FILE_WRITE_DATA) &&
5951             !nfs41_fobx->write_thru)
5952         flag = ENABLE_WRITE_CACHING;
5953     if ((SrvOpen->DesiredAccess & FILE_READ_DATA) &&
5954             (SrvOpen->DesiredAccess & FILE_WRITE_DATA) &&
5955             !nfs41_fobx->write_thru)
5956         flag = ENABLE_READWRITE_CACHING;
5957 
5958 #if defined(DEBUG_TIME_BASED_COHERENCY) || \
5959         defined(DEBUG_WRITE) || defined(DEBUG_READ)
5960     print_caching_level(1, flag, SrvOpen->pAlreadyPrefixedName);
5961 #endif
5962 
5963     if (!flag)
5964         return;
5965 
5966     RxChangeBufferingState((PSRV_OPEN)SrvOpen, ULongToPtr(flag), 1);
5967 
5968     ExAcquireFastMutex(&fcblistLock);
5969     pEntry = openlist.head.Flink;
5970     while (!IsListEmpty(&openlist.head)) {
5971         cur = (nfs41_fcb_list_entry *)CONTAINING_RECORD(pEntry,
5972                 nfs41_fcb_list_entry, next);
5973         if (cur->fcb == SrvOpen->pFcb) {
5974 #ifdef DEBUG_TIME_BASED_COHERENCY
5975             DbgP("enable_caching: Looked&Found match for fcb=%p %wZ\n",
5976                 SrvOpen->pFcb, SrvOpen->pAlreadyPrefixedName);
5977 #endif
5978             cur->skip = FALSE;
5979             found = TRUE;
5980             break;
5981         }
5982         if (pEntry->Flink == &openlist.head) {
5983 #ifdef DEBUG_TIME_BASED_COHERENCY
5984             DbgP("enable_caching: reached EOL looking for fcb=%p %wZ\n",
5985                 SrvOpen->pFcb, SrvOpen->pAlreadyPrefixedName);
5986 #endif
5987             break;
5988         }
5989         pEntry = pEntry->Flink;
5990     }
5991     if (!found && nfs41_fobx->deleg_type) {
5992         nfs41_fcb_list_entry *oentry;
5993 #ifdef DEBUG_TIME_BASED_COHERENCY
5994         DbgP("enable_caching: delegation recalled: srv_open=%p\n", SrvOpen);
5995 #endif
5996         oentry = RxAllocatePoolWithTag(NonPagedPool,
5997             sizeof(nfs41_fcb_list_entry), NFS41_MM_POOLTAG_OPEN);
5998         if (oentry == NULL) return;
5999         oentry->fcb = SrvOpen->pFcb;
6000         oentry->session = session;
6001         oentry->nfs41_fobx = nfs41_fobx;
6002         oentry->ChangeTime = ChangeTime;
6003         oentry->skip = FALSE;
6004         InsertTailList(&openlist.head, &oentry->next);
6005         nfs41_fobx->deleg_type = 0;
6006     }
6007     ExReleaseFastMutex(&fcblistLock);
6008 }
6009 
6010 NTSTATUS map_readwrite_errors(
6011     DWORD status)
6012 {
6013     switch (status) {
6014     case ERROR_ACCESS_DENIED:           return STATUS_ACCESS_DENIED;
6015     case ERROR_HANDLE_EOF:              return STATUS_END_OF_FILE;
6016     case ERROR_FILE_INVALID:            return STATUS_FILE_INVALID;
6017     case ERROR_INVALID_PARAMETER:       return STATUS_INVALID_PARAMETER;
6018     case ERROR_LOCK_VIOLATION:          return STATUS_FILE_LOCK_CONFLICT;
6019     case ERROR_NETWORK_ACCESS_DENIED:   return STATUS_NETWORK_ACCESS_DENIED;
6020     case ERROR_NETNAME_DELETED:         return STATUS_NETWORK_NAME_DELETED;
6021     default:
6022         print_error("failed to map windows error %d to NTSTATUS; "
6023             "defaulting to STATUS_NET_WRITE_FAULT\n", status);
6024     case ERROR_NET_WRITE_FAULT:         return STATUS_NET_WRITE_FAULT;
6025     }
6026 }
6027 
6028 NTSTATUS check_nfs41_read_args(
6029     IN PRX_CONTEXT RxContext)
6030 {
6031     if (!RxContext->LowIoContext.ParamsFor.ReadWrite.Buffer)
6032         return STATUS_INVALID_USER_BUFFER;
6033     return STATUS_SUCCESS;
6034 }
6035 
6036 #ifdef __REACTOS__
6037 NTSTATUS NTAPI nfs41_Read(
6038 #else
6039 NTSTATUS nfs41_Read(
6040 #endif
6041     IN OUT PRX_CONTEXT RxContext)
6042 {
6043     NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
6044     nfs41_updowncall_entry *entry;
6045     BOOLEAN async = FALSE;
6046     PLOWIO_CONTEXT LowIoContext  = &RxContext->LowIoContext;
6047     __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
6048     __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
6049         NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
6050     __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
6051         NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
6052     __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
6053     __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
6054     DWORD io_delay;
6055 #ifdef ENABLE_TIMINGS
6056     LARGE_INTEGER t1, t2;
6057     t1 = KeQueryPerformanceCounter(NULL);
6058 #endif
6059 
6060 #ifdef DEBUG_READ
6061     DbgEn();
6062     print_readwrite_args(RxContext);
6063 #endif
6064     status = check_nfs41_read_args(RxContext);
6065     if (status) goto out;
6066 
6067     status = nfs41_UpcallCreate(NFS41_READ, &nfs41_fobx->sec_ctx,
6068         pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
6069         pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
6070     if (status) goto out;
6071 
6072     entry->u.ReadWrite.MdlAddress = LowIoContext->ParamsFor.ReadWrite.Buffer;
6073     entry->buf_len = LowIoContext->ParamsFor.ReadWrite.ByteCount;
6074     entry->u.ReadWrite.offset = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
6075     if (FlagOn(RxContext->CurrentIrpSp->FileObject->Flags,
6076             FO_SYNCHRONOUS_IO) == FALSE) {
6077         entry->u.ReadWrite.rxcontext = RxContext;
6078         async = entry->async_op = TRUE;
6079     }
6080 
6081     /* assume network speed is 100MB/s and disk speed is 100MB/s so add
6082      * time to transfer requested bytes over the network and read from disk
6083      */
6084     io_delay = pVNetRootContext->timeout + 2 * entry->buf_len / 104857600;
6085     status = nfs41_UpcallWaitForReply(entry, io_delay);
6086     if (status) goto out;
6087 
6088     if (async) {
6089 #ifdef DEBUG_READ
6090         DbgP("This is asynchronous read, returning control back to the user\n");
6091 #endif
6092         status = STATUS_PENDING;
6093         goto out;
6094     }
6095 
6096     if (entry->status == NO_ERROR) {
6097 #ifdef ENABLE_TIMINGS
6098         InterlockedIncrement(&read.sops);
6099         InterlockedAdd64(&read.size, entry->u.ReadWrite.len);
6100 #endif
6101         status = RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
6102         RxContext->IoStatusBlock.Information = entry->buf_len;
6103 
6104         if ((!BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,
6105                 LOWIO_READWRITEFLAG_PAGING_IO) &&
6106                 (SrvOpen->DesiredAccess & FILE_READ_DATA) &&
6107                 !pVNetRootContext->nocache && !nfs41_fobx->nocache &&
6108                 !(SrvOpen->BufferingFlags &
6109                 (FCB_STATE_READBUFFERING_ENABLED |
6110                  FCB_STATE_READCACHING_ENABLED)))) {
6111             enable_caching(SrvOpen, nfs41_fobx, nfs41_fcb->changeattr,
6112                 pVNetRootContext->session);
6113         }
6114     } else {
6115         status = map_readwrite_errors(entry->status);
6116         RxContext->CurrentIrp->IoStatus.Status = status;
6117         RxContext->IoStatusBlock.Information = 0;
6118     }
6119     RxFreePool(entry);
6120 out:
6121 #ifdef ENABLE_TIMINGS
6122     t2 = KeQueryPerformanceCounter(NULL);
6123     InterlockedIncrement(&read.tops);
6124     InterlockedAdd64(&read.ticks, t2.QuadPart - t1.QuadPart);
6125 #ifdef ENABLE_INDV_TIMINGS
6126     DbgP("nfs41_Read delta = %d op=%d sum=%d\n", t2.QuadPart - t1.QuadPart,
6127         read.tops, read.ticks);
6128 #endif
6129 #endif
6130 #ifdef DEBUG_READ
6131     DbgEx();
6132 #endif
6133     return status;
6134 }
6135 
6136 NTSTATUS check_nfs41_write_args(
6137     IN PRX_CONTEXT RxContext)
6138 {
6139     NTSTATUS status = STATUS_SUCCESS;
6140     __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
6141         NFS41GetVNetRootExtension(RxContext->pRelevantSrvOpen->pVNetRoot);
6142 
6143     if (!RxContext->LowIoContext.ParamsFor.ReadWrite.Buffer) {
6144         status = STATUS_INVALID_USER_BUFFER;
6145         goto out;
6146     }
6147 
6148     if (pVNetRootContext->read_only) {
6149         print_error("check_nfs41_write_args: Read-only mount\n");
6150         status = STATUS_ACCESS_DENIED;
6151         goto out;
6152     }
6153 out:
6154     return status;
6155 }
6156 
6157 #ifdef __REACTOS__
6158 NTSTATUS NTAPI nfs41_Write(
6159 #else
6160 NTSTATUS nfs41_Write(
6161 #endif
6162     IN OUT PRX_CONTEXT RxContext)
6163 {
6164     NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
6165     nfs41_updowncall_entry *entry;
6166     BOOLEAN async = FALSE;
6167     PLOWIO_CONTEXT LowIoContext  = &RxContext->LowIoContext;
6168     __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
6169     __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
6170         NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
6171     __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
6172         NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
6173     __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
6174     __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
6175     DWORD io_delay;
6176 #ifdef ENABLE_TIMINGS
6177     LARGE_INTEGER t1, t2;
6178     t1 = KeQueryPerformanceCounter(NULL);
6179 #endif
6180 
6181 #ifdef DEBUG_WRITE
6182     DbgEn();
6183     print_readwrite_args(RxContext);
6184 #endif
6185 
6186     status = check_nfs41_write_args(RxContext);
6187     if (status) goto out;
6188 
6189     status = nfs41_UpcallCreate(NFS41_WRITE, &nfs41_fobx->sec_ctx,
6190         pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
6191         pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
6192     if (status) goto out;
6193 
6194     entry->u.ReadWrite.MdlAddress = LowIoContext->ParamsFor.ReadWrite.Buffer;
6195     entry->buf_len = LowIoContext->ParamsFor.ReadWrite.ByteCount;
6196     entry->u.ReadWrite.offset = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
6197 
6198     if (FlagOn(RxContext->CurrentIrpSp->FileObject->Flags,
6199             FO_SYNCHRONOUS_IO) == FALSE) {
6200         entry->u.ReadWrite.rxcontext = RxContext;
6201         async = entry->async_op = TRUE;
6202     }
6203 
6204     /* assume network speed is 100MB/s and disk speed is 100MB/s so add
6205      * time to transfer requested bytes over the network and write to disk
6206      */
6207     io_delay = pVNetRootContext->timeout + 2 * entry->buf_len / 104857600;
6208     status = nfs41_UpcallWaitForReply(entry, io_delay);
6209     if (status) goto out;
6210 
6211     if (async) {
6212 #ifdef DEBUG_WRITE
6213         DbgP("This is asynchronous write, returning control back to the user\n");
6214 #endif
6215         status = STATUS_PENDING;
6216         goto out;
6217     }
6218 
6219     if (entry->status == NO_ERROR) {
6220         //update cached file attributes
6221 #ifdef ENABLE_TIMINGS
6222         InterlockedIncrement(&write.sops);
6223         InterlockedAdd64(&write.size, entry->u.ReadWrite.len);
6224 #endif
6225         nfs41_fcb->StandardInfo.EndOfFile.QuadPart = entry->buf_len +
6226             entry->u.ReadWrite.offset;
6227         status = RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
6228         RxContext->IoStatusBlock.Information = entry->buf_len;
6229         nfs41_fcb->changeattr = entry->ChangeTime;
6230 
6231         //re-enable write buffering
6232         if (!BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,
6233                 LOWIO_READWRITEFLAG_PAGING_IO) &&
6234                 (SrvOpen->DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) &&
6235                 !pVNetRootContext->write_thru &&
6236                 !pVNetRootContext->nocache &&
6237                 !nfs41_fobx->write_thru && !nfs41_fobx->nocache &&
6238                 !(SrvOpen->BufferingFlags &
6239                 (FCB_STATE_WRITEBUFFERING_ENABLED |
6240                  FCB_STATE_WRITECACHING_ENABLED))) {
6241             enable_caching(SrvOpen, nfs41_fobx, nfs41_fcb->changeattr,
6242                 pVNetRootContext->session);
6243         } else if (!nfs41_fobx->deleg_type)
6244             nfs41_update_fcb_list(RxContext->pFcb, entry->ChangeTime);
6245 
6246     } else {
6247         status = map_readwrite_errors(entry->status);
6248         RxContext->CurrentIrp->IoStatus.Status = status;
6249         RxContext->IoStatusBlock.Information = 0;
6250     }
6251     RxFreePool(entry);
6252 out:
6253 #ifdef ENABLE_TIMINGS
6254     t2 = KeQueryPerformanceCounter(NULL);
6255     InterlockedIncrement(&write.tops);
6256     InterlockedAdd64(&write.ticks, t2.QuadPart - t1.QuadPart);
6257 #ifdef ENABLE_INDV_TIMINGS
6258     DbgP("nfs41_Write delta = %d op=%d sum=%d\n", t2.QuadPart - t1.QuadPart,
6259         write.tops, write.ticks);
6260 #endif
6261 #endif
6262 #ifdef DEBUG_WRITE
6263     DbgEx();
6264 #endif
6265     return status;
6266 }
6267 
6268 #ifdef __REACTOS__
6269 NTSTATUS NTAPI nfs41_IsLockRealizable(
6270 #else
6271 NTSTATUS nfs41_IsLockRealizable(
6272 #endif
6273     IN OUT PMRX_FCB pFcb,
6274     IN PLARGE_INTEGER  ByteOffset,
6275     IN PLARGE_INTEGER  Length,
6276     IN ULONG  LowIoLockFlags)
6277 {
6278     NTSTATUS status = STATUS_SUCCESS;
6279 #ifdef DEBUG_LOCK
6280     DbgEn();
6281     DbgP("offset 0x%llx, length 0x%llx, exclusive=%u, blocking=%u\n",
6282         ByteOffset->QuadPart,Length->QuadPart,
6283         BooleanFlagOn(LowIoLockFlags, SL_EXCLUSIVE_LOCK),
6284         !BooleanFlagOn(LowIoLockFlags, SL_FAIL_IMMEDIATELY));
6285 #endif
6286 
6287     /* NFS lock operations with length=0 MUST fail with NFS4ERR_INVAL */
6288     if (Length->QuadPart == 0)
6289         status = STATUS_NOT_SUPPORTED;
6290 
6291 #ifdef DEBUG_LOCK
6292     DbgEx();
6293 #endif
6294     return status;
6295 }
6296 
6297 NTSTATUS map_lock_errors(
6298     DWORD status)
6299 {
6300     switch (status) {
6301     case NO_ERROR:                  return STATUS_SUCCESS;
6302     case ERROR_NETNAME_DELETED:     return STATUS_NETWORK_NAME_DELETED;
6303     case ERROR_LOCK_FAILED:         return STATUS_LOCK_NOT_GRANTED;
6304     case ERROR_NOT_LOCKED:          return STATUS_RANGE_NOT_LOCKED;
6305     case ERROR_ATOMIC_LOCKS_NOT_SUPPORTED: return STATUS_UNSUCCESSFUL;
6306     case ERROR_OUTOFMEMORY:         return STATUS_INSUFFICIENT_RESOURCES;
6307     case ERROR_SHARING_VIOLATION:   return STATUS_SHARING_VIOLATION;
6308     case ERROR_FILE_INVALID:        return STATUS_FILE_INVALID;
6309     /* if we return ERROR_INVALID_PARAMETER, Windows translates that to
6310      * success!! */
6311     case ERROR_INVALID_PARAMETER:   return STATUS_LOCK_NOT_GRANTED;
6312     default:
6313         print_error("failed to map windows error %d to NTSTATUS; "
6314             "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", status);
6315     case ERROR_BAD_NET_RESP:        return STATUS_INVALID_NETWORK_RESPONSE;
6316     }
6317 }
6318 
6319 void print_lock_args(
6320     PRX_CONTEXT RxContext)
6321 {
6322     PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
6323     const ULONG flags = LowIoContext->ParamsFor.Locks.Flags;
6324     print_debug_header(RxContext);
6325     DbgP("offset 0x%llx, length 0x%llx, exclusive=%u, blocking=%u\n",
6326         LowIoContext->ParamsFor.Locks.ByteOffset,
6327         LowIoContext->ParamsFor.Locks.Length,
6328         BooleanFlagOn(flags, SL_EXCLUSIVE_LOCK),
6329         !BooleanFlagOn(flags, SL_FAIL_IMMEDIATELY));
6330 }
6331 
6332 
6333 /* use exponential backoff between polls for blocking locks */
6334 #define MSEC_TO_RELATIVE_WAIT   (-10000)
6335 #define MIN_LOCK_POLL_WAIT      (500 * MSEC_TO_RELATIVE_WAIT) /* 500ms */
6336 #define MAX_LOCK_POLL_WAIT      (30000 * MSEC_TO_RELATIVE_WAIT) /* 30s */
6337 
6338 void denied_lock_backoff(
6339     IN OUT PLARGE_INTEGER delay)
6340 {
6341     if (delay->QuadPart == 0)
6342         delay->QuadPart = MIN_LOCK_POLL_WAIT;
6343     else
6344         delay->QuadPart <<= 1;
6345 
6346     if (delay->QuadPart < MAX_LOCK_POLL_WAIT)
6347         delay->QuadPart = MAX_LOCK_POLL_WAIT;
6348 }
6349 
6350 #ifdef __REACTOS__
6351 NTSTATUS NTAPI nfs41_Lock(
6352 #else
6353 NTSTATUS nfs41_Lock(
6354 #endif
6355     IN OUT PRX_CONTEXT RxContext)
6356 {
6357     NTSTATUS status = STATUS_SUCCESS;
6358     nfs41_updowncall_entry *entry;
6359     PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
6360     __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
6361     __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
6362     __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
6363         NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
6364     __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
6365         NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
6366     const ULONG flags = LowIoContext->ParamsFor.Locks.Flags;
6367 #ifdef _MSC_VER
6368     LARGE_INTEGER poll_delay = {0};
6369 #else
6370     LARGE_INTEGER poll_delay;
6371 #endif
6372 #ifdef ENABLE_TIMINGS
6373     LARGE_INTEGER t1, t2;
6374     t1 = KeQueryPerformanceCounter(NULL);
6375 #endif
6376 
6377 #ifndef _MSC_VER
6378     poll_delay.QuadPart = 0;
6379 #endif
6380 
6381 #ifdef DEBUG_LOCK
6382     DbgEn();
6383     print_lock_args(RxContext);
6384 #endif
6385 
6386 /*  RxReleaseFcbResourceForThreadInMRx(RxContext, RxContext->pFcb,
6387         LowIoContext->ResourceThreadId); */
6388 
6389     status = nfs41_UpcallCreate(NFS41_LOCK, &nfs41_fobx->sec_ctx,
6390         pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
6391         pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
6392     if (status) goto out;
6393 
6394     entry->u.Lock.offset = LowIoContext->ParamsFor.Locks.ByteOffset;
6395     entry->u.Lock.length = LowIoContext->ParamsFor.Locks.Length;
6396     entry->u.Lock.exclusive = BooleanFlagOn(flags, SL_EXCLUSIVE_LOCK);
6397     entry->u.Lock.blocking = !BooleanFlagOn(flags, SL_FAIL_IMMEDIATELY);
6398 
6399 retry_upcall:
6400     status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
6401     if (status) goto out;
6402 
6403     /* blocking locks keep trying until it succeeds */
6404     if (entry->status == ERROR_LOCK_FAILED && entry->u.Lock.blocking) {
6405         denied_lock_backoff(&poll_delay);
6406         DbgP("returned ERROR_LOCK_FAILED; retrying in %llums\n",
6407             poll_delay.QuadPart / MSEC_TO_RELATIVE_WAIT);
6408         KeDelayExecutionThread(KernelMode, FALSE, &poll_delay);
6409         entry->state = NFS41_WAITING_FOR_UPCALL;
6410         goto retry_upcall;
6411     }
6412 
6413     status = map_lock_errors(entry->status);
6414     RxContext->CurrentIrp->IoStatus.Status = status;
6415 
6416     RxFreePool(entry);
6417 out:
6418 #ifdef ENABLE_TIMINGS
6419     t2 = KeQueryPerformanceCounter(NULL);
6420     InterlockedIncrement(&lock.tops);
6421     InterlockedAdd64(&lock.ticks, t2.QuadPart - t1.QuadPart);
6422 #ifdef ENABLE_INDV_TIMINGS
6423     DbgP("nfs41_Lock delta = %d op=%d sum=%d\n", t2.QuadPart - t1.QuadPart,
6424         lock.tops, lock.ticks);
6425 #endif
6426 #endif
6427 #ifdef DEBUG_LOCK
6428     DbgEx();
6429 #endif
6430     return status;
6431 }
6432 
6433 void print_unlock_args(
6434     PRX_CONTEXT RxContext)
6435 {
6436     PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
6437     print_debug_header(RxContext);
6438     if (LowIoContext->Operation == LOWIO_OP_UNLOCK_MULTIPLE) {
6439         PLOWIO_LOCK_LIST lock = LowIoContext->ParamsFor.Locks.LockList;
6440         DbgP("LOWIO_OP_UNLOCK_MULTIPLE:");
6441         while (lock) {
6442             DbgP(" (offset=%llu, length=%llu)", lock->ByteOffset, lock->Length);
6443             lock = lock->Next;
6444         }
6445         DbgP("\n");
6446     } else {
6447         DbgP("LOWIO_OP_UNLOCK: offset=%llu, length=%llu\n",
6448             LowIoContext->ParamsFor.Locks.ByteOffset,
6449             LowIoContext->ParamsFor.Locks.Length);
6450     }
6451 }
6452 
6453 __inline ULONG unlock_list_count(
6454     PLOWIO_LOCK_LIST lock)
6455 {
6456     ULONG count = 0;
6457     while (lock) {
6458         count++;
6459         lock = lock->Next;
6460     }
6461     return count;
6462 }
6463 
6464 #ifdef __REACTOS__
6465 NTSTATUS NTAPI nfs41_Unlock(
6466 #else
6467 NTSTATUS nfs41_Unlock(
6468 #endif
6469     IN OUT PRX_CONTEXT RxContext)
6470 {
6471     NTSTATUS status = STATUS_SUCCESS;
6472     nfs41_updowncall_entry *entry;
6473     PLOWIO_CONTEXT LowIoContext  = &RxContext->LowIoContext;
6474     __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
6475     __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
6476     __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
6477         NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
6478     __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
6479         NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
6480 #ifdef ENABLE_TIMINGS
6481     LARGE_INTEGER t1, t2;
6482     t1 = KeQueryPerformanceCounter(NULL);
6483 #endif
6484 #ifdef DEBUG_LOCK
6485     DbgEn();
6486     print_lock_args(RxContext);
6487 #endif
6488 
6489 /*  RxReleaseFcbResourceForThreadInMRx(RxContext, RxContext->pFcb,
6490         LowIoContext->ResourceThreadId); */
6491 
6492     status = nfs41_UpcallCreate(NFS41_UNLOCK, &nfs41_fobx->sec_ctx,
6493         pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
6494         pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
6495     if (status) goto out;
6496 
6497     if (LowIoContext->Operation == LOWIO_OP_UNLOCK_MULTIPLE) {
6498         entry->u.Unlock.count = unlock_list_count(
6499             LowIoContext->ParamsFor.Locks.LockList);
6500         RtlCopyMemory(&entry->u.Unlock.locks,
6501             LowIoContext->ParamsFor.Locks.LockList,
6502             sizeof(LOWIO_LOCK_LIST));
6503     } else {
6504         entry->u.Unlock.count = 1;
6505         entry->u.Unlock.locks.ByteOffset =
6506             LowIoContext->ParamsFor.Locks.ByteOffset;
6507         entry->u.Unlock.locks.Length =
6508             LowIoContext->ParamsFor.Locks.Length;
6509     }
6510 
6511     status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
6512     if (status) goto out;
6513 
6514     status = map_lock_errors(entry->status);
6515     RxContext->CurrentIrp->IoStatus.Status = status;
6516     RxFreePool(entry);
6517 out:
6518 #ifdef ENABLE_TIMINGS
6519     t2 = KeQueryPerformanceCounter(NULL);
6520     InterlockedIncrement(&unlock.tops);
6521     InterlockedAdd64(&unlock.ticks, t2.QuadPart - t1.QuadPart);
6522 #ifdef ENABLE_INDV_TIMINGS
6523     DbgP("nfs41_Unlock delta = %d op=%d sum=%d\n", t2.QuadPart - t1.QuadPart,
6524         unlock.tops, unlock.ticks);
6525 #endif
6526 #endif
6527 #ifdef DEBUG_LOCK
6528     DbgEx();
6529 #endif
6530     return status;
6531 }
6532 
6533 NTSTATUS map_symlink_errors(
6534     NTSTATUS status)
6535 {
6536     switch (status) {
6537     case NO_ERROR:                  return STATUS_SUCCESS;
6538     case ERROR_INVALID_REPARSE_DATA: return STATUS_IO_REPARSE_DATA_INVALID;
6539     case ERROR_NOT_A_REPARSE_POINT: return STATUS_NOT_A_REPARSE_POINT;
6540     case ERROR_ACCESS_DENIED:       return STATUS_ACCESS_DENIED;
6541     case ERROR_NOT_EMPTY:           return STATUS_DIRECTORY_NOT_EMPTY;
6542     case ERROR_OUTOFMEMORY:         return STATUS_INSUFFICIENT_RESOURCES;
6543     case ERROR_INSUFFICIENT_BUFFER: return STATUS_BUFFER_TOO_SMALL;
6544     case STATUS_BUFFER_TOO_SMALL:
6545     case ERROR_BUFFER_OVERFLOW:     return STATUS_BUFFER_OVERFLOW;
6546     default:
6547         print_error("failed to map windows error %d to NTSTATUS; "
6548             "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", status);
6549     case ERROR_BAD_NET_RESP:        return STATUS_INVALID_NETWORK_RESPONSE;
6550     }
6551 }
6552 
6553 void print_reparse_buffer(
6554     PREPARSE_DATA_BUFFER Reparse)
6555 {
6556     UNICODE_STRING name;
6557     DbgP("ReparseTag:           %08X\n", Reparse->ReparseTag);
6558     DbgP("ReparseDataLength:    %8u\n", Reparse->ReparseDataLength);
6559     DbgP("Reserved:             %8u\n", Reparse->Reserved);
6560     DbgP("SubstituteNameOffset: %8u\n",
6561          Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset);
6562     DbgP("SubstituteNameLength: %8u\n",
6563          Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength);
6564     DbgP("PrintNameOffset:      %8u\n",
6565          Reparse->SymbolicLinkReparseBuffer.PrintNameOffset);
6566     DbgP("PrintNameLength:      %8u\n",
6567          Reparse->SymbolicLinkReparseBuffer.PrintNameLength);
6568     DbgP("Flags:                %08X\n",
6569          Reparse->SymbolicLinkReparseBuffer.Flags);
6570 
6571     name.Buffer = &Reparse->SymbolicLinkReparseBuffer.PathBuffer[
6572         Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
6573     name.MaximumLength = name.Length =
6574         Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength;
6575     DbgP("SubstituteName:       %wZ\n", &name);
6576 
6577     name.Buffer = &Reparse->SymbolicLinkReparseBuffer.PathBuffer[
6578         Reparse->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR)];
6579     name.MaximumLength = name.Length =
6580         Reparse->SymbolicLinkReparseBuffer.PrintNameLength;
6581     DbgP("PrintName:            %wZ\n", &name);
6582 }
6583 
6584 NTSTATUS check_nfs41_setreparse_args(
6585     IN PRX_CONTEXT RxContext)
6586 {
6587     NTSTATUS status = STATUS_SUCCESS;
6588     __notnull XXCTL_LOWIO_COMPONENT *FsCtl = &RxContext->LowIoContext.ParamsFor.FsCtl;
6589     __notnull PREPARSE_DATA_BUFFER Reparse = (PREPARSE_DATA_BUFFER)FsCtl->pInputBuffer;
6590     __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
6591     __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext =
6592         NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
6593     const ULONG HeaderLen = REPARSE_DATA_BUFFER_HEADER_SIZE;
6594 
6595     /* access checks */
6596     if (VNetRootContext->read_only) {
6597         status = STATUS_MEDIA_WRITE_PROTECTED;
6598         goto out;
6599     }
6600     if (!(SrvOpen->DesiredAccess & (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES))) {
6601         status = STATUS_ACCESS_DENIED;
6602         goto out;
6603     }
6604 
6605     /* must have a filename longer than vnetroot name,
6606      * or it's trying to operate on the volume itself */
6607     if (is_root_directory(RxContext)) {
6608         status = STATUS_INVALID_PARAMETER;
6609         goto out;
6610     }
6611     if (FsCtl->pOutputBuffer != NULL) {
6612         status = STATUS_INVALID_PARAMETER;
6613         goto out;
6614     }
6615 
6616     /* validate input buffer and length */
6617     if (!Reparse) {
6618         status = STATUS_INVALID_BUFFER_SIZE;
6619         goto out;
6620     }
6621 
6622     if (FsCtl->InputBufferLength < HeaderLen ||
6623             FsCtl->InputBufferLength > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) {
6624         status = STATUS_IO_REPARSE_DATA_INVALID;
6625         goto out;
6626     }
6627     if (FsCtl->InputBufferLength != HeaderLen + Reparse->ReparseDataLength) {
6628         status = STATUS_IO_REPARSE_DATA_INVALID;
6629         goto out;
6630     }
6631 
6632     /* validate reparse tag */
6633     if (!IsReparseTagValid(Reparse->ReparseTag)) {
6634         status = STATUS_IO_REPARSE_TAG_INVALID;
6635         goto out;
6636     }
6637     if (Reparse->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
6638         status = STATUS_IO_REPARSE_TAG_MISMATCH;
6639         goto out;
6640     }
6641 out:
6642     return status;
6643 }
6644 
6645 NTSTATUS nfs41_SetReparsePoint(
6646     IN OUT PRX_CONTEXT RxContext)
6647 {
6648     NTSTATUS status;
6649     UNICODE_STRING TargetName;
6650     __notnull XXCTL_LOWIO_COMPONENT *FsCtl = &RxContext->LowIoContext.ParamsFor.FsCtl;
6651     __notnull PREPARSE_DATA_BUFFER Reparse = (PREPARSE_DATA_BUFFER)FsCtl->pInputBuffer;
6652     __notnull PNFS41_FOBX Fobx = NFS41GetFobxExtension(RxContext->pFobx);
6653     __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
6654     __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext =
6655         NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
6656     __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
6657         NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
6658     nfs41_updowncall_entry *entry;
6659 
6660 #ifdef DEBUG_SYMLINK
6661     DbgEn();
6662     print_debug_header(RxContext);
6663     print_reparse_buffer(Reparse);
6664 #endif
6665     status = check_nfs41_setreparse_args(RxContext);
6666     if (status) goto out;
6667 
6668     TargetName.MaximumLength = TargetName.Length =
6669         Reparse->SymbolicLinkReparseBuffer.PrintNameLength;
6670     TargetName.Buffer = &Reparse->SymbolicLinkReparseBuffer.PathBuffer[
6671         Reparse->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR)];
6672 
6673     status = nfs41_UpcallCreate(NFS41_SYMLINK, &Fobx->sec_ctx,
6674         VNetRootContext->session, Fobx->nfs41_open_state,
6675         pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
6676     if (status) goto out;
6677 
6678     entry->u.Symlink.target = &TargetName;
6679     entry->u.Symlink.set = TRUE;
6680 
6681     status = nfs41_UpcallWaitForReply(entry, VNetRootContext->timeout);
6682     if (status) goto out;
6683 
6684     status = map_symlink_errors(entry->status);
6685     RxFreePool(entry);
6686 out:
6687 #ifdef DEBUG_SYMLINK
6688     DbgEx();
6689 #endif
6690     return status;
6691 }
6692 
6693 NTSTATUS check_nfs41_getreparse_args(
6694     PRX_CONTEXT RxContext)
6695 {
6696     NTSTATUS status = STATUS_SUCCESS;
6697     XXCTL_LOWIO_COMPONENT *FsCtl = &RxContext->LowIoContext.ParamsFor.FsCtl;
6698     const USHORT HeaderLen = FIELD_OFFSET(REPARSE_DATA_BUFFER,
6699         SymbolicLinkReparseBuffer.PathBuffer);
6700 
6701     /* must have a filename longer than vnetroot name,
6702      * or it's trying to operate on the volume itself */
6703     if (is_root_directory(RxContext)) {
6704         status = STATUS_INVALID_PARAMETER;
6705         goto out;
6706     }
6707     /* ifs reparse tests expect STATUS_INVALID_PARAMETER,
6708      * but 'dir' passes a buffer here when querying symlinks
6709     if (FsCtl->pInputBuffer != NULL) {
6710         status = STATUS_INVALID_PARAMETER;
6711         goto out;
6712     } */
6713     if (!FsCtl->pOutputBuffer) {
6714         status = STATUS_INVALID_USER_BUFFER;
6715         goto out;
6716     }
6717     if (!BooleanFlagOn(RxContext->pFcb->Attributes,
6718             FILE_ATTRIBUTE_REPARSE_POINT)) {
6719         status = STATUS_NOT_A_REPARSE_POINT;
6720         DbgP("FILE_ATTRIBUTE_REPARSE_POINT is not set!\n");
6721         goto out;
6722     }
6723 
6724     if (FsCtl->OutputBufferLength < HeaderLen) {
6725         RxContext->InformationToReturn = HeaderLen;
6726         status = STATUS_BUFFER_TOO_SMALL;
6727         goto out;
6728     }
6729 out:
6730     return status;
6731 }
6732 
6733 NTSTATUS nfs41_GetReparsePoint(
6734     IN OUT PRX_CONTEXT RxContext)
6735 {
6736     NTSTATUS status;
6737     UNICODE_STRING TargetName;
6738     XXCTL_LOWIO_COMPONENT *FsCtl = &RxContext->LowIoContext.ParamsFor.FsCtl;
6739     __notnull PNFS41_FOBX Fobx = NFS41GetFobxExtension(RxContext->pFobx);
6740     __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
6741     __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext =
6742         NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
6743     __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
6744         NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
6745     nfs41_updowncall_entry *entry;
6746     const USHORT HeaderLen = FIELD_OFFSET(REPARSE_DATA_BUFFER,
6747         SymbolicLinkReparseBuffer.PathBuffer);
6748 
6749 #ifdef DEBUG_SYMLINK
6750     DbgEn();
6751 #endif
6752     status = check_nfs41_getreparse_args(RxContext);
6753     if (status) goto out;
6754 
6755     TargetName.Buffer = (PWCH)((PBYTE)FsCtl->pOutputBuffer + HeaderLen);
6756     TargetName.MaximumLength = (USHORT)min(FsCtl->OutputBufferLength -
6757         HeaderLen, 0xFFFF);
6758 
6759     status = nfs41_UpcallCreate(NFS41_SYMLINK, &Fobx->sec_ctx,
6760         VNetRootContext->session, Fobx->nfs41_open_state,
6761         pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
6762     if (status) goto out;
6763 
6764     entry->u.Symlink.target = &TargetName;
6765     entry->u.Symlink.set = FALSE;
6766 
6767     status = nfs41_UpcallWaitForReply(entry, VNetRootContext->timeout);
6768     if (status) goto out;
6769 
6770     status = map_symlink_errors(entry->status);
6771     if (status == STATUS_SUCCESS) {
6772         /* fill in the output buffer */
6773         PREPARSE_DATA_BUFFER Reparse = (PREPARSE_DATA_BUFFER)
6774             FsCtl->pOutputBuffer;
6775         Reparse->ReparseTag = IO_REPARSE_TAG_SYMLINK;
6776         Reparse->ReparseDataLength = HeaderLen + TargetName.Length -
6777             REPARSE_DATA_BUFFER_HEADER_SIZE;
6778         Reparse->Reserved = 0;
6779         Reparse->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
6780         /* PrintName and SubstituteName point to the same string */
6781         Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
6782         Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength =
6783             TargetName.Length;
6784         Reparse->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
6785         Reparse->SymbolicLinkReparseBuffer.PrintNameLength = TargetName.Length;
6786         print_reparse_buffer(Reparse);
6787 
6788         RxContext->IoStatusBlock.Information = HeaderLen + TargetName.Length;
6789     } else if (status == STATUS_BUFFER_TOO_SMALL) {
6790         RxContext->InformationToReturn = HeaderLen + TargetName.Length;
6791     }
6792     RxFreePool(entry);
6793 out:
6794 #ifdef DEBUG_SYMLINK
6795     DbgEx();
6796 #endif
6797     return status;
6798 }
6799 
6800 #ifdef __REACTOS__
6801 NTSTATUS NTAPI nfs41_FsCtl(
6802 #else
6803 NTSTATUS nfs41_FsCtl(
6804 #endif
6805     IN OUT PRX_CONTEXT RxContext)
6806 {
6807     NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
6808 #ifdef DEBUG_MISC
6809     DbgEn();
6810     print_debug_header(RxContext);
6811 #endif
6812     switch (RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode) {
6813     case FSCTL_SET_REPARSE_POINT:
6814         status = nfs41_SetReparsePoint(RxContext);
6815         break;
6816 
6817     case FSCTL_GET_REPARSE_POINT:
6818         status = nfs41_GetReparsePoint(RxContext);
6819         break;
6820 #ifdef DEBUG_MISC
6821     default:
6822         DbgP("FsControlCode: %d\n",
6823              RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode);
6824 #endif
6825     }
6826 #ifdef DEBUG_MISC
6827     DbgEx();
6828 #endif
6829     return status;
6830 }
6831 
6832 #ifdef __REACTOS__
6833 NTSTATUS NTAPI nfs41_CompleteBufferingStateChangeRequest(
6834 #else
6835 NTSTATUS nfs41_CompleteBufferingStateChangeRequest(
6836 #endif
6837     IN OUT PRX_CONTEXT RxContext,
6838     IN OUT PMRX_SRV_OPEN SrvOpen,
6839     IN PVOID pContext)
6840 {
6841     return STATUS_SUCCESS;
6842 }
6843 
6844 #ifdef __REACTOS__
6845 NTSTATUS NTAPI nfs41_FsdDispatch (
6846 #else
6847 NTSTATUS nfs41_FsdDispatch (
6848 #endif
6849     IN PDEVICE_OBJECT dev,
6850     IN PIRP Irp)
6851 {
6852 #ifdef DEBUG_FSDDISPATCH
6853     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
6854 #endif
6855     NTSTATUS status;
6856 
6857 #ifdef DEBUG_FSDDISPATCH
6858     DbgEn();
6859     DbgP("CURRENT IRP = %d.%d\n", IrpSp->MajorFunction, IrpSp->MinorFunction);
6860     if(IrpSp->FileObject)
6861         DbgP("FileOject %p Filename %wZ\n", IrpSp->FileObject,
6862                 &IrpSp->FileObject->FileName);
6863 #endif
6864 
6865     if (dev != (PDEVICE_OBJECT)nfs41_dev) {
6866         print_error("*** not ours ***\n");
6867         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
6868         Irp->IoStatus.Information = 0;
6869         IoCompleteRequest(Irp, IO_NO_INCREMENT );
6870         status = STATUS_INVALID_DEVICE_REQUEST;
6871         goto out;
6872     }
6873 
6874     status = RxFsdDispatch((PRDBSS_DEVICE_OBJECT)dev,Irp);
6875     /* AGLO: 08/05/2009 - looks like RxFsdDispatch frees IrpSp */
6876 
6877 out:
6878 #ifdef DEBUG_FSDDISPATCH
6879     DbgP("IoStatus status = 0x%x info = 0x%x\n", Irp->IoStatus.Status,
6880          Irp->IoStatus.Information);
6881     DbgEx();
6882 #endif
6883     return status;
6884 }
6885 
6886 #ifdef __REACTOS__
6887 NTSTATUS NTAPI nfs41_Unimplemented(
6888 #else
6889 NTSTATUS nfs41_Unimplemented(
6890 #endif
6891     PRX_CONTEXT RxContext)
6892 {
6893     return STATUS_NOT_IMPLEMENTED;
6894 }
6895 
6896 #ifdef __REACTOS__
6897 NTSTATUS NTAPI nfs41_AreFilesAliased(
6898 #else
6899 NTSTATUS nfs41_AreFilesAliased(
6900 #endif
6901     PFCB a,
6902     PFCB b)
6903 {
6904     return STATUS_NOT_IMPLEMENTED;
6905 }
6906 
6907 NTSTATUS nfs41_init_ops()
6908 {
6909     DbgEn();
6910 
6911     ZeroAndInitializeNodeType(&nfs41_ops, RDBSS_NTC_MINIRDR_DISPATCH,
6912         sizeof(MINIRDR_DISPATCH));
6913 
6914     nfs41_ops.MRxFlags = (RDBSS_MANAGE_NET_ROOT_EXTENSION |
6915                             RDBSS_MANAGE_V_NET_ROOT_EXTENSION |
6916                             RDBSS_MANAGE_FCB_EXTENSION |
6917                             RDBSS_MANAGE_FOBX_EXTENSION);
6918 
6919     nfs41_ops.MRxSrvCallSize  = 0; // srvcall extension is not handled in rdbss
6920     nfs41_ops.MRxNetRootSize  = sizeof(NFS41_NETROOT_EXTENSION);
6921     nfs41_ops.MRxVNetRootSize = sizeof(NFS41_V_NET_ROOT_EXTENSION);
6922     nfs41_ops.MRxFcbSize      = sizeof(NFS41_FCB);
6923     nfs41_ops.MRxFobxSize     = sizeof(NFS41_FOBX);
6924 
6925     // Mini redirector cancel routine ..
6926 
6927     nfs41_ops.MRxCancel = NULL;
6928 
6929     //
6930     // Mini redirector Start/Stop. Each mini-rdr can be started or stopped
6931     // while the others continue to operate.
6932     //
6933 
6934     nfs41_ops.MRxStart                = nfs41_Start;
6935     nfs41_ops.MRxStop                 = nfs41_Stop;
6936     nfs41_ops.MRxDevFcbXXXControlFile = nfs41_DevFcbXXXControlFile;
6937 
6938     //
6939     // Mini redirector name resolution.
6940     //
6941 
6942     nfs41_ops.MRxCreateSrvCall       = nfs41_CreateSrvCall;
6943     nfs41_ops.MRxSrvCallWinnerNotify = nfs41_SrvCallWinnerNotify;
6944     nfs41_ops.MRxCreateVNetRoot      = nfs41_CreateVNetRoot;
6945     nfs41_ops.MRxExtractNetRootName  = nfs41_ExtractNetRootName;
6946     nfs41_ops.MRxFinalizeSrvCall     = nfs41_FinalizeSrvCall;
6947     nfs41_ops.MRxFinalizeNetRoot     = nfs41_FinalizeNetRoot;
6948     nfs41_ops.MRxFinalizeVNetRoot    = nfs41_FinalizeVNetRoot;
6949 
6950     //
6951     // File System Object Creation/Deletion.
6952     //
6953 
6954     nfs41_ops.MRxCreate            = nfs41_Create;
6955     nfs41_ops.MRxCollapseOpen      = nfs41_CollapseOpen;
6956     nfs41_ops.MRxShouldTryToCollapseThisOpen = nfs41_ShouldTryToCollapseThisOpen;
6957     nfs41_ops.MRxExtendForCache    = nfs41_ExtendForCache;
6958     nfs41_ops.MRxExtendForNonCache = nfs41_ExtendForCache;
6959     nfs41_ops.MRxCloseSrvOpen      = nfs41_CloseSrvOpen;
6960     nfs41_ops.MRxFlush             = nfs41_Flush;
6961     nfs41_ops.MRxDeallocateForFcb  = nfs41_DeallocateForFcb;
6962     nfs41_ops.MRxDeallocateForFobx = nfs41_DeallocateForFobx;
6963     nfs41_ops.MRxIsLockRealizable    = nfs41_IsLockRealizable;
6964 
6965     //
6966     // File System Objects query/Set
6967     //
6968 
6969     nfs41_ops.MRxQueryDirectory       = nfs41_QueryDirectory;
6970     nfs41_ops.MRxQueryVolumeInfo      = nfs41_QueryVolumeInformation;
6971     nfs41_ops.MRxQueryEaInfo          = nfs41_QueryEaInformation;
6972     nfs41_ops.MRxSetEaInfo            = nfs41_SetEaInformation;
6973     nfs41_ops.MRxQuerySdInfo          = nfs41_QuerySecurityInformation;
6974     nfs41_ops.MRxSetSdInfo            = nfs41_SetSecurityInformation;
6975     nfs41_ops.MRxQueryFileInfo        = nfs41_QueryFileInformation;
6976     nfs41_ops.MRxSetFileInfo          = nfs41_SetFileInformation;
6977 
6978     //
6979     // Buffering state change
6980     //
6981 
6982     nfs41_ops.MRxComputeNewBufferingState = nfs41_ComputeNewBufferingState;
6983 
6984     //
6985     // File System Object I/O
6986     //
6987 
6988     nfs41_ops.MRxLowIOSubmit[LOWIO_OP_READ]            = nfs41_Read;
6989     nfs41_ops.MRxLowIOSubmit[LOWIO_OP_WRITE]           = nfs41_Write;
6990     nfs41_ops.MRxLowIOSubmit[LOWIO_OP_SHAREDLOCK]      = nfs41_Lock;
6991     nfs41_ops.MRxLowIOSubmit[LOWIO_OP_EXCLUSIVELOCK]   = nfs41_Lock;
6992     nfs41_ops.MRxLowIOSubmit[LOWIO_OP_UNLOCK]          = nfs41_Unlock;
6993     nfs41_ops.MRxLowIOSubmit[LOWIO_OP_UNLOCK_MULTIPLE] = nfs41_Unlock;
6994     nfs41_ops.MRxLowIOSubmit[LOWIO_OP_FSCTL]           = nfs41_FsCtl;
6995 
6996     //
6997     // Miscellanous
6998     //
6999 
7000     nfs41_ops.MRxCompleteBufferingStateChangeRequest =
7001         nfs41_CompleteBufferingStateChangeRequest;
7002     nfs41_ops.MRxIsValidDirectory     = nfs41_IsValidDirectory;
7003 
7004     nfs41_ops.MRxTruncate = nfs41_Unimplemented;
7005     nfs41_ops.MRxZeroExtend = nfs41_Unimplemented;
7006     nfs41_ops.MRxAreFilesAliased = nfs41_AreFilesAliased;
7007     nfs41_ops.MRxQueryQuotaInfo = nfs41_Unimplemented;
7008     nfs41_ops.MRxSetQuotaInfo = nfs41_Unimplemented;
7009     nfs41_ops.MRxSetVolumeInfo = nfs41_Unimplemented;
7010 
7011     DbgR();
7012     return(STATUS_SUCCESS);
7013 }
7014 
7015 KSTART_ROUTINE fcbopen_main;
7016 #ifdef __REACTOS__
7017 VOID NTAPI fcbopen_main(PVOID ctx)
7018 #else
7019 VOID fcbopen_main(PVOID ctx)
7020 #endif
7021 {
7022     NTSTATUS status;
7023     LARGE_INTEGER timeout;
7024 
7025     DbgEn();
7026     timeout.QuadPart = RELATIVE(SECONDS(30));
7027     while(1) {
7028         PLIST_ENTRY pEntry;
7029         nfs41_fcb_list_entry *cur;
7030         status = KeDelayExecutionThread(KernelMode, TRUE, &timeout);
7031         ExAcquireFastMutex(&fcblistLock);
7032         pEntry = openlist.head.Flink;
7033         while (!IsListEmpty(&openlist.head)) {
7034             PNFS41_NETROOT_EXTENSION pNetRootContext;
7035             nfs41_updowncall_entry *entry;
7036             FILE_BASIC_INFORMATION binfo;
7037             PNFS41_FCB nfs41_fcb;
7038             cur = (nfs41_fcb_list_entry *)CONTAINING_RECORD(pEntry,
7039                     nfs41_fcb_list_entry, next);
7040 
7041 #ifdef DEBUG_TIME_BASED_COHERENCY
7042             DbgP("fcbopen_main: Checking attributes for fcb=%p "
7043                 "change_time=%llu skipping=%d\n", cur->fcb,
7044                 cur->ChangeTime, cur->skip);
7045 #endif
7046             if (cur->skip) goto out;
7047             pNetRootContext =
7048                 NFS41GetNetRootExtension(cur->fcb->pNetRoot);
7049             /* place an upcall for this srv_open */
7050             status = nfs41_UpcallCreate(NFS41_FILE_QUERY,
7051                 &cur->nfs41_fobx->sec_ctx, cur->session,
7052                 cur->nfs41_fobx->nfs41_open_state,
7053                 pNetRootContext->nfs41d_version, NULL, &entry);
7054             if (status) goto out;
7055 
7056             entry->u.QueryFile.InfoClass = FileBasicInformation;
7057             entry->buf = &binfo;
7058             entry->buf_len = sizeof(binfo);
7059 
7060             status = nfs41_UpcallWaitForReply(entry, UPCALL_TIMEOUT_DEFAULT);
7061             if (status) goto out;
7062 
7063             if (cur->ChangeTime != entry->ChangeTime) {
7064                 ULONG flag = DISABLE_CACHING;
7065                 PMRX_SRV_OPEN srv_open;
7066                 PLIST_ENTRY psrvEntry;
7067 #ifdef DEBUG_TIME_BASED_COHERENCY
7068                 DbgP("fcbopen_main: old ctime=%llu new_ctime=%llu\n",
7069                     cur->ChangeTime, entry->ChangeTime);
7070 #endif
7071                 cur->ChangeTime = entry->ChangeTime;
7072                 cur->skip = TRUE;
7073                 psrvEntry = &cur->fcb->SrvOpenList;
7074                 psrvEntry = psrvEntry->Flink;
7075                 while (!IsListEmpty(&cur->fcb->SrvOpenList)) {
7076                     srv_open = (PMRX_SRV_OPEN)CONTAINING_RECORD(psrvEntry,
7077                             MRX_SRV_OPEN, SrvOpenQLinks);
7078                     if (srv_open->DesiredAccess &
7079                             (FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA)) {
7080 #ifdef DEBUG_TIME_BASED_COHERENCY
7081                         DbgP("fcbopen_main: ************ Invalidate the cache %wZ"
7082                              "************\n", srv_open->pAlreadyPrefixedName);
7083 #endif
7084                         RxIndicateChangeOfBufferingStateForSrvOpen(
7085                             cur->fcb->pNetRoot->pSrvCall, srv_open,
7086                             srv_open->Key, ULongToPtr(flag));
7087                     }
7088                     if (psrvEntry->Flink == &cur->fcb->SrvOpenList) {
7089 #ifdef DEBUG_TIME_BASED_COHERENCY
7090                         DbgP("fcbopen_main: reached end of srvopen for fcb %p\n",
7091                             cur->fcb);
7092 #endif
7093                         break;
7094                     }
7095                     psrvEntry = psrvEntry->Flink;
7096                 };
7097             }
7098             nfs41_fcb = (PNFS41_FCB)cur->fcb->Context;
7099             nfs41_fcb->changeattr = entry->ChangeTime;
7100             RxFreePool(entry);
7101 out:
7102             if (pEntry->Flink == &openlist.head) {
7103 #ifdef DEBUG_TIME_BASED_COHERENCY
7104                 DbgP("fcbopen_main: reached end of the fcb list\n");
7105 #endif
7106                 break;
7107             }
7108             pEntry = pEntry->Flink;
7109         }
7110         ExReleaseFastMutex(&fcblistLock);
7111     }
7112     DbgEx();
7113 }
7114 
7115 #ifdef __REACTOS__
7116 NTSTATUS NTAPI DriverEntry(
7117 #else
7118 NTSTATUS DriverEntry(
7119 #endif
7120     IN PDRIVER_OBJECT drv,
7121     IN PUNICODE_STRING path)
7122 {
7123     NTSTATUS status;
7124     ULONG flags = 0, i;
7125     UNICODE_STRING dev_name, user_dev_name;
7126     PNFS41_DEVICE_EXTENSION dev_exts;
7127     TIME_FIELDS jan_1_1970 = {1970, 1, 1, 0, 0, 0, 0, 0};
7128     ACCESS_MASK mask = 0;
7129     OBJECT_ATTRIBUTES oattrs;
7130 
7131     DbgEn();
7132 
7133     status = RxDriverEntry(drv, path);
7134     if (status != STATUS_SUCCESS) {
7135         print_error("RxDriverEntry failed: %08lx\n", status);
7136         goto out;
7137     }
7138 
7139     RtlInitUnicodeString(&dev_name, NFS41_DEVICE_NAME);
7140     SetFlag(flags, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS);
7141 
7142     status = nfs41_init_ops();
7143     if (status != STATUS_SUCCESS) {
7144         print_error("nfs41_init_ops failed to initialize dispatch table\n");
7145         goto out;
7146     }
7147 
7148     DbgP("calling RxRegisterMinirdr\n");
7149     status = RxRegisterMinirdr(&nfs41_dev, drv, &nfs41_ops, flags, &dev_name,
7150                 sizeof(NFS41_DEVICE_EXTENSION),
7151                 FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_REMOTE_DEVICE);
7152     if (status != STATUS_SUCCESS) {
7153         print_error("RxRegisterMinirdr failed: %08lx\n", status);
7154         goto out;
7155     }
7156 #ifndef __REACTOS__
7157     nfs41_dev->Flags |= DO_BUFFERED_IO;
7158 #endif
7159 
7160     dev_exts = (PNFS41_DEVICE_EXTENSION)
7161         ((PBYTE)(nfs41_dev) + sizeof(RDBSS_DEVICE_OBJECT));
7162 
7163     RxDefineNode(dev_exts, NFS41_DEVICE_EXTENSION);
7164     dev_exts->DeviceObject = nfs41_dev;
7165     nfs41_create_volume_info((PFILE_FS_VOLUME_INFORMATION)dev_exts->VolAttrs,
7166         &dev_exts->VolAttrsLen);
7167 
7168     RtlInitUnicodeString(&user_dev_name, NFS41_SHADOW_DEVICE_NAME);
7169     DbgP("calling IoCreateSymbolicLink %wZ %wZ\n", &user_dev_name, &dev_name);
7170     status = IoCreateSymbolicLink(&user_dev_name, &dev_name);
7171     if (status != STATUS_SUCCESS) {
7172         print_error("Device name IoCreateSymbolicLink failed: %08lx\n", status);
7173         goto out_unregister;
7174     }
7175 
7176     KeInitializeEvent(&upcallEvent, SynchronizationEvent, FALSE );
7177     ExInitializeFastMutex(&upcallLock);
7178     ExInitializeFastMutex(&downcallLock);
7179     ExInitializeFastMutex(&xidLock);
7180     ExInitializeFastMutex(&openOwnerLock);
7181     ExInitializeFastMutex(&fcblistLock);
7182     InitializeListHead(&upcall.head);
7183     InitializeListHead(&downcall.head);
7184     InitializeListHead(&openlist.head);
7185     InitializeObjectAttributes(&oattrs, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
7186     status = PsCreateSystemThread(&dev_exts->openlistHandle, mask,
7187         &oattrs, NULL, NULL, &fcbopen_main, NULL);
7188     if (status != STATUS_SUCCESS)
7189         goto out_unregister;
7190 
7191     drv->DriverUnload = nfs41_driver_unload;
7192 
7193     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
7194         drv->MajorFunction[i] = (PDRIVER_DISPATCH)nfs41_FsdDispatch;
7195 
7196     RtlTimeFieldsToTime(&jan_1_1970, &unix_time_diff);
7197 
7198 out_unregister:
7199     if (status != STATUS_SUCCESS)
7200         RxUnregisterMinirdr(nfs41_dev);
7201 out:
7202     DbgEx();
7203     return status;
7204 }
7205 
7206 #ifdef __REACTOS__
7207 VOID NTAPI nfs41_driver_unload(IN PDRIVER_OBJECT drv)
7208 #else
7209 VOID nfs41_driver_unload(IN PDRIVER_OBJECT drv)
7210 #endif
7211 {
7212     PRX_CONTEXT RxContext;
7213     NTSTATUS    status;
7214     UNICODE_STRING dev_name, pipe_name;
7215 
7216     DbgEn();
7217 
7218     RxContext = RxCreateRxContext(NULL, nfs41_dev, RX_CONTEXT_FLAG_IN_FSP);
7219     if (RxContext == NULL) {
7220         status = STATUS_INSUFFICIENT_RESOURCES;
7221         goto unload;
7222     }
7223     status = RxStopMinirdr(RxContext, &RxContext->PostRequest);
7224     RxDereferenceAndDeleteRxContext(RxContext);
7225 
7226 unload:
7227     RtlInitUnicodeString(&dev_name, NFS41_SHADOW_DEVICE_NAME);
7228     status = IoDeleteSymbolicLink(&dev_name);
7229     if (status != STATUS_SUCCESS) {
7230         print_error("couldn't delete device symbolic link\n");
7231     }
7232     RtlInitUnicodeString(&pipe_name, NFS41_SHADOW_PIPE_NAME);
7233     status = IoDeleteSymbolicLink(&pipe_name);
7234     if (status != STATUS_SUCCESS) {
7235         print_error("couldn't delete pipe symbolic link\n");
7236     }
7237     RxUnload(drv);
7238 
7239     DbgP("driver unloaded %p\n", drv);
7240     DbgR();
7241 }
7242