Files
fscalc/webroot/js/filesystems/ext.js
2025-12-07 16:02:57 +01:00

259 lines
18 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.
// EXT filesystem implementation (ext2/ext3/ext4)
import { BaseFilesystem } from './base.js';
import { checkDependencies, updateResultItem } from '../utils.js';
export class EXTFilesystem extends BaseFilesystem {
constructor() {
super('EXT', [
{
id: 'ext',
name: 'EXT (ext2/ext3/ext4)',
constants: [
{ id: 'partitionStartEXT', label: 'Partitionsstart (Basis-Offset)', unit: 'Bytes', default: '0x0' },
{ id: 'superblockOffsetEXT', label: 'Superblock-Offset (relativ zur Partition)', unit: 'Bytes', default: '0x400' }
],
inputs: [
{ id: 'blockSizeExpEXT', label: 'Block-Größe Exponent (Offset 0x418)', unit: 'Exponent n', placeholder: '0x0' },
{ id: 'blocksPerGroupEXT', label: 'Blöcke pro Blockgruppe (Offset 0x420)', unit: 'Anzahl', placeholder: '0x8000' },
{ id: 'inodesPerGroupEXT', label: 'Inodes pro Blockgruppe (Offset 0x428)', unit: 'Anzahl', placeholder: '0x2000' },
{ id: 'inodeSizeEXT', label: 'Inode-Größe (Offset 0x458)', unit: 'Bytes', placeholder: '0x100' },
{ id: 'totalBlocksEXT', label: 'Gesamtanzahl Blöcke (Offset 0x404)', unit: 'Anzahl', placeholder: '0x40000' },
{ id: 'groupDescSizeEXT', label: 'Größe Gruppendeskriptor (Offset 0x4FE)', unit: 'Bytes', placeholder: '0x20' },
{ id: 'inodeTableBlockGroupEXT', label: 'Inode-Tabelle Block (aus GDT, Offset 0x08)', unit: 'Block-Nummer', placeholder: '0x21' },
{ id: 'targetInodeEXT', label: 'Gesuchter Inode', unit: 'Nummer', placeholder: '0x02' },
{ id: 'targetBlockEXT', label: 'Gesuchter Block', unit: 'Nummer', placeholder: '0x100' },
{ id: 'blockgroupNumberEXT', label: 'Blockgruppen-Nummer', unit: 'Nummer', placeholder: '0x0' }
],
resultGroups: [
{
name: 'Basis-Berechnungen',
results: [
{ id: 'superblockPosEXT', label: 'Superblock Position', dependencies: ['partitionStartEXT', 'superblockOffsetEXT'], formula: 'Partitionsstart + 0x400' },
{ id: 'blockSizeBytesEXT', label: 'Block-Größe (Bytes)', dependencies: ['blockSizeExpEXT'], formula: '2^(10+n) Bytes' },
{ id: 'totalBlockgroupsEXT', label: 'Anzahl Blockgruppen', dependencies: ['totalBlocksEXT', 'blocksPerGroupEXT'], formula: 'Aufrunden(Gesamtblöcke ÷ Blöcke pro Gruppe)' }
]
},
{
name: 'Gruppendeskriptor-Tabelle',
results: [
{ id: 'gdtStartEXT', label: 'GDT Start', dependencies: ['partitionStartEXT', 'superblockOffsetEXT', 'blockSizeExpEXT'], formula: 'Partitionsstart + Block nach Superblock' },
{ id: 'gdtBlockgroupOffsetEXT', label: 'GDT-Eintrag für Blockgruppe', dependencies: ['partitionStartEXT', 'superblockOffsetEXT', 'blockSizeExpEXT', 'blockgroupNumberEXT', 'groupDescSizeEXT'], formula: 'GDT Start + (Blockgruppe × GD-Größe)' }
]
},
{
name: 'Inode-Berechnungen',
results: [
{ id: 'inodeBlockgroupEXT', label: 'Blockgruppe des Inodes', dependencies: ['targetInodeEXT', 'inodesPerGroupEXT'], formula: 'Abrunden((Inode - 1) ÷ Inodes pro Gruppe)' },
{ id: 'inodeRelativeIndexEXT', label: 'Relativer Index in Blockgruppe', dependencies: ['targetInodeEXT', 'inodesPerGroupEXT'], formula: '(Inode - 1) % Inodes pro Gruppe' },
{ id: 'inodeTableStartEXT', label: 'Inode-Tabelle Start', dependencies: ['partitionStartEXT', 'inodeTableBlockGroupEXT', 'blockSizeExpEXT'], formula: 'Partitionsstart + (Block × Block-Größe)' },
{ id: 'inodeOffsetEXT', label: 'Inode Offset', dependencies: ['partitionStartEXT', 'inodeTableBlockGroupEXT', 'blockSizeExpEXT', 'targetInodeEXT', 'inodesPerGroupEXT', 'inodeSizeEXT'], formula: 'Inode-Tabelle Start + (Relativer Index × Inode-Größe)' }
]
},
{
name: 'Block-Berechnungen',
results: [
{ id: 'blockOffsetEXT', label: 'Block Offset', dependencies: ['partitionStartEXT', 'targetBlockEXT', 'blockSizeExpEXT'], formula: 'Partitionsstart + (Block-Nummer × Block-Größe)' }
]
},
{
name: 'Reservierte Inodes (Systemdateien)',
results: [
{ id: 'badBlocksInodeEXT', label: 'Inode 1 - Beschädigte Blöcke', dependencies: ['partitionStartEXT', 'inodeTableBlockGroupEXT', 'blockSizeExpEXT', 'inodeSizeEXT'], formula: 'Inode-Tabelle Start + (0 × Inode-Größe)' },
{ id: 'rootDirInodeEXT', label: 'Inode 2 - Wurzelverzeichnis', dependencies: ['partitionStartEXT', 'inodeTableBlockGroupEXT', 'blockSizeExpEXT', 'inodeSizeEXT'], formula: 'Inode-Tabelle Start + (1 × Inode-Größe)' },
{ id: 'userQuotaInodeEXT', label: 'Inode 3 - Benutzer-Quotas', dependencies: ['partitionStartEXT', 'inodeTableBlockGroupEXT', 'blockSizeExpEXT', 'inodeSizeEXT'], formula: 'Inode-Tabelle Start + (2 × Inode-Größe)' },
{ id: 'groupQuotaInodeEXT', label: 'Inode 4 - Gruppen-Quotas', dependencies: ['partitionStartEXT', 'inodeTableBlockGroupEXT', 'blockSizeExpEXT', 'inodeSizeEXT'], formula: 'Inode-Tabelle Start + (3 × Inode-Größe)' },
{ id: 'bootloaderInodeEXT', label: 'Inode 5 - Bootloader', dependencies: ['partitionStartEXT', 'inodeTableBlockGroupEXT', 'blockSizeExpEXT', 'inodeSizeEXT'], formula: 'Inode-Tabelle Start + (4 × Inode-Größe)' },
{ id: 'journalInodeEXT', label: 'Inode 8 - Journal (ext3/ext4)', dependencies: ['partitionStartEXT', 'inodeTableBlockGroupEXT', 'blockSizeExpEXT', 'inodeSizeEXT'], formula: 'Inode-Tabelle Start + (7 × Inode-Größe)' }
]
},
{
name: 'Inode-Tabellen-Übersicht',
results: [
{ id: 'inodeTableSizeEXT', label: 'Inode-Tabelle Größe (Bytes)', dependencies: ['inodesPerGroupEXT', 'inodeSizeEXT'], formula: 'Inodes pro Gruppe × Inode-Größe' },
{ id: 'inodeTableSizeBlocksEXT', label: 'Inode-Tabelle Größe (Blöcke)', dependencies: ['inodesPerGroupEXT', 'inodeSizeEXT', 'blockSizeExpEXT'], formula: 'Aufrunden(Tabellengröße ÷ Block-Größe)' }
]
}
],
formulas: [
{ name: 'Superblock Position', expression: 'Partitionsstart + 0x400 (immer fix bei Offset 0x400)' },
{ name: 'Block-Größe', expression: '2^(10+n) Bytes, wobei n der Exponent aus Offset 0x418 ist (0 = 1024, 1 = 2048, 2 = 4096, etc.)' },
{ name: 'Anzahl Blockgruppen', expression: 'Aufrunden(Gesamtanzahl Blöcke ÷ Blöcke pro Blockgruppe)' },
{ name: 'GDT Start', expression: 'Partitionsstart + (Block nach Superblock × Block-Größe)' },
{ name: 'GDT-Eintrag Offset', expression: 'GDT Start + (Blockgruppen-Nummer × Gruppendeskriptor-Größe)' },
{ name: 'Blockgruppe des Inodes', expression: 'Abrunden((Inode-Nummer - 1) ÷ Inodes pro Blockgruppe)' },
{ name: 'Relativer Index', expression: '(Inode-Nummer - 1) % Inodes pro Blockgruppe' },
{ name: 'Inode-Tabelle Start', expression: 'Partitionsstart + (Inode-Tabelle Block-Nummer × Block-Größe)' },
{ name: 'Inode Offset', expression: 'Inode-Tabelle Start + (Relativer Index × Inode-Größe)' },
{ name: 'Block Offset', expression: 'Partitionsstart + (Block-Nummer × Block-Größe)' },
{ name: 'Reservierte Inodes', expression: 'Inode-Tabelle Start + ((Inode-Nummer - 1) × Inode-Größe)' },
{ name: 'Inode-Tabelle Größe', expression: 'Inodes pro Blockgruppe × Inode-Größe' }
]
}
]);
}
calculate(variantId) {
if (variantId !== 'ext') return;
const values = this.getInputValues(variantId);
const results = {};
this.calculateEXT(values, results);
}
calculateEXT(values, results) {
// Superblock Position
if (checkDependencies(['partitionStartEXT', 'superblockOffsetEXT'])) {
results.superblockPos = values.partitionStartEXT + values.superblockOffsetEXT;
updateResultItem('superblockPosEXT', results.superblockPos, true,
`0x${values.partitionStartEXT.toString(16)} + 0x${values.superblockOffsetEXT.toString(16)} = 0x${results.superblockPos.toString(16)}`);
} else {
updateResultItem('superblockPosEXT', 0, false);
}
// Block Size (2^(10+n))
if (checkDependencies(['blockSizeExpEXT'])) {
results.blockSize = Math.pow(2, 10 + values.blockSizeExpEXT);
updateResultItem('blockSizeBytesEXT', results.blockSize, true,
`2^(10 + ${values.blockSizeExpEXT}) = 2^${10 + values.blockSizeExpEXT} = 0x${results.blockSize.toString(16)} (${results.blockSize} Bytes)`);
} else {
updateResultItem('blockSizeBytesEXT', 0, false);
}
// Total Blockgroups
if (checkDependencies(['totalBlocksEXT', 'blocksPerGroupEXT'])) {
results.totalBlockgroups = Math.ceil(values.totalBlocksEXT / values.blocksPerGroupEXT);
updateResultItem('totalBlockgroupsEXT', results.totalBlockgroups, true,
`Aufrunden(0x${values.totalBlocksEXT.toString(16)} ÷ 0x${values.blocksPerGroupEXT.toString(16)}) = ${results.totalBlockgroups}`);
} else {
updateResultItem('totalBlockgroupsEXT', 0, false);
}
// GDT Start (block after superblock)
if (checkDependencies(['partitionStartEXT', 'superblockOffsetEXT', 'blockSizeExpEXT']) && results.blockSize !== undefined) {
// If block size is 1024 (0x400), superblock is in block 1, GDT starts at block 2
// Otherwise, superblock is in block 0, GDT starts at block 1
const superblockBlock = (results.blockSize === 1024) ? 1 : 0;
const gdtBlock = superblockBlock + 1;
results.gdtStart = values.partitionStartEXT + (gdtBlock * results.blockSize);
updateResultItem('gdtStartEXT', results.gdtStart, true,
`0x${values.partitionStartEXT.toString(16)} + (Block ${gdtBlock} × 0x${results.blockSize.toString(16)}) = 0x${results.gdtStart.toString(16)}`);
} else {
updateResultItem('gdtStartEXT', 0, false);
}
// GDT Entry for specific Blockgroup
if (checkDependencies(['blockgroupNumberEXT', 'groupDescSizeEXT']) && results.gdtStart !== undefined) {
results.gdtBlockgroupOffset = results.gdtStart + (values.blockgroupNumberEXT * values.groupDescSizeEXT);
updateResultItem('gdtBlockgroupOffsetEXT', results.gdtBlockgroupOffset, true,
`0x${results.gdtStart.toString(16)} + (0x${values.blockgroupNumberEXT.toString(16)} × 0x${values.groupDescSizeEXT.toString(16)}) = 0x${results.gdtBlockgroupOffset.toString(16)}`);
} else {
updateResultItem('gdtBlockgroupOffsetEXT', 0, false);
}
// Inode Blockgroup
if (checkDependencies(['targetInodeEXT', 'inodesPerGroupEXT'])) {
results.inodeBlockgroup = Math.floor((values.targetInodeEXT - 1) / values.inodesPerGroupEXT);
updateResultItem('inodeBlockgroupEXT', results.inodeBlockgroup, true,
`Abrunden((0x${values.targetInodeEXT.toString(16)} - 1) ÷ 0x${values.inodesPerGroupEXT.toString(16)}) = ${results.inodeBlockgroup}`);
} else {
updateResultItem('inodeBlockgroupEXT', 0, false);
}
// Inode Relative Index
if (checkDependencies(['targetInodeEXT', 'inodesPerGroupEXT'])) {
results.inodeRelativeIndex = (values.targetInodeEXT - 1) % values.inodesPerGroupEXT;
updateResultItem('inodeRelativeIndexEXT', results.inodeRelativeIndex, true,
`(0x${values.targetInodeEXT.toString(16)} - 1) % 0x${values.inodesPerGroupEXT.toString(16)} = 0x${results.inodeRelativeIndex.toString(16)}`);
} else {
updateResultItem('inodeRelativeIndexEXT', 0, false);
}
// Inode Table Start
if (checkDependencies(['partitionStartEXT', 'inodeTableBlockGroupEXT', 'blockSizeExpEXT']) && results.blockSize !== undefined) {
results.inodeTableStart = values.partitionStartEXT + (values.inodeTableBlockGroupEXT * results.blockSize);
updateResultItem('inodeTableStartEXT', results.inodeTableStart, true,
`0x${values.partitionStartEXT.toString(16)} + (0x${values.inodeTableBlockGroupEXT.toString(16)} × 0x${results.blockSize.toString(16)}) = 0x${results.inodeTableStart.toString(16)}`);
} else {
updateResultItem('inodeTableStartEXT', 0, false);
}
// Inode Offset
if (checkDependencies(['targetInodeEXT', 'inodesPerGroupEXT', 'inodeSizeEXT']) && results.inodeTableStart !== undefined && results.inodeRelativeIndex !== undefined) {
results.inodeOffset = results.inodeTableStart + (results.inodeRelativeIndex * values.inodeSizeEXT);
updateResultItem('inodeOffsetEXT', results.inodeOffset, true,
`0x${results.inodeTableStart.toString(16)} + (0x${results.inodeRelativeIndex.toString(16)} × 0x${values.inodeSizeEXT.toString(16)}) = 0x${results.inodeOffset.toString(16)}`);
} else {
updateResultItem('inodeOffsetEXT', 0, false);
}
// Block Offset
if (checkDependencies(['partitionStartEXT', 'targetBlockEXT', 'blockSizeExpEXT']) && results.blockSize !== undefined) {
results.blockOffset = values.partitionStartEXT + (values.targetBlockEXT * results.blockSize);
updateResultItem('blockOffsetEXT', results.blockOffset, true,
`0x${values.partitionStartEXT.toString(16)} + (0x${values.targetBlockEXT.toString(16)} × 0x${results.blockSize.toString(16)}) = 0x${results.blockOffset.toString(16)}`);
} else {
updateResultItem('blockOffsetEXT', 0, false);
}
// Reserved Inodes (always in blockgroup 0, inode table)
if (results.inodeTableStart !== undefined && checkDependencies(['inodeSizeEXT'])) {
// Inode 1 (Bad Blocks) - Index 0
results.badBlocksInode = results.inodeTableStart + (0 * values.inodeSizeEXT);
updateResultItem('badBlocksInodeEXT', results.badBlocksInode, true,
`0x${results.inodeTableStart.toString(16)} + (0 × 0x${values.inodeSizeEXT.toString(16)}) = 0x${results.badBlocksInode.toString(16)}`);
// Inode 2 (Root Directory) - Index 1
results.rootDirInode = results.inodeTableStart + (1 * values.inodeSizeEXT);
updateResultItem('rootDirInodeEXT', results.rootDirInode, true,
`0x${results.inodeTableStart.toString(16)} + (1 × 0x${values.inodeSizeEXT.toString(16)}) = 0x${results.rootDirInode.toString(16)}`);
// Inode 3 (User Quotas) - Index 2
results.userQuotaInode = results.inodeTableStart + (2 * values.inodeSizeEXT);
updateResultItem('userQuotaInodeEXT', results.userQuotaInode, true,
`0x${results.inodeTableStart.toString(16)} + (2 × 0x${values.inodeSizeEXT.toString(16)}) = 0x${results.userQuotaInode.toString(16)}`);
// Inode 4 (Group Quotas) - Index 3
results.groupQuotaInode = results.inodeTableStart + (3 * values.inodeSizeEXT);
updateResultItem('groupQuotaInodeEXT', results.groupQuotaInode, true,
`0x${results.inodeTableStart.toString(16)} + (3 × 0x${values.inodeSizeEXT.toString(16)}) = 0x${results.groupQuotaInode.toString(16)}`);
// Inode 5 (Bootloader) - Index 4
results.bootloaderInode = results.inodeTableStart + (4 * values.inodeSizeEXT);
updateResultItem('bootloaderInodeEXT', results.bootloaderInode, true,
`0x${results.inodeTableStart.toString(16)} + (4 × 0x${values.inodeSizeEXT.toString(16)}) = 0x${results.bootloaderInode.toString(16)}`);
// Inode 8 (Journal) - Index 7
results.journalInode = results.inodeTableStart + (7 * values.inodeSizeEXT);
updateResultItem('journalInodeEXT', results.journalInode, true,
`0x${results.inodeTableStart.toString(16)} + (7 × 0x${values.inodeSizeEXT.toString(16)}) = 0x${results.journalInode.toString(16)}`);
} else {
updateResultItem('badBlocksInodeEXT', 0, false);
updateResultItem('rootDirInodeEXT', 0, false);
updateResultItem('userQuotaInodeEXT', 0, false);
updateResultItem('groupQuotaInodeEXT', 0, false);
updateResultItem('bootloaderInodeEXT', 0, false);
updateResultItem('journalInodeEXT', 0, false);
}
// Inode Table Size (Bytes)
if (checkDependencies(['inodesPerGroupEXT', 'inodeSizeEXT'])) {
results.inodeTableSize = values.inodesPerGroupEXT * values.inodeSizeEXT;
updateResultItem('inodeTableSizeEXT', results.inodeTableSize, true,
`0x${values.inodesPerGroupEXT.toString(16)} × 0x${values.inodeSizeEXT.toString(16)} = 0x${results.inodeTableSize.toString(16)} (${results.inodeTableSize} Bytes)`);
} else {
updateResultItem('inodeTableSizeEXT', 0, false);
}
// Inode Table Size (Blocks)
if (checkDependencies(['inodesPerGroupEXT', 'inodeSizeEXT', 'blockSizeExpEXT']) && results.blockSize !== undefined && results.inodeTableSize !== undefined) {
results.inodeTableSizeBlocks = Math.ceil(results.inodeTableSize / results.blockSize);
updateResultItem('inodeTableSizeBlocksEXT', results.inodeTableSizeBlocks, true,
`Aufrunden(0x${results.inodeTableSize.toString(16)} ÷ 0x${results.blockSize.toString(16)}) = ${results.inodeTableSizeBlocks} Blöcke`);
} else {
updateResultItem('inodeTableSizeBlocksEXT', 0, false);
}
}
}