Chameleon

Chameleon Commit Details

Date:2011-06-25 22:25:50 (3 years 2 months ago)
Author:Evan Lojewski
Commit:1076
Parents: 1075
Message:Removed disk code + fs code from libsaio. Moved modulesystem to within /modules/ folder
Changes:
D/branches/rewrite/i386/libsaio/ntfs_private.h
D/branches/rewrite/i386/libsaio/ntfs.c
D/branches/rewrite/i386/libsaio/ext2fs.c
D/branches/rewrite/i386/libsaio/hfs_CaseTables.h
D/branches/rewrite/i386/libsaio/ntfs.h
D/branches/rewrite/i386/libsaio/nbp.c
D/branches/rewrite/i386/libsaio/ext2fs.h
D/branches/rewrite/i386/libsaio/hfs.c
D/branches/rewrite/i386/libsaio/ufs_byteorder.h
D/branches/rewrite/i386/libsaio/hfs.h
D/branches/rewrite/i386/libsaio/hfs_compare.c
D/branches/rewrite/i386/libsaio/disk.c
D/branches/rewrite/Chameleon.xcodeproj
D/branches/rewrite/i386/libsaio/disk.h
D/branches/rewrite/i386/modules/include/modules
D/branches/rewrite/i386/libsaio/ufs.h
D/branches/rewrite/i386/libsaio/nbp_cmd.h
D/branches/rewrite/i386/boot2/modules.c
D/branches/rewrite/i386/libsaio/stringTable.c
D/branches/rewrite/i386/boot2/modules.h
D/branches/rewrite/i386/libsaio/msdos_private.h
D/branches/rewrite/i386/libsaio/msdos.c
D/branches/rewrite/i386/boot2/modules_support.s
D/branches/rewrite/i386/libsaio/msdos.h
M/branches/rewrite/i386/boot2/Makefile
M/branches/rewrite/i386/boot2/boot.c
M/branches/rewrite/i386/modules/Cconfig
M/branches/rewrite/i386/libsaio/sys.c
M/branches/rewrite/i386/boot2/mboot.c
M/branches/rewrite/i386/libsaio/Makefile
M/branches/rewrite/i386/modules/FileSystem/FileSystem.cpp
M/branches/rewrite/i386/Cconfig
M/branches/rewrite/i386/modules/FileSystem/Makefile
M/branches/rewrite/i386/modules/Makefile
M/branches/rewrite/i386/libsaio/saio_types.h
M/branches/rewrite/i386/modules/MakeInc.dir
M/branches/rewrite/i386/boot2/Cconfig
M/branches/rewrite/i386/libsaio/saio_internal.h

File differences

branches/rewrite/i386/libsaio/ntfs_private.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*$NetBSD: ntfs.h,v 1.9 1999/10/31 19:45:26 jdolecek Exp $*/
/*-
* Copyright (c) 1998, 1999 Semen Ustimenko
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: src/sys/fs/ntfs/ntfs.h,v 1.14 2001/11/27 00:18:33 jhb Exp $
*/
/*#define NTFS_DEBUG 1*/
#ifdef APPLE
/* We're using FreeBSD style byte order macros in the source. */
#include <libkern/OSByteOrder.h>
#define le16toh(x)OSSwapLittleToHostInt16(x)
#define le32toh(x)OSSwapLittleToHostInt32(x)
#define le64toh(x)OSSwapLittleToHostInt64(x)
/* FreeBSD mutexes correspond to Darwin's simple locks */
#define mtx_lock(lock)simple_lock(lock)
#define mtx_unlock(lock)simple_unlock(lock)
#define mtx_destroy(lock)/* Nothing. */
#define lockdestroy(lock)/* Nothing. */
#endif
typedef u_int64_t cn_t;
typedef u_int16_t wchar;
#pragma pack(1)
#define BBSIZE1024
#defineBBOFF((off_t)(0))
#defineBBLOCK((daddr_t)(0))
#defineNTFS_MFTINO0
#defineNTFS_VOLUMEINO3
#defineNTFS_ATTRDEFINO4
#defineNTFS_ROOTINO5
#defineNTFS_BITMAPINO6
#defineNTFS_BOOTINO7
#defineNTFS_BADCLUSINO8
#defineNTFS_UPCASEINO10
#define NTFS_MAXFILENAME255
struct fixuphdr {
u_int32_t fh_magic;
u_int16_t fh_foff;
u_int16_t fh_fnum;
};
#define NTFS_AF_INRUN0x00000001
struct attrhdr {
u_int32_t a_type;
u_int32_t reclen;
u_int8_t a_flag;
u_int8_t a_namelen;
u_int8_t a_nameoff;
u_int8_t reserved1;
u_int8_t a_compression;
u_int8_t reserved2;
u_int16_t a_index;
};
#define NTFS_A_STD0x10
#define NTFS_A_ATTRLIST0x20
#define NTFS_A_NAME0x30
#define NTFS_A_VOLUMENAME0x60
#define NTFS_A_DATA0x80
#defineNTFS_A_INDXROOT0x90
#defineNTFS_A_INDX0xA0
#define NTFS_A_INDXBITMAP 0xB0
#define NTFS_MAXATTRNAME255
struct attr {
struct attrhdr a_hdr;
union {
struct {
u_int16_t a_datalen;
u_int16_t reserved1;
u_int16_t a_dataoff;
u_int16_t a_indexed;
} a_S_r;
struct {
cn_t a_vcnstart;
cn_t a_vcnend;
u_int16_t a_dataoff;
u_int16_t a_compressalg;
u_int32_t reserved1;
u_int64_t a_allocated;
u_int64_t a_datalen;
u_int64_t a_initialized;
} a_S_nr;
} a_S;
};
#define a_ra_S.a_S_r
#define a_nra_S.a_S_nr
typedef struct {
u_int64_t t_create;
u_int64_t t_write;
u_int64_t t_mftwrite;
u_int64_t t_access;
} ntfs_times_t;
#define NTFS_FFLAG_RDONLY0x01LL
#define NTFS_FFLAG_HIDDEN0x02LL
#define NTFS_FFLAG_SYSTEM0x04LL
#define NTFS_FFLAG_ARCHIVE0x20LL
#define NTFS_FFLAG_COMPRESSED0x0800LL
#define NTFS_FFLAG_DIR0x10000000LL
struct attr_name {
u_int32_tn_pnumber;/* Parent ntnode */
u_int32_t reserved;
ntfs_times_t n_times;
u_int64_t n_size;
u_int64_t n_attrsz;
u_int64_t n_flag;
u_int8_t n_namelen;
u_int8_t n_nametype;
u_int16_t n_name[1];
};
#define NTFS_IRFLAG_INDXALLOC0x00000001
struct attr_indexroot {
u_int32_t ir_unkn1;/* attribute type (0x30 for $FILE_NAME) */
u_int32_t ir_unkn2;/* collation rule (0x01 for file names) */
u_int32_t ir_size;/* size of index allocation entry */
u_int32_t ir_unkn3;/* clusters per index record, and 3 bytes padding */
u_int32_t ir_unkn4;/* (offset to first index entry?) always 0x10 */
u_int32_t ir_datalen;/* (total size of index enties?) sizeof something */
u_int32_t ir_allocated;/* (allocated size of index entries?) */
u_int8_t ir_flag;/* 1=index allocation needed (large index) */
u_int8_tir_pad1;/* padding */
u_int16_t ir_pad2;/* padding */
};
struct attr_attrlist {
u_int32_t al_type;/* Attribute type */
u_int16_t reclen;/* length of this entry */
u_int8_t al_namelen;/* Attribute name len */
u_int8_t al_nameoff;/* Name offset from entry start */
u_int64_t al_vcnstart;/* VCN number */
u_int32_t al_inumber;/* Parent ntnode */
u_int32_t reserved;
u_int16_t al_index;/* Attribute index in MFT record */
u_int16_t al_name[1];/* Name */
};
#defineNTFS_INDXMAGIC(u_int32_t)(0x58444E49)
struct attr_indexalloc {
struct fixuphdr ia_fixup;
u_int64_t unknown1;
cn_t ia_bufcn;
u_int16_t ia_hdrsize;
u_int16_t unknown2;
u_int32_t ia_inuse;
u_int32_t ia_allocated;
};
#defineNTFS_IEFLAG_SUBNODE0x00000001
#defineNTFS_IEFLAG_LAST0x00000002
struct attr_indexentry {
u_int32_t ie_number;
u_int32_t unknown1;
u_int16_t reclen;
u_int16_t ie_size;
u_int32_t ie_flag;/* 1 - has subnodes, 2 - last */
u_int32_t ie_fpnumber;
u_int32_t unknown2;
ntfs_times_t ie_ftimes;
u_int64_t ie_fallocated;
u_int64_t ie_fsize;
u_int32_t ie_fflag;
u_int32_tunknown3;/* used by reparse points and external attributes? */
u_int8_t ie_fnamelen;
u_int8_t ie_fnametype;
wchar ie_fname[NTFS_MAXFILENAME];
/* cn_tie_bufcn; buffer with subnodes */
};
#defineNTFS_FILEMAGIC(u_int32_t)(0x454C4946)
#defineNTFS_FRFLAG_DIR0x0002
struct filerec {
struct fixuphdr fr_fixup;
u_int8_t reserved[8];
u_int16_t fr_seqnum;/* Sequence number */
u_int16_t fr_nlink;
u_int16_t fr_attroff;/* offset to attributes */
u_int16_t fr_flags;/* 1-nonresident attr, 2-directory */
u_int32_t fr_size;/* hdr + attributes */
u_int32_t fr_allocated;/* allocated length of record */
u_int64_t fr_mainrec;/* main record */
u_int16_t fr_attrnum;/* maximum attr number + 1 ??? */
};
#defineNTFS_ATTRNAME_MAXLEN0x40
#defineNTFS_ADFLAG_NONRES0x0080/* Attrib can be non resident */
#defineNTFS_ADFLAG_INDEX0x0002/* Attrib can be indexed */
struct attrdef {
wcharad_name[NTFS_ATTRNAME_MAXLEN];
u_int32_tad_type;
u_int32_treserved1[2];
u_int32_tad_flag;
u_int64_tad_minlen;
u_int64_tad_maxlen;/* -1 for nonlimited */
};
struct ntvattrdef {
charad_name[0x40];
intad_namelen;
u_int32_tad_type;
};
#defineNTFS_BBID"NTFS "
#defineNTFS_BBIDLEN8
struct bootfile {
u_int8_t reserved1[3];/* asm jmp near ... */
u_int8_t bf_sysid[8];/* 'NTFS ' */
u_int16_t bf_bps;/* bytes per sector */
u_int8_t bf_spc;/* sectors per cluster */
u_int8_t reserved2[7];/* unused (zeroed) */
u_int8_t bf_media;/* media desc. (0xF8) */
u_int8_t reserved3[2];
u_int16_t bf_spt;/* sectors per track */
u_int16_t bf_heads;/* number of heads */
u_int8_t reserver4[12];
u_int64_t bf_spv;/* sectors per volume */
cn_t bf_mftcn;/* $MFT cluster number */
cn_t bf_mftmirrcn;/* $MFTMirr cn */
u_int8_t bf_mftrecsz;/* MFT record size (clust) */
/* 0xF6 inducates 1/4 */
u_int8_t reserved5[3];
u_int8_t bf_ibsz;/* index buffer size */
u_int8_t reserved6[3];
u_int64_t bf_volsn;/* volume ser. num. */
};
/*
* Darwin's ntfs.util needs to include this file to get definitions
* for the on-disk structures. It doesn't need the ntfsmount structure.
* In fact, since it doesn't #define KERNEL, the struct netexport below
* won't be defined.
*
* So, I'm using #ifdef KERNEL around the things that are only relevant
* to the in-kernel implementation.
*
* invent a different conditional here.
*/
#ifdef KERNEL
#defineNTFS_SYSNODESNUM0x0B
struct ntfsmount {
struct mount *ntm_mountp;/* filesystem vfs structure */
struct bootfile ntm_bootfile;
dev_t ntm_dev;/* device mounted */
struct vnode *ntm_devvp;/* block device mounted vnode */
struct vnode *ntm_sysvn[NTFS_SYSNODESNUM];
u_int32_t ntm_bpmftrec;
uid_t ntm_uid;
gid_t ntm_gid;
mode_t ntm_mode;
u_long ntm_flag;
cn_tntm_cfree;
struct ntvattrdef *ntm_ad;/* attribute names are stored in native byte order */
intntm_adnum;
wchar *ntm_82u;/* 8bit to Unicode */
char **ntm_u28;/* Unicode to 8 bit */
#ifdef APPLE
struct netexport ntm_export;/* NFS export information */
#endif
};
#define ntm_mftcnntm_bootfile.bf_mftcn
#define ntm_mftmirrcnntm_bootfile.bf_mftmirrcn
#definentm_mftrecszntm_bootfile.bf_mftrecsz
#definentm_spcntm_bootfile.bf_spc
#definentm_bpsntm_bootfile.bf_bps
#pragma pack()
#defineNTFS_NEXTREC(s, type) ((type)(((caddr_t) s) + le16toh((s)->reclen)))
/* Convert mount ptr to ntfsmount ptr. */
#define VFSTONTFS(mp)((struct ntfsmount *)((mp)->mnt_data))
#define VTONT(v)FTONT(VTOF(v))
#defineVTOF(v)((struct fnode *)((v)->v_data))
#defineFTOV(f)((f)->f_vp)
#defineFTONT(f)((f)->f_ip)
#define ntfs_cntobn(cn)((daddr_t)(cn) * (ntmp->ntm_spc))
#define ntfs_cntob(cn)((off_t)(cn) * (ntmp)->ntm_spc * (ntmp)->ntm_bps)
#define ntfs_btocn(off)(cn_t)((off) / ((ntmp)->ntm_spc * (ntmp)->ntm_bps))
#define ntfs_btocl(off)(cn_t)((off + ntfs_cntob(1) - 1) / ((ntmp)->ntm_spc * (ntmp)->ntm_bps))
#define ntfs_btocnoff(off)(off_t)((off) % ((ntmp)->ntm_spc * (ntmp)->ntm_bps))
#define ntfs_bntob(bn)(daddr_t)((bn) * (ntmp)->ntm_bps)
#definentfs_bpbl(daddr_t)((ntmp)->ntm_bps)
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_NTFSMNT);
MALLOC_DECLARE(M_NTFSNTNODE);
MALLOC_DECLARE(M_NTFSFNODE);
MALLOC_DECLARE(M_NTFSDIR);
MALLOC_DECLARE(M_NTFSNTHASH);
#endif
#ifndef M_NTFSMNT
#define M_NTFSMNT M_TEMP
#endif
#ifndef M_NTFSNTNODE
#define M_NTFSNTNODE M_TEMP
#endif
#ifndef M_NTFSFNODE
#define M_NTFSFNODE M_TEMP
#endif
#ifndef M_NTFSDIR
#define M_NTFSDIR M_TEMP
#endif
#ifndef M_NTFSNTHASH
#define M_NTFSNTHASH M_TEMP
#endif
#ifndef M_NTFSRUN
#define M_NTFSRUN M_TEMP
#endif
#ifndef M_NTFSRDATA
#define M_NTFSRDATA M_TEMP
#endif
#ifndef M_NTFSNTVATTR
#define M_NTFSNTVATTR M_TEMP
#endif
#ifndef M_NTFSDECOMP
#define M_NTFSDECOMP M_TEMP
#endif
#define VT_NTFS VT_OTHER
#if defined(NTFS_DEBUG)
#define dprintf(a) printf a
#if NTFS_DEBUG > 1
#define ddprintf(a) printf a
#else
#define ddprintf(a)
#endif
#else
#define dprintf(a)
#define ddprintf(a)
#endif
#ifdef APPLE
typedef int vop_t(void *);
#else
#endif
extern vop_t **ntfs_vnodeop_p;
#endif /* KERNEL */
branches/rewrite/i386/libsaio/ntfs.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
/*
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2004 Apple Computer, Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include "libsaio.h"
#include "sl.h"
#define BYTE_ORDER_MARK0xFEFF
#include "ntfs_private.h"
#define FS_TYPE"ntfs"
#define FS_NAME_FILE"NTFS"
#define MAX_BLOCK_SIZE2048
#define MAX_CLUSTER_SIZE32768
#define LABEL_LENGTH1024
#define UNKNOWN_LABEL"Untitled NTFS"
#define FSUR_IO_FAIL -1
#define FSUR_UNRECOGNIZED -1
#define FSUR_RECOGNIZED 0
#define ERROR -1
/*
* Process per-sector "fixups" that NTFS uses to detect corruption of
* multi-sector data structures, like MFT records.
*/
static int
ntfs_fixup(
char *buf,
size_t len,
u_int32_t magic,
u_int32_t bytesPerSector)
{
struct fixuphdr *fhp = (struct fixuphdr *) buf;
int i;
u_int16_t fixup;
u_int16_t *fxp;
u_int16_t *cfxp;
u_int32_tfixup_magic;
u_int16_tfixup_count;
u_int16_tfixup_offset;
fixup_magic = OSReadLittleInt32(&fhp->fh_magic,0);
if (fixup_magic != magic) {
error("ntfs_fixup: magic doesn't match: %08x != %08x\n",
fixup_magic, magic);
return (ERROR);
}
fixup_count = OSReadLittleInt16(&fhp->fh_fnum,0);
if ((fixup_count - 1) * bytesPerSector != len) {
error("ntfs_fixup: " \
"bad fixups number: %d for %ld bytes block\n",
fixup_count, (long)len);/* XXX printf kludge */
return (ERROR);
}
fixup_offset = OSReadLittleInt16(&fhp->fh_foff,0);
if (fixup_offset >= len) {
error("ntfs_fixup: invalid offset: %x", fixup_offset);
return (ERROR);
}
fxp = (u_int16_t *) (buf + fixup_offset);
cfxp = (u_int16_t *) (buf + bytesPerSector - 2);
fixup = *fxp++;
for (i = 1; i < fixup_count; i++, fxp++) {
if (*cfxp != fixup) {
error("ntfs_fixup: fixup %d doesn't match\n", i);
return (ERROR);
}
*cfxp = *fxp;
cfxp = (u_int16_t *)(((caddr_t)cfxp) + bytesPerSector);
}
return (0);
}
/*
* Find a resident attribute of a given type. Returns a pointer to the
* attribute data, and its size in bytes.
*/
static int
ntfs_find_attr(
char *buf,
u_int32_t attrType,
void **attrData,
size_t *attrSize)
{
struct filerec *filerec;
struct attr *attr;
u_int16_t offset;
filerec = (struct filerec *) buf;
offset = OSReadLittleInt16(&filerec->fr_attroff,0);
attr = (struct attr *) (buf + offset);
while (attr->a_hdr.a_type != 0xFFFFFFFF)/* same for big/little endian */
{
if (OSReadLittleInt32(&attr->a_hdr.a_type,0) == attrType)
{
if (attr->a_hdr.a_flag != 0)
{
//verbose("NTFS: attriubte 0x%X is non-resident\n", attrType);
return 1;
}
*attrSize = OSReadLittleInt16(&attr->a_r.a_datalen,0);
*attrData = buf + offset + OSReadLittleInt16(&attr->a_r.a_dataoff,0);
return 0;/* found it! */
}
/* Skip to the next attribute */
offset += OSReadLittleInt32(&attr->a_hdr.reclen,0);
attr = (struct attr *) (buf + offset);
}
return 1;/* No matching attrType found */
}
/*
* Examine a volume to see if we recognize it as a mountable.
*/
void
NTFSGetDescription(CICell ih, char *str, long strMaxLen)
{
struct bootfile *boot;
unsigned bytesPerSector;
unsigned sectorsPerCluster;
int mftRecordSize;
u_int64_t totalClusters;
u_int64_t cluster, mftCluster;
size_t mftOffset;
void *nameAttr;
size_t nameSize;
char *buf;
buf = (char *)malloc(MAX_CLUSTER_SIZE);
if (buf == 0) {
goto error;
}
/*
* Read the boot sector, check signatures, and do some minimal
* sanity checking. NOTE: the size of the read below is intended
* to be a multiple of all supported block sizes, so we don't
* have to determine or change the device's block size.
*/
Seek(ih, 0);
Read(ih, (long)buf, MAX_BLOCK_SIZE);
boot = (struct bootfile *) buf;
/*
* The first three bytes are an Intel x86 jump instruction. I assume it
* can be the same forms as DOS FAT:
* 0xE9 0x?? 0x??
* 0xEC 0x?? 0x90
* where 0x?? means any byte value is OK.
*/
if (boot->reserved1[0] != 0xE9
&& (boot->reserved1[0] != 0xEB || boot->reserved1[2] != 0x90))
{
goto error;
}
/*
* Check the "NTFS " signature.
*/
if (memcmp((const char *)boot->bf_sysid, "NTFS ", 8) != 0)
{
goto error;
}
/*
* Make sure the bytes per sector and sectors per cluster are
* powers of two, and within reasonable ranges.
*/
bytesPerSector = OSReadLittleInt16(&boot->bf_bps,0);
if ((bytesPerSector & (bytesPerSector-1)) || bytesPerSector < 512 || bytesPerSector > 32768)
{
//verbose("NTFS: invalid bytes per sector (%d)\n", bytesPerSector);
goto error;
}
sectorsPerCluster = boot->bf_spc;/* Just one byte; no swapping needed */
if ((sectorsPerCluster & (sectorsPerCluster-1)) || sectorsPerCluster > 128)
{
//verbose("NTFS: invalid sectors per cluster (%d)\n", bytesPerSector);
goto error;
}
/*
* Calculate the number of clusters from the number of sectors.
* Then bounds check the $MFT and $MFTMirr clusters.
*/
totalClusters = OSReadLittleInt64(&boot->bf_spv,0) / sectorsPerCluster;
mftCluster = OSReadLittleInt64(&boot->bf_mftcn,0);
if (mftCluster > totalClusters)
{
////verbose("NTFS: invalid $MFT cluster (%lld)\n", mftCluster);
goto error;
}
cluster = OSReadLittleInt64(&boot->bf_mftmirrcn,0);
if (cluster > totalClusters)
{
//verbose("NTFS: invalid $MFTMirr cluster (%lld)\n", cluster);
goto error;
}
/*
* Determine the size of an MFT record.
*/
mftRecordSize = (int8_t) boot->bf_mftrecsz;
if (mftRecordSize < 0)
mftRecordSize = 1 << -mftRecordSize;
else
mftRecordSize *= bytesPerSector * sectorsPerCluster;
//verbose("NTFS: MFT record size = %d\n", mftRecordSize);
/*
* Read the MFT record for $Volume. This assumes the first four
* file records in the MFT are contiguous; if they aren't, we
* would have to map the $MFT itself.
*
* This will fail if the device sector size is larger than the
* MFT record size, since the $Volume record won't be aligned
* on a sector boundary.
*/
mftOffset = mftCluster * sectorsPerCluster * bytesPerSector;
mftOffset += mftRecordSize * NTFS_VOLUMEINO;
Seek(ih, mftOffset);
Read(ih, (long)buf, mftRecordSize);
#if UNUSED
if (lseek(fd, mftOffset, SEEK_SET) == -1)
{
//verbose("NTFS: lseek to $Volume failed: %s\n", strerror(errno));
goto error;
}
if (read(fd, buf, mftRecordSize) != mftRecordSize)
{
//verbose("NTFS: error reading MFT $Volume record: %s\n",
strerror(errno));
goto error;
}
#endif
if (ntfs_fixup(buf, mftRecordSize, NTFS_FILEMAGIC, bytesPerSector) != 0)
{
//verbose("NTFS: block fixup failed\n");
goto error;
}
/*
* Loop over the attributes, looking for $VOLUME_NAME (0x60).
*/
if(ntfs_find_attr(buf, NTFS_A_VOLUMENAME, &nameAttr, &nameSize) != 0)
{
//verbose("NTFS: $VOLUME_NAME attribute not found\n");
goto error;
}
str[0] = '\0';
utf_encodestr( nameAttr, nameSize / 2, (u_int8_t *)str, strMaxLen, OSLittleEndian );
free(buf);
return;
error:
if (buf) free(buf);
return;
}
long NTFSGetUUID(CICell ih, char *uuidStr)
{
bool NTFSProbe(const void*);
struct bootfile *boot;
void *buf = malloc(MAX_BLOCK_SIZE);
if ( !buf )
return -1;
/*
* Read the boot sector, check signatures, and do some minimal
* sanity checking. NOTE: the size of the read below is intended
* to be a multiple of all supported block sizes, so we don't
* have to determine or change the device's block size.
*/
Seek(ih, 0);
Read(ih, (long)buf, MAX_BLOCK_SIZE);
boot = (struct bootfile *) buf;
// Check for NTFS signature
if ( memcmp((void*)boot->bf_sysid, NTFS_BBID, NTFS_BBIDLEN) != 0 )
return -1;
// Check for non-null volume serial number
if( !boot->bf_volsn )
return -1;
// Use UUID like the one you get on Windows
sprintf(uuidStr, "%04X-%04X",(unsigned short)(boot->bf_volsn >> 16) & 0xFFFF,
(unsigned short)boot->bf_volsn & 0xFFFF);
return 0;
}
bool NTFSProbe(const void * buffer)
{
bool result = false;
const struct bootfile* part_bootfile = buffer;// NTFS boot sector structure
// Looking for NTFS signature.
if (strncmp((const char *)part_bootfile->bf_sysid, NTFS_BBID, NTFS_BBIDLEN) == 0)
result = true;
return result;
}
branches/rewrite/i386/libsaio/hfs_CaseTables.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
/*
* Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 2.0 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
File:CaseTables.h
*/
/*The lower case table consists of a 256-entry high-byte table followed by some number of
256-entry subtables. The high-byte table contains either an offset to the subtable for
characters with that high byte or zero, which means that there are no case mappings or
ignored characters in that block. Ignored characters are mapped to zero.
*/
#if UNCOMPRESSED
u_int16_t gLowerCaseTable[] = {
// High-byte indices ( == 0 iff no case mapping and no ignorables )
/* 0 */0x0100, 0x0200, 0x0000, 0x0300, 0x0400, 0x0500, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 1 */0x0600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 2 */0x0700, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 3 */0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 4 */0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 5 */0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 6 */0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 7 */0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 8 */0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 9 */0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* A */0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* B */0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* C */0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* D */0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* E */0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* F */0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0900, 0x0A00,
// Table 1 (for high byte 0x00)
/* 0 */0xFFFF, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
/* 1 */0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
/* 2 */0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
/* 3 */0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
/* 4 */0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
/* 5 */0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
/* 6 */0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
/* 7 */0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
/* 8 */0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
/* 9 */0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
/* A */0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
/* B */0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
/* C */0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00E6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
/* D */0x00F0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00F8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00FE, 0x00DF,
/* E */0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
/* F */0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
// Table 2 (for high byte 0x01)
/* 0 */0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F,
/* 1 */0x0111, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117, 0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, 0x011F,
/* 2 */0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0127, 0x0127, 0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F,
/* 3 */0x0130, 0x0131, 0x0133, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137, 0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x0140,
/* 4 */0x0140, 0x0142, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147, 0x0148, 0x0149, 0x014B, 0x014B, 0x014C, 0x014D, 0x014E, 0x014F,
/* 5 */0x0150, 0x0151, 0x0153, 0x0153, 0x0154, 0x0155, 0x0156, 0x0157, 0x0158, 0x0159, 0x015A, 0x015B, 0x015C, 0x015D, 0x015E, 0x015F,
/* 6 */0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165, 0x0167, 0x0167, 0x0168, 0x0169, 0x016A, 0x016B, 0x016C, 0x016D, 0x016E, 0x016F,
/* 7 */0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177, 0x0178, 0x0179, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x017F,
/* 8 */0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188, 0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259,
/* 9 */0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268, 0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275,
/* A */0x01A0, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x01A6, 0x01A8, 0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01AF,
/* B */0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292, 0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF,
/* C */0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9, 0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC, 0x01CD, 0x01CE, 0x01CF,
/* D */0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6, 0x01D7, 0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, 0x01DD, 0x01DE, 0x01DF,
/* E */0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E5, 0x01E5, 0x01E6, 0x01E7, 0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x01EC, 0x01ED, 0x01EE, 0x01EF,
/* F */0x01F0, 0x01F3, 0x01F3, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7, 0x01F8, 0x01F9, 0x01FA, 0x01FB, 0x01FC, 0x01FD, 0x01FE, 0x01FF,
// Table 3 (for high byte 0x03)
/* 0 */0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F,
/* 1 */0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, 0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F,
/* 2 */0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, 0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F,
/* 3 */0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, 0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F,
/* 4 */0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347, 0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F,
/* 5 */0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, 0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F,
/* 6 */0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F,
/* 7 */0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, 0x0378, 0x0379, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x037F,
/* 8 */0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387, 0x0388, 0x0389, 0x038A, 0x038B, 0x038C, 0x038D, 0x038E, 0x038F,
/* 9 */0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
/* A */0x03C0, 0x03C1, 0x03A2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
/* B */0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
/* C */0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x03CF,
/* D */0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7, 0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF,
/* E */0x03E0, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7, 0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF,
/* F */0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7, 0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF,
// Table 4 (for high byte 0x04)
/* 0 */0x0400, 0x0401, 0x0452, 0x0403, 0x0454, 0x0455, 0x0456, 0x0407, 0x0458, 0x0459, 0x045A, 0x045B, 0x040C, 0x040D, 0x040E, 0x045F,
/* 1 */0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0419, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
/* 2 */0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
/* 3 */0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
/* 4 */0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
/* 5 */0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045D, 0x045E, 0x045F,
/* 6 */0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467, 0x0469, 0x0469, 0x046B, 0x046B, 0x046D, 0x046D, 0x046F, 0x046F,
/* 7 */0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0476, 0x0477, 0x0479, 0x0479, 0x047B, 0x047B, 0x047D, 0x047D, 0x047F, 0x047F,
/* 8 */0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F,
/* 9 */0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497, 0x0499, 0x0499, 0x049B, 0x049B, 0x049D, 0x049D, 0x049F, 0x049F,
/* A */0x04A1, 0x04A1, 0x04A3, 0x04A3, 0x04A5, 0x04A5, 0x04A7, 0x04A7, 0x04A9, 0x04A9, 0x04AB, 0x04AB, 0x04AD, 0x04AD, 0x04AF, 0x04AF,
/* B */0x04B1, 0x04B1, 0x04B3, 0x04B3, 0x04B5, 0x04B5, 0x04B7, 0x04B7, 0x04B9, 0x04B9, 0x04BB, 0x04BB, 0x04BD, 0x04BD, 0x04BF, 0x04BF,
/* C */0x04C0, 0x04C1, 0x04C2, 0x04C4, 0x04C4, 0x04C5, 0x04C6, 0x04C8, 0x04C8, 0x04C9, 0x04CA, 0x04CC, 0x04CC, 0x04CD, 0x04CE, 0x04CF,
/* D */0x04D0, 0x04D1, 0x04D2, 0x04D3, 0x04D4, 0x04D5, 0x04D6, 0x04D7, 0x04D8, 0x04D9, 0x04DA, 0x04DB, 0x04DC, 0x04DD, 0x04DE, 0x04DF,
/* E */0x04E0, 0x04E1, 0x04E2, 0x04E3, 0x04E4, 0x04E5, 0x04E6, 0x04E7, 0x04E8, 0x04E9, 0x04EA, 0x04EB, 0x04EC, 0x04ED, 0x04EE, 0x04EF,
/* F */0x04F0, 0x04F1, 0x04F2, 0x04F3, 0x04F4, 0x04F5, 0x04F6, 0x04F7, 0x04F8, 0x04F9, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF,
// Table 5 (for high byte 0x05)
/* 0 */0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509, 0x050A, 0x050B, 0x050C, 0x050D, 0x050E, 0x050F,
/* 1 */0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517, 0x0518, 0x0519, 0x051A, 0x051B, 0x051C, 0x051D, 0x051E, 0x051F,
/* 2 */0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, 0x0528, 0x0529, 0x052A, 0x052B, 0x052C, 0x052D, 0x052E, 0x052F,
/* 3 */0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, 0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
/* 4 */0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, 0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
/* 5 */0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557, 0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F,
/* 6 */0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, 0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
/* 7 */0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, 0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
/* 8 */0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587, 0x0588, 0x0589, 0x058A, 0x058B, 0x058C, 0x058D, 0x058E, 0x058F,
/* 9 */0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597, 0x0598, 0x0599, 0x059A, 0x059B, 0x059C, 0x059D, 0x059E, 0x059F,
/* A */0x05A0, 0x05A1, 0x05A2, 0x05A3, 0x05A4, 0x05A5, 0x05A6, 0x05A7, 0x05A8, 0x05A9, 0x05AA, 0x05AB, 0x05AC, 0x05AD, 0x05AE, 0x05AF,
/* B */0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, 0x05B8, 0x05B9, 0x05BA, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
/* C */0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05C4, 0x05C5, 0x05C6, 0x05C7, 0x05C8, 0x05C9, 0x05CA, 0x05CB, 0x05CC, 0x05CD, 0x05CE, 0x05CF,
/* D */0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
/* E */0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC, 0x05ED, 0x05EE, 0x05EF,
/* F */0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x05F5, 0x05F6, 0x05F7, 0x05F8, 0x05F9, 0x05FA, 0x05FB, 0x05FC, 0x05FD, 0x05FE, 0x05FF,
// Table 6 (for high byte 0x10)
/* 0 */0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1008, 0x1009, 0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F,
/* 1 */0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017, 0x1018, 0x1019, 0x101A, 0x101B, 0x101C, 0x101D, 0x101E, 0x101F,
/* 2 */0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027, 0x1028, 0x1029, 0x102A, 0x102B, 0x102C, 0x102D, 0x102E, 0x102F,
/* 3 */0x1030, 0x1031, 0x1032, 0x1033, 0x1034, 0x1035, 0x1036, 0x1037, 0x1038, 0x1039, 0x103A, 0x103B, 0x103C, 0x103D, 0x103E, 0x103F,
/* 4 */0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047, 0x1048, 0x1049, 0x104A, 0x104B, 0x104C, 0x104D, 0x104E, 0x104F,
/* 5 */0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057, 0x1058, 0x1059, 0x105A, 0x105B, 0x105C, 0x105D, 0x105E, 0x105F,
/* 6 */0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067, 0x1068, 0x1069, 0x106A, 0x106B, 0x106C, 0x106D, 0x106E, 0x106F,
/* 7 */0x1070, 0x1071, 0x1072, 0x1073, 0x1074, 0x1075, 0x1076, 0x1077, 0x1078, 0x1079, 0x107A, 0x107B, 0x107C, 0x107D, 0x107E, 0x107F,
/* 8 */0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087, 0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x108F,
/* 9 */0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097, 0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x109F,
/* A */0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
/* B */0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
/* C */0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10C6, 0x10C7, 0x10C8, 0x10C9, 0x10CA, 0x10CB, 0x10CC, 0x10CD, 0x10CE, 0x10CF,
/* D */0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
/* E */0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
/* F */0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10F6, 0x10F7, 0x10F8, 0x10F9, 0x10FA, 0x10FB, 0x10FC, 0x10FD, 0x10FE, 0x10FF,
// Table 7 (for high byte 0x20)
/* 0 */0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x200B, 0x0000, 0x0000, 0x0000, 0x0000,
/* 1 */0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017, 0x2018, 0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F,
/* 2 */0x2020, 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027, 0x2028, 0x2029, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x202F,
/* 3 */0x2030, 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037, 0x2038, 0x2039, 0x203A, 0x203B, 0x203C, 0x203D, 0x203E, 0x203F,
/* 4 */0x2040, 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047, 0x2048, 0x2049, 0x204A, 0x204B, 0x204C, 0x204D, 0x204E, 0x204F,
/* 5 */0x2050, 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057, 0x2058, 0x2059, 0x205A, 0x205B, 0x205C, 0x205D, 0x205E, 0x205F,
/* 6 */0x2060, 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067, 0x2068, 0x2069, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
/* 7 */0x2070, 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F,
/* 8 */0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087, 0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x208F,
/* 9 */0x2090, 0x2091, 0x2092, 0x2093, 0x2094, 0x2095, 0x2096, 0x2097, 0x2098, 0x2099, 0x209A, 0x209B, 0x209C, 0x209D, 0x209E, 0x209F,
/* A */0x20A0, 0x20A1, 0x20A2, 0x20A3, 0x20A4, 0x20A5, 0x20A6, 0x20A7, 0x20A8, 0x20A9, 0x20AA, 0x20AB, 0x20AC, 0x20AD, 0x20AE, 0x20AF,
/* B */0x20B0, 0x20B1, 0x20B2, 0x20B3, 0x20B4, 0x20B5, 0x20B6, 0x20B7, 0x20B8, 0x20B9, 0x20BA, 0x20BB, 0x20BC, 0x20BD, 0x20BE, 0x20BF,
/* C */0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7, 0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x20CF,
/* D */0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7, 0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x20DF,
/* E */0x20E0, 0x20E1, 0x20E2, 0x20E3, 0x20E4, 0x20E5, 0x20E6, 0x20E7, 0x20E8, 0x20E9, 0x20EA, 0x20EB, 0x20EC, 0x20ED, 0x20EE, 0x20EF,
/* F */0x20F0, 0x20F1, 0x20F2, 0x20F3, 0x20F4, 0x20F5, 0x20F6, 0x20F7, 0x20F8, 0x20F9, 0x20FA, 0x20FB, 0x20FC, 0x20FD, 0x20FE, 0x20FF,
// Table 8 (for high byte 0x21)
/* 0 */0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107, 0x2108, 0x2109, 0x210A, 0x210B, 0x210C, 0x210D, 0x210E, 0x210F,
/* 1 */0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117, 0x2118, 0x2119, 0x211A, 0x211B, 0x211C, 0x211D, 0x211E, 0x211F,
/* 2 */0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127, 0x2128, 0x2129, 0x212A, 0x212B, 0x212C, 0x212D, 0x212E, 0x212F,
/* 3 */0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137, 0x2138, 0x2139, 0x213A, 0x213B, 0x213C, 0x213D, 0x213E, 0x213F,
/* 4 */0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147, 0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F,
/* 5 */0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F,
/* 6 */0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
/* 7 */0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
/* 8 */0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187, 0x2188, 0x2189, 0x218A, 0x218B, 0x218C, 0x218D, 0x218E, 0x218F,
/* 9 */0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197, 0x2198, 0x2199, 0x219A, 0x219B, 0x219C, 0x219D, 0x219E, 0x219F,
/* A */0x21A0, 0x21A1, 0x21A2, 0x21A3, 0x21A4, 0x21A5, 0x21A6, 0x21A7, 0x21A8, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21AE, 0x21AF,
/* B */0x21B0, 0x21B1, 0x21B2, 0x21B3, 0x21B4, 0x21B5, 0x21B6, 0x21B7, 0x21B8, 0x21B9, 0x21BA, 0x21BB, 0x21BC, 0x21BD, 0x21BE, 0x21BF,
/* C */0x21C0, 0x21C1, 0x21C2, 0x21C3, 0x21C4, 0x21C5, 0x21C6, 0x21C7, 0x21C8, 0x21C9, 0x21CA, 0x21CB, 0x21CC, 0x21CD, 0x21CE, 0x21CF,
/* D */0x21D0, 0x21D1, 0x21D2, 0x21D3, 0x21D4, 0x21D5, 0x21D6, 0x21D7, 0x21D8, 0x21D9, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21DE, 0x21DF,
/* E */0x21E0, 0x21E1, 0x21E2, 0x21E3, 0x21E4, 0x21E5, 0x21E6, 0x21E7, 0x21E8, 0x21E9, 0x21EA, 0x21EB, 0x21EC, 0x21ED, 0x21EE, 0x21EF,
/* F */0x21F0, 0x21F1, 0x21F2, 0x21F3, 0x21F4, 0x21F5, 0x21F6, 0x21F7, 0x21F8, 0x21F9, 0x21FA, 0x21FB, 0x21FC, 0x21FD, 0x21FE, 0x21FF,
// Table 9 (for high byte 0xFE)
/* 0 */0xFE00, 0xFE01, 0xFE02, 0xFE03, 0xFE04, 0xFE05, 0xFE06, 0xFE07, 0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F,
/* 1 */0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, 0xFE16, 0xFE17, 0xFE18, 0xFE19, 0xFE1A, 0xFE1B, 0xFE1C, 0xFE1D, 0xFE1E, 0xFE1F,
/* 2 */0xFE20, 0xFE21, 0xFE22, 0xFE23, 0xFE24, 0xFE25, 0xFE26, 0xFE27, 0xFE28, 0xFE29, 0xFE2A, 0xFE2B, 0xFE2C, 0xFE2D, 0xFE2E, 0xFE2F,
/* 3 */0xFE30, 0xFE31, 0xFE32, 0xFE33, 0xFE34, 0xFE35, 0xFE36, 0xFE37, 0xFE38, 0xFE39, 0xFE3A, 0xFE3B, 0xFE3C, 0xFE3D, 0xFE3E, 0xFE3F,
/* 4 */0xFE40, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE45, 0xFE46, 0xFE47, 0xFE48, 0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F,
/* 5 */0xFE50, 0xFE51, 0xFE52, 0xFE53, 0xFE54, 0xFE55, 0xFE56, 0xFE57, 0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, 0xFE5E, 0xFE5F,
/* 6 */0xFE60, 0xFE61, 0xFE62, 0xFE63, 0xFE64, 0xFE65, 0xFE66, 0xFE67, 0xFE68, 0xFE69, 0xFE6A, 0xFE6B, 0xFE6C, 0xFE6D, 0xFE6E, 0xFE6F,
/* 7 */0xFE70, 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE75, 0xFE76, 0xFE77, 0xFE78, 0xFE79, 0xFE7A, 0xFE7B, 0xFE7C, 0xFE7D, 0xFE7E, 0xFE7F,
/* 8 */0xFE80, 0xFE81, 0xFE82, 0xFE83, 0xFE84, 0xFE85, 0xFE86, 0xFE87, 0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 0xFE8D, 0xFE8E, 0xFE8F,
/* 9 */0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, 0xFE96, 0xFE97, 0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, 0xFE9E, 0xFE9F,
/* A */0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, 0xFEAE, 0xFEAF,
/* B */0xFEB0, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, 0xFEBE, 0xFEBF,
/* C */0xFEC0, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, 0xFECD, 0xFECE, 0xFECF,
/* D */0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 0xFED5, 0xFED6, 0xFED7, 0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, 0xFEDE, 0xFEDF,
/* E */0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, 0xFEEE, 0xFEEF,
/* F */0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, 0xFEF6, 0xFEF7, 0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0xFEFD, 0xFEFE, 0x0000,
// Table 10 (for high byte 0xFF)
/* 0 */0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07, 0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F,
/* 1 */0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17, 0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F,
/* 2 */0xFF20, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
/* 3 */0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F,
/* 4 */0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
/* 5 */0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E, 0xFF5F,
/* 6 */0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67, 0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F,
/* 7 */0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77, 0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F,
/* 8 */0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87, 0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F,
/* 9 */0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97, 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F,
/* A */0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0xFFA6, 0xFFA7, 0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0xFFAE, 0xFFAF,
/* B */0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, 0xFFB6, 0xFFB7, 0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, 0xFFBE, 0xFFBF,
/* C */0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC6, 0xFFC7, 0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF,
/* D */0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, 0xFFD6, 0xFFD7, 0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, 0xFFDE, 0xFFDF,
/* E */0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, 0xFFE6, 0xFFE7, 0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, 0xFFEE, 0xFFEF,
/* F */0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7, 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF,
};
/* RelString case folding table */
unsigned short gCompareTable[] = {
/* 0 */0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00, 0x0F00,
/* 1 */0x1000, 0x1100, 0x1200, 0x1300, 0x1400, 0x1500, 0x1600, 0x1700, 0x1800, 0x1900, 0x1A00, 0x1B00, 0x1C00, 0x1D00, 0x1E00, 0x1F00,
/* 2 */0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x2600, 0x2700, 0x2800, 0x2900, 0x2A00, 0x2B00, 0x2C00, 0x2D00, 0x2E00, 0x2F00,
/* 3 */0x3000, 0x3100, 0x3200, 0x3300, 0x3400, 0x3500, 0x3600, 0x3700, 0x3800, 0x3900, 0x3A00, 0x3B00, 0x3C00, 0x3D00, 0x3E00, 0x3F00,
/* 4 */0x4000, 0x4100, 0x4200, 0x4300, 0x4400, 0x4500, 0x4600, 0x4700, 0x4800, 0x4900, 0x4A00, 0x4B00, 0x4C00, 0x4D00, 0x4E00, 0x4F00,
/* 5 */0x5000, 0x5100, 0x5200, 0x5300, 0x5400, 0x5500, 0x5600, 0x5700, 0x5800, 0x5900, 0x5A00, 0x5B00, 0x5C00, 0x5D00, 0x5E00, 0x5F00,
// 0x60 maps to 'a'
// range 0x61 to 0x7a ('a' to 'z') map to upper case
/* 6 */0x4180, 0x4100, 0x4200, 0x4300, 0x4400, 0x4500, 0x4600, 0x4700, 0x4800, 0x4900, 0x4A00, 0x4B00, 0x4C00, 0x4D00, 0x4E00, 0x4F00,
/* 7 */0x5000, 0x5100, 0x5200, 0x5300, 0x5400, 0x5500, 0x5600, 0x5700, 0x5800, 0x5900, 0x5A00, 0x7B00, 0x7C00, 0x7D00, 0x7E00, 0x7F00,
// range 0x80 to 0xd8 gets mapped...
/* 8 */0x4108, 0x410C, 0x4310, 0x4502, 0x4E0A, 0x4F08, 0x5508, 0x4182, 0x4104, 0x4186, 0x4108, 0x410A, 0x410C, 0x4310, 0x4502, 0x4584,
/* 9 */0x4586, 0x4588, 0x4982, 0x4984, 0x4986, 0x4988, 0x4E0A, 0x4F82, 0x4F84, 0x4F86, 0x4F08, 0x4F0A, 0x5582, 0x5584, 0x5586, 0x5508,
/* A */0xA000, 0xA100, 0xA200, 0xA300, 0xA400, 0xA500, 0xA600, 0x5382, 0xA800, 0xA900, 0xAA00, 0xAB00, 0xAC00, 0xAD00, 0x4114, 0x4F0E,
/* B */0xB000, 0xB100, 0xB200, 0xB300, 0xB400, 0xB500, 0xB600, 0xB700, 0xB800, 0xB900, 0xBA00, 0x4192, 0x4F92, 0xBD00, 0x4114, 0x4F0E,
/* C */0xC000, 0xC100, 0xC200, 0xC300, 0xC400, 0xC500, 0xC600, 0x2206, 0x2208, 0xC900, 0x2000, 0x4104, 0x410A, 0x4F0A, 0x4F14, 0x4F14,
/* D */0xD000, 0xD100, 0x2202, 0x2204, 0x2702, 0x2704, 0xD600, 0xD700, 0x5988, 0xD900, 0xDA00, 0xDB00, 0xDC00, 0xDD00, 0xDE00, 0xDF00,
/* E */0xE000, 0xE100, 0xE200, 0xE300, 0xE400, 0xE500, 0xE600, 0xE700, 0xE800, 0xE900, 0xEA00, 0xEB00, 0xEC00, 0xED00, 0xEE00, 0xEF00,
/* F */0xF000, 0xF100, 0xF200, 0xF300, 0xF400, 0xF500, 0xF600, 0xF700, 0xF800, 0xF900, 0xFA00, 0xFB00, 0xFC00, 0xFD00, 0xFE00, 0xFF00,
};
#else /* ! UNCOMPRESSED */
enum {
kTypeLiteral = 0,
kTypeAscending = 1,
kTypeAscending256 = 2
};
struct compressed_block {
unsigned char type;
unsigned char count;
unsigned short data;
};
unsigned short *gLowerCaseTable;
struct compressed_block gLowerCaseTableCompressed[] = {
{0x0, 0x1, 0x100},
{0x0, 0x1, 0x200},
{0x0, 0x1, 0x0},
{0x0, 0x1, 0x300},
{0x0, 0x1, 0x400},
{0x0, 0x1, 0x500},
{0x0, 0xa, 0x0},
{0x0, 0x1, 0x600},
{0x0, 0xf, 0x0},
{0x0, 0x1, 0x700},
{0x0, 0x1, 0x800},
{0x0, 0xdc, 0x0},
{0x0, 0x1, 0x900},
{0x0, 0x1, 0xa00},
{0x0, 0x1, 0xffff},
{0x1, 0x40, 0x1},
{0x1, 0x1a, 0x61},
{0x1, 0x6b, 0x5b},
{0x0, 0x1, 0xe6},
{0x1, 0x9, 0xc7},
{0x0, 0x1, 0xf0},
{0x1, 0x7, 0xd1},
{0x0, 0x1, 0xf8},
{0x1, 0x5, 0xd9},
{0x0, 0x1, 0xfe},
{0x1, 0x31, 0xdf},
{0x0, 0x2, 0x111},
{0x1, 0x14, 0x112},
{0x0, 0x2, 0x127},
{0x1, 0xa, 0x128},
{0x0, 0x2, 0x133},
{0x1, 0xb, 0x134},
{0x0, 0x2, 0x140},
{0x0, 0x2, 0x142},
{0x1, 0x7, 0x143},
{0x0, 0x2, 0x14b},
{0x1, 0x6, 0x14c},
{0x0, 0x2, 0x153},
{0x1, 0x12, 0x154},
{0x0, 0x2, 0x167},
{0x1, 0x19, 0x168},
{0x0, 0x1, 0x253},
{0x0, 0x2, 0x183},
{0x0, 0x2, 0x185},
{0x0, 0x1, 0x254},
{0x0, 0x2, 0x188},
{0x1, 0x2, 0x256},
{0x0, 0x2, 0x18c},
{0x0, 0x1, 0x18d},
{0x0, 0x1, 0x1dd},
{0x0, 0x1, 0x259},
{0x0, 0x1, 0x25b},
{0x0, 0x2, 0x192},
{0x0, 0x1, 0x260},
{0x0, 0x1, 0x263},
{0x0, 0x1, 0x195},
{0x0, 0x1, 0x269},
{0x0, 0x1, 0x268},
{0x0, 0x2, 0x199},
{0x1, 0x2, 0x19a},
{0x0, 0x1, 0x26f},
{0x0, 0x1, 0x272},
{0x0, 0x1, 0x19e},
{0x0, 0x1, 0x275},
{0x1, 0x2, 0x1a0},
{0x0, 0x2, 0x1a3},
{0x0, 0x2, 0x1a5},
{0x0, 0x1, 0x1a6},
{0x0, 0x2, 0x1a8},
{0x0, 0x1, 0x283},
{0x1, 0x2, 0x1aa},
{0x0, 0x2, 0x1ad},
{0x0, 0x1, 0x288},
{0x1, 0x2, 0x1af},
{0x1, 0x2, 0x28a},
{0x0, 0x2, 0x1b4},
{0x0, 0x2, 0x1b6},
{0x0, 0x1, 0x292},
{0x0, 0x2, 0x1b9},
{0x1, 0x2, 0x1ba},
{0x0, 0x2, 0x1bd},
{0x1, 0x6, 0x1be},
{0x0, 0x3, 0x1c6},
{0x0, 0x3, 0x1c9},
{0x0, 0x3, 0x1cc},
{0x1, 0x17, 0x1cd},
{0x0, 0x2, 0x1e5},
{0x1, 0xb, 0x1e6},
{0x0, 0x3, 0x1f3},
{0x1, 0xc, 0x1f4},
{0x1, 0x91, 0x300},
{0x1, 0x11, 0x3b1},
{0x0, 0x1, 0x3a2},
{0x1, 0x7, 0x3c3},
{0x1, 0x38, 0x3aa},
{0x0, 0x2, 0x3e3},
{0x0, 0x2, 0x3e5},
{0x0, 0x2, 0x3e7},
{0x0, 0x2, 0x3e9},
{0x0, 0x2, 0x3eb},
{0x0, 0x2, 0x3ed},
{0x0, 0x2, 0x3ef},
{0x1, 0x12, 0x3f0},
{0x0, 0x1, 0x452},
{0x0, 0x1, 0x403},
{0x1, 0x3, 0x454},
{0x0, 0x1, 0x407},
{0x1, 0x4, 0x458},
{0x1, 0x3, 0x40c},
{0x0, 0x1, 0x45f},
{0x1, 0x9, 0x430},
{0x0, 0x1, 0x419},
{0x1, 0x16, 0x43a},
{0x1, 0x30, 0x430},
{0x0, 0x2, 0x461},
{0x0, 0x2, 0x463},
{0x0, 0x2, 0x465},
{0x0, 0x2, 0x467},
{0x0, 0x2, 0x469},
{0x0, 0x2, 0x46b},
{0x0, 0x2, 0x46d},
{0x0, 0x2, 0x46f},
{0x0, 0x2, 0x471},
{0x0, 0x2, 0x473},
{0x0, 0x2, 0x475},
{0x1, 0x2, 0x476},
{0x0, 0x2, 0x479},
{0x0, 0x2, 0x47b},
{0x0, 0x2, 0x47d},
{0x0, 0x2, 0x47f},
{0x0, 0x2, 0x481},
{0x1, 0xe, 0x482},
{0x0, 0x2, 0x491},
{0x0, 0x2, 0x493},
{0x0, 0x2, 0x495},
{0x0, 0x2, 0x497},
{0x0, 0x2, 0x499},
{0x0, 0x2, 0x49b},
{0x0, 0x2, 0x49d},
{0x0, 0x2, 0x49f},
{0x0, 0x2, 0x4a1},
{0x0, 0x2, 0x4a3},
{0x0, 0x2, 0x4a5},
{0x0, 0x2, 0x4a7},
{0x0, 0x2, 0x4a9},
{0x0, 0x2, 0x4ab},
{0x0, 0x2, 0x4ad},
{0x0, 0x2, 0x4af},
{0x0, 0x2, 0x4b1},
{0x0, 0x2, 0x4b3},
{0x0, 0x2, 0x4b5},
{0x0, 0x2, 0x4b7},
{0x0, 0x2, 0x4b9},
{0x0, 0x2, 0x4bb},
{0x0, 0x2, 0x4bd},
{0x0, 0x2, 0x4bf},
{0x1, 0x3, 0x4c0},
{0x0, 0x2, 0x4c4},
{0x1, 0x2, 0x4c5},
{0x0, 0x2, 0x4c8},
{0x1, 0x2, 0x4c9},
{0x0, 0x2, 0x4cc},
{0x1, 0x64, 0x4cd},
{0x1, 0x26, 0x561},
{0x1, 0xa9, 0x557},
{0x1, 0xa0, 0x1000},
{0x1, 0x26, 0x10d0},
{0x1, 0x3a, 0x10c6},
{0x1, 0xc, 0x2000},
{0x0, 0x4, 0x0},
{0x1, 0x1a, 0x2010},
{0x0, 0x5, 0x0},
{0x1, 0x3b, 0x202f},
{0x0, 0x6, 0x0},
{0x1, 0xf0, 0x2070},
{0x1, 0x10, 0x2170},
{0x1, 0x90, 0x2170},
{0x1, 0xff, 0xfe00},
{0x0, 0x1, 0x0},
{0x1, 0x21, 0xff00},
{0x1, 0x1a, 0xff41},
{0x1, 0xc5, 0xff3b},
};
// Please update count if you add/remove entries but also please just let
// the compiler calculate it so you don't get it wrong.
//#define kLowerCaseTableNBlocks 182
#define kLowerCaseTableNBlocks (sizeof(gLowerCaseTableCompressed)/sizeof(*gLowerCaseTableCompressed))
// WARNING: The expanded size MUST be updated if you change the table and
// cannot be calculated at compile time.
#define kLowerCaseTableDataSize 5632 /* size of uncompressed structure in bytes */
unsigned short *gCompareTable;
struct compressed_block gCompareTableCompressed[] = {
{0x2, 0x60, 0x0},
{0x0, 0x1, 0x4180},
{0x2, 0x1a, 0x4100},
{0x2, 0x5, 0x7b00},
{0x0, 0x1, 0x4108},
{0x0, 0x1, 0x410c},
{0x0, 0x1, 0x4310},
{0x0, 0x1, 0x4502},
{0x0, 0x1, 0x4e0a},
{0x0, 0x1, 0x4f08},
{0x0, 0x1, 0x5508},
{0x0, 0x1, 0x4182},
{0x0, 0x1, 0x4104},
{0x0, 0x1, 0x4186},
{0x0, 0x1, 0x4108},
{0x0, 0x1, 0x410a},
{0x0, 0x1, 0x410c},
{0x0, 0x1, 0x4310},
{0x0, 0x1, 0x4502},
{0x0, 0x1, 0x4584},
{0x0, 0x1, 0x4586},
{0x0, 0x1, 0x4588},
{0x0, 0x1, 0x4982},
{0x0, 0x1, 0x4984},
{0x0, 0x1, 0x4986},
{0x0, 0x1, 0x4988},
{0x0, 0x1, 0x4e0a},
{0x0, 0x1, 0x4f82},
{0x0, 0x1, 0x4f84},
{0x0, 0x1, 0x4f86},
{0x0, 0x1, 0x4f08},
{0x0, 0x1, 0x4f0a},
{0x0, 0x1, 0x5582},
{0x0, 0x1, 0x5584},
{0x0, 0x1, 0x5586},
{0x0, 0x1, 0x5508},
{0x2, 0x7, 0xa000},
{0x0, 0x1, 0x5382},
{0x2, 0x6, 0xa800},
{0x0, 0x1, 0x4114},
{0x0, 0x1, 0x4f0e},
{0x2, 0xb, 0xb000},
{0x0, 0x1, 0x4192},
{0x0, 0x1, 0x4f92},
{0x0, 0x1, 0xbd00},
{0x0, 0x1, 0x4114},
{0x0, 0x1, 0x4f0e},
{0x2, 0x7, 0xc000},
{0x0, 0x1, 0x2206},
{0x0, 0x1, 0x2208},
{0x0, 0x1, 0xc900},
{0x0, 0x1, 0x2000},
{0x0, 0x1, 0x4104},
{0x0, 0x1, 0x410a},
{0x0, 0x1, 0x4f0a},
{0x0, 0x2, 0x4f14},
{0x2, 0x2, 0xd000},
{0x0, 0x1, 0x2202},
{0x0, 0x1, 0x2204},
{0x0, 0x1, 0x2702},
{0x0, 0x1, 0x2704},
{0x2, 0x2, 0xd600},
{0x0, 0x1, 0x5988},
{0x2, 0x27, 0xd900},
};
// Please update count if you add/remove entries but also please just let
// the compiler calculate it so you don't get it wrong.
//#define kCompareTableNBlocks 64
#define kCompareTableNBlocks (sizeof(gCompareTableCompressed)/sizeof(*gCompareTableCompressed))
// WARNING: The expanded size MUST be updated if you change the table and
// cannot be calculated at compile time.
#define kCompareTableDataSize 512 /* size of uncompressed structure in bytes */
#endif /* UNCOMPRESSED */
branches/rewrite/i386/libsaio/ext2fs.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/*
* ext2fs.c
*
*
* Created by mackerintel on 1/26/09.
* Copyright 2009 __MyCompanyName__. All rights reserved.
*
*/
#include "libsaio.h"
#include "sl.h"
#include "ext2fs.h"
#define EX2ProbeSize2048
bool EX2Probe (const void *buf)
{
return (OSReadLittleInt16(buf+0x438,0)==0xEF53);
}
void EX2GetDescription(CICell ih, char *str, long strMaxLen)
{
char * buf=malloc (EX2ProbeSize);
str[0]=0;
if (!buf)
return;
Seek(ih, 0);
Read(ih, (long)buf, EX2ProbeSize);
if (!EX2Probe (buf))
{
free (buf);
return;
}
if (OSReadLittleInt32 (buf+0x44c,0)<1)
{
free (buf);
return;
}
str[strMaxLen]=0;
strncpy (str, buf+0x478, MIN(strMaxLen, 16));
free (buf);
}
branches/rewrite/i386/libsaio/nbp.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
* Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
* Reserved. This file contains Original Code and/or Modifications of
* Original Code as defined in and that are subject to the Apple Public
* Source License Version 2.0 (the "License"). You may not use this file
* except in compliance with the License. Please obtain a copy of the
* License at http://www.apple.com/publicsource and read it before using
* this file.
*
* The Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include "libsaio.h"
/* This NBP code is pretty useless because it just blindly calls INT 2B.
Presumably INT 2B was implemented by some first-stage bootloader that
is long gone.
One good reason to disable this is that nbpScanBootVolumes always
succeeds. The scanBootVolumes function thus never fails because
it always falls back to NBP. This is a problem because there is
other code in the booter (for example, in open) which needs to
fail instead of attempting to use this NBP which will often
hang the machine.
*/
#ifndef NBP_SUPPORT
#define NBP_SUPPORT 0
#endif
#if NBP_SUPPORT
/*
* Convert zero-based linear address to far pointer.
*/
#define GET_FP(x) ( (((x) & 0xffff0000) << (16 - 4)) | ((x) & 0xffff) )
/*==========================================================================
* Issue a command to the network loader.
*
* The 'cmd' command structure should be allocated on the stack to
* ensure that it resides within the addressable range for the
* network loader, which runs in real mode.
*/
static UInt32 nbp(nbpCommandCode_t code, nbpCommand_u * cmd)
{
loader(code, GET_FP((UInt32) cmd));
// Must re-enable the A20 address line, the PXE firmware will
// disable the A20 line control.
//
enableA20();
return cmd->header.status;
}
/*==========================================================================
* Unload Base Code Stack command.
*/
UInt32 nbpUnloadBaseCode()
{
return nbp(nbpCommandUnloadBaseCode, (nbpCommand_u *) 0);
}
/*==========================================================================
* TFTP Read File command.
*/
static long NBPLoadFile(CICell ih, char * filePath)
{
nbpCommandTFTPReadFile_s cmd;
UInt32 ret;
strcpy((char *)cmd.filename, filePath);
cmd.status = nbpStatusFailed;
cmd.bufferSize = TFTP_LEN;
cmd.buffer = TFTP_ADDR;
verbose("Loading file: %s\n", filePath);
ret = nbp(nbpCommandTFTPReadFile, (nbpCommand_u *) &cmd);
return (ret == nbpStatusSuccess) ? (long)cmd.bufferSize : -1;
}
/*==========================================================================
* GetDirEntry is not supported.
*/
static long NBPGetDirEntry(CICell ih, char * dirPath, long long * dirIndex,
char ** name, long * flags, long * time,
FinderInfo * finderInfo, long * infoValid)
{
return -1;
}
//==========================================================================
static void NBPGetDescription(CICell ih, char * str, long strMaxLen)
{
sprintf( str, "Ethernet PXE Client" );
}
//==========================================================================
BVRef nbpScanBootVolumes( int biosdev, int * countPtr )
{
static BVRef gNetBVR = NULL;
if ( countPtr ) *countPtr = 1;
if ( !gNetBVR )
{
gNetBVR = malloc( sizeof(*gNetBVR) );
if ( gNetBVR )
{
bzero(gNetBVR, sizeof(*gNetBVR));
gNetBVR->biosdev = biosdev;
gNetBVR->flags = kBVFlagPrimary | kBVFlagNativeBoot;
gNetBVR->description = NBPGetDescription;
gNetBVR->fs_loadfile = NBPLoadFile;
gNetBVR->fs_getdirentry = NBPGetDirEntry;
}
}
return gNetBVR;
}
#else
BVRef nbpScanBootVolumes( int biosdev, int * countPtr )
{
return NULL;
}
UInt32 nbpUnloadBaseCode()
{
return 0;
}
#endif
branches/rewrite/i386/libsaio/ntfs.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 2.0 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
extern void NTFSGetDescription(CICell ih, char *str, long strMaxLen);
extern bool NTFSProbe (const void *buf);
extern long NTFSGetUUID(CICell ih, char *uuidStr);
branches/rewrite/i386/libsaio/ext2fs.h
1
2
3
4
5
6
7
8
9
10
11
/*
* ext2fs.h
*
*
* Created by mackerintel on 1/26/09.
* Copyright 2009 __MyCompanyName__. All rights reserved.
*
*/
extern bool EX2Probe (const void *buf);
extern void EX2GetDescription(CICell ih, char *str, long strMaxLen);
branches/rewrite/i386/libsaio/hfs.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
/*
* Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 2.0 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* hfs.c - File System Module for HFS and HFS+.
*
* Copyright (c) 1999-2002 Apple Computer, Inc.
*
* DRI: Josh de Cesare
*/
#include <sl.h>
#include <hfs/hfs_format.h>
#include "hfs.h"
#define kBlockSize (0x200)
#define kMDBBaseOffset (2 * kBlockSize)
#define kBTreeCatalog (0)
#define kBTreeExtents (1)
#ifdef __i386__
static CICell gCurrentIH;
static long long gAllocationOffset;
static long gIsHFSPlus;
static long gCaseSensitive;
static long gBlockSize;
static long gCacheBlockSize;
static char *gBTreeHeaderBuffer;
static BTHeaderRec *gBTHeaders[2];
static char *gHFSMdbVib;
static HFSMasterDirectoryBlock *gHFSMDB;
static char *gHFSPlusHeader;
static HFSPlusVolumeHeader *gHFSPlus;
static char *gLinkTemp;
static long long gVolID;
static char *gTempStr;
#else /* !__i386__ */
static CICell gCurrentIH;
static long long gAllocationOffset;
static long gIsHFSPlus;
static long gBlockSize;
static long gCaseSensitive;
static long gCacheBlockSize;
static char gBTreeHeaderBuffer[512];
static BTHeaderRec *gBTHeaders[2];
static char gHFSMdbVib[kBlockSize];
static HFSMasterDirectoryBlock *gHFSMDB =(HFSMasterDirectoryBlock*)gHFSMdbVib;
static char gHFSPlusHeader[kBlockSize];
static HFSPlusVolumeHeader *gHFSPlus =(HFSPlusVolumeHeader*)gHFSPlusHeader;
static char gLinkTemp[64];
static long long gVolID;
#endif /* !__i386__ */
static long ReadFile(void *file, uint64_t *length, void *base, uint64_t offset);
static long GetCatalogEntryInfo(void *entry, long *flags, long *time,
FinderInfo *finderInfo, long *infoValid);
static long ResolvePathToCatalogEntry(char *filePath, long *flags,
void *entry, long dirID, long long *dirIndex);
static long GetCatalogEntry(long long *dirIndex, char **name,
long *flags, long *time,
FinderInfo *finderInfo, long *infoValid);
static long ReadCatalogEntry(char *fileName, long dirID, void *entry,
long long *dirIndex);
static long ReadExtentsEntry(long fileID, long startBlock, void *entry);
static long ReadBTreeEntry(long btree, void *key, char *entry, long long *dirIndex);
static void GetBTreeRecord(long index, char *nodeBuffer, long nodeSize,
char **key, char **data);
static long ReadExtent(char *extent, uint64_t extentSize, long extentFile,
uint64_t offset, uint64_t size, void *buffer, long cache);
static long GetExtentStart(void *extents, long index);
static long GetExtentSize(void *extents, long index);
static long CompareHFSCatalogKeys(void *key, void *testKey);
static long CompareHFSPlusCatalogKeys(void *key, void *testKey);
static long CompareHFSExtentsKeys(void *key, void *testKey);
static long CompareHFSPlusExtentsKeys(void *key, void *testKey);
extern long FastRelString(u_int8_t *str1, u_int8_t *str2);
extern long BinaryUnicodeCompare(u_int16_t *uniStr1, u_int32_t len1,
u_int16_t *uniStr2, u_int32_t len2);
static void SwapFinderInfo(FndrFileInfo *dst, FndrFileInfo *src)
{
dst->fdType = SWAP_BE32(src->fdType);
dst->fdCreator = SWAP_BE32(src->fdCreator);
dst->fdFlags = SWAP_BE16(src->fdFlags);
// Don't bother with location
}
void HFSFree(CICell ih)
{
if(gCurrentIH == ih)
gCurrentIH = 0;
free(ih);
}
bool HFSProbe (const void *buf)
{
const HFSMasterDirectoryBlock *mdb;
const HFSPlusVolumeHeader *header;
mdb=(const HFSMasterDirectoryBlock *)(((const char*)buf)+kMDBBaseOffset);
header=(const HFSPlusVolumeHeader *)(((const char*)buf)+kMDBBaseOffset);
if ( SWAP_BE16(mdb->drSigWord) == kHFSSigWord )
return true;
if (SWAP_BE16(header->signature) != kHFSPlusSigWord &&
SWAP_BE16(header->signature) != kHFSXSigWord)
return false;
return true;
}
long HFSInitPartition(CICell ih)
{
long extentSize, extentFile, nodeSize;
void *extent;
if (ih == gCurrentIH) {
#ifdef __i386__
CacheInit(ih, gCacheBlockSize);
#endif
return 0;
}
#ifdef __i386__
if (!gTempStr) gTempStr = (char *)malloc(4096);
if (!gLinkTemp) gLinkTemp = (char *)malloc(64);
if (!gBTreeHeaderBuffer) gBTreeHeaderBuffer = (char *)malloc(512);
if (!gHFSMdbVib) {
gHFSMdbVib = (char *)malloc(kBlockSize);
gHFSMDB = (HFSMasterDirectoryBlock *)gHFSMdbVib;
}
if (!gHFSPlusHeader) {
gHFSPlusHeader = (char *)malloc(kBlockSize);
gHFSPlus = (HFSPlusVolumeHeader *)gHFSPlusHeader;
}
if (!gTempStr || !gLinkTemp || !gBTreeHeaderBuffer ||
!gHFSMdbVib || !gHFSPlusHeader) return -1;
#endif /* __i386__ */
gAllocationOffset = 0;
gIsHFSPlus = 0;
gCaseSensitive = 0;
gBTHeaders[0] = 0;
gBTHeaders[1] = 0;
// Look for the HFS MDB
Seek(ih, kMDBBaseOffset);
Read(ih, (long)gHFSMdbVib, kBlockSize);
if ( SWAP_BE16(gHFSMDB->drSigWord) == kHFSSigWord ) {
gAllocationOffset = SWAP_BE16(gHFSMDB->drAlBlSt) * kBlockSize;
// See if it is HFSPlus
if (SWAP_BE16(gHFSMDB->drEmbedSigWord) != kHFSPlusSigWord) {
// Normal HFS;
gCacheBlockSize = gBlockSize = SWAP_BE32(gHFSMDB->drAlBlkSiz);
CacheInit(ih, gCacheBlockSize);
gCurrentIH = ih;
// grab the 64 bit volume ID
bcopy(&gHFSMDB->drFndrInfo[6], &gVolID, 8);
// Get the Catalog BTree node size.
extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec;
extentSize = SWAP_BE32(gHFSMDB->drCTFlSize);
extentFile = kHFSCatalogFileID;
ReadExtent(extent, extentSize, extentFile, 0, 256,
gBTreeHeaderBuffer + kBTreeCatalog * 256, 0);
nodeSize = SWAP_BE16(((BTHeaderRec *)(gBTreeHeaderBuffer + kBTreeCatalog * 256 +
sizeof(BTNodeDescriptor)))->nodeSize);
// If the BTree node size is larger than the block size, reset the cache.
if (nodeSize > gBlockSize) {
gCacheBlockSize = nodeSize;
CacheInit(ih, gCacheBlockSize);
}
return 0;
}
// Calculate the offset to the embeded HFSPlus volume.
gAllocationOffset += (long long)SWAP_BE16(gHFSMDB->drEmbedExtent.startBlock) *
SWAP_BE32(gHFSMDB->drAlBlkSiz);
}
// Look for the HFSPlus Header
Seek(ih, gAllocationOffset + kMDBBaseOffset);
Read(ih, (long)gHFSPlusHeader, kBlockSize);
// Not a HFS+ or HFSX volume.
if (SWAP_BE16(gHFSPlus->signature) != kHFSPlusSigWord &&
SWAP_BE16(gHFSPlus->signature) != kHFSXSigWord) {
verbose("HFS signature was not present.\n");
gCurrentIH = 0;
return -1;
}
gIsHFSPlus = 1;
gCacheBlockSize = gBlockSize = SWAP_BE32(gHFSPlus->blockSize);
CacheInit(ih, gCacheBlockSize);
gCurrentIH = ih;
ih->modTime = SWAP_BE32(gHFSPlus->modifyDate) - 2082844800;
// grab the 64 bit volume ID
bcopy(&gHFSPlus->finderInfo[24], &gVolID, 8);
// Get the Catalog BTree node size.
extent = &gHFSPlus->catalogFile.extents;
extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize);
extentFile = kHFSCatalogFileID;
ReadExtent(extent, extentSize, extentFile, 0, 256,
gBTreeHeaderBuffer + kBTreeCatalog * 256, 0);
nodeSize = SWAP_BE16(((BTHeaderRec *)(gBTreeHeaderBuffer + kBTreeCatalog * 256 +
sizeof(BTNodeDescriptor)))->nodeSize);
// If the BTree node size is larger than the block size, reset the cache.
if (nodeSize > gBlockSize) {
gCacheBlockSize = nodeSize;
CacheInit(ih, gCacheBlockSize);
}
return 0;
}
long HFSLoadFile(CICell ih, char * filePath)
{
return HFSReadFile(ih, filePath, (void *)gFSLoadAddress, 0, 0);
}
long HFSReadFile(CICell ih, char * filePath, void *base, uint64_t offset, uint64_t length)
{
char entry[512];
char devStr[12];
long dirID, result, flags;
if (HFSInitPartition(ih) == -1) return -1;
dirID = kHFSRootFolderID;
// Skip a lead '\'. Start in the system folder if there are two.
if (filePath[0] == '/') {
if (filePath[1] == '/') {
if (gIsHFSPlus) dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]);
else dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]);
if (dirID == 0) {
return -1;
}
filePath++;
}
filePath++;
}
result = ResolvePathToCatalogEntry(filePath, &flags, entry, dirID, 0);
if ((result == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) {
return -1;
}
#if UNUSED
// Not yet for Intel. System.config/Default.table will fail this check.
// Check file owner and permissions.
if (flags & (kOwnerNotRoot | kPermGroupWrite | kPermOtherWrite)) return -1;
#endif
result = ReadFile(entry, &length, base, offset);
if (result == -1) {
return -1;
}
getDeviceDescription(ih, devStr);
verbose("Read HFS%s file: [%s/%s] %d bytes.\n",
(gIsHFSPlus ? "+" : ""), devStr, filePath, (uint32_t)length);
return length;
}
long HFSGetDirEntry(CICell ih, char * dirPath, long long * dirIndex, char ** name,
long * flags, long * time,
FinderInfo * finderInfo, long * infoValid)
{
char entry[512];
long dirID, dirFlags;
if (HFSInitPartition(ih) == -1) return -1;
if (*dirIndex == -1) return -1;
dirID = kHFSRootFolderID;
// Skip a lead '\'. Start in the system folder if there are two.
if (dirPath[0] == '/') {
if (dirPath[1] == '/') {
if (gIsHFSPlus) dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]);
else dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]);
if (dirID == 0) return -1;
dirPath++;
}
dirPath++;
}
if (*dirIndex == 0) {
ResolvePathToCatalogEntry(dirPath, &dirFlags, entry, dirID, dirIndex);
if (*dirIndex == 0) *dirIndex = -1;
if ((dirFlags & kFileTypeMask) != kFileTypeUnknown) return -1;
}
GetCatalogEntry(dirIndex, name, flags, time, finderInfo, infoValid);
if (*dirIndex == 0) *dirIndex = -1;
if ((*flags & kFileTypeMask) == kFileTypeUnknown) return -1;
return 0;
}
void
HFSGetDescription(CICell ih, char *str, long strMaxLen)
{
UInt16 nodeSize;
UInt32 firstLeafNode;
long long dirIndex;
char *name;
long flags, time;
if (HFSInitPartition(ih) == -1) { return; }
/* Fill some crucial data structures by side effect. */
dirIndex = 0;
HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0);
/* Now we can loook up the volume name node. */
nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize);
firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode);
dirIndex = (long long) firstLeafNode * nodeSize;
GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0);
strncpy(str, name, strMaxLen);
str[strMaxLen] = '\0';
}
long
HFSGetFileBlock(CICell ih, char *filePath, unsigned long long *firstBlock)
{
char entry[512];
long dirID, result, flags;
void *extents;
HFSCatalogFile *hfsFile = (void *)entry;
HFSPlusCatalogFile *hfsPlusFile = (void *)entry;
if (HFSInitPartition(ih) == -1) return -1;
dirID = kHFSRootFolderID;
// Skip a lead '\'. Start in the system folder if there are two.
if (filePath[0] == '/') {
if (filePath[1] == '/') {
if (gIsHFSPlus) dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]);
else dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]);
if (dirID == 0) {
return -1;
}
filePath++;
}
filePath++;
}
result = ResolvePathToCatalogEntry(filePath, &flags, entry, dirID, 0);
if ((result == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) {
printf("HFS: Resolve path %s failed\n", filePath);
return -1;
}
if (gIsHFSPlus) {
extents = &hfsPlusFile->dataFork.extents;
} else {
extents = &hfsFile->dataExtents;
}
#if DEBUG
printf("extent start 0x%x\n", (unsigned long)GetExtentStart(extents, 0));
printf("block size 0x%x\n", (unsigned long)gBlockSize);
printf("Allocation offset 0x%x\n", (unsigned long)gAllocationOffset);
#endif
*firstBlock = ((unsigned long long)GetExtentStart(extents, 0) * (unsigned long long) gBlockSize + gAllocationOffset) / 512ULL;
return 0;
}
long HFSGetUUID(CICell ih, char *uuidStr)
{
if (HFSInitPartition(ih) == -1) return -1;
if (gVolID == 0LL) return -1;
return CreateUUIDString((uint8_t*)(&gVolID), sizeof(gVolID), uuidStr);
}
// Private Functions
static long ReadFile(void * file, uint64_t * length, void * base, uint64_t offset)
{
void *extents;
long fileID;
uint64_t fileLength;
HFSCatalogFile *hfsFile = file;
HFSPlusCatalogFile *hfsPlusFile = file;
if (gIsHFSPlus) {
fileID = SWAP_BE32(hfsPlusFile->fileID);
fileLength = (uint64_t)SWAP_BE64(hfsPlusFile->dataFork.logicalSize);
extents = &hfsPlusFile->dataFork.extents;
} else {
fileID = SWAP_BE32(hfsFile->fileID);
fileLength = SWAP_BE32(hfsFile->dataLogicalSize);
extents = &hfsFile->dataExtents;
}
if (offset > fileLength) {
printf("Offset is too large.\n");
return -1;
}
if ((*length == 0) || ((offset + *length) > fileLength)) {
*length = fileLength - offset;
}
/* if (*length > kLoadSize) {
printf("File is too large.\n");
return -1;
}*/
*length = ReadExtent((char *)extents, fileLength, fileID,
offset, *length, (char *)base, 0);
return 0;
}
static long GetCatalogEntryInfo(void * entry, long * flags, long * time,
FinderInfo * finderInfo, long * infoValid)
{
long tmpTime = 0;
long valid = 0;
// Get information about the file.
switch ( SWAP_BE16(*(short *)entry) )
{
case kHFSFolderRecord :
*flags = kFileTypeDirectory;
tmpTime = SWAP_BE32(((HFSCatalogFolder *)entry)->modifyDate);
break;
case kHFSPlusFolderRecord :
*flags = kFileTypeDirectory |
(SWAP_BE16(((HFSPlusCatalogFolder *)entry)->bsdInfo.fileMode) & kPermMask);
if (SWAP_BE32(((HFSPlusCatalogFolder *)entry)->bsdInfo.ownerID) != 0)
*flags |= kOwnerNotRoot;
tmpTime = SWAP_BE32(((HFSPlusCatalogFolder *)entry)->contentModDate);
break;
case kHFSFileRecord :
*flags = kFileTypeFlat;
tmpTime = SWAP_BE32(((HFSCatalogFile *)entry)->modifyDate);
if (finderInfo) {
SwapFinderInfo((FndrFileInfo *)finderInfo, &((HFSCatalogFile *)entry)->userInfo);
valid = 1;
}
break;
case kHFSPlusFileRecord :
*flags = kFileTypeFlat |
(SWAP_BE16(((HFSPlusCatalogFile *)entry)->bsdInfo.fileMode) & kPermMask);
if (SWAP_BE32(((HFSPlusCatalogFile *)entry)->bsdInfo.ownerID) != 0)
*flags |= kOwnerNotRoot;
tmpTime = SWAP_BE32(((HFSPlusCatalogFile *)entry)->contentModDate);
if (finderInfo) {
SwapFinderInfo((FndrFileInfo *)finderInfo, &((HFSPlusCatalogFile *)entry)->userInfo);
valid = 1;
}
break;
case kHFSFileThreadRecord :
case kHFSPlusFileThreadRecord :
case kHFSFolderThreadRecord :
case kHFSPlusFolderThreadRecord :
*flags = kFileTypeUnknown;
tmpTime = 0;
break;
}
if (time != 0) {
// Convert base time from 1904 to 1970.
*time = tmpTime - 2082844800;
}
if (infoValid) *infoValid = valid;
return 0;
}
static long ResolvePathToCatalogEntry(char * filePath, long * flags,
void * entry, long dirID, long long * dirIndex)
{
char *restPath;
long result, cnt, subFolderID = 0;
long long tmpDirIndex;
HFSPlusCatalogFile *hfsPlusFile;
// Copy the file name to gTempStr
cnt = 0;
while ((filePath[cnt] != '/') && (filePath[cnt] != '\0')) cnt++;
strlcpy(gTempStr, filePath, cnt+1);
// Move restPath to the right place.
if (filePath[cnt] != '\0') cnt++;
restPath = filePath + cnt;
// gTempStr is a name in the current Dir.
// restPath is the rest of the path if any.
result = ReadCatalogEntry(gTempStr, dirID, entry, dirIndex);
if (result == -1) {
return -1;
}
GetCatalogEntryInfo(entry, flags, 0, 0, 0);
if ((*flags & kFileTypeMask) == kFileTypeDirectory) {
if (gIsHFSPlus)
subFolderID = SWAP_BE32(((HFSPlusCatalogFolder *)entry)->folderID);
else
subFolderID = SWAP_BE32(((HFSCatalogFolder *)entry)->folderID);
}
if ((*flags & kFileTypeMask) == kFileTypeDirectory)
result = ResolvePathToCatalogEntry(restPath, flags, entry,
subFolderID, dirIndex);
if (gIsHFSPlus && ((*flags & kFileTypeMask) == kFileTypeFlat)) {
hfsPlusFile = (HFSPlusCatalogFile *)entry;
if ((SWAP_BE32(hfsPlusFile->userInfo.fdType) == kHardLinkFileType) &&
(SWAP_BE32(hfsPlusFile->userInfo.fdCreator) == kHFSPlusCreator)) {
sprintf(gLinkTemp, "%s/%s%ld", HFSPLUSMETADATAFOLDER,
HFS_INODE_PREFIX, SWAP_BE32(hfsPlusFile->bsdInfo.special.iNodeNum));
result = ResolvePathToCatalogEntry(gLinkTemp, flags, entry,
kHFSRootFolderID, &tmpDirIndex);
}
}
return result;
}
static long GetCatalogEntry(long long * dirIndex, char ** name,
long * flags, long * time,
FinderInfo * finderInfo, long * infoValid)
{
long extentSize, nodeSize, curNode, index;
void *extent;
char *nodeBuf, *testKey, *entry;
BTNodeDescriptor *node;
if (gIsHFSPlus) {
extent = &gHFSPlus->catalogFile.extents;
extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize);
} else {
extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec;
extentSize = SWAP_BE32(gHFSMDB->drCTFlSize);
}
nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize);
nodeBuf = (char *)malloc(nodeSize);
node = (BTNodeDescriptor *)nodeBuf;
index = (long) (*dirIndex % nodeSize);
curNode = (long) (*dirIndex / nodeSize);
// Read the BTree node and get the record for index.
ReadExtent(extent, extentSize, kHFSCatalogFileID,
(long long) curNode * nodeSize, nodeSize, nodeBuf, 1);
GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &entry);
GetCatalogEntryInfo(entry, flags, time, finderInfo, infoValid);
// Get the file name.
if (gIsHFSPlus) {
utf_encodestr(((HFSPlusCatalogKey *)testKey)->nodeName.unicode,
SWAP_BE16(((HFSPlusCatalogKey *)testKey)->nodeName.length),
(u_int8_t *)gTempStr, 256, OSBigEndian);
} else {
strncpy(gTempStr,
(const char *)&((HFSCatalogKey *)testKey)->nodeName[1],
((HFSCatalogKey *)testKey)->nodeName[0]);
gTempStr[((HFSCatalogKey *)testKey)->nodeName[0]] = '\0';
}
*name = gTempStr;
// Update dirIndex.
index++;
if (index == SWAP_BE16(node->numRecords)) {
index = 0;
curNode = SWAP_BE32(node->fLink);
}
*dirIndex = (long long) curNode * nodeSize + index;
free(nodeBuf);
return 0;
}
static long ReadCatalogEntry(char * fileName, long dirID,
void * entry, long long * dirIndex)
{
long length;
char key[sizeof(HFSPlusCatalogKey)];
HFSCatalogKey *hfsKey = (HFSCatalogKey *)key;
HFSPlusCatalogKey *hfsPlusKey = (HFSPlusCatalogKey *)key;
// Make the catalog key.
if ( gIsHFSPlus )
{
hfsPlusKey->parentID = SWAP_BE32(dirID);
length = strlen(fileName);
if (length > 255) length = 255;
utf_decodestr((u_int8_t *)fileName, hfsPlusKey->nodeName.unicode,
&(hfsPlusKey->nodeName.length), 512, OSBigEndian);
} else {
hfsKey->parentID = SWAP_BE32(dirID);
length = strlen(fileName);
if (length > 31) length = 31;
hfsKey->nodeName[0] = length;
strncpy((char *)(hfsKey->nodeName + 1), fileName, length);
}
return ReadBTreeEntry(kBTreeCatalog, &key, entry, dirIndex);
}
static long ReadExtentsEntry(long fileID, long startBlock, void * entry)
{
char key[sizeof(HFSPlusExtentKey)];
HFSExtentKey *hfsKey = (HFSExtentKey *)key;
HFSPlusExtentKey *hfsPlusKey = (HFSPlusExtentKey *)key;
// Make the extents key.
if (gIsHFSPlus) {
hfsPlusKey->forkType = 0;
hfsPlusKey->fileID = SWAP_BE32(fileID);
hfsPlusKey->startBlock = SWAP_BE32(startBlock);
} else {
hfsKey->forkType = 0;
hfsKey->fileID = SWAP_BE32(fileID);
hfsKey->startBlock = SWAP_BE16(startBlock);
}
return ReadBTreeEntry(kBTreeExtents, &key, entry, 0);
}
static long ReadBTreeEntry(long btree, void * key, char * entry, long long * dirIndex)
{
long extentSize;
void *extent;
short extentFile;
char *nodeBuf;
BTNodeDescriptor *node;
long nodeSize, result = 0, entrySize = 0;
long curNode, index = 0, lowerBound, upperBound;
char *testKey, *recordData;
// Figure out which tree is being looked at.
if (btree == kBTreeCatalog) {
if (gIsHFSPlus) {
extent = &gHFSPlus->catalogFile.extents;
extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize);
} else {
extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec;
extentSize = SWAP_BE32(gHFSMDB->drCTFlSize);
}
extentFile = kHFSCatalogFileID;
} else {
if (gIsHFSPlus) {
extent = &gHFSPlus->extentsFile.extents;
extentSize = SWAP_BE64(gHFSPlus->extentsFile.logicalSize);
} else {
extent = (HFSExtentDescriptor *)&gHFSMDB->drXTExtRec;
extentSize = SWAP_BE32(gHFSMDB->drXTFlSize);
}
extentFile = kHFSExtentsFileID;
}
// Read the BTree Header if needed.
if (gBTHeaders[btree] == 0) {
ReadExtent(extent, extentSize, extentFile, 0, 256,
gBTreeHeaderBuffer + btree * 256, 0);
gBTHeaders[btree] = (BTHeaderRec *)(gBTreeHeaderBuffer + btree * 256 +
sizeof(BTNodeDescriptor));
if ((gIsHFSPlus && btree == kBTreeCatalog) &&
(gBTHeaders[btree]->keyCompareType == kHFSBinaryCompare)) {
gCaseSensitive = 1;
}
}
curNode = SWAP_BE32(gBTHeaders[btree]->rootNode);
nodeSize = SWAP_BE16(gBTHeaders[btree]->nodeSize);
nodeBuf = (char *)malloc(nodeSize);
node = (BTNodeDescriptor *)nodeBuf;
while (1) {
// Read the current node.
ReadExtent(extent, extentSize, extentFile,
(long long) curNode * nodeSize, nodeSize, nodeBuf, 1);
// Find the matching key.
lowerBound = 0;
upperBound = SWAP_BE16(node->numRecords) - 1;
while (lowerBound <= upperBound) {
index = (lowerBound + upperBound) / 2;
GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData);
if (gIsHFSPlus) {
if (btree == kBTreeCatalog) {
result = CompareHFSPlusCatalogKeys(key, testKey);
} else {
result = CompareHFSPlusExtentsKeys(key, testKey);
}
} else {
if (btree == kBTreeCatalog) {
result = CompareHFSCatalogKeys(key, testKey);
} else {
result = CompareHFSExtentsKeys(key, testKey);
}
}
if (result < 0) upperBound = index - 1; // search < trial
else if (result > 0) lowerBound = index + 1; // search > trial
else break; // search = trial
}
if (result < 0) {
index = upperBound;
GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData);
}
// Found the closest key... Recurse on it if this is an index node.
if (node->kind == kBTIndexNode) {
curNode = SWAP_BE32( *((long *)recordData) );
} else break;
}
// Return error if the file was not found.
if (result != 0) { free(nodeBuf); return -1; }
if (btree == kBTreeCatalog) {
switch (SWAP_BE16(*(short *)recordData)) {
case kHFSFolderRecord : entrySize = 70; break;
case kHFSFileRecord : entrySize = 102; break;
case kHFSFolderThreadRecord : entrySize = 46; break;
case kHFSFileThreadRecord : entrySize = 46; break;
case kHFSPlusFolderRecord : entrySize = 88; break;
case kHFSPlusFileRecord : entrySize = 248; break;
case kHFSPlusFolderThreadRecord : entrySize = 264; break;
case kHFSPlusFileThreadRecord : entrySize = 264; break;
}
} else {
if (gIsHFSPlus) entrySize = sizeof(HFSPlusExtentRecord);
else entrySize = sizeof(HFSExtentRecord);
}
bcopy(recordData, entry, entrySize);
// Update dirIndex.
if (dirIndex != 0) {
index++;
if (index == SWAP_BE16(node->numRecords)) {
index = 0;
curNode = SWAP_BE32(node->fLink);
}
*dirIndex = (long long) curNode * nodeSize + index;
}
free(nodeBuf);
return 0;
}
static void GetBTreeRecord(long index, char * nodeBuffer, long nodeSize,
char ** key, char ** data)
{
long keySize;
long recordOffset;
recordOffset = SWAP_BE16(*((short *)(nodeBuffer + (nodeSize - 2 * index - 2))));
*key = nodeBuffer + recordOffset;
if (gIsHFSPlus) {
keySize = SWAP_BE16(*(short *)*key);
*data = *key + 2 + keySize;
} else {
keySize = **key;
*data = *key + 2 + keySize - (keySize & 1);
}
}
static long ReadExtent(char * extent, uint64_t extentSize,
long extentFile, uint64_t offset, uint64_t size,
void * buffer, long cache)
{
uint64_t lastOffset;
long long blockNumber, countedBlocks = 0;
long long nextExtent = 0, sizeRead = 0, readSize;
long long nextExtentBlock, currentExtentBlock = 0;
long long readOffset;
long long extentDensity, sizeofExtent, currentExtentSize;
char *currentExtent, *extentBuffer = 0, *bufferPos = buffer;
if (offset >= extentSize) return 0;
if (gIsHFSPlus) {
extentDensity = kHFSPlusExtentDensity;
sizeofExtent = sizeof(HFSPlusExtentDescriptor);
} else {
extentDensity = kHFSExtentDensity;
sizeofExtent = sizeof(HFSExtentDescriptor);
}
lastOffset = offset + size;
while (offset < lastOffset) {
blockNumber = offset / gBlockSize;
// Find the extent for the offset.
for (; ; nextExtent++) {
if (nextExtent < extentDensity) {
if ((countedBlocks+GetExtentSize(extent, nextExtent)-1)<blockNumber) {
countedBlocks += GetExtentSize(extent, nextExtent);
continue;
}
currentExtent = extent + nextExtent * sizeofExtent;
break;
}
if (extentBuffer == 0) {
extentBuffer = malloc(sizeofExtent * extentDensity);
if (extentBuffer == 0) return -1;
}
nextExtentBlock = nextExtent / extentDensity;
if (currentExtentBlock != nextExtentBlock) {
ReadExtentsEntry(extentFile, countedBlocks, extentBuffer);
currentExtentBlock = nextExtentBlock;
}
currentExtentSize = GetExtentSize(extentBuffer, nextExtent % extentDensity);
if ((countedBlocks + currentExtentSize - 1) >= blockNumber) {
currentExtent = extentBuffer + sizeofExtent * (nextExtent % extentDensity);
break;
}
countedBlocks += currentExtentSize;
}
readOffset = ((blockNumber - countedBlocks) * gBlockSize) +
(offset % gBlockSize);
// MacWen: fix overflow in multiplication by forcing 64bit multiplication
readSize = (long long)GetExtentSize(currentExtent, 0) * gBlockSize - readOffset;
if (readSize > (size - sizeRead)) readSize = size - sizeRead;
readOffset += (long long)GetExtentStart(currentExtent, 0) * gBlockSize;
CacheRead(gCurrentIH, bufferPos, gAllocationOffset + readOffset,
readSize, cache);
sizeRead += readSize;
offset += readSize;
bufferPos += readSize;
}
if (extentBuffer) free(extentBuffer);
return sizeRead;
}
static long GetExtentStart(void * extents, long index)
{
long start;
HFSExtentDescriptor *hfsExtents = extents;
HFSPlusExtentDescriptor *hfsPlusExtents = extents;
if (gIsHFSPlus) start = SWAP_BE32(hfsPlusExtents[index].startBlock);
else start = SWAP_BE16(hfsExtents[index].startBlock);
return start;
}
static long GetExtentSize(void * extents, long index)
{
long size;
HFSExtentDescriptor *hfsExtents = extents;
HFSPlusExtentDescriptor *hfsPlusExtents = extents;
if (gIsHFSPlus) size = SWAP_BE32(hfsPlusExtents[index].blockCount);
else size = SWAP_BE16(hfsExtents[index].blockCount);
return size;
}
static long CompareHFSCatalogKeys(void * key, void * testKey)
{
HFSCatalogKey *searchKey, *trialKey;
long result, searchParentID, trialParentID;
searchKey = key;
trialKey = testKey;
searchParentID = SWAP_BE32(searchKey->parentID);
trialParentID = SWAP_BE32(trialKey->parentID);
// parent dirID is unsigned
if (searchParentID > trialParentID) result = 1;
else if (searchParentID < trialParentID) result = -1;
else {
// parent dirID's are equal, compare names
result = FastRelString(searchKey->nodeName, trialKey->nodeName);
}
return result;
}
static long CompareHFSPlusCatalogKeys(void * key, void * testKey)
{
HFSPlusCatalogKey *searchKey, *trialKey;
long result, searchParentID, trialParentID;
searchKey = key;
trialKey = testKey;
searchParentID = SWAP_BE32(searchKey->parentID);
trialParentID = SWAP_BE32(trialKey->parentID);
// parent dirID is unsigned
if (searchParentID > trialParentID) result = 1;
else if (searchParentID < trialParentID) result = -1;
else {
// parent dirID's are equal, compare names
if ((searchKey->nodeName.length == 0) || (trialKey->nodeName.length == 0))
result = searchKey->nodeName.length - trialKey->nodeName.length;
else
if (gCaseSensitive) {
result = BinaryUnicodeCompare(&searchKey->nodeName.unicode[0],
SWAP_BE16(searchKey->nodeName.length),
&trialKey->nodeName.unicode[0],
SWAP_BE16(trialKey->nodeName.length));
} else {
result = FastUnicodeCompare(&searchKey->nodeName.unicode[0],
SWAP_BE16(searchKey->nodeName.length),
&trialKey->nodeName.unicode[0],
SWAP_BE16(trialKey->nodeName.length), OSBigEndian);
}
}
return result;
}
static long CompareHFSExtentsKeys(void * key, void * testKey)
{
HFSExtentKey *searchKey, *trialKey;
long result;
searchKey = key;
trialKey = testKey;
// assume searchKey < trialKey
result = -1;
if (searchKey->fileID == trialKey->fileID) {
// FileNum's are equal; compare fork types
if (searchKey->forkType == trialKey->forkType) {
// Fork types are equal; compare allocation block number
if (searchKey->startBlock == trialKey->startBlock) {
// Everything is equal
result = 0;
} else {
// Allocation block numbers differ; determine sign
if (SWAP_BE16(searchKey->startBlock) > SWAP_BE16(trialKey->startBlock))
result = 1;
}
} else {
// Fork types differ; determine sign
if (searchKey->forkType > trialKey->forkType) result = 1;
}
} else {
// FileNums differ; determine sign
if (SWAP_BE32(searchKey->fileID) > SWAP_BE32(trialKey->fileID))
result = 1;
}
return result;
}
static long CompareHFSPlusExtentsKeys(void * key, void * testKey)
{
HFSPlusExtentKey *searchKey, *trialKey;
long result;
searchKey = key;
trialKey = testKey;
// assume searchKey < trialKey
result = -1;
if (searchKey->fileID == trialKey->fileID) {
// FileNum's are equal; compare fork types
if (searchKey->forkType == trialKey->forkType) {
// Fork types are equal; compare allocation block number
if (searchKey->startBlock == trialKey->startBlock) {
// Everything is equal
result = 0;
} else {
// Allocation block numbers differ; determine sign
if (SWAP_BE32(searchKey->startBlock) > SWAP_BE32(trialKey->startBlock))
result = 1;
}
} else {
// Fork types differ; determine sign
if (searchKey->forkType > trialKey->forkType) result = 1;
}
} else {
// FileNums differ; determine sign
if (SWAP_BE32(searchKey->fileID) > SWAP_BE32(trialKey->fileID))
result = 1;
}
return result;
}
branches/rewrite/i386/libsaio/ufs_byteorder.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/*
* Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
* Reserved. This file contains Original Code and/or Modifications of
* Original Code as defined in and that are subject to the Apple Public
* Source License Version 2.0 (the "License"). You may not use this file
* except in compliance with the License. Please obtain a copy of the
* License at http://www.apple.com/publicsource and read it before using
* this file.
*
* The Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* Copyright (c) 1992 NeXT Computer, Inc.
*
* UFS byte swapping routines to make a big endian file system useful on a
* little endian machine.
*
* HISTORY
*
* 8 Jul 1992 Brian Pinkerton at NeXT
* Created.
*/
#ifndef __LIBSAIO_UFS_BYTEORDER_H
#define __LIBSAIO_UFS_BYTEORDER_H
//#include <sys/vnode.h>
#include <ufs/ffs/fs.h>
#include <sys/buf.h>
#include <sys/disk.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/dir.h>
void byte_swap_ints(unsigned int *array, int count);
void byte_swap_shorts(unsigned short *array, int count);
void byte_swap_longlongs(unsigned long long *array, int count);
void byte_swap_superblock(struct fs *sb);
void byte_swap_dinode_in(struct dinode *di);
void byte_swap_dir_block_in(char *addr, int count);
void byte_swap_inode_in(struct dinode *dc, struct dinode *ic);
#endif /* !__LIBSAIO_UFS_BYTEORDER_H */
branches/rewrite/i386/libsaio/hfs.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 2.0 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
extern long HFSInitPartition(CICell ih);
extern long HFSLoadFile(CICell ih, char * filePath);
extern long HFSReadFile(CICell ih, char * filePath, void *base, uint64_t offset, uint64_t length);
extern long HFSGetDirEntry(CICell ih, char * dirPath, long long * dirIndex,
char ** name, long * flags, long * time,
FinderInfo * finderInfo, long * infoValid);
extern void HFSGetDescription(CICell ih, char *str, long strMaxLen);
extern long HFSGetFileBlock(CICell ih, char *str, unsigned long long *firstBlock);
extern long HFSGetUUID(CICell ih, char *uuidStr);
extern void HFSFree(CICell ih);
extern bool HFSProbe (const void *buf);
branches/rewrite/i386/libsaio/hfs_compare.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
/*
* Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 2.0 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* HFSCompare.c - Functions for working with and comparing HFS nams.
*
* Copyright (c) 1999-2000 Apple Computer, Inc.
*
* DRI: Josh de Cesare
*/
#include <sl.h>
#include "hfs_CaseTables.h"
#if ! UNCOMPRESSED
static unsigned short *
UncompressStructure(struct compressed_block *bp, int count, int size)
{
unsigned short *out = malloc(size);
unsigned short *op = out;
unsigned short data;
int i, j;
for (i=0; i<count; i++, bp++) {
// If this happens (it shouldn't) please fix size and/or double check that count really is
// the number of elements in the array.
// This was a very hard bug to find, so please leave this code here.
if(out + size <= op + bp->count)
{
stop("HFS+ Unicode tables are malformed\n");
}
data = bp->data;
for (j=0; j<bp->count; j++) {
*op++ = data;
if (bp->type == kTypeAscending) data++;
else if (bp->type == kTypeAscending256) data += 256;
}
}
return out;
}
static void
InitCompareTables(void)
{
if (gCompareTable == 0) {
gCompareTable = UncompressStructure(gCompareTableCompressed,
kCompareTableNBlocks, kCompareTableDataSize);
gLowerCaseTable = UncompressStructure(gLowerCaseTableCompressed,
kLowerCaseTableNBlocks, kLowerCaseTableDataSize);
}
}
#endif /* ! UNCOMPRESSED */
//_______________________________________________________________________
//
//Routine:FastRelString
//
//Output:returns -1 if str1 < str2
//returns 1 if str1 > str2
//return 0 if equal
//
//_______________________________________________________________________
int32_tFastRelString(u_int8_t * str1, u_int8_t * str2)
{
int32_t bestGuess;
u_int8_t length, length2;
#if ! UNCOMPRESED
InitCompareTables();
#endif
length = *(str1++);
length2 = *(str2++);
if (length == length2)
bestGuess = 0;
else if (length < length2)
bestGuess = -1;
else
{
bestGuess = 1;
length = length2;
}
while (length--)
{
u_int32_t aChar, bChar;
aChar = *(str1++);
bChar = *(str2++);
if (aChar != bChar)/* If they don't match exacly, do case conversion */
{
u_int16_t aSortWord, bSortWord;
aSortWord = gCompareTable[aChar];
bSortWord = gCompareTable[bChar];
if (aSortWord > bSortWord)
return 1;
if (aSortWord < bSortWord)
return -1;
}
/*
* If characters match exactly, then go on to next character
* immediately without doing any extra work.
*/
}
/* if you got to here, then return bestGuess */
return bestGuess;
}
//
//FastUnicodeCompare - Compare two Unicode strings; produce a relative ordering
//
// IFRESULT
//--------------------------
//str1 < str2=>-1
//str1 = str2=> 0
//str1 > str2=>+1
//
//The lower case table starts with 256 entries (one for each of the upper bytes
//of the original Unicode char). If that entry is zero, then all characters with
//that upper byte are already case folded. If the entry is non-zero, then it is
//the _index_ (not byte offset) of the start of the sub-table for the characters
//with that upper byte. All ignorable characters are folded to the value zero.
//
//In pseudocode:
//
//Let c = source Unicode character
//Let table[] = lower case table
//
//lower = table[highbyte(c)]
//if (lower == 0)
//lower = c
//else
//lower = table[lower+lowbyte(c)]
//
//if (lower == 0)
//ignore this character
//
//To handle ignorable characters, we now need a loop to find the next valid character.
//Also, we can't pre-compute the number of characters to compare; the string length might
//be larger than the number of non-ignorable characters. Further, we must be able to handle
//ignorable characters at any point in the string, including as the first or last characters.
//We use a zero value as a sentinel to detect both end-of-string and ignorable characters.
//Since the File Manager doesn't prevent the NUL character (value zero) as part of a filename,
//the case mapping table is assumed to map u+0000 to some non-zero value (like 0xFFFF, which is
//an invalid Unicode character).
//
//Pseudocode:
//
//while (1) {
//c1 = GetNextValidChar(str1)//returns zero if at end of string
//c2 = GetNextValidChar(str2)
//
//if (c1 != c2) break//found a difference
//
//if (c1 == 0)//reached end of string on both strings at once?
//return 0;//yes, so strings are equal
//}
//
//// When we get here, c1 != c2. So, we just need to determine which one is less.
//if (c1 < c2)
//return -1;
//else
//return 1;
//
int32_t FastUnicodeCompare( u_int16_t * str1, register u_int32_t length1,
u_int16_t * str2, register u_int32_t length2, int byte_order )
{
register u_int16_t c1,c2;
register u_int16_t temp;
#if ! UNCOMPRESSED
InitCompareTables();
#endif
while (1) {
/* Set default values for c1, c2 in case there are no more valid chars */
c1 = 0;
c2 = 0;
/* Find next non-ignorable char from str1, or zero if no more */
while (length1 && c1 == 0) {
if (byte_order == OSBigEndian)
c1 = SWAP_BE16(*(str1++));
else
c1 = SWAP_LE16(*(str1++));
--length1;
if ((temp = gLowerCaseTable[c1>>8]) != 0)// is there a subtable for this upper byte?
c1 = gLowerCaseTable[temp + (c1 & 0x00FF)];// yes, so fold the char
}
/* Find next non-ignorable char from str2, or zero if no more */
while (length2 && c2 == 0) {
if (byte_order == OSBigEndian)
c2 = SWAP_BE16(*(str2++));
else
c2 = SWAP_LE16(*(str2++));
--length2;
if ((temp = gLowerCaseTable[c2>>8]) != 0)// is there a subtable for this upper byte?
c2 = gLowerCaseTable[temp + (c2 & 0x00FF)];// yes, so fold the char
}
if (c1 != c2)/* found a difference, so stop looping */
break;
if (c1 == 0)/* did we reach the end of both strings at the same time? */
return 0;/* yes, so strings are equal */
}
if (c1 < c2)
return -1;
else
return 1;
}
//
// BinaryUnicodeCompare - Compare two Unicode strings; produce a relative ordering
// Compared using a 16-bit binary comparison (no case folding)
//
int32_t BinaryUnicodeCompare (u_int16_t * str1, u_int32_t length1,
u_int16_t * str2, u_int32_t length2)
{
register u_int16_t c1, c2;
int32_t bestGuess;
u_int32_t length;
bestGuess = 0;
if (length1 < length2) {
length = length1;
--bestGuess;
} else if (length1 > length2) {
length = length2;
++bestGuess;
} else {
length = length1;
}
while (length--) {
c1 = *(str1++);
c2 = *(str2++);
if (c1 > c2)
return (1);
if (c1 < c2)
return (-1);
}
return (bestGuess);
}
/*
* UTF-8 (UCS Transformation Format)
*
* The following subset of UTF-8 is used to encode UCS-2 filenames. It
* requires a maximum of three 3 bytes per UCS-2 character. Only the
* shortest encoding required to represent the significant UCS-2 bits
* is legal.
*
* UTF-8 Multibyte Codes
*
* Bytes Bits UCS-2 Min UCS-2 Max UTF-8 Byte Sequence (binary)
* -------------------------------------------------------------------
* 1 7 0x0000 0x007F 0xxxxxxx
* 2 11 0x0080 0x07FF 110xxxxx 10xxxxxx
* 3 16 0x0800 0xFFFF 1110xxxx 10xxxxxx 10xxxxxx
* -------------------------------------------------------------------
*/
/*
* utf_encodestr - Encodes the UCS-2 (Unicode) string at ucsp into a
* null terminated UTF-8 string at utf8p.
*
* ucslen is the number of UCS-2 input characters (not bytes)
* bufsize is the size of the output buffer in bytes
*/
void
utf_encodestr( const u_int16_t * ucsp, int ucslen,
u_int8_t * utf8p, u_int32_t bufsize, int byte_order )
{
u_int8_t *bufend;
u_int16_t ucs_ch;
bufend = utf8p + bufsize;
while (ucslen-- > 0) {
if (byte_order == OSBigEndian)
ucs_ch = SWAP_BE16(*ucsp++);
else
ucs_ch = SWAP_LE16(*ucsp++);
if (ucs_ch < 0x0080) {
if (utf8p >= bufend)
break;
if (ucs_ch == '\0')
continue;/* skip over embedded NULLs */
*utf8p++ = ucs_ch;
} else if (ucs_ch < 0x800) {
if ((utf8p + 1) >= bufend)
break;
*utf8p++ = (ucs_ch >> 6) | 0xc0;
*utf8p++ = (ucs_ch & 0x3f) | 0x80;
} else {
if ((utf8p + 2) >= bufend)
break;
*utf8p++ = (ucs_ch >> 12) | 0xe0;
*utf8p++ = ((ucs_ch >> 6) & 0x3f) | 0x80;
*utf8p++ = ((ucs_ch) & 0x3f) | 0x80;
}
}
*utf8p = '\0';
}
/*
* utf_decodestr - Decodes the null terminated UTF-8 string at
* utf8p into a UCS-2 (Unicode) string at ucsp.
*
* ucslen is the number of UCS-2 output characters (not bytes)
* bufsize is the size of the output buffer in bytes
*/
void utf_decodestr(const u_int8_t * utf8p, u_int16_t * ucsp, u_int16_t * ucslen, u_int32_t bufsize, int byte_order)
{
u_int16_t *bufstart;
u_int16_t *bufend;
u_int16_t ucs_ch;
u_int8_t byte;
bufstart = ucsp;
bufend = (u_int16_t *)((u_int8_t *)ucsp + bufsize);
while ((byte = *utf8p++) != '\0') {
if (ucsp >= bufend)
break;
/* check for ascii */
if (byte < 0x80) {
ucs_ch = byte;
if (byte_order == OSBigEndian)
*ucsp++ = SWAP_BE16(ucs_ch);
else
*ucsp++ = SWAP_LE16(ucs_ch);
continue;
}
switch (byte & 0xf0) {
/* 2 byte sequence*/
case 0xc0:
case 0xd0:
/* extract bits 6 - 10 from first byte */
ucs_ch = (byte & 0x1F) << 6;
break;
/* 3 byte sequence*/
case 0xe0:
/* extract bits 12 - 15 from first byte */
ucs_ch = (byte & 0x0F) << 6;
/* extract bits 6 - 11 from second byte */
if (((byte = *utf8p++) & 0xc0) != 0x80)
goto stop;
ucs_ch += (byte & 0x3F);
ucs_ch <<= 6;
break;
default:
goto stop;
}
/* extract bits 0 - 5 from final byte */
if (((byte = *utf8p++) & 0xc0) != 0x80)
goto stop;
ucs_ch += (byte & 0x3F);
if (byte_order == OSBigEndian)
*ucsp++ = SWAP_BE16(ucs_ch);
else
*ucsp++ = SWAP_LE16(ucs_ch);
}
stop:
if (byte_order == OSBigEndian)
*ucslen = SWAP_BE16(ucsp - bufstart);
else
*ucslen = SWAP_LE16(ucsp - bufstart);
}
branches/rewrite/i386/libsaio/disk.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
/*
* Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
* Reserved. This file contains Original Code and/or Modifications of
* Original Code as defined in and that are subject to the Apple Public
* Source License Version 2.0 (the "License"). You may not use this file
* except in compliance with the License. Please obtain a copy of the
* License at http://www.apple.com/publicsource and read it before using
* this file.
*
* The Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* Mach Operating System
* Copyright (c) 1990 Carnegie-Mellon University
* Copyright (c) 1989 Carnegie-Mellon University
* All rights reserved. The CMU software License Agreement specifies
* the terms and conditions for use and redistribution.
*/
/*
* INTEL CORPORATION PROPRIETARY INFORMATION
*
* This software is supplied under the terms of a license agreement or
* nondisclosure agreement with Intel Corporation and may not be copied
* nor disclosed except in accordance with the terms of that agreement.
*
* Copyright 1988, 1989 Intel Corporation
*/
/*
* Copyright 1993 NeXT Computer, Inc.
* All rights reserved.
*/
/*
* Copyright 2007 VMware Inc.
* "Preboot" ramdisk support added by David Elliott
* GPT support added by David Elliott. Based on IOGUIDPartitionScheme.cpp.
*/
//Azi: style the rest later...
// Allow UFS_SUPPORT to be overridden with preprocessor option.
#ifndef UFS_SUPPORT
// zef: Disabled UFS support
#define UFS_SUPPORT 0
#endif
#if UFS_SUPPORT
#include "ufs.h"
#endif
#include <limits.h>
#include <IOKit/storage/IOApplePartitionScheme.h>
#include <IOKit/storage/IOGUIDPartitionScheme.h>
#include "libsaio.h"
#include "boot.h"
#include "memory.h"
#include "fdisk.h"
#include "hfs.h"
#include "ntfs.h"
#include "msdos.h"
#include "ext2fs.h"
#include "xml.h"
#include "disk.h"
// For EFI_GUID
#include "efi.h"
#include "efi_tables.h"
typedef struct gpt_hdr gpt_hdr;
typedef struct gpt_ent gpt_ent;
#define PROBEFS_SIZE BPS * 4 /* buffer size for filesystem probe */
#define CD_BPS 2048 /* CD-ROM block size */
#define N_CACHE_SECS (BIOS_LEN / BPS) /* Must be a multiple of 4 for CD-ROMs */
#define UFS_FRONT_PORCH 0
#define kAPMSector 2 /* Sector number of Apple partition map */
#define kAPMCDSector 8 /* Translated sector of Apple partition map on a CD */
/*
* IORound and IOTrunc convenience functions, in the spirit
* of vm's round_page() and trunc_page().
*/
#define IORound(value,multiple) \
((((value) + (multiple) - 1) / (multiple)) * (multiple))
#define IOTrunc(value,multiple) \
(((value) / (multiple)) * (multiple));
/*
* trackbuf points to the start of the track cache. Biosread()
* will store the sectors read from disk to this memory area.
*
* biosbuf points to a sector within the track cache, and is
* updated by Biosread().
*/
static char * const trackbuf = (char *) ptov(BIOS_ADDR);
static char * biosbuf;
/*
* Map a disk drive to bootable volumes contained within.
*/
struct DiskBVMap {
int biosdev; // BIOS device number (unique)
BVRef bvr; // chain of boot volumes on the disk
int bvrcnt; // number of boot volumes
struct DiskBVMap * next; // linkage to next mapping
};
static struct DiskBVMap * gDiskBVMap = NULL;
static struct disk_blk0 * gBootSector = NULL;
// Function pointers to be filled in if ramdisks are available:
int (*p_ramdiskReadBytes)( int biosdev, unsigned int blkno,
unsigned int byteoff,
unsigned int byteCount, void * buffer ) = NULL;
int (*p_get_ramdisk_info)(int biosdev, struct driveInfo *dip) = NULL;
//==========================================================================
static int getDriveInfo( int biosdev, struct driveInfo *dip )
{
static struct driveInfo cached_di;
int cc;
// Real BIOS devices are 8-bit, so anything above that is for internal use.
// Don't cache ramdisk drive info since it doesn't require several BIOS
// calls and is thus not worth it.
if(biosdev >= 0x100)
{
if(p_get_ramdisk_info != NULL)
cc = (*p_get_ramdisk_info)(biosdev, dip);
else
cc = -1;
if(cc < 0)
{
dip->valid = 0;
return -1;
}
else
return 0;
}
if ( !cached_di.valid || biosdev != cached_di.biosdev )
{
cc = get_drive_info(biosdev, &cached_di);
if (cc < 0) {
cached_di.valid = 0;
DEBUG_DISK(("get_drive_info returned error\n"));
return (-1); // BIOS call error
}
}
bcopy(&cached_di, dip, sizeof(cached_di));
return 0;
}
//==========================================================================
// Maps (E)BIOS return codes to message strings.
struct NamedValue {
unsigned char value;
const char * name;
};
static const char * getNameForValue( const struct NamedValue * nameTable,
unsigned char value )
{
const struct NamedValue * np;
for ( np = nameTable; np->value; np++)
if (np->value == value)
return np->name;
return NULL;
}
#define ECC_CORRECTED_ERR 0x11
static const struct NamedValue bios_errors[] = {
{ 0x10, "Media error" },
{ 0x11, "Corrected ECC error" },
{ 0x20, "Controller or device error" },
{ 0x40, "Seek failed" },
{ 0x80, "Device timeout" },
{ 0xAA, "Drive not ready" },
{ 0x00, 0 }
};
static const char * bios_error(int errnum)
{
static char errorstr[] = "Error 0x00";
const char * errname;
errname = getNameForValue( bios_errors, errnum );
if ( errname ) return errname;
sprintf(errorstr, "Error 0x%02x", errnum);
return errorstr; // No string, print error code only
}
//==========================================================================
// Use BIOS INT13 calls to read the sector specified. This function will
// also perform read-ahead to cache a few subsequent sector to the sector
// cache.
//
// Return:
// 0 on success, or an error code from INT13/F2 or INT13/F42 BIOS call.
static bool cache_valid = false;
static int Biosread( int biosdev, unsigned long long secno )
{
static int xbiosdev, xcyl, xhead;
static unsigned int xsec, xnsecs;
struct driveInfo di;
int rc = -1;
int cyl, head, sec;
int tries = 0;
int bps, divisor;
if (getDriveInfo(biosdev, &di) < 0) {
return -1;
}
if (di.no_emulation) {
/* Always assume 2k block size; BIOS may lie about geometry */
bps = 2048;
} else {
bps = di.di.params.phys_nbps;
if (bps == 0) {
return -1;
}
}
divisor = bps / BPS;
DEBUG_DISK(("Biosread dev %x sec %d bps %d\n", biosdev, secno, bps));
// To read the disk sectors, use EBIOS if we can. Otherwise,
// revert to the standard BIOS calls.
if ((biosdev >= kBIOSDevTypeHardDrive) &&
(di.uses_ebios & EBIOS_FIXED_DISK_ACCESS))
{
if (cache_valid &&
(biosdev == xbiosdev) &&
(secno >= xsec) &&
((unsigned int)secno < (xsec + xnsecs)))
{
biosbuf = trackbuf + (BPS * (secno - xsec));
return 0;
}
xnsecs = N_CACHE_SECS;
xsec = (secno / divisor) * divisor;
cache_valid = false;
while ((rc = ebiosread(biosdev, secno / divisor, xnsecs / divisor)) && (++tries < 5))
{
if (rc == ECC_CORRECTED_ERR) {
/* Ignore corrected ECC errors */
rc = 0;
break;
}
error(" EBIOS read error: %s\n", bios_error(rc), rc);
error(" Block 0x%x Sectors %d\n", secno, xnsecs);
sleep(1);
}
}
else
{
/* spc = spt * heads */
int spc = (di.di.params.phys_spt * di.di.params.phys_heads);
cyl = secno / spc;
head = (secno % spc) / di.di.params.phys_spt;
sec = secno % di.di.params.phys_spt;
if (cache_valid &&
(biosdev == xbiosdev) &&
(cyl == xcyl) &&
(head == xhead) &&
((unsigned int)sec >= xsec) &&
((unsigned int)sec < (xsec + xnsecs)))
{
// this sector is in trackbuf cache
biosbuf = trackbuf + (BPS * (sec - xsec));
return 0;
}
// Cache up to a track worth of sectors, but do not cross a
// track boundary.
xcyl = cyl;
xhead = head;
xsec = sec;
xnsecs = ((unsigned int)(sec + N_CACHE_SECS) > di.di.params.phys_spt) ? (di.di.params.phys_spt - sec) : N_CACHE_SECS;
cache_valid = false;
while ((rc = biosread(biosdev, cyl, head, sec, xnsecs)) &&
(++tries < 5))
{
if (rc == ECC_CORRECTED_ERR) {
/* Ignore corrected ECC errors */
rc = 0;
break;
}
error(" BIOS read error: %s\n", bios_error(rc), rc);
error(" Block %d, Cyl %d Head %d Sector %d\n",
secno, cyl, head, sec);
sleep(1);
}
}
// If the BIOS reported success, mark the sector cache as valid.
if (rc == 0) {
cache_valid = true;
}
biosbuf = trackbuf + (secno % divisor) * BPS;
xbiosdev = biosdev;
return rc;
}
//==========================================================================
int testBiosread( int biosdev, unsigned long long secno )
{
return Biosread(biosdev, secno);
}
//==========================================================================
static int readBytes( int biosdev, unsigned long long blkno,
unsigned int byteoff,
unsigned int byteCount, void * buffer )
{
// ramdisks require completely different code for reading.
if(p_ramdiskReadBytes != NULL && biosdev >= 0x100)
return (*p_ramdiskReadBytes)(biosdev, blkno, byteoff, byteCount, buffer);
char * cbuf = (char *) buffer;
int error;
int copy_len;
DEBUG_DISK(("%s: dev %x block %x [%d] -> 0x%x...", __FUNCTION__,
biosdev, blkno, byteCount, (unsigned)cbuf));
for ( ; byteCount; cbuf += copy_len, blkno++ )
{
error = Biosread( biosdev, blkno );
if ( error )
{
DEBUG_DISK(("error\n"));
return (-1);
}
copy_len = ((byteCount + byteoff) > BPS) ? (BPS - byteoff) : byteCount;
bcopy( biosbuf + byteoff, cbuf, copy_len );
byteCount -= copy_len;
byteoff = 0;
}
DEBUG_DISK(("done\n"));
return 0;
}
//==========================================================================
static int isExtendedFDiskPartition( const struct fdisk_part * part )
{
static unsigned char extParts[] =
{
0x05, /* Extended */
0x0f, /* Win95 extended */
0x85, /* Linux extended */
};
unsigned int i;
for (i = 0; i < sizeof(extParts)/sizeof(extParts[0]); i++)
{
if (extParts[i] == part->systid) return 1;
}
return 0;
}
//==========================================================================
static int getNextFDiskPartition( int biosdev, int * partno,
const struct fdisk_part ** outPart )
{
static int sBiosdev = -1;
static int sNextPartNo;
static unsigned int sFirstBase;
static unsigned int sExtBase;
static unsigned int sExtDepth;
static struct fdisk_part * sExtPart;
struct fdisk_part * part;
if ( sBiosdev != biosdev || *partno < 0 )
{
// Fetch MBR.
if ( readBootSector( biosdev, DISK_BLK0, 0 ) ) return 0;
sBiosdev = biosdev;
sNextPartNo = 0;
sFirstBase = 0;
sExtBase = 0;
sExtDepth = 0;
sExtPart = NULL;
}
while (1)
{
part = NULL;
if ( sNextPartNo < FDISK_NPART )
{
part = (struct fdisk_part *) gBootSector->parts[sNextPartNo];
}
else if ( sExtPart )
{
unsigned int blkno = sExtPart->relsect + sFirstBase;
// Save the block offset of the first extended partition.
if (sExtDepth == 0) {
sFirstBase = blkno;
}
sExtBase = blkno;
// Load extended partition table.
if ( readBootSector( biosdev, blkno, 0 ) == 0 )
{
sNextPartNo = 0;
sExtDepth++;
sExtPart = NULL;
continue;
}
// Fall through to part == NULL
}
if ( part == NULL ) break; // Reached end of partition chain.
// Advance to next partition number.
sNextPartNo++;
if ( isExtendedFDiskPartition(part) )
{
sExtPart = part;
continue;
}
// Skip empty slots.
if ( part->systid == 0x00 )
{
continue;
}
// Change relative offset to an absolute offset.
part->relsect += sExtBase;
*outPart = part;
*partno = sExtDepth ? (int)(sExtDepth + FDISK_NPART) : sNextPartNo;
break;
}
return (part != NULL);
}
//==========================================================================
static BVRef newFDiskBVRef( int biosdev, int partno, unsigned int blkoff,
const struct fdisk_part * part,
FSInit initFunc, FSLoadFile loadFunc,
FSReadFile readFunc,
FSGetDirEntry getdirFunc,
FSGetFileBlock getBlockFunc,
FSGetUUID getUUIDFunc,
BVGetDescription getDescriptionFunc,
BVFree bvFreeFunc,
int probe, int type, unsigned int bvrFlags )
{
BVRef bvr = (BVRef) malloc( sizeof(*bvr) );
if ( bvr )
{
bzero(bvr, sizeof(*bvr));
bvr->biosdev = biosdev;
bvr->part_no = partno;
bvr->part_boff = blkoff;
bvr->part_type = part->systid;
bvr->fs_loadfile = loadFunc;
bvr->fs_readfile = readFunc;
bvr->fs_getdirentry = getdirFunc;
bvr->fs_getfileblock= getBlockFunc;
bvr->fs_getuuid = getUUIDFunc;
bvr->description = getDescriptionFunc;
bvr->type = type;
bvr->bv_free = bvFreeFunc;
if ((part->bootid & FDISK_ACTIVE) && (part->systid == FDISK_HFS))
bvr->flags |= kBVFlagPrimary;
// Probe the filesystem.
if ( initFunc )
{
bvr->flags |= kBVFlagNativeBoot;
if ( probe && initFunc( bvr ) != 0 )
{
// filesystem probe failed.
DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
__FUNCTION__, biosdev, partno));
(*bvr->bv_free)(bvr);
bvr = NULL;
}
if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
{
bvr->flags |= kBVFlagBootable;
}
}
else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
{
bvr->flags |= kBVFlagForeignBoot;
}
else
{
(*bvr->bv_free)(bvr);
bvr = NULL;
}
}
if (bvr) bvr->flags |= bvrFlags;
return bvr;
}
//==========================================================================
BVRef newAPMBVRef( int biosdev, int partno, unsigned int blkoff,
const DPME * part,
FSInit initFunc, FSLoadFile loadFunc,
FSReadFile readFunc,
FSGetDirEntry getdirFunc,
FSGetFileBlock getBlockFunc,
FSGetUUID getUUIDFunc,
BVGetDescription getDescriptionFunc,
BVFree bvFreeFunc,
int probe, int type, unsigned int bvrFlags )
{
BVRef bvr = (BVRef) malloc( sizeof(*bvr) );
if ( bvr )
{
bzero(bvr, sizeof(*bvr));
bvr->biosdev = biosdev;
bvr->part_no = partno;
bvr->part_boff = blkoff;
bvr->fs_loadfile = loadFunc;
bvr->fs_readfile = readFunc;
bvr->fs_getdirentry = getdirFunc;
bvr->fs_getfileblock= getBlockFunc;
bvr->fs_getuuid = getUUIDFunc;
bvr->description = getDescriptionFunc;
bvr->type = type;
bvr->bv_free = bvFreeFunc;
strlcpy(bvr->name, part->dpme_name, DPISTRLEN);
strlcpy(bvr->type_name, part->dpme_type, DPISTRLEN);
/*
if ( part->bootid & FDISK_ACTIVE )
bvr->flags |= kBVFlagPrimary;
*/
// Probe the filesystem.
if ( initFunc )
{
bvr->flags |= kBVFlagNativeBoot | kBVFlagBootable | kBVFlagSystemVolume;
if ( probe && initFunc( bvr ) != 0 )
{
// filesystem probe failed.
DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
__FUNCTION__, biosdev, partno));
(*bvr->bv_free)(bvr);
bvr = NULL;
}
}
/*
else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
{
bvr->flags |= kBVFlagForeignBoot;
}
*/
else
{
(*bvr->bv_free)(bvr);
bvr = NULL;
}
}
if (bvr) bvr->flags |= bvrFlags;
return bvr;
}
//==========================================================================
// GUID's in LE form:
// HFS+ partition - 48465300-0000-11AA-AA11-00306543ECAC
EFI_GUID const GPT_HFS_GUID = { 0x48465300, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };
// turbo - Apple Boot Partition - 426F6F74-0000-11AA-AA11-00306543ECAC
EFI_GUID const GPT_BOOT_GUID = { 0x426F6F74, 0x0000, 0x11AA, { 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC } };
// turbo - or an EFI System Partition - C12A7328-F81F-11D2-BA4B-00A0C93EC93B
EFI_GUID const GPT_EFISYS_GUID = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B } };
// zef - Basic Data Partition - EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 for foreign OS support
EFI_GUID const GPT_BASICDATA_GUID = { 0xEBD0A0A2, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 } };
// Microsoft Reserved Partition - E3C9E316-0B5C-4DB8-817DF92DF00215AE
EFI_GUID const GPT_BASICDATA2_GUID = { 0xE3C9E316, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE } };
BVRef newGPTBVRef( int biosdev, int partno, unsigned int blkoff,
const gpt_ent * part,
FSInit initFunc, FSLoadFile loadFunc,
FSReadFile readFunc,
FSGetDirEntry getdirFunc,
FSGetFileBlock getBlockFunc,
FSGetUUID getUUIDFunc,
BVGetDescription getDescriptionFunc,
BVFree bvFreeFunc,
int probe, int type, unsigned int bvrFlags )
{
BVRef bvr = (BVRef) malloc( sizeof(*bvr) );
if ( bvr )
{
bzero(bvr, sizeof(*bvr));
bvr->biosdev = biosdev;
bvr->part_no = partno;
bvr->part_boff = blkoff;
bvr->fs_loadfile = loadFunc;
bvr->fs_readfile = readFunc;
bvr->fs_getdirentry = getdirFunc;
bvr->fs_getfileblock= getBlockFunc;
bvr->fs_getuuid = getUUIDFunc;
bvr->description = getDescriptionFunc;
bvr->type = type;
bvr->bv_free = bvFreeFunc;
// FIXME: UCS-2 -> UTF-8 the name
strlcpy(bvr->name, "----", DPISTRLEN);
if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)part->ent_type) == 0) ||
(efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)part->ent_type) == 0) )
strlcpy(bvr->type_name, "GPT HFS+", DPISTRLEN);
else
strlcpy(bvr->type_name, "GPT Unknown", DPISTRLEN);
/*
if ( part->bootid & FDISK_ACTIVE )
bvr->flags |= kBVFlagPrimary;
*/
// Probe the filesystem.
if ( initFunc )
{
bvr->flags |= kBVFlagNativeBoot;
if ( probe && initFunc( bvr ) != 0 )
{
// filesystem probe failed.
DEBUG_DISK(("%s: failed probe on dev %x part %d\n",
__FUNCTION__, biosdev, partno));
(*bvr->bv_free)(bvr);
bvr = NULL;
}
if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
{
bvr->flags |= kBVFlagBootable;
}
}
else if ( readBootSector( biosdev, blkoff, (void *)0x7e00 ) == 0 )
{
bvr->flags |= kBVFlagForeignBoot;
}
else
{
(*bvr->bv_free)(bvr);
bvr = NULL;
}
}
if (bvr) bvr->flags |= bvrFlags;
return bvr;
}
//==========================================================================
/* A note on partition numbers:
* IOKit makes the primary partitions numbers 1-4, and then
* extended partitions are numbered consecutively 5 and up.
* So, for example, if you have two primary partitions and
* one extended partition they will be numbered 1, 2, 5.
*/
static BVRef diskScanFDiskBootVolumes( int biosdev, int * countPtr )
{
const struct fdisk_part * part;
struct DiskBVMap * map;
int partno = -1;
BVRef bvr;
#if UFS_SUPPORT
BVRef booterUFS = NULL;
#endif
int spc;
struct driveInfo di;
boot_drive_info_t *dp;
/* Initialize disk info */
if (getDriveInfo(biosdev, &di) != 0) {
return NULL;
}
dp = &di.di;
spc = (dp->params.phys_spt * dp->params.phys_heads);
if (spc == 0) {
/* This is probably a CD-ROM; punt on the geometry. */
spc = 1;
}
do {
// Create a new mapping.
map = (struct DiskBVMap *) malloc( sizeof(*map) );
if ( map )
{
map->biosdev = biosdev;
map->bvr = NULL;
map->bvrcnt = 0;
map->next = gDiskBVMap;
gDiskBVMap = map;
// Create a record for each partition found on the disk.
while ( getNextFDiskPartition( biosdev, &partno, &part ) )
{
DEBUG_DISK(("%s: part %d [%x]\n", __FUNCTION__,
partno, part->systid));
bvr = 0;
switch ( part->systid )
{
#if UFS_SUPPORT
case FDISK_UFS:
bvr = newFDiskBVRef(
biosdev, partno,
part->relsect + UFS_FRONT_PORCH/BPS,
part,
UFSInitPartition,
UFSLoadFile,
UFSReadFile,
UFSGetDirEntry,
UFSGetFileBlock,
UFSGetUUID,
UFSGetDescription,
UFSFree,
0,
kBIOSDevTypeHardDrive, 0);
break;
#endif
case FDISK_HFS:
bvr = newFDiskBVRef(
biosdev, partno,
part->relsect,
part,
HFSInitPartition,
HFSLoadFile,
HFSReadFile,
HFSGetDirEntry,
HFSGetFileBlock,
HFSGetUUID,
HFSGetDescription,
HFSFree,
0,
kBIOSDevTypeHardDrive, 0);
break;
// turbo - we want the booter type scanned also
case FDISK_BOOTER:
if (part->bootid & FDISK_ACTIVE)
gBIOSBootVolume = newFDiskBVRef(
biosdev, partno,
part->relsect,
part,
HFSInitPartition,
HFSLoadFile,
HFSReadFile,
HFSGetDirEntry,
HFSGetFileBlock,
HFSGetUUID,
HFSGetDescription,
HFSFree,
0,
kBIOSDevTypeHardDrive, 0);
break;
#if UFS_SUPPORT
case FDISK_BOOTER:
booterUFS = newFDiskBVRef(
biosdev, partno,
((part->relsect + spc - 1) / spc) * spc,
part,
UFSInitPartition,
UFSLoadFile,
UFSReadFile,
UFSGetDirEntry,
UFSGetFileBlock,
UFSGetUUID,
UFSGetDescription,
UFSFree,
0,
kBIOSDevTypeHardDrive, 0);
break;
#endif
case FDISK_FAT32:
case FDISK_DOS12:
case FDISK_DOS16S:
case FDISK_DOS16B:
case FDISK_SMALLFAT32:
case FDISK_DOS16SLBA:
bvr = newFDiskBVRef(
biosdev, partno,
part->relsect,
part,
MSDOSInitPartition,
MSDOSLoadFile,
MSDOSReadFile,
MSDOSGetDirEntry,
MSDOSGetFileBlock,
MSDOSGetUUID,
MSDOSGetDescription,
MSDOSFree,
0,
kBIOSDevTypeHardDrive, 0);
break;
case FDISK_NTFS:
bvr = newFDiskBVRef(
biosdev, partno,
part->relsect,
part,
0, 0, 0, 0, 0,
NTFSGetUUID,
NTFSGetDescription,
(BVFree)free,
0, kBIOSDevTypeHardDrive, 0);
break;
case FDISK_LINUX:
bvr = newFDiskBVRef(
biosdev, partno,
part->relsect,
part,
0, 0, 0, 0, 0, 0,
EX2GetDescription,
(BVFree)free,
0, kBIOSDevTypeHardDrive, 0);
break;
default:
bvr = newFDiskBVRef(
biosdev, partno,
part->relsect,
part,
0, 0, 0, 0, 0, 0, 0,
(BVFree)free,
0,
kBIOSDevTypeHardDrive, 0);
break;
}
if ( bvr )
{
bvr->next = map->bvr;
map->bvr = bvr;
map->bvrcnt++;
}
}
#if UFS_SUPPORT
// Booting from a CD with an UFS filesystem embedded
// in a booter partition.
if ( booterUFS )
{
if ( map->bvrcnt == 0 )
{
map->bvr = booterUFS;
map->bvrcnt++;
}
else free( booterUFS );
}
#endif
}
} while (0);
/*
* If no FDisk partition, then we will check for
* an Apple partition map elsewhere.
*/
#if UNUSED
if (map->bvrcnt == 0) {
static struct fdisk_part cdpart;
cdpart.systid = 0xCD;
/* Let's try assuming we are on a hybrid HFS/ISO9660 CD. */
bvr = newFDiskBVRef(
biosdev, 0,
0,
&cdpart,
HFSInitPartition,
HFSLoadFile,
HFSReadFile,
HFSGetDirEntry,
HFSGetFileBlock,
HFSGetUUID,
0,
kBIOSDevTypeHardDrive);
bvr->next = map->bvr;
map->bvr = bvr;
map->bvrcnt++;
}
#endif
// Actually this should always be true given the above code
if(map == gDiskBVMap)
{
// Don't leave a null map in the chain
if(map->bvrcnt == 0 && map->bvr == NULL)
{
gDiskBVMap = map->next;
free(map);
map = NULL;
}
}
if (countPtr) *countPtr = map ? map->bvrcnt : 0;
return map ? map->bvr : NULL;
}
//==========================================================================
static BVRef diskScanAPMBootVolumes( int biosdev, int * countPtr )
{
struct DiskBVMap * map;
struct Block0 *block0_p;
unsigned int blksize;
unsigned int factor;
void *buffer = malloc(BPS);
/* Check for alternate block size */
if (readBytes( biosdev, 0, 0, BPS, buffer ) != 0) {
return NULL;
}
block0_p = buffer;
if (OSSwapBigToHostInt16(block0_p->sbSig) == BLOCK0_SIGNATURE) {
blksize = OSSwapBigToHostInt16(block0_p->sbBlkSize);
if (blksize != BPS) {
free(buffer);
buffer = malloc(blksize);
}
factor = blksize / BPS;
} else {
blksize = BPS;
factor = 1;
}
do {
// Create a new mapping.
map = (struct DiskBVMap *) malloc( sizeof(*map) );
if ( map )
{
int error;
DPME *dpme_p = (DPME *)buffer;
UInt32 i, npart = UINT_MAX;
BVRef bvr;
map->biosdev = biosdev;
map->bvr = NULL;
map->bvrcnt = 0;
map->next = gDiskBVMap;
gDiskBVMap = map;
for (i=0; i<npart; i++) {
error = readBytes( biosdev, (kAPMSector + i) * factor, 0, blksize, buffer );
if (error || OSSwapBigToHostInt16(dpme_p->dpme_signature) != DPME_SIGNATURE) {
break;
}
if (i==0) {
npart = OSSwapBigToHostInt32(dpme_p->dpme_map_entries);
}
/*
printf("name = %s, %s%s %d -> %d [%d -> %d] {%d}\n",
dpme.dpme_name, dpme.dpme_type, (dpme.dpme_flags & DPME_FLAGS_BOOTABLE) ? "(bootable)" : "",
dpme.dpme_pblock_start, dpme.dpme_pblocks,
dpme.dpme_lblock_start, dpme.dpme_lblocks,
dpme.dpme_boot_block);
*/
if (strcmp(dpme_p->dpme_type, "Apple_HFS") == 0) {
bvr = newAPMBVRef(biosdev,
i,
OSSwapBigToHostInt32(dpme_p->dpme_pblock_start) * factor,
dpme_p,
HFSInitPartition,
HFSLoadFile,
HFSReadFile,
HFSGetDirEntry,
HFSGetFileBlock,
HFSGetUUID,
HFSGetDescription,
HFSFree,
0,
kBIOSDevTypeHardDrive, 0);
bvr->next = map->bvr;
map->bvr = bvr;
map->bvrcnt++;
}
}
}
} while (0);
free(buffer);
if (countPtr) *countPtr = map ? map->bvrcnt : 0;
return map ? map->bvr : NULL;
}
//==========================================================================
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*
* Trying to figure out the filsystem type of a given partition.
*/
static int probeFileSystem(int biosdev, unsigned int blkoff)
{
// detected filesystem type;
int result = -1;
int fatbits;
// Allocating buffer for 4 sectors.
const void * probeBuffer = malloc(PROBEFS_SIZE);
if (probeBuffer == NULL)
goto exit;
// Reading first 4 sectors of current partition
int error = readBytes(biosdev, blkoff, 0, PROBEFS_SIZE, (void *)probeBuffer);
if (error)
goto exit;
if (HFSProbe(probeBuffer))
result = FDISK_HFS;
else if (EX2Probe(probeBuffer))
result = FDISK_LINUX;
else if (NTFSProbe(probeBuffer))
result = FDISK_NTFS;
else if (fatbits=MSDOSProbe(probeBuffer))
{
switch (fatbits)
{
case 32:
default:
result = FDISK_FAT32;
break;
case 16:
result = FDISK_DOS16B;
break;
case 12:
result = FDISK_DOS12;
break;
}
}
else
// Couldn't detect filesystem type
result = 0;
exit:
if (probeBuffer != NULL) free((void *)probeBuffer);
return result;
}
static bool isPartitionUsed(gpt_ent * partition)
{
//
// Ask whether the given partition is used.
//
return efi_guid_is_null((EFI_GUID const*)partition->ent_type) ? false : true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static BVRef diskScanGPTBootVolumes( int biosdev, int * countPtr )
{
struct DiskBVMap * map = NULL;
void *buffer = malloc(BPS);
int error;
if ( error = readBytes( biosdev, /*secno*/0, 0, BPS, buffer ) != 0) {
verbose("Failed to read boot sector from BIOS device %02xh. Error=%d\n", biosdev, error);
goto scanErr;
}
struct REAL_disk_blk0 *fdiskMap = buffer;
if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )
{
verbose("Failed to find boot signature on BIOS device %02xh\n", biosdev);
goto scanErr;
}
int fdiskID = 0;
unsigned index;
for ( index = 0; index < FDISK_NPART; index++ )
{
if ( fdiskMap->parts[index].systid )
{
if ( fdiskMap->parts[index].systid == 0xEE )
{
// Fail if two 0xEE partitions are present which
// means the FDISK code will wind up parsing it.
if ( fdiskID ) goto scanErr;
fdiskID = index + 1;
}
}
}
if ( fdiskID == 0 ) goto scanErr;
verbose("Attempting to read GPT\n");
if(readBytes(biosdev, 1, 0, BPS, buffer) != 0)
goto scanErr;
gpt_hdr *headerMap = buffer;
// Determine whether the partition header signature is present.
if ( memcmp(headerMap->hdr_sig, GPT_HDR_SIG, strlen(GPT_HDR_SIG)) )
{
goto scanErr;
}
// Determine whether the partition header size is valid.
UInt32 headerCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_self);
UInt32 headerSize = OSSwapLittleToHostInt32(headerMap->hdr_size);
if ( headerSize < offsetof(gpt_hdr, padding) )
{
goto scanErr;
}
if ( headerSize > BPS )
{
goto scanErr;
}
// Determine whether the partition header checksum is valid.
headerMap->hdr_crc_self = 0;
if ( crc32(0, headerMap, headerSize) != headerCheck )
{
goto scanErr;
}
// Determine whether the partition entry size is valid.
UInt64 gptBlock = 0;
UInt32 gptCheck = 0;
UInt32 gptCount = 0;
UInt32 gptID = 0;
gpt_ent * gptMap = 0;
UInt32 gptSize = 0;
gptBlock = OSSwapLittleToHostInt64(headerMap->hdr_lba_table);
gptCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_table);
gptCount = OSSwapLittleToHostInt32(headerMap->hdr_entries);
gptSize = OSSwapLittleToHostInt32(headerMap->hdr_entsz);
if ( gptSize < sizeof(gpt_ent) )
{
goto scanErr;
}
// Allocate a buffer large enough to hold one map, rounded to a media block.
free(buffer);
buffer = NULL;
UInt32 bufferSize = IORound(gptCount * gptSize, BPS);
if(bufferSize == 0)
goto scanErr;
buffer = malloc(bufferSize);
if(readBytes(biosdev, gptBlock, 0, bufferSize, buffer) != 0)
goto scanErr;
verbose("Read GPT\n");
// Allocate a new map for this BIOS device and insert it into the chain
map = malloc(sizeof(*map));
map->biosdev = biosdev;
map->bvr = NULL;
map->bvrcnt = 0;
map->next = gDiskBVMap;
gDiskBVMap = map;
// fdisk like partition type id.
int fsType = 0;
for(gptID = 1; gptID <= gptCount; ++gptID)
{
BVRef bvr = NULL;
unsigned int bvrFlags = 0;
// size on disk can be larger than sizeof(gpt_ent)
gptMap = (gpt_ent *) ( buffer + ( (gptID - 1) * gptSize) );
// NOTE: EFI_GUID's are in LE and we know we're on an x86.
// The IOGUIDPartitionScheme.cpp code uses byte-based UUIDs, we don't.
if (isPartitionUsed(gptMap))
{
char stringuuid[100];
efi_guid_unparse_upper((EFI_GUID*)gptMap->ent_type, stringuuid);
verbose("Reading GPT partition %d, type %s\n", gptID, stringuuid);
// Getting fdisk like partition type.
fsType = probeFileSystem(biosdev, gptMap->ent_lba_start);
if ( (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
(efi_guid_compare(&GPT_HFS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
{
bvrFlags = (efi_guid_compare(&GPT_BOOT_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ? kBVFlagBooter : 0;
bvr = newGPTBVRef(biosdev,
gptID,
gptMap->ent_lba_start,
gptMap,
HFSInitPartition,
HFSLoadFile,
HFSReadFile,
HFSGetDirEntry,
HFSGetFileBlock,
HFSGetUUID,
HFSGetDescription,
HFSFree,
0,
kBIOSDevTypeHardDrive, bvrFlags);
}
// zef - foreign OS support
if ( (efi_guid_compare(&GPT_BASICDATA_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) ||
(efi_guid_compare(&GPT_BASICDATA2_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
{
switch (fsType)
{
case FDISK_NTFS:
bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
0, 0, 0, 0, 0, 0, NTFSGetDescription,
(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
break;
default:
bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
0, 0, 0, 0, 0, 0, 0,
(BVFree)free, 0, kBIOSDevTypeHardDrive, 0);
break;
}
}
// turbo - save our booter partition
// zef - only on original boot device
if ( (efi_guid_compare(&GPT_EFISYS_GUID, (EFI_GUID const*)gptMap->ent_type) == 0) )
{
switch (fsType)
{
case FDISK_HFS:
if (readBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
{
bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
HFSInitPartition,
HFSLoadFile,
HFSReadFile,
HFSGetDirEntry,
HFSGetFileBlock,
HFSGetUUID,
HFSGetDescription,
HFSFree,
0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
}
break;
case FDISK_FAT32:
if (testFAT32EFIBootSector( biosdev, gptMap->ent_lba_start, (void *)0x7e00 ) == 0)
{
bvr = newGPTBVRef(biosdev, gptID, gptMap->ent_lba_start, gptMap,
MSDOSInitPartition,
MSDOSLoadFile,
MSDOSReadFile,
MSDOSGetDirEntry,
MSDOSGetFileBlock,
MSDOSGetUUID,
MSDOSGetDescription,
MSDOSFree,
0, kBIOSDevTypeHardDrive, kBVFlagEFISystem);
}
break;
if (biosdev == gBIOSDev)
gBIOSBootVolume = bvr;
}
}
if (bvr)
{
// Fixup bvr with the fake fdisk partition type.
if (fsType > 0) bvr->part_type = fsType;
bvr->next = map->bvr;
map->bvr = bvr;
++map->bvrcnt;
}
}
}
scanErr:
free(buffer);
if(map)
{
if(countPtr) *countPtr = map->bvrcnt;
return map->bvr;
}
else
{
if(countPtr) *countPtr = 0;
return NULL;
}
}
//==========================================================================
static void scanFSLevelBVRSettings(BVRef chain)
{
BVRef bvr;
char dirSpec[512], fileSpec[512];
char label[BVSTRLEN];
int ret;
long flags, time;
int fh, fileSize, error;
for (bvr = chain; bvr; bvr = bvr->next)
{
ret = -1;
error = 0;
//
// Check for alternate volume label on boot helper partitions.
//
if (bvr->flags & kBVFlagBooter)
{
sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
strcpy(fileSpec, ".disk_label.contentDetails");
ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
if (!ret)
{
fh = open(strcat(dirSpec, fileSpec), 0);
fileSize = file_size(fh);
if (fileSize > 0 && fileSize < BVSTRLEN)
{
if (read(fh, label, fileSize) != fileSize)
error = -1;
}
else
error = -1;
close(fh);
if (!error)
{
label[fileSize] = '\0';
strcpy(bvr->altlabel, label);
}
}
}
//
// Check for SystemVersion.plist or ServerVersion.plist
// to determine if a volume hosts an installed system.
//
if (bvr->flags & kBVFlagNativeBoot)
{
sprintf(dirSpec, "hd(%d,%d)/System/Library/CoreServices/", BIOS_DEV_UNIT(bvr), bvr->part_no);
strcpy(fileSpec, "SystemVersion.plist");
ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
if (ret == -1)
{
strcpy(fileSpec, "ServerVersion.plist");
ret = GetFileInfo(dirSpec, fileSpec, &flags, &time);
}
if (!ret)
bvr->flags |= kBVFlagSystemVolume;
}
}
}
void rescanBIOSDevice(int biosdev)
{
struct DiskBVMap *oldMap = diskResetBootVolumes(biosdev);
CacheReset();
diskFreeMap(oldMap);
oldMap = NULL;
scanBootVolumes(biosdev, 0);
}
struct DiskBVMap* diskResetBootVolumes(int biosdev)
{
struct DiskBVMap * map;
struct DiskBVMap *prevMap = NULL;
for ( map = gDiskBVMap; map; prevMap = map, map = map->next ) {
if ( biosdev == map->biosdev ) {
break;
}
}
if(map != NULL)
{
verbose("Resetting BIOS device %xh\n", biosdev);
// Reset the biosbuf cache
cache_valid = false;
if(map == gDiskBVMap)
gDiskBVMap = map->next;
else if(prevMap != NULL)
prevMap->next = map->next;
else
stop("");
}
// Return the old map, either to be freed, or reinserted later
return map;
}
// Frees a DiskBVMap and all of its BootVolume's
void diskFreeMap(struct DiskBVMap *map)
{
if(map != NULL)
{
while(map->bvr != NULL)
{
BVRef bvr = map->bvr;
map->bvr = bvr->next;
(*bvr->bv_free)(bvr);
}
free(map);
}
}
BVRef diskScanBootVolumes( int biosdev, int * countPtr )
{
struct DiskBVMap * map;
BVRef bvr;
int count = 0;
// Find an existing mapping for this device.
for ( map = gDiskBVMap; map; map = map->next ) {
if ( biosdev == map->biosdev ) {
count = map->bvrcnt;
break;
}
}
if (map == NULL) {
bvr = diskScanGPTBootVolumes(biosdev, &count);
if (bvr == NULL) {
bvr = diskScanFDiskBootVolumes(biosdev, &count);
}
if (bvr == NULL) {
bvr = diskScanAPMBootVolumes(biosdev, &count);
}
if (bvr)
{
scanFSLevelBVRSettings(bvr);
}
} else {
bvr = map->bvr;
}
if (countPtr) *countPtr += count;
return bvr;
}
BVRef getBVChainForBIOSDev(int biosdev)
{
BVRef chain = NULL;
struct DiskBVMap * map = NULL;
for (map = gDiskBVMap; map; map = map->next)
{
if (map->biosdev == biosdev)
{
chain = map->bvr;
break;
}
}
return chain;
}
BVRef newFilteredBVChain(int minBIOSDev, int maxBIOSDev, unsigned int allowFlags, unsigned int denyFlags, int *count)
{
BVRef chain = NULL;
BVRef bvr = NULL;
BVRef newBVR = NULL;
BVRef prevBVR = NULL;
struct DiskBVMap * map = NULL;
int bvCount = 0;
/*
* Traverse gDISKBVmap to get references for
* individual bvr chains of each drive.
*/
for (map = gDiskBVMap; map; map = map->next)
{
for (bvr = map->bvr; bvr; bvr = bvr->next)
{
/*
* Save the last bvr.
*/
if (newBVR) prevBVR = newBVR;
/*
* Allocate and copy the matched bvr entry into a new one.
*/
newBVR = (BVRef) malloc(sizeof(*newBVR));
bcopy(bvr, newBVR, sizeof(*newBVR));
/*
* Adjust the new bvr's fields.
*/
newBVR->next = NULL;
newBVR->filtered = true;
if ( (!allowFlags || newBVR->flags & allowFlags)
&& (!denyFlags || !(newBVR->flags & denyFlags) )
&& (newBVR->biosdev >= minBIOSDev && newBVR->biosdev <= maxBIOSDev)
)
newBVR->visible = true;
/*
* Use the first bvr entry as the starting chain pointer.
*/
if (!chain)
chain = newBVR;
/*
* Update the previous bvr's link pointer to use the new memory area.
*/
if (prevBVR)
prevBVR->next = newBVR;
if (newBVR->visible)
bvCount++;
}
}
#if DEBUG //Azi: warning - too big for boot-log.. far too big.. i mean HUGE!! :P
for (bvr = chain; bvr; bvr = bvr->next)
{
printf(" bvr: %d, dev: %d, part: %d, flags: %d, vis: %d\n", bvr, bvr->biosdev, bvr->part_no, bvr->flags, bvr->visible);
}
printf("count: %d\n", bvCount);
getchar();
#endif
*count = bvCount;
return chain;
}
int freeFilteredBVChain(const BVRef chain)
{
int ret = 1;
BVRef bvr = chain;
BVRef nextBVR = NULL;
while (bvr)
{
nextBVR = bvr->next;
if (bvr->filtered)
{
free(bvr);
}
else
{
ret = 0;
break;
}
bvr = nextBVR;
}
return ret;
}
//==========================================================================
static const struct NamedValue fdiskTypes[] =
{
{ FDISK_NTFS, "Windows NTFS" },
{ FDISK_DOS12, "Windows FAT12" },
{ FDISK_DOS16B, "Windows FAT16" },
{ FDISK_DOS16S, "Windows FAT16" },
{ FDISK_DOS16SLBA, "Windows FAT16" },
{ FDISK_SMALLFAT32, "Windows FAT32" },
{ FDISK_FAT32, "Windows FAT32" },
{ FDISK_LINUX, "Linux" },
{ FDISK_UFS, "Apple UFS" },
{ FDISK_HFS, "Apple HFS" },
{ FDISK_BOOTER, "Apple Boot/UFS" },
{ 0xCD, "CD-ROM" },
{ 0x00, 0 } /* must be last */
};
//==========================================================================
bool matchVolumeToString( BVRef bvr, const char* match, long matchLen)
{
char testStr[128];
if ( !bvr || !match || !*match)
return 0;
if ( bvr->biosdev < 0x80 || bvr->biosdev >= 0x100 )
return 0;
// Try to match hd(x,y) first.
sprintf(testStr, "hd(%d,%d)", BIOS_DEV_UNIT(bvr), bvr->part_no);
if ( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
return true;
// Try to match volume UUID.
if ( bvr->fs_getuuid && bvr->fs_getuuid(bvr, testStr) == 0)
{
if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
return true;
}
// Try to match volume label (always quoted).
if ( bvr->description )
{
bvr->description(bvr, testStr, sizeof(testStr)-1);
if( matchLen ? !strncmp(match, testStr, matchLen) : !strcmp(match, testStr) )
return true;
}
return false;
}
void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription )
{
unsigned char type;
char *p = str;
if(!bvr || !p || strMaxLen <= 0)
return;
type = (unsigned char) bvr->part_type;
if (useDeviceDescription)
{
int len = getDeviceDescription(bvr, str);
if(len >= strMaxLen)
return;
strcpy(str + len, " ");
len++;
strMaxLen -= len;
p += len;
}
//
// Get the volume label using filesystem specific functions
// or use the alternate volume label if available.
//
if (*bvr->altlabel != '\0')
strncpy(p, bvr->altlabel, strMaxLen);
else if (bvr->description)
bvr->description(bvr, p, strMaxLen);
if (*p == '\0') {
const char * name = getNameForValue( fdiskTypes, type );
if (name == NULL) {
name = bvr->type_name;
}
if (name == NULL) {
sprintf(p, "TYPE %02x", type);
} else {
strncpy(p, name, strMaxLen);
}
}
// Set the devices label
sprintf(bvr->label, p);
}
//==========================================================================
int readBootSector( int biosdev, unsigned int secno, void * buffer )
{
struct disk_blk0 * bootSector = (struct disk_blk0 *) buffer;
int error;
if ( bootSector == NULL )
{
if ( gBootSector == NULL )
{