VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxFsDxe/fsw_hfs.c@ 35072

最後變更 在這個檔案從35072是 33540,由 vboxsync 提交於 14 年 前

*: spelling fixes, thanks Timeless!

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 35.4 KB
 
1/* $Id: fsw_hfs.c 33540 2010-10-28 09:27:05Z vboxsync $ */
2/** @file
3 * fsw_hfs.c - HFS file system driver code, see
4 *
5 * http://developer.apple.com/technotes/tn/tn1150.html
6 *
7 * Current limitations:
8 * - Doesn't support permissions
9 * - Complete Unicode case-insensitiveness disabled (large tables)
10 * - No links
11 * - Only supports pure HFS+ (i.e. no HFS, or HFS+ embedded to HFS)
12 */
13
14/*
15 * Copyright (C) 2010 Oracle Corporation
16 *
17 * This file is part of VirtualBox Open Source Edition (OSE), as
18 * available from http://www.alldomusa.eu.org. This file is free software;
19 * you can redistribute it and/or modify it under the terms of the GNU
20 * General Public License (GPL) as published by the Free Software
21 * Foundation, in version 2 as it comes in the "COPYING" file of the
22 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
23 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
24 */
25
26#include "fsw_hfs.h"
27
28#ifdef HOST_POSIX
29#define DPRINT(x) printf(x)
30#define DPRINT2(x,y) printf(x,y)
31#define BP(msg) do { printf("ERROR: %s", msg); asm("int3"); } while (0)
32#else
33#define CONCAT(x,y) x##y
34#define DPRINT(x) Print(CONCAT(L,x))
35#define DPRINT2(x,y) Print(CONCAT(L,x), y)
36#define BP(msg) DPRINT(msg)
37#endif
38
39// functions
40#if 0
41void dump_str(fsw_u16* p, fsw_u32 len, int swap)
42{
43 int i;
44
45 for (i=0; i<len; i++)
46 {
47 fprintf(stderr, "%c", swap ? be16_to_cpu(p[i]) : p[i]);
48 }
49 fprintf(stderr, "\n");
50}
51#endif
52
53static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol);
54static void fsw_hfs_volume_free(struct fsw_hfs_volume *vol);
55static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb);
56
57static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno);
58static void fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno);
59static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
60 struct fsw_dnode_stat *sb);
61static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
62 struct fsw_extent *extent);
63
64static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
65 struct fsw_string *lookup_name, struct fsw_hfs_dnode **child_dno);
66static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
67 struct fsw_shandle *shand, struct fsw_hfs_dnode **child_dno);
68#if 0
69static fsw_status_t fsw_hfs_read_dirrec(struct fsw_shandle *shand, struct hfs_dirrec_buffer *dirrec_buffer);
70#endif
71
72static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
73 struct fsw_string *link);
74
75//
76// Dispatch Table
77//
78
79struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(hfs) = {
80 { FSW_STRING_TYPE_ISO88591, 4, 4, "hfs" },
81 sizeof(struct fsw_hfs_volume),
82 sizeof(struct fsw_hfs_dnode),
83
84 fsw_hfs_volume_mount,
85 fsw_hfs_volume_free,
86 fsw_hfs_volume_stat,
87 fsw_hfs_dnode_fill,
88 fsw_hfs_dnode_free,
89 fsw_hfs_dnode_stat,
90 fsw_hfs_get_extent,
91 fsw_hfs_dir_lookup,
92 fsw_hfs_dir_read,
93 fsw_hfs_readlink,
94};
95
96static fsw_s32
97fsw_hfs_read_block (struct fsw_hfs_dnode * dno,
98 fsw_u32 log_bno,
99 fsw_u32 off,
100 fsw_s32 len,
101 fsw_u8 * buf)
102{
103 fsw_status_t status;
104 struct fsw_extent extent;
105 fsw_u32 phys_bno;
106 fsw_u8* buffer;
107
108 extent.log_start = log_bno;
109 status = fsw_hfs_get_extent(dno->g.vol, dno, &extent);
110 if (status)
111 return status;
112
113 phys_bno = extent.phys_start;
114 status = fsw_block_get(dno->g.vol, phys_bno, 0, (void **)&buffer);
115 if (status)
116 return status;
117
118 fsw_memcpy(buf, buffer + off, len);
119
120 fsw_block_release(dno->g.vol, phys_bno, buffer);
121
122 return FSW_SUCCESS;
123
124}
125
126/* Read data from HFS file. */
127static fsw_s32
128fsw_hfs_read_file (struct fsw_hfs_dnode * dno,
129 fsw_u64 pos,
130 fsw_s32 len,
131 fsw_u8 * buf)
132{
133
134 fsw_status_t status;
135 fsw_u32 log_bno;
136 fsw_u32 block_size_bits = dno->g.vol->block_size_shift;
137 fsw_u32 block_size = (1 << block_size_bits);
138 fsw_u32 block_size_mask = block_size - 1;
139 fsw_s32 read = 0;
140
141 while (len > 0)
142 {
143 fsw_u32 off = (fsw_u32)(pos & block_size_mask);
144 fsw_s32 next_len = len;
145
146 log_bno = (fsw_u32)RShiftU64(pos, block_size_bits);
147
148 if ( next_len >= 0
149 && (fsw_u32)next_len > block_size)
150 next_len = block_size;
151 status = fsw_hfs_read_block(dno, log_bno, off, next_len, buf);
152 if (status)
153 return -1;
154 buf += next_len;
155 pos += next_len;
156 len -= next_len;
157 read += next_len;
158 }
159
160 return read;
161}
162
163
164static fsw_s32
165fsw_hfs_compute_shift(fsw_u32 size)
166{
167 fsw_s32 i;
168
169 for (i=0; i<32; i++)
170 {
171 if ((size >> i) == 0)
172 return i - 1;
173 }
174
175 BP("BUG\n");
176 return 0;
177}
178
179/**
180 * Mount an HFS+ volume. Reads the superblock and constructs the
181 * root directory dnode.
182 */
183
184static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol)
185{
186 fsw_status_t status, rv;
187 void *buffer = NULL;
188 HFSPlusVolumeHeader *voldesc;
189 fsw_u32 blockno;
190 struct fsw_string s;
191
192 rv = FSW_UNSUPPORTED;
193
194 vol->primary_voldesc = NULL;
195 fsw_set_blocksize(vol, HFS_BLOCKSIZE, HFS_BLOCKSIZE);
196 blockno = HFS_SUPERBLOCK_BLOCKNO;
197
198#define CHECK(s) \
199 if (status) { \
200 rv = status; \
201 break; \
202 }
203
204 vol->emb_block_off = 0;
205 vol->hfs_kind = 0;
206 do {
207 fsw_u16 signature;
208 BTHeaderRec tree_header;
209 fsw_s32 r;
210 fsw_u32 block_size;
211
212 status = fsw_block_get(vol, blockno, 0, &buffer);
213 CHECK(status);
214 voldesc = (HFSPlusVolumeHeader *)buffer;
215 signature = be16_to_cpu(voldesc->signature);
216
217 if ((signature == kHFSPlusSigWord) || (signature == kHFSXSigWord))
218 {
219 if (vol->hfs_kind == 0)
220 {
221 DPRINT("found HFS+\n");
222 vol->hfs_kind = FSW_HFS_PLUS;
223 }
224 }
225 else if (signature == kHFSSigWord)
226 {
227 HFSMasterDirectoryBlock* mdb = (HFSMasterDirectoryBlock*)buffer;
228
229 if (be16_to_cpu(mdb->drEmbedSigWord) == kHFSPlusSigWord)
230 {
231 DPRINT("found HFS+ inside HFS, untested\n");
232 vol->hfs_kind = FSW_HFS_PLUS_EMB;
233 vol->emb_block_off = be32_to_cpu(mdb->drEmbedExtent.startBlock);
234 blockno += vol->emb_block_off;
235 /* retry */
236 continue;
237 }
238 else
239 {
240 DPRINT("found plain HFS, unsupported\n");
241 vol->hfs_kind = FSW_HFS_PLAIN;
242 }
243 rv = FSW_UNSUPPORTED;
244 break;
245 }
246 else
247 {
248 rv = FSW_UNSUPPORTED;
249 break;
250 }
251
252 status = fsw_memdup((void **)&vol->primary_voldesc, voldesc,
253 sizeof(*voldesc));
254 CHECK(status);
255
256
257 block_size = be32_to_cpu(voldesc->blockSize);
258 vol->block_size_shift = fsw_hfs_compute_shift(block_size);
259
260 fsw_block_release(vol, blockno, buffer);
261 buffer = NULL;
262 voldesc = NULL;
263 fsw_set_blocksize(vol, block_size, block_size);
264
265 /* get volume name */
266 s.type = FSW_STRING_TYPE_ISO88591;
267 s.size = s.len = kHFSMaxVolumeNameChars;
268 s.data = "HFS+ volume";
269 status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
270 CHECK(status);
271
272 /* Setup catalog dnode */
273 status = fsw_dnode_create_root(vol, kHFSCatalogFileID, &vol->catalog_tree.file);
274 CHECK(status);
275 fsw_memcpy (vol->catalog_tree.file->extents,
276 vol->primary_voldesc->catalogFile.extents,
277 sizeof vol->catalog_tree.file->extents);
278 vol->catalog_tree.file->g.size =
279 be64_to_cpu(vol->primary_voldesc->catalogFile.logicalSize);
280
281 /* Setup extents overflow file */
282 status = fsw_dnode_create_root(vol, kHFSExtentsFileID, &vol->extents_tree.file);
283 fsw_memcpy (vol->extents_tree.file->extents,
284 vol->primary_voldesc->extentsFile.extents,
285 sizeof vol->extents_tree.file->extents);
286 vol->extents_tree.file->g.size =
287 be64_to_cpu(vol->primary_voldesc->extentsFile.logicalSize);
288
289 /* Setup the root dnode */
290 status = fsw_dnode_create_root(vol, kHFSRootFolderID, &vol->g.root);
291 CHECK(status);
292
293 /*
294 * Read catalog file, we know that first record is in the first node, right after
295 * the node descriptor.
296 */
297 r = fsw_hfs_read_file(vol->catalog_tree.file,
298 sizeof (BTNodeDescriptor),
299 sizeof (BTHeaderRec), (fsw_u8 *) &tree_header);
300 if (r <= 0)
301 {
302 status = FSW_VOLUME_CORRUPTED;
303 break;
304 }
305 vol->case_sensitive =
306 (signature == kHFSXSigWord) &&
307 (tree_header.keyCompareType == kHFSBinaryCompare);
308 vol->catalog_tree.root_node = be32_to_cpu (tree_header.rootNode);
309 vol->catalog_tree.node_size = be16_to_cpu (tree_header.nodeSize);
310
311 /* Read extents overflow file */
312 r = fsw_hfs_read_file(vol->extents_tree.file,
313 sizeof (BTNodeDescriptor),
314 sizeof (BTHeaderRec), (fsw_u8 *) &tree_header);
315 if (r <= 0)
316 {
317 status = FSW_VOLUME_CORRUPTED;
318 break;
319 }
320
321 vol->extents_tree.root_node = be32_to_cpu (tree_header.rootNode);
322 vol->extents_tree.node_size = be16_to_cpu (tree_header.nodeSize);
323
324 rv = FSW_SUCCESS;
325 } while (0);
326
327#undef CHECK
328
329
330 if (buffer != NULL)
331 fsw_block_release(vol, blockno, buffer);
332
333 return rv;
334}
335
336/**
337 * Free the volume data structure. Called by the core after an unmount or after
338 * an unsuccessful mount to release the memory used by the file system type specific
339 * part of the volume structure.
340 */
341
342static void fsw_hfs_volume_free(struct fsw_hfs_volume *vol)
343{
344 if (vol->primary_voldesc)
345 {
346 fsw_free(vol->primary_voldesc);
347 vol->primary_voldesc = NULL;
348 }
349}
350
351/**
352 * Get in-depth information on a volume.
353 */
354
355static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb)
356{
357 sb->total_bytes = be32_to_cpu(vol->primary_voldesc->totalBlocks) << vol->block_size_shift;
358 sb->free_bytes = be32_to_cpu(vol->primary_voldesc->freeBlocks) << vol->block_size_shift;
359 return FSW_SUCCESS;
360}
361
362/**
363 * Get full information on a dnode from disk. This function is called by the core
364 * whenever it needs to access fields in the dnode structure that may not
365 * be filled immediately upon creation of the dnode.
366 */
367
368static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno)
369{
370 return FSW_SUCCESS;
371}
372
373/**
374 * Free the dnode data structure. Called by the core when deallocating a dnode
375 * structure to release the memory used by the file system type specific part
376 * of the dnode structure.
377 */
378
379static void fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno)
380{
381}
382
383static fsw_u32 mac_to_posix(fsw_u32 mac_time)
384{
385 /* Mac time is 1904 year based */
386 return mac_time ? mac_time - 2082844800 : 0;
387}
388
389/**
390 * Get in-depth information on a dnode. The core makes sure that fsw_hfs_dnode_fill
391 * has been called on the dnode before this function is called. Note that some
392 * data is not directly stored into the structure, but passed to a host-specific
393 * callback that converts it to the host-specific format.
394 */
395
396static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol,
397 struct fsw_hfs_dnode *dno,
398 struct fsw_dnode_stat *sb)
399{
400 sb->used_bytes = dno->used_bytes;
401 sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, mac_to_posix(dno->ctime));
402 sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, mac_to_posix(dno->mtime));
403 sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, 0);
404 sb->store_attr_posix(sb, 0700);
405
406 return FSW_SUCCESS;
407}
408
409static int
410fsw_hfs_find_block(HFSPlusExtentRecord * exts,
411 fsw_u32 * lbno,
412 fsw_u32 * pbno)
413{
414 int i;
415 fsw_u32 cur_lbno = *lbno;
416
417 for (i = 0; i < 8; i++)
418 {
419 fsw_u32 start = be32_to_cpu ((*exts)[i].startBlock);
420 fsw_u32 count = be32_to_cpu ((*exts)[i].blockCount);
421
422 if (cur_lbno < count)
423 {
424 *pbno = start + cur_lbno;
425 return 1;
426 }
427
428 cur_lbno -= count;
429 }
430
431 *lbno = cur_lbno;
432
433 return 0;
434}
435
436/* Find record offset, numbering starts from the end */
437static fsw_u32
438fsw_hfs_btree_recoffset (struct fsw_hfs_btree * btree,
439 BTNodeDescriptor * node,
440 fsw_u32 index)
441{
442 fsw_u8 *cnode = (fsw_u8 *) node;
443 fsw_u16 *recptr;
444 recptr = (fsw_u16 *) (cnode+btree->node_size - index * 2 - 2);
445 return be16_to_cpu(*recptr);
446}
447
448/* Pointer to the key inside node */
449static BTreeKey *
450fsw_hfs_btree_rec (struct fsw_hfs_btree * btree,
451 BTNodeDescriptor * node,
452 fsw_u32 index)
453{
454 fsw_u8 *cnode = (fsw_u8 *) node;
455 fsw_u32 offset;
456 offset = fsw_hfs_btree_recoffset (btree, node, index);
457 return (BTreeKey *) (cnode + offset);
458}
459
460
461static fsw_status_t
462fsw_hfs_btree_search (struct fsw_hfs_btree * btree,
463 BTreeKey * key,
464 int (*compare_keys) (BTreeKey* key1, BTreeKey* key2),
465 BTNodeDescriptor ** result,
466 fsw_u32 * key_offset)
467{
468 BTNodeDescriptor* node;
469 fsw_u32 currnode;
470 fsw_u32 rec;
471 fsw_status_t status;
472 fsw_u8* buffer = NULL;
473
474 currnode = btree->root_node;
475 status = fsw_alloc(btree->node_size, &buffer);
476 if (status)
477 return status;
478 node = (BTNodeDescriptor*)buffer;
479
480 while (1)
481 {
482 int cmp = 0;
483 int match;
484 fsw_u32 count;
485
486 readnode:
487 match = 0;
488 /* Read a node. */
489 if (fsw_hfs_read_file (btree->file,
490 (fsw_u64)currnode * btree->node_size,
491 btree->node_size, buffer) <= 0)
492 {
493 status = FSW_VOLUME_CORRUPTED;
494 break;
495 }
496
497 if (be16_to_cpu(*(fsw_u16*)(buffer + btree->node_size - 2)) != sizeof(BTNodeDescriptor))
498 BP("corrupted node\n");
499
500 count = be16_to_cpu (node->numRecords);
501
502#if 1
503 for (rec = 0; rec < count; rec++)
504 {
505 BTreeKey *currkey;
506
507 currkey = fsw_hfs_btree_rec (btree, node, rec);
508 cmp = compare_keys (currkey, key);
509 //fprintf(stderr, "rec=%d cmp=%d kind=%d \n", rec, cmp, node->kind);
510
511 /* Leaf node. */
512 if (node->kind == kBTLeafNode)
513 {
514 if (cmp == 0)
515 {
516 /* Found! */
517 *result = node;
518 *key_offset = rec;
519
520 status = FSW_SUCCESS;
521 goto done;
522 }
523 }
524 else if (node->kind == kBTIndexNode)
525 {
526 fsw_u32 *pointer;
527
528 if (cmp > 0)
529 break;
530
531 pointer = (fsw_u32 *) ((char *) currkey
532 + be16_to_cpu (currkey->length16)
533 + 2);
534 currnode = be32_to_cpu (*pointer);
535 match = 1;
536 }
537 }
538
539 if (node->kind == kBTLeafNode && cmp < 0 && node->fLink)
540 {
541 currnode = be32_to_cpu(node->fLink);
542 goto readnode;
543 }
544 else if (!match)
545 {
546 status = FSW_NOT_FOUND;
547 break;
548 }
549#else
550 /* Perform binary search */
551 fsw_u32 lower = 0;
552 fsw_u32 upper = count - 1;
553 fsw_s32 cmp = -1;
554 BTreeKey *currkey = NULL;
555
556 if (count == 0)
557 {
558 status = FSW_NOT_FOUND;
559 goto done;
560 }
561
562 while (lower <= upper)
563 {
564 fsw_u32 index = (lower + upper) / 2;
565
566 currkey = fsw_hfs_btree_rec (btree, node, index);
567
568 cmp = compare_keys (currkey, key);
569 if (cmp < 0) upper = index - 1;
570 if (cmp > 0) lower = index + 1;
571 if (cmp == 0)
572 {
573 /* Found! */
574 *result = node;
575 *key_offset = rec;
576
577 status = FSW_SUCCESS;
578 goto done;
579 }
580 }
581
582 if (cmp < 0)
583 currkey = fsw_hfs_btree_rec (btree, node, upper);
584
585 if (node->kind == kBTIndexNode && currkey)
586 {
587 fsw_u32 *pointer;
588
589 pointer = (fsw_u32 *) ((char *) currkey
590 + be16_to_cpu (currkey->length16)
591 + 2);
592 currnode = be32_to_cpu (*pointer);
593 }
594 else
595 {
596 status = FSW_NOT_FOUND;
597 break;
598 }
599#endif
600 }
601
602
603 done:
604 if (buffer != NULL && status != FSW_SUCCESS)
605 fsw_free(buffer);
606
607 return status;
608}
609typedef struct
610{
611 fsw_u32 id;
612 fsw_u32 type;
613 struct fsw_string * name;
614 fsw_u64 size;
615 fsw_u64 used;
616 fsw_u32 ctime;
617 fsw_u32 mtime;
618 HFSPlusExtentRecord extents;
619} file_info_t;
620
621typedef struct
622{
623 fsw_u32 cur_pos; /* current position */
624 fsw_u32 parent;
625 struct fsw_hfs_volume * vol;
626
627 struct fsw_shandle * shandle; /* this one track iterator's state */
628 file_info_t file_info;
629} visitor_parameter_t;
630
631static int
632fsw_hfs_btree_visit_node(BTreeKey *record, void* param)
633{
634 visitor_parameter_t* vp = (visitor_parameter_t*)param;
635 fsw_u8* base = (fsw_u8*)record->rawData + be16_to_cpu(record->length16) + 2;
636 fsw_u16 rec_type = be16_to_cpu(*(fsw_u16*)base);
637 struct HFSPlusCatalogKey* cat_key = (HFSPlusCatalogKey*)record;
638 fsw_u16 name_len;
639 fsw_u16 *name_ptr;
640 fsw_u32 i;
641 struct fsw_string * file_name;
642
643 if (be32_to_cpu(cat_key->parentID) != vp->parent)
644 return -1;
645
646 /* not smth we care about */
647 if (vp->shandle->pos != vp->cur_pos++)
648 return 0;
649
650 switch (rec_type)
651 {
652 case kHFSPlusFolderRecord:
653 {
654 HFSPlusCatalogFolder* folder_info = (HFSPlusCatalogFolder*)base;
655
656 vp->file_info.id = be32_to_cpu(folder_info->folderID);
657 vp->file_info.type = FSW_DNODE_TYPE_DIR;
658 vp->file_info.size = be32_to_cpu(folder_info->valence);
659 vp->file_info.used = be32_to_cpu(folder_info->valence);
660 vp->file_info.ctime = be32_to_cpu(folder_info->createDate);
661 vp->file_info.mtime = be32_to_cpu(folder_info->contentModDate);
662 break;
663 }
664 case kHFSPlusFileRecord:
665 {
666 HFSPlusCatalogFile* file_info = (HFSPlusCatalogFile*)base;
667
668 vp->file_info.id = be32_to_cpu(file_info->fileID);
669 vp->file_info.type = FSW_DNODE_TYPE_FILE;
670 vp->file_info.size = be64_to_cpu(file_info->dataFork.logicalSize);
671 vp->file_info.used = LShiftU64(be32_to_cpu(file_info->dataFork.totalBlocks),
672 vp->vol->block_size_shift);
673 vp->file_info.ctime = be32_to_cpu(file_info->createDate);
674 vp->file_info.mtime = be32_to_cpu(file_info->contentModDate);
675 fsw_memcpy(&vp->file_info.extents, &file_info->dataFork.extents,
676 sizeof vp->file_info.extents);
677 break;
678 }
679 case kHFSPlusFolderThreadRecord:
680 case kHFSPlusFileThreadRecord:
681 {
682 vp->shandle->pos++;
683 return 0;
684 }
685 default:
686 BP("unknown file type\n");
687 vp->file_info.type = FSW_DNODE_TYPE_UNKNOWN;
688 break;
689 }
690
691 name_len = be16_to_cpu(cat_key->nodeName.length);
692
693 file_name = vp->file_info.name;
694 file_name->len = name_len;
695 fsw_memdup(&file_name->data, &cat_key->nodeName.unicode[0], 2*name_len);
696 file_name->size = 2*name_len;
697 file_name->type = FSW_STRING_TYPE_UTF16;
698 name_ptr = (fsw_u16*)file_name->data;
699 for (i=0; i<name_len; i++)
700 {
701 name_ptr[i] = be16_to_cpu(name_ptr[i]);
702 }
703 vp->shandle->pos++;
704
705 return 1;
706}
707
708static fsw_status_t
709fsw_hfs_btree_iterate_node (struct fsw_hfs_btree * btree,
710 BTNodeDescriptor * first_node,
711 fsw_u32 first_rec,
712 int (*callback) (BTreeKey *record, void* param),
713 void * param)
714{
715 fsw_status_t status;
716 /* We modify node, so make a copy */
717 BTNodeDescriptor* node = first_node;
718 fsw_u8* buffer = NULL;
719
720 status = fsw_alloc(btree->node_size, &buffer);
721 if (status)
722 return status;
723
724 while (1)
725 {
726 fsw_u32 i;
727 fsw_u32 count = be16_to_cpu(node->numRecords);
728 fsw_u32 next_node;
729
730 /* Iterate over all records in this node. */
731 for (i = first_rec; i < count; i++)
732 {
733 int rv = callback(fsw_hfs_btree_rec (btree, node, i), param);
734
735 switch (rv)
736 {
737 case 1:
738 status = FSW_SUCCESS;
739 goto done;
740 case -1:
741 status = FSW_NOT_FOUND;
742 goto done;
743 }
744 /* if callback returned 0 - continue */
745 }
746
747 next_node = be32_to_cpu(node->fLink);
748
749 if (!next_node)
750 {
751 status = FSW_NOT_FOUND;
752 break;
753 }
754
755 if (fsw_hfs_read_file (btree->file,
756 next_node * btree->node_size,
757 btree->node_size, buffer) <= 0)
758 {
759 status = FSW_VOLUME_CORRUPTED;
760 return 1;
761 }
762
763 node = (BTNodeDescriptor*)buffer;
764 first_rec = 0;
765 }
766 done:
767 if (buffer)
768 fsw_free(buffer);
769
770 return status;
771}
772
773#if 0
774void deb(fsw_u16* p, int len, int swap)
775{
776 int i;
777 for (i=0; i<len; i++)
778 {
779 printf("%c", swap ? be16_to_cpu(p[i]) : p[i]);
780 }
781 printf("\n");
782}
783#endif
784
785static int
786fsw_hfs_cmp_extkey(BTreeKey* key1, BTreeKey* key2)
787{
788 HFSPlusExtentKey* ekey1 = (HFSPlusExtentKey*)key1;
789 HFSPlusExtentKey* ekey2 = (HFSPlusExtentKey*)key2;
790 int result;
791
792 /* First key is read from the FS data, second is in-memory in CPU endianess */
793 result = be32_to_cpu(ekey1->fileID) - ekey2->fileID;
794
795 if (result)
796 return result;
797
798 result = ekey1->forkType - ekey2->forkType;
799
800 if (result)
801 return result;
802
803 result = be32_to_cpu(ekey1->startBlock) - ekey2->startBlock;
804 return result;
805}
806
807static int
808fsw_hfs_cmp_catkey (BTreeKey *key1, BTreeKey *key2)
809{
810 HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1;
811 HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2;
812
813 int apos, bpos, lc;
814 fsw_u16 ac, bc;
815 fsw_u32 parentId1;
816 int key1Len;
817 fsw_u16 *p1;
818 fsw_u16 *p2;
819
820 parentId1 = be32_to_cpu(ckey1->parentID);
821
822 if (parentId1 > ckey2->parentID)
823 return 1;
824 if (parentId1 < ckey2->parentID)
825 return -1;
826
827 p1 = &ckey1->nodeName.unicode[0];
828 p2 = &ckey2->nodeName.unicode[0];
829 key1Len = be16_to_cpu (ckey1->nodeName.length);
830 apos = bpos = 0;
831
832 while(1)
833 {
834 /* get next valid character from ckey1 */
835 for (lc = 0; lc == 0 && apos < key1Len; apos++) {
836 ac = be16_to_cpu(p1[apos]);
837 lc = ac;
838 };
839 ac = (fsw_u16)lc;
840
841 /* get next valid character from ckey2 */
842 for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) {
843 bc = p2[bpos];
844 lc = bc;
845 };
846 bc = (fsw_u16)lc;
847
848 if (ac != bc || (ac == 0 && bc == 0))
849 return ac - bc;
850 }
851}
852
853static int
854fsw_hfs_cmpi_catkey (BTreeKey *key1, BTreeKey *key2)
855{
856 HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1;
857 HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2;
858
859 int apos, bpos, lc;
860 fsw_u16 ac, bc;
861 fsw_u32 parentId1;
862 int key1Len;
863 fsw_u16 *p1;
864 fsw_u16 *p2;
865
866 parentId1 = be32_to_cpu(ckey1->parentID);
867
868 if (parentId1 > ckey2->parentID)
869 return 1;
870 if (parentId1 < ckey2->parentID)
871 return -1;
872
873 key1Len = be16_to_cpu (ckey1->nodeName.length);
874
875 if (key1Len == 0 && ckey2->nodeName.length == 0)
876 return 0;
877
878 p1 = &ckey1->nodeName.unicode[0];
879 p2 = &ckey2->nodeName.unicode[0];
880
881 apos = bpos = 0;
882
883 while(1)
884 {
885 /* get next valid character from ckey1 */
886 for (lc = 0; lc == 0 && apos < key1Len; apos++) {
887 ac = be16_to_cpu(p1[apos]);
888 lc = ac ? fsw_to_lower(ac) : 0;
889 };
890 ac = (fsw_u16)lc;
891
892 /* get next valid character from ckey2 */
893 for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) {
894 bc = p2[bpos];
895 lc = bc ? fsw_to_lower(bc) : 0;
896 };
897 bc = (fsw_u16)lc;
898
899 if (ac != bc || (ac == 0 && bc == 0))
900 return ac - bc;
901 }
902}
903
904/**
905 * Retrieve file data mapping information. This function is called by the core when
906 * fsw_shandle_read needs to know where on the disk the required piece of the file's
907 * data can be found. The core makes sure that fsw_hfs_dnode_fill has been called
908 * on the dnode before. Our task here is to get the physical disk block number for
909 * the requested logical block number.
910 */
911
912static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume * vol,
913 struct fsw_hfs_dnode * dno,
914 struct fsw_extent * extent)
915{
916 fsw_status_t status;
917 fsw_u32 lbno;
918 HFSPlusExtentRecord *exts;
919 BTNodeDescriptor *node = NULL;
920
921 extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
922 extent->log_count = 1;
923 lbno = extent->log_start;
924
925 /* we only care about data forks atm, do we? */
926 exts = &dno->extents;
927
928 while (1)
929 {
930 struct HFSPlusExtentKey* key;
931 struct HFSPlusExtentKey overflowkey;
932 fsw_u32 ptr;
933 fsw_u32 phys_bno;
934
935 if (fsw_hfs_find_block(exts, &lbno, &phys_bno))
936 {
937 extent->phys_start = phys_bno + vol->emb_block_off;
938 status = FSW_SUCCESS;
939 break;
940 }
941
942
943 /* Find appropriate overflow record */
944 overflowkey.fileID = dno->g.dnode_id;
945 overflowkey.startBlock = extent->log_start - lbno;
946
947 if (node != NULL)
948 {
949 fsw_free(node);
950 node = NULL;
951 }
952
953 status = fsw_hfs_btree_search (&vol->extents_tree,
954 (BTreeKey*)&overflowkey,
955 fsw_hfs_cmp_extkey,
956 &node, &ptr);
957 if (status)
958 break;
959
960 key = (struct HFSPlusExtentKey *)
961 fsw_hfs_btree_rec (&vol->extents_tree, node, ptr);
962 exts = (HFSPlusExtentRecord*) (key + 1);
963 }
964
965 if (node != NULL)
966 fsw_free(node);
967
968 return status;
969}
970
971static const fsw_u16* g_blacklist[] =
972{
973 //L"AppleIntelCPUPowerManagement.kext",
974 NULL
975};
976
977
978//#define HFS_FILE_INJECTION
979
980#ifdef HFS_FILE_INJECTION
981static struct
982{
983 const fsw_u16* path;
984 const fsw_u16* name;
985} g_injectList[] =
986{
987 {
988 L"/System/Library/Extensions",
989 L"ApplePS2Controller.kext"
990 },
991 {
992 NULL,
993 NULL
994 }
995};
996#endif
997
998static fsw_status_t
999create_hfs_dnode(struct fsw_hfs_dnode * dno,
1000 file_info_t * file_info,
1001 struct fsw_hfs_dnode ** child_dno_out)
1002{
1003 fsw_status_t status;
1004 struct fsw_hfs_dnode * baby;
1005
1006 status = fsw_dnode_create(dno, file_info->id, file_info->type,
1007 file_info->name, &baby);
1008 if (status)
1009 return status;
1010
1011 baby->g.size = file_info->size;
1012 baby->used_bytes = file_info->used;
1013 baby->ctime = file_info->ctime;
1014 baby->mtime = file_info->mtime;
1015
1016
1017 /* Fill-in extents info */
1018 if (file_info->type == FSW_DNODE_TYPE_FILE)
1019 {
1020 fsw_memcpy(baby->extents, &file_info->extents, sizeof file_info->extents);
1021 }
1022
1023 *child_dno_out = baby;
1024
1025 return FSW_SUCCESS;
1026}
1027
1028
1029/**
1030 * Lookup a directory's child dnode by name. This function is called on a directory
1031 * to retrieve the directory entry with the given name. A dnode is constructed for
1032 * this entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called
1033 * and the dnode is actually a directory.
1034 */
1035
1036static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume * vol,
1037 struct fsw_hfs_dnode * dno,
1038 struct fsw_string * lookup_name,
1039 struct fsw_hfs_dnode ** child_dno_out)
1040{
1041 fsw_status_t status;
1042 struct HFSPlusCatalogKey catkey;
1043 fsw_u32 ptr;
1044 fsw_u16 rec_type;
1045 BTNodeDescriptor * node = NULL;
1046 struct fsw_string rec_name;
1047 int free_data = 0, i;
1048 HFSPlusCatalogKey* file_key;
1049 file_info_t file_info;
1050 fsw_u8* base;
1051
1052
1053 fsw_memzero(&file_info, sizeof file_info);
1054 file_info.name = &rec_name;
1055
1056 catkey.parentID = dno->g.dnode_id;
1057 catkey.nodeName.length = (fsw_u16)lookup_name->len;
1058
1059 /* no need to allocate anything */
1060 if (lookup_name->type == FSW_STRING_TYPE_UTF16)
1061 {
1062 fsw_memcpy(catkey.nodeName.unicode, lookup_name->data, lookup_name->size);
1063 rec_name = *lookup_name;
1064 } else
1065 {
1066 status = fsw_strdup_coerce(&rec_name, FSW_STRING_TYPE_UTF16, lookup_name);
1067 /* nothing allocated so far */
1068 if (status)
1069 goto done;
1070 free_data = 1;
1071 fsw_memcpy(catkey.nodeName.unicode, rec_name.data, rec_name.size);
1072 }
1073
1074 /* Dirty hack: blacklisting of certain files on FS driver level */
1075 for (i = 0; g_blacklist[i]; i++)
1076 {
1077 if (fsw_memeq(g_blacklist[i], catkey.nodeName.unicode, catkey.nodeName.length*2))
1078 {
1079 DPRINT2("Blacklisted %s\n", g_blacklist[i]);
1080 status = FSW_NOT_FOUND;
1081 goto done;
1082 }
1083 }
1084
1085#ifdef HFS_FILE_INJECTION
1086 if (fsw_hfs_inject(vol,
1087 dno,
1088 catkey.nodeName.unicode,
1089 catkey.nodeName.length,
1090 &file_info))
1091 {
1092 status = FSW_SUCCESS;
1093 goto create;
1094 }
1095#endif
1096
1097 catkey.keyLength = (fsw_u16)(5 + rec_name.size);
1098
1099 status = fsw_hfs_btree_search (&vol->catalog_tree,
1100 (BTreeKey*)&catkey,
1101 vol->case_sensitive ?
1102 fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
1103 &node, &ptr);
1104 if (status)
1105 goto done;
1106
1107 file_key = (HFSPlusCatalogKey *)fsw_hfs_btree_rec (&vol->catalog_tree, node, ptr);
1108 /* for plain HFS "-(keySize & 1)" would be needed */
1109 base = (fsw_u8*)file_key + be16_to_cpu(file_key->keyLength) + 2;
1110 rec_type = be16_to_cpu(*(fsw_u16*)base);
1111
1112 /** @todo: read additional info */
1113 switch (rec_type)
1114 {
1115 case kHFSPlusFolderRecord:
1116 {
1117 HFSPlusCatalogFolder* info = (HFSPlusCatalogFolder*)base;
1118
1119 file_info.id = be32_to_cpu(info->folderID);
1120 file_info.type = FSW_DNODE_TYPE_DIR;
1121 /* @todo: return number of elements, maybe use smth else */
1122 file_info.size = be32_to_cpu(info->valence);
1123 file_info.used = be32_to_cpu(info->valence);
1124 file_info.ctime = be32_to_cpu(info->createDate);
1125 file_info.mtime = be32_to_cpu(info->contentModDate);
1126 break;
1127 }
1128 case kHFSPlusFileRecord:
1129 {
1130 HFSPlusCatalogFile* info = (HFSPlusCatalogFile*)base;
1131
1132 file_info.id = be32_to_cpu(info->fileID);
1133 file_info.type = FSW_DNODE_TYPE_FILE;
1134 file_info.size = be64_to_cpu(info->dataFork.logicalSize);
1135 file_info.used = LShiftU64(be32_to_cpu(info->dataFork.totalBlocks), vol->block_size_shift);
1136 file_info.ctime = be32_to_cpu(info->createDate);
1137 file_info.mtime = be32_to_cpu(info->contentModDate);
1138 fsw_memcpy(&file_info.extents, &info->dataFork.extents,
1139 sizeof file_info.extents);
1140 break;
1141 }
1142 default:
1143 BP("unknown file type\n");
1144 file_info.type = FSW_DNODE_TYPE_UNKNOWN;
1145
1146 break;
1147 }
1148#ifdef HFS_FILE_INJECTION
1149create:
1150#endif
1151 status = create_hfs_dnode(dno, &file_info, child_dno_out);
1152 if (status)
1153 goto done;
1154
1155done:
1156
1157 if (node != NULL)
1158 fsw_free(node);
1159
1160 if (free_data)
1161 fsw_strfree(&rec_name);
1162
1163 return status;
1164}
1165
1166/**
1167 * Get the next directory entry when reading a directory. This function is called during
1168 * directory iteration to retrieve the next directory entry. A dnode is constructed for
1169 * the entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called
1170 * and the dnode is actually a directory. The shandle provided by the caller is used to
1171 * record the position in the directory between calls.
1172 */
1173
1174static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol,
1175 struct fsw_hfs_dnode *dno,
1176 struct fsw_shandle *shand,
1177 struct fsw_hfs_dnode **child_dno_out)
1178{
1179 fsw_status_t status;
1180 struct HFSPlusCatalogKey catkey;
1181 fsw_u32 ptr;
1182 BTNodeDescriptor * node = NULL;
1183
1184 visitor_parameter_t param;
1185 struct fsw_string rec_name;
1186
1187 catkey.parentID = dno->g.dnode_id;
1188 catkey.nodeName.length = 0;
1189
1190 fsw_memzero(&param, sizeof(param));
1191
1192 rec_name.type = FSW_STRING_TYPE_EMPTY;
1193 param.file_info.name = &rec_name;
1194
1195 status = fsw_hfs_btree_search (&vol->catalog_tree,
1196 (BTreeKey*)&catkey,
1197 vol->case_sensitive ?
1198 fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
1199 &node, &ptr);
1200 if (status)
1201 goto done;
1202
1203 /* Iterator updates shand state */
1204 param.vol = vol;
1205 param.shandle = shand;
1206 param.parent = dno->g.dnode_id;
1207 param.cur_pos = 0;
1208 status = fsw_hfs_btree_iterate_node (&vol->catalog_tree,
1209 node,
1210 ptr,
1211 fsw_hfs_btree_visit_node,
1212 &param);
1213 if (status)
1214 goto done;
1215
1216 status = create_hfs_dnode(dno, &param.file_info, child_dno_out);
1217
1218 if (status)
1219 goto done;
1220
1221 done:
1222 fsw_strfree(&rec_name);
1223
1224 return status;
1225}
1226
1227/**
1228 * Get the target path of a symbolic link. This function is called when a symbolic
1229 * link needs to be resolved. The core makes sure that the fsw_hfs_dnode_fill has been
1230 * called on the dnode and that it really is a symlink.
1231 *
1232 */
1233static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
1234 struct fsw_string *link_target)
1235{
1236 return FSW_UNSUPPORTED;
1237}
1238
1239// EOF
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette