From: Rafał Miłecki Date: Mon, 25 Dec 2017 19:52:11 +0000 (+0100) Subject: libblkid-tiny: add support for NTFS superblock X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=bdeb95a849913bfe2c0eff5d03857c79a4c7d66d;p=oweals%2Ffstools.git libblkid-tiny: add support for NTFS superblock Its copied from the util-linux project and its libblkid. Call to the blkid_probe_set_utf8label was commented out due to libblkid-tiny not supporting it yet. Signed-off-by: Rafał Miłecki Acked-by: John Crispin --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 8752612..9e855bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,7 @@ ADD_LIBRARY(blkid-tiny SHARED libblkid-tiny/ext.c libblkid-tiny/jffs2.c libblkid-tiny/vfat.c + libblkid-tiny/ntfs.c libblkid-tiny/hfs.c libblkid-tiny/swap.c libblkid-tiny/ubi.c diff --git a/libblkid-tiny/libblkid-tiny.c b/libblkid-tiny/libblkid-tiny.c index 352d1f6..f020e23 100644 --- a/libblkid-tiny/libblkid-tiny.c +++ b/libblkid-tiny/libblkid-tiny.c @@ -162,6 +162,7 @@ static const struct blkid_idinfo *idinfos[] = &ext3_idinfo, &ext2_idinfo, &jbd_idinfo, + &ntfs_idinfo, &squashfs_idinfo, &ubi_idinfo, &ubifs_idinfo, diff --git a/libblkid-tiny/ntfs.c b/libblkid-tiny/ntfs.c new file mode 100644 index 0000000..93c1d88 --- /dev/null +++ b/libblkid-tiny/ntfs.c @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2004 Kay Sievers + * Copyright (C) 2008 Karel Zak + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include +#include +#include +#include +#include + +#include "superblocks.h" + +struct ntfs_bios_parameters { + uint16_t sector_size; /* Size of a sector in bytes. */ + uint8_t sectors_per_cluster; /* Size of a cluster in sectors. */ + uint16_t reserved_sectors; /* zero */ + uint8_t fats; /* zero */ + uint16_t root_entries; /* zero */ + uint16_t sectors; /* zero */ + uint8_t media_type; /* 0xf8 = hard disk */ + uint16_t sectors_per_fat; /* zero */ + uint16_t sectors_per_track; /* irrelevant */ + uint16_t heads; /* irrelevant */ + uint32_t hidden_sectors; /* zero */ + uint32_t large_sectors; /* zero */ +} __attribute__ ((__packed__)); + +struct ntfs_super_block { + uint8_t jump[3]; + uint8_t oem_id[8]; /* magic string */ + + struct ntfs_bios_parameters bpb; + + uint16_t unused[2]; + uint64_t number_of_sectors; + uint64_t mft_cluster_location; + uint64_t mft_mirror_cluster_location; + int8_t clusters_per_mft_record; + uint8_t reserved1[3]; + int8_t cluster_per_index_record; + uint8_t reserved2[3]; + uint64_t volume_serial; + uint32_t checksum; +} __attribute__((packed)); + +struct master_file_table_record { + uint32_t magic; + uint16_t usa_ofs; + uint16_t usa_count; + uint64_t lsn; + uint16_t sequence_number; + uint16_t link_count; + uint16_t attrs_offset; + uint16_t flags; + uint32_t bytes_in_use; + uint32_t bytes_allocated; +} __attribute__((__packed__)); + +struct file_attribute { + uint32_t type; + uint32_t len; + uint8_t non_resident; + uint8_t name_len; + uint16_t name_offset; + uint16_t flags; + uint16_t instance; + uint32_t value_len; + uint16_t value_offset; +} __attribute__((__packed__)); + +#define MFT_RECORD_VOLUME 3 +#define NTFS_MAX_CLUSTER_SIZE (64 * 1024) + +enum { + MFT_RECORD_ATTR_VOLUME_NAME = 0x60, + MFT_RECORD_ATTR_END = 0xffffffff +}; + +static int probe_ntfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct ntfs_super_block *ns; +#if 0 + struct master_file_table_record *mft; +#endif + + uint32_t sectors_per_cluster, mft_record_size; + uint16_t sector_size; + uint64_t nr_clusters, off; //, attr_off; + unsigned char *buf_mft; + + ns = blkid_probe_get_sb(pr, mag, struct ntfs_super_block); + if (!ns) + return errno ? -errno : 1; + + /* + * Check bios parameters block + */ + sector_size = le16_to_cpu(ns->bpb.sector_size); + sectors_per_cluster = ns->bpb.sectors_per_cluster; + + if (sector_size < 256 || sector_size > 4096) + return 1; + + switch (sectors_per_cluster) { + case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128: + break; + default: + return 1; + } + + if ((uint16_t) le16_to_cpu(ns->bpb.sector_size) * + ns->bpb.sectors_per_cluster > NTFS_MAX_CLUSTER_SIZE) + return 1; + + /* Unused fields must be zero */ + if (le16_to_cpu(ns->bpb.reserved_sectors) + || le16_to_cpu(ns->bpb.root_entries) + || le16_to_cpu(ns->bpb.sectors) + || le16_to_cpu(ns->bpb.sectors_per_fat) + || le32_to_cpu(ns->bpb.large_sectors) + || ns->bpb.fats) + return 1; + + if ((uint8_t) ns->clusters_per_mft_record < 0xe1 + || (uint8_t) ns->clusters_per_mft_record > 0xf7) { + + switch (ns->clusters_per_mft_record) { + case 1: case 2: case 4: case 8: case 16: case 32: case 64: + break; + default: + return 1; + } + } + + if (ns->clusters_per_mft_record > 0) + mft_record_size = ns->clusters_per_mft_record * + sectors_per_cluster * sector_size; + else + mft_record_size = 1 << (0 - ns->clusters_per_mft_record); + + nr_clusters = le64_to_cpu(ns->number_of_sectors) / sectors_per_cluster; + + if ((le64_to_cpu(ns->mft_cluster_location) > nr_clusters) || + (le64_to_cpu(ns->mft_mirror_cluster_location) > nr_clusters)) + return 1; + + + off = le64_to_cpu(ns->mft_cluster_location) * sector_size * + sectors_per_cluster; + + DBG(LOWPROBE, ul_debug("NTFS: sector_size=%"PRIu16", mft_record_size=%"PRIu32", " + "sectors_per_cluster=%"PRIu32", nr_clusters=%"PRIu64" " + "cluster_offset=%"PRIu64"", + sector_size, mft_record_size, + sectors_per_cluster, nr_clusters, + off)); + + buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size); + if (!buf_mft) + return errno ? -errno : 1; + + if (memcmp(buf_mft, "FILE", 4)) + return 1; + + off += MFT_RECORD_VOLUME * mft_record_size; + + buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size); + if (!buf_mft) + return errno ? -errno : 1; + + if (memcmp(buf_mft, "FILE", 4)) + return 1; + +#if 0 + mft = (struct master_file_table_record *) buf_mft; + attr_off = le16_to_cpu(mft->attrs_offset); + + while (attr_off + sizeof(struct file_attribute) <= mft_record_size && + attr_off <= le32_to_cpu(mft->bytes_allocated)) { + + uint32_t attr_len; + struct file_attribute *attr; + + attr = (struct file_attribute *) (buf_mft + attr_off); + attr_len = le32_to_cpu(attr->len); + if (!attr_len) + break; + + if (le32_to_cpu(attr->type) == MFT_RECORD_ATTR_END) + break; + if (le32_to_cpu(attr->type) == MFT_RECORD_ATTR_VOLUME_NAME) { + unsigned int val_off = le16_to_cpu(attr->value_offset); + unsigned int val_len = le32_to_cpu(attr->value_len); + unsigned char *val = ((uint8_t *) attr) + val_off; + + if (attr_off + val_off + val_len <= mft_record_size) + blkid_probe_set_utf8label(pr, val, val_len, + BLKID_ENC_UTF16LE); + break; + } + + attr_off += attr_len; + } +#endif + + blkid_probe_sprintf_uuid(pr, + (unsigned char *) &ns->volume_serial, + sizeof(ns->volume_serial), + "%016" PRIX64, le64_to_cpu(ns->volume_serial)); + return 0; +} + + +const struct blkid_idinfo ntfs_idinfo = +{ + .name = "ntfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ntfs, + .magics = + { + { .magic = "NTFS ", .len = 8, .sboff = 3 }, + { NULL } + } +}; +