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(¤t_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