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.
14
#include "superblocks.h"
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
int bytes_per_sector, sectors_per_cluster;
69
int mft_record_size, attr_off, attr_len;
70
unsigned int attr_type, val_len;
74
unsigned char *buf_mft, *val;
76
ns = blkid_probe_get_sb(pr, mag, struct ntfs_super_block);
80
bytes_per_sector = ns->bios_parameter_block[0] +
81
(ns->bios_parameter_block[1] << 8);
82
sectors_per_cluster = ns->bios_parameter_block[2];
84
if ((bytes_per_sector < 512) || (sectors_per_cluster == 0))
87
if (ns->cluster_per_mft_record < 0)
88
mft_record_size = 1 << (0 - ns->cluster_per_mft_record);
90
mft_record_size = ns->cluster_per_mft_record *
91
sectors_per_cluster * bytes_per_sector;
92
nr_clusters = le64_to_cpu(ns->number_of_sectors) / sectors_per_cluster;
94
if ((le64_to_cpu(ns->mft_cluster_location) > nr_clusters) ||
95
(le64_to_cpu(ns->mft_mirror_cluster_location) > nr_clusters))
98
off = le64_to_cpu(ns->mft_mirror_cluster_location) *
99
bytes_per_sector * sectors_per_cluster;
101
buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
105
if (memcmp(buf_mft, "FILE", 4))
108
off = le64_to_cpu(ns->mft_cluster_location) * bytes_per_sector *
111
buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
115
if (memcmp(buf_mft, "FILE", 4))
118
off += MFT_RECORD_VOLUME * mft_record_size;
120
buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
124
if (memcmp(buf_mft, "FILE", 4))
127
mft = (struct master_file_table_record *) buf_mft;
129
attr_off = le16_to_cpu(mft->attrs_offset);
132
attr = (struct file_attribute *) (buf_mft + attr_off);
133
attr_len = le32_to_cpu(attr->len);
134
attr_type = le32_to_cpu(attr->type);
135
val_off = le16_to_cpu(attr->value_offset);
136
val_len = le32_to_cpu(attr->value_len);
138
attr_off += attr_len;
140
if ((attr_off > mft_record_size) ||
144
if (attr_type == MFT_RECORD_ATTR_END)
147
if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
148
val = ((uint8_t *) attr) + val_off;
149
blkid_probe_set_utf8label(pr, val, val_len, BLKID_ENC_UTF16LE);
153
blkid_probe_sprintf_uuid(pr,
154
(unsigned char *) &ns->volume_serial,
155
sizeof(ns->volume_serial),
156
"%016" PRIX64, le64_to_cpu(ns->volume_serial));
161
const struct blkid_idinfo ntfs_idinfo =
164
.usage = BLKID_USAGE_FILESYSTEM,
165
.probefunc = probe_ntfs,
168
{ .magic = "NTFS ", .len = 8, .sboff = 3 },