// NTFS filesystem implementation import { BaseFilesystem } from './base.js'; import { checkDependencies, updateResultItem } from '../utils.js'; export class NTFSFilesystem extends BaseFilesystem { constructor() { super('NTFS', [ { id: 'ntfs', name: 'NTFS', constants: [ { id: 'baseOffsetNTFS', label: 'Basis-Offset (Partitionsstart)', unit: 'Bytes', default: '0x10000' }, { id: 'sectorSizeNTFS', label: 'Sektor-Größe (Boot-Offset 0x0B)', unit: 'Bytes', default: '0x200' } ], inputs: [ { id: 'clusterSizeSectorsNTFS', label: 'Cluster-Größe (Boot-Offset 0x0D)', unit: 'Sektoren', placeholder: '0x8' }, { id: 'mftStartClusterNTFS', label: 'MFT Start (Boot-Offset 0x30)', unit: 'Cluster', placeholder: '0xC0000' }, { id: 'mftMirrStartClusterNTFS', label: 'Backup-MFT Start (Boot-Offset 0x38)', unit: 'Cluster', placeholder: '0x2' }, { id: 'mftEntrySizeRawNTFS', label: 'Größe MFT-Eintrag (Boot-Offset 0x40)', unit: 'Roh-Wert', placeholder: '0xF6' }, { id: 'indexSizeRawNTFS', label: 'Größe Index (Boot-Offset 0x44)', unit: 'Roh-Wert', placeholder: '0x01' }, { id: 'partitionSizeSectorsNTFS', label: 'Partitionsgröße (Boot-Offset 0x28)', unit: 'Sektoren', placeholder: '0x3E7FFF' }, { id: 'mftEntryNumberNTFS', label: 'MFT-Eintrags-Nummer', unit: 'Nummer', placeholder: '0x27' }, { id: 'attributeListPosValueNTFS', label: 'Attribut-Start-Offset (MFT-Header-Offset 0x14)', unit: 'Bytes', placeholder: '0x38', tooltip: 'Der 2-Byte-Wert, den Sie an Position 0x14 innerhalb des MFT-Eintrags lesen. Gibt an, wo die Attribut-Liste relativ zum MFT-Eintrag beginnt.' }, { id: 'clusterNumberNTFS', label: 'Cluster-Nummer', unit: 'Nummer', placeholder: '0x1234' }, { id: 'attributeOffsetNTFS', label: 'Attribut-Offset (relativ zum MFT-Eintrag)', unit: 'Bytes', placeholder: '0x50' }, { id: 'attributeTypeNTFS', label: 'Attribut-Typ (optional)', unit: 'Hex', placeholder: '0x80' } ], resultGroups: [ { name: 'Basis-Berechnungen', results: [ { id: 'clusterSizeBytesNTFS', label: 'Cluster-Größe', dependencies: ['sectorSizeNTFS', 'clusterSizeSectorsNTFS'], formula: 'Sektor-Größe × Cluster-Größe in Sektoren' }, { id: 'mftEntrySizeBytesNTFS', label: 'MFT-Eintrag Größe', dependencies: ['mftEntrySizeRawNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS'], formula: 'Wenn positiv: Wert × Cluster-Größe, wenn negativ: 2^|Wert|' }, { id: 'indexSizeBytesNTFS', label: 'Index-Größe', dependencies: ['indexSizeRawNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS'], formula: 'Wenn positiv: Wert × Cluster-Größe, wenn negativ: 2^|Wert|' } ] }, { name: 'MFT-Struktur', results: [ { id: 'mftStartOffsetNTFS', label: 'MFT Start', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS'], formula: 'Basis-Offset + (MFT Start Cluster × Cluster-Größe)' }, { id: 'mftMirrStartOffsetNTFS', label: 'Backup-MFT Start (MFTMirr)', dependencies: ['baseOffsetNTFS', 'mftMirrStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS'], formula: 'Basis-Offset + (Backup-MFT Cluster × Cluster-Größe)' } ] }, { name: 'Spezifischer MFT-Eintrag', results: [ { id: 'mftEntryOffsetNTFS', label: 'MFT-Eintrag Offset', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS', 'mftEntryNumberNTFS'], formula: 'MFT Start + (MFT-Eintrags-Nummer × MFT-Eintrag Größe)' }, { id: 'mftHeaderAttributeListPtrNTFS', label: 'Position 0x14 im MFT-Header (wo zu lesen)', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS', 'mftEntryNumberNTFS'], formula: 'MFT-Eintrag Offset + 0x14' }, { id: 'calculatedAttributeStartNTFS', label: 'Tatsächlicher Attribut-Start (berechnet)', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS', 'mftEntryNumberNTFS', 'attributeListPosValueNTFS'], formula: 'MFT-Eintrag Offset + (gelesener Wert)' }, { id: 'specificAttributeOffsetNTFS', label: 'Spezifisches Attribut Offset', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS', 'mftEntryNumberNTFS', 'attributeOffsetNTFS'], formula: 'MFT-Eintrag Offset + Attribut-Offset' } ] }, { name: 'Reservierte MFT-Einträge (Systemdateien)', results: [ { id: 'mftSelfOffsetNTFS', label: '$Mft (0) - Master File Table', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS'], formula: 'MFT Start + (0 × MFT-Eintrag Größe)' }, { id: 'mftMirrOffsetNTFS', label: '$MftMirr (1) - Backup erste 4 Einträge', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS'], formula: 'MFT Start + (1 × MFT-Eintrag Größe)' }, { id: 'logFileOffsetNTFS', label: '$LogFile (2) - Transaktionslog', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS'], formula: 'MFT Start + (2 × MFT-Eintrag Größe)' }, { id: 'volumeOffsetNTFS', label: '$Volume (3) - Volume-Informationen', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS'], formula: 'MFT Start + (3 × MFT-Eintrag Größe)' }, { id: 'attrDefOffsetNTFS', label: '$AttrDef (4) - Attributbeschreibungen', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS'], formula: 'MFT Start + (4 × MFT-Eintrag Größe)' }, { id: 'rootDirOffsetNTFS', label: '. (5) - Wurzelverzeichnis', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS'], formula: 'MFT Start + (5 × MFT-Eintrag Größe)' }, { id: 'bitmapOffsetNTFS', label: '$Bitmap (6) - Cluster-Belegung', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS'], formula: 'MFT Start + (6 × MFT-Eintrag Größe)' }, { id: 'bootOffsetNTFS', label: '$Boot (7) - Bootsektor', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS'], formula: 'MFT Start + (7 × MFT-Eintrag Größe)' }, { id: 'badClusOffsetNTFS', label: '$BadClus (8) - Fehlerhafte Cluster', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS'], formula: 'MFT Start + (8 × MFT-Eintrag Größe)' }, { id: 'secureOffsetNTFS', label: '$Secure (9) - Sicherheitsinformationen', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS'], formula: 'MFT Start + (9 × MFT-Eintrag Größe)' }, { id: 'upCaseOffsetNTFS', label: '$UpCase (10) - Zeichenkonvertierung', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS'], formula: 'MFT Start + (10 × MFT-Eintrag Größe)' }, { id: 'extendOffsetNTFS', label: '$Extend (11) - Erweiterungen', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS'], formula: 'MFT Start + (11 × MFT-Eintrag Größe)' } ] }, { name: 'Spezifischer Cluster', results: [ { id: 'clusterOffsetNTFS', label: 'Cluster Offset', dependencies: ['baseOffsetNTFS', 'clusterNumberNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS'], formula: 'Basis-Offset + (Cluster-Nummer × Cluster-Größe)' } ] }, { name: 'Partitions-Übersicht', results: [ { id: 'partitionSizeBytesNTFS', label: 'Partitionsgröße', dependencies: ['partitionSizeSectorsNTFS', 'sectorSizeNTFS'], formula: 'Partitionsgröße in Sektoren × Sektor-Größe' }, { id: 'totalClustersNTFS', label: 'Anzahl Cluster', dependencies: ['partitionSizeSectorsNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS'], formula: 'Partitionsgröße ÷ Cluster-Größe' }, { id: 'partitionEndOffsetNTFS', label: 'Partitionsende', dependencies: ['baseOffsetNTFS', 'partitionSizeSectorsNTFS', 'sectorSizeNTFS'], formula: 'Basis-Offset + Partitionsgröße' } ] } ], formulas: [ { name: 'Cluster-Größe (Bytes)', expression: 'Sektor-Größe × Cluster-Größe in Sektoren' }, { name: 'MFT-Eintrag Größe', expression: 'Wenn Wert positiv (0x00-0x7F): Wert × Cluster-Größe; Wenn Wert negativ (0x80-0xFF): 2^|Wert| Bytes' }, { name: 'Index-Größe', expression: 'Wenn Wert positiv (0x00-0x7F): Wert × Cluster-Größe; Wenn Wert negativ (0x80-0xFF): 2^|Wert| Bytes' }, { name: 'MFT Start Offset', expression: 'Basis-Offset + (MFT Start Cluster × Cluster-Größe in Bytes)' }, { name: 'Backup-MFT Start', expression: 'Basis-Offset + (Backup-MFT Cluster × Cluster-Größe in Bytes)' }, { name: 'MFT-Eintrag Offset', expression: 'MFT Start + (MFT-Eintrags-Nummer × MFT-Eintrag Größe)' }, { name: 'Zeiger auf Attribut-Liste', expression: 'MFT-Eintrag Offset + 0x14 (Adresse des Zeigers im Header)' }, { name: 'Berechneter Attribut-Start', expression: 'MFT-Eintrag Offset + (Wert der an Offset 0x14 gelesen wurde)' }, { name: 'Spezifisches Attribut', expression: 'MFT-Eintrag Offset + Attribut-Offset (relativ)' }, { name: 'Cluster Offset', expression: 'Basis-Offset + (Cluster-Nummer × Cluster-Größe in Bytes)' }, { name: 'Partitionsgröße', expression: 'Partitionsgröße in Sektoren × Sektor-Größe' }, { name: 'Anzahl Cluster', expression: 'Partitionsgröße in Bytes ÷ Cluster-Größe in Bytes' }, { name: 'Reservierte MFT-Einträge', expression: 'MFT Start + (Eintragsnummer 0-15 × MFT-Eintrag Größe)' } ] } ]); } calculate(variantId) { const values = this.getInputValues(variantId); const results = {}; if (variantId === 'ntfs') { this.calculateNTFS(values, results); } } calculateMFTEntrySize(rawValue, clusterSizeBytes) { // Special encoding from offset 0x40 and 0x44 // If positive (0x00-0x7F): size = value * cluster size // If negative (0x80-0xFF): size = 2^|value| bytes let size = 0; let explanation = ''; if (rawValue >= 0x00 && rawValue <= 0x7F) { // Positive value: multiply by cluster size size = rawValue * clusterSizeBytes; explanation = `Positiv (0x${rawValue.toString(16).toUpperCase()}): 0x${rawValue.toString(16).toUpperCase()} × 0x${clusterSizeBytes.toString(16).toUpperCase()} = 0x${size.toString(16).toUpperCase()} (${size} Bytes)`; } else if (rawValue >= 0x80 && rawValue <= 0xFF) { // Negative value: 2^|value| bytes // Calculate two's complement for 1 byte: 0x100 - value const negativeValue = 0x100 - rawValue; size = Math.pow(2, negativeValue); explanation = `Negativ (0x${rawValue.toString(16).toUpperCase()}): 2^${negativeValue} = 0x${size.toString(16).toUpperCase()} (${size} Bytes)`; } return { size, explanation }; } getAttributeTypeName(typeCode) { const types = { 0x10: '$STANDARD_INFORMATION', 0x20: '$ATTRIBUTE_LIST', 0x30: '$FILE_NAME', 0x40: '$OBJECT_ID', 0x50: '$SECURITY_DESCRIPTOR', 0x60: '$VOLUME_NAME', 0x70: '$VOLUME_INFORMATION', 0x80: '$DATA', 0x90: '$INDEX_ROOT', 0xA0: '$INDEX_ALLOCATION', 0xB0: '$BITMAP', 0xC0: '$REPARSE_POINT', 0xD0: '$EA_INFORMATION', 0xE0: '$EA', 0xF0: '$PROPERTY_SET', 0x100: '$LOGGED_UTILITY_STREAM' }; return types[typeCode] || `0x${typeCode.toString(16).toUpperCase()}`; } calculateNTFS(values, results) { // Cluster Size (bytes and sectors) if (checkDependencies(['sectorSizeNTFS', 'clusterSizeSectorsNTFS'])) { results.clusterSizeBytes = values.sectorSizeNTFS * values.clusterSizeSectorsNTFS; results.clusterSizeSectors = values.clusterSizeSectorsNTFS; updateResultItem('clusterSizeBytesNTFS', { bytes: results.clusterSizeBytes, sectors: results.clusterSizeSectors }, true, `0x${values.sectorSizeNTFS.toString(16).toUpperCase()} × 0x${values.clusterSizeSectorsNTFS.toString(16).toUpperCase()} = 0x${results.clusterSizeBytes.toString(16).toUpperCase()}`); } else { updateResultItem('clusterSizeBytesNTFS', 0, false); } // MFT Entry Size (with special encoding) if (checkDependencies(['mftEntrySizeRawNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS']) && results.clusterSizeBytes !== undefined) { const mftEntryCalc = this.calculateMFTEntrySize(values.mftEntrySizeRawNTFS, results.clusterSizeBytes); results.mftEntrySizeBytes = mftEntryCalc.size; results.mftEntrySizeExplanation = mftEntryCalc.explanation; updateResultItem('mftEntrySizeBytesNTFS', results.mftEntrySizeBytes, true, mftEntryCalc.explanation); } else { updateResultItem('mftEntrySizeBytesNTFS', 0, false); } // Index Size (with special encoding, same as MFT entry size) if (checkDependencies(['indexSizeRawNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS']) && results.clusterSizeBytes !== undefined) { const indexSizeCalc = this.calculateMFTEntrySize(values.indexSizeRawNTFS, results.clusterSizeBytes); results.indexSizeBytes = indexSizeCalc.size; updateResultItem('indexSizeBytesNTFS', results.indexSizeBytes, true, indexSizeCalc.explanation); } else { updateResultItem('indexSizeBytesNTFS', 0, false); } // MFT Start Offset (bytes and sector) if (checkDependencies(['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS']) && results.clusterSizeBytes !== undefined) { results.mftStartOffset = values.baseOffsetNTFS + (values.mftStartClusterNTFS * results.clusterSizeBytes); results.mftStartSector = Math.floor(results.mftStartOffset / values.sectorSizeNTFS); updateResultItem('mftStartOffsetNTFS', { bytes: results.mftStartOffset, sectors: results.mftStartSector }, true, `0x${values.baseOffsetNTFS.toString(16).toUpperCase()} + (0x${values.mftStartClusterNTFS.toString(16).toUpperCase()} × 0x${results.clusterSizeBytes.toString(16).toUpperCase()}) = 0x${results.mftStartOffset.toString(16).toUpperCase()}`); } else { updateResultItem('mftStartOffsetNTFS', 0, false); } // Backup MFT (MFTMirr) Start Offset (bytes and sector) if (checkDependencies(['baseOffsetNTFS', 'mftMirrStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS']) && results.clusterSizeBytes !== undefined) { results.mftMirrStartOffset = values.baseOffsetNTFS + (values.mftMirrStartClusterNTFS * results.clusterSizeBytes); results.mftMirrStartSector = Math.floor(results.mftMirrStartOffset / values.sectorSizeNTFS); updateResultItem('mftMirrStartOffsetNTFS', { bytes: results.mftMirrStartOffset, sectors: results.mftMirrStartSector }, true, `0x${values.baseOffsetNTFS.toString(16).toUpperCase()} + (0x${values.mftMirrStartClusterNTFS.toString(16).toUpperCase()} × 0x${results.clusterSizeBytes.toString(16).toUpperCase()}) = 0x${results.mftMirrStartOffset.toString(16).toUpperCase()}`); } else { updateResultItem('mftMirrStartOffsetNTFS', 0, false); } // Specific MFT Entry Offset (bytes and sector for offset) if (checkDependencies(['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS', 'mftEntryNumberNTFS']) && results.mftStartOffset !== undefined && results.mftEntrySizeBytes !== undefined) { results.mftEntryOffset = results.mftStartOffset + (values.mftEntryNumberNTFS * results.mftEntrySizeBytes); results.mftEntryOffsetSector = Math.floor(results.mftEntryOffset / values.sectorSizeNTFS); updateResultItem('mftEntryOffsetNTFS', { bytes: results.mftEntryOffset, sectors: results.mftEntryOffsetSector }, true, `0x${results.mftStartOffset.toString(16).toUpperCase()} + (0x${values.mftEntryNumberNTFS.toString(16).toUpperCase()} × 0x${results.mftEntrySizeBytes.toString(16).toUpperCase()}) = 0x${results.mftEntryOffset.toString(16).toUpperCase()}`); // Offset 0x14: Address of the pointer to attribute list results.mftHeaderAttributeListPtr = results.mftEntryOffset + 0x14; updateResultItem('mftHeaderAttributeListPtrNTFS', results.mftHeaderAttributeListPtr, true, `0x${results.mftEntryOffset.toString(16).toUpperCase()} + 0x14 = 0x${results.mftHeaderAttributeListPtr.toString(16).toUpperCase()} (lies 2 Bytes an dieser Adresse)`); // Calculated Attribute Start (if user provides the value read from 0x14) if (checkDependencies(['attributeListPosValueNTFS'])) { results.calculatedAttributeStart = results.mftEntryOffset + values.attributeListPosValueNTFS; updateResultItem('calculatedAttributeStartNTFS', results.calculatedAttributeStart, true, `0x${results.mftEntryOffset.toString(16).toUpperCase()} + 0x${values.attributeListPosValueNTFS.toString(16).toUpperCase()} = 0x${results.calculatedAttributeStart.toString(16).toUpperCase()}`); } else { updateResultItem('calculatedAttributeStartNTFS', 0, false); } // Specific Attribute Offset if (checkDependencies(['attributeOffsetNTFS'])) { results.specificAttributeOffset = results.mftEntryOffset + values.attributeOffsetNTFS; let attrInfo = ''; if (checkDependencies(['attributeTypeNTFS']) && values.attributeTypeNTFS) { attrInfo = ` (${this.getAttributeTypeName(values.attributeTypeNTFS)})`; } updateResultItem('specificAttributeOffsetNTFS', results.specificAttributeOffset, true, `0x${results.mftEntryOffset.toString(16).toUpperCase()} + 0x${values.attributeOffsetNTFS.toString(16).toUpperCase()} = 0x${results.specificAttributeOffset.toString(16).toUpperCase()}${attrInfo}`); } else { updateResultItem('specificAttributeOffsetNTFS', 0, false); } } else { updateResultItem('mftEntryOffsetNTFS', 0, false); updateResultItem('mftHeaderAttributeListPtrNTFS', 0, false); updateResultItem('calculatedAttributeStartNTFS', 0, false); updateResultItem('specificAttributeOffsetNTFS', 0, false); } // Reserved MFT Entries (System files 0-11) if (checkDependencies(['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS']) && results.mftStartOffset !== undefined && results.mftEntrySizeBytes !== undefined) { const systemFiles = [ { id: 'mftSelfOffsetNTFS', num: 0, name: '$Mft' }, { id: 'mftMirrOffsetNTFS', num: 1, name: '$MftMirr' }, { id: 'logFileOffsetNTFS', num: 2, name: '$LogFile' }, { id: 'volumeOffsetNTFS', num: 3, name: '$Volume' }, { id: 'attrDefOffsetNTFS', num: 4, name: '$AttrDef' }, { id: 'rootDirOffsetNTFS', num: 5, name: 'Root (.)' }, { id: 'bitmapOffsetNTFS', num: 6, name: '$Bitmap' }, { id: 'bootOffsetNTFS', num: 7, name: '$Boot' }, { id: 'badClusOffsetNTFS', num: 8, name: '$BadClus' }, { id: 'secureOffsetNTFS', num: 9, name: '$Secure' }, { id: 'upCaseOffsetNTFS', num: 10, name: '$UpCase' }, { id: 'extendOffsetNTFS', num: 11, name: '$Extend' } ]; systemFiles.forEach(file => { const offset = results.mftStartOffset + (file.num * results.mftEntrySizeBytes); updateResultItem(file.id, offset, true, `0x${results.mftStartOffset.toString(16).toUpperCase()} + (${file.num} × 0x${results.mftEntrySizeBytes.toString(16).toUpperCase()}) = 0x${offset.toString(16).toUpperCase()}`); }); } else { const systemFileIds = ['mftSelfOffsetNTFS', 'mftMirrOffsetNTFS', 'logFileOffsetNTFS', 'volumeOffsetNTFS', 'attrDefOffsetNTFS', 'rootDirOffsetNTFS', 'bitmapOffsetNTFS', 'bootOffsetNTFS', 'badClusOffsetNTFS', 'secureOffsetNTFS', 'upCaseOffsetNTFS', 'extendOffsetNTFS']; systemFileIds.forEach(id => updateResultItem(id, 0, false)); } // Specific Cluster Offset (bytes and sector) if (checkDependencies(['baseOffsetNTFS', 'clusterNumberNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS']) && results.clusterSizeBytes !== undefined) { results.clusterOffset = values.baseOffsetNTFS + (values.clusterNumberNTFS * results.clusterSizeBytes); results.clusterSector = Math.floor(results.clusterOffset / values.sectorSizeNTFS); updateResultItem('clusterOffsetNTFS', { bytes: results.clusterOffset, sectors: results.clusterSector }, true, `0x${values.baseOffsetNTFS.toString(16).toUpperCase()} + (0x${values.clusterNumberNTFS.toString(16).toUpperCase()} × 0x${results.clusterSizeBytes.toString(16).toUpperCase()}) = 0x${results.clusterOffset.toString(16).toUpperCase()}`); } else { updateResultItem('clusterOffsetNTFS', 0, false); } // Partition Overview (bytes and sectors) if (checkDependencies(['partitionSizeSectorsNTFS', 'sectorSizeNTFS'])) { results.partitionSizeBytes = values.partitionSizeSectorsNTFS * values.sectorSizeNTFS; results.partitionSizeSectors = values.partitionSizeSectorsNTFS; updateResultItem('partitionSizeBytesNTFS', { bytes: results.partitionSizeBytes, sectors: results.partitionSizeSectors }, true, `0x${values.partitionSizeSectorsNTFS.toString(16).toUpperCase()} × 0x${values.sectorSizeNTFS.toString(16).toUpperCase()} = 0x${results.partitionSizeBytes.toString(16).toUpperCase()}`); if (checkDependencies(['baseOffsetNTFS'])) { results.partitionEndOffset = values.baseOffsetNTFS + results.partitionSizeBytes; updateResultItem('partitionEndOffsetNTFS', results.partitionEndOffset, true, `0x${values.baseOffsetNTFS.toString(16).toUpperCase()} + 0x${results.partitionSizeBytes.toString(16).toUpperCase()} = 0x${results.partitionEndOffset.toString(16).toUpperCase()}`); } } else { updateResultItem('partitionSizeBytesNTFS', 0, false); updateResultItem('partitionEndOffsetNTFS', 0, false); } if (checkDependencies(['partitionSizeSectorsNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS']) && results.clusterSizeBytes !== undefined && results.partitionSizeBytes !== undefined) { results.totalClusters = Math.floor(results.partitionSizeBytes / results.clusterSizeBytes); updateResultItem('totalClustersNTFS', results.totalClusters, true, `0x${results.partitionSizeBytes.toString(16).toUpperCase()} ÷ 0x${results.clusterSizeBytes.toString(16).toUpperCase()} = 0x${results.totalClusters.toString(16).toUpperCase()}`); } else { updateResultItem('totalClustersNTFS', 0, false); } } }