overcuriousity 16a754fa3f ntfs beta
2025-10-04 20:41:55 +02:00

215 lines
14 KiB
JavaScript
Raw 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 (Beta)',
constants: [
{ id: 'baseOffsetNTFS', label: 'Basis-Offset (Partitionsstart)', unit: 'Bytes', default: '0x10000' },
{ id: 'sectorSizeNTFS', label: 'Sektor-Größe', unit: 'Bytes', default: '0x200' }
],
inputs: [
{ id: 'clusterSizeSectorsNTFS', label: 'Cluster-Größe', unit: 'Sektoren', placeholder: '0x8' },
{ id: 'mftStartClusterNTFS', label: 'MFT Start', unit: 'Cluster', placeholder: '0xC0000' },
{ id: 'mftEntrySizeRawNTFS', label: 'Größe MFT-Eintrag (Roh-Wert)', unit: 'Hex von Offset 0x40', placeholder: '0xF6' },
{ id: 'partitionSizeSectorsNTFS', label: 'Partitionsgröße', unit: 'Sektoren', placeholder: '0x3E7FFF' },
{ id: 'mftEntryNumberNTFS', label: 'MFT-Eintrags-Nummer', unit: 'Nummer', placeholder: '0x27' },
{ id: 'clusterNumberNTFS', label: 'Cluster-Nummer', unit: 'Nummer', placeholder: '0x1234' }
],
resultGroups: [
{
name: 'Basis-Berechnungen',
results: [
{ id: 'clusterSizeBytesNTFS', label: 'Cluster-Größe (Bytes)', dependencies: ['sectorSizeNTFS', 'clusterSizeSectorsNTFS'], formula: 'Sektor-Größe × Cluster-Größe in Sektoren' },
{ id: 'mftEntrySizeBytesNTFS', label: 'MFT-Eintrag Größe (Bytes)', dependencies: ['mftEntrySizeRawNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS'], formula: 'Wenn positiv: Wert × Cluster-Größe, wenn negativ: 2^|Wert|' },
{ id: 'mftEntrySizeCalculationNTFS', label: 'MFT-Eintrag Berechnung', dependencies: ['mftEntrySizeRawNTFS'], formula: 'Erklärung der Kodierung' }
]
},
{
name: 'MFT-Struktur',
results: [
{ id: 'mftStartOffsetNTFS', label: 'MFT Start (Bytes)', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS'], formula: 'Basis-Offset + (MFT Start Cluster × Cluster-Größe)' },
{ id: 'mftStartSectorNTFS', label: 'MFT Start (Sektor)', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS'], formula: 'MFT Start Offset ÷ Sektor-Größe' }
]
},
{
name: 'Spezifischer MFT-Eintrag',
results: [
{ id: 'mftEntryOffsetNTFS', label: 'MFT-Eintrag Offset (Bytes)', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS', 'mftEntryNumberNTFS'], formula: 'MFT Start + (MFT-Eintrags-Nummer × MFT-Eintrag Größe)' },
{ id: 'attributeListOffsetNTFS', label: 'Attribut-Liste Position', dependencies: ['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS', 'mftEntryNumberNTFS'], formula: 'MFT-Eintrag Offset + 0x14 (aus Tabelle A2)' }
]
},
{
name: 'Spezifischer Cluster',
results: [
{ id: 'clusterOffsetNTFS', label: 'Cluster Offset (Bytes)', dependencies: ['baseOffsetNTFS', 'clusterNumberNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS'], formula: 'Basis-Offset + (Cluster-Nummer × Cluster-Größe)' },
{ id: 'clusterSectorNTFS', label: 'Cluster Start (Sektor)', dependencies: ['baseOffsetNTFS', 'clusterNumberNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS'], formula: 'Cluster Offset ÷ Sektor-Größe' }
]
},
{
name: 'Partitions-Übersicht',
results: [
{ id: 'partitionSizeBytesNTFS', label: 'Partitionsgröße (Bytes)', 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 (Bytes)', 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: 'MFT Start Offset', expression: 'Basis-Offset + (MFT Start Cluster × Cluster-Größe in Bytes)' },
{ name: 'MFT-Eintrag Offset', expression: 'MFT Start + (MFT-Eintrags-Nummer × MFT-Eintrag Größe)' },
{ name: 'Attribut-Liste Position', expression: 'MFT-Eintrag Offset + 0x14 (Position aus Tabelle A2)' },
{ 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' }
]
}
]);
}
calculate(variantId) {
const values = this.getInputValues(variantId);
const results = {};
if (variantId === 'ntfs') {
this.calculateNTFS(values, results);
}
}
calculateMFTEntrySize(rawValue, clusterSizeBytes) {
// Special encoding from offset 0x40
// 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()}`;
} 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()} Bytes`;
}
return { size, explanation };
}
calculateNTFS(values, results) {
// Cluster Size in Bytes
if (checkDependencies(['sectorSizeNTFS', 'clusterSizeSectorsNTFS'])) {
results.clusterSizeBytes = values.sectorSizeNTFS * values.clusterSizeSectorsNTFS;
updateResultItem('clusterSizeBytesNTFS', results.clusterSizeBytes, 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);
// Display explanation as text
const explanationElement = document.getElementById('mftEntrySizeCalculationNTFS');
if (explanationElement) {
explanationElement.innerHTML = mftEntryCalc.explanation;
const resultItem = explanationElement.closest('.result-item');
resultItem.classList.remove('unavailable');
resultItem.classList.add('available');
}
} else {
updateResultItem('mftEntrySizeBytesNTFS', 0, false);
updateResultItem('mftEntrySizeCalculationNTFS', 0, false);
}
// MFT Start Offset
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', results.mftStartOffset, 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()}`);
updateResultItem('mftStartSectorNTFS', results.mftStartSector, true,
`0x${results.mftStartOffset.toString(16).toUpperCase()} ÷ 0x${values.sectorSizeNTFS.toString(16).toUpperCase()} = 0x${results.mftStartSector.toString(16).toUpperCase()}`);
} else {
updateResultItem('mftStartOffsetNTFS', 0, false);
updateResultItem('mftStartSectorNTFS', 0, false);
}
// Specific MFT Entry Offset
if (checkDependencies(['baseOffsetNTFS', 'mftStartClusterNTFS', 'sectorSizeNTFS', 'clusterSizeSectorsNTFS', 'mftEntrySizeRawNTFS', 'mftEntryNumberNTFS'])
&& results.mftStartOffset !== undefined && results.mftEntrySizeBytes !== undefined) {
results.mftEntryOffset = results.mftStartOffset + (values.mftEntryNumberNTFS * results.mftEntrySizeBytes);
updateResultItem('mftEntryOffsetNTFS', results.mftEntryOffset, 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()}`);
// Attribute List Position (from Table A2, offset 0x14)
results.attributeListOffset = results.mftEntryOffset + 0x14;
updateResultItem('attributeListOffsetNTFS', results.attributeListOffset, true,
`0x${results.mftEntryOffset.toString(16).toUpperCase()} + 0x14 = 0x${results.attributeListOffset.toString(16).toUpperCase()}`);
} else {
updateResultItem('mftEntryOffsetNTFS', 0, false);
updateResultItem('attributeListOffsetNTFS', 0, false);
}
// Specific Cluster Offset
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', results.clusterOffset, 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()}`);
updateResultItem('clusterSectorNTFS', results.clusterSector, true,
`0x${results.clusterOffset.toString(16).toUpperCase()} ÷ 0x${values.sectorSizeNTFS.toString(16).toUpperCase()} = 0x${results.clusterSector.toString(16).toUpperCase()}`);
} else {
updateResultItem('clusterOffsetNTFS', 0, false);
updateResultItem('clusterSectorNTFS', 0, false);
}
// Partition Overview
if (checkDependencies(['partitionSizeSectorsNTFS', 'sectorSizeNTFS'])) {
results.partitionSizeBytes = values.partitionSizeSectorsNTFS * values.sectorSizeNTFS;
updateResultItem('partitionSizeBytesNTFS', results.partitionSizeBytes, 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);
}
}
}