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