Esempio n. 1
0
        public FileRecord CreateFile(List <FileNameRecord> fileNameRecords, uint transactionID)
        {
            if (fileNameRecords.Count == 0)
            {
                throw new ArgumentException();
            }
            bool isDirectory = fileNameRecords[0].IsDirectory;
            MftSegmentReference segmentReference  = AllocateFileRecordSegment(transactionID);
            FileRecordSegment   fileRecordSegment = new FileRecordSegment(segmentReference.SegmentNumber, segmentReference.SequenceNumber);

            // UpdateFileRecord() expects the base segment to be present on disk
            byte[] redoData     = fileRecordSegment.GetBytes(m_volume.BytesPerFileRecordSegment, m_volume.MinorVersion, false);
            ulong  streamOffset = (ulong)(fileRecordSegment.SegmentNumber * m_volume.BytesPerFileRecordSegment);

            m_volume.LogClient.WriteLogRecord(m_mftRecord.BaseSegmentReference, m_mftRecord.DataRecord, streamOffset, NTFSLogOperation.InitializeFileRecordSegment, redoData, NTFSLogOperation.DeallocateFileRecordSegment, new byte[0], transactionID);
            UpdateFileRecordSegment(fileRecordSegment);

            fileRecordSegment.ReferenceCount = (ushort)fileNameRecords.Count; // Each FileNameRecord is about to be indexed
            fileRecordSegment.IsInUse        = true;
            fileRecordSegment.IsDirectory    = isDirectory;

            FileRecord fileRecord = new FileRecord(fileRecordSegment);
            StandardInformationRecord standardInformation = (StandardInformationRecord)fileRecord.CreateAttributeRecord(AttributeType.StandardInformation, String.Empty);

            standardInformation.CreationTime        = fileNameRecords[0].CreationTime;
            standardInformation.ModificationTime    = fileNameRecords[0].ModificationTime;
            standardInformation.MftModificationTime = fileNameRecords[0].MftModificationTime;
            standardInformation.LastAccessTime      = fileNameRecords[0].LastAccessTime;
            standardInformation.FileAttributes      = 0;
            foreach (FileNameRecord fileNameRecord in fileNameRecords)
            {
                FileNameAttributeRecord fileNameAttribute = (FileNameAttributeRecord)fileRecord.CreateAttributeRecord(AttributeType.FileName, String.Empty);
                fileNameAttribute.IsIndexed = true;
                fileNameAttribute.Record    = fileNameRecord;
            }

            if (isDirectory)
            {
                string          indexName = IndexHelper.GetIndexName(AttributeType.FileName);
                IndexRootRecord indexRoot = (IndexRootRecord)fileRecord.CreateAttributeRecord(AttributeType.IndexRoot, indexName);
                IndexHelper.InitializeIndexRoot(indexRoot, AttributeType.FileName, m_volume.BytesPerIndexRecord, m_volume.BytesPerCluster);
            }
            else
            {
                fileRecord.CreateAttributeRecord(AttributeType.Data, String.Empty);
            }

            UpdateFileRecord(fileRecord, transactionID);

            return(fileRecord);
        }
Esempio n. 2
0
        public void AddEntry(MftSegmentReference fileReference, byte[] key)
        {
            IndexEntry entry = new IndexEntry();

            entry.FileReference = fileReference;
            entry.Key           = key;
            if (!m_rootRecord.IsParentNode)
            {
                int insertIndex = CollationHelper.FindIndexForSortedInsert(m_rootRecord.IndexEntries, key, m_rootRecord.CollationRule);
                m_rootRecord.IndexEntries.Insert(insertIndex, entry);
                if (m_rootRecord.RecordLength >= m_volume.AttributeRecordLengthToMakeNonResident)
                {
                    if (m_indexAllocationRecord == null)
                    {
                        m_indexAllocationRecord = (IndexAllocationRecord)m_fileRecord.CreateAttributeRecord(AttributeType.IndexAllocation, m_indexName);
                        m_indexAllocationData   = new NonResidentAttributeData(m_volume, m_fileRecord, m_indexAllocationRecord);
                        m_bitmapRecord          = m_fileRecord.CreateAttributeRecord(AttributeType.Bitmap, m_indexName);
                        m_bitmapData            = new BitmapData(m_volume, m_fileRecord, m_bitmapRecord, 0);
                    }
                    SplitRootIndexRecord();
                }
                else
                {
                    m_volume.UpdateFileRecord(m_fileRecord);
                }
            }
            else
            {
                KeyValuePairList <int, IndexRecord> path = FindInsertPath(key);
                IndexRecord leafRecord    = path[path.Count - 1].Value;
                long        leafRecordVBN = leafRecord.RecordVBN;
                int         insertIndex   = CollationHelper.FindIndexForSortedInsert(leafRecord.IndexEntries, key, m_rootRecord.CollationRule);
                leafRecord.IndexEntries.Insert(insertIndex, entry);
                long leafRecordIndex = ConvertToRecordIndex(leafRecordVBN);
                if (leafRecord.DoesFit((int)m_rootRecord.BytesPerIndexRecord))
                {
                    WriteIndexRecord(leafRecordIndex, leafRecord);
                }
                else
                {
                    // Split index record
                    SplitIndexRecord(path);
                }
            }
        }
Esempio n. 3
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);
            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;

            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);

            foreach (FileNameRecord fileNameRecord in fileNameRecords)
            {
                newParentDirectoryIndex.AddEntry(fileRecord.BaseSegmentReference, fileNameRecord.GetBytes());
            }
        }
Esempio n. 4
0
        public FileRecord CreateFile(List <FileNameRecord> fileNameRecords)
        {
            if (fileNameRecords.Count == 0)
            {
                throw new ArgumentException();
            }
            bool isDirectory = fileNameRecords[0].IsDirectory;
            MftSegmentReference segmentReference  = AllocateFileRecordSegment();
            FileRecordSegment   fileRecordSegment = new FileRecordSegment(segmentReference.SegmentNumber, segmentReference.SequenceNumber);

            fileRecordSegment.ReferenceCount = (ushort)fileNameRecords.Count; // Each FileNameRecord is about to be indexed
            fileRecordSegment.IsInUse        = true;
            fileRecordSegment.IsDirectory    = isDirectory;
            FileRecord fileRecord = new FileRecord(fileRecordSegment);
            StandardInformationRecord standardInformation = (StandardInformationRecord)fileRecord.CreateAttributeRecord(AttributeType.StandardInformation, String.Empty);

            standardInformation.CreationTime        = fileNameRecords[0].CreationTime;
            standardInformation.ModificationTime    = fileNameRecords[0].ModificationTime;
            standardInformation.MftModificationTime = fileNameRecords[0].MftModificationTime;
            standardInformation.LastAccessTime      = fileNameRecords[0].LastAccessTime;
            standardInformation.FileAttributes      = 0;
            foreach (FileNameRecord fileNameRecord in fileNameRecords)
            {
                FileNameAttributeRecord fileNameAttribute = (FileNameAttributeRecord)fileRecord.CreateAttributeRecord(AttributeType.FileName, String.Empty);
                fileNameAttribute.IsIndexed = true;
                fileNameAttribute.Record    = fileNameRecord;
            }

            if (isDirectory)
            {
                string          indexName = IndexHelper.GetIndexName(AttributeType.FileName);
                IndexRootRecord indexRoot = (IndexRootRecord)fileRecord.CreateAttributeRecord(AttributeType.IndexRoot, indexName);
                IndexHelper.InitializeIndexRoot(indexRoot, AttributeType.FileName, m_volume.BytesPerIndexRecord, m_volume.BytesPerCluster);
            }
            else
            {
                fileRecord.CreateAttributeRecord(AttributeType.Data, String.Empty);
            }

            UpdateFileRecord(fileRecord);

            return(fileRecord);
        }
Esempio n. 5
0
        public override FileSystemEntry CreateFile(string path)
        {
            string streamName = GetStreamName(path);

            path = GetFilePath(path);
            string     parentDirectoryName   = Path.GetDirectoryName(path);
            string     fileName              = Path.GetFileName(path);
            FileRecord parentDirectoryRecord = m_volume.GetFileRecord(parentDirectoryName);
            FileRecord fileRecord            = null;

            if (streamName == String.Empty)
            {
                fileRecord = m_volume.CreateFile(parentDirectoryRecord.BaseSegmentReference, fileName, false);
            }
            else
            {
                try
                {
                    fileRecord = m_volume.GetFileRecord(path);
                }
                catch (FileNotFoundException)
                {
                }

                if (fileRecord == null)
                {
                    fileRecord = m_volume.CreateFile(parentDirectoryRecord.BaseSegmentReference, fileName, false);
                }
                else
                {
                    // 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);
            }
            return(ToFileSystemEntry(path, fileRecord));
        }
Esempio n. 6
0
        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);
        }
Esempio n. 7
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);
            }
        }