• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/fstools/libblkid-tiny/ntfs.c

  1 /*
  2  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
  3  * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
  4  *
  5  * This file may be redistributed under the terms of the
  6  * GNU Lesser General Public License.
  7  */
  8 #include <stdio.h>
  9 #include <stdlib.h>
 10 #include <unistd.h>
 11 #include <string.h>
 12 #include <inttypes.h>
 13 
 14 #include "superblocks.h"
 15 
 16 struct ntfs_bios_parameters {
 17         uint16_t        sector_size;    /* Size of a sector in bytes. */
 18         uint8_t         sectors_per_cluster;    /* Size of a cluster in sectors. */
 19         uint16_t        reserved_sectors;       /* zero */
 20         uint8_t         fats;                   /* zero */
 21         uint16_t        root_entries;           /* zero */
 22         uint16_t        sectors;                /* zero */
 23         uint8_t         media_type;             /* 0xf8 = hard disk */
 24         uint16_t        sectors_per_fat;        /* zero */
 25         uint16_t        sectors_per_track;      /* irrelevant */
 26         uint16_t        heads;                  /* irrelevant */
 27         uint32_t        hidden_sectors;         /* zero */
 28         uint32_t        large_sectors;          /* zero */
 29 } __attribute__ ((__packed__));
 30 
 31 struct ntfs_super_block {
 32         uint8_t         jump[3];
 33         uint8_t         oem_id[8];      /* magic string */
 34 
 35         struct ntfs_bios_parameters     bpb;
 36 
 37         uint16_t        unused[2];
 38         uint64_t        number_of_sectors;
 39         uint64_t        mft_cluster_location;
 40         uint64_t        mft_mirror_cluster_location;
 41         int8_t          clusters_per_mft_record;
 42         uint8_t         reserved1[3];
 43         int8_t          cluster_per_index_record;
 44         uint8_t         reserved2[3];
 45         uint64_t        volume_serial;
 46         uint32_t        checksum;
 47 } __attribute__((packed));
 48 
 49 struct master_file_table_record {
 50         uint32_t        magic;
 51         uint16_t        usa_ofs;
 52         uint16_t        usa_count;
 53         uint64_t        lsn;
 54         uint16_t        sequence_number;
 55         uint16_t        link_count;
 56         uint16_t        attrs_offset;
 57         uint16_t        flags;
 58         uint32_t        bytes_in_use;
 59         uint32_t        bytes_allocated;
 60 } __attribute__((__packed__));
 61 
 62 struct file_attribute {
 63         uint32_t        type;
 64         uint32_t        len;
 65         uint8_t         non_resident;
 66         uint8_t         name_len;
 67         uint16_t        name_offset;
 68         uint16_t        flags;
 69         uint16_t        instance;
 70         uint32_t        value_len;
 71         uint16_t        value_offset;
 72 } __attribute__((__packed__));
 73 
 74 #define MFT_RECORD_VOLUME       3
 75 #define NTFS_MAX_CLUSTER_SIZE   (64 * 1024)
 76 
 77 enum {
 78         MFT_RECORD_ATTR_VOLUME_NAME             = 0x60,
 79         MFT_RECORD_ATTR_END                     = 0xffffffff
 80 };
 81 
 82 static int probe_ntfs(blkid_probe pr, const struct blkid_idmag *mag)
 83 {
 84         struct ntfs_super_block *ns;
 85         struct master_file_table_record *mft;
 86 
 87         uint32_t sectors_per_cluster, mft_record_size;
 88         uint16_t sector_size;
 89         uint64_t volume_serial;
 90         uint64_t nr_clusters, off, attr_off;
 91         unsigned char *buf_mft;
 92 
 93         ns = blkid_probe_get_sb(pr, mag, struct ntfs_super_block);
 94         if (!ns)
 95                 return errno ? -errno : 1;
 96 
 97         /*
 98          * Check bios parameters block
 99          */
100         sector_size = le16_to_cpu(ns->bpb.sector_size);
101         sectors_per_cluster = ns->bpb.sectors_per_cluster;
102 
103         if (sector_size < 256 || sector_size > 4096)
104                 return 1;
105 
106         switch (sectors_per_cluster) {
107         case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
108                 break;
109         default:
110                 return 1;
111         }
112 
113         if ((uint16_t) le16_to_cpu(ns->bpb.sector_size) *
114                         ns->bpb.sectors_per_cluster > NTFS_MAX_CLUSTER_SIZE)
115                 return 1;
116 
117         /* Unused fields must be zero */
118         if (le16_to_cpu(ns->bpb.reserved_sectors)
119             || le16_to_cpu(ns->bpb.root_entries)
120             || le16_to_cpu(ns->bpb.sectors)
121             || le16_to_cpu(ns->bpb.sectors_per_fat)
122             || le32_to_cpu(ns->bpb.large_sectors)
123             || ns->bpb.fats)
124                 return 1;
125 
126         if ((uint8_t) ns->clusters_per_mft_record < 0xe1
127             || (uint8_t) ns->clusters_per_mft_record > 0xf7) {
128 
129                 switch (ns->clusters_per_mft_record) {
130                 case 1: case 2: case 4: case 8: case 16: case 32: case 64:
131                         break;
132                 default:
133                         return 1;
134                 }
135         }
136 
137         if (ns->clusters_per_mft_record > 0)
138                 mft_record_size = ns->clusters_per_mft_record *
139                                   sectors_per_cluster * sector_size;
140         else
141                 mft_record_size = 1 << (0 - ns->clusters_per_mft_record);
142 
143         nr_clusters = le64_to_cpu(ns->number_of_sectors) / sectors_per_cluster;
144 
145         if ((le64_to_cpu(ns->mft_cluster_location) > nr_clusters) ||
146             (le64_to_cpu(ns->mft_mirror_cluster_location) > nr_clusters))
147                 return 1;
148 
149 
150         volume_serial = ns->volume_serial;
151         off = le64_to_cpu(ns->mft_cluster_location) * sector_size *
152                 sectors_per_cluster;
153 
154         DBG(LOWPROBE, ul_debug("NTFS: sector_size=%"PRIu16", mft_record_size=%"PRIu32", "
155                         "sectors_per_cluster=%"PRIu32", nr_clusters=%"PRIu64" "
156                         "cluster_offset=%"PRIu64", volume_serial=%"PRIu64"",
157                         sector_size, mft_record_size,
158                         sectors_per_cluster, nr_clusters,
159                         off, volume_serial));
160 
161         buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
162         if (!buf_mft)
163                 return errno ? -errno : 1;
164 
165         if (memcmp(buf_mft, "FILE", 4))
166                 return 1;
167 
168         off += MFT_RECORD_VOLUME * mft_record_size;
169 
170         buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
171         if (!buf_mft)
172                 return errno ? -errno : 1;
173 
174         if (memcmp(buf_mft, "FILE", 4))
175                 return 1;
176 
177         mft = (struct master_file_table_record *) buf_mft;
178         attr_off = le16_to_cpu(mft->attrs_offset);
179 
180         while (attr_off + sizeof(struct file_attribute) <= mft_record_size &&
181                attr_off <= le32_to_cpu(mft->bytes_allocated)) {
182 
183                 uint32_t attr_len;
184                 struct file_attribute *attr;
185 
186                 attr = (struct file_attribute *) (buf_mft + attr_off);
187                 attr_len = le32_to_cpu(attr->len);
188                 if (!attr_len)
189                         break;
190 
191                 if (le32_to_cpu(attr->type) == MFT_RECORD_ATTR_END)
192                         break;
193                 if (le32_to_cpu(attr->type) == MFT_RECORD_ATTR_VOLUME_NAME) {
194                         unsigned int val_off = le16_to_cpu(attr->value_offset);
195                         unsigned int val_len = le32_to_cpu(attr->value_len);
196                         unsigned char *val = ((uint8_t *) attr) + val_off;
197 
198                         if (attr_off + val_off + val_len <= mft_record_size)
199                                 blkid_probe_set_utf8label(pr, val, val_len,
200                                                           BLKID_ENC_UTF16LE);
201                         break;
202                 }
203 
204                 attr_off += attr_len;
205         }
206 
207         blkid_probe_sprintf_uuid(pr,
208                         (unsigned char *) &volume_serial,
209                         sizeof(volume_serial),
210                         "%016" PRIX64, le64_to_cpu(volume_serial));
211         return 0;
212 }
213 
214 
215 const struct blkid_idinfo ntfs_idinfo =
216 {
217         .name           = "ntfs",
218         .usage          = BLKID_USAGE_FILESYSTEM,
219         .probefunc      = probe_ntfs,
220         .magics         =
221         {
222                 { .magic = "NTFS    ", .len = 8, .sboff = 3 },
223                 { NULL }
224         }
225 };
226 
227 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt