busybox/util-linux/volume_id/ntfs.c
<<
>>
Prefs
   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//config:config FEATURE_VOLUMEID_NTFS
  21//config:       bool "ntfs filesystem"
  22//config:       default y
  23//config:       depends on VOLUMEID
  24
  25//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_NTFS) += ntfs.o
  26
  27#include "volume_id_internal.h"
  28
  29struct ntfs_super_block {
  30        uint8_t         jump[3];
  31        uint8_t         oem_id[8];
  32        uint16_t        bytes_per_sector;
  33        uint8_t         sectors_per_cluster;
  34        uint16_t        reserved_sectors;
  35        uint8_t         fats;
  36        uint16_t        root_entries;
  37        uint16_t        sectors;
  38        uint8_t         media_type;
  39        uint16_t        sectors_per_fat;
  40        uint16_t        sectors_per_track;
  41        uint16_t        heads;
  42        uint32_t        hidden_sectors;
  43        uint32_t        large_sectors;
  44        uint16_t        unused[2];
  45        uint64_t        number_of_sectors;
  46        uint64_t        mft_cluster_location;
  47        uint64_t        mft_mirror_cluster_location;
  48        int8_t          cluster_per_mft_record;
  49        uint8_t         reserved1[3];
  50        int8_t          cluster_per_index_record;
  51        uint8_t         reserved2[3];
  52        uint8_t         volume_serial[8];
  53        uint16_t        checksum;
  54} PACKED;
  55
  56struct master_file_table_record {
  57        uint8_t         magic[4];
  58        uint16_t        usa_ofs;
  59        uint16_t        usa_count;
  60        uint64_t        lsn;
  61        uint16_t        sequence_number;
  62        uint16_t        link_count;
  63        uint16_t        attrs_offset;
  64        uint16_t        flags;
  65        uint32_t        bytes_in_use;
  66        uint32_t        bytes_allocated;
  67} PACKED;
  68
  69struct file_attribute {
  70        uint32_t        type;
  71        uint32_t        len;
  72        uint8_t         non_resident;
  73        uint8_t         name_len;
  74        uint16_t        name_offset;
  75        uint16_t        flags;
  76        uint16_t        instance;
  77        uint32_t        value_len;
  78        uint16_t        value_offset;
  79} PACKED;
  80
  81struct volume_info {
  82        uint64_t        reserved;
  83        uint8_t         major_ver;
  84        uint8_t         minor_ver;
  85} PACKED;
  86
  87#define MFT_RECORD_VOLUME                       3
  88#define MFT_RECORD_ATTR_VOLUME_NAME             0x60
  89#define MFT_RECORD_ATTR_VOLUME_INFO             0x70
  90#define MFT_RECORD_ATTR_OBJECT_ID               0x40
  91#define MFT_RECORD_ATTR_END                     0xffffffffu
  92
  93int FAST_FUNC volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/)
  94{
  95#define off ((uint64_t)0)
  96        unsigned sector_size;
  97        unsigned cluster_size;
  98        uint64_t mft_cluster;
  99        uint64_t mft_off;
 100        unsigned mft_record_size;
 101        unsigned attr_type;
 102        unsigned attr_off;
 103        unsigned attr_len;
 104        unsigned val_off;
 105        unsigned val_len;
 106        struct master_file_table_record *mftr;
 107        struct ntfs_super_block *ns;
 108        const uint8_t *buf;
 109        const uint8_t *val;
 110
 111        dbg("probing at offset 0x%llx", (unsigned long long) off);
 112
 113        ns = volume_id_get_buffer(id, off, 0x200);
 114        if (ns == NULL)
 115                return -1;
 116
 117        if (memcmp(ns->oem_id, "NTFS", 4) != 0)
 118                return -1;
 119
 120        volume_id_set_uuid(id, ns->volume_serial, UUID_NTFS);
 121
 122        sector_size = le16_to_cpu(ns->bytes_per_sector);
 123        cluster_size = ns->sectors_per_cluster * sector_size;
 124        mft_cluster = le64_to_cpu(ns->mft_cluster_location);
 125        mft_off = mft_cluster * cluster_size;
 126
 127        if (ns->cluster_per_mft_record < 0)
 128                /* size = -log2(mft_record_size); normally 1024 Bytes */
 129                mft_record_size = 1 << -ns->cluster_per_mft_record;
 130        else
 131                mft_record_size = ns->cluster_per_mft_record * cluster_size;
 132
 133        dbg("sectorsize  0x%x", sector_size);
 134        dbg("clustersize 0x%x", cluster_size);
 135        dbg("mftcluster  %llu", (unsigned long long) mft_cluster);
 136        dbg("mftoffset  0x%llx", (unsigned long long) mft_off);
 137        dbg("cluster per mft_record  %i", ns->cluster_per_mft_record);
 138        dbg("mft record size  %i", mft_record_size);
 139
 140        buf = volume_id_get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size),
 141                        mft_record_size);
 142        if (buf == NULL)
 143                goto found;
 144
 145        mftr = (struct master_file_table_record*) buf;
 146
 147        dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]);
 148        if (memcmp(mftr->magic, "FILE", 4) != 0)
 149                goto found;
 150
 151        attr_off = le16_to_cpu(mftr->attrs_offset);
 152        dbg("file $Volume's attributes are at offset %i", attr_off);
 153
 154        while (1) {
 155                struct file_attribute *attr;
 156
 157                attr = (struct file_attribute*) &buf[attr_off];
 158                attr_type = le32_to_cpu(attr->type);
 159                attr_len = le32_to_cpu(attr->len);
 160                val_off = le16_to_cpu(attr->value_offset);
 161                val_len = le32_to_cpu(attr->value_len);
 162                attr_off += attr_len;
 163
 164                if (attr_len == 0)
 165                        break;
 166
 167                if (attr_off >= mft_record_size)
 168                        break;
 169
 170                if (attr_type == MFT_RECORD_ATTR_END)
 171                        break;
 172
 173                dbg("found attribute type 0x%x, len %i, at offset %i",
 174                        attr_type, attr_len, attr_off);
 175
 176//              if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) {
 177//                      struct volume_info *info;
 178//                      dbg("found info, len %i", val_len);
 179//                      info = (struct volume_info*) (((uint8_t *) attr) + val_off);
 180//                      snprintf(id->type_version, sizeof(id->type_version)-1,
 181//                               "%u.%u", info->major_ver, info->minor_ver);
 182//              }
 183
 184                if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
 185                        dbg("found label, len %i", val_len);
 186                        if (val_len > VOLUME_ID_LABEL_SIZE)
 187                                val_len = VOLUME_ID_LABEL_SIZE;
 188
 189                        val = ((uint8_t *) attr) + val_off;
 190//                      volume_id_set_label_raw(id, val, val_len);
 191                        volume_id_set_label_unicode16(id, val, LE, val_len);
 192                }
 193        }
 194
 195 found:
 196//      volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
 197        IF_FEATURE_BLKID_TYPE(id->type = "ntfs";)
 198
 199        return 0;
 200}
 201