1/* 2 * volume_id - reads filesystem label and uuid 3 * 4 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21#include "volume_id_internal.h" 22 23struct ntfs_super_block { 24 uint8_t jump[3]; 25 uint8_t oem_id[8]; 26 uint16_t bytes_per_sector; 27 uint8_t sectors_per_cluster; 28 uint16_t reserved_sectors; 29 uint8_t fats; 30 uint16_t root_entries; 31 uint16_t sectors; 32 uint8_t media_type; 33 uint16_t sectors_per_fat; 34 uint16_t sectors_per_track; 35 uint16_t heads; 36 uint32_t hidden_sectors; 37 uint32_t large_sectors; 38 uint16_t unused[2]; 39 uint64_t number_of_sectors; 40 uint64_t mft_cluster_location; 41 uint64_t mft_mirror_cluster_location; 42 int8_t cluster_per_mft_record; 43 uint8_t reserved1[3]; 44 int8_t cluster_per_index_record; 45 uint8_t reserved2[3]; 46 uint8_t volume_serial[8]; 47 uint16_t checksum; 48} PACKED; 49 50struct master_file_table_record { 51 uint8_t magic[4]; 52 uint16_t usa_ofs; 53 uint16_t usa_count; 54 uint64_t lsn; 55 uint16_t sequence_number; 56 uint16_t link_count; 57 uint16_t attrs_offset; 58 uint16_t flags; 59 uint32_t bytes_in_use; 60 uint32_t bytes_allocated; 61} PACKED; 62 63struct file_attribute { 64 uint32_t type; 65 uint32_t len; 66 uint8_t non_resident; 67 uint8_t name_len; 68 uint16_t name_offset; 69 uint16_t flags; 70 uint16_t instance; 71 uint32_t value_len; 72 uint16_t value_offset; 73} PACKED; 74 75struct volume_info { 76 uint64_t reserved; 77 uint8_t major_ver; 78 uint8_t minor_ver; 79} PACKED; 80 81#define MFT_RECORD_VOLUME 3 82#define MFT_RECORD_ATTR_VOLUME_NAME 0x60 83#define MFT_RECORD_ATTR_VOLUME_INFO 0x70 84#define MFT_RECORD_ATTR_OBJECT_ID 0x40 85#define MFT_RECORD_ATTR_END 0xffffffffu 86 87int FAST_FUNC volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/) 88{ 89#define off ((uint64_t)0) 90 unsigned sector_size; 91 unsigned cluster_size; 92 uint64_t mft_cluster; 93 uint64_t mft_off; 94 unsigned mft_record_size; 95 unsigned attr_type; 96 unsigned attr_off; 97 unsigned attr_len; 98 unsigned val_off; 99 unsigned val_len; 100 struct master_file_table_record *mftr; 101 struct ntfs_super_block *ns; 102 const uint8_t *buf; 103 const uint8_t *val; 104 105 dbg("probing at offset 0x%llx", (unsigned long long) off); 106 107 ns = volume_id_get_buffer(id, off, 0x200); 108 if (ns == NULL) 109 return -1; 110 111 if (memcmp(ns->oem_id, "NTFS", 4) != 0) 112 return -1; 113 114 volume_id_set_uuid(id, ns->volume_serial, UUID_NTFS); 115 116 sector_size = le16_to_cpu(ns->bytes_per_sector); 117 cluster_size = ns->sectors_per_cluster * sector_size; 118 mft_cluster = le64_to_cpu(ns->mft_cluster_location); 119 mft_off = mft_cluster * cluster_size; 120 121 if (ns->cluster_per_mft_record < 0) 122 /* size = -log2(mft_record_size); normally 1024 Bytes */ 123 mft_record_size = 1 << -ns->cluster_per_mft_record; 124 else 125 mft_record_size = ns->cluster_per_mft_record * cluster_size; 126 127 dbg("sectorsize 0x%x", sector_size); 128 dbg("clustersize 0x%x", cluster_size); 129 dbg("mftcluster %llu", (unsigned long long) mft_cluster); 130 dbg("mftoffset 0x%llx", (unsigned long long) mft_off); 131 dbg("cluster per mft_record %i", ns->cluster_per_mft_record); 132 dbg("mft record size %i", mft_record_size); 133 134 buf = volume_id_get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size), 135 mft_record_size); 136 if (buf == NULL) 137 goto found; 138 139 mftr = (struct master_file_table_record*) buf; 140 141 dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]); 142 if (memcmp(mftr->magic, "FILE", 4) != 0) 143 goto found; 144 145 attr_off = le16_to_cpu(mftr->attrs_offset); 146 dbg("file $Volume's attributes are at offset %i", attr_off); 147 148 while (1) { 149 struct file_attribute *attr; 150 151 attr = (struct file_attribute*) &buf[attr_off]; 152 attr_type = le32_to_cpu(attr->type); 153 attr_len = le32_to_cpu(attr->len); 154 val_off = le16_to_cpu(attr->value_offset); 155 val_len = le32_to_cpu(attr->value_len); 156 attr_off += attr_len; 157 158 if (attr_len == 0) 159 break; 160 161 if (attr_off >= mft_record_size) 162 break; 163 164 if (attr_type == MFT_RECORD_ATTR_END) 165 break; 166 167 dbg("found attribute type 0x%x, len %i, at offset %i", 168 attr_type, attr_len, attr_off); 169 170// if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) { 171// struct volume_info *info; 172// dbg("found info, len %i", val_len); 173// info = (struct volume_info*) (((uint8_t *) attr) + val_off); 174// snprintf(id->type_version, sizeof(id->type_version)-1, 175// "%u.%u", info->major_ver, info->minor_ver); 176// } 177 178 if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) { 179 dbg("found label, len %i", val_len); 180 if (val_len > VOLUME_ID_LABEL_SIZE) 181 val_len = VOLUME_ID_LABEL_SIZE; 182 183 val = ((uint8_t *) attr) + val_off; 184// volume_id_set_label_raw(id, val, val_len); 185 volume_id_set_label_unicode16(id, val, LE, val_len); 186 } 187 } 188 189 found: 190// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); 191// id->type = "ntfs"; 192 193 return 0; 194} 195