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