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