part_blk: add minimal file system probing

For now it is enough to differentiate the most commonly used file
system on Genode, e.g. Ext2 for the Genode partition and FAT32 for
(U)EFI partitions.

Issue #2803.
This commit is contained in:
Josef Söntgen 2018-05-03 15:34:08 +02:00 committed by Christian Helmuth
parent 9f8369c01e
commit 40a0fe9349
3 changed files with 122 additions and 0 deletions

View File

@ -0,0 +1,104 @@
/*
* \brief Poor man's partition probe for known file system
* \author Josef Soentgen
* \date 2018-05-03
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _PART_BLK__FSPROBE_H_
#define _PART_BLK__FSPROBE_H_
/* Genode includes */
#include <base/env.h>
#include <base/log.h>
namespace Fs {
using namespace Genode;
using Type = Genode::String<32>;
Type probe(uint8_t *buffer, size_t len);
/**
* Probe for Ext2/3/4
*/
Type _probe_extfs(uint8_t *p, size_t len)
{
if (len < 4096) { return Type(); }
/* super block starts a byte offset 1024 */
p += 0x400;
bool const found_ext_sig = p[0x38] == 0x53 && p[0x39] == 0xEF;
enum {
COMPAT_HAS_JOURNAL = 0x004u,
INCOMPAT_EXTENTS = 0x040u,
RO_COMPAT_METADATA_CSUM = 0x400u,
};
uint32_t const compat = *(uint32_t*)(p + 0x5C);
uint32_t const incompat = *(uint32_t*)(p + 0x60);
uint32_t const ro_compat = *(uint32_t*)(p + 0x64);
/* the feature flags should denote a given Ext version */
bool const ext3 = compat & COMPAT_HAS_JOURNAL;
bool const ext4 = ext3 && ((incompat & INCOMPAT_EXTENTS)
&& (ro_compat & RO_COMPAT_METADATA_CSUM));
if (found_ext_sig && ext4) { return Type("Ext4"); }
else if (found_ext_sig && ext3) { return Type("Ext3"); }
else if (found_ext_sig) { return Type("Ext2"); }
return Type();
}
/**
* Probe for FAT16/32
*/
Type _probe_fatfs(uint8_t *p, size_t len)
{
if (len < 512) { return Type(); }
/* at least the checks ring true when mkfs.vfat is used... */
bool const found_boot_sig = p[510] == 0x55 && p[511] == 0xAA;
bool const fat16 = p[38] == 0x28 || p[38] == 0x29;
bool const fat32 = (p[66] == 0x28 || p[66] == 0x29)
&& (p[82] == 'F' && p[83] == 'A');
if (found_boot_sig && fat32) { return Type("FAT32"); }
if (found_boot_sig && fat16) { return Type("FAT16"); }
return Type();
}
}
Fs::Type Fs::probe(uint8_t *p, size_t len)
{
/* Ext2/3/4 */
{
Type t = _probe_extfs(p, len);
if (t.valid()) { return t; }
}
/* FAT16/32 */
{
Type t = _probe_fatfs(p, len);
if (t.valid()) { return t; }
}
return Type();
}
#endif /* _PART_BLK__FSPROBE_H_ */

View File

@ -20,6 +20,7 @@
#include "driver.h"
#include "partition_table.h"
#include "fsprobe.h"
namespace {
@ -265,6 +266,10 @@ class Gpt : public Block::Partition_table
continue;
}
enum { BYTES = 4096, };
Sector fs(driver, e->_lba_start, BYTES / driver.blk_size());
Fs::Type fs_type = Fs::probe(fs.addr<Genode::uint8_t*>(), BYTES);
xml.node("partition", [&] () {
xml.attribute("number", i + 1);
xml.attribute("name", e->name());
@ -272,6 +277,9 @@ class Gpt : public Block::Partition_table
xml.attribute("guid", e->_guid.to_string());
xml.attribute("start", e->_lba_start);
xml.attribute("length", e->_lba_end - e->_lba_start + 1);
if (fs_type.valid()) {
xml.attribute("file_system", fs_type);
}
});
}
});

View File

@ -21,6 +21,7 @@
#include <block_session/client.h>
#include "partition_table.h"
#include "fsprobe.h"
struct Mbr_partition_table : public Block::Partition_table
@ -165,11 +166,20 @@ struct Mbr_partition_table : public Block::Partition_table
xml.attribute("type", "mbr");
_parse_mbr(mbr, [&] (int i, Partition_record *r, unsigned offset) {
enum { BYTES = 4096, };
Sector fs(driver, r->_lba + offset, BYTES / driver.blk_size());
Fs::Type fs_type = Fs::probe(fs.addr<Genode::uint8_t*>(), BYTES);
xml.node("partition", [&] {
xml.attribute("number", i);
xml.attribute("type", r->_type);
xml.attribute("start", r->_lba + offset);
xml.attribute("length", r->_sectors);
if (fs_type.valid()) {
xml.attribute("file_system", fs_type);
}
});
});
});