// Private #region Methods private static void Create(IBlockIO deviceIO, string volumeName, Geometry geometry, Guid volumeID, PrivateKey signatureKey) { // Write the Partition Cluster FileSystemHeaderCluster fileSystemHeaderCluster = new FileSystemHeaderCluster(deviceIO.BlockSizeBytes, volumeID); fileSystemHeaderCluster.BytesPerDataCluster = geometry.BytesPerCluster; fileSystemHeaderCluster.ClustersPerTrack = geometry.ClustersPerTrack; fileSystemHeaderCluster.DataClustersPerTrack = geometry.DataClustersPerTrack; fileSystemHeaderCluster.TrackCount = geometry.TrackCount; fileSystemHeaderCluster.VolumeName = volumeName; byte[] data = new byte[fileSystemHeaderCluster.ClusterSizeBytes]; fileSystemHeaderCluster.Save(data, 0, signatureKey); deviceIO.Write(0, data, 0, data.Length); // Cluster State Table int entryCount = geometry.ClustersPerTrack * geometry.TrackCount; int clusterCount = (entryCount + ClusterStatesCluster.CalculateElementsPerCluster(geometry.BytesPerCluster) - 1) / ClusterStatesCluster.CalculateElementsPerCluster(geometry.BytesPerCluster); ClusterTable <ClusterState> clusterStateTable = new ClusterTable <ClusterState>( Enumerable.Range(0, clusterCount), sizeof(ClusterState), (address) => new ClusterStatesCluster(address, geometry.BytesPerCluster, volumeID)); // Next Cluster Address Table entryCount = geometry.DataClustersPerTrack * geometry.TrackCount; clusterCount = (entryCount + Int32ArrayCluster.CalculateElementsPerCluster(geometry.BytesPerCluster) - 1) / Int32ArrayCluster.CalculateElementsPerCluster(geometry.BytesPerCluster); ClusterTable <int> nextClusterAddressTable = new ClusterTable <int>( Enumerable.Range(clusterStateTable.ClusterAddresses.Last() + 1, clusterCount), sizeof(int), (address) => new Int32ArrayCluster(address, geometry.BytesPerCluster, volumeID, ClusterType.NextClusterAddressTable)); // Bytes Used Table ClusterTable <int> bytesUsedTable = new ClusterTable <int>( Enumerable.Range(nextClusterAddressTable.ClusterAddresses.Last() + 1, clusterCount), sizeof(int), (address) => new Int32ArrayCluster(address, geometry.BytesPerCluster, volumeID, ClusterType.BytesUsedTable)); entryCount = geometry.ClustersPerTrack * geometry.TrackCount; clusterCount = (entryCount + VerifyTimesCluster.CalculateElementsPerCluster(geometry.BytesPerCluster) - 1) / VerifyTimesCluster.CalculateElementsPerCluster(geometry.BytesPerCluster); // Verify Time Table ClusterTable <DateTime> verifyTimeTable = new ClusterTable <DateTime>( Enumerable.Range(bytesUsedTable.ClusterAddresses.Last() + 1, clusterCount), sizeof(long), (address) => new VerifyTimesCluster(address, geometry.BytesPerCluster, volumeID)); // Directory Table MutableObjectClusterTable <Directory> directoryTable = new MutableObjectClusterTable <Directory>( new int[] { verifyTimeTable.ClusterAddresses.Last() + 1 }, Directory.StorageLength, (address) => Directory.CreateArrayCluster(address)); // File Table MutableObjectClusterTable <File> fileTable = new MutableObjectClusterTable <File>( new int[] { directoryTable.ClusterAddresses.Last() + 1 }, File.StorageLength, (address) => File.CreateArrayCluster(address)); // Access Rules Table ClusterTable <SrfsAccessRule> accessRules = new ClusterTable <SrfsAccessRule>( new int[] { fileTable.ClusterAddresses.Last() + 1 }, SrfsAccessRule.StorageLength + sizeof(bool), (address) => SrfsAccessRule.CreateArrayCluster(address)); // Audit Rules Table ClusterTable <SrfsAuditRule> auditRules = new ClusterTable <SrfsAuditRule>( new int[] { accessRules.ClusterAddresses.Last() + 1 }, SrfsAuditRule.StorageLength + sizeof(bool), (address) => SrfsAuditRule.CreateArrayCluster(address)); // Initialize the tables int nDataClusters = geometry.DataClustersPerTrack * geometry.TrackCount; int nParityClusters = geometry.ParityClustersPerTrack * geometry.TrackCount; for (int i = 0; i < nDataClusters; i++) { clusterStateTable[i] = ClusterState.Data | ClusterState.Unwritten; } for (int i = nDataClusters; i < nDataClusters + nParityClusters; i++) { clusterStateTable[i] = ClusterState.Parity | ClusterState.Unwritten; } for (int i = nDataClusters + nParityClusters; i < clusterStateTable.Count; i++) { clusterStateTable[i] = ClusterState.Null; } for (int i = 0; i < clusterStateTable.Count; i++) { clusterStateTable[i] = ClusterState.None; } for (int i = 0; i < nextClusterAddressTable.Count; i++) { nextClusterAddressTable[i] = Constants.NoAddress; } for (int i = 0; i < bytesUsedTable.Count; i++) { bytesUsedTable[i] = 0; } for (int i = 0; i < verifyTimeTable.Count; i++) { verifyTimeTable[i] = DateTime.MinValue; } for (int i = 0; i < directoryTable.Count; i++) { directoryTable[i] = null; } for (int i = 0; i < fileTable.Count; i++) { fileTable[i] = null; } for (int i = 0; i < accessRules.Count; i++) { accessRules[i] = null; } for (int i = 0; i < auditRules.Count; i++) { auditRules[i] = null; } // Update the cluster state and next cluster address tables foreach (var t in new IEnumerable <int>[] { clusterStateTable.ClusterAddresses, nextClusterAddressTable.ClusterAddresses, bytesUsedTable.ClusterAddresses, verifyTimeTable.ClusterAddresses, directoryTable.ClusterAddresses, fileTable.ClusterAddresses, accessRules.ClusterAddresses, auditRules.ClusterAddresses }) { foreach (var n in t) { clusterStateTable[n] = ClusterState.System | ClusterState.Used; nextClusterAddressTable[n] = n + 1; } nextClusterAddressTable[t.Last()] = Constants.NoAddress; } // Create the root directory Directory dir = new Directory(0, ""); dir.Attributes = System.IO.FileAttributes.Directory; dir.ParentID = Constants.NoID; dir.Owner = WindowsIdentity.GetCurrent().User; dir.Group = WindowsIdentity.GetCurrent().User; directoryTable[0] = dir; accessRules[0] = new SrfsAccessRule(dir, new FileSystemAccessRule(WindowsIdentity.GetCurrent().User, FileSystemRights.FullControl, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow)); SimpleClusterIO clusterIO = new SimpleClusterIO(deviceIO, fileSystemHeaderCluster.BytesPerDataCluster); clusterStateTable.Flush(clusterIO); nextClusterAddressTable.Flush(clusterIO); bytesUsedTable.Flush(clusterIO); verifyTimeTable.Flush(clusterIO); directoryTable.Flush(clusterIO); fileTable.Flush(clusterIO); accessRules.Flush(clusterIO); auditRules.Flush(clusterIO); }
// Public #region Construction / Destruction /// <summary> /// Open a file system. /// </summary> /// <param name="partition"></param> /// <param name="signatureKeys"></param> /// <param name="decryptionKey"></param> /// <param name="options"></param> public FileSystem(IBlockIO device, Dictionary <KeyThumbprint, PublicKey> signatureKeys, PrivateKey decryptionKey, Options options) { _keys = new Dictionary <Signature, CngKey>(); foreach (var p in _keys) { _keys.Add(p.Key, p.Value); } _decryptionKey = decryptionKey; _options = options; _readOnly = true; // Create IO Devices _deviceIO = device; _clusterIO = new FileSystemClusterIO(this, _deviceIO); _disposeDeviceIO = true; // Initialize Indices _freeClusterSearchStart = 0; _nextEntryID = 0; _nextDirectoryIndex = 0; _nextFileIndex = 0; _nextAccessRuleIndex = 0; _nextAuditRuleIndex = 0; // Create Indexes _directoryIndex = new Dictionary <int, int>(); _containedDirectoriesIndex = new Dictionary <int, SortedList <string, Directory> >(); _containedFilesIndex = new Dictionary <int, SortedList <string, File> >(); _fileIndex = new Dictionary <int, int>(); _accessRulesIndex = new Dictionary <int, List <int> >(); _auditRulesIndex = new Dictionary <int, List <int> >(); // Read the File System Header Cluster FileSystemHeaderCluster fileSystemHeaderCluster = new FileSystemHeaderCluster(_deviceIO.BlockSizeBytes, Guid.Empty); byte[] header = new byte[FileSystemHeaderCluster.CalculateClusterSize(_deviceIO.BlockSizeBytes)]; _deviceIO.Read(0, header, 0, header.Length); fileSystemHeaderCluster.Load(header, 0, signatureKeys, options); // Initialize values from the File System Header Cluster _geometry = new Geometry( fileSystemHeaderCluster.BytesPerDataCluster, fileSystemHeaderCluster.ClustersPerTrack, fileSystemHeaderCluster.DataClustersPerTrack, fileSystemHeaderCluster.TrackCount); _volumeName = fileSystemHeaderCluster.VolumeName; _volumeID = fileSystemHeaderCluster.VolumeID; // Initialize the Cluster State Table int entryCount = _geometry.ClustersPerTrack * _geometry.TrackCount; int clusterCount = (entryCount + ClusterStatesCluster.CalculateElementsPerCluster(_geometry.BytesPerCluster) - 1) / ClusterStatesCluster.CalculateElementsPerCluster(_geometry.BytesPerCluster); _clusterStateTable = new ClusterTable <ClusterState>( Enumerable.Range(0, clusterCount), sizeof(ClusterState), (address) => new ClusterStatesCluster(address, _geometry.BytesPerCluster, _volumeID)); _clusterStateTable.Load(_clusterIO); // Initialize the Next Cluster Address Table entryCount = _geometry.DataClustersPerTrack * _geometry.TrackCount; clusterCount = (entryCount + Int32ArrayCluster.CalculateElementsPerCluster(_geometry.BytesPerCluster) - 1) / Int32ArrayCluster.CalculateElementsPerCluster(_geometry.BytesPerCluster); _nextClusterAddressTable = new ClusterTable <int>( Enumerable.Range(_clusterStateTable.ClusterAddresses.Last() + 1, clusterCount), sizeof(int), (address) => new Int32ArrayCluster(address, _geometry.BytesPerCluster, _volumeID, ClusterType.NextClusterAddressTable)); _nextClusterAddressTable.Load(_clusterIO); // Initialize the Bytes Used Table _bytesUsedTable = new ClusterTable <int>( Enumerable.Range(_nextClusterAddressTable.ClusterAddresses.Last() + 1, clusterCount), sizeof(int), (address) => new Int32ArrayCluster(address, _geometry.BytesPerCluster, _volumeID, ClusterType.BytesUsedTable)); _bytesUsedTable.Load(_clusterIO); entryCount = _geometry.ClustersPerTrack * _geometry.TrackCount; clusterCount = (entryCount + VerifyTimesCluster.CalculateElementsPerCluster(_geometry.BytesPerCluster) - 1) / VerifyTimesCluster.CalculateElementsPerCluster(_geometry.BytesPerCluster); // Initialize the Verify Time Table _verifyTimeTable = new ClusterTable <DateTime>( Enumerable.Range(_bytesUsedTable.ClusterAddresses.Last() + 1, clusterCount), sizeof(long), (address) => new VerifyTimesCluster(address, _geometry.BytesPerCluster, _volumeID)); _verifyTimeTable.Load(_clusterIO); int l = _verifyTimeTable.ClusterAddresses.Last() + 1; int[] cl = getClusterChain(l).ToArray(); // Initialize the Directory Table _directoryTable = new MutableObjectClusterTable <Directory>( getClusterChain(_verifyTimeTable.ClusterAddresses.Last() + 1), Directory.StorageLength, (address) => Directory.CreateArrayCluster(address)); _directoryTable.Load(_clusterIO); // Initialize the File Table _fileTable = new MutableObjectClusterTable <File>( getClusterChain(_directoryTable.ClusterAddresses.First() + 1), File.StorageLength, (address) => File.CreateArrayCluster(address)); _fileTable.Load(_clusterIO); // Initialize the Access Rules Table _accessRules = new ClusterTable <SrfsAccessRule>( getClusterChain(_fileTable.ClusterAddresses.First() + 1), SrfsAccessRule.StorageLength + sizeof(bool), (address) => SrfsAccessRule.CreateArrayCluster(address)); _accessRules.Load(_clusterIO); // Initialize the Audit Rules Table _auditRules = new ClusterTable <SrfsAuditRule>( getClusterChain(_accessRules.ClusterAddresses.First() + 1), SrfsAuditRule.StorageLength + sizeof(bool), (address) => SrfsAuditRule.CreateArrayCluster(address)); _auditRules.Load(_clusterIO); // Create the Indexes for (int i = 0; i < _directoryTable.Count; i++) { Directory d = _directoryTable[i]; if (d != null) { _directoryIndex.Add(d.ID, i); _containedDirectoriesIndex.Add(d.ID, new SortedList <string, Directory>(StringComparer.OrdinalIgnoreCase)); _containedFilesIndex.Add(d.ID, new SortedList <string, File>(StringComparer.OrdinalIgnoreCase)); _accessRulesIndex.Add(d.ID, new List <int>()); _auditRulesIndex.Add(d.ID, new List <int>()); } } foreach (var d in from d in _directoryTable where d != null && d.ParentID != Constants.NoID select d) { _containedDirectoriesIndex[d.ParentID].Add(d.Name, d); } for (int i = 0; i < _fileTable.Count; i++) { File f = _fileTable[i]; if (f != null) { _fileIndex.Add(f.ID, i); _containedFilesIndex[f.ParentID].Add(f.Name, f); _accessRulesIndex.Add(f.ID, new List <int>()); _auditRulesIndex.Add(f.ID, new List <int>()); } } for (int i = 0; i < _accessRules.Count; i++) { Data.SrfsAccessRule r = _accessRules[i]; if (r != null) { _accessRulesIndex[r.ID].Add(i); } } for (int i = 0; i < _auditRules.Count; i++) { Data.SrfsAuditRule r = _auditRules[i]; if (r != null) { _auditRulesIndex[r.ID].Add(i); } } // Update the next entry ID _nextEntryID = Math.Max( _directoryIndex.Keys.Max(), _fileIndex.Count == 0 ? -1 : _fileIndex.Keys.Max()) + 1; }