2.1.5.10.39 FSCTL_SET_ZERO_DATA

The server provides:

  • Open: An Open of a DataStream.

  • InputBufferSize: The byte count of the InputBuffer.

  • InputBuffer: An array of bytes containing a FILE_ZERO_DATA_INFORMATION structure as defined in [MS-FSCC] section 2.3.89.

On completion, the object store MUST return:

  • Status: An NTSTATUS code that specifies the result.

This algorithm uses the following local variables:

  • 64-bit signed integers: StartingOffset, CurrentBytes, CurrentOffset, CurrentFinalByte, NextVcn, CurrentVcn, ClusterCount

  • 64-bit signed integer initialized to -1: LastOffset

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.<150><151>

The operation MUST be failed with STATUS_INVALID_PARAMETER under any of the following conditions:

  • InputBufferSize is less than sizeof(FILE_ZERO_DATA_INFORMATION).

  • InputBuffer.FileOffset is less than 0.

  • InputBuffer.BeyondFinalZero is less than 0.

  • InputBuffer.FileOffset is greater than InputBuffer.BeyondFinalZero.

  • Open.Stream.StreamType is not DataStream.

Pseudocode for the operation is as follows:

  • If Open.File.Volume.IsReadOnly is TRUE, the operation MUST be failed with STATUS_MEDIA_WRITE_PROTECTED.

  • Set StartingOffset equal to InputBuffer.FileOffset.

  • While TRUE:

    • If Open.Stream.IsDeleted is TRUE, the operation MUST be failed with STATUS_FILE_DELETED.

    • If StartingOffset is greater than or equal to Open.Stream.Size, or if StartingOffset is greater than or equal to InputBuffer.BeyondFinalZero, break out of the while loop.

    • Set CurrentBytes to InputBuffer.BeyondFinalZero - StartingOffset.

    • If InputBuffer.BeyondFinalZero is greater than Open.Stream.Size, set CurrentBytes to Open.Stream.Size - StartingOffset.

    • If CurrentBytes is greater than 0x40000000 (1 gigabyte), set CurrentBytes to 0x40000000.

    • If Open.Stream.Oplock is not empty, the object store MUST check for an oplock break according to the algorithm in section 2.1.4.12, with input values as follows:

      • Open equal to this operation's Open

      • Oplock equal to Open.Stream.Oplock

      • Operation equal to "FS_CONTROL"

      • OpParams containing a member ControlCode containing "FSCTL_SET_ZERO_DATA"

    • The object store MUST check for byte range lock conflicts using the algorithm described in section 2.1.4.10 with ByteOffset set to StartingOffset, Length set to CurrentBytes, IsExclusive set to TRUE, LockIntent set to FALSE and Open set to Open. If a conflict is detected, the operation MUST be failed with STATUS_FILE_LOCK_CONFLICT.

    • The object store MUST post a USN change as specified in section 2.1.4.11 with File equal to File, Reason equal to USN_REASON_DATA_OVERWRITE, and FileName equal to Open.Link.Name.

    • The object store MUST note that the file has been modified as specified in section 2.1.4.17 with Open equal to Open.

    • If LastOffset is -1 and StartingOffset is greater than Open.Stream.ValidDataLength:

      • Zero the data in the file according to the algorithm in section 2.1.5.10.39.1, setting the algorithm's parameters as follows:

        • Pass in the current Open.

        • StartingZero equal to Open.Stream.ValidDataLength.

        • ByteCount equal to StartingOffset -Open.Stream.ValidDataLength.

    • EndIf

    • If Open.Stream.IsCompressed is TRUE, or if Open.Stream.IsSparse is TRUE:

      • Set CurrentOffset to StartingOffset & ~(Open.File.Volume.CompressionUnitSize - 1). This aligns the starting point to a compression unit boundary, since when setting zero ranges on a sparse or compressed file, allocation is deleted in compression unit-aligned chunks.

      • Set CurrentFinalByte to InputBuffer.BeyondFinalZero.

      • If CurrentFinalByte is greater than or equal to Open.Stream.Size, set CurrentFinalByte to BlockAlign(Open.Stream.Size, Open.File.Volume.CompressionUnitSize).

      • Set NextVcn and CurrentVcn equal to ClustersFromBytesTruncate(Open.File.Volume, CurrentOffset).

      • While an unallocated range of the file exists starting at NextVcn:

        • NextVcn += The size of the unallocated range in clusters.

        • If (NextVcn * Open.File.Volume.ClusterSize) is greater than or equal to CurrentFinalByte:

          • NextVcn = ClustersFromBytesTruncate(Open.File.Volume, CurrentFinalByte).

          • Break out of the While loop.

        • EndIf

      • EndWhile

      • NextVcn = BlockAlignTruncate(NextVcn, ClustersFromBytes(Open.File.Volume, Open.File.Volume.CompressionUnitSize) ). This aligns NextVcn to a compression unit boundary.

      • If NextVcn != CurrentVcn:

        • ClusterCount = NextVcn - CurrentVcn

        • CurrentVcn += ClusterCount

      • EndIf

      • CurrentOffset = (CurrentVcn * Open.File.Volume.ClusterSize)

      • If CurrentOffset >= CurrentFinalByte, break out of the while loop.

      • If CurrentOffset < StartingOffset:

        • If there are not enough free clusters on the storage media to accommodate a write of Open.File.Volume.CompressionUnitSize bytes, the operation MUST be failed with STATUS_DISK_FULL. The object store is not required to undo any file zeroing or range deallocation that has been performed during the operation.

        • CurrentBytes = Open.File.Volume.CompressionUnitSize - (StartingOffset - CurrentOffset)

        • If (CurrentOffset + Open.File.Volume.CompressionUnitSize) > CurrentFinalByte:

          • CurrentBytes = CurrentFinalByte - StartingOffset

        • EndIf

        • The object store MUST write CurrentBytes zeroes into the stream beginning at CurrentOffset + (StartingOffset & (Open.File.Volume.CompressionUnitSize - 1)).

        • CurrentOffset += (StartingOffset & (Open.File.Volume.CompressionUnitSize - 1))

      • ElseIf CurrentOffset + Open.File.Volume.CompressionUnitSize > CurrentFinalByte:

        • If there are not enough free clusters on the storage media to accommodate a write of Open.File.Volume.CompressionUnitSize bytes, the operation MUST be failed with STATUS_DISK_FULL. The object store is not required to undo any file zeroing or range deallocation that has been performed during the operation.

        • CurrentBytes = CurrentFinalByte & (Open.File.Volume.CompressionUnitSize - 1)

        • The object store MUST write CurrentBytes zeroes into the stream beginning at CurrentOffset.

      • Else

        • CurrentBytes = CurrentFinalByte - CurrentOffset

        • If CurrentBytes is greater than 0x40000000, set CurrentBytes to 0x40000000.

        • CurrentBytes = BlockAlignTruncate(CurrentBytes, Open.File.Volume.CompressionUnitSize)

        • If (CurrentBytes != 0) and (NextVcn <= (CurrentVcn +ClustersFromBytesTruncate(Open.File.Volume, CurrentBytes) - 1)):

          • The object store MUST delete CurrentVcn + ClustersFromBytesTruncate(Open.File.Volume, CurrentBytes) - 1 clusters of allocation from the stream starting with the cluster at NextVcn.

        • EndIf

      • EndIf

    • Else

      • CurrentOffset = StartingOffset

      • CurrentFinalByte = ((CurrentOffset + 0x40000) & -(0x40000))

      • If CurrentFinalByte is greater than or equal to Open.Stream.Size, set CurrentFinalByte to Open.Stream.Size.

      • If CurrentFinalByte is greater than InputBuffer.BeyondFinalZero, set CurrentFinalByte to InputBuffer.BeyondFinalZero.

      • CurrentBytes = CurrentFinalByte - CurrentOffset

      • If CurrentBytes != 0 and CurrentOffset is less than Open.Stream.ValidDataLength:

        • The object store MUST write CurrentBytes zeroes into the stream beginning at CurrentOffset.

      • EndIf

    • EndIf

    • If CurrentOffset + CurrentBytes is greater than Open.Stream.ValidDataLength and StartingOffset is less than Open.Stream.ValidDataLength:

      • The object store MUST set Open.Stream.ValidDataLength equal to CurrentOffset + CurrentBytes.

    • EndIf

    • LastOffset = StartingOffset

    • If CurrentBytes != 0, set StartingOffset equal to CurrentOffset + CurrentBytes.

  • EndWhile

  • If Open.Mode contains either FILE_NO_INTERMEDIATE_BUFFERING or FILE_WRITE_THROUGH, the object store MUST flush all changes to the stream made during this operation, including any file size changes, to stable storage, and MUST fail the operation if the underlying physical storage reports an error flushing the data.

  • Upon successful completion of the operation, the object store MUST return:

    • Status set to STATUS_SUCCESS.