(root)/
util-linux-2.39/
libblkid/
src/
superblocks/
ntfs.c
       1  /*
       2   * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
       3   * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
       4   *
       5   * This file may be redistributed under the terms of the
       6   * GNU Lesser General Public License.
       7   */
       8  #include <stdio.h>
       9  #include <stdlib.h>
      10  #include <unistd.h>
      11  #include <string.h>
      12  #include <inttypes.h>
      13  
      14  #include "superblocks.h"
      15  
      16  struct ntfs_bios_parameters {
      17  	uint16_t	sector_size;	/* Size of a sector in bytes. */
      18  	uint8_t		sectors_per_cluster;	/* Size of a cluster in sectors. */
      19  	uint16_t	reserved_sectors;	/* zero */
      20  	uint8_t		fats;			/* zero */
      21  	uint16_t	root_entries;		/* zero */
      22  	uint16_t	sectors;		/* zero */
      23  	uint8_t		media_type;		/* 0xf8 = hard disk */
      24  	uint16_t	sectors_per_fat;	/* zero */
      25  	uint16_t	sectors_per_track;	/* irrelevant */
      26  	uint16_t	heads;			/* irrelevant */
      27  	uint32_t	hidden_sectors;		/* zero */
      28  	uint32_t	large_sectors;		/* zero */
      29  } __attribute__ ((__packed__));
      30  
      31  struct ntfs_super_block {
      32  	uint8_t		jump[3];
      33  	uint8_t		oem_id[8];	/* magic string */
      34  
      35  	struct ntfs_bios_parameters	bpb;
      36  
      37  	uint16_t	unused[2];
      38  	uint64_t	number_of_sectors;
      39  	uint64_t	mft_cluster_location;
      40  	uint64_t	mft_mirror_cluster_location;
      41  	int8_t		clusters_per_mft_record;
      42  	uint8_t		reserved1[3];
      43  	int8_t		cluster_per_index_record;
      44  	uint8_t		reserved2[3];
      45  	uint64_t	volume_serial;
      46  	uint32_t	checksum;
      47  } __attribute__((packed));
      48  
      49  struct master_file_table_record {
      50  	uint32_t	magic;
      51  	uint16_t	usa_ofs;
      52  	uint16_t	usa_count;
      53  	uint64_t	lsn;
      54  	uint16_t	sequence_number;
      55  	uint16_t	link_count;
      56  	uint16_t	attrs_offset;
      57  	uint16_t	flags;
      58  	uint32_t	bytes_in_use;
      59  	uint32_t	bytes_allocated;
      60  } __attribute__((__packed__));
      61  
      62  struct file_attribute {
      63  	uint32_t	type;
      64  	uint32_t	len;
      65  	uint8_t		non_resident;
      66  	uint8_t		name_len;
      67  	uint16_t	name_offset;
      68  	uint16_t	flags;
      69  	uint16_t	instance;
      70  	uint32_t	value_len;
      71  	uint16_t	value_offset;
      72  } __attribute__((__packed__));
      73  
      74  #define MFT_RECORD_VOLUME	3
      75  /* Windows 10 Creators edition has extended the cluster size limit to 2MB */
      76  #define NTFS_MAX_CLUSTER_SIZE	(2 * 1024 * 1024)
      77  
      78  #define	MFT_RECORD_ATTR_VOLUME_NAME	0x60
      79  #define	MFT_RECORD_ATTR_END		0xffffffff
      80  
      81  static int __probe_ntfs(blkid_probe pr, const struct blkid_idmag *mag, int save_info)
      82  {
      83  	struct ntfs_super_block *ns;
      84  	struct master_file_table_record *mft;
      85  
      86  	uint32_t sectors_per_cluster, mft_record_size;
      87  	uint16_t sector_size;
      88  	uint64_t nr_clusters, off, attr_off;
      89  	unsigned char *buf_mft;
      90  
      91  	ns = blkid_probe_get_sb(pr, mag, struct ntfs_super_block);
      92  	if (!ns)
      93  		return errno ? -errno : 1;
      94  
      95  	/*
      96  	 * Check bios parameters block
      97  	 */
      98  	sector_size = le16_to_cpu(ns->bpb.sector_size);
      99  
     100  	if (sector_size < 256 || sector_size > 4096)
     101  		return 1;
     102  
     103  	switch (ns->bpb.sectors_per_cluster) {
     104  	case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
     105  		sectors_per_cluster = ns->bpb.sectors_per_cluster;
     106  		break;
     107  	default:
     108  		if ((ns->bpb.sectors_per_cluster < 240)
     109  		    || (ns->bpb.sectors_per_cluster > 249))
     110  			return 1;
     111  		sectors_per_cluster = 1 << (256 - ns->bpb.sectors_per_cluster);
     112  	}
     113  
     114  	if ((uint16_t) le16_to_cpu(ns->bpb.sector_size) *
     115  			sectors_per_cluster > NTFS_MAX_CLUSTER_SIZE)
     116  		return 1;
     117  
     118  	/* Unused fields must be zero */
     119  	if (le16_to_cpu(ns->bpb.reserved_sectors)
     120  	    || le16_to_cpu(ns->bpb.root_entries)
     121  	    || le16_to_cpu(ns->bpb.sectors)
     122  	    || le16_to_cpu(ns->bpb.sectors_per_fat)
     123  	    || le32_to_cpu(ns->bpb.large_sectors)
     124  	    || ns->bpb.fats)
     125  		return 1;
     126  
     127  	if ((uint8_t) ns->clusters_per_mft_record < 0xe1
     128  	    || (uint8_t) ns->clusters_per_mft_record > 0xf7) {
     129  
     130  		switch (ns->clusters_per_mft_record) {
     131  		case 1: case 2: case 4: case 8: case 16: case 32: case 64:
     132  			break;
     133  		default:
     134  			return 1;
     135  		}
     136  	}
     137  
     138  	if (ns->clusters_per_mft_record > 0) {
     139  		mft_record_size = ns->clusters_per_mft_record *
     140  				  sectors_per_cluster * sector_size;
     141  	} else {
     142  		int8_t mft_record_size_shift = 0 - ns->clusters_per_mft_record;
     143  		if (mft_record_size_shift < 0 || mft_record_size_shift >= 31)
     144  			return 1;
     145  		mft_record_size = 1 << mft_record_size_shift;
     146  	}
     147  
     148  	nr_clusters = le64_to_cpu(ns->number_of_sectors) / sectors_per_cluster;
     149  
     150  	if ((le64_to_cpu(ns->mft_cluster_location) > nr_clusters) ||
     151  	    (le64_to_cpu(ns->mft_mirror_cluster_location) > nr_clusters))
     152  		return 1;
     153  
     154  
     155  	off = le64_to_cpu(ns->mft_cluster_location) * sector_size *
     156  		sectors_per_cluster;
     157  
     158  	DBG(LOWPROBE, ul_debug("NTFS: sector_size=%"PRIu16", mft_record_size=%"PRIu32", "
     159  			"sectors_per_cluster=%"PRIu32", nr_clusters=%"PRIu64" "
     160  			"cluster_offset=%"PRIu64"",
     161  			sector_size, mft_record_size,
     162  			sectors_per_cluster, nr_clusters,
     163  			off));
     164  
     165  	if (mft_record_size < 4)
     166  		return 1;
     167  
     168  	buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
     169  	if (!buf_mft)
     170  		return errno ? -errno : 1;
     171  
     172  	if (memcmp(buf_mft, "FILE", 4) != 0)
     173  		return 1;
     174  
     175  	off += MFT_RECORD_VOLUME * mft_record_size;
     176  
     177  	buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
     178  	if (!buf_mft)
     179  		return errno ? -errno : 1;
     180  
     181  	if (memcmp(buf_mft, "FILE", 4) != 0)
     182  		return 1;
     183  
     184  	/* return if caller does not care about UUID and LABEL */
     185  	if (!save_info)
     186  		return 0;
     187  
     188  	mft = (struct master_file_table_record *) buf_mft;
     189  	attr_off = le16_to_cpu(mft->attrs_offset);
     190  
     191  	while (attr_off + sizeof(struct file_attribute) <= mft_record_size &&
     192  	       attr_off <= le32_to_cpu(mft->bytes_allocated)) {
     193  
     194  		uint32_t attr_len;
     195  		struct file_attribute *attr;
     196  
     197  		attr = (struct file_attribute *) (buf_mft + attr_off);
     198  		attr_len = le32_to_cpu(attr->len);
     199  		if (!attr_len)
     200  			break;
     201  
     202  		if (le32_to_cpu(attr->type) == (uint32_t) MFT_RECORD_ATTR_END)
     203  			break;
     204  		if (le32_to_cpu(attr->type) == (uint32_t) MFT_RECORD_ATTR_VOLUME_NAME) {
     205  			unsigned int val_off = le16_to_cpu(attr->value_offset);
     206  			unsigned int val_len = le32_to_cpu(attr->value_len);
     207  			unsigned char *val = ((uint8_t *) attr) + val_off;
     208  
     209  			if (attr_off + val_off + val_len <= mft_record_size)
     210  				blkid_probe_set_utf8label(pr, val, val_len,
     211  							  UL_ENCODE_UTF16LE);
     212  			break;
     213  		}
     214  
     215  		attr_off += attr_len;
     216  	}
     217  
     218  
     219  	blkid_probe_set_fsblocksize(pr, sector_size * sectors_per_cluster);
     220  	blkid_probe_set_block_size(pr, sector_size);
     221  	blkid_probe_set_fssize(pr, le64_to_cpu(ns->number_of_sectors) * sector_size);
     222  
     223  	blkid_probe_sprintf_uuid(pr,
     224  			(unsigned char *) &ns->volume_serial,
     225  			sizeof(ns->volume_serial),
     226  			"%016" PRIX64, le64_to_cpu(ns->volume_serial));
     227  	return 0;
     228  }
     229  
     230  static int probe_ntfs(blkid_probe pr, const struct blkid_idmag *mag)
     231  {
     232  	return __probe_ntfs(pr, mag, 1);
     233  }
     234  
     235  int blkid_probe_is_ntfs(blkid_probe pr)
     236  {
     237  	const struct blkid_idmag *mag = NULL;
     238  	int rc;
     239  
     240  	rc = blkid_probe_get_idmag(pr, &ntfs_idinfo, NULL, &mag);
     241  	if (rc < 0)
     242  		return rc;	/* error */
     243  	if (rc != BLKID_PROBE_OK || !mag)
     244  		return 0;
     245  
     246  	return __probe_ntfs(pr, mag, 0) == 0 ? 1 : 0;
     247  }
     248  
     249  const struct blkid_idinfo ntfs_idinfo =
     250  {
     251  	.name		= "ntfs",
     252  	.usage		= BLKID_USAGE_FILESYSTEM,
     253  	.probefunc	= probe_ntfs,
     254  	.magics		=
     255  	{
     256  		{ .magic = "NTFS    ", .len = 8, .sboff = 3 },
     257  		{ NULL }
     258  	}
     259  };
     260