public void Invoke() { Partition p = PartitionOptions.GetPartition(); if (BytesPerSlice > int.MaxValue) { throw new CommandLineArgumentException("Argument to -s is too large."); } int bytesPerSlice = (int)BytesPerSlice; int fileSystemHeaderClusterSize = FileSystemHeaderCluster.CalculateClusterSize(p.BytesPerBlock); long bytesAvailable = p.SizeBytes - fileSystemHeaderClusterSize; Geometry g = new Geometry(bytesPerSlice, ReedSolomon.N, ReedSolomon.K, 1); long totalTracks = bytesAvailable / g.CalculateTrackSizeBytes(p.BytesPerBlock); if (totalTracks > int.MaxValue) { throw new CommandLineArgumentException("Too many tracks, please use a larger value of Reed Solomon N and/or bytesPerCluster."); } g = new Geometry(bytesPerSlice, ReedSolomon.N, ReedSolomon.K, (int)totalTracks); Configuration.Geometry = g; Console.WriteLine($"Bytes per Cluster: {g.BytesPerCluster.ToFileSize()}"); Console.WriteLine($"Data Clusters per Track: {g.DataClustersPerTrack}"); Console.WriteLine($"Parity Clusters per Track: {g.ParityClustersPerTrack}"); Console.WriteLine($"Total Clusters per Track: {g.ClustersPerTrack}"); Console.WriteLine($"Resiliency: {(double)g.ParityClustersPerTrack / g.ClustersPerTrack:%#0.00}"); Console.WriteLine($"Total Tracks: {g.TrackCount}"); Console.WriteLine($"Bytes Used: {(g.CalculateFileSystemSize(p.BytesPerBlock)).ToFileSize()}"); Console.WriteLine($"Bytes Available: {((long)g.DataClustersPerTrack * g.TrackCount * (g.BytesPerCluster - FileDataCluster.FileBaseClusterHeaderLength)).ToFileSize()}"); Console.WriteLine($"Bytes Wasted: {(p.SizeBytes - g.CalculateFileSystemSize(p.BytesPerBlock)).ToFileSize()}"); }
public void Invoke() { Partition p = PartitionOptions.GetPartition(); if (BytesPerSlice > int.MaxValue) { throw new CommandLineArgumentException("Argument to -s is too large."); } int bytesPerSlice = (int)BytesPerSlice; long bytesAvailable = p.SizeBytes - FileSystemHeaderCluster.CalculateClusterSize(p.BytesPerBlock); Geometry g = new Geometry(bytesPerSlice, ReedSolomon.N, ReedSolomon.K, 1); long totalTracks = bytesAvailable / g.CalculateTrackSizeBytes(p.BytesPerBlock); if (totalTracks > int.MaxValue) { throw new CommandLineArgumentException("Too many chains, please use a larger value of n (Reed Solomon parameter) and/or bytesPerSlice."); } g = new Geometry(bytesPerSlice, ReedSolomon.N, ReedSolomon.K, (int)totalTracks); Configuration.Geometry = g; Configuration.VolumeName = VolumeName; Configuration.FileSystemID = Guid.NewGuid(); Options options = Options.None; if (doNotVerifyHashes) { options |= Options.DoNotVerifyClusterHashes; } if (doNotVerifySignatures) { options |= Options.DoNotVerifyClusterSignatures; } Configuration.Options = options; CngKey encryptionKey = CryptoSettingsOptions.GetEncryptionKey(); CngKey decryptionKey = CryptoSettingsOptions.GetDecryptionKey(); CngKey signingKey = CryptoSettingsOptions.GetSigningKey(); Configuration.CryptoSettings = new CryptoSettings(decryptionKey, signingKey, encryptionKey); using (var f = FileSystem.Create(new PartitionIO(p))) { } }
public SimpleClusterIO(IBlockIO io, Geometry geometry, PrivateKey signingKey, IDictionary <KeyThumbprint, PublicKey> signatureKeys, Options options) { if (io == null) { throw new ArgumentNullException(); } _fileSystemHeaderClusterSize = FileSystemHeaderCluster.CalculateClusterSize(io.BlockSizeBytes); _parityClusterSize = _geometry.BytesPerCluster + ParityCluster.CalculateHeaderLength(io.BlockSizeBytes); _io = io; _buffer = new byte[_parityClusterSize]; _geometry = geometry; _signingKey = signingKey; _signatureKeys = signatureKeys; _options = options; }
public long CalculateFileSystemSize(int bytesPerBlock) { int fileSystemHeaderSize = FileSystemHeaderCluster.CalculateClusterSize(bytesPerBlock); return(fileSystemHeaderSize + CalculateTrackSizeBytes(bytesPerBlock) * TrackCount); }
public FileSystemClusterIO(FileSystem fs, IBlockIO io) : base(io, FileSystemHeaderCluster.CalculateClusterSize(io.BlockSizeBytes)) { _fileSystem = fs; }
// 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; }