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