diff --git a/lib/index.ts b/lib/index.ts index 3db10f3..4eba200 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -223,10 +223,60 @@ export async function getLabel( disk: Disk, partition: partitioninfo.GPTPartition | partitioninfo.MBRPartition, ): Promise { - 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; } diff --git a/tests/fsLabel.ts b/tests/fsLabel.ts index 4edc149..ea4f6af 100644 --- a/tests/fsLabel.ts +++ b/tests/fsLabel.ts @@ -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) => { @@ -52,7 +53,10 @@ function testWithFileCopy( function testFileDisk( title: string, image: { image: string; partition: number }, - fn: (label: string) => Promise, + fn: ( + disk: FileDisk, + partition: partitioninfo.GPTPartition | partitioninfo.MBRPartition, + ) => Promise, ) { testWithFileCopy( `${title} (filedisk)`, @@ -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'); + }, +); diff --git a/tests/images/mbr-fat32.img b/tests/images/mbr-fat32.img new file mode 100644 index 0000000..56eb403 Binary files /dev/null and b/tests/images/mbr-fat32.img differ