4b28bb965f423b660f7d203ae8b1f7e3f71bf3fb
[openafs.git] / src / WINNT / afsrdr / kernel / fs / AFSRDRSupport.cpp
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3  * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * - Redistributions of source code must retain the above copyright notice,
11  *   this list of conditions and the following disclaimer.
12  * - Redistributions in binary form must reproduce the above copyright
13  *   notice,
14  *   this list of conditions and the following disclaimer in the
15  *   documentation
16  *   and/or other materials provided with the distribution.
17  * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
18  *   nor the names of their contributors may be used to endorse or promote
19  *   products derived from this software without specific prior written
20  *   permission from Kernel Drivers, LLC and Your File System, Inc.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
26  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 //
36 // File: AFSRDRSupport.cpp
37 //
38 #include "AFSCommon.h"
39
40 typedef NTSTATUS  (*FsRtlRegisterUncProviderEx_t)( PHANDLE  MupHandle, PUNICODE_STRING  RedirDevName, PDEVICE_OBJECT  DeviceObject, ULONG  Flags);
41
42 NTSTATUS
43 AFSInitRDRDevice()
44 {
45
46     NTSTATUS       ntStatus = STATUS_SUCCESS;
47     UNICODE_STRING uniDeviceName;
48     ULONG          ulIndex = 0;
49     AFSDeviceExt  *pDeviceExt = NULL;
50     AFSFileID      stRootFid;
51     UNICODE_STRING uniFsRtlRegisterUncProviderEx;
52     FsRtlRegisterUncProviderEx_t pFsRtlRegisterUncProviderEx = NULL;
53
54     __Enter
55     {
56
57         RtlInitUnicodeString( &uniDeviceName,
58                               AFS_RDR_DEVICE_NAME);
59
60         RtlInitUnicodeString( &uniFsRtlRegisterUncProviderEx,
61                               L"FsRtlRegisterUncProviderEx");
62
63         pFsRtlRegisterUncProviderEx = (FsRtlRegisterUncProviderEx_t)MmGetSystemRoutineAddress(&uniFsRtlRegisterUncProviderEx);
64
65         ntStatus = IoCreateDevice( AFSDriverObject,
66                                    sizeof( AFSDeviceExt),
67                                    pFsRtlRegisterUncProviderEx ? NULL : &uniDeviceName,
68                                    FILE_DEVICE_NETWORK_FILE_SYSTEM,
69                                    FILE_REMOTE_DEVICE,
70                                    FALSE,
71                                    &AFSRDRDeviceObject);
72
73         if( !NT_SUCCESS( ntStatus))
74         {
75
76             AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
77                           AFS_TRACE_LEVEL_ERROR,
78                           "AFSInitRDRDevice IoCreateDevice failure %08lX\n",
79                           ntStatus);
80
81             try_return( ntStatus);
82         }
83
84         pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
85
86         RtlZeroMemory( pDeviceExt,
87                        sizeof( AFSDeviceExt));
88
89         //
90         // Initialize resources
91         //
92
93         pDeviceExt->Specific.RDR.VolumeTree.TreeLock = &pDeviceExt->Specific.RDR.VolumeTreeLock;
94
95         ExInitializeResourceLite( pDeviceExt->Specific.RDR.VolumeTree.TreeLock);
96
97         pDeviceExt->Specific.RDR.VolumeTree.TreeHead = NULL;
98
99         ExInitializeResourceLite( &pDeviceExt->Specific.RDR.VolumeListLock);
100
101         pDeviceExt->Specific.RDR.VolumeListHead = NULL;
102
103         pDeviceExt->Specific.RDR.VolumeListTail = NULL;
104
105         KeInitializeEvent( &pDeviceExt->Specific.RDR.QueuedReleaseExtentEvent,
106                            NotificationEvent,
107                            TRUE);
108
109         ExInitializeResourceLite( &pDeviceExt->Specific.RDR.RootCellTreeLock);
110
111         pDeviceExt->Specific.RDR.RootCellTree.TreeLock = &pDeviceExt->Specific.RDR.RootCellTreeLock;
112
113         pDeviceExt->Specific.RDR.RootCellTree.TreeHead = NULL;
114
115         ExInitializeResourceLite( &pDeviceExt->Specific.RDR.ProviderListLock);
116
117         ntStatus = AFSInitRdrFcb( &pDeviceExt->Fcb);
118
119         if ( !NT_SUCCESS(ntStatus))
120         {
121
122             AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
123                           AFS_TRACE_LEVEL_ERROR,
124                           "AFSInitRDRDevice AFSInitRdrFcb failure %08lX\n",
125                           ntStatus);
126
127             try_return( ntStatus);
128         }
129
130         //
131         // Clear the initializing bit
132         //
133
134         AFSRDRDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
135
136         //
137         // Register this device with MUP with FilterMgr if Vista or above
138         //
139
140         if( pFsRtlRegisterUncProviderEx)
141         {
142
143             ntStatus = pFsRtlRegisterUncProviderEx( &AFSMUPHandle,
144                                                     &uniDeviceName,
145                                                     AFSRDRDeviceObject,
146                                                     0);
147             if ( !NT_SUCCESS( ntStatus))
148             {
149                 AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
150                               AFS_TRACE_LEVEL_ERROR,
151                               "AFSInitRDRDevice FsRtlRegisterUncProvider failure %08lX\n",
152                               ntStatus);
153             }
154         }
155         else
156         {
157
158             ntStatus = FsRtlRegisterUncProvider( &AFSMUPHandle,
159                                                  &uniDeviceName,
160                                                  FALSE);
161
162             if ( NT_SUCCESS( ntStatus))
163             {
164
165                 IoRegisterFileSystem( AFSRDRDeviceObject);
166             }
167             else
168             {
169                 AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
170                               AFS_TRACE_LEVEL_ERROR,
171                               "AFSInitRDRDevice FsRtlRegisterUncProvider failure %08lX\n",
172                               ntStatus);
173             }
174         }
175
176         //
177         // Good to go, all registered and ready to start receiving requests
178         //
179
180 try_exit:
181
182         if( !NT_SUCCESS( ntStatus))
183         {
184
185             //
186             // Delete our device and bail
187             //
188
189             ExDeleteResourceLite( pDeviceExt->Specific.RDR.VolumeTree.TreeLock);
190
191             ExDeleteResourceLite( &pDeviceExt->Specific.RDR.VolumeListLock);
192
193             ExDeleteResourceLite( &pDeviceExt->Specific.RDR.RootCellTreeLock);
194
195             ExDeleteResourceLite( &pDeviceExt->Specific.RDR.ProviderListLock);
196
197             IoDeleteDevice( AFSRDRDeviceObject);
198
199             AFSRDRDeviceObject = NULL;
200
201             try_return( ntStatus);
202         }
203     }
204
205     return ntStatus;
206 }
207
208 NTSTATUS
209 AFSRDRDeviceControl( IN PDEVICE_OBJECT DeviceObject,
210                      IN PIRP Irp)
211 {
212
213     NTSTATUS           ntStatus = STATUS_SUCCESS;
214     PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp);
215     PFILE_OBJECT       pFileObject = pIrpSp->FileObject;
216     BOOLEAN            bCompleteIrp = TRUE;
217
218     __Enter
219     {
220
221         switch( pIrpSp->Parameters.DeviceIoControl.IoControlCode)
222         {
223
224             case IOCTL_REDIR_QUERY_PATH:
225             {
226
227                 QUERY_PATH_REQUEST *pPathRequest = (QUERY_PATH_REQUEST *)pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
228                 QUERY_PATH_RESPONSE *pPathResponse = (QUERY_PATH_RESPONSE *)Irp->UserBuffer;
229                 UNICODE_STRING uniPathName;
230
231                 ntStatus = STATUS_BAD_NETWORK_PATH;
232
233                 uniPathName.Length = (USHORT)pPathRequest->PathNameLength;
234                 uniPathName.MaximumLength = uniPathName.Length;
235
236                 uniPathName.Buffer = pPathRequest->FilePathName;
237
238                 if( uniPathName.Length >= AFSServerName.Length + sizeof( WCHAR))
239                 {
240
241                     USHORT usLength = uniPathName.Length;
242
243                     uniPathName.Length = AFSServerName.Length;
244
245                     //
246                     // Skip over the first slash in the name
247                     //
248
249                     uniPathName.Buffer = &uniPathName.Buffer[ 1];
250
251
252                     //
253                     // Check to see if the first (or only) component
254                     // of the path matches the server name
255                     //
256
257                     if( RtlCompareUnicodeString( &AFSServerName,
258                                                  &uniPathName,
259                                                  TRUE) == 0 &&
260                         ( usLength == AFSServerName.Length + sizeof( WCHAR) ||
261                           uniPathName.Buffer[ AFSServerName.Length / sizeof( WCHAR)] == '\\'))
262                     {
263
264                         ntStatus = STATUS_SUCCESS;
265
266                         pPathResponse->LengthAccepted = AFSServerName.Length + sizeof( WCHAR);
267                     }
268                 }
269
270                 break;
271             }
272
273             case IOCTL_REDIR_QUERY_PATH_EX:
274             {
275
276                 QUERY_PATH_REQUEST_EX *pPathRequest = (QUERY_PATH_REQUEST_EX *)pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
277                 QUERY_PATH_RESPONSE *pPathResponse = (QUERY_PATH_RESPONSE *)Irp->UserBuffer;
278                 UNICODE_STRING uniPathName;
279
280                 ntStatus = STATUS_BAD_NETWORK_PATH;
281
282                 uniPathName.Length = pPathRequest->PathName.Length;
283                 uniPathName.MaximumLength = uniPathName.Length;
284
285                 uniPathName.Buffer = pPathRequest->PathName.Buffer;
286
287                 if( uniPathName.Length >= AFSServerName.Length + sizeof( WCHAR))
288                 {
289
290                     USHORT usLength = uniPathName.Length;
291
292                     uniPathName.Length = AFSServerName.Length;
293
294                     //
295                     // Skip over the first slash in the name
296                     //
297
298                     uniPathName.Buffer = &uniPathName.Buffer[ 1];
299
300
301                     //
302                     // Check to see if the first (or only) component
303                     // of the path matches the server name
304                     //
305
306                     if( RtlCompareUnicodeString( &AFSServerName,
307                                                  &uniPathName,
308                                                  TRUE) == 0 &&
309                         ( usLength == AFSServerName.Length + sizeof( WCHAR) ||
310                           uniPathName.Buffer[ AFSServerName.Length / sizeof( WCHAR)] == '\\'))
311                     {
312
313                         ntStatus = STATUS_SUCCESS;
314
315                         pPathResponse->LengthAccepted = AFSServerName.Length + sizeof( WCHAR);
316                     }
317                 }
318
319                 break;
320             }
321
322             default:
323
324                 ntStatus = STATUS_INVALID_DEVICE_REQUEST;
325
326                 break;
327         }
328
329         if (bCompleteIrp)
330         {
331             //
332             // Complete the request
333             //
334
335             AFSCompleteRequest( Irp,
336                                 ntStatus);
337         }
338     }
339
340     return ntStatus;
341 }
342
343 NTSTATUS
344 AFSInitializeRedirector( IN AFSRedirectorInitInfo *RedirInitInfo)
345 {
346
347     NTSTATUS ntStatus = STATUS_SUCCESS;
348     LARGE_INTEGER cacheSizeBytes;
349     AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
350     AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSDeviceObject->DeviceExtension;
351     OBJECT_ATTRIBUTES   stObjectAttribs;
352     IO_STATUS_BLOCK stIoStatus;
353     UNICODE_STRING uniServiceName;
354
355     __Enter
356     {
357
358         //
359         // First this is to load the library
360         //
361
362         RtlInitUnicodeString( &uniServiceName,
363                               AFS_REDIR_LIBRARY_SERVICE_ENTRY);
364
365         ntStatus = AFSLoadLibrary( 0,
366                                    &uniServiceName);
367
368         if( !NT_SUCCESS( ntStatus))
369         {
370
371             AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
372                           AFS_TRACE_LEVEL_ERROR,
373                           "AFSInitializeRedirector AFSLoadLibrary failure %08lX\n",
374                           ntStatus);
375
376             try_return( ntStatus);
377         }
378
379         //
380         // Save off the cache file information
381         //
382
383         pDevExt->Specific.RDR.CacheBlockSize = RedirInitInfo->CacheBlockSize;
384
385         pDevExt->Specific.RDR.CacheBlockCount = RedirInitInfo->ExtentCount;
386
387         pDevExt->Specific.RDR.MaximumRPCLength = RedirInitInfo->MaximumChunkLength;
388
389         cacheSizeBytes = RedirInitInfo->ExtentCount;
390         cacheSizeBytes.QuadPart *= RedirInitInfo->CacheBlockSize;
391
392         AFSDumpFileLocation.Length = 0;
393
394         AFSDumpFileLocation.MaximumLength = (USHORT)RedirInitInfo->DumpFileLocationLength + (4 * sizeof( WCHAR));
395
396         AFSDumpFileLocation.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
397                                                                         AFSDumpFileLocation.MaximumLength,
398                                                                         AFS_GENERIC_MEMORY_23_TAG);
399
400         if( AFSDumpFileLocation.Buffer == NULL)
401         {
402
403             AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
404                           AFS_TRACE_LEVEL_ERROR,
405                           "AFSInitializeRedirector AFS_GENERIC_MEMORY_23_TAG allocation error\n");
406
407             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
408         }
409
410         RtlCopyMemory( AFSDumpFileLocation.Buffer,
411                        L"\\??\\",
412                        4 * sizeof( WCHAR));
413
414         AFSDumpFileLocation.Length = 4 * sizeof( WCHAR);
415
416         RtlCopyMemory( &AFSDumpFileLocation.Buffer[ AFSDumpFileLocation.Length/sizeof( WCHAR)],
417                        (void *)((char *)RedirInitInfo + RedirInitInfo->DumpFileLocationOffset),
418                        RedirInitInfo->DumpFileLocationLength);
419
420         AFSDumpFileLocation.Length += (USHORT)RedirInitInfo->DumpFileLocationLength;
421
422         //
423         // Be sure the shutdown flag is not set
424         //
425
426         ClearFlag( pDevExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN);
427
428         //
429         // Set up the Throttles.
430         //
431         // Max IO is 10% of the cache, or the value in the registry,
432         // with a minimum of 5Mb (and a maximum of 50% cache size)
433         //
434         if( AFSMaxDirectIo)
435         {
436             //
437             // collect what the user
438             //
439             pDevExt->Specific.RDR.MaxIo.QuadPart = AFSMaxDirectIo;
440             pDevExt->Specific.RDR.MaxIo.QuadPart *= (1024 * 1024);
441
442         }
443         else
444         {
445
446             pDevExt->Specific.RDR.MaxIo.QuadPart = cacheSizeBytes.QuadPart / 2;
447         }
448
449         if (pDevExt->Specific.RDR.MaxIo.QuadPart < (5 * 1024 * 1204))
450         {
451
452             pDevExt->Specific.RDR.MaxIo.QuadPart = 5 * 1024 * 1204;
453
454         }
455
456         //
457         // For small cache configurations ...
458         //
459
460         if (pDevExt->Specific.RDR.MaxIo.QuadPart > cacheSizeBytes.QuadPart / 2)
461         {
462
463             pDevExt->Specific.RDR.MaxIo.QuadPart  = cacheSizeBytes.QuadPart / 2;
464         }
465
466         //
467         // Maximum Dirty is 50% of the cache, or the value in the
468         // registry.  No minimum, maximum of 90% of cache size.
469         //
470         if (AFSMaxDirtyFile)
471         {
472
473             pDevExt->Specific.RDR.MaxDirty.QuadPart = AFSMaxDirtyFile;
474             pDevExt->Specific.RDR.MaxDirty.QuadPart *= (1024 * 1024);
475
476         }
477         else
478         {
479
480             pDevExt->Specific.RDR.MaxDirty.QuadPart = cacheSizeBytes.QuadPart/2;
481
482         }
483
484         cacheSizeBytes.QuadPart *= 9;
485         cacheSizeBytes.QuadPart  = cacheSizeBytes.QuadPart / 10;
486
487         if (pDevExt->Specific.RDR.MaxDirty.QuadPart > cacheSizeBytes.QuadPart)
488         {
489             pDevExt->Specific.RDR.MaxDirty.QuadPart = cacheSizeBytes.QuadPart;
490         }
491
492         //
493         // Store off any flags for the file system
494         //
495
496         if( BooleanFlagOn( RedirInitInfo->Flags, AFS_REDIR_INIT_FLAG_HIDE_DOT_FILES))
497         {
498
499             //
500             // Hide files which begin with .
501             //
502
503             SetFlag( pDevExt->DeviceFlags, AFS_DEVICE_FLAG_HIDE_DOT_NAMES);
504         }
505
506         if( RedirInitInfo->MemoryCacheOffset.QuadPart != 0 &&
507             RedirInitInfo->MemoryCacheLength.QuadPart != 0)
508         {
509
510             ntStatus = STATUS_INSUFFICIENT_RESOURCES;
511
512 #ifdef AMD64
513             pDevExt->Specific.RDR.CacheMdl = MmCreateMdl( NULL,
514                                                           (void *)RedirInitInfo->MemoryCacheOffset.QuadPart,
515                                                           RedirInitInfo->MemoryCacheLength.QuadPart);
516 #else
517             pDevExt->Specific.RDR.CacheMdl = MmCreateMdl( NULL,
518                                                           (void *)RedirInitInfo->MemoryCacheOffset.LowPart,
519                                                           RedirInitInfo->MemoryCacheLength.LowPart);
520 #endif
521
522             if( pDevExt->Specific.RDR.CacheMdl != NULL)
523             {
524
525                 __try
526                 {
527
528                     MmProbeAndLockPages( pDevExt->Specific.RDR.CacheMdl,
529                                          KernelMode,
530                                          IoModifyAccess);
531
532                     pDevExt->Specific.RDR.CacheBaseAddress = MmGetSystemAddressForMdlSafe( pDevExt->Specific.RDR.CacheMdl,
533                                                                                            NormalPagePriority);
534                 }
535                 __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
536                 {
537
538                     AFSDumpTraceFilesFnc();
539
540                     IoFreeMdl( pDevExt->Specific.RDR.CacheMdl);
541                     pDevExt->Specific.RDR.CacheMdl = NULL;
542                 }
543
544                 if( pDevExt->Specific.RDR.CacheMdl != NULL)
545                 {
546                     pDevExt->Specific.RDR.CacheLength = RedirInitInfo->MemoryCacheLength;
547                     ntStatus = STATUS_SUCCESS;
548                 }
549
550             }
551         }
552
553         if( !NT_SUCCESS( ntStatus) &&
554             RedirInitInfo->CacheFileNameLength == 0)
555         {
556
557             AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
558                           AFS_TRACE_LEVEL_ERROR,
559                           "AFSInitializeRedirector Unable to initialize cache file %08lX\n",
560                           ntStatus);
561
562             try_return( ntStatus);
563         }
564
565         if( pDevExt->Specific.RDR.CacheMdl == NULL)
566         {
567
568             if( RedirInitInfo->CacheFileNameLength == 0)
569             {
570
571                 AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
572                               AFS_TRACE_LEVEL_ERROR,
573                               "AFSInitializeRedirector CacheMdl == NULL\n");
574
575                 try_return( ntStatus = STATUS_INVALID_PARAMETER);
576             }
577
578             //
579             // Go open the cache file
580             //
581
582             pDevExt->Specific.RDR.CacheFile.Length = 0;
583             pDevExt->Specific.RDR.CacheFile.MaximumLength = (USHORT)RedirInitInfo->CacheFileNameLength + (4 * sizeof( WCHAR));
584
585             pDevExt->Specific.RDR.CacheFile.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
586                                                                                         pDevExt->Specific.RDR.CacheFile.MaximumLength,
587                                                                                         AFS_GENERIC_MEMORY_24_TAG);
588
589             if( pDevExt->Specific.RDR.CacheFile.Buffer == NULL)
590             {
591
592                 AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
593                               AFS_TRACE_LEVEL_ERROR,
594                               "AFSInitializeRedirector AFS_GENERIC_MEMORY_24_TAG allocation failure\n");
595
596                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
597             }
598
599             RtlCopyMemory( pDevExt->Specific.RDR.CacheFile.Buffer,
600                            L"\\??\\",
601                            4 * sizeof( WCHAR));
602
603             pDevExt->Specific.RDR.CacheFile.Length = 4 * sizeof( WCHAR);
604
605             RtlCopyMemory( &pDevExt->Specific.RDR.CacheFile.Buffer[ pDevExt->Specific.RDR.CacheFile.Length/sizeof( WCHAR)],
606                            RedirInitInfo->CacheFileName,
607                            RedirInitInfo->CacheFileNameLength);
608
609             pDevExt->Specific.RDR.CacheFile.Length += (USHORT)RedirInitInfo->CacheFileNameLength;
610
611             InitializeObjectAttributes( &stObjectAttribs,
612                                         &pDevExt->Specific.RDR.CacheFile,
613                                         OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
614                                         NULL,
615                                         NULL);
616
617             ntStatus = ZwOpenFile( &pDevExt->Specific.RDR.CacheFileHandle,
618                                    GENERIC_READ | GENERIC_WRITE,
619                                    &stObjectAttribs,
620                                    &stIoStatus,
621                                    FILE_SHARE_READ | FILE_SHARE_WRITE,
622                                    FILE_WRITE_THROUGH | FILE_RANDOM_ACCESS);
623
624             if( !NT_SUCCESS( ntStatus))
625             {
626
627                 AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
628                               AFS_TRACE_LEVEL_ERROR,
629                               "AFSInitializeRedirector ZwOpenFile failure %08lX\n",
630                               ntStatus);
631
632                 try_return( ntStatus);
633             }
634
635             //
636             // Map to the fileobject
637             //
638
639             ntStatus = ObReferenceObjectByHandle( pDevExt->Specific.RDR.CacheFileHandle,
640                                                   SYNCHRONIZE,
641                                                   NULL,
642                                                   KernelMode,
643                                                   (void **)&pDevExt->Specific.RDR.CacheFileObject,
644                                                   NULL);
645
646             if( !NT_SUCCESS( ntStatus))
647             {
648
649                 AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
650                               AFS_TRACE_LEVEL_ERROR,
651                               "AFSInitializeRedirector ObReferenceObjectByHandle failure %08lX\n",
652                               ntStatus);
653
654                 try_return( ntStatus);
655             }
656         }
657
658         pDevExt->Specific.RDR.MaxLinkCount = RedirInitInfo->MaxPathLinkCount;
659
660         pDevExt->Specific.RDR.NameArrayLength = RedirInitInfo->NameArrayLength;
661
662         //
663         // Intialize the library
664         //
665
666         ntStatus = AFSInitializeLibrary( &RedirInitInfo->GlobalFileId,
667                                          TRUE);
668
669         if ( !NT_SUCCESS( ntStatus))
670         {
671             AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
672                           AFS_TRACE_LEVEL_ERROR,
673                           "AFSInitializeRedirector AFSInitializeLibrary failure %08lX\n",
674                           ntStatus);
675         }
676
677 try_exit:
678
679         if( !NT_SUCCESS( ntStatus))
680         {
681
682             if( pDevExt->Specific.RDR.CacheMdl != NULL)
683             {
684
685                 MmUnmapLockedPages( pDevExt->Specific.RDR.CacheBaseAddress,
686                                     pDevExt->Specific.RDR.CacheMdl);
687
688                 MmUnlockPages( pDevExt->Specific.RDR.CacheMdl);
689
690                 ExFreePool( pDevExt->Specific.RDR.CacheMdl);
691
692                 pDevExt->Specific.RDR.CacheMdl = NULL;
693                 pDevExt->Specific.RDR.CacheBaseAddress = NULL;
694                 pDevExt->Specific.RDR.CacheLength.QuadPart = 0;
695             }
696
697             if( pDevExt->Specific.RDR.CacheFileHandle != NULL)
698             {
699
700                 ZwClose( pDevExt->Specific.RDR.CacheFileHandle);
701
702                 pDevExt->Specific.RDR.CacheFileHandle = NULL;
703             }
704
705             if( pDevExt->Specific.RDR.CacheFileObject != NULL)
706             {
707
708                 ObDereferenceObject( pDevExt->Specific.RDR.CacheFileObject);
709
710                 pDevExt->Specific.RDR.CacheFileObject = NULL;
711             }
712
713             if( pDevExt->Specific.RDR.CacheFile.Buffer != NULL)
714             {
715
716                 ExFreePool( pDevExt->Specific.RDR.CacheFile.Buffer);
717
718                 pDevExt->Specific.RDR.CacheFile.Buffer = NULL;
719             }
720
721             if( AFSDumpFileLocation.Buffer != NULL)
722             {
723                 ExFreePool( AFSDumpFileLocation.Buffer);
724
725                 AFSDumpFileLocation.Buffer = NULL;
726             }
727
728             if ( pDevExt->Fcb != NULL)
729             {
730
731                 AFSRemoveRdrFcb( &pDevExt->Fcb);
732
733                 pDevExt = NULL;
734             }
735
736             AFSUnloadLibrary( TRUE);
737         }
738     }
739
740     return ntStatus;
741 }
742
743 NTSTATUS
744 AFSCloseRedirector()
745 {
746
747     NTSTATUS ntStatus = STATUS_SUCCESS;
748     AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
749
750     __Enter
751     {
752
753         //
754         // Unload the library first so we close off any accesses to the cache or underlying
755         // shared memory
756         //
757
758         AFSUnloadLibrary( TRUE);
759
760         //
761         // Close off the cache file or mapping
762         //
763
764         if( pDevExt->Specific.RDR.CacheMdl != NULL)
765         {
766
767             MmUnmapLockedPages( pDevExt->Specific.RDR.CacheBaseAddress,
768                                 pDevExt->Specific.RDR.CacheMdl);
769
770             MmUnlockPages( pDevExt->Specific.RDR.CacheMdl);
771
772             ExFreePool( pDevExt->Specific.RDR.CacheMdl);
773
774             pDevExt->Specific.RDR.CacheMdl = NULL;
775             pDevExt->Specific.RDR.CacheBaseAddress = NULL;
776             pDevExt->Specific.RDR.CacheLength.QuadPart = 0;
777         }
778
779         if( pDevExt->Specific.RDR.CacheFileHandle != NULL)
780         {
781
782             ZwClose( pDevExt->Specific.RDR.CacheFileHandle);
783
784             pDevExt->Specific.RDR.CacheFileHandle = NULL;
785         }
786
787         if( pDevExt->Specific.RDR.CacheFileObject != NULL)
788         {
789
790             ObDereferenceObject( pDevExt->Specific.RDR.CacheFileObject);
791
792             pDevExt->Specific.RDR.CacheFileObject = NULL;
793         }
794
795         if( pDevExt->Specific.RDR.CacheFile.Buffer != NULL)
796         {
797
798             ExFreePool( pDevExt->Specific.RDR.CacheFile.Buffer);
799
800             pDevExt->Specific.RDR.CacheFile.Buffer = NULL;
801         }
802
803         if( AFSDumpFileLocation.Buffer != NULL)
804         {
805             ExFreePool( AFSDumpFileLocation.Buffer);
806
807             AFSDumpFileLocation.Buffer = NULL;
808         }
809
810         if ( pDevExt->Fcb != NULL)
811         {
812
813             AFSRemoveRdrFcb( &pDevExt->Fcb);
814
815             pDevExt->Fcb = NULL;
816         }
817
818     }
819
820     return ntStatus;
821 }
822
823 //
824 // Function: AFSInitRdrFcb
825 //
826 // Description:
827 //
828 //      This function performs Redirector Fcb initialization
829 //
830 // Return:
831 //
832 //      A status is returned for the function
833 //
834
835 NTSTATUS
836 AFSInitRdrFcb( OUT AFSFcb **RdrFcb)
837 {
838
839     NTSTATUS ntStatus = STATUS_SUCCESS;
840     AFSFcb *pFcb = NULL;
841     AFSNonPagedFcb *pNPFcb = NULL;
842     IO_STATUS_BLOCK stIoStatus = {0,0};
843     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
844
845     __Enter
846     {
847
848         //
849         // Initialize the root fcb
850         //
851
852         pFcb = (AFSFcb *)AFSExAllocatePoolWithTag( PagedPool,
853                                                    sizeof( AFSFcb),
854                                                    AFS_FCB_ALLOCATION_TAG);
855
856         if( pFcb == NULL)
857         {
858
859             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
860                           AFS_TRACE_LEVEL_ERROR,
861                           "AFSInitRdrFcb Failed to allocate the root fcb\n");
862
863             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
864         }
865
866         RtlZeroMemory( pFcb,
867                        sizeof( AFSFcb));
868
869         pFcb->Header.NodeByteSize = sizeof( AFSFcb);
870         pFcb->Header.NodeTypeCode = AFS_REDIRECTOR_FCB;
871
872         pNPFcb = (AFSNonPagedFcb *)AFSExAllocatePoolWithTag( NonPagedPool,
873                                                              sizeof( AFSNonPagedFcb),
874                                                              AFS_FCB_NP_ALLOCATION_TAG);
875
876         if( pNPFcb == NULL)
877         {
878
879             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
880                           AFS_TRACE_LEVEL_ERROR,
881                           "AFSInitRdrFcb Failed to allocate the non-paged fcb\n");
882
883             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
884         }
885
886         RtlZeroMemory( pNPFcb,
887                        sizeof( AFSNonPagedFcb));
888
889         pNPFcb->Size = sizeof( AFSNonPagedFcb);
890
891         pNPFcb->Type = AFS_NON_PAGED_FCB;
892
893         //
894         // OK, initialize the entry
895         //
896
897         ExInitializeFastMutex( &pNPFcb->AdvancedHdrMutex);
898
899         FsRtlSetupAdvancedHeader( &pFcb->Header, &pNPFcb->AdvancedHdrMutex);
900
901         ExInitializeResourceLite( &pNPFcb->Resource);
902
903         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
904                       AFS_TRACE_LEVEL_VERBOSE,
905                       "AFSInitRootFcb Acquiring Fcb lock %08lX EXCL %08lX\n",
906                       &pNPFcb->Resource,
907                       PsGetCurrentThread());
908
909         ExInitializeResourceLite( &pNPFcb->PagingResource);
910
911         pFcb->Header.Resource = &pNPFcb->Resource;
912
913         pFcb->Header.PagingIoResource = &pNPFcb->PagingResource;
914
915         pFcb->NPFcb = pNPFcb;
916
917         if ( InterlockedCompareExchangePointer( (PVOID *)RdrFcb, pFcb, NULL) != NULL)
918         {
919
920             try_return( ntStatus = STATUS_REPARSE);
921         }
922
923 try_exit:
924
925         if( ntStatus != STATUS_SUCCESS)
926         {
927
928             if( pFcb != NULL)
929             {
930
931                 AFSRemoveRdrFcb( &pFcb);
932             }
933         }
934     }
935
936     return ntStatus;
937 }
938
939 //
940 // Function: AFSRemoveRdrFcb
941 //
942 // Description:
943 //
944 //      This function performs Redirector Fcb removal/deallocation
945 //
946 // Return:
947 //
948 //      void.
949 //
950
951 void
952 AFSRemoveRdrFcb( IN OUT AFSFcb **RdrFcb)
953 {
954     AFSFcb *pFcb = NULL;
955
956     pFcb = (AFSFcb *) InterlockedCompareExchangePointer( (PVOID *)RdrFcb, NULL, (PVOID)(*RdrFcb));
957
958     if ( pFcb == NULL)
959     {
960
961         return;
962     }
963
964     if( pFcb->NPFcb != NULL)
965     {
966
967         //
968         // Now the resource
969         //
970
971         ExDeleteResourceLite( &pFcb->NPFcb->Resource);
972
973         ExDeleteResourceLite( &pFcb->NPFcb->PagingResource);
974
975         //
976         // The non paged region
977         //
978
979         AFSExFreePoolWithTag( pFcb->NPFcb, AFS_FCB_NP_ALLOCATION_TAG);
980     }
981
982     //
983     // And the Fcb itself
984     //
985
986     AFSExFreePoolWithTag( pFcb, AFS_FCB_ALLOCATION_TAG);
987
988     return;
989 }