public BitmapData(NTFSVolume volume, FileRecord fileRecord, AttributeRecord attributeRecord, long numberOfUsableBits) : base(volume, fileRecord, attributeRecord) { m_numberOfUsableBits = numberOfUsableBits; }
protected internal virtual void UpdateFileRecord(FileRecord fileRecord) { m_mft.UpdateFileRecord(fileRecord); }
public NTFSFile(NTFSVolume volume, FileRecord fileRecord) : this(volume, fileRecord, String.Empty) { }
public override Stream OpenFile(string path, FileMode mode, FileAccess access, FileShare share, FileOptions options) { string streamName = GetStreamName(path); path = GetFilePath(path); FileRecord fileRecord = null; AttributeRecord dataRecord = null; if (mode == FileMode.CreateNew || mode == FileMode.Create || mode == FileMode.OpenOrCreate) { bool fileExists = false; try { fileRecord = m_volume.GetFileRecord(path); fileExists = true; } catch (FileNotFoundException) { } catch (DirectoryNotFoundException) { } if (fileExists) { if (mode == FileMode.CreateNew) { if (streamName == String.Empty) { throw new AlreadyExistsException(); } else { dataRecord = fileRecord.GetAttributeRecord(AttributeType.Data, streamName); if (dataRecord != null) { throw new AlreadyExistsException(); } } } if (streamName != String.Empty && dataRecord == null) { // We might need to allocate an additional FileRecordSegment so we have to make sure we can extend the MFT if it is full if (m_volume.NumberOfFreeClusters < m_volume.NumberOfClustersRequiredToExtendMft) { throw new DiskFullException(); } fileRecord.CreateAttributeRecord(AttributeType.Data, streamName); m_volume.UpdateFileRecord(fileRecord); } if (mode == FileMode.Create) { mode = FileMode.Truncate; } } else { string directoryPath = Path.GetDirectoryName(path); string fileName = Path.GetFileName(path); FileRecord directoryRecord = m_volume.GetFileRecord(directoryPath); fileRecord = m_volume.CreateFile(directoryRecord.BaseSegmentReference, fileName, false); if (streamName != String.Empty) { fileRecord.CreateAttributeRecord(AttributeType.Data, streamName); m_volume.UpdateFileRecord(fileRecord); } } } else // Open, Truncate or Append { fileRecord = m_volume.GetFileRecord(path); dataRecord = fileRecord.GetAttributeRecord(AttributeType.Data, streamName); if (streamName != String.Empty && dataRecord == null) { throw new FileNotFoundException(String.Format("The file '{0}' does not contain a stream named '{1}'", path, streamName)); } } if (fileRecord.IsDirectory) { throw new UnauthorizedAccessException(); } List <NTFSFileStream> openStreams; lock (m_openStreams) { if (m_openStreams.TryGetValue(fileRecord.BaseSegmentNumber, out openStreams)) { if ((access & FileAccess.Write) != 0) { // Currently we only support opening a file stream for write access if no other stream is opened for that file throw new SharingViolationException(); } else if ((access & FileAccess.Read) != 0) { foreach (NTFSFileStream openStream in openStreams) { if (openStream.CanWrite && ((share & FileShare.Write) == 0)) { throw new SharingViolationException(); } } } } else { openStreams = new List <NTFSFileStream>(); m_openStreams.Add(fileRecord.BaseSegmentNumber, openStreams); } } NTFSFile file = new NTFSFile(m_volume, fileRecord, streamName); NTFSFileStream stream = new NTFSFileStream(file, access); openStreams.Add(stream); stream.Closed += delegate(object sender, EventArgs e) { openStreams.Remove(stream); if (openStreams.Count == 0) { lock (m_openStreams) { m_openStreams.Remove(fileRecord.BaseSegmentNumber); } } }; if (mode == FileMode.Truncate) { stream.SetLength(0); } else if (mode == FileMode.Append) { stream.Seek((long)file.Length, SeekOrigin.Begin); } return(stream); }
internal VolumeInformationRecord GetVolumeInformationRecord() { FileRecord volumeRecord = m_mft.GetVolumeRecord(); return((VolumeInformationRecord)volumeRecord.GetAttributeRecord(AttributeType.VolumeInformation, String.Empty)); }
public NonResidentAttributeData(NTFSVolume volume, FileRecord fileRecord, NonResidentAttributeRecord attributeRecord) { m_volume = volume; m_fileRecord = fileRecord; m_attributeRecord = attributeRecord; }
protected internal void UpdateFileRecord(FileRecord fileRecord) { UpdateFileRecord(fileRecord, null); }
public virtual void MoveFile(FileRecord fileRecord, MftSegmentReference newParentDirectory, string newFileName) { // Worst case scenrario: the new parent directory index requires multiple splits. // We assume IndexData.ExtendGranularity is bigger than or equal to the number of splits. if (NumberOfFreeClusters < NumberOfClustersRequiredToExtendIndex) { throw new DiskFullException(); } lock (m_mftLock) { FileRecord oldParentDirectoryRecord = GetFileRecord(fileRecord.ParentDirectoryReference); IndexData oldParentDirectoryIndex = new IndexData(this, oldParentDirectoryRecord, AttributeType.FileName); IndexData newParentDirectoryIndex; if (fileRecord.ParentDirectoryReference == newParentDirectory) { newParentDirectoryIndex = oldParentDirectoryIndex; } else { FileRecord newParentDirectoryRecord = GetFileRecord(newParentDirectory); newParentDirectoryIndex = new IndexData(this, newParentDirectoryRecord, AttributeType.FileName); } if (newParentDirectoryIndex.ContainsFileName(newFileName)) { throw new AlreadyExistsException(); } List <FileNameRecord> fileNameRecords = fileRecord.FileNameRecords; uint transactionID = m_logClient.AllocateTransactionID(); foreach (FileNameRecord fileNameRecord in fileNameRecords) { oldParentDirectoryIndex.RemoveEntry(fileNameRecord.GetBytes()); } // Windows will not update the dates and FileAttributes in $File_Name as often as their counterparts in $STANDARD_INFORMATION. DateTime creationTime = fileRecord.StandardInformation.CreationTime; DateTime modificationTime = fileRecord.StandardInformation.ModificationTime; DateTime mftModificationTime = fileRecord.StandardInformation.MftModificationTime; DateTime lastAccessTime = fileRecord.StandardInformation.LastAccessTime; ulong allocatedLength = fileRecord.FileNameRecord.AllocatedLength; FileAttributes fileAttributes = fileRecord.StandardInformation.FileAttributes; ushort packedEASize = fileRecord.FileNameRecord.PackedEASize; // Windows NTFS v5.1 driver does not usually update the value of the FileSize field belonging to the FileNameRecords that are stored in the FileRecord. // The driver does update the value during a rename, which is inconsistent file creation and is likely to be incidental rather than intentional. // We will set the value to 0 to be consistent with file creation. fileNameRecords = IndexHelper.GenerateFileNameRecords(newParentDirectory, newFileName, fileRecord.IsDirectory, GenerateDosNames, newParentDirectoryIndex, creationTime, modificationTime, mftModificationTime, lastAccessTime, allocatedLength, 0, fileAttributes, packedEASize); fileRecord.RemoveAttributeRecords(AttributeType.FileName, String.Empty); foreach (FileNameRecord fileNameRecord in fileNameRecords) { FileNameAttributeRecord fileNameAttribute = (FileNameAttributeRecord)fileRecord.CreateAttributeRecord(AttributeType.FileName, String.Empty); fileNameAttribute.IsIndexed = true; fileNameAttribute.Record = fileNameRecord; } UpdateFileRecord(fileRecord, transactionID); foreach (FileNameRecord fileNameRecord in fileNameRecords) { if (!fileRecord.IsDirectory) { fileNameRecord.FileSize = fileRecord.DataRecord.DataLength; } newParentDirectoryIndex.AddEntry(fileRecord.BaseSegmentReference, fileNameRecord.GetBytes()); } m_logClient.WriteForgetTransactionRecord(transactionID); m_logClient.WriteRestartRecord(true); } }
public virtual void MoveFile(FileRecord fileRecord, MftSegmentReference newParentDirectory, string newFileName) { // Worst case scenrario: the new parent directory index requires multiple splits if (NumberOfFreeClusters < 4) { throw new DiskFullException(); } FileRecord oldParentDirectoryRecord = GetFileRecord(fileRecord.ParentDirectoryReference); m_mftLock.AcquireWriterLock(Timeout.Infinite); IndexData oldParentDirectoryIndex = new IndexData(this, oldParentDirectoryRecord, AttributeType.FileName); IndexData newParentDirectoryIndex; if (fileRecord.ParentDirectoryReference == newParentDirectory) { newParentDirectoryIndex = oldParentDirectoryIndex; } else { FileRecord newParentDirectoryRecord = GetFileRecord(newParentDirectory); newParentDirectoryIndex = new IndexData(this, newParentDirectoryRecord, AttributeType.FileName); if (newParentDirectoryIndex.ContainsFileName(newFileName)) { m_mftLock.ReleaseWriterLock(); throw new AlreadyExistsException(); } } List <FileNameRecord> fileNameRecords = fileRecord.FileNameRecords; uint transactionID = m_logClient.AllocateTransactionID(); foreach (FileNameRecord fileNameRecord in fileNameRecords) { oldParentDirectoryIndex.RemoveEntry(fileNameRecord.GetBytes()); } DateTime creationTime = fileRecord.FileNameRecord.CreationTime; DateTime modificationTime = fileRecord.FileNameRecord.ModificationTime; DateTime mftModificationTime = fileRecord.FileNameRecord.MftModificationTime; DateTime lastAccessTime = fileRecord.FileNameRecord.LastAccessTime; ulong allocatedLength = fileRecord.FileNameRecord.AllocatedLength; ulong fileSize = fileRecord.FileNameRecord.FileSize; FileAttributes fileAttributes = fileRecord.FileNameRecord.FileAttributes; ushort packedEASize = fileRecord.FileNameRecord.PackedEASize; fileNameRecords = IndexHelper.GenerateFileNameRecords(newParentDirectory, newFileName, fileRecord.IsDirectory, m_generateDosNames, newParentDirectoryIndex, creationTime, modificationTime, mftModificationTime, lastAccessTime, allocatedLength, fileSize, fileAttributes, packedEASize); fileRecord.RemoveAttributeRecords(AttributeType.FileName, String.Empty); foreach (FileNameRecord fileNameRecord in fileNameRecords) { FileNameAttributeRecord fileNameAttribute = (FileNameAttributeRecord)fileRecord.CreateAttributeRecord(AttributeType.FileName, String.Empty); fileNameAttribute.IsIndexed = true; fileNameAttribute.Record = fileNameRecord; } UpdateFileRecord(fileRecord, transactionID); foreach (FileNameRecord fileNameRecord in fileNameRecords) { newParentDirectoryIndex.AddEntry(fileRecord.BaseSegmentReference, fileNameRecord.GetBytes()); } m_logClient.WriteForgetTransactionRecord(transactionID); m_logClient.WriteRestartRecord(this.MajorVersion, true); m_mftLock.ReleaseWriterLock(); }
public NTFSFile(NTFSVolume volume, FileRecord fileRecord) { m_volume = volume; m_fileRecord = fileRecord; }
public NTFSFile(NTFSVolume volume, MftSegmentReference fileReference) { m_volume = volume; m_fileRecord = m_volume.GetFileRecord(fileReference); }
public AttributeData(NTFSVolume volume, FileRecord fileRecord, AttributeRecord attributeRecord) { m_volume = volume; m_fileRecord = fileRecord; m_attributeRecord = attributeRecord; }
public void UpdateFileRecord(FileRecord fileRecord, uint transactionID) { Dictionary <MftSegmentReference, byte[]> undoDictionary = new Dictionary <MftSegmentReference, byte[]>(); foreach (FileRecordSegment segment in fileRecord.Segments) { byte[] segmentBytes = segment.GetBytes(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion, false); undoDictionary.Add(segment.SegmentReference, segmentBytes); } AttributeRecord oldAttributeList = fileRecord.BaseSegment.GetImmediateAttributeRecord(AttributeType.AttributeList, String.Empty); fileRecord.UpdateSegments(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion); FileRecordSegment baseSegment = fileRecord.BaseSegment; for (int segmentIndex = 1; segmentIndex < fileRecord.Segments.Count; segmentIndex++) { FileRecordSegment segment = fileRecord.Segments[segmentIndex]; if (segment.SegmentReference == MftSegmentReference.NullReference) { // New segment, we must allocate space for it MftSegmentReference segmentReference; if (baseSegment.SegmentNumber == MasterFileTable.MasterFileTableSegmentNumber) { segmentReference = AllocateReservedFileRecordSegment(transactionID); } else { segmentReference = AllocateFileRecordSegment(transactionID); } FileRecordSegment newSegment = new FileRecordSegment(segmentReference.SegmentNumber, segmentReference.SequenceNumber, baseSegment.SegmentReference); newSegment.IsInUse = true; newSegment.IsDirectory = fileRecord.IsDirectory; newSegment.NextAttributeInstance = segment.NextAttributeInstance; newSegment.ImmediateAttributes.AddRange(segment.ImmediateAttributes); fileRecord.Segments[segmentIndex] = newSegment; } else if (segment.ImmediateAttributes.Count == 0) { byte[] undoData = undoDictionary[segment.SegmentReference]; ulong streamOffset = (ulong)(segment.SegmentNumber * m_volume.BytesPerFileRecordSegment); m_volume.LogClient.WriteLogRecord(m_mftRecord.BaseSegmentReference, m_mftRecord.DataRecord, streamOffset, m_volume.BytesPerFileRecordSegment, NTFSLogOperation.DeallocateFileRecordSegment, new byte[0], NTFSLogOperation.InitializeFileRecordSegment, undoData, transactionID); DeallocateFileRecordSegment(segment, transactionID); fileRecord.Segments.RemoveAt(segmentIndex); segmentIndex--; } } for (int segmentIndex = 1; segmentIndex < fileRecord.Segments.Count; segmentIndex++) { FileRecordSegment segment = fileRecord.Segments[segmentIndex]; byte[] undoData; byte[] redoData = segment.GetBytes(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion, false); ulong streamOffset = (ulong)(segment.SegmentNumber * m_volume.BytesPerFileRecordSegment); if (undoDictionary.TryGetValue(segment.SegmentReference, out undoData)) { m_volume.LogClient.WriteLogRecord(m_mftRecord.BaseSegmentReference, m_mftRecord.DataRecord, streamOffset, m_volume.BytesPerFileRecordSegment, NTFSLogOperation.InitializeFileRecordSegment, redoData, NTFSLogOperation.InitializeFileRecordSegment, undoData, transactionID); } else { // New segment m_volume.LogClient.WriteLogRecord(m_mftRecord.BaseSegmentReference, m_mftRecord.DataRecord, streamOffset, m_volume.BytesPerFileRecordSegment, NTFSLogOperation.InitializeFileRecordSegment, redoData, NTFSLogOperation.DeallocateFileRecordSegment, new byte[0], transactionID); } UpdateFileRecordSegment(segment); } if (oldAttributeList is NonResidentAttributeRecord) { new NonResidentAttributeData(m_volume, null, (NonResidentAttributeRecord)oldAttributeList).Truncate(0); } bool needsAttributeList = (fileRecord.Segments.Count > 1); if (needsAttributeList) { List <AttributeListEntry> entries = FileRecordHelper.BuildAttributeList(fileRecord.Segments, m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion); int dataLength = AttributeList.GetLength(entries); int attributeListRecordLength = ResidentAttributeRecord.GetRecordLength(0, dataLength); int numberOfBytesFreeInBaseSegment = baseSegment.GetNumberOfBytesFree(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion); bool isResident = (attributeListRecordLength <= numberOfBytesFreeInBaseSegment); AttributeRecord attributeListRecord = baseSegment.CreateAttributeListRecord(isResident); AttributeList attributeList = new AttributeList(m_volume, attributeListRecord); attributeList.WriteEntries(entries); } byte[] baseRecordUndoData = undoDictionary[baseSegment.SegmentReference]; byte[] baseRecordRedoData = baseSegment.GetBytes(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion, false); ulong baseRecordStreamOffset = (ulong)(baseSegment.SegmentNumber * m_volume.BytesPerFileRecordSegment); m_volume.LogClient.WriteLogRecord(m_mftRecord.BaseSegmentReference, m_mftRecord.DataRecord, baseRecordStreamOffset, m_volume.BytesPerFileRecordSegment, NTFSLogOperation.InitializeFileRecordSegment, baseRecordRedoData, NTFSLogOperation.InitializeFileRecordSegment, baseRecordUndoData, transactionID); UpdateFileRecordSegment(baseSegment); }