12b899d8fa497e2915fb200e4a196dd2626f4a2e
[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( BooleanFlagOn( RedirInitInfo->Flags, AFS_REDIR_INIT_FLAG_DISABLE_SHORTNAMES))
507         {
508
509             //
510             // Hide files which begin with .
511             //
512
513             SetFlag( pDevExt->DeviceFlags, AFS_DEVICE_FLAG_DISABLE_SHORTNAMES);
514         }
515
516         if( RedirInitInfo->MemoryCacheOffset.QuadPart != 0 &&
517             RedirInitInfo->MemoryCacheLength.QuadPart != 0)
518         {
519
520             ntStatus = STATUS_INSUFFICIENT_RESOURCES;
521
522 #ifdef AMD64
523             pDevExt->Specific.RDR.CacheMdl = MmCreateMdl( NULL,
524                                                           (void *)RedirInitInfo->MemoryCacheOffset.QuadPart,
525                                                           RedirInitInfo->MemoryCacheLength.QuadPart);
526 #else
527             pDevExt->Specific.RDR.CacheMdl = MmCreateMdl( NULL,
528                                                           (void *)RedirInitInfo->MemoryCacheOffset.LowPart,
529                                                           RedirInitInfo->MemoryCacheLength.LowPart);
530 #endif
531
532             if( pDevExt->Specific.RDR.CacheMdl != NULL)
533             {
534
535                 __try
536                 {
537
538                     MmProbeAndLockPages( pDevExt->Specific.RDR.CacheMdl,
539                                          KernelMode,
540                                          IoModifyAccess);
541
542                     pDevExt->Specific.RDR.CacheBaseAddress = MmGetSystemAddressForMdlSafe( pDevExt->Specific.RDR.CacheMdl,
543                                                                                            NormalPagePriority);
544                 }
545                 __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
546                 {
547
548                     AFSDumpTraceFilesFnc();
549
550                     IoFreeMdl( pDevExt->Specific.RDR.CacheMdl);
551                     pDevExt->Specific.RDR.CacheMdl = NULL;
552                 }
553
554                 if( pDevExt->Specific.RDR.CacheMdl != NULL)
555                 {
556                     pDevExt->Specific.RDR.CacheLength = RedirInitInfo->MemoryCacheLength;
557                     ntStatus = STATUS_SUCCESS;
558                 }
559
560             }
561         }
562
563         if( !NT_SUCCESS( ntStatus) &&
564             RedirInitInfo->CacheFileNameLength == 0)
565         {
566
567             AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
568                           AFS_TRACE_LEVEL_ERROR,
569                           "AFSInitializeRedirector Unable to initialize cache file %08lX\n",
570                           ntStatus);
571
572             try_return( ntStatus);
573         }
574
575         if( pDevExt->Specific.RDR.CacheMdl == NULL)
576         {
577
578             if( RedirInitInfo->CacheFileNameLength == 0)
579             {
580
581                 AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
582                               AFS_TRACE_LEVEL_ERROR,
583                               "AFSInitializeRedirector CacheMdl == NULL\n");
584
585                 try_return( ntStatus = STATUS_INVALID_PARAMETER);
586             }
587
588             //
589             // Go open the cache file
590             //
591
592             pDevExt->Specific.RDR.CacheFile.Length = 0;
593             pDevExt->Specific.RDR.CacheFile.MaximumLength = (USHORT)RedirInitInfo->CacheFileNameLength + (4 * sizeof( WCHAR));
594
595             pDevExt->Specific.RDR.CacheFile.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
596                                                                                         pDevExt->Specific.RDR.CacheFile.MaximumLength,
597                                                                                         AFS_GENERIC_MEMORY_24_TAG);
598
599             if( pDevExt->Specific.RDR.CacheFile.Buffer == NULL)
600             {
601
602                 AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
603                               AFS_TRACE_LEVEL_ERROR,
604                               "AFSInitializeRedirector AFS_GENERIC_MEMORY_24_TAG allocation failure\n");
605
606                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
607             }
608
609             RtlCopyMemory( pDevExt->Specific.RDR.CacheFile.Buffer,
610                            L"\\??\\",
611                            4 * sizeof( WCHAR));
612
613             pDevExt->Specific.RDR.CacheFile.Length = 4 * sizeof( WCHAR);
614
615             RtlCopyMemory( &pDevExt->Specific.RDR.CacheFile.Buffer[ pDevExt->Specific.RDR.CacheFile.Length/sizeof( WCHAR)],
616                            RedirInitInfo->CacheFileName,
617                            RedirInitInfo->CacheFileNameLength);
618
619             pDevExt->Specific.RDR.CacheFile.Length += (USHORT)RedirInitInfo->CacheFileNameLength;
620
621             InitializeObjectAttributes( &stObjectAttribs,
622                                         &pDevExt->Specific.RDR.CacheFile,
623                                         OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
624                                         NULL,
625                                         NULL);
626
627             ntStatus = ZwOpenFile( &pDevExt->Specific.RDR.CacheFileHandle,
628                                    GENERIC_READ | GENERIC_WRITE,
629                                    &stObjectAttribs,
630                                    &stIoStatus,
631                                    FILE_SHARE_READ | FILE_SHARE_WRITE,
632                                    FILE_WRITE_THROUGH | FILE_RANDOM_ACCESS);
633
634             if( !NT_SUCCESS( ntStatus))
635             {
636
637                 AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
638                               AFS_TRACE_LEVEL_ERROR,
639                               "AFSInitializeRedirector ZwOpenFile failure %08lX\n",
640                               ntStatus);
641
642                 try_return( ntStatus);
643             }
644
645             //
646             // Map to the fileobject
647             //
648
649             ntStatus = ObReferenceObjectByHandle( pDevExt->Specific.RDR.CacheFileHandle,
650                                                   SYNCHRONIZE,
651                                                   NULL,
652                                                   KernelMode,
653                                                   (void **)&pDevExt->Specific.RDR.CacheFileObject,
654                                                   NULL);
655
656             if( !NT_SUCCESS( ntStatus))
657             {
658
659                 AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
660                               AFS_TRACE_LEVEL_ERROR,
661                               "AFSInitializeRedirector ObReferenceObjectByHandle failure %08lX\n",
662                               ntStatus);
663
664                 try_return( ntStatus);
665             }
666         }
667
668         pDevExt->Specific.RDR.MaxLinkCount = RedirInitInfo->MaxPathLinkCount;
669
670         pDevExt->Specific.RDR.NameArrayLength = RedirInitInfo->NameArrayLength;
671
672         //
673         // Intialize the library
674         //
675
676         ntStatus = AFSInitializeLibrary( &RedirInitInfo->GlobalFileId,
677                                          TRUE);
678
679         if ( !NT_SUCCESS( ntStatus))
680         {
681             AFSDbgLogMsg( AFS_SUBSYSTEM_INIT_PROCESSING,
682                           AFS_TRACE_LEVEL_ERROR,
683                           "AFSInitializeRedirector AFSInitializeLibrary failure %08lX\n",
684                           ntStatus);
685         }
686
687 try_exit:
688
689         if( !NT_SUCCESS( ntStatus))
690         {
691
692             if( pDevExt->Specific.RDR.CacheMdl != NULL)
693             {
694
695                 MmUnmapLockedPages( pDevExt->Specific.RDR.CacheBaseAddress,
696                                     pDevExt->Specific.RDR.CacheMdl);
697
698                 MmUnlockPages( pDevExt->Specific.RDR.CacheMdl);
699
700                 ExFreePool( pDevExt->Specific.RDR.CacheMdl);
701
702                 pDevExt->Specific.RDR.CacheMdl = NULL;
703                 pDevExt->Specific.RDR.CacheBaseAddress = NULL;
704                 pDevExt->Specific.RDR.CacheLength.QuadPart = 0;
705             }
706
707             if( pDevExt->Specific.RDR.CacheFileHandle != NULL)
708             {
709
710                 ZwClose( pDevExt->Specific.RDR.CacheFileHandle);
711
712                 pDevExt->Specific.RDR.CacheFileHandle = NULL;
713             }
714
715             if( pDevExt->Specific.RDR.CacheFileObject != NULL)
716             {
717
718                 ObDereferenceObject( pDevExt->Specific.RDR.CacheFileObject);
719
720                 pDevExt->Specific.RDR.CacheFileObject = NULL;
721             }
722
723             if( pDevExt->Specific.RDR.CacheFile.Buffer != NULL)
724             {
725
726                 ExFreePool( pDevExt->Specific.RDR.CacheFile.Buffer);
727
728                 pDevExt->Specific.RDR.CacheFile.Buffer = NULL;
729             }
730
731             if( AFSDumpFileLocation.Buffer != NULL)
732             {
733                 ExFreePool( AFSDumpFileLocation.Buffer);
734
735                 AFSDumpFileLocation.Buffer = NULL;
736             }
737
738             if ( pDevExt->Fcb != NULL)
739             {
740
741                 AFSRemoveRdrFcb( &pDevExt->Fcb);
742
743                 pDevExt = NULL;
744             }
745
746             AFSUnloadLibrary( TRUE);
747         }
748     }
749
750     return ntStatus;
751 }
752
753 NTSTATUS
754 AFSCloseRedirector()
755 {
756
757     NTSTATUS ntStatus = STATUS_SUCCESS;
758     AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
759
760     __Enter
761     {
762
763         //
764         // Unload the library first so we close off any accesses to the cache or underlying
765         // shared memory
766         //
767
768         AFSUnloadLibrary( TRUE);
769
770         //
771         // Close off the cache file or mapping
772         //
773
774         if( pDevExt->Specific.RDR.CacheMdl != NULL)
775         {
776
777             MmUnmapLockedPages( pDevExt->Specific.RDR.CacheBaseAddress,
778                                 pDevExt->Specific.RDR.CacheMdl);
779
780             MmUnlockPages( pDevExt->Specific.RDR.CacheMdl);
781
782             ExFreePool( pDevExt->Specific.RDR.CacheMdl);
783
784             pDevExt->Specific.RDR.CacheMdl = NULL;
785             pDevExt->Specific.RDR.CacheBaseAddress = NULL;
786             pDevExt->Specific.RDR.CacheLength.QuadPart = 0;
787         }
788
789         if( pDevExt->Specific.RDR.CacheFileHandle != NULL)
790         {
791
792             ZwClose( pDevExt->Specific.RDR.CacheFileHandle);
793
794             pDevExt->Specific.RDR.CacheFileHandle = NULL;
795         }
796
797         if( pDevExt->Specific.RDR.CacheFileObject != NULL)
798         {
799
800             ObDereferenceObject( pDevExt->Specific.RDR.CacheFileObject);
801
802             pDevExt->Specific.RDR.CacheFileObject = NULL;
803         }
804
805         if( pDevExt->Specific.RDR.CacheFile.Buffer != NULL)
806         {
807
808             ExFreePool( pDevExt->Specific.RDR.CacheFile.Buffer);
809
810             pDevExt->Specific.RDR.CacheFile.Buffer = NULL;
811         }
812
813         if( AFSDumpFileLocation.Buffer != NULL)
814         {
815             ExFreePool( AFSDumpFileLocation.Buffer);
816
817             AFSDumpFileLocation.Buffer = NULL;
818         }
819
820         if ( pDevExt->Fcb != NULL)
821         {
822
823             AFSRemoveRdrFcb( &pDevExt->Fcb);
824
825             pDevExt->Fcb = NULL;
826         }
827
828     }
829
830     return ntStatus;
831 }
832
833 //
834 // Function: AFSInitRdrFcb
835 //
836 // Description:
837 //
838 //      This function performs Redirector Fcb initialization
839 //
840 // Return:
841 //
842 //      A status is returned for the function
843 //
844
845 NTSTATUS
846 AFSInitRdrFcb( OUT AFSFcb **RdrFcb)
847 {
848
849     NTSTATUS ntStatus = STATUS_SUCCESS;
850     AFSFcb *pFcb = NULL;
851     AFSNonPagedFcb *pNPFcb = NULL;
852     IO_STATUS_BLOCK stIoStatus = {0,0};
853     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
854
855     __Enter
856     {
857
858         //
859         // Initialize the root fcb
860         //
861
862         pFcb = (AFSFcb *)AFSExAllocatePoolWithTag( PagedPool,
863                                                    sizeof( AFSFcb),
864                                                    AFS_FCB_ALLOCATION_TAG);
865
866         if( pFcb == NULL)
867         {
868
869             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
870                           AFS_TRACE_LEVEL_ERROR,
871                           "AFSInitRdrFcb Failed to allocate the root fcb\n");
872
873             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
874         }
875
876         RtlZeroMemory( pFcb,
877                        sizeof( AFSFcb));
878
879         pFcb->Header.NodeByteSize = sizeof( AFSFcb);
880         pFcb->Header.NodeTypeCode = AFS_REDIRECTOR_FCB;
881
882         pNPFcb = (AFSNonPagedFcb *)AFSExAllocatePoolWithTag( NonPagedPool,
883                                                              sizeof( AFSNonPagedFcb),
884                                                              AFS_FCB_NP_ALLOCATION_TAG);
885
886         if( pNPFcb == NULL)
887         {
888
889             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
890                           AFS_TRACE_LEVEL_ERROR,
891                           "AFSInitRdrFcb Failed to allocate the non-paged fcb\n");
892
893             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
894         }
895
896         RtlZeroMemory( pNPFcb,
897                        sizeof( AFSNonPagedFcb));
898
899         pNPFcb->Size = sizeof( AFSNonPagedFcb);
900
901         pNPFcb->Type = AFS_NON_PAGED_FCB;
902
903         //
904         // OK, initialize the entry
905         //
906
907         ExInitializeFastMutex( &pNPFcb->AdvancedHdrMutex);
908
909         FsRtlSetupAdvancedHeader( &pFcb->Header, &pNPFcb->AdvancedHdrMutex);
910
911         ExInitializeResourceLite( &pNPFcb->Resource);
912
913         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
914                       AFS_TRACE_LEVEL_VERBOSE,
915                       "AFSInitRootFcb Acquiring Fcb lock %08lX EXCL %08lX\n",
916                       &pNPFcb->Resource,
917                       PsGetCurrentThread());
918
919         ExInitializeResourceLite( &pNPFcb->PagingResource);
920
921         pFcb->Header.Resource = &pNPFcb->Resource;
922
923         pFcb->Header.PagingIoResource = &pNPFcb->PagingResource;
924
925         pFcb->NPFcb = pNPFcb;
926
927         if ( InterlockedCompareExchangePointer( (PVOID *)RdrFcb, pFcb, NULL) != NULL)
928         {
929
930             try_return( ntStatus = STATUS_REPARSE);
931         }
932
933 try_exit:
934
935         if( ntStatus != STATUS_SUCCESS)
936         {
937
938             if( pFcb != NULL)
939             {
940
941                 AFSRemoveRdrFcb( &pFcb);
942             }
943         }
944     }
945
946     return ntStatus;
947 }
948
949 //
950 // Function: AFSRemoveRdrFcb
951 //
952 // Description:
953 //
954 //      This function performs Redirector Fcb removal/deallocation
955 //
956 // Return:
957 //
958 //      void.
959 //
960
961 void
962 AFSRemoveRdrFcb( IN OUT AFSFcb **RdrFcb)
963 {
964     AFSFcb *pFcb = NULL;
965
966     pFcb = (AFSFcb *) InterlockedCompareExchangePointer( (PVOID *)RdrFcb, NULL, (PVOID)(*RdrFcb));
967
968     if ( pFcb == NULL)
969     {
970
971         return;
972     }
973
974     if( pFcb->NPFcb != NULL)
975     {
976
977         //
978         // Now the resource
979         //
980
981         ExDeleteResourceLite( &pFcb->NPFcb->Resource);
982
983         ExDeleteResourceLite( &pFcb->NPFcb->PagingResource);
984
985         //
986         // The non paged region
987         //
988
989         AFSExFreePoolWithTag( pFcb->NPFcb, AFS_FCB_NP_ALLOCATION_TAG);
990     }
991
992     //
993     // And the Fcb itself
994     //
995
996     AFSExFreePoolWithTag( pFcb, AFS_FCB_ALLOCATION_TAG);
997
998     return;
999 }