[NFS]
[reactos.git] / reactos / drivers / filesystems / nfs / nfs41_driver.c
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
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
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 */
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
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
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
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 }
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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__
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__
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
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
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
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
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
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
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__
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__
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 switch (InfoClass) {
4550 case FileFsVolumeInformation:
4551 if ((ULONG)RxContext->Info.LengthRemaining >= DevExt->VolAttrsLen) {
4552 RtlCopyMemory(RxContext->Info.Buffer, DevExt->VolAttrs,
4553 DevExt->VolAttrsLen);
4554 RxContext->Info.LengthRemaining -= DevExt->VolAttrsLen;
4555 status = STATUS_SUCCESS;
4556 } else {
4557 RtlCopyMemory(RxContext->Info.Buffer, DevExt->VolAttrs,
4558 RxContext->Info.LengthRemaining);
4559 status = STATUS_BUFFER_OVERFLOW;
4560 }
4561 goto out;
4562 case FileFsDeviceInformation:
4563 {
4564 PFILE_FS_DEVICE_INFORMATION pDevInfo = RxContext->Info.Buffer;
4565
4566 SizeUsed = sizeof(FILE_FS_DEVICE_INFORMATION);
4567 if (RemainingLength < SizeUsed) {
4568 status = STATUS_BUFFER_TOO_SMALL;
4569 RxContext->InformationToReturn = SizeUsed;
4570 goto out;
4571 }
4572 pDevInfo->DeviceType = RxContext->pFcb->pNetRoot->DeviceType;
4573 pDevInfo->Characteristics = FILE_REMOTE_DEVICE | FILE_DEVICE_IS_MOUNTED;
4574 RxContext->Info.LengthRemaining -= SizeUsed;
4575 status = STATUS_SUCCESS;
4576 goto out;
4577 }
4578 case FileAccessInformation:
4579 status = STATUS_NOT_SUPPORTED;
4580 goto out;
4581
4582 case FileFsAttributeInformation:
4583 if (RxContext->Info.LengthRemaining < FS_ATTR_LEN) {
4584 RxContext->InformationToReturn = FS_ATTR_LEN;
4585 status = STATUS_BUFFER_TOO_SMALL;
4586 goto out;
4587 }
4588
4589 /* on attribute queries for the root directory,
4590 * use cached volume attributes from mount */
4591 if (is_root_directory(RxContext)) {
4592 PFILE_FS_ATTRIBUTE_INFORMATION attrs =
4593 (PFILE_FS_ATTRIBUTE_INFORMATION)RxContext->Info.Buffer;
4594 DECLARE_CONST_UNICODE_STRING(FsName, FS_NAME);
4595
4596 RtlCopyMemory(attrs, &pVNetRootContext->FsAttrs,
4597 sizeof(pVNetRootContext->FsAttrs));
4598
4599 /* fill in the FileSystemName */
4600 RtlCopyMemory(attrs->FileSystemName, FsName.Buffer,
4601 FsName.MaximumLength); /* 'MaximumLength' to include null */
4602 attrs->FileSystemNameLength = FsName.Length;
4603
4604 RxContext->Info.LengthRemaining -= FS_ATTR_LEN;
4605 goto out;
4606 }
4607 /* else fall through and send the upcall */
4608 case FileFsSizeInformation:
4609 case FileFsFullSizeInformation:
4610 break;
4611
4612 default:
4613 print_error("nfs41_QueryVolumeInformation: unhandled class %d\n", InfoClass);
4614 status = STATUS_NOT_SUPPORTED;
4615 goto out;
4616 }
4617 status = nfs41_UpcallCreate(NFS41_VOLUME_QUERY, &nfs41_fobx->sec_ctx,
4618 pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
4619 pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
4620 if (status) goto out;
4621
4622 entry->u.Volume.query = InfoClass;
4623 entry->buf = RxContext->Info.Buffer;
4624 entry->buf_len = RxContext->Info.LengthRemaining;
4625
4626 status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
4627 if (status) goto out;
4628
4629 if (entry->status == STATUS_BUFFER_TOO_SMALL) {
4630 RxContext->InformationToReturn = entry->buf_len;
4631 status = STATUS_BUFFER_TOO_SMALL;
4632 } else if (entry->status == STATUS_SUCCESS) {
4633 if (InfoClass == FileFsAttributeInformation) {
4634 /* fill in the FileSystemName */
4635 PFILE_FS_ATTRIBUTE_INFORMATION attrs =
4636 (PFILE_FS_ATTRIBUTE_INFORMATION)RxContext->Info.Buffer;
4637 DECLARE_CONST_UNICODE_STRING(FsName, FS_NAME);
4638
4639 RtlCopyMemory(attrs->FileSystemName, FsName.Buffer,
4640 FsName.MaximumLength); /* 'MaximumLength' to include null */
4641 attrs->FileSystemNameLength = FsName.Length;
4642
4643 entry->buf_len = FS_ATTR_LEN;
4644 }
4645 #ifdef ENABLE_TIMINGS
4646 InterlockedIncrement(&volume.sops);
4647 InterlockedAdd64(&volume.size, entry->u.Volume.buf_len);
4648 #endif
4649 RxContext->Info.LengthRemaining -= entry->buf_len;
4650 status = STATUS_SUCCESS;
4651 } else {
4652 status = map_volume_errors(entry->status);
4653 }
4654 RxFreePool(entry);
4655 out:
4656 #ifdef ENABLE_TIMINGS
4657 t2 = KeQueryPerformanceCounter(NULL);
4658 InterlockedIncrement(&volume.tops);
4659 InterlockedAdd64(&volume.ticks, t2.QuadPart - t1.QuadPart);
4660 #ifdef ENABLE_INDV_TIMINGS
4661 DbgP("nfs41_QueryVolumeInformation delta = %d op=%d sum=%d\n",
4662 t2.QuadPart - t1.QuadPart, volume.tops, volume.ticks);
4663 #endif
4664 #endif
4665 #ifdef DEBUG_VOLUME_QUERY
4666 DbgEx();
4667 #endif
4668 return status;
4669 }
4670
4671 VOID nfs41_update_fcb_list(
4672 PMRX_FCB fcb,
4673 ULONGLONG ChangeTime)
4674 {
4675 PLIST_ENTRY pEntry;
4676 nfs41_fcb_list_entry *cur;
4677 ExAcquireFastMutex(&fcblistLock);
4678 pEntry = openlist.head.Flink;
4679 while (!IsListEmpty(&openlist.head)) {
4680 cur = (nfs41_fcb_list_entry *)CONTAINING_RECORD(pEntry,
4681 nfs41_fcb_list_entry, next);
4682 if (cur->fcb == fcb &&
4683 cur->ChangeTime != ChangeTime) {
4684 #if defined(DEBUG_FILE_SET) || defined(DEBUG_ACL_SET) || \
4685 defined(DEBUG_WRITE) || defined(DEBUG_EA_SET)
4686 DbgP("nfs41_update_fcb_list: Found match for fcb %p: updating "
4687 "%llu to %llu\n", fcb, cur->ChangeTime, ChangeTime);
4688 #endif
4689 cur->ChangeTime = ChangeTime;
4690 break;
4691 }
4692 /* place an upcall for this srv_open */
4693 if (pEntry->Flink == &openlist.head) {
4694 #if defined(DEBUG_FILE_SET) || defined(DEBUG_ACL_SET) || \
4695 defined(DEBUG_WRITE) || defined(DEBUG_EA_SET)
4696 DbgP("nfs41_update_fcb_list: reached EOL loooking for "
4697 "fcb=%p\n", fcb);
4698 #endif
4699 break;
4700 }
4701 pEntry = pEntry->Flink;
4702 }
4703 ExReleaseFastMutex(&fcblistLock);
4704 }
4705
4706 void print_nfs3_attrs(
4707 nfs3_attrs *attrs)
4708 {
4709 DbgP("type=%d mode=%o nlink=%d size=%d atime=%x mtime=%x ctime=%x\n",
4710 attrs->type, attrs->mode, attrs->nlink, attrs->size, attrs->atime,
4711 attrs->mtime, attrs->ctime);
4712 }
4713
4714 void file_time_to_nfs_time(
4715 IN const PLARGE_INTEGER file_time,
4716 OUT LONGLONG *nfs_time)
4717 {
4718 LARGE_INTEGER diff = unix_time_diff;
4719 diff.QuadPart = file_time->QuadPart - diff.QuadPart;
4720 *nfs_time = diff.QuadPart / 10000000;
4721 }
4722
4723 void create_nfs3_attrs(
4724 nfs3_attrs *attrs,
4725 PNFS41_FCB nfs41_fcb)
4726 {
4727 RtlZeroMemory(attrs, sizeof(nfs3_attrs));
4728 if (nfs41_fcb->BasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
4729 attrs->type = NF3LNK;
4730 else if (nfs41_fcb->StandardInfo.Directory)
4731 attrs->type = NF3DIR;
4732 else
4733 attrs->type = NF3REG;
4734 attrs->mode = nfs41_fcb->mode;
4735 attrs->nlink = nfs41_fcb->StandardInfo.NumberOfLinks;
4736 attrs->size.QuadPart = attrs->used.QuadPart =
4737 nfs41_fcb->StandardInfo.EndOfFile.QuadPart;
4738 file_time_to_nfs_time(&nfs41_fcb->BasicInfo.LastAccessTime, &attrs->atime);
4739 file_time_to_nfs_time(&nfs41_fcb->BasicInfo.ChangeTime, &attrs->mtime);
4740 file_time_to_nfs_time(&nfs41_fcb->BasicInfo.CreationTime, &attrs->ctime);
4741 }
4742
4743
4744 NTSTATUS map_setea_error(
4745 DWORD error)
4746 {
4747 switch (error) {
4748 case NO_ERROR: return STATUS_SUCCESS;
4749 case ERROR_FILE_NOT_FOUND: return STATUS_NO_EAS_ON_FILE;
4750 case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED;
4751 case ERROR_NETWORK_ACCESS_DENIED: return STATUS_NETWORK_ACCESS_DENIED;
4752 case ERROR_NETNAME_DELETED: return STATUS_NETWORK_NAME_DELETED;
4753 case ERROR_FILE_TOO_LARGE: return STATUS_EA_TOO_LARGE;
4754 case ERROR_BUFFER_OVERFLOW: return STATUS_BUFFER_OVERFLOW;
4755 case STATUS_BUFFER_TOO_SMALL:
4756 case ERROR_INSUFFICIENT_BUFFER: return STATUS_BUFFER_TOO_SMALL;
4757 case ERROR_INVALID_EA_HANDLE: return STATUS_NONEXISTENT_EA_ENTRY;
4758 case ERROR_NO_MORE_FILES: return STATUS_NO_MORE_EAS;
4759 case ERROR_EA_FILE_CORRUPT: return STATUS_EA_CORRUPT_ERROR;
4760 default:
4761 print_error("failed to map windows error %d to NTSTATUS; "
4762 "defaulting to STATUS_INVALID_PARAMETER\n", error);
4763 case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
4764 }
4765 }
4766
4767 NTSTATUS check_nfs41_setea_args(
4768 IN PRX_CONTEXT RxContext)
4769 {
4770 NTSTATUS status;
4771 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
4772 NFS41GetVNetRootExtension(RxContext->pRelevantSrvOpen->pVNetRoot);
4773 __notnull PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs =
4774 &pVNetRootContext->FsAttrs;
4775 __notnull PFILE_FULL_EA_INFORMATION ea =
4776 (PFILE_FULL_EA_INFORMATION)RxContext->Info.Buffer;
4777
4778 status = check_nfs41_dirquery_args(RxContext);
4779 if (status) goto out;
4780
4781 if (ea == NULL) {
4782 status = STATUS_INVALID_PARAMETER;
4783 goto out;
4784 }
4785 if (AnsiStrEq(&NfsActOnLink, ea->EaName, ea->EaNameLength) ||
4786 AnsiStrEq(&NfsSymlinkTargetName, ea->EaName, ea->EaNameLength)) {
4787 status = STATUS_INVALID_PARAMETER; /* only allowed on create */
4788 goto out;
4789 }
4790 /* ignore cygwin EAs when checking support */
4791 if (!(FsAttrs->FileSystemAttributes & FILE_SUPPORTS_EXTENDED_ATTRIBUTES)
4792 && !AnsiStrEq(&NfsV3Attributes, ea->EaName, ea->EaNameLength)) {
4793 status = STATUS_EAS_NOT_SUPPORTED;
4794 goto out;
4795 }
4796 if ((RxContext->pRelevantSrvOpen->DesiredAccess & FILE_WRITE_EA) == 0) {
4797 status = STATUS_ACCESS_DENIED;
4798 goto out;
4799 }
4800 if (pVNetRootContext->read_only) {
4801 print_error("check_nfs41_setattr_args: Read-only mount\n");
4802 status = STATUS_ACCESS_DENIED;
4803 goto out;
4804 }
4805 out:
4806 return status;
4807 }
4808
4809 #ifdef __REACTOS__
4810 NTSTATUS NTAPI nfs41_SetEaInformation(
4811 #else
4812 NTSTATUS nfs41_SetEaInformation(
4813 #endif
4814 IN OUT PRX_CONTEXT RxContext)
4815 {
4816 NTSTATUS status = STATUS_EAS_NOT_SUPPORTED;
4817 nfs41_updowncall_entry *entry;
4818 __notnull PFILE_FULL_EA_INFORMATION eainfo =
4819 (PFILE_FULL_EA_INFORMATION)RxContext->Info.Buffer;
4820 nfs3_attrs *attrs = NULL;
4821 ULONG buflen = RxContext->CurrentIrpSp->Parameters.SetEa.Length, error_offset;
4822 __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
4823 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
4824 NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
4825 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
4826 NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
4827 __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
4828 __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
4829 #ifdef ENABLE_TIMINGS
4830 LARGE_INTEGER t1, t2;
4831 t1 = KeQueryPerformanceCounter(NULL);
4832 #endif
4833
4834 #ifdef DEBUG_EA_SET
4835 DbgEn();
4836 print_debug_header(RxContext);
4837 print_ea_info(1, eainfo);
4838 #endif
4839
4840 status = check_nfs41_setea_args(RxContext);
4841 if (status) goto out;
4842
4843 status = nfs41_UpcallCreate(NFS41_EA_SET, &nfs41_fobx->sec_ctx,
4844 pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
4845 pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
4846 if (status) goto out;
4847
4848 if (AnsiStrEq(&NfsV3Attributes, eainfo->EaName, eainfo->EaNameLength)) {
4849 attrs = (nfs3_attrs *)(eainfo->EaName + eainfo->EaNameLength + 1);
4850 #ifdef DEBUG_EA_SET
4851 print_nfs3_attrs(attrs);
4852 DbgP("old mode is %o new mode is %o\n", nfs41_fcb->mode, attrs->mode);
4853 #endif
4854 entry->u.SetEa.mode = attrs->mode;
4855 } else {
4856 entry->u.SetEa.mode = 0;
4857 status = IoCheckEaBufferValidity(eainfo, buflen, &error_offset);
4858 if (status) {
4859 RxFreePool(entry);
4860 goto out;
4861 }
4862 }
4863 entry->buf = eainfo;
4864 entry->buf_len = buflen;
4865
4866 status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
4867 if (status) goto out;
4868 #ifdef ENABLE_TIMINGS
4869 if (entry->status == STATUS_SUCCESS) {
4870 InterlockedIncrement(&setexattr.sops);
4871 InterlockedAdd64(&setexattr.size, entry->u.SetEa.buf_len);
4872 }
4873 #endif
4874 status = map_setea_error(entry->status);
4875 if (!status) {
4876 if (!nfs41_fobx->deleg_type && entry->ChangeTime &&
4877 (SrvOpen->DesiredAccess &
4878 (FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA)))
4879 nfs41_update_fcb_list(RxContext->pFcb, entry->ChangeTime);
4880 nfs41_fcb->changeattr = entry->ChangeTime;
4881 nfs41_fcb->mode = entry->u.SetEa.mode;
4882 }
4883 RxFreePool(entry);
4884 out:
4885 #ifdef ENABLE_TIMINGS
4886 t2 = KeQueryPerformanceCounter(NULL);
4887 InterlockedIncrement(&setexattr.tops);
4888 InterlockedAdd64(&setexattr.ticks, t2.QuadPart - t1.QuadPart);
4889 #ifdef ENABLE_INDV_TIMINGS
4890 DbgP("nfs41_SetEaInformation delta = %d op=%d sum=%d\n",
4891 t2.QuadPart - t1.QuadPart, setexattr.tops, setexattr.ticks);
4892 #endif
4893 #endif
4894 #ifdef DEBUG_EA_SET
4895 DbgEx();
4896 #endif
4897 return status;
4898 }
4899
4900 NTSTATUS check_nfs41_queryea_args(
4901 IN PRX_CONTEXT RxContext)
4902 {
4903 NTSTATUS status;
4904 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
4905 NFS41GetVNetRootExtension(RxContext->pRelevantSrvOpen->pVNetRoot);
4906 __notnull PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs =
4907 &pVNetRootContext->FsAttrs;
4908 PFILE_GET_EA_INFORMATION ea = (PFILE_GET_EA_INFORMATION)
4909 RxContext->CurrentIrpSp->Parameters.QueryEa.EaList;
4910
4911 status = check_nfs41_dirquery_args(RxContext);
4912 if (status) goto out;
4913
4914 if (!(FsAttrs->FileSystemAttributes & FILE_SUPPORTS_EXTENDED_ATTRIBUTES)) {
4915 if (ea == NULL) {
4916 status = STATUS_EAS_NOT_SUPPORTED;
4917 goto out;
4918 }
4919 /* ignore cygwin EAs when checking support */
4920 if (!AnsiStrEq(&NfsV3Attributes, ea->EaName, ea->EaNameLength) &&
4921 !AnsiStrEq(&NfsActOnLink, ea->EaName, ea->EaNameLength) &&
4922 !AnsiStrEq(&NfsSymlinkTargetName, ea->EaName, ea->EaNameLength)) {
4923 status = STATUS_EAS_NOT_SUPPORTED;
4924 goto out;
4925 }
4926 }
4927 if ((RxContext->pRelevantSrvOpen->DesiredAccess & FILE_READ_EA) == 0) {
4928 status = STATUS_ACCESS_DENIED;
4929 goto out;
4930 }
4931 out:
4932 return status;
4933 }
4934
4935 static NTSTATUS QueryCygwinSymlink(
4936 IN OUT PRX_CONTEXT RxContext,
4937 IN PFILE_GET_EA_INFORMATION query,
4938 OUT PFILE_FULL_EA_INFORMATION info)
4939 {
4940 __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
4941 __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext =
4942 NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
4943 __notnull PNFS41_NETROOT_EXTENSION NetRootContext =
4944 NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
4945 __notnull PNFS41_FOBX Fobx = NFS41GetFobxExtension(RxContext->pFobx);
4946 nfs41_updowncall_entry *entry;
4947 UNICODE_STRING TargetName;
4948 const USHORT HeaderLen = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) +
4949 query->EaNameLength + 1;
4950 NTSTATUS status;
4951
4952 if (RxContext->Info.LengthRemaining < HeaderLen) {
4953 status = STATUS_BUFFER_TOO_SMALL;
4954 RxContext->InformationToReturn = HeaderLen;
4955 goto out;
4956 }
4957
4958 TargetName.Buffer = (PWCH)(info->EaName + query->EaNameLength + 1);
4959 TargetName.MaximumLength = (USHORT)min(RxContext->Info.LengthRemaining -
4960 HeaderLen, 0xFFFF);
4961
4962 status = nfs41_UpcallCreate(NFS41_SYMLINK, &Fobx->sec_ctx,
4963 VNetRootContext->session, Fobx->nfs41_open_state,
4964 NetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
4965 if (status) goto out;
4966
4967 entry->u.Symlink.target = &TargetName;
4968 entry->u.Symlink.set = FALSE;
4969
4970 status = nfs41_UpcallWaitForReply(entry, VNetRootContext->timeout);
4971 if (status) goto out;
4972
4973 status = map_setea_error(entry->status);
4974 if (status == STATUS_SUCCESS) {
4975 info->NextEntryOffset = 0;
4976 info->Flags = 0;
4977 info->EaNameLength = query->EaNameLength;
4978 info->EaValueLength = TargetName.Length - sizeof(UNICODE_NULL);
4979 TargetName.Buffer[TargetName.Length/sizeof(WCHAR)] = UNICODE_NULL;
4980 RtlCopyMemory(info->EaName, query->EaName, query->EaNameLength);
4981 RxContext->Info.LengthRemaining = HeaderLen + info->EaValueLength;
4982 } else if (status == STATUS_BUFFER_TOO_SMALL) {
4983 RxContext->InformationToReturn = HeaderLen +
4984 entry->u.Symlink.target->Length;
4985 }
4986 RxFreePool(entry);
4987 out:
4988 return status;
4989 }
4990
4991 static NTSTATUS QueryCygwinEA(
4992 IN OUT PRX_CONTEXT RxContext,
4993 IN PFILE_GET_EA_INFORMATION query,
4994 OUT PFILE_FULL_EA_INFORMATION info)
4995 {
4996 NTSTATUS status = STATUS_NONEXISTENT_EA_ENTRY;
4997
4998 if (query == NULL)
4999 goto out;
5000
5001 if (AnsiStrEq(&NfsSymlinkTargetName, query->EaName, query->EaNameLength)) {
5002 __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
5003 if (nfs41_fcb->BasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
5004 status = QueryCygwinSymlink(RxContext, query, info);
5005 goto out;
5006 } else {
5007 const LONG LengthRequired = sizeof(FILE_FULL_EA_INFORMATION) +
5008 NfsSymlinkTargetName.Length - sizeof(CHAR);
5009 if (LengthRequired > RxContext->Info.LengthRemaining) {
5010 status = STATUS_BUFFER_TOO_SMALL;
5011 RxContext->InformationToReturn = LengthRequired;
5012 goto out;
5013 }
5014 info->NextEntryOffset = 0;
5015 info->Flags = 0;
5016 info->EaValueLength = 0;
5017 info->EaNameLength = (UCHAR)NfsActOnLink.Length;
5018 RtlCopyMemory(info->EaName, NfsSymlinkTargetName.Buffer,
5019 NfsSymlinkTargetName.Length);
5020 RxContext->Info.LengthRemaining = LengthRequired;
5021 status = STATUS_SUCCESS;
5022 goto out;
5023 }
5024 }
5025
5026 if (AnsiStrEq(&NfsV3Attributes, query->EaName, query->EaNameLength)) {
5027 nfs3_attrs attrs;
5028
5029 const LONG LengthRequired = sizeof(FILE_FULL_EA_INFORMATION) +
5030 NfsV3Attributes.Length + sizeof(nfs3_attrs) - sizeof(CHAR);
5031 if (LengthRequired > RxContext->Info.LengthRemaining) {
5032 status = STATUS_BUFFER_TOO_SMALL;
5033 RxContext->InformationToReturn = LengthRequired;
5034 goto out;
5035 }
5036
5037 create_nfs3_attrs(&attrs, NFS41GetFcbExtension(RxContext->pFcb));
5038 #ifdef DEBUG_EA_QUERY
5039 print_nfs3_attrs(&attrs);
5040 #endif
5041
5042 info->NextEntryOffset = 0;
5043 info->Flags = 0;
5044 info->EaNameLength = (UCHAR)NfsV3Attributes.Length;
5045 info->EaValueLength = sizeof(nfs3_attrs);
5046 RtlCopyMemory(info->EaName, NfsV3Attributes.Buffer,
5047 NfsV3Attributes.Length);
5048 RtlCopyMemory(info->EaName + info->EaNameLength + 1, &attrs,
5049 sizeof(nfs3_attrs));
5050 RxContext->Info.LengthRemaining = LengthRequired;
5051 status = STATUS_SUCCESS;
5052 goto out;
5053 }
5054
5055 if (AnsiStrEq(&NfsActOnLink, query->EaName, query->EaNameLength)) {
5056
5057 const LONG LengthRequired = sizeof(FILE_FULL_EA_INFORMATION) +
5058 query->EaNameLength - sizeof(CHAR);
5059 if (LengthRequired > RxContext->Info.LengthRemaining) {
5060 status = STATUS_BUFFER_TOO_SMALL;
5061 RxContext->InformationToReturn = LengthRequired;
5062 goto out;
5063 }
5064
5065 info->NextEntryOffset = 0;
5066 info->Flags = 0;
5067 info->EaNameLength = query->EaNameLength;
5068 info->EaValueLength = 0;
5069 RtlCopyMemory(info->EaName, query->EaName, query->EaNameLength);
5070 RxContext->Info.LengthRemaining = LengthRequired;
5071 status = STATUS_SUCCESS;
5072 goto out;
5073 }
5074 out:
5075 return status;
5076 }
5077
5078 #ifdef __REACTOS__
5079 NTSTATUS NTAPI nfs41_QueryEaInformation(
5080 #else
5081 NTSTATUS nfs41_QueryEaInformation(
5082 #endif
5083 IN OUT PRX_CONTEXT RxContext)
5084 {
5085 NTSTATUS status = STATUS_EAS_NOT_SUPPORTED;
5086 nfs41_updowncall_entry *entry;
5087 PFILE_GET_EA_INFORMATION query = (PFILE_GET_EA_INFORMATION)
5088 RxContext->CurrentIrpSp->Parameters.QueryEa.EaList;
5089 ULONG buflen = RxContext->CurrentIrpSp->Parameters.QueryEa.Length;
5090 __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
5091 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
5092 NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
5093 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
5094 NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
5095 __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
5096 #ifdef ENABLE_TIMINGS
5097 LARGE_INTEGER t1, t2;
5098 t1 = KeQueryPerformanceCounter(NULL);
5099 #endif
5100
5101 #ifdef DEBUG_EA_QUERY
5102 DbgEn();
5103 print_debug_header(RxContext);
5104 print_get_ea(1, query);
5105 #endif
5106 status = check_nfs41_queryea_args(RxContext);
5107 if (status) goto out;
5108
5109 /* handle queries for cygwin EAs */
5110 status = QueryCygwinEA(RxContext, query,
5111 (PFILE_FULL_EA_INFORMATION)RxContext->Info.Buffer);
5112 if (status != STATUS_NONEXISTENT_EA_ENTRY)
5113 goto out;
5114
5115 status = nfs41_UpcallCreate(NFS41_EA_GET, &nfs41_fobx->sec_ctx,
5116 pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
5117 pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
5118 if (status) goto out;
5119
5120 entry->buf_len = buflen;
5121 entry->buf = RxContext->Info.Buffer;
5122 entry->u.QueryEa.EaList = query;
5123 entry->u.QueryEa.EaListLength = query == NULL ? 0 :
5124 RxContext->QueryEa.UserEaListLength;
5125 entry->u.QueryEa.EaIndex = RxContext->QueryEa.IndexSpecified ?
5126 RxContext->QueryEa.UserEaIndex : 0;
5127 entry->u.QueryEa.RestartScan = RxContext->QueryEa.RestartScan;
5128 entry->u.QueryEa.ReturnSingleEntry = RxContext->QueryEa.ReturnSingleEntry;
5129
5130 status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
5131 if (status) goto out;
5132
5133 if (entry->status == STATUS_SUCCESS) {
5134 switch (entry->u.QueryEa.Overflow) {
5135 case ERROR_INSUFFICIENT_BUFFER:
5136 status = STATUS_BUFFER_TOO_SMALL;
5137 break;
5138 case ERROR_BUFFER_OVERFLOW:
5139 status = RxContext->IoStatusBlock.Status = STATUS_BUFFER_OVERFLOW;
5140 break;
5141 default:
5142 RxContext->IoStatusBlock.Status = STATUS_SUCCESS;
5143 break;
5144 }
5145 RxContext->InformationToReturn = entry->buf_len;
5146 #ifdef ENABLE_TIMINGS
5147 InterlockedIncrement(&getexattr.sops);
5148 InterlockedAdd64(&getexattr.size, entry->u.QueryEa.buf_len);
5149 #endif
5150 } else {
5151 status = map_setea_error(entry->status);
5152 }
5153 RxFreePool(entry);
5154 out:
5155 #ifdef ENABLE_TIMINGS
5156 t2 = KeQueryPerformanceCounter(NULL);
5157 InterlockedIncrement(&getexattr.tops);
5158 InterlockedAdd64(&getexattr.ticks, t2.QuadPart - t1.QuadPart);
5159 #ifdef ENABLE_INDV_TIMINGS
5160 DbgP("nfs41_QueryEaInformation delta = %d op=%d sum=%d\n",
5161 t2.QuadPart - t1.QuadPart, getexattr.tops, getexattr.ticks);
5162 #endif
5163 #endif
5164 #ifdef DEBUG_EA_QUERY
5165 DbgEx();
5166 #endif
5167 return status;
5168 }
5169
5170 NTSTATUS map_query_acl_error(
5171 DWORD error)
5172 {
5173 switch (error) {
5174 case NO_ERROR: return STATUS_SUCCESS;
5175 case ERROR_NOT_SUPPORTED: return STATUS_NOT_SUPPORTED;
5176 case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED;
5177 case ERROR_FILE_NOT_FOUND: return STATUS_OBJECT_NAME_NOT_FOUND;
5178 case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
5179 default:
5180 print_error("failed to map windows error %d to NTSTATUS; "
5181 "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", error);
5182 case ERROR_BAD_NET_RESP: return STATUS_INVALID_NETWORK_RESPONSE;
5183 }
5184 }
5185
5186 NTSTATUS check_nfs41_getacl_args(
5187 PRX_CONTEXT RxContext)
5188 {
5189 NTSTATUS status = STATUS_SUCCESS;
5190 SECURITY_INFORMATION info_class =
5191 RxContext->CurrentIrpSp->Parameters.QuerySecurity.SecurityInformation;
5192
5193 /* we don't support sacls */
5194 if (info_class == SACL_SECURITY_INFORMATION ||
5195 info_class == LABEL_SECURITY_INFORMATION) {
5196 status = STATUS_NOT_SUPPORTED;
5197 goto out;
5198 }
5199 if (RxContext->CurrentIrp->UserBuffer == NULL &&
5200 RxContext->CurrentIrpSp->Parameters.QuerySecurity.Length)
5201 status = STATUS_INVALID_USER_BUFFER;
5202 out:
5203 return status;
5204 }
5205
5206 #ifdef __REACTOS__
5207 NTSTATUS NTAPI nfs41_QuerySecurityInformation(
5208 #else
5209 NTSTATUS nfs41_QuerySecurityInformation(
5210 #endif
5211 IN OUT PRX_CONTEXT RxContext)
5212 {
5213 NTSTATUS status = STATUS_NOT_SUPPORTED;
5214 nfs41_updowncall_entry *entry;
5215 __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
5216 __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
5217 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
5218 NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
5219 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
5220 NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
5221 SECURITY_INFORMATION info_class =
5222 RxContext->CurrentIrpSp->Parameters.QuerySecurity.SecurityInformation;
5223 #ifdef ENABLE_TIMINGS
5224 LARGE_INTEGER t1, t2;
5225 t1 = KeQueryPerformanceCounter(NULL);
5226 #endif
5227
5228 #ifdef DEBUG_ACL_QUERY
5229 DbgEn();
5230 print_debug_header(RxContext);
5231 print_acl_args(info_class);
5232 #endif
5233
5234 status = check_nfs41_getacl_args(RxContext);
5235 if (status) goto out;
5236
5237 if (nfs41_fobx->acl && nfs41_fobx->acl_len) {
5238 LARGE_INTEGER current_time;
5239 KeQuerySystemTime(&current_time);
5240 #ifdef DEBUG_ACL_QUERY
5241 DbgP("CurrentTime %lx Saved Acl time %lx\n",
5242 current_time.QuadPart, nfs41_fobx->time.QuadPart);
5243 #endif
5244 if (current_time.QuadPart - nfs41_fobx->time.QuadPart <= 20*1000) {
5245 PSECURITY_DESCRIPTOR sec_desc = (PSECURITY_DESCRIPTOR)
5246 RxContext->CurrentIrp->UserBuffer;
5247 RtlCopyMemory(sec_desc, nfs41_fobx->acl, nfs41_fobx->acl_len);
5248 RxContext->IoStatusBlock.Information =
5249 RxContext->InformationToReturn = nfs41_fobx->acl_len;
5250 RxContext->IoStatusBlock.Status = status = STATUS_SUCCESS;
5251 #ifdef ENABLE_TIMINGS
5252 InterlockedIncrement(&getacl.sops);
5253 InterlockedAdd64(&getacl.size, nfs41_fobx->acl_len);
5254 #endif
5255 } else status = 1;
5256 RxFreePool(nfs41_fobx->acl);
5257 nfs41_fobx->acl = NULL;
5258 nfs41_fobx->acl_len = 0;
5259 if (!status)
5260 goto out;
5261 }
5262
5263 status = nfs41_UpcallCreate(NFS41_ACL_QUERY, &nfs41_fobx->sec_ctx,
5264 pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
5265 pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
5266 if (status) goto out;
5267
5268 entry->u.Acl.query = info_class;
5269 /* we can't provide RxContext->CurrentIrp->UserBuffer to the upcall thread
5270 * because it becomes an invalid pointer with that execution context
5271 */
5272 entry->buf_len = RxContext->CurrentIrpSp->Parameters.QuerySecurity.Length;
5273
5274 status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
5275 if (status) goto out;
5276
5277 if (entry->status == STATUS_BUFFER_TOO_SMALL) {
5278 #ifdef DEBUG_ACL_QUERY
5279 DbgP("nfs41_QuerySecurityInformation: provided buffer size=%d but we "
5280 "need %lu\n",
5281 RxContext->CurrentIrpSp->Parameters.QuerySecurity.Length,
5282 entry->buf_len);
5283 #endif
5284 status = STATUS_BUFFER_OVERFLOW;
5285 RxContext->InformationToReturn = entry->buf_len;
5286
5287 /* Save ACL buffer */
5288 nfs41_fobx->acl = entry->buf;
5289 nfs41_fobx->acl_len = entry->buf_len;
5290 KeQuerySystemTime(&nfs41_fobx->time);
5291 } else if (entry->status == STATUS_SUCCESS) {
5292 PSECURITY_DESCRIPTOR sec_desc = (PSECURITY_DESCRIPTOR)
5293 RxContext->CurrentIrp->UserBuffer;
5294 RtlCopyMemory(sec_desc, entry->buf, entry->buf_len);
5295 #ifdef ENABLE_TIMINGS
5296 InterlockedIncrement(&getacl.sops);
5297 InterlockedAdd64(&getacl.size, entry->u.Acl.buf_len);
5298 #endif
5299 RxFreePool(entry->buf);
5300 nfs41_fobx->acl = NULL;
5301 nfs41_fobx->acl_len = 0;
5302 RxContext->IoStatusBlock.Information = RxContext->InformationToReturn =
5303 entry->buf_len;
5304 RxContext->IoStatusBlock.Status = status = STATUS_SUCCESS;
5305 } else {
5306 status = map_query_acl_error(entry->status);
5307 }
5308 RxFreePool(entry);
5309 out:
5310 #ifdef ENABLE_TIMINGS
5311 t2 = KeQueryPerformanceCounter(NULL);
5312 /* only count getacl that we made an upcall for */
5313 if (status == STATUS_BUFFER_OVERFLOW) {
5314 InterlockedIncrement(&getacl.tops);
5315 InterlockedAdd64(&getacl.ticks, t2.QuadPart - t1.QuadPart);
5316 }
5317 #ifdef ENABLE_INDV_TIMINGS
5318 DbgP("nfs41_QuerySecurityInformation: delta = %d op=%d sum=%d\n",
5319 t2.QuadPart - t1.QuadPart, getacl.tops, getacl.ticks);
5320 #endif
5321 #endif
5322 #ifdef DEBUG_ACL_QUERY
5323 DbgEx();
5324 #endif
5325 return status;
5326 }
5327
5328 NTSTATUS check_nfs41_setacl_args(
5329 PRX_CONTEXT RxContext)
5330 {
5331 NTSTATUS status = STATUS_SUCCESS;
5332 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
5333 NFS41GetVNetRootExtension(RxContext->pRelevantSrvOpen->pVNetRoot);
5334 SECURITY_INFORMATION info_class =
5335 RxContext->CurrentIrpSp->Parameters.SetSecurity.SecurityInformation;
5336
5337 if (pVNetRootContext->read_only) {
5338 print_error("check_nfs41_setacl_args: Read-only mount\n");
5339 status = STATUS_ACCESS_DENIED;
5340 goto out;
5341 }
5342 /* we don't support sacls */
5343 if (info_class == SACL_SECURITY_INFORMATION ||
5344 info_class == LABEL_SECURITY_INFORMATION) {
5345 status = STATUS_NOT_SUPPORTED;
5346 goto out;
5347 }
5348 out:
5349 return status;
5350 }
5351
5352 #ifdef __REACTOS__
5353 NTSTATUS NTAPI nfs41_SetSecurityInformation(
5354 #else
5355 NTSTATUS nfs41_SetSecurityInformation(
5356 #endif
5357 IN OUT PRX_CONTEXT RxContext)
5358 {
5359 NTSTATUS status = STATUS_NOT_SUPPORTED;
5360 nfs41_updowncall_entry *entry;
5361 __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
5362 __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
5363 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
5364 NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
5365 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
5366 NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
5367 __notnull PSECURITY_DESCRIPTOR sec_desc =
5368 RxContext->CurrentIrpSp->Parameters.SetSecurity.SecurityDescriptor;
5369 __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
5370 SECURITY_INFORMATION info_class =
5371 RxContext->CurrentIrpSp->Parameters.SetSecurity.SecurityInformation;
5372 #ifdef ENABLE_TIMINGS
5373 LARGE_INTEGER t1, t2;
5374 t1 = KeQueryPerformanceCounter(NULL);
5375 #endif
5376
5377 #ifdef DEBUG_ACL_SET
5378 DbgEn();
5379 print_debug_header(RxContext);
5380 print_acl_args(info_class);
5381 #endif
5382
5383 status = check_nfs41_setacl_args(RxContext);
5384 if (status) goto out;
5385
5386 /* check that ACL is present */
5387 if (info_class & DACL_SECURITY_INFORMATION) {
5388 PACL acl;
5389 BOOLEAN present, dacl_default;
5390 status = RtlGetDaclSecurityDescriptor(sec_desc, &present, &acl,
5391 &dacl_default);
5392 if (status) {
5393 DbgP("RtlGetDaclSecurityDescriptor failed %x\n", status);
5394 goto out;
5395 }
5396 if (present == FALSE) {
5397 DbgP("NO ACL present\n");
5398 goto out;
5399 }
5400 }
5401
5402 status = nfs41_UpcallCreate(NFS41_ACL_SET, &nfs41_fobx->sec_ctx,
5403 pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
5404 pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
5405 if (status) goto out;
5406
5407 entry->u.Acl.query = info_class;
5408 entry->buf = sec_desc;
5409 entry->buf_len = RtlLengthSecurityDescriptor(sec_desc);
5410 #ifdef ENABLE_TIMINGS
5411 InterlockedIncrement(&setacl.sops);
5412 InterlockedAdd64(&setacl.size, entry->u.Acl.buf_len);
5413 #endif
5414
5415 status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
5416 if (status) goto out;
5417
5418 status = map_query_acl_error(entry->status);
5419 if (!status) {
5420 if (!nfs41_fobx->deleg_type && entry->ChangeTime &&
5421 (SrvOpen->DesiredAccess &
5422 (FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA)))
5423 nfs41_update_fcb_list(RxContext->pFcb, entry->ChangeTime);
5424 nfs41_fcb->changeattr = entry->ChangeTime;
5425 }
5426 RxFreePool(entry);
5427 out:
5428 #ifdef ENABLE_TIMINGS
5429 t2 = KeQueryPerformanceCounter(NULL);
5430 InterlockedIncrement(&setacl.tops);
5431 InterlockedAdd64(&setacl.ticks, t2.QuadPart - t1.QuadPart);
5432 #ifdef ENABLE_INDV_TIMINGS
5433 DbgP("nfs41_SetSecurityInformation delta = %d op=%d sum=%d\n",
5434 t2.QuadPart - t1.QuadPart, setacl.tops, setacl.ticks);
5435 #endif
5436 #endif
5437 #ifdef DEBUG_ACL_SET
5438 DbgEx();
5439 #endif
5440 return status;
5441 }
5442
5443 NTSTATUS map_queryfile_error(
5444 DWORD error)
5445 {
5446 switch (error) {
5447 case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED;
5448 case ERROR_NETNAME_DELETED: return STATUS_NETWORK_NAME_DELETED;
5449 case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
5450 default:
5451 print_error("failed to map windows error %d to NTSTATUS; "
5452 "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", error);
5453 case ERROR_BAD_NET_RESP: return STATUS_INVALID_NETWORK_RESPONSE;
5454 }
5455 }
5456
5457 #ifdef __REACTOS__
5458 NTSTATUS NTAPI nfs41_QueryFileInformation(
5459 #else
5460 NTSTATUS nfs41_QueryFileInformation(
5461 #endif
5462 IN OUT PRX_CONTEXT RxContext)
5463 {
5464 NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
5465 FILE_INFORMATION_CLASS InfoClass = RxContext->Info.FileInformationClass;
5466 nfs41_updowncall_entry *entry;
5467 __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
5468 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
5469 NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
5470 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
5471 NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
5472 __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
5473 __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
5474 #ifdef ENABLE_TIMINGS
5475 LARGE_INTEGER t1, t2;
5476 t1 = KeQueryPerformanceCounter(NULL);
5477 #endif
5478
5479 #ifdef DEBUG_FILE_QUERY
5480 DbgEn();
5481 print_debug_filedirquery_header(RxContext);
5482 #endif
5483
5484 status = check_nfs41_dirquery_args(RxContext);
5485 if (status) goto out;
5486
5487 switch (InfoClass) {
5488 case FileEaInformation:
5489 {
5490 PFILE_EA_INFORMATION info =
5491 (PFILE_EA_INFORMATION)RxContext->Info.Buffer;
5492 info->EaSize = 0;
5493 RxContext->Info.LengthRemaining -= sizeof(FILE_EA_INFORMATION);
5494 status = STATUS_SUCCESS;
5495 goto out;
5496 }
5497 case FileBasicInformation:
5498 case FileStandardInformation:
5499 case FileInternalInformation:
5500 case FileAttributeTagInformation:
5501 case FileNetworkOpenInformation:
5502 break;
5503 default:
5504 print_error("nfs41_QueryFileInformation: unhandled class %d\n", InfoClass);
5505 status = STATUS_NOT_SUPPORTED;
5506 goto out;
5507 }
5508
5509 status = nfs41_UpcallCreate(NFS41_FILE_QUERY, &nfs41_fobx->sec_ctx,
5510 pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
5511 pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
5512 if (status) goto out;
5513
5514 entry->u.QueryFile.InfoClass = InfoClass;
5515 entry->buf = RxContext->Info.Buffer;
5516 entry->buf_len = RxContext->Info.LengthRemaining;
5517
5518 status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
5519 if (status) goto out;
5520
5521 if (entry->status == STATUS_BUFFER_TOO_SMALL) {
5522 RxContext->InformationToReturn = entry->buf_len;
5523 status = STATUS_BUFFER_TOO_SMALL;
5524 } else if (entry->status == STATUS_SUCCESS) {
5525 BOOLEAN DeletePending = FALSE;
5526 #ifdef ENABLE_TIMINGS
5527 InterlockedIncrement(&getattr.sops);
5528 InterlockedAdd64(&getattr.size, entry->u.QueryFile.buf_len);
5529 #endif
5530 RxContext->Info.LengthRemaining -= entry->buf_len;
5531 status = STATUS_SUCCESS;
5532
5533 switch (InfoClass) {
5534 case FileBasicInformation:
5535 RtlCopyMemory(&nfs41_fcb->BasicInfo, RxContext->Info.Buffer,
5536 sizeof(nfs41_fcb->BasicInfo));
5537 #ifdef DEBUG_FILE_QUERY
5538 print_basic_info(1, &nfs41_fcb->BasicInfo);
5539 #endif
5540 break;
5541 case FileStandardInformation:
5542 /* this a fix for RDBSS behaviour when it first calls ExtendForCache,
5543 * then it sends a file query irp for standard attributes and
5544 * expects to receive EndOfFile of value set by the ExtendForCache.
5545 * It seems to cache the filesize based on that instead of sending
5546 * a file size query for after doing the write.
5547 */
5548 {
5549 PFILE_STANDARD_INFORMATION std_info;
5550 std_info = (PFILE_STANDARD_INFORMATION)RxContext->Info.Buffer;
5551 if (nfs41_fcb->StandardInfo.AllocationSize.QuadPart >
5552 std_info->AllocationSize.QuadPart) {
5553 #ifdef DEBUG_FILE_QUERY
5554 DbgP("Old AllocationSize is bigger: saving %x\n",
5555 nfs41_fcb->StandardInfo.AllocationSize.QuadPart);
5556 #endif
5557 std_info->AllocationSize.QuadPart =
5558 nfs41_fcb->StandardInfo.AllocationSize.QuadPart;
5559 }
5560 if (nfs41_fcb->StandardInfo.EndOfFile.QuadPart >
5561 std_info->EndOfFile.QuadPart) {
5562 #ifdef DEBUG_FILE_QUERY
5563 DbgP("Old EndOfFile is bigger: saving %x\n",
5564 nfs41_fcb->StandardInfo.EndOfFile);
5565 #endif
5566 std_info->EndOfFile.QuadPart =
5567 nfs41_fcb->StandardInfo.EndOfFile.QuadPart;
5568 }
5569 std_info->DeletePending = nfs41_fcb->DeletePending;
5570 }
5571 if (nfs41_fcb->StandardInfo.DeletePending)
5572 DeletePending = TRUE;
5573 RtlCopyMemory(&nfs41_fcb->StandardInfo, RxContext->Info.Buffer,
5574 sizeof(nfs41_fcb->StandardInfo));
5575 nfs41_fcb->StandardInfo.DeletePending = DeletePending;
5576 #ifdef DEBUG_FILE_QUERY
5577 print_std_info(1, &nfs41_fcb->StandardInfo);
5578 #endif
5579 break;
5580 }
5581 } else {
5582 status = map_queryfile_error(entry->status);
5583 }
5584 RxFreePool(entry);
5585 out:
5586 #ifdef ENABLE_TIMINGS
5587 t2 = KeQueryPerformanceCounter(NULL);
5588 InterlockedIncrement(&getattr.tops);
5589 InterlockedAdd64(&getattr.ticks, t2.QuadPart - t1.QuadPart);
5590 #ifdef ENABLE_INDV_TIMINGS
5591 DbgP("nfs41_QueryFileInformation delta = %d op=%d sum=%d\n",
5592 t2.QuadPart - t1.QuadPart, getattr.tops, getattr.ticks);
5593 #endif
5594 #endif
5595 #ifdef DEBUG_FILE_QUERY
5596 DbgEx();
5597 #endif
5598 return status;
5599 }
5600
5601 NTSTATUS map_setfile_error(
5602 DWORD error)
5603 {
5604 switch (error) {
5605 case NO_ERROR: return STATUS_SUCCESS;
5606 case ERROR_NOT_EMPTY: return STATUS_DIRECTORY_NOT_EMPTY;
5607 case ERROR_FILE_EXISTS: return STATUS_OBJECT_NAME_COLLISION;
5608 case ERROR_FILE_NOT_FOUND: return STATUS_OBJECT_NAME_NOT_FOUND;
5609 case ERROR_PATH_NOT_FOUND: return STATUS_OBJECT_PATH_NOT_FOUND;
5610 case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED;
5611 case ERROR_FILE_INVALID: return STATUS_FILE_INVALID;
5612 case ERROR_NOT_SAME_DEVICE: return STATUS_NOT_SAME_DEVICE;
5613 case ERROR_NOT_SUPPORTED: return STATUS_NOT_IMPLEMENTED;
5614 case ERROR_NETWORK_ACCESS_DENIED: return STATUS_NETWORK_ACCESS_DENIED;
5615 case ERROR_NETNAME_DELETED: return STATUS_NETWORK_NAME_DELETED;
5616 case ERROR_BUFFER_OVERFLOW: return STATUS_INSUFFICIENT_RESOURCES;
5617 default:
5618 print_error("failed to map windows error %d to NTSTATUS; "
5619 "defaulting to STATUS_INVALID_PARAMETER\n", error);
5620 case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
5621 }
5622 }
5623
5624 NTSTATUS check_nfs41_setattr_args(
5625 IN PRX_CONTEXT RxContext)
5626 {
5627 NTSTATUS status = STATUS_SUCCESS;
5628 FILE_INFORMATION_CLASS InfoClass = RxContext->Info.FileInformationClass;
5629 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
5630 NFS41GetVNetRootExtension(RxContext->pRelevantSrvOpen->pVNetRoot);
5631
5632 if (pVNetRootContext->read_only) {
5633 print_error("check_nfs41_setattr_args: Read-only mount\n");
5634 status = STATUS_ACCESS_DENIED;
5635 goto out;
5636 }
5637
5638 /* http://msdn.microsoft.com/en-us/library/ff469355(v=PROT.10).aspx
5639 * http://msdn.microsoft.com/en-us/library/ff469424(v=PROT.10).aspx
5640 * If Open.GrantedAccess does not contain FILE_WRITE_DATA, the operation
5641 * MUST be failed with STATUS_ACCESS_DENIED.
5642 */
5643 if (InfoClass == FileAllocationInformation ||
5644 InfoClass == FileEndOfFileInformation) {
5645 if (!(RxContext->pRelevantSrvOpen->DesiredAccess & FILE_WRITE_DATA)) {
5646 status = STATUS_ACCESS_DENIED;
5647 goto out;
5648 }
5649 }
5650 status = check_nfs41_dirquery_args(RxContext);
5651 if (status) goto out;
5652
5653 switch (InfoClass) {
5654 case FileRenameInformation:
5655 {
5656 PFILE_RENAME_INFORMATION rinfo =
5657 (PFILE_RENAME_INFORMATION)RxContext->Info.Buffer;
5658 UNICODE_STRING dst = { (USHORT)rinfo->FileNameLength,
5659 (USHORT)rinfo->FileNameLength, rinfo->FileName };
5660 #ifdef DEBUG_FILE_SET
5661 DbgP("Attempting to rename to '%wZ'\n", &dst);
5662 #endif
5663 if (isFilenameTooLong(&dst, pVNetRootContext)) {
5664 status = STATUS_OBJECT_NAME_INVALID;
5665 goto out;
5666 }
5667 if (rinfo->RootDirectory) {
5668 status = STATUS_INVALID_PARAMETER;
5669 goto out;
5670 }
5671 break;
5672 }
5673 case FileLinkInformation:
5674 {
5675 PFILE_LINK_INFORMATION linfo =
5676 (PFILE_LINK_INFORMATION)RxContext->Info.Buffer;
5677 UNICODE_STRING dst = { (USHORT)linfo->FileNameLength,
5678 (USHORT)linfo->FileNameLength, linfo->FileName };
5679 #ifdef DEBUG_FILE_SET
5680 DbgP("Attempting to add link as '%wZ'\n", &dst);
5681 #endif
5682 if (isFilenameTooLong(&dst, pVNetRootContext)) {
5683 status = STATUS_OBJECT_NAME_INVALID;
5684 goto out;
5685 }
5686 if (linfo->RootDirectory) {
5687 status = STATUS_INVALID_PARAMETER;
5688 goto out;
5689 }
5690 break;
5691 }
5692 case FileDispositionInformation:
5693 {
5694 PFILE_DISPOSITION_INFORMATION dinfo =
5695 (PFILE_DISPOSITION_INFORMATION)RxContext->Info.Buffer;
5696 __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
5697 if (dinfo->DeleteFile && nfs41_fcb->DeletePending) {
5698 status = STATUS_DELETE_PENDING;
5699 goto out;
5700 }
5701 break;
5702 }
5703 case FileBasicInformation:
5704 case FileAllocationInformation:
5705 case FileEndOfFileInformation:
5706 break;
5707 default:
5708 print_error("nfs41_SetFileInformation: unhandled class %d\n", InfoClass);
5709 status = STATUS_NOT_SUPPORTED;
5710 }
5711
5712 out:
5713 return status;
5714 }
5715
5716 #ifdef __REACTOS__
5717 NTSTATUS NTAPI nfs41_SetFileInformation(
5718 #else
5719 NTSTATUS nfs41_SetFileInformation(
5720 #endif
5721 IN OUT PRX_CONTEXT RxContext)
5722 {
5723 NTSTATUS status = STATUS_INVALID_PARAMETER;
5724 nfs41_updowncall_entry *entry;
5725 FILE_INFORMATION_CLASS InfoClass = RxContext->Info.FileInformationClass;
5726 FILE_RENAME_INFORMATION rinfo;
5727 __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
5728 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
5729 NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
5730 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
5731 NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
5732 __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
5733 __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
5734 #ifdef ENABLE_TIMINGS
5735 LARGE_INTEGER t1, t2;
5736 t1 = KeQueryPerformanceCounter(NULL);
5737 #endif
5738
5739 #ifdef DEBUG_FILE_SET
5740 DbgEn();
5741 print_debug_filedirquery_header(RxContext);
5742 #endif
5743
5744 status = check_nfs41_setattr_args(RxContext);
5745 if (status) goto out;
5746
5747 switch (InfoClass) {
5748 case FileDispositionInformation:
5749 {
5750 PFILE_DISPOSITION_INFORMATION dinfo =
5751 (PFILE_DISPOSITION_INFORMATION)RxContext->Info.Buffer;
5752 if (dinfo->DeleteFile) {
5753 nfs41_fcb->DeletePending = TRUE;
5754 // we can delete directories right away
5755 if (nfs41_fcb->StandardInfo.Directory)
5756 break;
5757 nfs41_fcb->StandardInfo.DeletePending = TRUE;
5758 if (RxContext->pFcb->OpenCount > 1) {
5759 rinfo.ReplaceIfExists = 0;
5760 rinfo.RootDirectory = INVALID_HANDLE_VALUE;
5761 rinfo.FileNameLength = 0;
5762 rinfo.FileName[0] = L'\0';
5763 InfoClass = FileRenameInformation;
5764 nfs41_fcb->Renamed = TRUE;
5765 break;
5766 }
5767 } else {
5768 /* section 4.3.3 of [FSBO]
5769 * "file system behavior in the microsoft windows environment"
5770 */
5771 if (nfs41_fcb->DeletePending) {
5772 nfs41_fcb->DeletePending = 0;
5773 nfs41_fcb->StandardInfo.DeletePending = 0;
5774 }
5775 }
5776 status = STATUS_SUCCESS;
5777 goto out;
5778 }
5779 case FileEndOfFileInformation:
5780 {
5781 PFILE_END_OF_FILE_INFORMATION info =
5782 (PFILE_END_OF_FILE_INFORMATION)RxContext->Info.Buffer;
5783 nfs41_fcb->StandardInfo.AllocationSize =
5784 nfs41_fcb->StandardInfo.EndOfFile = info->EndOfFile;
5785 break;
5786 }
5787 case FileRenameInformation:
5788 {
5789 /* noop if filename and destination are the same */
5790 PFILE_RENAME_INFORMATION prinfo =
5791 (PFILE_RENAME_INFORMATION)RxContext->Info.Buffer;
5792 const UNICODE_STRING dst = { (USHORT)prinfo->FileNameLength,
5793 (USHORT)prinfo->FileNameLength, prinfo->FileName };
5794 if (RtlCompareUnicodeString(&dst,
5795 SrvOpen->pAlreadyPrefixedName, FALSE) == 0) {
5796 status = STATUS_SUCCESS;
5797 goto out;
5798 }
5799 }
5800 }
5801
5802 status = nfs41_UpcallCreate(NFS41_FILE_SET, &nfs41_fobx->sec_ctx,
5803 pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
5804 pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
5805 if (status) goto out;
5806
5807 entry->u.SetFile.InfoClass = InfoClass;
5808
5809 /* original irp has infoclass for remove but we need to rename instead,
5810 * thus we changed the local variable infoclass */
5811 if (RxContext->Info.FileInformationClass == FileDispositionInformation &&
5812 InfoClass == FileRenameInformation) {
5813 entry->buf = &rinfo;
5814 entry->buf_len = sizeof(rinfo);
5815 } else {
5816 entry->buf = RxContext->Info.Buffer;
5817 entry->buf_len = RxContext->Info.Length;
5818 }
5819 #ifdef ENABLE_TIMINGS
5820 InterlockedIncrement(&setattr.sops);
5821 InterlockedAdd64(&setattr.size, entry->u.SetFile.buf_len);
5822 #endif
5823
5824 status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
5825 if (status) goto out;
5826
5827 status = map_setfile_error(entry->status);
5828 if (!status) {
5829 if (!nfs41_fobx->deleg_type && entry->ChangeTime &&
5830 (SrvOpen->DesiredAccess &
5831 (FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA)))
5832 nfs41_update_fcb_list(RxContext->pFcb, entry->ChangeTime);
5833 nfs41_fcb->changeattr = entry->ChangeTime;
5834 }
5835 RxFreePool(entry);
5836 out:
5837 #ifdef ENABLE_TIMINGS
5838 t2 = KeQueryPerformanceCounter(NULL);
5839 InterlockedIncrement(&setattr.tops);
5840 InterlockedAdd64(&setattr.ticks, t2.QuadPart - t1.QuadPart);
5841 #ifdef ENABLE_INDV_TIMINGS
5842 DbgP("nfs41_SetFileInformation delta = %d op=%d sum=%d\n",
5843 t2.QuadPart - t1.QuadPart, setattr.tops, setattr.ticks);
5844 #endif
5845 #endif
5846 #ifdef DEBUG_FILE_SET
5847 DbgEx();
5848 #endif
5849 return status;
5850 }
5851
5852 NTSTATUS nfs41_SetFileInformationAtCleanup(
5853 IN OUT PRX_CONTEXT RxContext)
5854 {
5855 NTSTATUS status;
5856 DbgEn();
5857 status = nfs41_SetFileInformation(RxContext);
5858 DbgEx();
5859 return status;
5860 }
5861
5862 #ifdef __REACTOS__
5863 NTSTATUS NTAPI nfs41_IsValidDirectory (
5864 #else
5865 NTSTATUS nfs41_IsValidDirectory (
5866 #endif
5867 IN OUT PRX_CONTEXT RxContext,
5868 IN PUNICODE_STRING DirectoryName)
5869 {
5870 return STATUS_SUCCESS;
5871 }
5872
5873 #ifdef __REACTOS__
5874 NTSTATUS NTAPI nfs41_ComputeNewBufferingState(
5875 #else
5876 NTSTATUS nfs41_ComputeNewBufferingState(
5877 #endif
5878 IN OUT PMRX_SRV_OPEN pSrvOpen,
5879 IN PVOID pMRxContext,
5880 OUT ULONG *pNewBufferingState)
5881 {
5882 NTSTATUS status = STATUS_SUCCESS;
5883 ULONG flag = PtrToUlong(pMRxContext), oldFlags = pSrvOpen->BufferingFlags;
5884
5885 switch(flag) {
5886 case DISABLE_CACHING:
5887 if (pSrvOpen->BufferingFlags &
5888 (FCB_STATE_READBUFFERING_ENABLED | FCB_STATE_READCACHING_ENABLED))
5889 pSrvOpen->BufferingFlags &=
5890 ~(FCB_STATE_READBUFFERING_ENABLED |
5891 FCB_STATE_READCACHING_ENABLED);
5892 if (pSrvOpen->BufferingFlags &
5893 (FCB_STATE_WRITECACHING_ENABLED | FCB_STATE_WRITEBUFFERING_ENABLED))
5894 pSrvOpen->BufferingFlags &=
5895 ~(FCB_STATE_WRITECACHING_ENABLED |
5896 FCB_STATE_WRITEBUFFERING_ENABLED);
5897 pSrvOpen->BufferingFlags |= FCB_STATE_DISABLE_LOCAL_BUFFERING;
5898 break;
5899 case ENABLE_READ_CACHING:
5900 pSrvOpen->BufferingFlags |=
5901 (FCB_STATE_READBUFFERING_ENABLED | FCB_STATE_READCACHING_ENABLED);
5902 break;
5903 case ENABLE_WRITE_CACHING:
5904 pSrvOpen->BufferingFlags |=
5905 (FCB_STATE_WRITECACHING_ENABLED | FCB_STATE_WRITEBUFFERING_ENABLED);
5906 break;
5907 case ENABLE_READWRITE_CACHING:
5908 pSrvOpen->BufferingFlags =
5909 (FCB_STATE_READBUFFERING_ENABLED | FCB_STATE_READCACHING_ENABLED |
5910 FCB_STATE_WRITECACHING_ENABLED | FCB_STATE_WRITEBUFFERING_ENABLED);
5911 }
5912 #ifdef DEBUG_TIME_BASED_COHERENCY
5913 DbgP("nfs41_ComputeNewBufferingState: %wZ pSrvOpen %p Old %08x New %08x\n",
5914 pSrvOpen->pAlreadyPrefixedName, pSrvOpen, oldFlags,
5915 pSrvOpen->BufferingFlags);
5916 *pNewBufferingState = pSrvOpen->BufferingFlags;
5917 #endif
5918 return status;
5919 }
5920
5921 void print_readwrite_args(
5922 PRX_CONTEXT RxContext)
5923 {
5924 PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
5925
5926 print_debug_header(RxContext);
5927 DbgP("Bytecount 0x%x Byteoffset 0x%x Buffer %p\n",
5928 LowIoContext->ParamsFor.ReadWrite.ByteCount,
5929 LowIoContext->ParamsFor.ReadWrite.ByteOffset,
5930 LowIoContext->ParamsFor.ReadWrite.Buffer);
5931 }
5932
5933 void enable_caching(
5934 PMRX_SRV_OPEN SrvOpen,
5935 PNFS41_FOBX nfs41_fobx,
5936 ULONGLONG ChangeTime,
5937 HANDLE session)
5938 {
5939 ULONG flag = 0;
5940 PLIST_ENTRY pEntry;
5941 nfs41_fcb_list_entry *cur;
5942 BOOLEAN found = FALSE;
5943
5944 if (SrvOpen->DesiredAccess & FILE_READ_DATA)
5945 flag = ENABLE_READ_CACHING;
5946 if ((SrvOpen->DesiredAccess & FILE_WRITE_DATA) &&
5947 !nfs41_fobx->write_thru)
5948 flag = ENABLE_WRITE_CACHING;
5949 if ((SrvOpen->DesiredAccess & FILE_READ_DATA) &&
5950 (SrvOpen->DesiredAccess & FILE_WRITE_DATA) &&
5951 !nfs41_fobx->write_thru)
5952 flag = ENABLE_READWRITE_CACHING;
5953
5954 #if defined(DEBUG_TIME_BASED_COHERENCY) || \
5955 defined(DEBUG_WRITE) || defined(DEBUG_READ)
5956 print_caching_level(1, flag, SrvOpen->pAlreadyPrefixedName);
5957 #endif
5958
5959 if (!flag)
5960 return;
5961
5962 RxChangeBufferingState((PSRV_OPEN)SrvOpen, ULongToPtr(flag), 1);
5963
5964 ExAcquireFastMutex(&fcblistLock);
5965 pEntry = openlist.head.Flink;
5966 while (!IsListEmpty(&openlist.head)) {
5967 cur = (nfs41_fcb_list_entry *)CONTAINING_RECORD(pEntry,
5968 nfs41_fcb_list_entry, next);
5969 if (cur->fcb == SrvOpen->pFcb) {
5970 #ifdef DEBUG_TIME_BASED_COHERENCY
5971 DbgP("enable_caching: Looked&Found match for fcb=%p %wZ\n",
5972 SrvOpen->pFcb, SrvOpen->pAlreadyPrefixedName);
5973 #endif
5974 cur->skip = FALSE;
5975 found = TRUE;
5976 break;
5977 }
5978 if (pEntry->Flink == &openlist.head) {
5979 #ifdef DEBUG_TIME_BASED_COHERENCY
5980 DbgP("enable_caching: reached EOL looking for fcb=%p %wZ\n",
5981 SrvOpen->pFcb, SrvOpen->pAlreadyPrefixedName);
5982 #endif
5983 break;
5984 }
5985 pEntry = pEntry->Flink;
5986 }
5987 if (!found && nfs41_fobx->deleg_type) {
5988 nfs41_fcb_list_entry *oentry;
5989 #ifdef DEBUG_TIME_BASED_COHERENCY
5990 DbgP("enable_caching: delegation recalled: srv_open=%p\n", SrvOpen);
5991 #endif
5992 oentry = RxAllocatePoolWithTag(NonPagedPool,
5993 sizeof(nfs41_fcb_list_entry), NFS41_MM_POOLTAG_OPEN);
5994 if (oentry == NULL) return;
5995 oentry->fcb = SrvOpen->pFcb;
5996 oentry->session = session;
5997 oentry->nfs41_fobx = nfs41_fobx;
5998 oentry->ChangeTime = ChangeTime;
5999 oentry->skip = FALSE;
6000 InsertTailList(&openlist.head, &oentry->next);
6001 nfs41_fobx->deleg_type = 0;
6002 }
6003 ExReleaseFastMutex(&fcblistLock);
6004 }
6005
6006 NTSTATUS map_readwrite_errors(
6007 DWORD status)
6008 {
6009 switch (status) {
6010 case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED;
6011 case ERROR_HANDLE_EOF: return STATUS_END_OF_FILE;
6012 case ERROR_FILE_INVALID: return STATUS_FILE_INVALID;
6013 case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
6014 case ERROR_LOCK_VIOLATION: return STATUS_FILE_LOCK_CONFLICT;
6015 case ERROR_NETWORK_ACCESS_DENIED: return STATUS_NETWORK_ACCESS_DENIED;
6016 case ERROR_NETNAME_DELETED: return STATUS_NETWORK_NAME_DELETED;
6017 default:
6018 print_error("failed to map windows error %d to NTSTATUS; "
6019 "defaulting to STATUS_NET_WRITE_FAULT\n", status);
6020 case ERROR_NET_WRITE_FAULT: return STATUS_NET_WRITE_FAULT;
6021 }
6022 }
6023
6024 NTSTATUS check_nfs41_read_args(
6025 IN PRX_CONTEXT RxContext)
6026 {
6027 if (!RxContext->LowIoContext.ParamsFor.ReadWrite.Buffer)
6028 return STATUS_INVALID_USER_BUFFER;
6029 return STATUS_SUCCESS;
6030 }
6031
6032 #ifdef __REACTOS__
6033 NTSTATUS NTAPI nfs41_Read(
6034 #else
6035 NTSTATUS nfs41_Read(
6036 #endif
6037 IN OUT PRX_CONTEXT RxContext)
6038 {
6039 NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
6040 nfs41_updowncall_entry *entry;
6041 BOOLEAN async = FALSE;
6042 PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
6043 __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
6044 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
6045 NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
6046 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
6047 NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
6048 __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
6049 __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
6050 DWORD io_delay;
6051 #ifdef ENABLE_TIMINGS
6052 LARGE_INTEGER t1, t2;
6053 t1 = KeQueryPerformanceCounter(NULL);
6054 #endif
6055
6056 #ifdef DEBUG_READ
6057 DbgEn();
6058 print_readwrite_args(RxContext);
6059 #endif
6060 status = check_nfs41_read_args(RxContext);
6061 if (status) goto out;
6062
6063 status = nfs41_UpcallCreate(NFS41_READ, &nfs41_fobx->sec_ctx,
6064 pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
6065 pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
6066 if (status) goto out;
6067
6068 entry->u.ReadWrite.MdlAddress = LowIoContext->ParamsFor.ReadWrite.Buffer;
6069 entry->buf_len = LowIoContext->ParamsFor.ReadWrite.ByteCount;
6070 entry->u.ReadWrite.offset = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
6071 if (FlagOn(RxContext->CurrentIrpSp->FileObject->Flags,
6072 FO_SYNCHRONOUS_IO) == FALSE) {
6073 entry->u.ReadWrite.rxcontext = RxContext;
6074 async = entry->async_op = TRUE;
6075 }
6076
6077 /* assume network speed is 100MB/s and disk speed is 100MB/s so add
6078 * time to transfer requested bytes over the network and read from disk
6079 */
6080 io_delay = pVNetRootContext->timeout + 2 * entry->buf_len / 104857600;
6081 status = nfs41_UpcallWaitForReply(entry, io_delay);
6082 if (status) goto out;
6083
6084 if (async) {
6085 #ifdef DEBUG_READ
6086 DbgP("This is asynchronous read, returning control back to the user\n");
6087 #endif
6088 status = STATUS_PENDING;
6089 goto out;
6090 }
6091
6092 if (entry->status == NO_ERROR) {
6093 #ifdef ENABLE_TIMINGS
6094 InterlockedIncrement(&read.sops);
6095 InterlockedAdd64(&read.size, entry->u.ReadWrite.len);
6096 #endif
6097 status = RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
6098 RxContext->IoStatusBlock.Information = entry->buf_len;
6099
6100 if ((!BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,
6101 LOWIO_READWRITEFLAG_PAGING_IO) &&
6102 (SrvOpen->DesiredAccess & FILE_READ_DATA) &&
6103 !pVNetRootContext->nocache && !nfs41_fobx->nocache &&
6104 !(SrvOpen->BufferingFlags &
6105 (FCB_STATE_READBUFFERING_ENABLED |
6106 FCB_STATE_READCACHING_ENABLED)))) {
6107 enable_caching(SrvOpen, nfs41_fobx, nfs41_fcb->changeattr,
6108 pVNetRootContext->session);
6109 }
6110 } else {
6111 status = map_readwrite_errors(entry->status);
6112 RxContext->CurrentIrp->IoStatus.Status = status;
6113 RxContext->IoStatusBlock.Information = 0;
6114 }
6115 RxFreePool(entry);
6116 out:
6117 #ifdef ENABLE_TIMINGS
6118 t2 = KeQueryPerformanceCounter(NULL);
6119 InterlockedIncrement(&read.tops);
6120 InterlockedAdd64(&read.ticks, t2.QuadPart - t1.QuadPart);
6121 #ifdef ENABLE_INDV_TIMINGS
6122 DbgP("nfs41_Read delta = %d op=%d sum=%d\n", t2.QuadPart - t1.QuadPart,
6123 read.tops, read.ticks);
6124 #endif
6125 #endif
6126 #ifdef DEBUG_READ
6127 DbgEx();
6128 #endif
6129 return status;
6130 }
6131
6132 NTSTATUS check_nfs41_write_args(
6133 IN PRX_CONTEXT RxContext)
6134 {
6135 NTSTATUS status = STATUS_SUCCESS;
6136 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
6137 NFS41GetVNetRootExtension(RxContext->pRelevantSrvOpen->pVNetRoot);
6138
6139 if (!RxContext->LowIoContext.ParamsFor.ReadWrite.Buffer) {
6140 status = STATUS_INVALID_USER_BUFFER;
6141 goto out;
6142 }
6143
6144 if (pVNetRootContext->read_only) {
6145 print_error("check_nfs41_write_args: Read-only mount\n");
6146 status = STATUS_ACCESS_DENIED;
6147 goto out;
6148 }
6149 out:
6150 return status;
6151 }
6152
6153 #ifdef __REACTOS__
6154 NTSTATUS NTAPI nfs41_Write(
6155 #else
6156 NTSTATUS nfs41_Write(
6157 #endif
6158 IN OUT PRX_CONTEXT RxContext)
6159 {
6160 NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
6161 nfs41_updowncall_entry *entry;
6162 BOOLEAN async = FALSE;
6163 PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
6164 __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
6165 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
6166 NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
6167 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
6168 NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
6169 __notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
6170 __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
6171 DWORD io_delay;
6172 #ifdef ENABLE_TIMINGS
6173 LARGE_INTEGER t1, t2;
6174 t1 = KeQueryPerformanceCounter(NULL);
6175 #endif
6176
6177 #ifdef DEBUG_WRITE
6178 DbgEn();
6179 print_readwrite_args(RxContext);
6180 #endif
6181
6182 status = check_nfs41_write_args(RxContext);
6183 if (status) goto out;
6184
6185 status = nfs41_UpcallCreate(NFS41_WRITE, &nfs41_fobx->sec_ctx,
6186 pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
6187 pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
6188 if (status) goto out;
6189
6190 entry->u.ReadWrite.MdlAddress = LowIoContext->ParamsFor.ReadWrite.Buffer;
6191 entry->buf_len = LowIoContext->ParamsFor.ReadWrite.ByteCount;
6192 entry->u.ReadWrite.offset = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
6193
6194 if (FlagOn(RxContext->CurrentIrpSp->FileObject->Flags,
6195 FO_SYNCHRONOUS_IO) == FALSE) {
6196 entry->u.ReadWrite.rxcontext = RxContext;
6197 async = entry->async_op = TRUE;
6198 }
6199
6200 /* assume network speed is 100MB/s and disk speed is 100MB/s so add
6201 * time to transfer requested bytes over the network and write to disk
6202 */
6203 io_delay = pVNetRootContext->timeout + 2 * entry->buf_len / 104857600;
6204 status = nfs41_UpcallWaitForReply(entry, io_delay);
6205 if (status) goto out;
6206
6207 if (async) {
6208 #ifdef DEBUG_WRITE
6209 DbgP("This is asynchronous write, returning control back to the user\n");
6210 #endif
6211 status = STATUS_PENDING;
6212 goto out;
6213 }
6214
6215 if (entry->status == NO_ERROR) {
6216 //update cached file attributes
6217 #ifdef ENABLE_TIMINGS
6218 InterlockedIncrement(&write.sops);
6219 InterlockedAdd64(&write.size, entry->u.ReadWrite.len);
6220 #endif
6221 nfs41_fcb->StandardInfo.EndOfFile.QuadPart = entry->buf_len +
6222 entry->u.ReadWrite.offset;
6223 status = RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
6224 RxContext->IoStatusBlock.Information = entry->buf_len;
6225 nfs41_fcb->changeattr = entry->ChangeTime;
6226
6227 //re-enable write buffering
6228 if (!BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,
6229 LOWIO_READWRITEFLAG_PAGING_IO) &&
6230 (SrvOpen->DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) &&
6231 !pVNetRootContext->write_thru &&
6232 !pVNetRootContext->nocache &&
6233 !nfs41_fobx->write_thru && !nfs41_fobx->nocache &&
6234 !(SrvOpen->BufferingFlags &
6235 (FCB_STATE_WRITEBUFFERING_ENABLED |
6236 FCB_STATE_WRITECACHING_ENABLED))) {
6237 enable_caching(SrvOpen, nfs41_fobx, nfs41_fcb->changeattr,
6238 pVNetRootContext->session);
6239 } else if (!nfs41_fobx->deleg_type)
6240 nfs41_update_fcb_list(RxContext->pFcb, entry->ChangeTime);
6241
6242 } else {
6243 status = map_readwrite_errors(entry->status);
6244 RxContext->CurrentIrp->IoStatus.Status = status;
6245 RxContext->IoStatusBlock.Information = 0;
6246 }
6247 RxFreePool(entry);
6248 out:
6249 #ifdef ENABLE_TIMINGS
6250 t2 = KeQueryPerformanceCounter(NULL);
6251 InterlockedIncrement(&write.tops);
6252 InterlockedAdd64(&write.ticks, t2.QuadPart - t1.QuadPart);
6253 #ifdef ENABLE_INDV_TIMINGS
6254 DbgP("nfs41_Write delta = %d op=%d sum=%d\n", t2.QuadPart - t1.QuadPart,
6255 write.tops, write.ticks);
6256 #endif
6257 #endif
6258 #ifdef DEBUG_WRITE
6259 DbgEx();
6260 #endif
6261 return status;
6262 }
6263
6264 #ifdef __REACTOS__
6265 NTSTATUS NTAPI nfs41_IsLockRealizable(
6266 #else
6267 NTSTATUS nfs41_IsLockRealizable(
6268 #endif
6269 IN OUT PMRX_FCB pFcb,
6270 IN PLARGE_INTEGER ByteOffset,
6271 IN PLARGE_INTEGER Length,
6272 IN ULONG LowIoLockFlags)
6273 {
6274 NTSTATUS status = STATUS_SUCCESS;
6275 #ifdef DEBUG_LOCK
6276 DbgEn();
6277 DbgP("offset 0x%llx, length 0x%llx, exclusive=%u, blocking=%u\n",
6278 ByteOffset->QuadPart,Length->QuadPart,
6279 BooleanFlagOn(LowIoLockFlags, SL_EXCLUSIVE_LOCK),
6280 !BooleanFlagOn(LowIoLockFlags, SL_FAIL_IMMEDIATELY));
6281 #endif
6282
6283 /* NFS lock operations with length=0 MUST fail with NFS4ERR_INVAL */
6284 if (Length->QuadPart == 0)
6285 status = STATUS_NOT_SUPPORTED;
6286
6287 #ifdef DEBUG_LOCK
6288 DbgEx();
6289 #endif
6290 return status;
6291 }
6292
6293 NTSTATUS map_lock_errors(
6294 DWORD status)
6295 {
6296 switch (status) {
6297 case NO_ERROR: return STATUS_SUCCESS;
6298 case ERROR_NETNAME_DELETED: return STATUS_NETWORK_NAME_DELETED;
6299 case ERROR_LOCK_FAILED: return STATUS_LOCK_NOT_GRANTED;
6300 case ERROR_NOT_LOCKED: return STATUS_RANGE_NOT_LOCKED;
6301 case ERROR_ATOMIC_LOCKS_NOT_SUPPORTED: return STATUS_UNSUCCESSFUL;
6302 case ERROR_OUTOFMEMORY: return STATUS_INSUFFICIENT_RESOURCES;
6303 case ERROR_SHARING_VIOLATION: return STATUS_SHARING_VIOLATION;
6304 case ERROR_FILE_INVALID: return STATUS_FILE_INVALID;
6305 /* if we return ERROR_INVALID_PARAMETER, Windows translates that to
6306 * success!! */
6307 case ERROR_INVALID_PARAMETER: return STATUS_LOCK_NOT_GRANTED;
6308 default:
6309 print_error("failed to map windows error %d to NTSTATUS; "
6310 "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", status);
6311 case ERROR_BAD_NET_RESP: return STATUS_INVALID_NETWORK_RESPONSE;
6312 }
6313 }
6314
6315 void print_lock_args(
6316 PRX_CONTEXT RxContext)
6317 {
6318 PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
6319 const ULONG flags = LowIoContext->ParamsFor.Locks.Flags;
6320 print_debug_header(RxContext);
6321 DbgP("offset 0x%llx, length 0x%llx, exclusive=%u, blocking=%u\n",
6322 LowIoContext->ParamsFor.Locks.ByteOffset,
6323 LowIoContext->ParamsFor.Locks.Length,
6324 BooleanFlagOn(flags, SL_EXCLUSIVE_LOCK),
6325 !BooleanFlagOn(flags, SL_FAIL_IMMEDIATELY));
6326 }
6327
6328
6329 /* use exponential backoff between polls for blocking locks */
6330 #define MSEC_TO_RELATIVE_WAIT (-10000)
6331 #define MIN_LOCK_POLL_WAIT (500 * MSEC_TO_RELATIVE_WAIT) /* 500ms */
6332 #define MAX_LOCK_POLL_WAIT (30000 * MSEC_TO_RELATIVE_WAIT) /* 30s */
6333
6334 void denied_lock_backoff(
6335 IN OUT PLARGE_INTEGER delay)
6336 {
6337 if (delay->QuadPart == 0)
6338 delay->QuadPart = MIN_LOCK_POLL_WAIT;
6339 else
6340 delay->QuadPart <<= 1;
6341
6342 if (delay->QuadPart < MAX_LOCK_POLL_WAIT)
6343 delay->QuadPart = MAX_LOCK_POLL_WAIT;
6344 }
6345
6346 #ifdef __REACTOS__
6347 NTSTATUS NTAPI nfs41_Lock(
6348 #else
6349 NTSTATUS nfs41_Lock(
6350 #endif
6351 IN OUT PRX_CONTEXT RxContext)
6352 {
6353 NTSTATUS status = STATUS_SUCCESS;
6354 nfs41_updowncall_entry *entry;
6355 PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
6356 __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
6357 __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
6358 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
6359 NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
6360 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
6361 NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
6362 const ULONG flags = LowIoContext->ParamsFor.Locks.Flags;
6363 #ifdef _MSC_VER
6364 LARGE_INTEGER poll_delay = {0};
6365 #else
6366 LARGE_INTEGER poll_delay;
6367 #endif
6368 #ifdef ENABLE_TIMINGS
6369 LARGE_INTEGER t1, t2;
6370 t1 = KeQueryPerformanceCounter(NULL);
6371 #endif
6372
6373 #ifndef _MSC_VER
6374 poll_delay.QuadPart = 0;
6375 #endif
6376
6377 #ifdef DEBUG_LOCK
6378 DbgEn();
6379 print_lock_args(RxContext);
6380 #endif
6381
6382 /* RxReleaseFcbResourceForThreadInMRx(RxContext, RxContext->pFcb,
6383 LowIoContext->ResourceThreadId); */
6384
6385 status = nfs41_UpcallCreate(NFS41_LOCK, &nfs41_fobx->sec_ctx,
6386 pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
6387 pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
6388 if (status) goto out;
6389
6390 entry->u.Lock.offset = LowIoContext->ParamsFor.Locks.ByteOffset;
6391 entry->u.Lock.length = LowIoContext->ParamsFor.Locks.Length;
6392 entry->u.Lock.exclusive = BooleanFlagOn(flags, SL_EXCLUSIVE_LOCK);
6393 entry->u.Lock.blocking = !BooleanFlagOn(flags, SL_FAIL_IMMEDIATELY);
6394
6395 retry_upcall:
6396 status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
6397 if (status) goto out;
6398
6399 /* blocking locks keep trying until it succeeds */
6400 if (entry->status == ERROR_LOCK_FAILED && entry->u.Lock.blocking) {
6401 denied_lock_backoff(&poll_delay);
6402 DbgP("returned ERROR_LOCK_FAILED; retrying in %llums\n",
6403 poll_delay.QuadPart / MSEC_TO_RELATIVE_WAIT);
6404 KeDelayExecutionThread(KernelMode, FALSE, &poll_delay);
6405 entry->state = NFS41_WAITING_FOR_UPCALL;
6406 goto retry_upcall;
6407 }
6408
6409 status = map_lock_errors(entry->status);
6410 RxContext->CurrentIrp->IoStatus.Status = status;
6411
6412 RxFreePool(entry);
6413 out:
6414 #ifdef ENABLE_TIMINGS
6415 t2 = KeQueryPerformanceCounter(NULL);
6416 InterlockedIncrement(&lock.tops);
6417 InterlockedAdd64(&lock.ticks, t2.QuadPart - t1.QuadPart);
6418 #ifdef ENABLE_INDV_TIMINGS
6419 DbgP("nfs41_Lock delta = %d op=%d sum=%d\n", t2.QuadPart - t1.QuadPart,
6420 lock.tops, lock.ticks);
6421 #endif
6422 #endif
6423 #ifdef DEBUG_LOCK
6424 DbgEx();
6425 #endif
6426 return status;
6427 }
6428
6429 void print_unlock_args(
6430 PRX_CONTEXT RxContext)
6431 {
6432 PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
6433 print_debug_header(RxContext);
6434 if (LowIoContext->Operation == LOWIO_OP_UNLOCK_MULTIPLE) {
6435 PLOWIO_LOCK_LIST lock = LowIoContext->ParamsFor.Locks.LockList;
6436 DbgP("LOWIO_OP_UNLOCK_MULTIPLE:");
6437 while (lock) {
6438 DbgP(" (offset=%llu, length=%llu)", lock->ByteOffset, lock->Length);
6439 lock = lock->Next;
6440 }
6441 DbgP("\n");
6442 } else {
6443 DbgP("LOWIO_OP_UNLOCK: offset=%llu, length=%llu\n",
6444 LowIoContext->ParamsFor.Locks.ByteOffset,
6445 LowIoContext->ParamsFor.Locks.Length);
6446 }
6447 }
6448
6449 __inline ULONG unlock_list_count(
6450 PLOWIO_LOCK_LIST lock)
6451 {
6452 ULONG count = 0;
6453 while (lock) {
6454 count++;
6455 lock = lock->Next;
6456 }
6457 return count;
6458 }
6459
6460 #ifdef __REACTOS__
6461 NTSTATUS NTAPI nfs41_Unlock(
6462 #else
6463 NTSTATUS nfs41_Unlock(
6464 #endif
6465 IN OUT PRX_CONTEXT RxContext)
6466 {
6467 NTSTATUS status = STATUS_SUCCESS;
6468 nfs41_updowncall_entry *entry;
6469 PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
6470 __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
6471 __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
6472 __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
6473 NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
6474 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
6475 NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
6476 #ifdef ENABLE_TIMINGS
6477 LARGE_INTEGER t1, t2;
6478 t1 = KeQueryPerformanceCounter(NULL);
6479 #endif
6480 #ifdef DEBUG_LOCK
6481 DbgEn();
6482 print_lock_args(RxContext);
6483 #endif
6484
6485 /* RxReleaseFcbResourceForThreadInMRx(RxContext, RxContext->pFcb,
6486 LowIoContext->ResourceThreadId); */
6487
6488 status = nfs41_UpcallCreate(NFS41_UNLOCK, &nfs41_fobx->sec_ctx,
6489 pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
6490 pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
6491 if (status) goto out;
6492
6493 if (LowIoContext->Operation == LOWIO_OP_UNLOCK_MULTIPLE) {
6494 entry->u.Unlock.count = unlock_list_count(
6495 LowIoContext->ParamsFor.Locks.LockList);
6496 RtlCopyMemory(&entry->u.Unlock.locks,
6497 LowIoContext->ParamsFor.Locks.LockList,
6498 sizeof(LOWIO_LOCK_LIST));
6499 } else {
6500 entry->u.Unlock.count = 1;
6501 entry->u.Unlock.locks.ByteOffset =
6502 LowIoContext->ParamsFor.Locks.ByteOffset;
6503 entry->u.Unlock.locks.Length =
6504 LowIoContext->ParamsFor.Locks.Length;
6505 }
6506
6507 status = nfs41_UpcallWaitForReply(entry, pVNetRootContext->timeout);
6508 if (status) goto out;
6509
6510 status = map_lock_errors(entry->status);
6511 RxContext->CurrentIrp->IoStatus.Status = status;
6512 RxFreePool(entry);
6513 out:
6514 #ifdef ENABLE_TIMINGS
6515 t2 = KeQueryPerformanceCounter(NULL);
6516 InterlockedIncrement(&unlock.tops);
6517 InterlockedAdd64(&unlock.ticks, t2.QuadPart - t1.QuadPart);
6518 #ifdef ENABLE_INDV_TIMINGS
6519 DbgP("nfs41_Unlock delta = %d op=%d sum=%d\n", t2.QuadPart - t1.QuadPart,
6520 unlock.tops, unlock.ticks);
6521 #endif
6522 #endif
6523 #ifdef DEBUG_LOCK
6524 DbgEx();
6525 #endif
6526 return status;
6527 }
6528
6529 NTSTATUS map_symlink_errors(
6530 NTSTATUS status)
6531 {
6532 switch (status) {
6533 case NO_ERROR: return STATUS_SUCCESS;
6534 case ERROR_INVALID_REPARSE_DATA: return STATUS_IO_REPARSE_DATA_INVALID;
6535 case ERROR_NOT_A_REPARSE_POINT: return STATUS_NOT_A_REPARSE_POINT;
6536 case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED;
6537 case ERROR_NOT_EMPTY: return STATUS_DIRECTORY_NOT_EMPTY;
6538 case ERROR_OUTOFMEMORY: return STATUS_INSUFFICIENT_RESOURCES;
6539 case ERROR_INSUFFICIENT_BUFFER: return STATUS_BUFFER_TOO_SMALL;
6540 case STATUS_BUFFER_TOO_SMALL:
6541 case ERROR_BUFFER_OVERFLOW: return STATUS_BUFFER_OVERFLOW;
6542 default:
6543 print_error("failed to map windows error %d to NTSTATUS; "
6544 "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", status);
6545 case ERROR_BAD_NET_RESP: return STATUS_INVALID_NETWORK_RESPONSE;
6546 }
6547 }
6548
6549 void print_reparse_buffer(
6550 PREPARSE_DATA_BUFFER Reparse)
6551 {
6552 UNICODE_STRING name;
6553 DbgP("ReparseTag: %08X\n", Reparse->ReparseTag);
6554 DbgP("ReparseDataLength: %8u\n", Reparse->ReparseDataLength);
6555 DbgP("Reserved: %8u\n", Reparse->Reserved);
6556 DbgP("SubstituteNameOffset: %8u\n",
6557 Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset);
6558 DbgP("SubstituteNameLength: %8u\n",
6559 Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength);
6560 DbgP("PrintNameOffset: %8u\n",
6561 Reparse->SymbolicLinkReparseBuffer.PrintNameOffset);
6562 DbgP("PrintNameLength: %8u\n",
6563 Reparse->SymbolicLinkReparseBuffer.PrintNameLength);
6564 DbgP("Flags: %08X\n",
6565 Reparse->SymbolicLinkReparseBuffer.Flags);
6566
6567 name.Buffer = &Reparse->SymbolicLinkReparseBuffer.PathBuffer[
6568 Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
6569 name.MaximumLength = name.Length =
6570 Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength;
6571 DbgP("SubstituteName: %wZ\n", &name);
6572
6573 name.Buffer = &Reparse->SymbolicLinkReparseBuffer.PathBuffer[
6574 Reparse->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR)];
6575 name.MaximumLength = name.Length =
6576 Reparse->SymbolicLinkReparseBuffer.PrintNameLength;
6577 DbgP("PrintName: %wZ\n", &name);
6578 }
6579
6580 NTSTATUS check_nfs41_setreparse_args(
6581 IN PRX_CONTEXT RxContext)
6582 {
6583 NTSTATUS status = STATUS_SUCCESS;
6584 __notnull XXCTL_LOWIO_COMPONENT *FsCtl = &RxContext->LowIoContext.ParamsFor.FsCtl;
6585 __notnull PREPARSE_DATA_BUFFER Reparse = (PREPARSE_DATA_BUFFER)FsCtl->pInputBuffer;
6586 __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
6587 __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext =
6588 NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
6589 const ULONG HeaderLen = REPARSE_DATA_BUFFER_HEADER_SIZE;
6590
6591 /* access checks */
6592 if (VNetRootContext->read_only) {
6593 status = STATUS_MEDIA_WRITE_PROTECTED;
6594 goto out;
6595 }
6596 if (!(SrvOpen->DesiredAccess & (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES))) {
6597 status = STATUS_ACCESS_DENIED;
6598 goto out;
6599 }
6600
6601 /* must have a filename longer than vnetroot name,
6602 * or it's trying to operate on the volume itself */
6603 if (is_root_directory(RxContext)) {
6604 status = STATUS_INVALID_PARAMETER;
6605 goto out;
6606 }
6607 if (FsCtl->pOutputBuffer != NULL) {
6608 status = STATUS_INVALID_PARAMETER;
6609 goto out;
6610 }
6611
6612 /* validate input buffer and length */
6613 if (!Reparse) {
6614 status = STATUS_INVALID_BUFFER_SIZE;
6615 goto out;
6616 }
6617
6618 if (FsCtl->InputBufferLength < HeaderLen ||
6619 FsCtl->InputBufferLength > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) {
6620 status = STATUS_IO_REPARSE_DATA_INVALID;
6621 goto out;
6622 }
6623 if (FsCtl->InputBufferLength != HeaderLen + Reparse->ReparseDataLength) {
6624 status = STATUS_IO_REPARSE_DATA_INVALID;
6625 goto out;
6626 }
6627
6628 /* validate reparse tag */
6629 if (!IsReparseTagValid(Reparse->ReparseTag)) {
6630 status = STATUS_IO_REPARSE_TAG_INVALID;
6631 goto out;
6632 }
6633 if (Reparse->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
6634 status = STATUS_IO_REPARSE_TAG_MISMATCH;
6635 goto out;
6636 }
6637 out:
6638 return status;
6639 }
6640
6641 NTSTATUS nfs41_SetReparsePoint(
6642 IN OUT PRX_CONTEXT RxContext)
6643 {
6644 NTSTATUS status;
6645 UNICODE_STRING TargetName;
6646 __notnull XXCTL_LOWIO_COMPONENT *FsCtl = &RxContext->LowIoContext.ParamsFor.FsCtl;
6647 __notnull PREPARSE_DATA_BUFFER Reparse = (PREPARSE_DATA_BUFFER)FsCtl->pInputBuffer;
6648 __notnull PNFS41_FOBX Fobx = NFS41GetFobxExtension(RxContext->pFobx);
6649 __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
6650 __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext =
6651 NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
6652 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
6653 NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
6654 nfs41_updowncall_entry *entry;
6655
6656 #ifdef DEBUG_SYMLINK
6657 DbgEn();
6658 print_debug_header(RxContext);
6659 print_reparse_buffer(Reparse);
6660 #endif
6661 status = check_nfs41_setreparse_args(RxContext);
6662 if (status) goto out;
6663
6664 TargetName.MaximumLength = TargetName.Length =
6665 Reparse->SymbolicLinkReparseBuffer.PrintNameLength;
6666 TargetName.Buffer = &Reparse->SymbolicLinkReparseBuffer.PathBuffer[
6667 Reparse->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR)];
6668
6669 status = nfs41_UpcallCreate(NFS41_SYMLINK, &Fobx->sec_ctx,
6670 VNetRootContext->session, Fobx->nfs41_open_state,
6671 pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
6672 if (status) goto out;
6673
6674 entry->u.Symlink.target = &TargetName;
6675 entry->u.Symlink.set = TRUE;
6676
6677 status = nfs41_UpcallWaitForReply(entry, VNetRootContext->timeout);
6678 if (status) goto out;
6679
6680 status = map_symlink_errors(entry->status);
6681 RxFreePool(entry);
6682 out:
6683 #ifdef DEBUG_SYMLINK
6684 DbgEx();
6685 #endif
6686 return status;
6687 }
6688
6689 NTSTATUS check_nfs41_getreparse_args(
6690 PRX_CONTEXT RxContext)
6691 {
6692 NTSTATUS status = STATUS_SUCCESS;
6693 XXCTL_LOWIO_COMPONENT *FsCtl = &RxContext->LowIoContext.ParamsFor.FsCtl;
6694 const USHORT HeaderLen = FIELD_OFFSET(REPARSE_DATA_BUFFER,
6695 SymbolicLinkReparseBuffer.PathBuffer);
6696
6697 /* must have a filename longer than vnetroot name,
6698 * or it's trying to operate on the volume itself */
6699 if (is_root_directory(RxContext)) {
6700 status = STATUS_INVALID_PARAMETER;
6701 goto out;
6702 }
6703 /* ifs reparse tests expect STATUS_INVALID_PARAMETER,
6704 * but 'dir' passes a buffer here when querying symlinks
6705 if (FsCtl->pInputBuffer != NULL) {
6706 status = STATUS_INVALID_PARAMETER;
6707 goto out;
6708 } */
6709 if (!FsCtl->pOutputBuffer) {
6710 status = STATUS_INVALID_USER_BUFFER;
6711 goto out;
6712 }
6713 if (!BooleanFlagOn(RxContext->pFcb->Attributes,
6714 FILE_ATTRIBUTE_REPARSE_POINT)) {
6715 status = STATUS_NOT_A_REPARSE_POINT;
6716 DbgP("FILE_ATTRIBUTE_REPARSE_POINT is not set!\n");
6717 goto out;
6718 }
6719
6720 if (FsCtl->OutputBufferLength < HeaderLen) {
6721 RxContext->InformationToReturn = HeaderLen;
6722 status = STATUS_BUFFER_TOO_SMALL;
6723 goto out;
6724 }
6725 out:
6726 return status;
6727 }
6728
6729 NTSTATUS nfs41_GetReparsePoint(
6730 IN OUT PRX_CONTEXT RxContext)
6731 {
6732 NTSTATUS status;
6733 UNICODE_STRING TargetName;
6734 XXCTL_LOWIO_COMPONENT *FsCtl = &RxContext->LowIoContext.ParamsFor.FsCtl;
6735 __notnull PNFS41_FOBX Fobx = NFS41GetFobxExtension(RxContext->pFobx);
6736 __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
6737 __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext =
6738 NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
6739 __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
6740 NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
6741 nfs41_updowncall_entry *entry;
6742 const USHORT HeaderLen = FIELD_OFFSET(REPARSE_DATA_BUFFER,
6743 SymbolicLinkReparseBuffer.PathBuffer);
6744
6745 #ifdef DEBUG_SYMLINK
6746 DbgEn();
6747 #endif
6748 status = check_nfs41_getreparse_args(RxContext);
6749 if (status) goto out;
6750
6751 TargetName.Buffer = (PWCH)((PBYTE)FsCtl->pOutputBuffer + HeaderLen);
6752 TargetName.MaximumLength = (USHORT)min(FsCtl->OutputBufferLength -
6753 HeaderLen, 0xFFFF);
6754
6755 status = nfs41_UpcallCreate(NFS41_SYMLINK, &Fobx->sec_ctx,
6756 VNetRootContext->session, Fobx->nfs41_open_state,
6757 pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
6758 if (status) goto out;
6759
6760 entry->u.Symlink.target = &TargetName;
6761 entry->u.Symlink.set = FALSE;
6762
6763 status = nfs41_UpcallWaitForReply(entry, VNetRootContext->timeout);
6764 if (status) goto out;
6765
6766 status = map_symlink_errors(entry->status);
6767 if (status == STATUS_SUCCESS) {
6768 /* fill in the output buffer */
6769 PREPARSE_DATA_BUFFER Reparse = (PREPARSE_DATA_BUFFER)
6770 FsCtl->pOutputBuffer;
6771 Reparse->ReparseTag = IO_REPARSE_TAG_SYMLINK;
6772 Reparse->ReparseDataLength = HeaderLen + TargetName.Length -
6773 REPARSE_DATA_BUFFER_HEADER_SIZE;
6774 Reparse->Reserved = 0;
6775 Reparse->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
6776 /* PrintName and SubstituteName point to the same string */
6777 Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
6778 Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength =
6779 TargetName.Length;
6780 Reparse->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
6781 Reparse->SymbolicLinkReparseBuffer.PrintNameLength = TargetName.Length;
6782 print_reparse_buffer(Reparse);
6783
6784 RxContext->IoStatusBlock.Information = HeaderLen + TargetName.Length;
6785 } else if (status == STATUS_BUFFER_TOO_SMALL) {
6786 RxContext->InformationToReturn = HeaderLen + TargetName.Length;
6787 }
6788 RxFreePool(entry);
6789 out:
6790 #ifdef DEBUG_SYMLINK
6791 DbgEx();
6792 #endif
6793 return status;
6794 }
6795
6796 #ifdef __REACTOS__
6797 NTSTATUS NTAPI nfs41_FsCtl(
6798 #else
6799 NTSTATUS nfs41_FsCtl(
6800 #endif
6801 IN OUT PRX_CONTEXT RxContext)
6802 {
6803 NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
6804 #ifdef DEBUG_MISC
6805 DbgEn();
6806 print_debug_header(RxContext);
6807 #endif
6808 switch (RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode) {
6809 case FSCTL_SET_REPARSE_POINT:
6810 status = nfs41_SetReparsePoint(RxContext);
6811 break;
6812
6813 case FSCTL_GET_REPARSE_POINT:
6814 status = nfs41_GetReparsePoint(RxContext);
6815 break;
6816 #ifdef DEBUG_MISC
6817 default:
6818 DbgP("FsControlCode: %d\n",
6819 RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode);
6820 #endif
6821 }
6822 #ifdef DEBUG_MISC
6823 DbgEx();
6824 #endif
6825 return status;
6826 }
6827
6828 #ifdef __REACTOS__
6829 NTSTATUS NTAPI nfs41_CompleteBufferingStateChangeRequest(
6830 #else
6831 NTSTATUS nfs41_CompleteBufferingStateChangeRequest(
6832 #endif
6833 IN OUT PRX_CONTEXT RxContext,
6834 IN OUT PMRX_SRV_OPEN SrvOpen,
6835 IN PVOID pContext)
6836 {
6837 return STATUS_SUCCESS;
6838 }
6839
6840 #ifdef __REACTOS__
6841 NTSTATUS NTAPI nfs41_FsdDispatch (
6842 #else
6843 NTSTATUS nfs41_FsdDispatch (
6844 #endif
6845 IN PDEVICE_OBJECT dev,
6846 IN PIRP Irp)
6847 {
6848 #ifdef DEBUG_FSDDISPATCH
6849 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
6850 #endif
6851 NTSTATUS status;
6852
6853 #ifdef DEBUG_FSDDISPATCH
6854 DbgEn();
6855 DbgP("CURRENT IRP = %d.%d\n", IrpSp->MajorFunction, IrpSp->MinorFunction);
6856 if(IrpSp->FileObject)
6857 DbgP("FileOject %p Filename %wZ\n", IrpSp->FileObject,
6858 &IrpSp->FileObject->FileName);
6859 #endif
6860
6861 if (dev != (PDEVICE_OBJECT)nfs41_dev) {
6862 print_error("*** not ours ***\n");
6863 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
6864 Irp->IoStatus.Information = 0;
6865 IoCompleteRequest(Irp, IO_NO_INCREMENT );
6866 status = STATUS_INVALID_DEVICE_REQUEST;
6867 goto out;
6868 }
6869
6870 status = RxFsdDispatch((PRDBSS_DEVICE_OBJECT)dev,Irp);
6871 /* AGLO: 08/05/2009 - looks like RxFsdDispatch frees IrpSp */
6872
6873 out:
6874 #ifdef DEBUG_FSDDISPATCH
6875 DbgP("IoStatus status = 0x%x info = 0x%x\n", Irp->IoStatus.Status,
6876 Irp->IoStatus.Information);
6877 DbgEx();
6878 #endif
6879 return status;
6880 }
6881
6882 #ifdef __REACTOS__
6883 NTSTATUS NTAPI nfs41_Unimplemented(
6884 #else
6885 NTSTATUS nfs41_Unimplemented(
6886 #endif
6887 PRX_CONTEXT RxContext)
6888 {
6889 return STATUS_NOT_IMPLEMENTED;
6890 }
6891
6892 #ifdef __REACTOS__
6893 NTSTATUS NTAPI nfs41_AreFilesAliased(
6894 #else
6895 NTSTATUS nfs41_AreFilesAliased(
6896 #endif
6897 PFCB a,
6898 PFCB b)
6899 {
6900 return STATUS_NOT_IMPLEMENTED;
6901 }
6902
6903 NTSTATUS nfs41_init_ops()
6904 {
6905 DbgEn();
6906
6907 ZeroAndInitializeNodeType(&nfs41_ops, RDBSS_NTC_MINIRDR_DISPATCH,
6908 sizeof(MINIRDR_DISPATCH));
6909
6910 nfs41_ops.MRxFlags = (RDBSS_MANAGE_NET_ROOT_EXTENSION |
6911 RDBSS_MANAGE_V_NET_ROOT_EXTENSION |
6912 RDBSS_MANAGE_FCB_EXTENSION |
6913 RDBSS_MANAGE_FOBX_EXTENSION);
6914
6915 nfs41_ops.MRxSrvCallSize = 0; // srvcall extension is not handled in rdbss
6916 nfs41_ops.MRxNetRootSize = sizeof(NFS41_NETROOT_EXTENSION);
6917 nfs41_ops.MRxVNetRootSize = sizeof(NFS41_V_NET_ROOT_EXTENSION);
6918 nfs41_ops.MRxFcbSize = sizeof(NFS41_FCB);
6919 nfs41_ops.MRxFobxSize = sizeof(NFS41_FOBX);
6920
6921 // Mini redirector cancel routine ..
6922
6923 nfs41_ops.MRxCancel = NULL;
6924
6925 //
6926 // Mini redirector Start/Stop. Each mini-rdr can be started or stopped
6927 // while the others continue to operate.
6928 //
6929
6930 nfs41_ops.MRxStart = nfs41_Start;
6931 nfs41_ops.MRxStop = nfs41_Stop;
6932 nfs41_ops.MRxDevFcbXXXControlFile = nfs41_DevFcbXXXControlFile;
6933
6934 //
6935 // Mini redirector name resolution.
6936 //
6937
6938 nfs41_ops.MRxCreateSrvCall = nfs41_CreateSrvCall;
6939 nfs41_ops.MRxSrvCallWinnerNotify = nfs41_SrvCallWinnerNotify;
6940 nfs41_ops.MRxCreateVNetRoot = nfs41_CreateVNetRoot;
6941 nfs41_ops.MRxExtractNetRootName = nfs41_ExtractNetRootName;
6942 nfs41_ops.MRxFinalizeSrvCall = nfs41_FinalizeSrvCall;
6943 nfs41_ops.MRxFinalizeNetRoot = nfs41_FinalizeNetRoot;
6944 nfs41_ops.MRxFinalizeVNetRoot = nfs41_FinalizeVNetRoot;
6945
6946 //
6947 // File System Object Creation/Deletion.
6948 //
6949
6950 nfs41_ops.MRxCreate = nfs41_Create;
6951 nfs41_ops.MRxCollapseOpen = nfs41_CollapseOpen;
6952 nfs41_ops.MRxShouldTryToCollapseThisOpen = nfs41_ShouldTryToCollapseThisOpen;
6953 nfs41_ops.MRxExtendForCache = nfs41_ExtendForCache;
6954 nfs41_ops.MRxExtendForNonCache = nfs41_ExtendForCache;
6955 nfs41_ops.MRxCloseSrvOpen = nfs41_CloseSrvOpen;
6956 nfs41_ops.MRxFlush = nfs41_Flush;
6957 nfs41_ops.MRxDeallocateForFcb = nfs41_DeallocateForFcb;
6958 nfs41_ops.MRxDeallocateForFobx = nfs41_DeallocateForFobx;
6959 nfs41_ops.MRxIsLockRealizable = nfs41_IsLockRealizable;
6960
6961 //
6962 // File System Objects query/Set
6963 //
6964
6965 nfs41_ops.MRxQueryDirectory = nfs41_QueryDirectory;
6966 nfs41_ops.MRxQueryVolumeInfo = nfs41_QueryVolumeInformation;
6967 nfs41_ops.MRxQueryEaInfo = nfs41_QueryEaInformation;
6968 nfs41_ops.MRxSetEaInfo = nfs41_SetEaInformation;
6969 nfs41_ops.MRxQuerySdInfo = nfs41_QuerySecurityInformation;
6970 nfs41_ops.MRxSetSdInfo = nfs41_SetSecurityInformation;
6971 nfs41_ops.MRxQueryFileInfo = nfs41_QueryFileInformation;
6972 nfs41_ops.MRxSetFileInfo = nfs41_SetFileInformation;
6973
6974 //
6975 // Buffering state change
6976 //
6977
6978 nfs41_ops.MRxComputeNewBufferingState = nfs41_ComputeNewBufferingState;
6979
6980 //
6981 // File System Object I/O
6982 //
6983
6984 nfs41_ops.MRxLowIOSubmit[LOWIO_OP_READ] = nfs41_Read;
6985 nfs41_ops.MRxLowIOSubmit[LOWIO_OP_WRITE] = nfs41_Write;
6986 nfs41_ops.MRxLowIOSubmit[LOWIO_OP_SHAREDLOCK] = nfs41_Lock;
6987 nfs41_ops.MRxLowIOSubmit[LOWIO_OP_EXCLUSIVELOCK] = nfs41_Lock;
6988 nfs41_ops.MRxLowIOSubmit[LOWIO_OP_UNLOCK] = nfs41_Unlock;
6989 nfs41_ops.MRxLowIOSubmit[LOWIO_OP_UNLOCK_MULTIPLE] = nfs41_Unlock;
6990 nfs41_ops.MRxLowIOSubmit[LOWIO_OP_FSCTL] = nfs41_FsCtl;
6991
6992 //
6993 // Miscellanous
6994 //
6995
6996 nfs41_ops.MRxCompleteBufferingStateChangeRequest =
6997 nfs41_CompleteBufferingStateChangeRequest;
6998 nfs41_ops.MRxIsValidDirectory = nfs41_IsValidDirectory;
6999
7000 nfs41_ops.MRxTruncate = nfs41_Unimplemented;
7001 nfs41_ops.MRxZeroExtend = nfs41_Unimplemented;
7002 nfs41_ops.MRxAreFilesAliased = nfs41_AreFilesAliased;
7003 nfs41_ops.MRxQueryQuotaInfo = nfs41_Unimplemented;
7004 nfs41_ops.MRxSetQuotaInfo = nfs41_Unimplemented;
7005 nfs41_ops.MRxSetVolumeInfo = nfs41_Unimplemented;
7006
7007 DbgR();
7008 return(STATUS_SUCCESS);
7009 }
7010
7011 KSTART_ROUTINE fcbopen_main;
7012 #ifdef __REACTOS__
7013 VOID NTAPI fcbopen_main(PVOID ctx)
7014 #else
7015 VOID fcbopen_main(PVOID ctx)
7016 #endif
7017 {
7018 NTSTATUS status;
7019 LARGE_INTEGER timeout;
7020
7021 DbgEn();
7022 timeout.QuadPart = RELATIVE(SECONDS(30));
7023 while(1) {
7024 PLIST_ENTRY pEntry;
7025 nfs41_fcb_list_entry *cur;
7026 status = KeDelayExecutionThread(KernelMode, TRUE, &timeout);
7027 ExAcquireFastMutex(&fcblistLock);
7028 pEntry = openlist.head.Flink;
7029 while (!IsListEmpty(&openlist.head)) {
7030 PNFS41_NETROOT_EXTENSION pNetRootContext;
7031 nfs41_updowncall_entry *entry;
7032 FILE_BASIC_INFORMATION binfo;
7033 PNFS41_FCB nfs41_fcb;
7034 cur = (nfs41_fcb_list_entry *)CONTAINING_RECORD(pEntry,
7035 nfs41_fcb_list_entry, next);
7036
7037 #ifdef DEBUG_TIME_BASED_COHERENCY
7038 DbgP("fcbopen_main: Checking attributes for fcb=%p "
7039 "change_time=%llu skipping=%d\n", cur->fcb,
7040 cur->ChangeTime, cur->skip);
7041 #endif
7042 if (cur->skip) goto out;
7043 pNetRootContext =
7044 NFS41GetNetRootExtension(cur->fcb->pNetRoot);
7045 /* place an upcall for this srv_open */
7046 status = nfs41_UpcallCreate(NFS41_FILE_QUERY,
7047 &cur->nfs41_fobx->sec_ctx, cur->session,
7048 cur->nfs41_fobx->nfs41_open_state,
7049 pNetRootContext->nfs41d_version, NULL, &entry);
7050 if (status) goto out;
7051
7052 entry->u.QueryFile.InfoClass = FileBasicInformation;
7053 entry->buf = &binfo;
7054 entry->buf_len = sizeof(binfo);
7055
7056 status = nfs41_UpcallWaitForReply(entry, UPCALL_TIMEOUT_DEFAULT);
7057 if (status) goto out;
7058
7059 if (cur->ChangeTime != entry->ChangeTime) {
7060 ULONG flag = DISABLE_CACHING;
7061 PMRX_SRV_OPEN srv_open;
7062 PLIST_ENTRY psrvEntry;
7063 #ifdef DEBUG_TIME_BASED_COHERENCY
7064 DbgP("fcbopen_main: old ctime=%llu new_ctime=%llu\n",
7065 cur->ChangeTime, entry->ChangeTime);
7066 #endif
7067 cur->ChangeTime = entry->ChangeTime;
7068 cur->skip = TRUE;
7069 psrvEntry = &cur->fcb->SrvOpenList;
7070 psrvEntry = psrvEntry->Flink;
7071 while (!IsListEmpty(&cur->fcb->SrvOpenList)) {
7072 srv_open = (PMRX_SRV_OPEN)CONTAINING_RECORD(psrvEntry,
7073 MRX_SRV_OPEN, SrvOpenQLinks);
7074 if (srv_open->DesiredAccess &
7075 (FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA)) {
7076 #ifdef DEBUG_TIME_BASED_COHERENCY
7077 DbgP("fcbopen_main: ************ Invalidate the cache %wZ"
7078 "************\n", srv_open->pAlreadyPrefixedName);
7079 #endif
7080 RxIndicateChangeOfBufferingStateForSrvOpen(
7081 cur->fcb->pNetRoot->pSrvCall, srv_open,
7082 srv_open->Key, ULongToPtr(flag));
7083 }
7084 if (psrvEntry->Flink == &cur->fcb->SrvOpenList) {
7085 #ifdef DEBUG_TIME_BASED_COHERENCY
7086 DbgP("fcbopen_main: reached end of srvopen for fcb %p\n",
7087 cur->fcb);
7088 #endif
7089 break;
7090 }
7091 psrvEntry = psrvEntry->Flink;
7092 };
7093 }
7094 nfs41_fcb = (PNFS41_FCB)cur->fcb->Context;
7095 nfs41_fcb->changeattr = entry->ChangeTime;
7096 RxFreePool(entry);
7097 out:
7098 if (pEntry->Flink == &openlist.head) {
7099 #ifdef DEBUG_TIME_BASED_COHERENCY
7100 DbgP("fcbopen_main: reached end of the fcb list\n");
7101 #endif
7102 break;
7103 }
7104 pEntry = pEntry->Flink;
7105 }
7106 ExReleaseFastMutex(&fcblistLock);
7107 }
7108 DbgEx();
7109 }
7110
7111 #ifdef __REACTOS__
7112 NTSTATUS NTAPI DriverEntry(
7113 #else
7114 NTSTATUS DriverEntry(
7115 #endif
7116 IN PDRIVER_OBJECT drv,
7117 IN PUNICODE_STRING path)
7118 {
7119 NTSTATUS status;
7120 ULONG flags = 0, i;
7121 UNICODE_STRING dev_name, user_dev_name;
7122 PNFS41_DEVICE_EXTENSION dev_exts;
7123 TIME_FIELDS jan_1_1970 = {1970, 1, 1, 0, 0, 0, 0, 0};
7124 ACCESS_MASK mask = 0;
7125 OBJECT_ATTRIBUTES oattrs;
7126
7127 DbgEn();
7128
7129 status = RxDriverEntry(drv, path);
7130 if (status != STATUS_SUCCESS) {
7131 print_error("RxDriverEntry failed: %08lx\n", status);
7132 goto out;
7133 }
7134
7135 RtlInitUnicodeString(&dev_name, NFS41_DEVICE_NAME);
7136 SetFlag(flags, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS);
7137
7138 status = nfs41_init_ops();
7139 if (status != STATUS_SUCCESS) {
7140 print_error("nfs41_init_ops failed to initialize dispatch table\n");
7141 goto out;
7142 }
7143
7144 DbgP("calling RxRegisterMinirdr\n");
7145 status = RxRegisterMinirdr(&nfs41_dev, drv, &nfs41_ops, flags, &dev_name,
7146 sizeof(NFS41_DEVICE_EXTENSION),
7147 FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_REMOTE_DEVICE);
7148 if (status != STATUS_SUCCESS) {
7149 print_error("RxRegisterMinirdr failed: %08lx\n", status);
7150 goto out;
7151 }
7152 #ifndef __REACTOS__
7153 nfs41_dev->Flags |= DO_BUFFERED_IO;
7154 #endif
7155
7156 dev_exts = (PNFS41_DEVICE_EXTENSION)
7157 ((PBYTE)(nfs41_dev) + sizeof(RDBSS_DEVICE_OBJECT));
7158
7159 RxDefineNode(dev_exts, NFS41_DEVICE_EXTENSION);
7160 dev_exts->DeviceObject = nfs41_dev;
7161 nfs41_create_volume_info((PFILE_FS_VOLUME_INFORMATION)dev_exts->VolAttrs,
7162 &dev_exts->VolAttrsLen);
7163
7164 RtlInitUnicodeString(&user_dev_name, NFS41_SHADOW_DEVICE_NAME);
7165 DbgP("calling IoCreateSymbolicLink %wZ %wZ\n", &user_dev_name, &dev_name);
7166 status = IoCreateSymbolicLink(&user_dev_name, &dev_name);
7167 if (status != STATUS_SUCCESS) {
7168 print_error("Device name IoCreateSymbolicLink failed: %08lx\n", status);
7169 goto out_unregister;
7170 }
7171
7172 KeInitializeEvent(&upcallEvent, SynchronizationEvent, FALSE );
7173 ExInitializeFastMutex(&upcallLock);
7174 ExInitializeFastMutex(&downcallLock);
7175 ExInitializeFastMutex(&xidLock);
7176 ExInitializeFastMutex(&openOwnerLock);
7177 ExInitializeFastMutex(&fcblistLock);
7178 InitializeListHead(&upcall.head);
7179 InitializeListHead(&downcall.head);
7180 InitializeListHead(&openlist.head);
7181 InitializeObjectAttributes(&oattrs, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
7182 status = PsCreateSystemThread(&dev_exts->openlistHandle, mask,
7183 &oattrs, NULL, NULL, &fcbopen_main, NULL);
7184 if (status != STATUS_SUCCESS)
7185 goto out_unregister;
7186
7187 drv->DriverUnload = nfs41_driver_unload;
7188
7189 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
7190 drv->MajorFunction[i] = (PDRIVER_DISPATCH)nfs41_FsdDispatch;
7191
7192 RtlTimeFieldsToTime(&jan_1_1970, &unix_time_diff);
7193
7194 out_unregister:
7195 if (status != STATUS_SUCCESS)
7196 RxUnregisterMinirdr(nfs41_dev);
7197 out:
7198 DbgEx();
7199 return status;
7200 }
7201
7202 #ifdef __REACTOS__
7203 VOID NTAPI nfs41_driver_unload(IN PDRIVER_OBJECT drv)
7204 #else
7205 VOID nfs41_driver_unload(IN PDRIVER_OBJECT drv)
7206 #endif
7207 {
7208 PRX_CONTEXT RxContext;
7209 NTSTATUS status;
7210 UNICODE_STRING dev_name, pipe_name;
7211
7212 DbgEn();
7213
7214 RxContext = RxCreateRxContext(NULL, nfs41_dev, RX_CONTEXT_FLAG_IN_FSP);
7215 if (RxContext == NULL) {
7216 status = STATUS_INSUFFICIENT_RESOURCES;
7217 goto unload;
7218 }
7219 status = RxStopMinirdr(RxContext, &RxContext->PostRequest);
7220 RxDereferenceAndDeleteRxContext(RxContext);
7221
7222 unload:
7223 RtlInitUnicodeString(&dev_name, NFS41_SHADOW_DEVICE_NAME);
7224 status = IoDeleteSymbolicLink(&dev_name);
7225 if (status != STATUS_SUCCESS) {
7226 print_error("couldn't delete device symbolic link\n");
7227 }
7228 RtlInitUnicodeString(&pipe_name, NFS41_SHADOW_PIPE_NAME);
7229 status = IoDeleteSymbolicLink(&pipe_name);
7230 if (status != STATUS_SUCCESS) {
7231 print_error("couldn't delete pipe symbolic link\n");
7232 }
7233 RxUnload(drv);
7234
7235 DbgP("driver unloaded %p\n", drv);
7236 DbgR();
7237 }