xref: /reactos/drivers/filesystems/ext2/src/volinfo.c (revision 29fa274d)
1 /*************************************************************************
2 *
3 * File: volinfo.c
4 *
5 * Module: Ext2 File System Driver (Kernel mode execution only)
6 *
7 * Description:
8 *	Contains code to handle the various Volume Information related calls.
9 *
10 * Author: Manoj Paul Joseph
11 *
12 *
13 *************************************************************************/
14 
15 
16 
17 #include "ext2fsd.h"
18 
19 
20 
21 
22 // define the file specific bug-check id
23 #define			EXT2_BUG_CHECK_ID				EXT2_FILE_VOL_INFORMATION
24 #define			DEBUG_LEVEL						(DEBUG_TRACE_VOLINFO)
25 
26 
27 /*************************************************************************
28 *
29 * Function: Ext2QueryVolInfo()
30 *
31 * Description:
32 *	The I/O Manager will invoke this routine to handle a
33 *   Query Volume Info IRP
34 *
35 * Expected Interrupt Level (for execution) :
36 *
37 *	???
38 *
39 * Arguments:
40 *
41 *    DeviceObject - Supplies the volume device object where the
42 *                   file exists
43 *
44 *    Irp - Supplies the Irp being processed
45 *
46 *
47 * Return Value:
48 *
49 *    NTSTATUS - The FSD status for the IRP
50 *
51 *************************************************************************/
52 NTSTATUS NTAPI Ext2QueryVolInfo (
53 	IN PDEVICE_OBJECT	DeviceObject,
54 	IN PIRP Irp)
55 {
56 
57 	//	The Return Status
58     NTSTATUS Status = STATUS_SUCCESS;
59 
60 	//	The IRP Stack Location
61 	PIO_STACK_LOCATION	IrpSp = NULL;
62 
63 	//	Volume Control Block
64 	PtrExt2VCB			PtrVCB = NULL;
65 
66 	//	The class of the query IRP
67     FS_INFORMATION_CLASS FsInformationClass;
68 
69 	//	The System Buffer Pointer
70     PVOID Buffer = NULL;
71 
72 	//	Parameter Length
73 	ULONG Length = 0;
74 
75 	//	Bytes copied...
76 	ULONG BytesCopied = 0;
77 
78 	//	Pointers to the Output Information...
79 	PFILE_FS_VOLUME_INFORMATION		PtrVolumeInformation	= NULL;
80 	PFILE_FS_SIZE_INFORMATION		PtrSizeInformation		= NULL;
81 	PFILE_FS_ATTRIBUTE_INFORMATION	PtrAttributeInformation	= NULL;
82 	PFILE_FS_DEVICE_INFORMATION		PtrDeviceInformation	= NULL;
83 	PFILE_FS_FULL_SIZE_INFORMATION	PtrFullSizeInformation	= NULL;
84 
85 
86 	//	Now for the handler code...
87     DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "QueryVolumeInformation IRP", 0);
88 
89     FsRtlEnterFileSystem();
90 
91     try
92 	{
93 		// Getting a pointer to the current I/O stack location
94 		IrpSp = IoGetCurrentIrpStackLocation(Irp);
95 		ASSERT( IrpSp );
96 
97 		//	Getting the VCB and Verifying it...
98 		PtrVCB = ( PtrExt2VCB )( DeviceObject->DeviceExtension );
99 		ASSERT(PtrVCB);
100 		ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB);
101 
102 		//	Getting the query parameters...
103 		Length = IrpSp->Parameters.QueryVolume.Length;
104 		FsInformationClass = IrpSp->Parameters.QueryVolume.FsInformationClass;
105 		Buffer = Irp->AssociatedIrp.SystemBuffer;
106 
107 		//	Now servicing the request depending on the type...
108         switch (FsInformationClass)
109 		{
110         case FileFsVolumeInformation:
111 			DebugTrace(DEBUG_TRACE_MISC,   "Query Volume - FileFsVolumeInformation", 0);
112 			PtrVolumeInformation = Buffer;
113 			PtrVolumeInformation->SupportsObjects = FALSE;
114 			PtrVolumeInformation->VolumeCreationTime.QuadPart = 0;
115 			RtlCopyMemory(
116 				PtrVolumeInformation->VolumeLabel,	//	destination
117 				PtrVCB->PtrVPB->VolumeLabel,		//	source
118 				PtrVCB->PtrVPB->VolumeLabelLength );
119 			PtrVolumeInformation->VolumeLabelLength = PtrVCB->PtrVPB->VolumeLabelLength;
120 			PtrVolumeInformation->VolumeSerialNumber = PtrVCB->PtrVPB->SerialNumber;
121 			BytesCopied = sizeof( FILE_FS_VOLUME_INFORMATION ) + PtrVolumeInformation->VolumeLabelLength - sizeof( WCHAR);
122             break;
123 
124         case FileFsSizeInformation:
125 			DebugTrace(DEBUG_TRACE_MISC,   "Query Volume - FileFsSizeInformation", 0);
126 			PtrSizeInformation = Buffer;
127 			PtrSizeInformation->BytesPerSector = DeviceObject->SectorSize;
128 			PtrSizeInformation->AvailableAllocationUnits.QuadPart	= PtrVCB->FreeBlocksCount;
129 			PtrSizeInformation->SectorsPerAllocationUnit	= ( EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize) / DeviceObject->SectorSize;
130 			PtrSizeInformation->TotalAllocationUnits.QuadPart		= PtrVCB->BlocksCount;
131 			BytesCopied = sizeof( FILE_FS_SIZE_INFORMATION );
132             break;
133 
134         case FileFsDeviceInformation:
135             DebugTrace(DEBUG_TRACE_MISC,   "Query Volume - FileFsDeviceInformation", 0);
136 			PtrDeviceInformation = Buffer;
137 			PtrDeviceInformation->DeviceType = FILE_DEVICE_DISK;
138 			PtrDeviceInformation->Characteristics = FILE_DEVICE_IS_MOUNTED;
139 			BytesCopied = sizeof( FILE_FS_DEVICE_INFORMATION );
140             break;
141 
142         case FileFsAttributeInformation:
143             DebugTrace(DEBUG_TRACE_MISC,   "Query Volume - FileFsAttributeInformation", 0);
144 			PtrAttributeInformation = Buffer;
145 			RtlCopyMemory( PtrAttributeInformation->FileSystemName,	L"EXT2", 10 );
146 			PtrAttributeInformation->FileSystemNameLength = 8;
147 			PtrAttributeInformation->MaximumComponentNameLength = 255;
148 			PtrAttributeInformation->FileSystemAttributes  =
149 				FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
150 			BytesCopied = sizeof( FILE_FS_ATTRIBUTE_INFORMATION ) + 8;
151 
152             break;
153 
154         case FileFsFullSizeInformation:
155             DebugTrace(DEBUG_TRACE_MISC,   "Query Volume - FileFsFullSizeInformation", 0);
156 			PtrFullSizeInformation = Buffer;
157 			PtrFullSizeInformation->BytesPerSector = DeviceObject->SectorSize;
158 			PtrFullSizeInformation->ActualAvailableAllocationUnits.QuadPart	= PtrVCB->FreeBlocksCount;
159 			PtrFullSizeInformation->SectorsPerAllocationUnit	= (EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize) / DeviceObject->SectorSize;
160 			PtrFullSizeInformation->TotalAllocationUnits.QuadPart		= PtrVCB->BlocksCount;
161 			PtrFullSizeInformation->CallerAvailableAllocationUnits.QuadPart = PtrVCB->FreeBlocksCount - PtrVCB->ReservedBlocksCount;
162 			BytesCopied = sizeof( FILE_FS_FULL_SIZE_INFORMATION );
163             break;
164 
165         default:
166             Status = STATUS_INVALID_PARAMETER;
167 			DebugTrace(DEBUG_TRACE_MISC,   "Query Volume - STATUS_INVALID_PARAMETER", 0);
168             break;
169         }
170 
171 		if( IrpSp->Parameters.QueryVolume.Length < BytesCopied )
172 		{
173 			BytesCopied = IrpSp->Parameters.QueryVolume.Length;
174 			Status = STATUS_BUFFER_OVERFLOW;
175 			DebugTrace(DEBUG_TRACE_MISC,   " === Buffer insufficient", 0);
176 		}
177     }
178 	finally
179 	{
180 		Irp->IoStatus.Information = BytesCopied;
181 		Ext2CompleteRequest( Irp, Status );
182 	}
183     FsRtlExitFileSystem();
184 
185     //
186     //  Now return to the caller
187     //
188 
189     return Status;
190 }
191 
192 
193 
194 NTSTATUS NTAPI Ext2SetVolInfo(
195 	IN PDEVICE_OBJECT	DeviceObject,
196 	IN PIRP Irp)
197 {
198 	//	The Return Status
199     NTSTATUS Status = STATUS_SUCCESS;
200 
201 	//	The IRP Stack Location
202 	PIO_STACK_LOCATION	IrpSp = NULL;
203 
204 	//	Volume Control Block
205 	PtrExt2VCB			PtrVCB = NULL;
206 
207 	//	The class of the query IRP
208     FS_INFORMATION_CLASS FsInformationClass;
209 
210 	//	Pointers to the Output Information...
211 	PFILE_FS_LABEL_INFORMATION		PtrVolumeLabelInformation = NULL;
212 
213 	//	Now for the handler code...
214     DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "Set Volume Information IRP", 0);
215 
216     FsRtlEnterFileSystem();
217 
218     try
219 	{
220 		// Getting a pointer to the current I/O stack location
221 		IrpSp = IoGetCurrentIrpStackLocation(Irp);
222 		ASSERT( IrpSp );
223 
224 		//	Getting the VCB and Verifying it...
225 		PtrVCB = ( PtrExt2VCB )( DeviceObject->DeviceExtension );
226 		AssertVCB(PtrVCB);
227 
228 		//	Getting the query parameters...
229 		//	Length = IrpSp->Parameters.SetVolume.Length;
230 #ifdef _GNU_NTIFS_
231 		FsInformationClass = ((PEXTENDED_IO_STACK_LOCATION)IrpSp)->Parameters.SetVolume.FsInformationClass;
232 #else
233 		FsInformationClass = IrpSp->Parameters.SetVolume.FsInformationClass;
234 #endif
235 
236 		//	Now servicing the request depending on the type...
237         switch (FsInformationClass)
238 		{
239 		case FileFsLabelInformation:
240 			PtrVolumeLabelInformation = Irp->AssociatedIrp.SystemBuffer;
241 			if( PtrVolumeLabelInformation->VolumeLabelLength > MAXIMUM_VOLUME_LABEL_LENGTH ||	//	This is the maximum that the
242 																								//	VPB can take...
243 				PtrVolumeLabelInformation->VolumeLabelLength > 32 )	//	this is the maximum that Ext2 FS can support..
244 			{
245 				try_return( Status = STATUS_INVALID_VOLUME_LABEL );
246 			}
247 
248 			PtrVCB->PtrVPB->VolumeLabelLength = (USHORT)PtrVolumeLabelInformation->VolumeLabelLength ;
249 			RtlCopyMemory(
250 				PtrVCB->PtrVPB->VolumeLabel,		//	destination
251 				PtrVolumeLabelInformation->VolumeLabel,	//	source
252 				PtrVolumeLabelInformation->VolumeLabelLength );
253 
254 			{
255 				//	Now update the volume's super block...
256 
257 				PEXT2_SUPER_BLOCK	PtrSuperBlock = NULL;
258 				PBCB				PtrSuperBlockBCB = NULL;
259 				LARGE_INTEGER		VolumeByteOffset;
260 				ULONG				LogicalBlockSize = 0;
261 				ULONG				NumberOfBytesToRead = 0;
262 
263 
264 				//	Reading in the super block...
265 				VolumeByteOffset.QuadPart = 1024;
266 
267 				LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
268 
269 				//	THis shouldn't be more than a block in size...
270 				NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize );
271 
272 				if( !CcPinRead( PtrVCB->PtrStreamFileObject,
273 					   &VolumeByteOffset,
274 					   NumberOfBytesToRead,
275 					   TRUE,
276 					   &PtrSuperBlockBCB,
277 					   (PVOID*)&PtrSuperBlock ) )
278 				{
279 					DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
280 					try_return( Status = STATUS_INVALID_VOLUME_LABEL );
281 				}
282 				else
283 				{
284 					ULONG i;
285 					for( i = 0; i < (PtrVolumeLabelInformation->VolumeLabelLength/2) ; i++ )
286 					{
287 						PtrSuperBlock->s_volume_name[i] =
288 							(char) PtrVolumeLabelInformation->VolumeLabel[i] ;
289 						if( PtrSuperBlock->s_volume_name[i] == 0 )
290 						{
291 							break;
292 						}
293 					}
294 					if( i < 16 )
295 					{
296 						PtrSuperBlock->s_volume_name[i] = 0;
297 					}
298 
299 
300 					CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL );
301 
302 					//	Not saving and flushing this information synchronously...
303 					//	This is not a critical information..
304 					//	Settling for lazy writing of this information
305 
306 					//	Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject );
307 
308 					if( PtrSuperBlockBCB )
309 					{
310 						CcUnpinData( PtrSuperBlockBCB );
311 						PtrSuperBlockBCB = NULL;
312 					}
313 
314 				}
315 			}
316 
317 			break;
318         default:
319             Status = STATUS_INVALID_PARAMETER;
320 			DebugTrace(DEBUG_TRACE_MISC,   "Query Volume - STATUS_INVALID_PARAMETER", 0);
321             break;
322 		}
323 
324 		try_exit: NOTHING;
325     }
326 	finally
327 	{
328 		Irp->IoStatus.Information = 0;
329 		Ext2CompleteRequest( Irp, Status );
330 	}
331     FsRtlExitFileSystem();
332 
333     //
334     //  Now return to the caller
335     //
336 
337     return Status;
338 }
339