Upload Tizen:Base source
[framework/base/util-linux-ng.git] / shlibs / blkid / src / probers / hfs.c
1 /*
2  * Copyright (C) 2004-2008 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 #include "md5.h"
16
17 /* HFS / HFS+ */
18 struct hfs_finder_info {
19         uint32_t        boot_folder;
20         uint32_t        start_app;
21         uint32_t        open_folder;
22         uint32_t        os9_folder;
23         uint32_t        reserved;
24         uint32_t        osx_folder;
25         uint8_t         id[8];
26 } __attribute__((packed));
27
28 struct hfs_mdb {
29         uint8_t         signature[2];
30         uint32_t        cr_date;
31         uint32_t        ls_Mod;
32         uint16_t        atrb;
33         uint16_t        nm_fls;
34         uint16_t        vbm_st;
35         uint16_t        alloc_ptr;
36         uint16_t        nm_al_blks;
37         uint32_t        al_blk_size;
38         uint32_t        clp_size;
39         uint16_t        al_bl_st;
40         uint32_t        nxt_cnid;
41         uint16_t        free_bks;
42         uint8_t         label_len;
43         uint8_t         label[27];
44         uint32_t        vol_bkup;
45         uint16_t        vol_seq_num;
46         uint32_t        wr_cnt;
47         uint32_t        xt_clump_size;
48         uint32_t        ct_clump_size;
49         uint16_t        num_root_dirs;
50         uint32_t        file_count;
51         uint32_t        dir_count;
52         struct hfs_finder_info finder_info;
53         uint8_t         embed_sig[2];
54         uint16_t        embed_startblock;
55         uint16_t        embed_blockcount;
56 } __attribute__((packed));
57
58
59 #define HFS_NODE_LEAF                   0xff
60 #define HFSPLUS_POR_CNID                1
61
62 struct hfsplus_bnode_descriptor {
63         uint32_t                next;
64         uint32_t                prev;
65         uint8_t         type;
66         uint8_t         height;
67         uint16_t                num_recs;
68         uint16_t                reserved;
69 } __attribute__((packed));
70
71 struct hfsplus_bheader_record {
72         uint16_t                depth;
73         uint32_t                root;
74         uint32_t                leaf_count;
75         uint32_t                leaf_head;
76         uint32_t                leaf_tail;
77         uint16_t                node_size;
78 } __attribute__((packed));
79
80 struct hfsplus_catalog_key {
81         uint16_t        key_len;
82         uint32_t        parent_id;
83         uint16_t        unicode_len;
84         uint8_t         unicode[255 * 2];
85 } __attribute__((packed));
86
87 struct hfsplus_extent {
88         uint32_t                start_block;
89         uint32_t                block_count;
90 } __attribute__((packed));
91
92 #define HFSPLUS_EXTENT_COUNT            8
93 struct hfsplus_fork {
94         uint64_t                total_size;
95         uint32_t                clump_size;
96         uint32_t                total_blocks;
97         struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
98 } __attribute__((packed));
99
100 struct hfsplus_vol_header {
101         uint8_t         signature[2];
102         uint16_t                version;
103         uint32_t                attributes;
104         uint32_t                last_mount_vers;
105         uint32_t                reserved;
106         uint32_t                create_date;
107         uint32_t                modify_date;
108         uint32_t                backup_date;
109         uint32_t                checked_date;
110         uint32_t                file_count;
111         uint32_t                folder_count;
112         uint32_t                blocksize;
113         uint32_t                total_blocks;
114         uint32_t                free_blocks;
115         uint32_t                next_alloc;
116         uint32_t                rsrc_clump_sz;
117         uint32_t                data_clump_sz;
118         uint32_t                next_cnid;
119         uint32_t                write_count;
120         uint64_t                encodings_bmp;
121         struct hfs_finder_info finder_info;
122         struct hfsplus_fork alloc_file;
123         struct hfsplus_fork ext_file;
124         struct hfsplus_fork cat_file;
125         struct hfsplus_fork attr_file;
126         struct hfsplus_fork start_file;
127 }  __attribute__((packed));
128
129 static int hfs_set_uuid(blkid_probe pr, unsigned char const *hfs_info, size_t len)
130 {
131         static unsigned char const hash_init[16] = {
132                 0xb3, 0xe2, 0x0f, 0x39, 0xf2, 0x92, 0x11, 0xd6,
133                 0x97, 0xa4, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
134         };
135         unsigned char uuid[16];
136         struct MD5Context md5c;
137
138         if (memcmp(hfs_info, "\0\0\0\0\0\0\0\0", len) == 0)
139                 return -1;
140         MD5Init(&md5c);
141         MD5Update(&md5c, hash_init, 16);
142         MD5Update(&md5c, hfs_info, len);
143         MD5Final(uuid, &md5c);
144         uuid[6] = 0x30 | (uuid[6] & 0x0f);
145         uuid[8] = 0x80 | (uuid[8] & 0x3f);
146         return blkid_probe_set_uuid(pr, uuid);
147 }
148
149 static int probe_hfs(blkid_probe pr, const struct blkid_idmag *mag)
150 {
151         struct hfs_mdb  *hfs;
152
153         hfs = blkid_probe_get_sb(pr, mag, struct hfs_mdb);
154         if (!hfs)
155                 return -1;
156
157         if ((memcmp(hfs->embed_sig, "H+", 2) == 0) ||
158             (memcmp(hfs->embed_sig, "HX", 2) == 0))
159                 return 1;       /* Not hfs, but an embedded HFS+ */
160
161         hfs_set_uuid(pr, hfs->finder_info.id, sizeof(hfs->finder_info.id));
162
163         blkid_probe_set_label(pr, hfs->label, hfs->label_len);
164         return 0;
165 }
166
167 static int probe_hfsplus(blkid_probe pr, const struct blkid_idmag *mag)
168 {
169         struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
170         struct hfsplus_bnode_descriptor *descr;
171         struct hfsplus_bheader_record *bnode;
172         struct hfsplus_catalog_key *key;
173         struct hfsplus_vol_header *hfsplus;
174         struct hfs_mdb *sbd;
175         unsigned int alloc_block_size;
176         unsigned int alloc_first_block;
177         unsigned int embed_first_block;
178         unsigned int off = 0;
179         unsigned int blocksize;
180         unsigned int cat_block;
181         unsigned int ext_block_start;
182         unsigned int ext_block_count;
183         unsigned int record_count;
184         unsigned int leaf_node_head;
185         unsigned int leaf_node_count;
186         unsigned int leaf_node_size;
187         unsigned int leaf_block;
188         int ext;
189         uint64_t leaf_off;
190         unsigned char *buf;
191
192         sbd = blkid_probe_get_sb(pr, mag, struct hfs_mdb);
193         if (!sbd)
194                 return -1;
195
196         /* Check for a HFS+ volume embedded in a HFS volume */
197         if (memcmp(sbd->signature, "BD", 2) == 0) {
198                 if ((memcmp(sbd->embed_sig, "H+", 2) != 0) &&
199                     (memcmp(sbd->embed_sig, "HX", 2) != 0))
200                         /* This must be an HFS volume, so fail */
201                         return 1;
202
203                 alloc_block_size = be32_to_cpu(sbd->al_blk_size);
204                 alloc_first_block = be16_to_cpu(sbd->al_bl_st);
205                 embed_first_block = be16_to_cpu(sbd->embed_startblock);
206                 off = (alloc_first_block * 512) +
207                         (embed_first_block * alloc_block_size);
208
209                 buf = blkid_probe_get_buffer(pr,
210                                 off + (mag->kboff * 1024),
211                                 sizeof(struct hfsplus_vol_header));
212                 hfsplus = (struct hfsplus_vol_header *) buf;
213
214         } else
215                 hfsplus = blkid_probe_get_sb(pr, mag,
216                                 struct hfsplus_vol_header);
217
218         if (!hfsplus)
219                 return -1;
220
221         if ((memcmp(hfsplus->signature, "H+", 2) != 0) &&
222             (memcmp(hfsplus->signature, "HX", 2) != 0))
223                 return 1;
224
225         hfs_set_uuid(pr, hfsplus->finder_info.id, sizeof(hfsplus->finder_info.id));
226
227         blocksize = be32_to_cpu(hfsplus->blocksize);
228         memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
229         cat_block = be32_to_cpu(extents[0].start_block);
230
231         buf = blkid_probe_get_buffer(pr,
232                         off + (cat_block * blocksize), 0x2000);
233         if (!buf)
234                 return 0;
235
236         bnode = (struct hfsplus_bheader_record *)
237                 &buf[sizeof(struct hfsplus_bnode_descriptor)];
238
239         leaf_node_head = be32_to_cpu(bnode->leaf_head);
240         leaf_node_size = be16_to_cpu(bnode->node_size);
241         leaf_node_count = be32_to_cpu(bnode->leaf_count);
242         if (leaf_node_count == 0)
243                 return 0;
244
245         leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
246
247         /* get physical location */
248         for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) {
249                 ext_block_start = be32_to_cpu(extents[ext].start_block);
250                 ext_block_count = be32_to_cpu(extents[ext].block_count);
251                 if (ext_block_count == 0)
252                         return 0;
253
254                 /* this is our extent */
255                 if (leaf_block < ext_block_count)
256                         break;
257
258                 leaf_block -= ext_block_count;
259         }
260         if (ext == HFSPLUS_EXTENT_COUNT)
261                 return 0;
262
263         leaf_off = (ext_block_start + leaf_block) * blocksize;
264
265         buf = blkid_probe_get_buffer(pr, off + leaf_off, leaf_node_size);
266         if (!buf)
267                 return 0;
268
269         descr = (struct hfsplus_bnode_descriptor *) buf;
270         record_count = be16_to_cpu(descr->num_recs);
271         if (record_count == 0)
272                 return 0;
273
274         if (descr->type != HFS_NODE_LEAF)
275                 return 0;
276
277         key = (struct hfsplus_catalog_key *)
278                 &buf[sizeof(struct hfsplus_bnode_descriptor)];
279
280         if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID)
281                 return 0;
282
283         blkid_probe_set_utf8label(pr, key->unicode,
284                         be16_to_cpu(key->unicode_len) * 2,
285                         BLKID_ENC_UTF16BE);
286         return 0;
287 }
288
289 const struct blkid_idinfo hfs_idinfo =
290 {
291         .name           = "hfs",
292         .usage          = BLKID_USAGE_FILESYSTEM,
293         .probefunc      = probe_hfs,
294         .magics         =
295         {
296                 { .magic = "BD", .len = 2, .kboff = 1 },
297                 { NULL }
298         }
299 };
300
301 const struct blkid_idinfo hfsplus_idinfo =
302 {
303         .name           = "hfsplus",
304         .usage          = BLKID_USAGE_FILESYSTEM,
305         .probefunc      = probe_hfsplus,
306         .magics         =
307         {
308                 { .magic = "BD", .len = 2, .kboff = 1 },
309                 { .magic = "H+", .len = 2, .kboff = 1 },
310                 { .magic = "HX", .len = 2, .kboff = 1 },
311                 { NULL }
312         }
313 };