2025-10-27 17:21:12 +01:00

313 lines
24 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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: 'calculatedAttributeStartNTFS', label: 'Attribut-Liste', 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()}`);
// 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('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);
}
}
}