672e4a68f97c0d42636201b504337d3110c930f5
[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     UNREFERENCED_PARAMETER(LibDeviceObject);
47     NTSTATUS ntStatus = STATUS_SUCCESS;
48     IO_STACK_LOCATION *pIrpSp;
49     FS_INFORMATION_CLASS FsInformationClass = FileFsMaximumInformation;
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 %p InfoClass %d FCB %p ObjectInfo %p VolCB %p\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     UNREFERENCED_PARAMETER(DeviceObject);
253     NTSTATUS ntStatus = STATUS_SUCCESS;
254     IO_STACK_LOCATION *pIrpSp;
255
256     pIrpSp = IoGetCurrentIrpStackLocation( Irp);
257
258     __try
259     {
260
261         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
262                       AFS_TRACE_LEVEL_WARNING,
263                       "AFSSetVolumeInfo Entry for FO %p\n", pIrpSp->FileObject);
264
265         AFSCompleteRequest( Irp,
266                             ntStatus);
267
268     }
269     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
270     {
271
272         AFSDbgLogMsg( 0,
273                       0,
274                       "EXCEPTION - AFSSetVolumeInfo\n");
275
276         AFSDumpTraceFilesFnc();
277     }
278
279     return ntStatus;
280 }
281
282 NTSTATUS
283 AFSQueryFsVolumeInfo( IN AFSVolumeInfoCB *VolumeInfo,
284                       IN PFILE_FS_VOLUME_INFORMATION Buffer,
285                       IN OUT PULONG Length)
286
287 {
288
289     NTSTATUS ntStatus = STATUS_BUFFER_TOO_SMALL;
290     ULONG ulCopyLength;
291
292     RtlZeroMemory( Buffer,
293                    *Length);
294
295     if( *Length >= (ULONG)sizeof( FILE_FS_VOLUME_INFORMATION))
296     {
297
298         if( *Length >= (ULONG)(FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel) + (LONG)VolumeInfo->VolumeLabelLength))
299         {
300
301             ulCopyLength = (LONG)VolumeInfo->VolumeLabelLength;
302
303             ntStatus = STATUS_SUCCESS;
304         }
305         else
306         {
307
308             ulCopyLength = *Length - FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel);
309
310             ntStatus = STATUS_BUFFER_OVERFLOW;
311         }
312
313         Buffer->VolumeCreationTime.QuadPart = VolumeInfo->VolumeCreationTime.QuadPart;
314
315         Buffer->VolumeSerialNumber = VolumeInfo->VolumeID;
316
317         Buffer->VolumeLabelLength = VolumeInfo->VolumeLabelLength;
318
319         Buffer->SupportsObjects = FALSE;
320
321         *Length -= FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel);
322
323         if( ulCopyLength > 0)
324         {
325
326             RtlCopyMemory( Buffer->VolumeLabel,
327                            VolumeInfo->VolumeLabel,
328                            ulCopyLength);
329
330             *Length -= ulCopyLength;
331         }
332     }
333
334     return ntStatus;
335 }
336
337 NTSTATUS
338 AFSQueryFsSizeInfo( IN AFSVolumeInfoCB *VolumeInfo,
339                     IN PFILE_FS_SIZE_INFORMATION Buffer,
340                     IN OUT PULONG Length)
341 {
342
343     NTSTATUS ntStatus = STATUS_SUCCESS;
344     AFSFileID FileID;
345     AFSVolumeSizeInfoCB VolumeSizeInfo;
346
347     RtlZeroMemory( Buffer,
348                    *Length);
349
350     if( *Length >= sizeof( FILE_FS_SIZE_INFORMATION))
351     {
352
353         RtlZeroMemory( &FileID,
354                        sizeof(AFSFileID));
355
356         FileID.Cell = VolumeInfo->CellID;
357
358         FileID.Volume = VolumeInfo->VolumeID;
359
360         ntStatus = AFSRetrieveVolumeSizeInformation( NULL,
361                                                      &FileID,
362                                                      &VolumeSizeInfo);
363
364         if ( NT_SUCCESS( ntStatus))
365         {
366
367             Buffer->TotalAllocationUnits.QuadPart = VolumeSizeInfo.TotalAllocationUnits.QuadPart;
368
369             Buffer->AvailableAllocationUnits.QuadPart = VolumeSizeInfo.AvailableAllocationUnits.QuadPart;
370
371             Buffer->SectorsPerAllocationUnit = VolumeSizeInfo.SectorsPerAllocationUnit;
372
373             Buffer->BytesPerSector = VolumeSizeInfo.BytesPerSector;
374
375             *Length -= sizeof( FILE_FS_SIZE_INFORMATION);
376         }
377     }
378     else
379     {
380
381         ntStatus = STATUS_BUFFER_TOO_SMALL;
382     }
383
384     return ntStatus;
385 }
386
387 NTSTATUS
388 AFSQueryFsDeviceInfo( IN AFSVolumeInfoCB *VolumeInfo,
389                       IN PFILE_FS_DEVICE_INFORMATION Buffer,
390                       IN OUT PULONG Length)
391 {
392     NTSTATUS ntStatus = STATUS_SUCCESS;
393
394     RtlZeroMemory( Buffer,
395                    *Length);
396
397     if( *Length >= (LONG)sizeof( FILE_FS_DEVICE_INFORMATION))
398     {
399
400         //
401         // This value is used to determine the return type of
402         // Win32 GetFileType().  Returning FILE_DEVICE_NETWORK_FILE_SYSTEM
403         // results in GetFileType returning FILE_TYPE_UNKNOWN which breaks
404         // msys-based applications.  They treat all files as character
405         // special devices instead of files.
406         //
407
408         Buffer->DeviceType = FILE_DEVICE_DISK;
409
410         Buffer->Characteristics = VolumeInfo->Characteristics;
411
412         *Length -= sizeof( FILE_FS_DEVICE_INFORMATION);
413     }
414     else
415     {
416
417         ntStatus = STATUS_BUFFER_TOO_SMALL;
418     }
419
420     return ntStatus;
421 }
422
423 NTSTATUS
424 AFSQueryFsAttributeInfo( IN AFSVolumeInfoCB *VolumeInfo,
425                          IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
426                          IN OUT PULONG Length)
427 {
428     UNREFERENCED_PARAMETER(VolumeInfo);
429     NTSTATUS ntStatus = STATUS_SUCCESS;
430
431     RtlZeroMemory( Buffer,
432                    *Length);
433
434     if( *Length >= (LONG)(sizeof( FILE_FS_ATTRIBUTE_INFORMATION)))
435     {
436
437         Buffer->FileSystemAttributes = (FILE_CASE_PRESERVED_NAMES |
438                                         FILE_UNICODE_ON_DISK |
439                                         FILE_SUPPORTS_HARD_LINKS |
440                                         FILE_SUPPORTS_REPARSE_POINTS);
441
442         Buffer->MaximumComponentNameLength = 255;
443
444         Buffer->FileSystemNameLength = 18;
445
446         *Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName);
447
448         if( *Length >= 18)
449         {
450
451             RtlCopyMemory( Buffer->FileSystemName,
452                            L"AFSRDRFsd",
453                            18);
454
455             *Length -= 18;
456         }
457         else
458         {
459
460             ntStatus = STATUS_BUFFER_OVERFLOW;
461         }
462     }
463     else
464     {
465
466         ntStatus = STATUS_BUFFER_TOO_SMALL;
467     }
468
469     return ntStatus;
470 }
471
472 NTSTATUS
473 AFSQueryFsFullSizeInfo( IN AFSVolumeInfoCB *VolumeInfo,
474                         IN PFILE_FS_FULL_SIZE_INFORMATION Buffer,
475                         IN OUT PULONG Length)
476 {
477
478     NTSTATUS ntStatus = STATUS_SUCCESS;
479     AFSFileID FileID;
480     AFSVolumeSizeInfoCB VolumeSizeInfo;
481
482     RtlZeroMemory( Buffer,
483                    *Length);
484
485     if( *Length >= sizeof( FILE_FS_FULL_SIZE_INFORMATION))
486     {
487
488         RtlZeroMemory( &FileID,
489                        sizeof(AFSFileID));
490
491         FileID.Cell = VolumeInfo->CellID;
492
493         FileID.Volume = VolumeInfo->VolumeID;
494
495         ntStatus = AFSRetrieveVolumeSizeInformation( NULL,
496                                                      &FileID,
497                                                      &VolumeSizeInfo);
498
499         if ( NT_SUCCESS( ntStatus))
500         {
501
502             Buffer->TotalAllocationUnits.QuadPart = VolumeSizeInfo.TotalAllocationUnits.QuadPart;
503
504             Buffer->CallerAvailableAllocationUnits.QuadPart = VolumeSizeInfo.AvailableAllocationUnits.QuadPart;
505
506             Buffer->ActualAvailableAllocationUnits.QuadPart = VolumeSizeInfo.AvailableAllocationUnits.QuadPart;
507
508             Buffer->SectorsPerAllocationUnit = VolumeSizeInfo.SectorsPerAllocationUnit;
509
510             Buffer->BytesPerSector = VolumeSizeInfo.BytesPerSector;
511
512             *Length -= sizeof( FILE_FS_FULL_SIZE_INFORMATION);
513         }
514     }
515     else
516     {
517
518         ntStatus = STATUS_BUFFER_TOO_SMALL;
519     }
520
521     return ntStatus;
522 }