internal DirectoryEntry AddEntry(File file, string name, FileNameNamespace nameNamespace) { if (name.Length > 255) { throw new IOException("Invalid file name, more than 255 characters: " + name); } else if (name.IndexOfAny(new char[] { '\0', '/' }) != -1) { throw new IOException(@"Invalid file name, contains '\0' or '/': " + name); } FileNameRecord newNameRecord = file.GetFileNameRecord(null, true); newNameRecord.FileNameNamespace = nameNamespace; newNameRecord.FileName = name; newNameRecord.ParentDirectory = MftReference; NtfsStream nameStream = file.CreateStream(AttributeType.FileName, null); nameStream.SetContent(newNameRecord); file.HardLinkCount++; file.UpdateRecordInMft(); Index[newNameRecord] = file.MftReference; Modified(); UpdateRecordInMft(); return(new DirectoryEntry(this, file.MftReference, newNameRecord)); }
public static File CreateNew(INtfsContext context, FileRecordFlags flags, FileAttributeFlags dirFlags) { File newFile = context.AllocateFile(flags); FileAttributeFlags fileFlags = FileAttributeFlags.Archive | FileRecord.ConvertFlags(flags) | (dirFlags & FileAttributeFlags.Compressed); AttributeFlags dataAttrFlags = AttributeFlags.None; if ((dirFlags & FileAttributeFlags.Compressed) != 0) { dataAttrFlags |= AttributeFlags.Compressed; } StandardInformation.InitializeNewFile(newFile, fileFlags); if (context.ObjectIds != null) { Guid newId = CreateNewGuid(context); NtfsStream stream = newFile.CreateStream(AttributeType.ObjectId, null); ObjectId objId = new ObjectId(); objId.Id = newId; stream.SetContent(objId); context.ObjectIds.Add(newId, newFile.MftReference, newId, Guid.Empty, Guid.Empty); } newFile.CreateAttribute(AttributeType.Data, dataAttrFlags); newFile.UpdateRecordInMft(); return(newFile); }
private static void SetSecurityAttribute(File file, string secDesc) { NtfsStream rootSecurityStream = file.CreateStream(AttributeType.SecurityDescriptor, null); SecurityDescriptor sd = new SecurityDescriptor(); sd.Descriptor = new RawSecurityDescriptor(secDesc); rootSecurityStream.SetContent(sd); }
public void Delete() { if (_records[0].HardLinkCount != 0) { throw new InvalidOperationException("Attempt to delete in-use file: " + ToString()); } _context.ForgetFile(this); NtfsStream objIdStream = GetStream(AttributeType.ObjectId, null); if (objIdStream != null) { ObjectId objId = objIdStream.GetContent <ObjectId>(); Context.ObjectIds.Remove(objId.Id); } // Truncate attributes, allowing for truncation silently removing the AttributeList attribute // in some cases (large file with all attributes first extent in the first MFT record). This // releases all allocated clusters in most cases. List <NtfsAttribute> truncateAttrs = new List <NtfsAttribute>(_attributes.Count); foreach (var attr in _attributes) { if (attr.Type != AttributeType.AttributeList) { truncateAttrs.Add(attr); } } foreach (NtfsAttribute attr in truncateAttrs) { attr.GetDataBuffer().SetCapacity(0); } // If the attribute list record remains, free any possible clusters it owns. We've now freed // all clusters. NtfsAttribute attrList = GetAttribute(AttributeType.AttributeList, null); if (attrList != null) { attrList.GetDataBuffer().SetCapacity(0); } // Now go through the MFT records, freeing them up foreach (var mftRecord in _records) { _context.Mft.RemoveRecord(mftRecord.Reference); } _attributes.Clear(); _records.Clear(); }
public void Accessed() { DateTime now = DateTime.UtcNow; NtfsStream siStream = GetStream(AttributeType.StandardInformation, null); StandardInformation si = siStream.GetContent <StandardInformation>(); si.LastAccessTime = now; siStream.SetContent(si); MarkMftRecordDirty(); }
public static StandardInformation InitializeNewFile(File file, FileAttributeFlags flags) { DateTime now = DateTime.UtcNow; NtfsStream siStream = file.CreateStream(AttributeType.StandardInformation, null); StandardInformation si = new StandardInformation(); si.CreationTime = now; si.ModificationTime = now; si.MftChangedTime = now; si.LastAccessTime = now; si.FileAttributes = flags; siStream.SetContent(si); return(si); }
public void Initialize(File file) { _self = file; if (_recordStream != null) { _recordStream.Dispose(); } NtfsStream bitmapStream = _self.GetStream(AttributeType.Bitmap, null); _bitmap = new Bitmap(bitmapStream.Open(FileAccess.ReadWrite), long.MaxValue); NtfsStream recordsStream = _self.GetStream(AttributeType.Data, null); _recordStream = recordsStream.Open(FileAccess.ReadWrite); }
public File InitializeNew(INtfsContext context, long firstBitmapCluster, ulong numBitmapClusters, long firstRecordsCluster, ulong numRecordsClusters) { BiosParameterBlock bpb = context.BiosParameterBlock; FileRecord fileRec = new FileRecord(bpb.BytesPerSector, bpb.MftRecordSize, (uint)MftIndex); fileRec.Flags = FileRecordFlags.InUse; fileRec.SequenceNumber = 1; _recordCache[MftIndex] = fileRec; _self = new File(context, fileRec); StandardInformation.InitializeNewFile(_self, FileAttributeFlags.Hidden | FileAttributeFlags.System); NtfsStream recordsStream = _self.CreateStream(AttributeType.Data, null, firstRecordsCluster, numRecordsClusters, (uint)bpb.BytesPerCluster); _recordStream = recordsStream.Open(FileAccess.ReadWrite); Wipe(_recordStream); NtfsStream bitmapStream = _self.CreateStream(AttributeType.Bitmap, null, firstBitmapCluster, numBitmapClusters, (uint)bpb.BytesPerCluster); using (Stream s = bitmapStream.Open(FileAccess.ReadWrite)) { Wipe(s); s.SetLength(8); _bitmap = new Bitmap(s, long.MaxValue); } _recordLength = context.BiosParameterBlock.MftRecordSize; _bytesPerSector = context.BiosParameterBlock.BytesPerSector; _bitmap.MarkPresentRange(0, 1); // Write the MFT's own record to itself byte[] buffer = new byte[_recordLength]; fileRec.ToBytes(buffer, 0); _recordStream.Position = 0; _recordStream.Write(buffer, 0, _recordLength); _recordStream.Flush(); return(_self); }
public NtfsFileSystem Format(Stream stream) { _context = new NtfsContext(); _context.Options = new NtfsOptions(); _context.RawStream = stream; _context.AttributeDefinitions = new AttributeDefinitions(); string localAdminString = (ComputerAccount == null) ? "LA" : new SecurityIdentifier(WellKnownSidType.AccountAdministratorSid, ComputerAccount).ToString(); using (new NtfsTransaction()) { _clusterSize = 4096; _mftRecordSize = 1024; _indexBufferSize = 4096; long totalClusters = ((SectorCount - 1) * Sizes.Sector) / _clusterSize; // Allocate a minimum of 8KB for the boot loader, but allow for more int numBootClusters = Utilities.Ceil(Math.Max((int)(8 * Sizes.OneKiB), BootCode == null ? 0 : BootCode.Length), _clusterSize); // Place MFT mirror in the middle of the volume _mftMirrorCluster = totalClusters / 2; uint numMftMirrorClusters = 1; // The bitmap is also near the middle _bitmapCluster = _mftMirrorCluster + 13; int numBitmapClusters = (int)Utilities.Ceil((totalClusters / 8), _clusterSize); // The MFT bitmap goes 'near' the start - approx 10% in - but ensure we avoid the bootloader long mftBitmapCluster = Math.Max(3 + (totalClusters / 10), numBootClusters); int numMftBitmapClusters = 1; // The MFT follows it's bitmap _mftCluster = mftBitmapCluster + numMftBitmapClusters; int numMftClusters = 8; if (_mftCluster + numMftClusters > _mftMirrorCluster || _bitmapCluster + numBitmapClusters >= totalClusters) { throw new IOException("Unable to determine initial layout of NTFS metadata - disk may be too small"); } CreateBiosParameterBlock(stream, numBootClusters * _clusterSize); _context.Mft = new MasterFileTable(_context); File mftFile = _context.Mft.InitializeNew(_context, mftBitmapCluster, (ulong)numMftBitmapClusters, (long)_mftCluster, (ulong)numMftClusters); File bitmapFile = CreateFixedSystemFile(MasterFileTable.BitmapIndex, _bitmapCluster, (ulong)numBitmapClusters, true); _context.ClusterBitmap = new ClusterBitmap(bitmapFile); _context.ClusterBitmap.MarkAllocated(0, numBootClusters); _context.ClusterBitmap.MarkAllocated(_bitmapCluster, numBitmapClusters); _context.ClusterBitmap.MarkAllocated(mftBitmapCluster, numMftBitmapClusters); _context.ClusterBitmap.MarkAllocated(_mftCluster, numMftClusters); _context.ClusterBitmap.SetTotalClusters(totalClusters); bitmapFile.UpdateRecordInMft(); File mftMirrorFile = CreateFixedSystemFile(MasterFileTable.MftMirrorIndex, _mftMirrorCluster, numMftMirrorClusters, true); File logFile = CreateSystemFile(MasterFileTable.LogFileIndex); using (Stream s = logFile.OpenStream(AttributeType.Data, null, FileAccess.ReadWrite)) { s.SetLength(Math.Min(Math.Max(2 * Sizes.OneMiB, (totalClusters / 500) * (long)_clusterSize), 64 * Sizes.OneMiB)); byte[] buffer = new byte[1024 * 1024]; for (int i = 0; i < buffer.Length; ++i) { buffer[i] = 0xFF; } long totalWritten = 0; while (totalWritten < s.Length) { int toWrite = (int)Math.Min(s.Length - totalWritten, buffer.Length); s.Write(buffer, 0, toWrite); totalWritten += toWrite; } } File volumeFile = CreateSystemFile(MasterFileTable.VolumeIndex); NtfsStream volNameStream = volumeFile.CreateStream(AttributeType.VolumeName, null); volNameStream.SetContent(new VolumeName(Label ?? "New Volume")); NtfsStream volInfoStream = volumeFile.CreateStream(AttributeType.VolumeInformation, null); volInfoStream.SetContent(new VolumeInformation(3, 1, VolumeInformationFlags.None)); SetSecurityAttribute(volumeFile, "O:" + localAdminString + "G:BAD:(A;;0x12019f;;;SY)(A;;0x12019f;;;BA)"); volumeFile.UpdateRecordInMft(); _context.GetFileByIndex = delegate(long index) { return(new File(_context, _context.Mft.GetRecord(index, false))); }; _context.AllocateFile = delegate(FileRecordFlags frf) { return(new File(_context, _context.Mft.AllocateRecord(frf, false))); }; File attrDefFile = CreateSystemFile(MasterFileTable.AttrDefIndex); _context.AttributeDefinitions.WriteTo(attrDefFile); SetSecurityAttribute(attrDefFile, "O:" + localAdminString + "G:BAD:(A;;FR;;;SY)(A;;FR;;;BA)"); attrDefFile.UpdateRecordInMft(); File bootFile = CreateFixedSystemFile(MasterFileTable.BootIndex, 0, (uint)numBootClusters, false); SetSecurityAttribute(bootFile, "O:" + localAdminString + "G:BAD:(A;;FR;;;SY)(A;;FR;;;BA)"); bootFile.UpdateRecordInMft(); File badClusFile = CreateSystemFile(MasterFileTable.BadClusIndex); badClusFile.CreateStream(AttributeType.Data, "$Bad"); badClusFile.UpdateRecordInMft(); File secureFile = CreateSystemFile(MasterFileTable.SecureIndex, FileRecordFlags.HasViewIndex); secureFile.RemoveStream(secureFile.GetStream(AttributeType.Data, null)); _context.SecurityDescriptors = SecurityDescriptors.Initialize(secureFile); secureFile.UpdateRecordInMft(); File upcaseFile = CreateSystemFile(MasterFileTable.UpCaseIndex); _context.UpperCase = UpperCase.Initialize(upcaseFile); upcaseFile.UpdateRecordInMft(); File objIdFile = File.CreateNew(_context, FileRecordFlags.IsMetaFile | FileRecordFlags.HasViewIndex, FileAttributeFlags.None); objIdFile.RemoveStream(objIdFile.GetStream(AttributeType.Data, null)); objIdFile.CreateIndex("$O", (AttributeType)0, AttributeCollationRule.MultipleUnsignedLongs); objIdFile.UpdateRecordInMft(); File reparseFile = File.CreateNew(_context, FileRecordFlags.IsMetaFile | FileRecordFlags.HasViewIndex, FileAttributeFlags.None); reparseFile.CreateIndex("$R", (AttributeType)0, AttributeCollationRule.MultipleUnsignedLongs); reparseFile.UpdateRecordInMft(); File quotaFile = File.CreateNew(_context, FileRecordFlags.IsMetaFile | FileRecordFlags.HasViewIndex, FileAttributeFlags.None); Quotas.Initialize(quotaFile); Directory extendDir = CreateSystemDirectory(MasterFileTable.ExtendIndex); extendDir.AddEntry(objIdFile, "$ObjId", FileNameNamespace.Win32AndDos); extendDir.AddEntry(reparseFile, "$Reparse", FileNameNamespace.Win32AndDos); extendDir.AddEntry(quotaFile, "$Quota", FileNameNamespace.Win32AndDos); extendDir.UpdateRecordInMft(); Directory rootDir = CreateSystemDirectory(MasterFileTable.RootDirIndex); rootDir.AddEntry(mftFile, "$MFT", FileNameNamespace.Win32AndDos); rootDir.AddEntry(mftMirrorFile, "$MFTMirr", FileNameNamespace.Win32AndDos); rootDir.AddEntry(logFile, "$LogFile", FileNameNamespace.Win32AndDos); rootDir.AddEntry(volumeFile, "$Volume", FileNameNamespace.Win32AndDos); rootDir.AddEntry(attrDefFile, "$AttrDef", FileNameNamespace.Win32AndDos); rootDir.AddEntry(rootDir, ".", FileNameNamespace.Win32AndDos); rootDir.AddEntry(bitmapFile, "$Bitmap", FileNameNamespace.Win32AndDos); rootDir.AddEntry(bootFile, "$Boot", FileNameNamespace.Win32AndDos); rootDir.AddEntry(badClusFile, "$BadClus", FileNameNamespace.Win32AndDos); rootDir.AddEntry(secureFile, "$Secure", FileNameNamespace.Win32AndDos); rootDir.AddEntry(upcaseFile, "$UpCase", FileNameNamespace.Win32AndDos); rootDir.AddEntry(extendDir, "$Extend", FileNameNamespace.Win32AndDos); SetSecurityAttribute(rootDir, "O:" + localAdminString + "G:BUD:(A;OICI;FA;;;BA)(A;OICI;FA;;;SY)(A;OICIIO;GA;;;CO)(A;OICI;0x1200a9;;;BU)(A;CI;LC;;;BU)(A;CIIO;DC;;;BU)(A;;0x1200a9;;;WD)"); rootDir.UpdateRecordInMft(); // A number of records are effectively 'reserved' for (long i = MasterFileTable.ExtendIndex + 1; i <= 15; i++) { File f = CreateSystemFile(i); SetSecurityAttribute(f, "O:S-1-5-21-1708537768-746137067-1060284298-1003G:BAD:(A;;0x12019f;;;SY)(A;;0x12019f;;;BA)"); f.UpdateRecordInMft(); } } // XP-style security permissions setup NtfsFileSystem ntfs = new NtfsFileSystem(stream); ntfs.SetSecurity(@"$MFT", new RawSecurityDescriptor("O:" + localAdminString + "G:BAD:(A;;FR;;;SY)(A;;FR;;;BA)")); ntfs.SetSecurity(@"$MFTMirr", new RawSecurityDescriptor("O:" + localAdminString + "G:BAD:(A;;FR;;;SY)(A;;FR;;;BA)")); ntfs.SetSecurity(@"$LogFile", new RawSecurityDescriptor("O:" + localAdminString + "G:BAD:(A;;FR;;;SY)(A;;FR;;;BA)")); ntfs.SetSecurity(@"$Bitmap", new RawSecurityDescriptor("O:" + localAdminString + "G:BAD:(A;;FR;;;SY)(A;;FR;;;BA)")); ntfs.SetSecurity(@"$BadClus", new RawSecurityDescriptor("O:" + localAdminString + "G:BAD:(A;;FR;;;SY)(A;;FR;;;BA)")); ntfs.SetSecurity(@"$UpCase", new RawSecurityDescriptor("O:" + localAdminString + "G:BAD:(A;;FR;;;SY)(A;;FR;;;BA)")); ntfs.SetSecurity(@"$Secure", new RawSecurityDescriptor("O:" + localAdminString + "G:BAD:(A;;0x12019f;;;SY)(A;;0x12019f;;;BA)")); ntfs.SetSecurity(@"$Extend", new RawSecurityDescriptor("O:" + localAdminString + "G:BAD:(A;;0x12019f;;;SY)(A;;0x12019f;;;BA)")); ntfs.SetSecurity(@"$Extend\$Quota", new RawSecurityDescriptor("O:" + localAdminString + "G:BAD:(A;;0x12019f;;;SY)(A;;0x12019f;;;BA)")); ntfs.SetSecurity(@"$Extend\$ObjId", new RawSecurityDescriptor("O:" + localAdminString + "G:BAD:(A;;0x12019f;;;SY)(A;;0x12019f;;;BA)")); ntfs.SetSecurity(@"$Extend\$Reparse", new RawSecurityDescriptor("O:" + localAdminString + "G:BAD:(A;;0x12019f;;;SY)(A;;0x12019f;;;BA)")); ntfs.CreateDirectory("System Volume Information"); ntfs.SetAttributes("System Volume Information", FileAttributes.Hidden | FileAttributes.System | FileAttributes.Directory); ntfs.SetSecurity("System Volume Information", new RawSecurityDescriptor("O:BAG:SYD:(A;OICI;FA;;;SY)")); using (Stream s = ntfs.OpenFile(@"System Volume Information\MountPointManagerRemoteDatabase", FileMode.Create)) { } ntfs.SetAttributes(@"System Volume Information\MountPointManagerRemoteDatabase", FileAttributes.Hidden | FileAttributes.System | FileAttributes.Archive); ntfs.SetSecurity(@"System Volume Information\MountPointManagerRemoteDatabase", new RawSecurityDescriptor("O:BAG:SYD:(A;;FA;;;SY)")); return(ntfs); }
public void RemoveStream(NtfsStream stream) { RemoveAttribute(stream.Attribute); }
public void UpdateRecordInMft() { if (_dirty) { if (NtfsTransaction.Current != null) { NtfsStream stream = GetStream(AttributeType.StandardInformation, null); StandardInformation si = stream.GetContent <StandardInformation>(); si.MftChangedTime = NtfsTransaction.Current.Timestamp; stream.SetContent(si); } bool fixesApplied = true; while (fixesApplied) { fixesApplied = false; for (int i = 0; i < _records.Count; ++i) { var record = _records[i]; bool fixedAttribute = true; while (record.Size > _mft.RecordSize && fixedAttribute) { fixedAttribute = false; if (!fixedAttribute && !record.IsMftRecord) { foreach (var attr in record.Attributes) { if (!attr.IsNonResident && !_context.AttributeDefinitions.MustBeResident(attr.AttributeType)) { MakeAttributeNonResident(new AttributeReference(record.Reference, attr.AttributeId), (int)attr.DataLength); fixedAttribute = true; break; } } } if (!fixedAttribute) { foreach (var attr in record.Attributes) { if (attr.AttributeType == AttributeType.IndexRoot && ShrinkIndexRoot(attr.Name)) { fixedAttribute = true; break; } } } if (!fixedAttribute) { if (record.Attributes.Count == 1) { fixedAttribute = SplitAttribute(record); } else { if (_records.Count == 1) { CreateAttributeList(); } fixedAttribute = ExpelAttribute(record); } } fixesApplied |= fixedAttribute; } } } _dirty = false; foreach (var record in _records) { _mft.WriteRecord(record); } } }