/// <summary> /// Retieve the positions of all linked metadata entries found in this block and associated child data blocks. /// </summary> /// <returns>Array of Long.</returns> public long[] GetMetadataBlocks() { if (CfsCommon.IsTrue(IsFile)) { throw new InvalidOperationException("Get metadata blocks must only be called on directory metadata blocks"); } List <long> ret = new List <long>(); if (Data == null || Data.Length < 8) { return(ret.ToArray()); } int pos = 0; LogDebug("GetMetadataBlocks retrieving metadata blocks from data length of " + Data.Length); while (pos < Data.Length) { byte[] currBlock = new byte[8]; Buffer.BlockCopy(Data, pos, currBlock, 0, 8); Int64 block = BitConverter.ToInt64(currBlock, 0); LogDebug("GetMetadataBlocks adding metadata block position " + block); ret.Add(block); pos += 8; } if (ChildDataBlock > 0) { LogDebug("GetMetadataBlocks child data block referenced at " + ChildDataBlock); byte[] nextBlockBytes = CfsCommon.ReadFromPosition(Filestream, ChildDataBlock, 512); MetadataBlock nextBlock = MetadataBlock.FromBytes(Filestream, BlockSizeBytes, nextBlockBytes, Logging); nextBlock.Filestream = Filestream; long[] childBlocks = nextBlock.GetMetadataBlocks(); foreach (long curr in childBlocks) { ret.Add(curr); } } return(ret.ToArray()); }
/// <summary> /// Create a new metadata block instance from a byte array from data found within the container file. /// </summary> /// <param name="fs">The FileStream instance to use.</param> /// <param name="blockSize">The block size, in bytes.</param> /// <param name="ba">The byte array containing the full block.</param> /// <param name="logging">Instance of LoggingModule to use for logging events.</param> /// <returns>A populated MetadataBlock object.</returns> public static MetadataBlock FromBytes(FileStream fs, int blockSize, byte[] ba, LoggingModule logging) { try { if (ba == null || ba.Length < 1) { throw new ArgumentNullException(nameof(ba)); } if (ba.Length < 64) { throw new ArgumentException("Byte array has length less than 64"); } if (blockSize < 4096) { throw new ArgumentOutOfRangeException("Block size must be greater than or equal to 4096"); } if (blockSize % 4096 != 0) { throw new ArgumentOutOfRangeException("Block size must be evenly divisible by 4096"); } if (fs == null) { throw new ArgumentNullException(nameof(fs)); } MetadataBlock ret = new MetadataBlock(); ret.Signature = MetadataBlock.SignatureBytes; ret.BlockSizeBytes = blockSize; ret.Logging = logging; ret.Filestream = fs; byte[] temp; Buffer.BlockCopy(ba, 0, ret.Signature, 0, 4); temp = new byte[8]; Buffer.BlockCopy(ba, 4, temp, 0, 8); ret.ParentBlock = BitConverter.ToInt64(temp, 0); temp = new byte[8]; Buffer.BlockCopy(ba, 12, temp, 0, 8); ret.ChildDataBlock = BitConverter.ToInt64(temp, 0); temp = new byte[4]; Buffer.BlockCopy(ba, 20, temp, 0, 4); ret.FullDataLength = BitConverter.ToInt32(temp, 0); temp = new byte[4]; Buffer.BlockCopy(ba, 28, temp, 0, 4); ret.LocalDataLength = BitConverter.ToInt32(temp, 0); temp = new byte[4]; Buffer.BlockCopy(ba, 32, temp, 0, 4); ret.IsDirectory = BitConverter.ToInt32(temp, 0); temp = new byte[4]; Buffer.BlockCopy(ba, 36, temp, 0, 4); ret.IsFile = BitConverter.ToInt32(temp, 0); temp = new byte[256]; Buffer.BlockCopy(ba, 40, temp, 0, 256); ret.Name = Encoding.UTF8.GetString(CfsCommon.TrimNullBytes(temp)).Trim(); temp = new byte[32]; Buffer.BlockCopy(ba, 296, temp, 0, 32); ret.CreatedUtc = Encoding.UTF8.GetString(CfsCommon.TrimNullBytes(temp)).Trim(); temp = new byte[32]; Buffer.BlockCopy(ba, 328, temp, 0, 32); ret.LastUpdateUtc = Encoding.UTF8.GetString(CfsCommon.TrimNullBytes(temp)).Trim(); temp = new byte[ret.LocalDataLength]; Buffer.BlockCopy(ba, 512, temp, 0, ret.LocalDataLength); ret.Data = temp; return(ret); } catch (Exception e) { if (logging != null) { logging.LogException("MetadataBlock", "FromBytes", e); } else { LoggingModule.ConsoleException("MetadataBlock", "FromBytes", e); } throw; } }