Upload Tizen:Base source
[framework/base/util-linux-ng.git] / shlibs / blkid / src / probers / 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 "blkidP.h"
15
16 struct ntfs_super_block {
17         uint8_t         jump[3];
18         uint8_t         oem_id[8];
19         uint8_t         bios_parameter_block[25];
20         uint16_t        unused[2];
21         uint64_t        number_of_sectors;
22         uint64_t        mft_cluster_location;
23         uint64_t        mft_mirror_cluster_location;
24         int8_t          cluster_per_mft_record;
25         uint8_t         reserved1[3];
26         int8_t          cluster_per_index_record;
27         uint8_t         reserved2[3];
28         uint64_t        volume_serial;
29         uint16_t        checksum;
30 } __attribute__((packed));
31
32 struct master_file_table_record {
33         uint32_t        magic;
34         uint16_t        usa_ofs;
35         uint16_t        usa_count;
36         uint64_t        lsn;
37         uint16_t        sequence_number;
38         uint16_t        link_count;
39         uint16_t        attrs_offset;
40         uint16_t        flags;
41         uint32_t        bytes_in_use;
42         uint32_t        bytes_allocated;
43 } __attribute__((__packed__));
44
45 struct file_attribute {
46         uint32_t        type;
47         uint32_t        len;
48         uint8_t         non_resident;
49         uint8_t         name_len;
50         uint16_t        name_offset;
51         uint16_t        flags;
52         uint16_t        instance;
53         uint32_t        value_len;
54         uint16_t        value_offset;
55 } __attribute__((__packed__));
56
57 #define MFT_RECORD_VOLUME                       3
58 #define MFT_RECORD_ATTR_VOLUME_NAME             0x60
59 #define MFT_RECORD_ATTR_VOLUME_INFO             0x70
60 #define MFT_RECORD_ATTR_OBJECT_ID               0x40
61 #define MFT_RECORD_ATTR_END                     0xffffffffu
62
63 static int probe_ntfs(blkid_probe pr, const struct blkid_idmag *mag)
64 {
65         struct ntfs_super_block *ns;
66         struct master_file_table_record *mft;
67         struct file_attribute *attr;
68         unsigned char   label_str[129], *cp;
69         int             bytes_per_sector, sectors_per_cluster;
70         int             mft_record_size, attr_off, attr_len;
71         unsigned int    i, attr_type, val_len;
72         int             val_off;
73         uint64_t                nr_clusters;
74         blkid_loff_t off;
75         unsigned char *buf_mft, *val;
76
77         ns = blkid_probe_get_sb(pr, mag, struct ntfs_super_block);
78         if (!ns)
79                 return -1;
80
81         bytes_per_sector = ns->bios_parameter_block[0] +
82                 (ns->bios_parameter_block[1]  << 8);
83         sectors_per_cluster = ns->bios_parameter_block[2];
84
85         if ((bytes_per_sector < 512) || (sectors_per_cluster == 0))
86                 return 1;
87
88         if (ns->cluster_per_mft_record < 0)
89                 mft_record_size = 1 << (0 - ns->cluster_per_mft_record);
90         else
91                 mft_record_size = ns->cluster_per_mft_record *
92                         sectors_per_cluster * bytes_per_sector;
93         nr_clusters = le64_to_cpu(ns->number_of_sectors) / sectors_per_cluster;
94
95         if ((le64_to_cpu(ns->mft_cluster_location) > nr_clusters) ||
96             (le64_to_cpu(ns->mft_mirror_cluster_location) > nr_clusters))
97                 return 1;
98
99         off = le64_to_cpu(ns->mft_mirror_cluster_location) *
100                 bytes_per_sector * sectors_per_cluster;
101
102         buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
103         if (!buf_mft)
104                 return 1;
105
106         if (memcmp(buf_mft, "FILE", 4))
107                 return 1;
108
109         off = le64_to_cpu(ns->mft_cluster_location) * bytes_per_sector *
110                 sectors_per_cluster;
111
112         buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
113         if (!buf_mft)
114                 return 1;
115
116         if (memcmp(buf_mft, "FILE", 4))
117                 return 1;
118
119         off += MFT_RECORD_VOLUME * mft_record_size;
120
121         buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size);
122         if (!buf_mft)
123                 return 1;
124
125         if (memcmp(buf_mft, "FILE", 4))
126                 return 1;
127
128         mft = (struct master_file_table_record *) buf_mft;
129
130         attr_off = le16_to_cpu(mft->attrs_offset);
131         label_str[0] = 0;
132
133         while (1) {
134                 attr = (struct file_attribute *) (buf_mft + attr_off);
135                 attr_len = le16_to_cpu(attr->len);
136                 attr_type = le32_to_cpu(attr->type);
137                 val_off = le16_to_cpu(attr->value_offset);
138                 val_len = le32_to_cpu(attr->value_len);
139
140                 attr_off += attr_len;
141
142                 if ((attr_off > mft_record_size) ||
143                     (attr_len == 0))
144                         break;
145
146                 if (attr_type == MFT_RECORD_ATTR_END)
147                         break;
148
149                 if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
150                         if (val_len > sizeof(label_str))
151                                 val_len = sizeof(label_str)-1;
152
153                         for (i=0, cp=label_str; i < val_len; i+=2,cp++) {
154                                 val = ((uint8_t *) attr) + val_off + i;
155                                 *cp = val[0];
156                                 if (val[1])
157                                         *cp = '?';
158                         }
159                         *cp = 0;
160                 }
161         }
162
163         blkid_probe_sprintf_uuid(pr,
164                         (unsigned char *) &ns->volume_serial,
165                         sizeof(ns->volume_serial),
166                         "%016" PRIX64, le64_to_cpu(ns->volume_serial));
167         if (label_str[0])
168                 blkid_probe_set_label(pr, label_str, strlen((char *)label_str));
169         return 0;
170 }
171
172
173 const struct blkid_idinfo ntfs_idinfo =
174 {
175         .name           = "ntfs",
176         .usage          = BLKID_USAGE_FILESYSTEM,
177         .probefunc      = probe_ntfs,
178         .magics         =
179         {
180                 { .magic = "NTFS    ", .len = 8, .sboff = 3 },
181                 { NULL }
182         }
183 };
184