public IndexData(NTFSVolume volume, FileRecord fileRecord, AttributeType indexedAttributeType) { m_volume = volume; m_fileRecord = fileRecord; m_indexedAttributeType = indexedAttributeType; m_indexName = IndexHelper.GetIndexName(indexedAttributeType); m_rootRecord = (IndexRootRecord)m_fileRecord.GetAttributeRecord(AttributeType.IndexRoot, m_indexName); // I have observed the NTFS v5.1 driver keeping the IndexAllocation and associated Bitmap attributes after deleting files from the directory even though m_rootRecord.IsParentNode is set to false. m_indexAllocationRecord = (IndexAllocationRecord)m_fileRecord.GetAttributeRecord(AttributeType.IndexAllocation, m_indexName); m_bitmapRecord = m_fileRecord.GetAttributeRecord(AttributeType.Bitmap, m_indexName); if (m_indexAllocationRecord != null && m_bitmapRecord != null) { m_indexAllocationData = new NonResidentAttributeData(m_volume, m_fileRecord, m_indexAllocationRecord); long numberOfUsableBits = (long)(m_indexAllocationRecord.DataLength / m_rootRecord.BytesPerIndexRecord); m_bitmapData = new BitmapData(m_volume, m_fileRecord, m_bitmapRecord, numberOfUsableBits); } else if (m_rootRecord.IsParentNode && m_indexAllocationRecord == null) { throw new InvalidDataException("Missing Index Allocation Record"); } else if (m_rootRecord.IsParentNode && m_bitmapRecord == null) { throw new InvalidDataException("Missing Index Bitmap Record"); } }
public override void Delete(string path) { string streamName = GetStreamName(path); path = GetFilePath(path); FileRecord fileRecord = m_volume.GetFileRecord(path); if (streamName == String.Empty) { m_volume.DeleteFile(fileRecord); } else { // We only delete the named stream AttributeRecord dataRecord = fileRecord.GetAttributeRecord(AttributeType.Data, streamName); if (dataRecord == null) { throw new FileNotFoundException(String.Format("The file '{0}' does not contain a stream named '{1}'", path, streamName)); } AttributeData attributeData = new AttributeData(m_volume, fileRecord, dataRecord); attributeData.Truncate(0); fileRecord.RemoveAttributeRecord(AttributeType.Data, streamName); m_volume.UpdateFileRecord(fileRecord); } }
/// <param name="attributeName">The name of the data attribute we wish to access</param> public NTFSFile(NTFSVolume volume, FileRecord fileRecord, string attributeName) { m_volume = volume; m_fileRecord = fileRecord; AttributeRecord attributeRecord = fileRecord.GetAttributeRecord(AttributeType.Data, attributeName); m_data = new AttributeData(m_volume, m_fileRecord, attributeRecord); }
public override FileSystemEntry GetEntry(string path) { string streamName = GetStreamName(path); path = GetFilePath(path); FileRecord fileRecord = m_volume.GetFileRecord(path); if (streamName != String.Empty && fileRecord.GetAttributeRecord(AttributeType.Data, streamName) == null) { throw new FileNotFoundException(String.Format("The file '{0}' does not contain a stream named '{1}'", path, streamName)); } return(ToFileSystemEntry(path, fileRecord)); }
internal VolumeInformationRecord GetVolumeInformationRecord() { FileRecord volumeRecord = m_mft.GetVolumeRecord(); if (volumeRecord != null) { return((VolumeInformationRecord)volumeRecord.GetAttributeRecord(AttributeType.VolumeInformation, String.Empty)); } else { throw new InvalidDataException("Invalid NTFS volume record"); } }
private KeyValuePairList <MftSegmentReference, FileNameRecord> GetFileNameRecordsInDirectory(long directoryBaseSegmentNumber) { FileRecord record = m_mft.GetFileRecord(directoryBaseSegmentNumber); KeyValuePairList <MftSegmentReference, FileNameRecord> result = null; if (record != null && record.IsDirectory) { IndexRootRecord indexRoot = (IndexRootRecord)record.GetAttributeRecord(AttributeType.IndexRoot, IndexRootRecord.FileNameIndexName); IndexAllocationRecord indexAllocation = (IndexAllocationRecord)record.GetAttributeRecord(AttributeType.IndexAllocation, IndexRootRecord.FileNameIndexName); if (indexRoot.IsLargeIndex) { if (indexAllocation != null) { result = indexAllocation.GetAllEntries(this, indexRoot); } } else { result = indexRoot.GetSmallIndexEntries(); } if (result != null) { for (int index = 0; index < result.Count; index++) { if (result[index].Value.Namespace == FilenameNamespace.DOS) { // The same FileRecord can have multiple entries, each with it's own namespace result.RemoveAt(index); index--; } } } } return(result); }
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)); }