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