Skip to content

Commit

Permalink
Add getLabel() to retrieve filesystem label
Browse files Browse the repository at this point in the history
Change-type: minor
Signed-off-by: Ken Bannister <[email protected]>
  • Loading branch information
kb2ma committed Jan 15, 2025
1 parent 08e921e commit 65c252a
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 8 deletions.
58 changes: 54 additions & 4 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,60 @@ export async function getLabel(
disk: Disk,
partition: partitioninfo.GPTPartition | partitioninfo.MBRPartition,
): Promise<string> {
let buf = Buffer.alloc(1024);
// Read buf.length bytes into buf starting at the beginning of the filesystem.
await disk.read(buf, 0, buf.length, partition.offset);
// If GPT, can we just read the protective MBR?
// Is there a more Typescript native way to determine partition table type?
// const isGpt = 'guid' in partition;

const label = buf.toString('utf8', 0x2B, 0x2B+11).trim();
// Linux native FS, expecting ext2+, so skip to superblock for metadata.
let metadataOffset = 0;
if (partition.type === 0x83) {
metadataOffset += 0x400;
}

// Read filesystem metadata
let buf = Buffer.alloc(0x100);
await disk.read(buf, 0, buf.length, partition.offset + metadataOffset);

let labelOffset = 0;
let maxLength = 0;
// First verify magic signature to determine metadata layout for label offset.
const fatTypes = [0xB, 0xC, 0xE];
if (fatTypes.some(ptype => partition.type === ptype)) {
maxLength = 11;
// FAT16
if (buf.readUInt8(0x26) === 0x29) {
labelOffset = 0x2B;
// FAT32
} else if (buf.readUInt8(0x42) === 0x29) {
labelOffset = 0x47;
} else {
return '';
}
} else if (partition.type === 0x83) {
maxLength = 16;
if (buf.readUInt16LE(0x38) === 0xEF53) {
labelOffset = 0x78;
} else {
return '';
}
// Unexpected partition type
} else {
return '';
}

// Identify and exclude trailing /0 bytes to stringify.
let i = 0;
for (; i <= maxLength; i++) {
// If label fills available space, no need to test. We just need i
// to have the expected value for Buffer.toString() call below.
if (i == maxLength) {
break;
}
if (buf.readUInt8(labelOffset + i) == 0) {
break;
}
}

const label = buf.toString('utf8', labelOffset, labelOffset + i).trim();
return label;
}
46 changes: 42 additions & 4 deletions tests/fsLabel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as partitioninfo from 'partitioninfo';
import * as imagefs from '../lib';

const RASPBERRYPI = Path.join(__dirname, 'images', 'raspberrypi.img');
const MBR_FAT32 = Path.join(__dirname, 'images', 'mbr-fat32.img');

async function tmpFile(): Promise<{ path: string; cleanup: () => void }> {
return await new Promise((resolve, reject) => {
Expand Down Expand Up @@ -52,7 +53,10 @@ function testWithFileCopy(
function testFileDisk(
title: string,
image: { image: string; partition: number },
fn: (label: string) => Promise<void>,
fn: (
disk: FileDisk,
partition: partitioninfo.GPTPartition | partitioninfo.MBRPartition,
) => Promise<void>,
) {
testWithFileCopy(
`${title} (filedisk)`,
Expand All @@ -61,19 +65,53 @@ function testFileDisk(
await withOpenFile(fileCopy, 'r+', async (handle) => {
const disk = new FileDisk(handle);
const partition = await partitioninfo.get(disk, image.partition);
await fn(await imagefs.getLabel(disk, partition));
await fn(disk, partition);
});
},
);
}

testFileDisk(
'should find label in MBR with FAT16 partition',
'should find label in MBR with FAT16 (0xB) partition',
{
image: RASPBERRYPI,
partition: 1,
},
async (label: string) => {
async (
disk: FileDisk,
partition: partitioninfo.GPTPartition | partitioninfo.MBRPartition,
) => {
const label = await imagefs.getLabel(disk, partition);
deepEqual(label, 'RESIN-BOOT');
},
);

testFileDisk(
'should find label in MBR with FAT32 (0xC) partition',
{
image: MBR_FAT32,
partition: 1,
},
async (
disk: FileDisk,
partition: partitioninfo.GPTPartition | partitioninfo.MBRPartition,
) => {
const label = await imagefs.getLabel(disk, partition);
deepEqual(label, 'resin-boot');
},
);

testFileDisk(
'should find label in MBR with ext4 (0x83) partition',
{
image: MBR_FAT32,
partition: 6,
},
async (
disk: FileDisk,
partition: partitioninfo.GPTPartition | partitioninfo.MBRPartition,
) => {
const label = await imagefs.getLabel(disk, partition);
deepEqual(label, 'resin-data');
},
);
Binary file added tests/images/mbr-fat32.img
Binary file not shown.

0 comments on commit 65c252a

Please sign in to comment.