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