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 #define NTFS_MAX_CLUSTER_SIZE (64 * 1024) 76 77 enum { 78 MFT_RECORD_ATTR_VOLUME_NAME = 0x60, 79 MFT_RECORD_ATTR_END = 0xffffffff 80 }; 81 82 static int probe_ntfs(blkid_probe pr, const struct blkid_idmag *mag) 83 { 84 struct ntfs_super_block *ns; 85 struct master_file_table_record *mft; 86 87 uint32_t sectors_per_cluster, mft_record_size; 88 uint16_t sector_size; 89 uint64_t volume_serial; 90 uint64_t nr_clusters, off, attr_off; 91 unsigned char *buf_mft; 92 93 ns = blkid_probe_get_sb(pr, mag, struct ntfs_super_block); 94 if (!ns) 95 return errno ? -errno : 1; 96 97 /* 98 * Check bios parameters block 99 */ 100 sector_size = le16_to_cpu(ns->bpb.sector_size); 101 sectors_per_cluster = ns->bpb.sectors_per_cluster; 102 103 if (sector_size < 256 || sector_size > 4096) 104 return 1; 105 106 switch (sectors_per_cluster) { 107 case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128: 108 break; 109 default: 110 return 1; 111 } 112 113 if ((uint16_t) le16_to_cpu(ns->bpb.sector_size) * 114 ns->bpb.sectors_per_cluster > NTFS_MAX_CLUSTER_SIZE) 115 return 1; 116 117 /* Unused fields must be zero */ 118 if (le16_to_cpu(ns->bpb.reserved_sectors) 119 || le16_to_cpu(ns->bpb.root_entries) 120 || le16_to_cpu(ns->bpb.sectors) 121 || le16_to_cpu(ns->bpb.sectors_per_fat) 122 || le32_to_cpu(ns->bpb.large_sectors) 123 || ns->bpb.fats) 124 return 1; 125 126 if ((uint8_t) ns->clusters_per_mft_record < 0xe1 127 || (uint8_t) ns->clusters_per_mft_record > 0xf7) { 128 129 switch (ns->clusters_per_mft_record) { 130 case 1: case 2: case 4: case 8: case 16: case 32: case 64: 131 break; 132 default: 133 return 1; 134 } 135 } 136 137 if (ns->clusters_per_mft_record > 0) 138 mft_record_size = ns->clusters_per_mft_record * 139 sectors_per_cluster * sector_size; 140 else 141 mft_record_size = 1 << (0 - ns->clusters_per_mft_record); 142 143 nr_clusters = le64_to_cpu(ns->number_of_sectors) / sectors_per_cluster; 144 145 if ((le64_to_cpu(ns->mft_cluster_location) > nr_clusters) || 146 (le64_to_cpu(ns->mft_mirror_cluster_location) > nr_clusters)) 147 return 1; 148 149 150 volume_serial = ns->volume_serial; 151 off = le64_to_cpu(ns->mft_cluster_location) * sector_size * 152 sectors_per_cluster; 153 154 DBG(LOWPROBE, ul_debug("NTFS: sector_size=%"PRIu16", mft_record_size=%"PRIu32", " 155 "sectors_per_cluster=%"PRIu32", nr_clusters=%"PRIu64" " 156 "cluster_offset=%"PRIu64", volume_serial=%"PRIu64"", 157 sector_size, mft_record_size, 158 sectors_per_cluster, nr_clusters, 159 off, volume_serial)); 160 161 buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size); 162 if (!buf_mft) 163 return errno ? -errno : 1; 164 165 if (memcmp(buf_mft, "FILE", 4)) 166 return 1; 167 168 off += MFT_RECORD_VOLUME * mft_record_size; 169 170 buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size); 171 if (!buf_mft) 172 return errno ? -errno : 1; 173 174 if (memcmp(buf_mft, "FILE", 4)) 175 return 1; 176 177 mft = (struct master_file_table_record *) buf_mft; 178 attr_off = le16_to_cpu(mft->attrs_offset); 179 180 while (attr_off + sizeof(struct file_attribute) <= mft_record_size && 181 attr_off <= le32_to_cpu(mft->bytes_allocated)) { 182 183 uint32_t attr_len; 184 struct file_attribute *attr; 185 186 attr = (struct file_attribute *) (buf_mft + attr_off); 187 attr_len = le32_to_cpu(attr->len); 188 if (!attr_len) 189 break; 190 191 if (le32_to_cpu(attr->type) == MFT_RECORD_ATTR_END) 192 break; 193 if (le32_to_cpu(attr->type) == MFT_RECORD_ATTR_VOLUME_NAME) { 194 unsigned int val_off = le16_to_cpu(attr->value_offset); 195 unsigned int val_len = le32_to_cpu(attr->value_len); 196 unsigned char *val = ((uint8_t *) attr) + val_off; 197 198 if (attr_off + val_off + val_len <= mft_record_size) 199 blkid_probe_set_utf8label(pr, val, val_len, 200 BLKID_ENC_UTF16LE); 201 break; 202 } 203 204 attr_off += attr_len; 205 } 206 207 blkid_probe_sprintf_uuid(pr, 208 (unsigned char *) &volume_serial, 209 sizeof(volume_serial), 210 "%016" PRIX64, le64_to_cpu(volume_serial)); 211 return 0; 212 } 213 214 215 const struct blkid_idinfo ntfs_idinfo = 216 { 217 .name = "ntfs", 218 .usage = BLKID_USAGE_FILESYSTEM, 219 .probefunc = probe_ntfs, 220 .magics = 221 { 222 { .magic = "NTFS ", .len = 8, .sboff = 3 }, 223 { NULL } 224 } 225 }; 226 227
This page was automatically generated by LXR 0.3.1. • OpenWrt