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