2 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
3 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
5 * This file may be redistributed under the terms of the
6 * GNU Lesser General Public License.
16 struct ntfs_super_block {
19 uint8_t bios_parameter_block[25];
21 uint64_t number_of_sectors;
22 uint64_t mft_cluster_location;
23 uint64_t mft_mirror_cluster_location;
24 int8_t cluster_per_mft_record;
26 int8_t cluster_per_index_record;
28 uint64_t volume_serial;
30 } __attribute__((packed));
32 struct master_file_table_record {
37 uint16_t sequence_number;
39 uint16_t attrs_offset;
41 uint32_t bytes_in_use;
42 uint32_t bytes_allocated;
43 } __attribute__((__packed__));
45 struct file_attribute {
54 uint16_t value_offset;
55 } __attribute__((__packed__));
57 #define MFT_RECORD_VOLUME 3
58 #define MFT_RECORD_ATTR_VOLUME_NAME 0x60
59 #define MFT_RECORD_ATTR_VOLUME_INFO 0x70
60 #define MFT_RECORD_ATTR_OBJECT_ID 0x40
61 #define MFT_RECORD_ATTR_END 0xffffffffu
63 static int probe_ntfs(blkid_probe pr, const struct blkid_idmag *mag)
65 struct ntfs_super_block *ns;
66 struct master_file_table_record *mft;
67 struct file_attribute *attr;
68 unsigned char label_str[129], *cp;
69 int bytes_per_sector, sectors_per_cluster;
70 int mft_record_size, attr_off, attr_len;
71 unsigned int i, attr_type, val_len;
75 unsigned char *buf_mft, *val;
77 ns = blkid_probe_get_sb(pr, mag, struct ntfs_super_block);
81 bytes_per_sector = ns->bios_parameter_block[0] +
82 (ns->bios_parameter_block[1] << 8);
83 sectors_per_cluster = ns->bios_parameter_block[2];
85 if ((bytes_per_sector < 512) || (sectors_per_cluster == 0))
88 if (ns->cluster_per_mft_record < 0)
89 mft_record_size = 1 << (0 - ns->cluster_per_mft_record);
91 mft_record_size = ns->cluster_per_mft_record *
92 sectors_per_cluster * bytes_per_sector;
93 nr_clusters = le64_to_cpu(ns->number_of_sectors) / sectors_per_cluster;
95 if ((le64_to_cpu(ns->mft_cluster_location) > nr_clusters) ||
96 (le64_to_cpu(ns->mft_mirror_cluster_location) > nr_clusters))
99 off = le64_to_cpu(ns->mft_mirror_cluster_location) *
100 bytes_per_sector * sectors_per_cluster;
102 buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
106 if (memcmp(buf_mft, "FILE", 4))
109 off = le64_to_cpu(ns->mft_cluster_location) * bytes_per_sector *
112 buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
116 if (memcmp(buf_mft, "FILE", 4))
119 off += MFT_RECORD_VOLUME * mft_record_size;
121 buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
125 if (memcmp(buf_mft, "FILE", 4))
128 mft = (struct master_file_table_record *) buf_mft;
130 attr_off = le16_to_cpu(mft->attrs_offset);
134 attr = (struct file_attribute *) (buf_mft + attr_off);
135 attr_len = le16_to_cpu(attr->len);
136 attr_type = le32_to_cpu(attr->type);
137 val_off = le16_to_cpu(attr->value_offset);
138 val_len = le32_to_cpu(attr->value_len);
140 attr_off += attr_len;
142 if ((attr_off > mft_record_size) ||
146 if (attr_type == MFT_RECORD_ATTR_END)
149 if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
150 if (val_len > sizeof(label_str))
151 val_len = sizeof(label_str)-1;
153 for (i=0, cp=label_str; i < val_len; i+=2,cp++) {
154 val = ((uint8_t *) attr) + val_off + i;
163 blkid_probe_sprintf_uuid(pr,
164 (unsigned char *) &ns->volume_serial,
165 sizeof(ns->volume_serial),
166 "%016" PRIX64, le64_to_cpu(ns->volume_serial));
168 blkid_probe_set_label(pr, label_str, strlen((char *)label_str));
173 const struct blkid_idinfo ntfs_idinfo =
176 .usage = BLKID_USAGE_FILESYSTEM,
177 .probefunc = probe_ntfs,
180 { .magic = "NTFS ", .len = 8, .sboff = 3 },