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;
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 },