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#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 = le16_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