2.1.5.5 Server Requests Closing an Open

The server provides:

  • Open: The Open that the application is to close.

On completion, the object store MUST return:

  • Status: An NTSTATUS code that specifies the result.

This operation uses the following local variables:

  • Boolean values (initialized to FALSE): LinkDeleted, StreamDeleted, FileDeleted, PostUsnClose

The Open provided by the application MUST be removed from Open.File.OpenList.

Pseudocode for the operation is as follows:

  • Phase 1 - Delete on Close:

  • If Open.Mode.FILE_DELETE_ON_CLOSE is TRUE:

    • If Open.Stream.Name is empty:

      • If (Open.Stream.StreamType is DataStream or Open.File.DirectoryList is empty), then Open.Link.IsDeleted MUST be set to TRUE.

    • Else:

      • Open.Stream.IsDeleted MUST be set to TRUE.

    • EndIf

  • EndIf

  • Phase 2 -Stream Deletion:

  • If Open.Stream.IsDeleted is TRUE and Open.File.OpenList does not contain any Opens on Open.Stream (this is a close of the last Open to a stream that has been marked deleted), then:

    • Open.Stream MUST be removed from Open.File.StreamList.

    • If Open.Stream.IsSparse is TRUE, and there does not exist an ExistingStream in Open.File.StreamList such that ExistingStream.IsSparse is TRUE:

      • The object store MUST set Open.File.FileAttributes.FILE_ATTRIBUTE_SPARSE_FILE to FALSE, indicating that no streams of the file are sparse.

      • 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_STREAM_CHANGE | USN_REASON_BASIC_INFO_CHANGE, and FileName equal to Open.Link.Name.

    • Else:

      • 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_STREAM_CHANGE, and FileName equal to Open.Link.Name.

    • EndIf

    • StreamDeleted MUST be set to TRUE.

    • PostUsnClose MUST be set to TRUE.

  • EndIf

  • Phase 3 - File Deletion:

  • If Open.Link.IsDeleted is TRUE and there does not exist an ExistingOpen in Open.File.OpenList that has ExistingOpen.Link equal to Open.Link:

    • Remove Open.Link from Open.File.LinkList.

    • Remove Open.Link from Open.Link.ParentFile.DirectoryList.

    • Set LinkDeleted to TRUE.

    • If Open.File.LinkList is empty:

      • Set FileDeleted to TRUE.

    • EndIf

  • EndIf

  • If LinkDeleted is FALSE:

    • The object store MUST update the duplicated information as specified in section 2.1.4.18 with Link equal to Link.

  • EndIf

  • Phase 4 - Truncate on Close:

  • Set AllocationClusters to ClustersFromBytes(Open.File.Volume, Open.Stream.AllocationSize).

  • Set FileClusters to ClustersFromBytes(Open.File.Volume, Open.Stream.FileSize).

  • If AllocationClusters > FileClusters:

    • This file has excess allocation. The object store SHOULD free (AllocationClusters - FileClusters) clusters of allocation from the end of the stream, and set Open.Stream.AllocationSize to FileClusters * Open.File.Volume.ClusterSize.

    • If the object store supports Open.File.Volume.ClusterRefcount, the object store MUST decrement the reference count of each cluster that is pointed to by the EXTENTS in the Open.Stream.ExtentList that were freed by the previous step. If the corresponding cluster's reference count goes to zero, the cluster MUST be freed.

  • EndIf

  • Phase 5 -- Directory Change Notification:

  • When a directory Open with outstanding directory change notification requests is closed, these requests are completed using the algorithm below.

  • If Open.Stream.StreamType is DirectoryStream:

    • For each ChangeNotifyEntry in Volume.ChangeNotifyList where ChangeNotifyEntry.OpenedDirectory is equal to Open then the following actions MUST be taken:

      • Remove ChangeNotifyEntry from Volume.ChangeNotifyList.

      • Complete the ChangeNotify operation with status STATUS_NOTIFY_CLEANUP.

    • EndFor

  • EndIf

  • If Open.Link is deleted, a directory change notification on Open.Link.ParentFile MUST be issued. Pseudocode for these notifications is as follows:

    • If LinkDeleted is TRUE:

      • Set Action to FILE_ACTION_REMOVED.

      • If Open.Stream.StreamType is DirectoryStream:

        • Set FilterMatch to FILE_NOTIFY_CHANGE_DIR_NAME.

      • Else:

        • Set FilterMatch to FILE_NOTIFY_CHANGE_FILE_NAME.

      • EndIf

      • Send directory change notification as specified in section 2.1.4.1 with Volume equal to Open.File.Volume, Action equal to Action, FilterMatch equal to FilterMatch, and FileName equal to Open.FileName.

    • EndIf

  • If Open.Stream was deleted, then the stream deletion change notification MUST be issued. Pseudocode for this notification is as follows:

    • If StreamDeleted is TRUE:

      • Set Action to FILE_ACTION_REMOVED_STREAM.

      • Set FilterMatch to FILE_NOTIFY_CHANGE_STREAM_NAME.

      • Send directory change notification as specified in section 2.1.4.1 with Volume equal to Open.File.Volume, Action equal to Action, FilterMatch equal to FilterMatch and FileName equal to Open.FileName + ":" + Stream.Name.

    • EndIf

  • If Open.File has had other changes that were not notified, a directory change notification reflecting those changes MUST be issued. Pseudocode for this notification is as follows:

    • Set FilterMatch to Open.File.PendingNotifications.

    • If FilterMatch is nonzero:

      • Set Action to FILE_ACTION_MODIFIED.

      • Send directory change notification as specified in section 2.1.4.1 with Volume equal to Open.File.Volume, Action equal to Action, FilterMatch equal to FilterMatch and FileName equal to Open.FileName.

      • Set Open.File.PendingNotifications to zero.

    • EndIf

  • If this is an Open to a named data Stream (Open.Stream.StreamType is DataStream and Open.Stream.Name is not empty) and there have been changes to it that weren't previously notified, a directory change notification reflecting those changes MUST be issued. Pseudocode for this notification is as follows:

    • Set FilterMatch to Open.Stream.PendingNotifications.

    • If FilterMatch is nonzero:

      • Set Action to FILE_ACTION_MODIFIED_STREAM.

      • Send directory change notification as specified in section 2.1.4.1 with Volume equal to Open.File.Volume, Action equal to Action, FilterMatch equal to FilterMatch and FileName equal to Open.FileName+ ":" + Stream.Name.

      • Set Open.Stream.PendingNotifications to zero.

    • EndIf

    • If LinkDeleted is TRUE:

      • If FileDeleted is FALSE:

        • Post a USN change as specified in section 2.1.4.11 with File equal to File, Reason equal to USN_REASON_HARD_LINK_CHANGE, and FileName equal to Open.Link.Name.

        • Set PostUsnClose to TRUE.

      • Else:

        • Post a USN change as specified in section 2.1.4.11 with File equal to File, Reason equal to USN_REASON_FILE_DELETE | USN_REASON_CLOSE, and FileName equal to Open.Link.Name.

      • EndIf

    • EndIf

  • If FileDeleted is TRUE and Open.File.ObjectId is not empty:

    • The object store MUST construct a FILE_OBJECTID_INFORMATION structure (as specified in [MS-FSCC] section 2.4.31.1) ObjectIdInfo as follows:

      • ObjectIdInfo.FileReference set to zero.

      • ObjectIdInfo.ObjectId set to Open.File.ObjectId.

      • ObjectIdInfo.BirthVolumeId set to Open.File.BirthVolumeId.

      • ObjectIdInfo.BirthObjectId set to Open.File.BirthObjectId.

      • ObjectIdInfo.DomainId set to Open.File.DomainId.

    • Send directory change notification as specified in section 2.1.4.1, with Volume equal to Open.File.Volume, Action equal to FILE_ACTION_REMOVED_BY_DELETE, FilterMatch equal to FILE_NOTIFY_CHANGE_FILE_NAME, FileName equal to "\$Extend\$ObjId", NotifyData equal to ObjectIdInfo, and NotifyDataLength equal to sizeof(FILE_OBJECTID_INFORMATION).

  • EndIf

  • Phase 6 -- USN Journal:

  • If PostUsnClose is TRUE:

    • Post a USN change as specified in section 2.1.4.11 with File equal to File, Reason equal to USN_REASON_CLOSE, and FileName equal to Open.Link.Name.

  • EndIf

  • Phase 7 -- Tunnel Cache:

  • If LinkDeleted is TRUE, then a new TunnelCacheEntry object TunnelCacheEntry MUST be constructed and added to the Open.File.Volume.TunnelCacheList as follows:

    • TunnelCacheEntry.EntryTime MUST be set to the current time.

    • TunnelCacheEntry.ParentFile MUST be set to Open.Link.ParentFile.

    • TunnelCacheEntry.FileName MUST be set to Open.Link.Name.

    • TunnelCacheEntry.FileShortName MUST be set to Open.Link.ShortName.

    • If Open.FileName matches Open.Link.ShortName then TunnelCacheEntry.KeyByShortName MUST be set to TRUE, else TunnelCacheEntry.KeyByShortName MUST be set to FALSE.

    • TunnelCacheEntry.FileCreationTime MUST be set to Open.File.CreationTime.

    • TunnelCacheEntry. ObjectIdInfo MUST be set to Open.File.ObjectId.

    • TunnelCacheEntry.ObjectIdInfo.BirthVolumeId MUST be set to Open.File.BirthVolumeId.

    • TunnelCacheEntry.ObjectIdInfo.BirthObjectId MUST be set to Open.File.BirthObjectId.

    • TunnelCacheEntry.ObjectIdInfo.DomainId MUST be set to Open.File.DomainId.

  • EndIf

  • If Open.File.FileType is DirectoryFile and LinkDeleted is TRUE, then Open.File MUST have every TunnelCacheEntry associated with it invalidated:

    • For every ExistingTunnelCacheEntry in Open.File.Volume.TunnelCacheList:

      • If ExistingTunnelCacheEntry.ParentFile matches Open.File, then ExistingTunnelCacheEntry MUST be removed from Open.File.Volume.TunnelCacheList.

    • EndFor

  • EndIf

  • Phase 8 -- Oplock Cleanup:

  • 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 "CLOSE"

    • OpParams empty

  • If LinkDeleted is TRUE or FileDeleted is TRUE:

    • If the Oplock member of the DirectoryStream in Open.Link.ParentFile.StreamList (hereinafter referred to as ParentOplock) is not empty, the object store MUST check for an oplock break on the parent 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 ParentOplock

      • Operation equal to "CLOSE"

      • Flags equal to "PARENT_OBJECT"

  • EndIf

  • Phase 9 -- Byte Range Locks:

  • All elements from Open.Stream.ByteRangeLockList where ByteRangeLock.OwnerOpen == Open MUST be removed.

  • Phase 10 - Update Timestamps

  • If LinkDeleted is TRUE and FileDeleted is FALSE:

    • If Open.UserSetChangeTime is FALSE, update Open.File.LastChangeTime to the current time.

    • Set Open.File.FileAttributes.FILE_ATTRIBUTE_ARCHIVE to TRUE.

  • EndIf

  • If Open.GrantedAccess.FILE_EXECUTE is TRUE and Open.UserSetAccessTime is FALSE:

    • Update Open.File.LastAccessTime to the current time.

  • EndIf

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

    • Status set to STATUS_SUCCESS.