Windows: Add Hard Link support to AFS Redirector
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSVolumeInfo.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: AFSVolumeInfo.cpp
37 //
38
39 #include "AFSCommon.h"
40
41 NTSTATUS
42 AFSQueryVolumeInfo( IN PDEVICE_OBJECT LibDeviceObject,
43                     IN PIRP Irp)
44 {
45
46     NTSTATUS ntStatus = STATUS_SUCCESS;
47     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
48     IO_STACK_LOCATION *pIrpSp;
49     FS_INFORMATION_CLASS FsInformationClass;
50     void *pBuffer = NULL;
51     ULONG ulLength = 0;
52     BOOLEAN bReleaseResource = FALSE;
53     PFILE_OBJECT pFileObject = NULL;
54     AFSFcb *pFcb = NULL;
55     AFSObjectInfoCB *pObjectInfo = NULL;
56     AFSVolumeCB *pVolumeCB = NULL;
57
58     pIrpSp = IoGetCurrentIrpStackLocation( Irp);
59
60     __try
61     {
62
63         pFileObject = pIrpSp->FileObject;
64
65         if( pFileObject == NULL)
66         {
67
68             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
69                           AFS_TRACE_LEVEL_ERROR,
70                           "AFSQueryVolumeInfo Failing request with NULL FileObject\n");
71
72             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
73         }
74
75         pFcb = (AFSFcb *)pFileObject->FsContext;
76
77         if( pFcb == NULL)
78         {
79
80             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
81                           AFS_TRACE_LEVEL_ERROR,
82                           "AFSQueryVolumeInfo Failing request with NULL Fcb\n");
83
84             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
85         }
86
87         pObjectInfo = pFcb->ObjectInformation;
88
89         if( pObjectInfo == NULL)
90         {
91
92             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
93                           AFS_TRACE_LEVEL_ERROR,
94                           "AFSQueryVolumeInfo Failing request with NULL ObjectInformation\n");
95
96             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
97         }
98
99         pVolumeCB = pObjectInfo->VolumeCB;
100
101         ulLength = pIrpSp->Parameters.QueryVolume.Length;
102         FsInformationClass = pIrpSp->Parameters.QueryVolume.FsInformationClass;
103         pBuffer = Irp->AssociatedIrp.SystemBuffer;
104
105         AFSAcquireShared( pVolumeCB->VolumeLock,
106                           TRUE);
107
108         bReleaseResource = TRUE;
109
110         //
111         // Don't allow requests against IOCtl nodes
112         //
113
114         if( pFcb->Header.NodeTypeCode == AFS_IOCTL_FCB)
115         {
116
117             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
118                           AFS_TRACE_LEVEL_ERROR,
119                           "AFSQueryVolumeInfo Failing request against PIOCtl Fcb\n");
120
121             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
122         }
123         else if( pFcb->Header.NodeTypeCode == AFS_SPECIAL_SHARE_FCB)
124         {
125
126             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
127                           AFS_TRACE_LEVEL_ERROR,
128                           "AFSQueryVolumeInfo Failing request against SpecialShare Fcb\n");
129
130             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
131         }
132         else if( pFcb->Header.NodeTypeCode == AFS_INVALID_FCB)
133         {
134
135             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
136                           AFS_TRACE_LEVEL_ERROR,
137                           "AFSQueryVolumeInfo Failing request against SpecialShare Fcb\n");
138
139             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
140         }
141
142         //
143         // Process the request
144         //
145
146         switch( FsInformationClass)
147         {
148
149             case FileFsVolumeInformation:
150             {
151
152                 ntStatus = AFSQueryFsVolumeInfo( &pVolumeCB->VolumeInformation,
153                                                  (PFILE_FS_VOLUME_INFORMATION)pBuffer,
154                                                  &ulLength);
155
156                 break;
157             }
158
159             case FileFsSizeInformation:
160             {
161
162                 ntStatus = AFSQueryFsSizeInfo( &pVolumeCB->VolumeInformation,
163                                                (PFILE_FS_SIZE_INFORMATION)pBuffer,
164                                                &ulLength);
165
166                 break;
167             }
168
169             case FileFsDeviceInformation:
170             {
171
172                 ntStatus = AFSQueryFsDeviceInfo( &pVolumeCB->VolumeInformation,
173                                                  (PFILE_FS_DEVICE_INFORMATION)pBuffer,
174                                                  &ulLength);
175
176                 break;
177             }
178
179             case FileFsAttributeInformation:
180             {
181
182                 ntStatus = AFSQueryFsAttributeInfo( &pVolumeCB->VolumeInformation,
183                                                     (PFILE_FS_ATTRIBUTE_INFORMATION)pBuffer,
184                                                     &ulLength);
185
186                 break;
187             }
188
189             case FileFsFullSizeInformation:
190             {
191
192                 ntStatus = AFSQueryFsFullSizeInfo( &pVolumeCB->VolumeInformation,
193                                                    (PFILE_FS_FULL_SIZE_INFORMATION)pBuffer,
194                                                    &ulLength);
195
196                 break;
197             }
198
199             default:
200
201                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
202                               AFS_TRACE_LEVEL_WARNING,
203                               "AFSQueryVolumeInfo Invalid class %d\n",
204                               FsInformationClass);
205
206                 ntStatus = STATUS_INVALID_PARAMETER;
207
208                 break;
209         }
210
211 try_exit:
212
213         //
214         // Setup the Irp's information field to what we actually copied in.
215         //
216
217         Irp->IoStatus.Information = pIrpSp->Parameters.QueryVolume.Length - ulLength;
218
219         if( bReleaseResource)
220         {
221
222             AFSReleaseResource( pVolumeCB->VolumeLock);
223         }
224
225         AFSCompleteRequest( Irp,
226                             ntStatus);
227
228     }
229     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
230     {
231
232         AFSDbgLogMsg( 0,
233                       0,
234                       "EXCEPTION - AFSQueryVolumeInfo FO %08lX InfoClass %d FCB %08lX ObjectInfo %08lX VolCB %08lX\n",
235                       pFileObject,
236                       FsInformationClass,
237                       pFcb,
238                       pObjectInfo,
239                       pVolumeCB);
240
241         AFSDumpTraceFilesFnc();
242     }
243
244     return ntStatus;
245 }
246
247 NTSTATUS
248 AFSSetVolumeInfo( IN PDEVICE_OBJECT DeviceObject,
249                   IN PIRP Irp)
250 {
251
252     NTSTATUS ntStatus = STATUS_SUCCESS;
253     IO_STACK_LOCATION *pIrpSp;
254
255     pIrpSp = IoGetCurrentIrpStackLocation( Irp);
256
257     __try
258     {
259
260         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
261                       AFS_TRACE_LEVEL_WARNING,
262                       "AFSSetVolumeInfo Entry for FO %08lX\n", pIrpSp->FileObject);
263
264         AFSCompleteRequest( Irp,
265                             ntStatus);
266
267     }
268     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
269     {
270
271         AFSDbgLogMsg( 0,
272                       0,
273                       "EXCEPTION - AFSSetVolumeInfo\n");
274
275         AFSDumpTraceFilesFnc();
276     }
277
278     return ntStatus;
279 }
280
281 NTSTATUS
282 AFSQueryFsVolumeInfo( IN AFSVolumeInfoCB *VolumeInfo,
283                       IN PFILE_FS_VOLUME_INFORMATION Buffer,
284                       IN OUT PULONG Length)
285
286 {
287
288     NTSTATUS ntStatus = STATUS_BUFFER_TOO_SMALL;
289     ULONG ulCopyLength;
290
291     RtlZeroMemory( Buffer,
292                    *Length);
293
294     if( *Length >= (ULONG)sizeof( FILE_FS_VOLUME_INFORMATION))
295     {
296
297         if( *Length >= (ULONG)(FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel) + (LONG)VolumeInfo->VolumeLabelLength))
298         {
299
300             ulCopyLength = (LONG)VolumeInfo->VolumeLabelLength;
301
302             ntStatus = STATUS_SUCCESS;
303         }
304         else
305         {
306
307             ulCopyLength = *Length - FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel);
308
309             ntStatus = STATUS_BUFFER_OVERFLOW;
310         }
311
312         Buffer->VolumeCreationTime.QuadPart = VolumeInfo->VolumeCreationTime.QuadPart;
313
314         Buffer->VolumeSerialNumber = VolumeInfo->VolumeID;
315
316         Buffer->VolumeLabelLength = VolumeInfo->VolumeLabelLength;
317
318         Buffer->SupportsObjects = FALSE;
319
320         *Length -= FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel);
321
322         if( ulCopyLength > 0)
323         {
324
325             RtlCopyMemory( Buffer->VolumeLabel,
326                            VolumeInfo->VolumeLabel,
327                            ulCopyLength);
328
329             *Length -= ulCopyLength;
330         }
331     }
332
333     return ntStatus;
334 }
335
336 NTSTATUS
337 AFSQueryFsSizeInfo( IN AFSVolumeInfoCB *VolumeInfo,
338                     IN PFILE_FS_SIZE_INFORMATION Buffer,
339                     IN OUT PULONG Length)
340 {
341
342     NTSTATUS ntStatus = STATUS_SUCCESS;
343     AFSFileID FileID;
344     AFSVolumeSizeInfoCB VolumeSizeInfo;
345
346     RtlZeroMemory( Buffer,
347                    *Length);
348
349     if( *Length >= sizeof( FILE_FS_SIZE_INFORMATION))
350     {
351
352         RtlZeroMemory( &FileID,
353                        sizeof(AFSFileID));
354
355         FileID.Cell = VolumeInfo->CellID;
356
357         FileID.Volume = VolumeInfo->VolumeID;
358
359         ntStatus = AFSRetrieveVolumeSizeInformation( NULL,
360                                                      &FileID,
361                                                      &VolumeSizeInfo);
362
363         if ( NT_SUCCESS( ntStatus))
364         {
365
366             Buffer->TotalAllocationUnits.QuadPart = VolumeSizeInfo.TotalAllocationUnits.QuadPart;
367
368             Buffer->AvailableAllocationUnits.QuadPart = VolumeSizeInfo.AvailableAllocationUnits.QuadPart;
369
370             Buffer->SectorsPerAllocationUnit = VolumeSizeInfo.SectorsPerAllocationUnit;
371
372             Buffer->BytesPerSector = VolumeSizeInfo.BytesPerSector;
373
374             *Length -= sizeof( FILE_FS_SIZE_INFORMATION);
375         }
376     }
377     else
378     {
379
380         ntStatus = STATUS_BUFFER_TOO_SMALL;
381     }
382
383     return ntStatus;
384 }
385
386 NTSTATUS
387 AFSQueryFsDeviceInfo( IN AFSVolumeInfoCB *VolumeInfo,
388                       IN PFILE_FS_DEVICE_INFORMATION Buffer,
389                       IN OUT PULONG Length)
390 {
391     NTSTATUS ntStatus = STATUS_SUCCESS;
392
393     RtlZeroMemory( Buffer,
394                    *Length);
395
396     if( *Length >= (LONG)sizeof( FILE_FS_DEVICE_INFORMATION))
397     {
398
399         Buffer->DeviceType = FILE_DEVICE_DISK;
400
401         Buffer->Characteristics = VolumeInfo->Characteristics;
402
403         *Length -= sizeof( FILE_FS_DEVICE_INFORMATION);
404     }
405     else
406     {
407
408         ntStatus = STATUS_BUFFER_TOO_SMALL;
409     }
410
411     return ntStatus;
412 }
413
414 NTSTATUS
415 AFSQueryFsAttributeInfo( IN AFSVolumeInfoCB *VolumeInfo,
416                          IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
417                          IN OUT PULONG Length)
418 {
419     NTSTATUS ntStatus = STATUS_SUCCESS;
420
421     RtlZeroMemory( Buffer,
422                    *Length);
423
424     if( *Length >= (LONG)(sizeof( FILE_FS_ATTRIBUTE_INFORMATION)))
425     {
426
427         Buffer->FileSystemAttributes = (FILE_CASE_PRESERVED_NAMES |
428                                         FILE_UNICODE_ON_DISK |
429                                         FILE_SUPPORTS_HARD_LINKS |
430                                         FILE_SUPPORTS_REPARSE_POINTS);
431
432         Buffer->MaximumComponentNameLength = 255;
433
434         Buffer->FileSystemNameLength = 18;
435
436         *Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName);
437
438         if( *Length >= 18)
439         {
440
441             RtlCopyMemory( Buffer->FileSystemName,
442                            L"AFSRDRFsd",
443                            18);
444
445             *Length -= 18;
446         }
447         else
448         {
449
450             ntStatus = STATUS_BUFFER_OVERFLOW;
451         }
452     }
453     else
454     {
455
456         ntStatus = STATUS_BUFFER_TOO_SMALL;
457     }
458
459     return ntStatus;
460 }
461
462 NTSTATUS
463 AFSQueryFsFullSizeInfo( IN AFSVolumeInfoCB *VolumeInfo,
464                         IN PFILE_FS_FULL_SIZE_INFORMATION Buffer,
465                         IN OUT PULONG Length)
466 {
467
468     NTSTATUS ntStatus = STATUS_SUCCESS;
469     AFSFileID FileID;
470     AFSVolumeSizeInfoCB VolumeSizeInfo;
471
472     RtlZeroMemory( Buffer,
473                    *Length);
474
475     if( *Length >= sizeof( FILE_FS_FULL_SIZE_INFORMATION))
476     {
477
478         RtlZeroMemory( &FileID,
479                        sizeof(AFSFileID));
480
481         FileID.Cell = VolumeInfo->CellID;
482
483         FileID.Volume = VolumeInfo->VolumeID;
484
485         ntStatus = AFSRetrieveVolumeSizeInformation( NULL,
486                                                      &FileID,
487                                                      &VolumeSizeInfo);
488
489         if ( NT_SUCCESS( ntStatus))
490         {
491
492             Buffer->TotalAllocationUnits.QuadPart = VolumeSizeInfo.TotalAllocationUnits.QuadPart;
493
494             Buffer->CallerAvailableAllocationUnits.QuadPart = VolumeSizeInfo.AvailableAllocationUnits.QuadPart;
495
496             Buffer->ActualAvailableAllocationUnits.QuadPart = VolumeSizeInfo.AvailableAllocationUnits.QuadPart;
497
498             Buffer->SectorsPerAllocationUnit = VolumeSizeInfo.SectorsPerAllocationUnit;
499
500             Buffer->BytesPerSector = VolumeSizeInfo.BytesPerSector;
501
502             *Length -= sizeof( FILE_FS_FULL_SIZE_INFORMATION);
503         }
504     }
505     else
506     {
507
508         ntStatus = STATUS_BUFFER_TOO_SMALL;
509     }
510
511     return ntStatus;
512 }