Files
fscalc/webroot/js/filesystems/exfat.js
2025-11-12 21:46:24 +01:00

145 lines
9.8 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.
// exFAT filesystem implementation
import { BaseFilesystem } from './base.js';
import { checkDependencies, updateResultItem } from '../utils.js';
export class ExFATFilesystem extends BaseFilesystem {
constructor() {
super('exFAT', [
{
id: 'exfat',
name: 'exFAT',
constants: [
{ id: 'partitionStartExfat', label: 'Partitions-Start (GPT-Offset)', unit: 'Bytes', default: '0x100000' },
{ id: 'sectorSizeExfat', label: 'Sektor-Größe 2^n (Offset 0x6C)', unit: 'Bytes (2^n)', default: '0x09' },
{ id: 'clusterSizeSectorsExfat', label: 'Cluster-Größe 2^n (Offset 0x6D)', unit: 'Sektoren (2^n)', default: '0x03' },
{ id: 'numFATsExfat', label: 'Anzahl FATs (Offset 0x6E)', unit: 'Anzahl', default: '0x01' }
],
inputs: [
{ id: 'fatPositionExfat', label: 'FAT-Position (Offset 0x50)', unit: 'Sektoren', placeholder: '0x80' },
{ id: 'dataAreaPositionExfat', label: 'Daten-Bereich Position (Offset 0x58)', unit: 'Sektoren', placeholder: '0x90' },
{ id: 'rootDirClusterExfat', label: 'Wurzelverzeichnis Cluster (Offset 0x60)', unit: 'Cluster', placeholder: '0x05' },
{ id: 'clusterNumberExfat', label: 'Cluster-Nummer', unit: 'Nummer', placeholder: '0x05' }
],
resultGroups: [
{
name: 'Boot-Struktur',
results: [
{ id: 'backupBootExfat', label: 'Backup Boot-Sektor', dependencies: ['partitionStartExfat'], formula: 'Partitions-Start + (12 Sektoren × Sektorgröße)' }
]
},
{
name: 'FAT-Bereich',
results: [
{ id: 'fatStartExfat', label: 'FAT-Bereich Anfang', dependencies: ['partitionStartExfat', 'fatPositionExfat', 'sectorSizeExfat'], formula: 'Partitions-Start + (FAT-Position × Sektorgröße)' },
{ id: 'dataAreaStartExfat', label: 'Daten-Bereich Anfang', dependencies: ['partitionStartExfat', 'dataAreaPositionExfat', 'sectorSizeExfat'], formula: 'Partitions-Start + (Daten-Position × Sektorgröße)' }
]
},
{
name: 'Cluster-Berechnungen',
results: [
{ id: 'clusterSizeBytesExfat', label: 'Cluster-Größe (Bytes)', dependencies: ['sectorSizeExfat', 'clusterSizeSectorsExfat'], formula: '2^Sektor-Größe × 2^Cluster-Größe' },
{ id: 'rootDirOffsetExfat', label: 'Wurzelverzeichnis Offset', dependencies: ['partitionStartExfat', 'dataAreaPositionExfat', 'sectorSizeExfat', 'clusterSizeSectorsExfat', 'rootDirClusterExfat'], formula: 'Daten-Bereich + (Cluster - 2) × Cluster-Größe' },
{ id: 'clusterOffsetExfat', label: 'Spezifischer Cluster Offset', dependencies: ['partitionStartExfat', 'dataAreaPositionExfat', 'sectorSizeExfat', 'clusterSizeSectorsExfat', 'clusterNumberExfat'], formula: 'Daten-Bereich + (Cluster - 2) × Cluster-Größe' },
{ id: 'fatEntryOffsetExfat', label: 'FAT-Eintrag Offset', dependencies: ['partitionStartExfat', 'fatPositionExfat', 'sectorSizeExfat', 'clusterNumberExfat'], formula: 'FAT-Start + (Cluster × 4)' }
]
}
],
formulas: [
{ name: 'Backup Boot-Sektor', expression: 'Partitions-Start + (12 × Sektorgröße)' },
{ name: 'Sektorgröße (Bytes)', expression: '2^n (aus Offset 0x6C)' },
{ name: 'Cluster-Größe (Sektoren)', expression: '2^n (aus Offset 0x6D)' },
{ name: 'Cluster-Größe (Bytes)', expression: 'Sektorgröße × Cluster-Größe (Sektoren)' },
{ name: 'FAT-Bereich Anfang', expression: 'Partitions-Start + (FAT-Position × Sektorgröße)' },
{ name: 'Daten-Bereich Anfang', expression: 'Partitions-Start + (Daten-Position × Sektorgröße)' },
{ name: 'Wurzelverzeichnis Offset', expression: 'Daten-Bereich + ((Cluster - 2) × Cluster-Größe)' },
{ name: 'Cluster Offset', expression: 'Daten-Bereich + ((Cluster-Nummer - 2) × Cluster-Größe)' },
{ name: 'FAT-Eintrag Offset', expression: 'FAT-Start + (Cluster-Nummer × 4)' }
]
}
]);
}
calculate(variantId) {
if (variantId !== 'exfat') return;
const values = this.getInputValues(variantId);
const results = {};
this.calculateExFAT(values, results);
}
calculateExFAT(values, results) {
// Calculate actual sector size from 2^n
const sectorSize = Math.pow(2, values.sectorSizeExfat);
// Calculate actual cluster size in sectors from 2^n
const clusterSizeSectors = Math.pow(2, values.clusterSizeSectorsExfat);
// Backup Boot-Sektor (12 sectors after partition start)
if (checkDependencies(['partitionStartExfat'])) {
results.backupBoot = values.partitionStartExfat + (12 * sectorSize);
updateResultItem('backupBootExfat', results.backupBoot, true,
`0x${values.partitionStartExfat.toString(16)} + (12 × 0x${sectorSize.toString(16)}) = 0x${results.backupBoot.toString(16)}`);
} else {
updateResultItem('backupBootExfat', 0, false);
}
// FAT-Bereich Anfang
if (checkDependencies(['partitionStartExfat', 'fatPositionExfat', 'sectorSizeExfat'])) {
results.fatStart = values.partitionStartExfat + (values.fatPositionExfat * sectorSize);
results.fatStartSector = values.fatPositionExfat;
updateResultItem('fatStartExfat', { bytes: results.fatStart, sectors: results.fatStartSector }, true,
`0x${values.partitionStartExfat.toString(16)} + (0x${values.fatPositionExfat.toString(16)} × 0x${sectorSize.toString(16)}) = 0x${results.fatStart.toString(16)}`);
} else {
updateResultItem('fatStartExfat', 0, false);
}
// Daten-Bereich Anfang
if (checkDependencies(['partitionStartExfat', 'dataAreaPositionExfat', 'sectorSizeExfat'])) {
results.dataAreaStart = values.partitionStartExfat + (values.dataAreaPositionExfat * sectorSize);
results.dataAreaStartSector = values.dataAreaPositionExfat;
updateResultItem('dataAreaStartExfat', { bytes: results.dataAreaStart, sectors: results.dataAreaStartSector }, true,
`0x${values.partitionStartExfat.toString(16)} + (0x${values.dataAreaPositionExfat.toString(16)} × 0x${sectorSize.toString(16)}) = 0x${results.dataAreaStart.toString(16)}`);
} else {
updateResultItem('dataAreaStartExfat', 0, false);
}
// Cluster-Größe in Bytes
if (checkDependencies(['sectorSizeExfat', 'clusterSizeSectorsExfat'])) {
results.clusterSizeBytes = sectorSize * clusterSizeSectors;
updateResultItem('clusterSizeBytesExfat', results.clusterSizeBytes, true,
`2^${values.sectorSizeExfat} × 2^${values.clusterSizeSectorsExfat} = 0x${sectorSize.toString(16)} × 0x${clusterSizeSectors.toString(16)} = 0x${results.clusterSizeBytes.toString(16)}`);
} else {
updateResultItem('clusterSizeBytesExfat', 0, false);
}
// Wurzelverzeichnis Offset (beachtet Index-Verschiebung von -2)
if (checkDependencies(['partitionStartExfat', 'dataAreaPositionExfat', 'sectorSizeExfat', 'clusterSizeSectorsExfat', 'rootDirClusterExfat']) && results.dataAreaStart !== undefined && results.clusterSizeBytes !== undefined) {
results.rootDirOffset = results.dataAreaStart + ((values.rootDirClusterExfat - 2) * results.clusterSizeBytes);
updateResultItem('rootDirOffsetExfat', results.rootDirOffset, true,
`0x${results.dataAreaStart.toString(16)} + ((0x${values.rootDirClusterExfat.toString(16)} - 0x2) × 0x${results.clusterSizeBytes.toString(16)}) = 0x${results.rootDirOffset.toString(16)}`);
} else {
updateResultItem('rootDirOffsetExfat', 0, false);
}
// Spezifischer Cluster Offset (beachtet Index-Verschiebung von -2)
if (checkDependencies(['partitionStartExfat', 'dataAreaPositionExfat', 'sectorSizeExfat', 'clusterSizeSectorsExfat', 'clusterNumberExfat']) && results.dataAreaStart !== undefined && results.clusterSizeBytes !== undefined) {
results.clusterOffset = results.dataAreaStart + ((values.clusterNumberExfat - 2) * results.clusterSizeBytes);
updateResultItem('clusterOffsetExfat', results.clusterOffset, true,
`0x${results.dataAreaStart.toString(16)} + ((0x${values.clusterNumberExfat.toString(16)} - 0x2) × 0x${results.clusterSizeBytes.toString(16)}) = 0x${results.clusterOffset.toString(16)}`);
} else {
updateResultItem('clusterOffsetExfat', 0, false);
}
// FAT-Eintrag Offset (32-Bit = 4 Bytes pro Eintrag)
if (checkDependencies(['partitionStartExfat', 'fatPositionExfat', 'sectorSizeExfat', 'clusterNumberExfat']) && results.fatStart !== undefined) {
const entrySize = 4; // exFAT uses 4 bytes (32-bit) per FAT entry
results.fatEntryOffset = results.fatStart + (values.clusterNumberExfat * entrySize);
updateResultItem('fatEntryOffsetExfat', results.fatEntryOffset, true,
`0x${results.fatStart.toString(16)} + (0x${values.clusterNumberExfat.toString(16)} × ${entrySize}) = 0x${results.fatEntryOffset.toString(16)}`);
} else {
updateResultItem('fatEntryOffsetExfat', 0, false);
}
}
}