/// <summary> /// Finish building the file. Don't use this builder after that! /// </summary> /// <returns></returns> public LoggedFile Close() { var ret = new LoggedFile(info.ID, log); info = new FileLog.LoggedFileInfo(); log = null; return(ret); }
/// <summary> /// Creates new file inside the passed FileLog /// </summary> /// <param name="log"></param> /// <exception cref="ArgumentNullException">log</exception> public LoggedFileBuilder(FileLog log) { if (log == null) { throw new ArgumentNullException("log"); } this.log = log; info = log.CreateFile(); }
/// <summary> /// Get file lentgh /// </summary> /// <param name="hint">file hint as returned from GetFileHint</param> /// <returns>file length</returns> public long GetFileLength(FileLog.LoggedFileInfo hint) { lock (streamLock) { var initialPos = stream.Position; stream.Position = hint.Hint; var ret = binReader.ReadInt64(); stream.Position = initialPos; return(ret); } }
/// <summary> /// Read file data to buffer /// </summary> /// <param name="hint">file hint as returned from GetFileHint</param> /// <param name="buffer">output buffer</param> /// <param name="start">file offset to start reading at</param> /// <param name="length">how many data to read</param> /// <param name="offset">start offset in the output buffer</param> /// <exception cref="ArgumentNullException">Buffer is null</exception> /// <exception cref="BufferNotLargeEnoughException"></exception> /// <exception cref="IndexOutOfRangeException">Data outside the file requested.</exception> /// <exception cref="LoggedFileCorruptedException">The logged file is somehow corrupted - eg. invalid pointers, missing data, ...</exception> public void ReadFileDataToBuffer(FileLog.LoggedFileInfo hint, byte[] buffer, long start, int length, int offset) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (buffer.Length - offset < length) { throw new BufferNotLargeEnoughException(); } lock (streamLock) { var initialPos = stream.Position; stream.Position = hint.Hint; long size = binReader.ReadInt64(); if (size < start + length) { throw new IndexOutOfRangeException("Data outside the file requested."); } long blockOffset = start % FileLog.BlockSize; long fbt2Offset = (start / (FileLog.BlockSize)) % (FileLog.FilesPerBlock + 1); long fbtOffset = start / (FileLog.BlockSize * (FileLog.FilesPerBlock + 1)) + 1; long currentFbt = stream.Position; long currentFbt2 = -1; var streamLength = stream.Length; while (length > 0) { while (fbtOffset <= FileLog.FilesPerBlock) { while (fbt2Offset <= FileLog.FilesPerBlock) { if (currentFbt2 < 0) { stream.Position = currentFbt + fbtOffset * sizeof(long); currentFbt2 = binReader.ReadInt64(); if (currentFbt2 <= 0 || currentFbt2 > streamLength - FileLog.BlockSize) { throw new LoggedFileCorruptedException(string.Format("Expected valid pointer to FBT2 at {0}! File hint: {1}.", stream.Position - sizeof(long), hint)); } } stream.Position = currentFbt2 + fbt2Offset * sizeof(long); long dataBlock = binReader.ReadInt64(); if (dataBlock <= 0 || dataBlock > streamLength - FileLog.BlockSize) { throw new LoggedFileCorruptedException(string.Format("Expected valid pointer to data block at {0}! File hint: {1}.", stream.Position - sizeof(long), hint)); } stream.Position = dataBlock + blockOffset; int toRead = Math.Min(length, (int)(FileLog.BlockSize - blockOffset)); int read = 0; // although all data should be available the implementation may not return them all at once while (toRead > 0 && (read = stream.Read(buffer, offset, toRead)) != 0) { toRead -= read; offset += read; length -= read; blockOffset += read; } if (toRead > 0) { throw new LoggedFileCorruptedException(string.Format("Expected to read {0} more bytes from data block starting at {1}. File hint: {2}.", toRead, dataBlock, hint)); } if (length == 0) { stream.Position = initialPos; return; } blockOffset = 0; fbt2Offset++; } fbt2Offset = 0; fbtOffset++; currentFbt2 = -1; } stream.Position = currentFbt; currentFbt = binReader.ReadInt64(); if (currentFbt <= 0 || currentFbt > streamLength - FileLog.BlockSize) { throw new LoggedFileCorruptedException(string.Format("Expected valid pointer to next FBT at {0}! File hint: {1}.", stream.Position - sizeof(long), hint)); } stream.Position = currentFbt; fbtOffset -= FileLog.FilesPerBlock; currentFbt2 = -1; } } }