Beispiel #1
0
 public BitmapData(NTFSVolume volume, FileRecord fileRecord, AttributeRecord attributeRecord, long numberOfUsableBits) : base(volume, fileRecord, attributeRecord)
 {
     m_numberOfUsableBits = numberOfUsableBits;
 }
Beispiel #2
0
 protected internal virtual void UpdateFileRecord(FileRecord fileRecord)
 {
     m_mft.UpdateFileRecord(fileRecord);
 }
Beispiel #3
0
 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);
        }
Beispiel #5
0
        internal VolumeInformationRecord GetVolumeInformationRecord()
        {
            FileRecord volumeRecord = m_mft.GetVolumeRecord();

            return((VolumeInformationRecord)volumeRecord.GetAttributeRecord(AttributeType.VolumeInformation, String.Empty));
        }
Beispiel #6
0
 public NonResidentAttributeData(NTFSVolume volume, FileRecord fileRecord, NonResidentAttributeRecord attributeRecord)
 {
     m_volume          = volume;
     m_fileRecord      = fileRecord;
     m_attributeRecord = attributeRecord;
 }
Beispiel #7
0
 protected internal void UpdateFileRecord(FileRecord fileRecord)
 {
     UpdateFileRecord(fileRecord, null);
 }
Beispiel #8
0
        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);
            }
        }
Beispiel #9
0
        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();
        }
Beispiel #10
0
 public NTFSFile(NTFSVolume volume, FileRecord fileRecord)
 {
     m_volume     = volume;
     m_fileRecord = fileRecord;
 }
Beispiel #11
0
 public NTFSFile(NTFSVolume volume, MftSegmentReference fileReference)
 {
     m_volume     = volume;
     m_fileRecord = m_volume.GetFileRecord(fileReference);
 }
Beispiel #12
0
 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);
        }