/// <summary> /// Reads and collects clusters in index /// </summary> private void ReconstructIndex() { byte[] buffer = new byte[HeaderCluster.HeaderBytes]; for (int i = 0; i < (fs.Length - ReservedHeaderLength) / clusterSize; i++) { PositionToCluster(i); fs.Read(buffer, 0, buffer.Length); ClusterFlags flags = (ClusterFlags)buffer[0]; if (flags != ClusterFlags.Empty) { if ((flags & ClusterFlags.StreamHeader) != 0) { Guid id = new Guid(new byte[] { buffer[5], buffer[6], buffer[7], buffer[8], buffer[9], buffer[10], buffer[11], buffer[12], buffer[13], buffer[14], buffer[15], buffer[16], buffer[17], buffer[18], buffer[19], buffer[20] }); if (!id.Equals(indexKey)) { if ((flags & ClusterFlags.SafeCopy) != 0) { // Write not safe copy status PositionToCluster(i); fs.WriteByte((byte)ClusterFlags.StreamHeader); // Key already in index ? if (index.ContainsKey(id)) { // Delete previous chain and free space DeleteChain((int)index[id], true); // Remove from index index.Remove(id); } } if (!index.ContainsKey(id)) { index.Add(id, i); } else { // Delete duplicate chain and free space DeleteChain(i, true); } } else { // Index entry found at this point means it was corrupted DeleteChain(i, false); } } } else { #if DEBUG Debug.Assert(!emptyClusters.Contains(i)); #endif emptyClusters.Enqueue(i); } } }
/// <summary> /// Reads the data from file /// </summary> /// <param name="clusterNumber">Cluster of data location.</param> /// <returns>Data bytes</returns> private byte[] Read(int clusterNumber) { byte[] result = null; int dataOffset = 0; int dataLength = 1; byte[] buffer = new byte[clusterSize]; while (dataOffset < dataLength) { PositionToCluster(clusterNumber); fs.Read(buffer, 0, clusterSize); ClusterFlags flags = (ClusterFlags)buffer[0]; int headerBytes = 0; if ((flags & ClusterFlags.StreamHeader) != 0) { clusterNumber = BitConverter.ToInt32(buffer, 1); dataLength = BitConverter.ToInt32(buffer, 21); headerBytes = HeaderCluster.HeaderBytes; if (result == null) { result = new byte[dataLength]; } else { throw new InvalidOperationException("Unexpected second header in chain"); } } else { if ((flags & ClusterFlags.StreamData) != 0) { clusterNumber = BitConverter.ToInt32(buffer, 1); headerBytes = DataCluster.HeaderBytes; } else { throw new InvalidDataException(); } } if (result == null) { throw new InvalidOperationException("Header not found in chain"); } int remainingBytes = clusterSize - headerBytes; Array.Copy(buffer, headerBytes, result, dataOffset, Math.Min(remainingBytes, dataLength - dataOffset)); dataOffset += remainingBytes; } return(result); }
/// <summary> /// Reads the chain of clusters /// </summary> /// <param name="clusterNumber">Cluster number</param> /// <returns>Cluster chain</returns> private DataCluster ReadChain(int clusterNumber) { if (clusterNumber == -1) { return(null); } // Position to start of cluster PositionToCluster(clusterNumber); byte[] buffer = new byte[HeaderCluster.HeaderBytes]; fs.Read(buffer, 0, buffer.Length); ClusterFlags flags = (ClusterFlags)buffer[0]; if ((flags & ClusterFlags.StreamHeader) != 0) { HeaderCluster cluster = new HeaderCluster( flags, new Guid(new byte[] { buffer[5], buffer[6], buffer[7], buffer[8], buffer[9], buffer[10], buffer[11], buffer[12], buffer[13], buffer[14], buffer[15], buffer[16], buffer[17], buffer[18], buffer[19], buffer[20] }), clusterNumber, BitConverter.ToInt32(buffer, 21), ReadChain(BitConverter.ToInt32(buffer, 1)) ); return(cluster); } else { if ((flags & ClusterFlags.StreamData) != 0) { DataCluster cluster = new DataCluster( flags, clusterNumber, ReadChain(BitConverter.ToInt32(buffer, 1))); return(cluster); } else { return(null); } } }
/// <summary> /// Generates report about data fragmentation /// </summary> /// <returns>List of present bytestream lengths separated by newline</returns> public string FragmentationReport() { StringBuilder sb = new StringBuilder(); byte[] buffer = new byte[clusterSize]; foreach (Guid item in index.Keys) { int clusterNumber = (int)index[item]; PositionToCluster(clusterNumber); fs.Read(buffer, 0, clusterSize); ClusterFlags flags = (ClusterFlags)buffer[0]; if ((flags & ClusterFlags.StreamHeader) != 0) { int dataLength = BitConverter.ToInt32(buffer, 21); sb.AppendLine(dataLength.ToString()); } } return(sb.ToString()); }
/// <summary> /// Creates new instance of HeaderCluster type /// </summary> /// <param name="flags">Initial flags</param> /// <param name="clusterNumber">Assigned cluster number</param> /// <param name="nextCluster">Next cluster</param> /// <param name="key">Key which is stored</param> /// <param name="dataLength">Total data length</param> public HeaderCluster(ClusterFlags flags, Guid key, int clusterNumber, int dataLength, DataCluster nextCluster) : base(flags, clusterNumber, nextCluster) { this.Key = key; this.DataLength = dataLength; }
/// <summary> /// Creates new instance of DataCluster type /// </summary> /// <param name="flags">Initial flags</param> /// <param name="clusterNumber">Assigned cluster number</param> /// <param name="nextCluster">Next cluster</param> public DataCluster(ClusterFlags flags, int clusterNumber, DataCluster nextCluster) { this.Flags = flags; this.ClusterNumber = clusterNumber; this.NextCluster = nextCluster; }
/// <summary> /// Creates new instance of DataCluster type /// </summary> /// <param name="flags">Initial flags</param> /// <param name="clusterNumber">Assigned cluster number</param> /// <param name="nextCluster">Next cluster</param> public DataCluster(ClusterFlags flags, int clusterNumber, DataCluster nextCluster) { this.Flags = flags; this.ClusterNumber = clusterNumber; this.NextCluster = nextCluster; }
/// <summary> /// Creates new instance of HeaderCluster type /// </summary> /// <param name="flags">Initial flags</param> /// <param name="clusterNumber">Assigned cluster number</param> /// <param name="nextCluster">Next cluster</param> /// <param name="key">Key which is stored</param> /// <param name="dataLength">Total data length</param> public HeaderCluster(ClusterFlags flags, Guid key, int clusterNumber, int dataLength, DataCluster nextCluster) : base(flags, clusterNumber, nextCluster) { this.Key = key; this.DataLength = dataLength; }