/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: FsObject.sg // using Microsoft.Singularity.Channels; using Microsoft.Singularity.Directory; namespace Microsoft.Singularity.Services.Fat.Fs { /// Base class for file system objects. /// Provides reference counting functionality and support for /// common directory and file operations, such as updating the /// last write time. /// internal abstract class FsObject { private Directory parent; private int shortEntryOffset; private int refcnt; public string cachedName = null; // Debugging info public string cachedPathName = null; // Debugging info /// /// Create an FsObject with a reference count of 1. /// [ Microsoft.Contracts.NotDelayed ] internal FsObject(Directory! parent, int shortEntryOffset) requires shortEntryOffset > 0; { this.parent = parent; this.shortEntryOffset = shortEntryOffset; this.refcnt = 1; } internal FsObject() { this.refcnt = 0; this.shortEntryOffset = -1; this.parent = null; } [ Microsoft.Contracts.Pure ] internal bool HasParent { get { return parent != null; } } [ Microsoft.Contracts.Pure ] internal bool HasNoReferences { get { return this.refcnt == 0; } } [ Microsoft.Contracts.Pure ] internal bool HasOneReference { get { return this.refcnt == 1; } } [ Microsoft.Contracts.Pure ] internal int ShortEntryOffset { get { return this.shortEntryOffset; } } abstract internal int FirstCluster { get; } private void PopulateCachedName() requires this.cachedName == null; ensures this.cachedName != null; { if (parent != null) { char[]! in ExHeap v = parent.GetName(this.shortEntryOffset); this.cachedName = Bitter.ToString2(v); delete v; } else { this.cachedName = "/"; } } internal string Name { get { if (cachedName == null) { PopulateCachedName(); } return cachedName; } } internal bool GetShortDirectoryEntry(out DirectoryEntry de) { if (this.parent != null) { this.parent.GetShortDirectoryEntry(this.shortEntryOffset, out de); } de = new DirectoryEntry(); return false; } private void PopulateCachedPathName() requires this.cachedPathName == null; ensures this.cachedPathName != null; { if (parent != null) { if (this.parent.FullPathName == "/") { this.cachedPathName = this.parent.FullPathName + this.Name; } else { this.cachedPathName = this.parent.FullPathName + "/" + this.Name; } } else { this.cachedPathName = this.Name; } } internal string FullPathName { get { if (cachedPathName == null) { PopulateCachedPathName(); } return cachedPathName; } } internal void UpdateLastWriteTime() { if (parent != null && !FatVolume.IsReadOnly) { parent.UpdateLastWriteTime(this.shortEntryOffset); } } internal void UpdateLastAccessTime() { if (parent != null && !FatVolume.IsReadOnly) { parent.UpdateLastAccessTime(this.shortEntryOffset); } } /// Update the file size field in the /// directory entry associated with a file object. This /// method also updates the last access and last update /// fields. internal void UpdateFileSize(uint fileBytes) { if (parent != null && !FatVolume.IsReadOnly) { DebugStub.Assert(fileBytes != 0); // TEMPORARY parent.UpdateFileSize(this.shortEntryOffset, fileBytes); } } internal void SetMutableAttributes(byte newAttributes) requires (newAttributes & ~DirectoryEntry.AttributeMutable) == 0; { if (parent != null && !FatVolume.IsReadOnly) { parent.SetMutableAttributes(this.shortEntryOffset, newAttributes); } } internal byte GetMutableAttributes() { if (parent != null) { return parent.GetMutableAttributes(); } return 0; } internal void GetAttributes(out NodeType nodeType, out uint sizeBytes) { if (parent == null) { nodeType = NodeType.Directory; sizeBytes = 0; } else { parent.GetAttributes(this.shortEntryOffset, out nodeType, out sizeBytes); } } /// Increment reference count by 1 internal void AddRef() { this.refcnt++; } /// Decrement reference count by 1 internal void Release() { this.refcnt--; } internal void CloseInstance() { if (parent != null) { parent.CloseOpenFsObject(this); } } } }