2.1.5.9.18 FSCTL_QUERY_ALLOCATED_RANGES
The server provides:
-
Open: An Open of a DataFile.
-
InputBuffer: An array of bytes containing a single FILE_ALLOCATED_RANGE_BUFFER structure indicating the range to query for allocation, as specified in [MS-FSCC] section 2.3.32.
-
InputBufferSize: The number of bytes in InputBuffer.
-
OutputBufferSize: The maximum number of bytes to return in OutputBuffer.
On completion, the object store MUST return:
-
Status: An NTSTATUS code that specifies the result.
-
OutputBuffer: An array of bytes that will return an array of zero or more FILE_ALLOCATED_RANGE_BUFFER structures as specified in [MS-FSCC] section 2.3.32.
-
BytesReturned: The number of bytes returned in OutputBuffer.
This operation uses the following local variables:
-
32-bit unsigned integer indicating the index of the next FILE_ALLOCATED_RANGE_BUFFER to fill in OutputBuffer (initialized to 0): OutputBufferIndex.
-
64-bit unsigned integer QueryStart: Is initialized to ClustersFromBytesTruncate(Open.File.Volume, InputBuffer.FileOffset). This is the cluster containing the first byte of the queried range.
-
64-bit unsigned integer QueryNext: Is initialized to ClustersFromBytesTruncate(Open.File.Volume, (InputBuffer.FileOffset + InputBuffer.Length - 1) ) + 1. This is the cluster following the last cluster of the range.
-
64-bit unsigned integers (initialized to 0): ExtentFirstVcn, ExtentNextVcn, RangeFirstVcn, RangeNextVcn
-
Boolean values (initialized to FALSE): FoundRangeStart, FoundRangeEnd
-
Pointer to an EXTENTS element (initialized to NULL): Extent
-
FILE_ALLOCATED_RANGE_BUFFER (initialized to zeros):Range
Support for this operation is optional. If the object store does not implement this functionality, the operation MUST be failed with STATUS_INVALID_DEVICE_REQUEST.<68>
Pseudocode for the operation is as follows:
-
If Open.Stream.StreamType is DirectoryStream, the operation MUST be failed with STATUS_INVALID_PARAMETER.
-
If InputBufferSize is less than sizeof(FILE_ALLOCATED_RANGE_BUFFER), the operation MUST be failed with STATUS_INVALID_PARAMETER.
-
If (InputBuffer.FileOffset < 0) or (InputBuffer.Length < 0) or (InputBuffer.Length > MAXLONGLONG - InputBuffer.FileOffset), the operation MUST be failed with STATUS_INVALID_PARAMETER. If InputBuffer.Length is 0:
-
Set BytesReturned to 0.
-
Return STATUS_SUCCESS.
-
-
EndIf
-
If OutputBufferSize < sizeof(FILE_ALLOCATED_RANGE_BUFFER), the operation MUST be failed with STATUS_BUFFER_TOO_SMALL.
-
If Open.Stream.IsSparse is FALSE:
-
Set OutputBuffer.FileOffset to InputBuffer.FileOffset.
-
Set OutputBuffer.Length to InputBuffer.Length.
-
Set BytesReturned to sizeof(FILE_ALLOCATED_RANGE_BUFFER).
-
Return STATUS_SUCCESS.
-
-
Else:
-
For sparse files, return a list of contiguous allocated ranges within the requested range. Contiguous allocated ranges in a sparse file might be fragmented on disk, therefore it is necessary to loop through the EXTENTS on this stream, coalescing the adjacent allocated EXTENTS into a single FILE_ALLOCATED_RANGE_BUFFER entry.
-
Set Status to STATUS_SUCCESS.
-
Set BytesReturned to 0.
-
For each Extent in Open.Stream.ExtentList:
-
Set ExtentFirstVcn to ExtentNextVcn.
-
Set ExtentNextVcn to Extent.NextVcn.
-
If Extent.Lcn != 0xffffffffffffffff, meaning Extent is allocated (not a sparse hole):
-
If FoundRangeStart is FALSE:
-
If QueryStart < ExtentFirstVcn:
-
Set FoundRangeStart to TRUE.
-
Set RangeFirstVcn to ExtentFirstVcn.
-
-
Else If ExtentFirstVcn <= QueryStart and QueryStart < ExtentNextVcn:
-
Set FoundRangeStart to TRUE.
-
Set RangeFirstVcn to QueryStart.
-
-
EndIf
-
-
EndIf
-
If FoundRangeStart is TRUE:
-
If QueryNext <= ExtentFirstVcn:
-
Break out of the For loop.
-
-
Else If ExtentFirstVcn < QueryNext and QueryNext <= ExtentNextVcn:
-
Set FoundRangeEnd to TRUE.
-
Set RangeNextVcn to QueryNext.
-
-
Else (ExtentNextVcn < QueryNext):
-
Set FoundRangeEnd to FALSE.
-
Set RangeNextVcn to ExtentNextVcn.
-
-
EndIf
-
-
EndIf
-
-
Else If FoundRangeStart is TRUE:
-
Set FoundRangeEnd to TRUE.
-
-
EndIf
-
If FoundRangeEnd is TRUE:
-
Set FoundRangeStart to FALSE and FoundRangeEnd to FALSE.
-
Add Range to OutputBuffer as follows:
-
Set Range.FileOffset to RangeFirstVcn * Open.File.Volume.ClusterSize.
-
Set Range.Length to (RangeNextVcn - RangeFirstVcn) * Open.File.Volume.ClusterSize.
-
If OutputBufferSize < ((OutputBufferIndex + 1) * sizeof(FILE_ALLOCATED_RANGE_BUFFER) ) then:
-
Set RangeFirstVcn to 0 and RangeNextVcn to 0.
-
Set Status to STATUS_BUFFER_OVERFLOW.
-
Break out of the For loop.
-
-
EndIf
-
Copy Range to OutputBuffer[OutputBufferIndex].
-
Increment OutputBufferIndex by 1.
-
Set RangeFirstVcn to 0 and RangeNextVcn to 0.
-
-
-
EndIf
-
-
EndFor
-
If RangeNextVcn is not 0:
-
If OutputBufferSize < ((OutputBufferIndex + 1) * sizeof(FILE_ALLOCATED_RANGE_BUFFER)) then:
-
Set Status to STATUS_BUFFER_OVERFLOW.
-
-
Else add Range to OutputBuffer as follows:
-
Set Range.FileOffset to RangeFirstVcn * Open.File.Volume.ClusterSize.
-
Set Range.Length to (RangeNextVcn - RangeFirstVcn) * Open.File.Volume.ClusterSize.
-
Copy Range to OutputBuffer[OutputBufferIndex].
-
Increment OutputBufferIndex by 1.
-
-
EndIf
-
-
EndIf
-
Bias the first and the last returned ranges so that they match the offset/length passed in, using the following algorithm:
-
If OutputBufferIndex > 0:
-
If OutputBuffer[0].FileOffset < InputBuffer.FileOffset:
-
Set OutputBuffer[0].Length to OutputBuffer[0].Length - (InputBuffer.FileOffset -OutputBuffer[0].FileOffset).
-
Set OutputBuffer[0].FileOffset to InputBuffer.FileOffset.
-
-
EndIf
-
If (OutputBuffer[OutputBufferIndex - 1].FileOffset + OutputBuffer[OutputBufferIndex - 1].Length) > (InputBuffer.FileOffset + InputBuffer.Length):
-
Set OutputBuffer[OutputBufferIndex - 1].Length to InputBuffer.FileOffset + InputBuffer.Length - OutputBuffer[OutputBufferIndex - 1].FileOffset.
-
-
EndIf
-
-
EndIf
-
-
Endif
-
Upon successful completion of the operation, the object store MUST return:
-
BytesReturned set to OutputBufferIndex * sizeof(FILE_ALLOCATED_RANGE_BUFFER).
-
Status set to STATUS_SUCCESS.
-