Chameleon

Chameleon Commit Details

Date:2011-06-25 22:25:50 (12 years 9 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 )
{
gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
if ( gBootSector == NULL ) return -1;
}
bootSector = gBootSector;
}
error = readBytes( biosdev, secno, 0, BPS, bootSector );
if ( error || bootSector->signature != DISK_SIGNATURE )
return -1;
return 0;
}
/*
* Format of boot1f32 block.
*/
#define BOOT1F32_MAGIC "BOOT "
#define BOOT1F32_MAGICLEN 11
struct disk_boot1f32_blk {
unsigned char init[3];
unsigned char fsheader[87];
unsigned char magic[BOOT1F32_MAGICLEN];
unsigned char bootcode[409];
unsigned short signature;
};
int testFAT32EFIBootSector( int biosdev, unsigned int secno, void * buffer )
{
struct disk_boot1f32_blk * bootSector = (struct disk_boot1f32_blk *) buffer;
int error;
if ( bootSector == NULL )
{
if ( gBootSector == NULL )
{
gBootSector = (struct disk_blk0 *) malloc(sizeof(*gBootSector));
if ( gBootSector == NULL ) return -1;
}
bootSector = (struct disk_boot1f32_blk *) gBootSector;
}
error = readBytes( biosdev, secno, 0, BPS, bootSector );
if ( error || bootSector->signature != DISK_SIGNATURE
|| strncmp((const char *)bootSector->magic, BOOT1F32_MAGIC, BOOT1F32_MAGICLEN) )
return -1;
return 0;
}
//==========================================================================
// Handle seek request from filesystem modules.
void diskSeek( BVRef bvr, long long position )
{
bvr->fs_boff = position / BPS;
bvr->fs_byteoff = position % BPS;
}
//==========================================================================
// Handle read request from filesystem modules.
int diskRead( BVRef bvr, long addr, long length )
{
return readBytes( bvr->biosdev,
bvr->fs_boff + bvr->part_boff,
bvr->fs_byteoff,
length,
(void *) addr );
}
int rawDiskRead( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
{
int secs;
unsigned char *cbuf = (unsigned char *)buffer;
unsigned int copy_len;
int rc;
if ((len & (BPS-1)) != 0) {
error("raw disk read not sector aligned");
return -1;
}
secno += bvr->part_boff;
cache_valid = false;
while (len > 0) {
secs = len / BPS;
if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
copy_len = secs * BPS;
//printf("rdr: ebiosread(%d, %d, %d)\n", bvr->biosdev, secno, secs);
if ((rc = ebiosread(bvr->biosdev, secno, secs)) != 0) {
/* Ignore corrected ECC errors */
if (rc != ECC_CORRECTED_ERR) {
error(" EBIOS read error: %s\n", bios_error(rc), rc);
error(" Block %d Sectors %d\n", secno, secs);
return rc;
}
}
bcopy( trackbuf, cbuf, copy_len );
len -= copy_len;
cbuf += copy_len;
secno += secs;
}
return 0;
}
int rawDiskWrite( BVRef bvr, unsigned int secno, void *buffer, unsigned int len )
{
int secs;
unsigned char *cbuf = (unsigned char *)buffer;
unsigned int copy_len;
int rc;
if ((len & (BPS-1)) != 0) {
error("raw disk write not sector aligned");
return -1;
}
secno += bvr->part_boff;
cache_valid = false;
while (len > 0) {
secs = len / BPS;
if (secs > N_CACHE_SECS) secs = N_CACHE_SECS;
copy_len = secs * BPS;
bcopy( cbuf, trackbuf, copy_len );
//printf("rdr: ebioswrite(%d, %d, %d)\n", bvr->biosdev, secno, secs);
if ((rc = ebioswrite(bvr->biosdev, secno, secs)) != 0) {
error(" EBIOS write error: %s\n", bios_error(rc), rc);
error(" Block %d Sectors %d\n", secno, secs);
return rc;
}
len -= copy_len;
cbuf += copy_len;
secno += secs;
}
return 0;
}
int diskIsCDROM(BVRef bvr)
{
struct driveInfo di;
if (getDriveInfo(bvr->biosdev, &di) == 0 && di.no_emulation) {
return 1;
}
return 0;
}
int biosDevIsCDROM(int biosdev)
{
struct driveInfo di;
if (getDriveInfo(biosdev, &di) == 0 && di.no_emulation)
{
return 1;
}
return 0;
}
branches/rewrite/i386/libsaio/disk.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*
* disk.h
* Chameleon
*
* Created by Daniel Miranda on 27/07/10.
* Copyright 2010 __MyCompanyName__. All rights reserved.
*
*/
#ifndef __LIBSAIO_DISK_H
#define __LIBSAIO_DISK_H
bool matchVolumeToString( BVRef bvr, const char* match, long strMaxLen);
#endif /* __LIBSAIO_DISK_H */
branches/rewrite/i386/libsaio/ufs.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 UFSInitPartition(CICell ih);
extern long UFSLoadFile(CICell ih, char * filePath);
extern long UFSReadFile( CICell ih, char * filePath, void * base, uint64_t offset, uint64_t length );
extern long UFSGetDirEntry(CICell ih, char * dirPath, long long * dirIndex,
char ** name, long * flags, long * time,
FinderInfo * finderInfo, long * infoValid);
extern void UFSGetDescription(CICell ih, char *str, long strMaxLen);
extern long UFSGetFileBlock(CICell ih, char *str, unsigned long long *firstBlock);
extern long UFSGetUUID(CICell ih, char *uuidStr);
extern void UFSFree(CICell ih);
branches/rewrite/i386/libsaio/nbp_cmd.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
/*
* 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@
*/
#ifndef __LIBSAIO_NBP_CMD_H
#define __LIBSAIO_NBP_CMD_H
#include <IOKit/IOTypes.h>
/*==========================================================================
* NBP return status codes.
*/
typedef enum {
nbpStatusSuccess = 0,
nbpStatusFailed,
nbpStatusInvalid,
} nbpStatus_t;
/*==========================================================================
* NBP commands codes.
*/
typedef enum {
nbpCommandTFTPReadFile = 1,
nbpCommandTFTPGetFileSize,
nbpCommandUnloadBaseCode,
} nbpCommandCode_t;
/*==========================================================================
* NBP commands.
*/
typedef struct {
UInt32 status; /* return code from NBP */
} nbpCommandHeader_s;
typedef struct {
UInt32 status; /* return code from NBP */
UInt8 filename[128]; /* name of file to be downloaded */
UInt32 bufferSize; /* size of the download buffer */
UInt32 buffer; /* physical address of the download buffer */
} nbpCommandTFTPReadFile_s;
typedef struct {
UInt32 status; /* return code from NBP */
UInt8 filename[128]; /* name of file to be downloaded */
UInt32 filesize; /* size of the file specified */
} nbpCommandTFTPGetFileSize_s;
typedef struct {
UInt32 status; /* return code from NBP */
UInt8 sname[64]; /* server name */
UInt32 CIP; /* client IP address */
UInt32 SIP; /* server IP address */
UInt32 GIP; /* gateway IP address */
} nbpCommandGetNetworkInfo_s;
/*==========================================================================
* An union of all NBP command structures.
*/
typedef union {
nbpCommandHeader_s header;
nbpCommandTFTPReadFile_s tftpReadFile;
nbpCommandTFTPGetFileSize_s tftpFileSize;
} nbpCommand_u;
#endif /* !__LIBSAIO_NBP_CMD_H */
branches/rewrite/i386/libsaio/stringTable.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
/*
* 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 1993 NeXT, Inc.
* All rights reserved.
*/
#include "libsaio.h"
#include "xml.h"
extern char *Language;
extern char *LoadableFamilies;
bool sysConfigValid;
/*
* Compare a string to a key with quoted characters
*/
static inline int
keyncmp(const char *str, const char *key, int n)
{
int c;
while (n--) {
c = *key++;
if (c == '\\') {
switch(c = *key++) {
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;
default:
break;
}
} else if (c == '\"') {
/* Premature end of key */
return 1;
}
if (c != *str++) {
return 1;
}
}
return 0;
}
#if UNUSED
static void eatThru(char val, const char **table_p)
{
register const char *table = *table_p;
register bool found = false;
while (*table && !found)
{
if (*table == '\\') table += 2;
else
{
if (*table == val) found = true;
table++;
}
}
*table_p = table;
}
/* Remove key and its associated value from the table. */
bool
removeKeyFromTable(const char *key, char *table)
{
register int len;
register char *tab;
char *buf;
len = strlen(key);
tab = (char *)table;
buf = (char *)malloc(len + 3);
sprintf(buf, "\"%s\"", key);
len = strlen(buf);
while(*tab) {
if(strncmp(buf, tab, len) == 0) {
char c;
while((c = *(tab + len)) != ';') {
if(c == 0) {
len = -1;
goto out;
}
len++;
}
len++;
if(*(tab + len) == '\n') len++;
goto out;
}
tab++;
}
len = -1;
out:
free(buf);
if(len == -1) return false;
while((*tab = *(tab + len))) {
tab++;
}
return true;
}
char *
newStringFromList(
char **list,
int *size
)
{
char *begin = *list, *end;
char *newstr;
int newsize = *size;
int bufsize;
while (*begin && newsize && isspace(*begin)) {
begin++;
newsize--;
}
end = begin;
while (*end && newsize && !isspace(*end)) {
end++;
newsize--;
}
if (begin == end)
return 0;
bufsize = end - begin + 1;
newstr = malloc(bufsize);
strlcpy(newstr, begin, bufsize);
*list = end;
*size = newsize;
return newstr;
}
#endif
/*
* compress == compress escaped characters to one character
*/
int stringLength(const char *table, int compress)
{
int ret = 0;
while (*table)
{
if (*table == '\\')
{
table += 2;
ret += 1 + (compress ? 0 : 1);
}
else
{
if (*table == '\"') return ret;
ret++;
table++;
}
}
return ret;
}
bool getValueForConfigTableKey(config_file_t *config, const char *key, const char **val, int *size)
{
if (config->dictionary != 0 ) {
// Look up key in XML dictionary
TagPtr value;
value = XMLGetProperty(config->dictionary, key);
if (value != 0) {
if (value->type != kTagTypeString) {
error("Non-string tag '%s' found in config file\n",
key);
return false;
}
*val = value->string;
*size = strlen(value->string);
return true;
}
} else {
// Legacy plist-style table
}
return false;
}
#if UNUSED
/*
* Returns a new malloc'ed string if one is found
* in the string table matching 'key'. Also translates
* \n escapes in the string.
*/
char *newStringForStringTableKey(
char *table,
char *key,
config_file_t *config
)
{
const char *val;
char *newstr, *p;
int size;
if (getValueForConfigTableKey(config, key, &val, &size)) {
newstr = (char *)malloc(size+1);
for (p = newstr; size; size--, p++, val++) {
if ((*p = *val) == '\\') {
switch (*++val) {
case 'r':
*p = '\r';
break;
case 'n':
*p = '\n';
break;
case 't':
*p = '\t';
break;
default:
*p = *val;
break;
}
size--;
}
}
*p = '\0';
return newstr;
} else {
return 0;
}
}
#endif
char *
newStringForKey(char *key, config_file_t *config)
{
const char *val;
char *newstr;
int size;
if (getValueForKey(key, &val, &size, config) && size) {
newstr = (char *)malloc(size + 1);
strlcpy(newstr, val, size + 1);
return newstr;
} else {
return 0;
}
}
/* parse a command line
* in the form: [<argument> ...] [<option>=<value> ...]
* both <option> and <value> must be either composed of
* non-whitespace characters, or enclosed in quotes.
*/
static const char *getToken(const char *line, const char **begin, int *len)
{
if (*line == '\"') {
*begin = ++line;
while (*line && *line != '\"')
line++;
*len = line++ - *begin;
} else {
*begin = line;
while (*line && !isspace(*line) && *line != '=')
line++;
*len = line - *begin;
}
return line;
}
bool getValueForBootKey(const char *line, const char *match, const char **matchval, int *len)
{
const char *key, *value;
int key_len, value_len;
bool retval = false;
while (*line) {
/* look for keyword or argument */
while (isspace(*line)) line++;
/* now look for '=' or whitespace */
line = getToken(line, &key, &key_len);
/* line now points to '=' or space */
if (*line && !isspace(*line)) {
line = getToken(++line, &value, &value_len);
} else {
value = line;
value_len = 0;
}
if ((strlen(match) == key_len)
&& strncmp(match, key, key_len) == 0) {
*matchval = value;
*len = value_len;
retval = true;
/* Continue to look for this key; last one wins. */
}
}
return retval;
}
/* Return NULL if no option has been successfully retrieved, or the string otherwise */
const char * getStringForKey(const char * key, config_file_t *config)
{
static const char* value =0;
int len=0;
if(!getValueForKey(key, &value, &len, config)) value = 0;
return value;
}
/* Returns TRUE if a value was found, FALSE otherwise.
* The boolean value of the key is stored in 'val'.
*/
bool getBoolForKey( const char *key, bool *result_val, config_file_t *config )
{
const char *key_val;
int size;
if (getValueForKey(key, &key_val, &size, config)) {
if ( (size >= 1) && (key_val[0] == 'Y' || key_val[0] == 'y') ) {
*result_val = true;
} else {
*result_val = false;
}
return true;
}
return false;
}
bool getIntForKey( const char *key, int *value, config_file_t *config )
{
const char *val;
int size, sum;
bool negative = false;
if (getValueForKey(key, &val, &size, config))
{
if ( size )
{
if (*val == '-')
{
negative = true;
val++;
size--;
}
for (sum = 0; size > 0; size--)
{
if (*val < '0' || *val > '9')
return false;
sum = (sum * 10) + (*val++ - '0');
}
if (negative)
sum = -sum;
*value = sum;
return true;
}
}
return false;
}
/*
*
*/
bool getDimensionForKey( const char *key, unsigned int *value, config_file_t *config, unsigned int dimension_max, unsigned int object_size )
{
const char *val;
int size = 0;
int sum = 0;
bool negative = false;
bool percentage = false;
if (getValueForKey(key, &val, &size, config))
{
if ( size )
{
if (*val == '-')
{
negative = true;
val++;
size--;
}
if (val[size-1] == '%')
{
percentage = true;
size--;
}
// convert string to integer
for (sum = 0; size > 0; size--)
{
if (*val < '0' || *val > '9')
return false;
sum = (sum * 10) + (*val++ - '0');
}
if (percentage)
sum = ( dimension_max * sum ) / 100;
// calculate offset from opposite origin
if (negative)
sum = ( ( dimension_max - object_size ) - sum );
} else {
// null value calculate center
sum = ( dimension_max - object_size ) / 2;
}
*value = (uint16_t) sum;
return true;
}
// key not found
return false;
}
/*
*get color value from plist format #RRGGBB
*/
bool getColorForKey( const char *key, unsigned int *value, config_file_t *config )
{
const char *val;
int size;
if (getValueForKey(key, &val, &size, config))
{
if (*val == '#')
{
val++;
*value = strtol(val, NULL, 16);
return true;
}
}
return false;
}
bool getValueForKey( const char *key, const char **val, int *size, config_file_t *config )
{
return getValueForConfigTableKey(config, key, val, size);
}
#if UNUSED
void
printSystemConfig(char *p1)
{
char *p2 = p1, tmp;
while (*p1 != '\0') {
while (*p2 != '\0' && *p2 != '\n') p2++;
tmp = *p2;
*p2 = '\0';
printf("%s\n", p1);
*p2 = tmp;
if (tmp == '\0') break;
p1 = ++p2;
}
}
#endif
//==========================================================================
// ParseXMLFile
// Modifies the input buffer.
// Expects to see one dictionary in the XML file.
// Puts the first dictionary it finds in the
// tag pointer and returns 0, or returns -1 if not found
// (and does not modify dict pointer).
// Prints an error message if there is a parsing error.
//
int ParseXMLFile( char * buffer, TagPtr * dict )
{
long length, pos;
TagPtr tag;
pos = 0;
char *configBuffer;
configBuffer = malloc(strlen(buffer)+1);
strcpy(configBuffer, buffer);
while (1)
{
length = XMLParseNextTag(configBuffer + pos, &tag);
if (length == -1) break;
pos += length;
if (tag == 0) continue;
if (tag->type == kTagTypeDict) break;
XMLFreeTag(tag);
}
free(configBuffer);
if (length < 0) {
error ("Error parsing plist file\n");
return -1;
}
*dict = tag;
return 0;
}
char * newString(const char * oldString)
{
if ( oldString )
return strcpy(malloc(strlen(oldString)+1), oldString);
else
return NULL;
}
/*
* Extracts the next argument from the command line, double quotes are allowed here.
*/
char * getNextArg(char ** argPtr, char * val)
{
char * ptr = *argPtr;
const char * strStart;
int len = 0;
bool isQuoted = false;
*val = '\0';
// Scan for the next non-whitespace character.
while ( *ptr && (*ptr == ' ' || *ptr == '=') )
{
ptr++;
}
strStart = ptr;
// Skip the leading double quote character.
if (*ptr == '\"')
{
isQuoted = true;
ptr++;
strStart++;
}
// Scan for the argument terminator character.
// This can be either a NULL character - in case we reach the end of the string,
// a double quote in case of quoted argument,
// or a whitespace character (' ' or '=') for non-quoted argument.
while (*ptr && !( (isQuoted && (*ptr == '\"')) ||
(!isQuoted && (*ptr == ' ' || *ptr == '=')) )
)
{
ptr++;
}
len = ptr - strStart;
// Skip the closing double quote character and adjust
// the starting pointer for the next getNextArg call.
if (*ptr && isQuoted && *ptr == '\"')
ptr++;
// Copy the extracted argument to val.
strncat(val, strStart, len);
// Set command line pointer.
*argPtr = ptr;
return ptr;
}
branches/rewrite/i386/libsaio/msdos_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
/*
* 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@
*/
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software, just don't say you wrote
* it, and don't remove this notice.
*
* This software is provided "as is".
*
* The author supplies this software to be publicly redistributed on the
* understanding that the author is not responsible for the correct
* functioning of this software in any circumstances and is not liable for
* any damages caused by this software.
*
* October 1992
*/
/*
* Format of a boot sector. This is the first sector on a DOS floppy disk
* or the fist sector of a partition on a hard disk. But, it is not the
* first sector of a partitioned hard disk.
*/
struct bootsector33 {
u_int8_tbsJump[3];/* jump inst E9xxxx or EBxx90 */
int8_tbsOemName[8];/* OEM name and version */
int8_tbsBPB[19];/* BIOS parameter block */
int8_tbsDriveNumber;/* drive number (0x80) */
int8_tbsBootCode[479];/* pad so struct is 512b */
u_int8_tbsBootSectSig0;
u_int8_tbsBootSectSig1;
#defineBOOTSIG00x55
#defineBOOTSIG10xaa
};
struct extboot {
int8_texDriveNumber;/* drive number (0x80) */
int8_texReserved1;/* reserved */
int8_texBootSignature;/* ext. boot signature (0x29) */
#defineEXBOOTSIG0x29
int8_texVolumeID[4];/* volume ID number */
int8_texVolumeLabel[11];/* volume label */
int8_texFileSysType[8];/* fs type (FAT12 or FAT16) */
};
struct bootsector50 {
u_int8_tbsJump[3];/* jump inst E9xxxx or EBxx90 */
int8_tbsOemName[8];/* OEM name and version */
int8_tbsBPB[25];/* BIOS parameter block */
int8_tbsExt[26];/* Bootsector Extension */
int8_tbsBootCode[448];/* pad so structure is 512b */
u_int8_tbsBootSectSig0;
u_int8_tbsBootSectSig1;
#defineBOOTSIG00x55
#defineBOOTSIG10xaa
};
struct bootsector710 {
u_int8_tbsJump[3];/* jump inst E9xxxx or EBxx90 */
int8_tbsOEMName[8];/* OEM name and version */
int8_tbsBPB[53];/* BIOS parameter block */
int8_tbsExt[26];/* Bootsector Extension */
int8_tbsBootCode[420];/* pad so structure is 512b */
u_int8_tbsBootSectSig0;
u_int8_tbsBootSectSig1;
#defineBOOTSIG00x55
#defineBOOTSIG10xaa
};
union bootsector {
struct bootsector33 bs33;
struct bootsector50 bs50;
struct bootsector710 bs710;
};
/* BPB */
/*
* BIOS Parameter Block (BPB) for DOS 3.3
*/
struct bpb33 {
u_int16_tbpbBytesPerSec;/* bytes per sector */
u_int8_tbpbSecPerClust;/* sectors per cluster */
u_int16_tbpbResSectors;/* number of reserved sectors */
u_int8_tbpbFATs;/* number of FATs */
u_int16_tbpbRootDirEnts;/* number of root directory entries */
u_int16_tbpbSectors;/* total number of sectors */
u_int8_tbpbMedia;/* media descriptor */
u_int16_tbpbFATsecs;/* number of sectors per FAT */
u_int16_tbpbSecPerTrack;/* sectors per track */
u_int16_tbpbHeads;/* number of heads */
u_int16_tbpbHiddenSecs;/* number of hidden sectors */
} __attribute__((packed));
/*
* BPB for DOS 5.0 The difference is bpbHiddenSecs is a short for DOS 3.3,
* and bpbHugeSectors is not in the 3.3 bpb.
*/
struct bpb50 {
u_int16_tbpbBytesPerSec;/* bytes per sector */
u_int8_tbpbSecPerClust;/* sectors per cluster */
u_int16_tbpbResSectors;/* number of reserved sectors */
u_int8_tbpbFATs;/* number of FATs */
u_int16_tbpbRootDirEnts;/* number of root directory entries */
u_int16_tbpbSectors;/* total number of sectors */
u_int8_tbpbMedia;/* media descriptor */
u_int16_tbpbFATsecs;/* number of sectors per FAT */
u_int16_tbpbSecPerTrack;/* sectors per track */
u_int16_tbpbHeads;/* number of heads */
u_int32_tbpbHiddenSecs;/* # of hidden sectors */
u_int32_tbpbHugeSectors;/* # of sectors if bpbSectors == 0 */
} __attribute__((packed));
/*
* BPB for DOS 7.10 (FAT32). This one has a few extensions to bpb50.
*/
struct bpb710 {
u_int16_tbpbBytesPerSec;/* bytes per sector */
u_int8_tbpbSecPerClust;/* sectors per cluster */
u_int16_tbpbResSectors;/* number of reserved sectors */
u_int8_tbpbFATs;/* number of FATs */
u_int16_tbpbRootDirEnts;/* number of root directory entries */
u_int16_tbpbSectors;/* total number of sectors */
u_int8_tbpbMedia;/* media descriptor */
u_int16_tbpbFATsecs;/* number of sectors per FAT */
u_int16_tbpbSecPerTrack;/* sectors per track */
u_int16_tbpbHeads;/* number of heads */
u_int32_tbpbHiddenSecs;/* # of hidden sectors */
u_int32_tbpbHugeSectors;/* # of sectors if bpbSectors == 0 */
u_int32_tbpbBigFATsecs;/* like bpbFATsecs for FAT32 */
u_int16_tbpbExtFlags;/* extended flags: */
#defineFATNUM0xf/* mask for numbering active FAT */
#defineFATMIRROR0x80/* FAT is mirrored (like it always was) */
u_int16_tbpbFSVers;/* filesystem version */
#defineFSVERS0/* currently only 0 is understood */
u_int32_tbpbRootClust;/* start cluster for root directory */
u_int16_tbpbFSInfo;/* filesystem info structure sector */
u_int16_tbpbBackup;/* backup boot sector */
/* There is a 12 byte filler here, but we ignore it */
} __attribute__((packed));
#if 0
/*
* BIOS Parameter Block (BPB) for DOS 3.3
*/
struct byte_bpb33 {
int8_t bpbBytesPerSec[2];/* bytes per sector */
int8_t bpbSecPerClust;/* sectors per cluster */
int8_t bpbResSectors[2];/* number of reserved sectors */
int8_t bpbFATs;/* number of FATs */
int8_t bpbRootDirEnts[2];/* number of root directory entries */
int8_t bpbSectors[2];/* total number of sectors */
int8_t bpbMedia;/* media descriptor */
int8_t bpbFATsecs[2];/* number of sectors per FAT */
int8_t bpbSecPerTrack[2];/* sectors per track */
int8_t bpbHeads[2];/* number of heads */
int8_t bpbHiddenSecs[2];/* number of hidden sectors */
};
/*
* BPB for DOS 5.0 The difference is bpbHiddenSecs is a short for DOS 3.3,
* and bpbHugeSectors is not in the 3.3 bpb.
*/
struct byte_bpb50 {
int8_t bpbBytesPerSec[2];/* bytes per sector */
int8_t bpbSecPerClust;/* sectors per cluster */
int8_t bpbResSectors[2];/* number of reserved sectors */
int8_t bpbFATs;/* number of FATs */
int8_t bpbRootDirEnts[2];/* number of root directory entries */
int8_t bpbSectors[2];/* total number of sectors */
int8_t bpbMedia;/* media descriptor */
int8_t bpbFATsecs[2];/* number of sectors per FAT */
int8_t bpbSecPerTrack[2];/* sectors per track */
int8_t bpbHeads[2];/* number of heads */
int8_t bpbHiddenSecs[4];/* number of hidden sectors */
int8_t bpbHugeSectors[4];/* # of sectors if bpbSectors == 0 */
};
/*
* BPB for DOS 7.10 (FAT32). This one has a few extensions to bpb50.
*/
struct byte_bpb710 {
u_int8_t bpbBytesPerSec[2];/* bytes per sector */
u_int8_t bpbSecPerClust;/* sectors per cluster */
u_int8_t bpbResSectors[2];/* number of reserved sectors */
u_int8_t bpbFATs;/* number of FATs */
u_int8_t bpbRootDirEnts[2];/* number of root directory entries */
u_int8_t bpbSectors[2];/* total number of sectors */
u_int8_t bpbMedia;/* media descriptor */
u_int8_t bpbFATsecs[2];/* number of sectors per FAT */
u_int8_t bpbSecPerTrack[2];/* sectors per track */
u_int8_t bpbHeads[2];/* number of heads */
u_int8_t bpbHiddenSecs[4];/* # of hidden sectors */
u_int8_t bpbHugeSectors[4];/* # of sectors if bpbSectors == 0 */
u_int8_t bpbBigFATsecs[4];/* like bpbFATsecs for FAT32 */
u_int8_t bpbExtFlags[2];/* extended flags: */
u_int8_t bpbFSVers[2];/* filesystem version */
u_int8_t bpbRootClust[4];/* start cluster for root directory */
u_int8_t bpbFSInfo[2];/* filesystem info structure sector */
u_int8_t bpbBackup[2];/* backup boot sector */
/* There is a 12 byte filler here, but we ignore it */
};
#endif
/*
* FAT32 FSInfo block.
*/
struct fsinfo {
u_int8_t fsisig1[4];
u_int8_t fsifill1[480];
u_int8_t fsisig2[4];
u_int8_t fsinfree[4];
u_int8_t fsinxtfree[4];
u_int8_t fsifill2[12];
u_int8_t fsisig3[4];
};
/* direntry */
/*-
* Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
* Copyright (C) 1994, 1995, 1997 TooLs GmbH.
* All rights reserved.
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see above).
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*This product includes software developed by TooLs GmbH.
* 4. The name of TooLs GmbH may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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.
*/
/*
* Structure of a dos directory entry.
*/
struct direntry {
u_int8_tdeName[8];/* filename, blank filled */
#defineSLOT_EMPTY0x00/* slot has never been used */
#defineSLOT_E50x05/* the real value is 0xe5 */
#defineSLOT_DELETED0xe5/* file in this slot deleted */
u_int8_tdeExtension[3];/* extension, blank filled */
u_int8_tdeAttributes;/* file attributes */
#defineATTR_NORMAL0x00/* normal file */
#defineATTR_READONLY0x01/* file is read-only (immutable) */
#defineATTR_HIDDEN0x02/* file is hidden */
#defineATTR_SYSTEM0x04/* file is a system file */
#defineATTR_VOLUME0x08/* entry is a volume label */
#defineATTR_DIRECTORY0x10/* entry is a directory name */
#defineATTR_ARCHIVE0x20/* file is new or modified */
u_int8_tdeLowerCase;/* NT VFAT lower case flags */
#defineLCASE_BASE0x08/* filename base in lower case */
#defineLCASE_EXT0x10/* filename extension in lower case */
u_int8_tdeCHundredth;/* hundredth of seconds in CTime */
u_int8_tdeCTime[2];/* create time */
u_int8_tdeCDate[2];/* create date */
u_int8_tdeADate[2];/* access date */
u_int8_tdeHighClust[2];/* high bytes of cluster number */
u_int16_tdeMTime;/* last update time */
u_int16_tdeMDate;/* last update date */
u_int8_tdeStartCluster[2]; /* starting cluster of file */
u_int8_tdeFileSize[4];/* size of file in bytes */
};
/*
* Structure of a Win95 long name directory entry
*/
struct winentry {
u_int8_tweCnt;
#defineWIN_LAST0x40
#defineWIN_CNT0x3f
u_int8_twePart1[10];
u_int8_tweAttributes;
#defineATTR_WIN950x0f
u_int8_tweReserved1;
u_int8_tweChksum;
u_int8_twePart2[12];
u_int16_tweReserved2;
u_int8_twePart3[4];
};
#defineWIN_CHARS13/* Number of chars per winentry */
/*
* Maximum filename length in Win95
* Note: Must be < sizeof(dirent.d_name)
*/
#defineWIN_MAXLEN255
/*
* This is the format of the contents of the deTime field in the direntry
* structure.
* We don't use bitfields because we don't know how compilers for
* arbitrary machines will lay them out.
*/
#define DT_2SECONDS_MASK0x1F/* seconds divided by 2 */
#define DT_2SECONDS_SHIFT0
#define DT_MINUTES_MASK0x7E0/* minutes */
#define DT_MINUTES_SHIFT5
#define DT_HOURS_MASK0xF800/* hours */
#define DT_HOURS_SHIFT11
/*
* This is the format of the contents of the deDate field in the direntry
* structure.
*/
#define DD_DAY_MASK0x1F/* day of month */
#define DD_DAY_SHIFT0
#define DD_MONTH_MASK0x1E0/* month */
#define DD_MONTH_SHIFT5
#define DD_YEAR_MASK0xFE00/* year - 1980 */
#define DD_YEAR_SHIFT9
branches/rewrite/i386/libsaio/msdos.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
/*
* 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@
*/
/*
* Copyright (c) 1998 Robert Nordier
* 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(S) ``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(S) 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.
*/
#include "libsaio.h"
#include "sl.h"
#include "msdos_private.h"
#include "msdos.h"
#define LABEL_LENGTH11
#define MSDOS_CACHE_BLOCKSIZE BPS
#defineCLUST_FIRST2/* reserved cluster range */
#defineCLUST_RSRVD320x0ffffff8/* reserved cluster range */
#defineCLUST_RSRVD160xfff8/* reserved cluster range */
#defineCLUST_RSRVD120xff8/* reserved cluster range */
#define tolower(c) (((c)>='A' && c<='Z')?((c) | 0x20):(c))
static int msdosressector=0;
static int msdosnfats = 0;
static int msdosfatsecs = 0;
static int msdosbps = 0;
static int msdosclustersize = 0;
static int msdosrootDirSectors = 0;
static CICell msdoscurrent = 0;
static int msdosrootcluster = 0;
static int msdosfatbits = 0;
#if UNUSED
/*
* Check a volume label.
*/
static int
oklabel(const char *src)
{
int c, i;
for (i = 0, c = 0; i <= 11; i++) {
c = (u_char)*src++;
if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c))
break;
}
return i && !c;
}
#endif /* UNUSED */
void MSDOSFree(CICell ih)
{
if(msdoscurrent == ih)
msdoscurrent = 0;
free(ih);
}
int MSDOSProbe(const void * buffer)
{
union bootsector *bsp;
struct bpb33 *b33;
struct bpb50 *b50;
struct bpb710 *b710;
u_int16_t bps;
u_int8_tspc;
bsp = (union bootsector *)buffer;
b33 = (struct bpb33 *)bsp->bs33.bsBPB;
b50 = (struct bpb50 *)bsp->bs50.bsBPB;
b710 = (struct bpb710 *)bsp->bs710.bsBPB;
/* We only work with 512, 1024, and 2048 byte sectors */
bps = OSSwapLittleToHostInt16(b33->bpbBytesPerSec);
if ((bps < 0x200) || (bps & (bps - 1)) || (bps > 0x800))
return 0;
/* Check to make sure valid sectors per cluster */
spc = b33->bpbSecPerClust;
if ((spc == 0 ) || (spc & (spc - 1)))
return 0;
if (OSSwapLittleToHostInt16(b50->bpbRootDirEnts) == 0) { /* It's FAT32 */
if (!memcmp(((struct extboot *)bsp->bs710.bsExt)->exFileSysType, "FAT32 ", 8))
return 32;
}
else if (((struct extboot *)bsp->bs50.bsExt)->exBootSignature == EXBOOTSIG) {
if (!memcmp((char *)((struct extboot *)bsp->bs50.bsExt)->exFileSysType, "FAT16 ", 8))
return 16;
if (!memcmp((char *)((struct extboot *)bsp->bs50.bsExt)->exFileSysType, "FAT12 ", 8))
return 12;
}
return 0;
}
long
MSDOSInitPartition (CICell ih)
{
union bootsector *bsp;
struct bpb33 *b33;
struct bpb50 *b50;
struct bpb710 *b710;
u_int8_tspc;
char *buf;
if (msdoscurrent == ih)
{
CacheInit(ih, MSDOS_CACHE_BLOCKSIZE);
return 0;
}
buf=malloc (512);
/*
* Read the boot sector of the filesystem, and then check the
* boot signature. If not a dos boot sector then error out.
*
* NOTE: 2048 is a maximum sector size in current...
*/
Seek(ih, 0);
Read(ih, (long)buf, 512);
bsp = (union bootsector *)buf;
b33 = (struct bpb33 *)bsp->bs33.bsBPB;
b50 = (struct bpb50 *)bsp->bs50.bsBPB;
b710 = (struct bpb710 *)bsp->bs710.bsBPB;
/* We only work with 512, 1024, and 2048 byte sectors */
msdosbps = OSSwapLittleToHostInt16(b33->bpbBytesPerSec);
if ((msdosbps < 0x200) || (msdosbps & (msdosbps - 1)) || (msdosbps > 0x800))
{
free (buf);
return -1;
}
/* Check to make sure valid sectors per cluster */
spc = b33->bpbSecPerClust;
if ((spc == 0 ) || (spc & (spc - 1)))
return -1;
if (OSSwapLittleToHostInt16(b50->bpbRootDirEnts) == 0) { /* It's FAT32 */
if (memcmp(((struct extboot *)bsp->bs710.bsExt)->exFileSysType, "FAT32 ", 8))
{
free (buf);
return -1;
}
msdosressector = OSSwapLittleToHostInt16(b710->bpbResSectors);
msdosnfats = b710->bpbFATs;
msdosfatsecs = OSSwapLittleToHostInt16(b710->bpbBigFATsecs);
msdosrootcluster = OSSwapLittleToHostInt32(b710->bpbRootClust);
msdosrootDirSectors = 0;
msdosfatbits = 32;
}
else if (((struct extboot *)bsp->bs50.bsExt)->exBootSignature == EXBOOTSIG) {
if (!memcmp((char *)((struct extboot *)bsp->bs50.bsExt)->exFileSysType, "FAT16 ", 8))
msdosfatbits = 16;
else if (!memcmp((char *)((struct extboot *)bsp->bs50.bsExt)->exFileSysType, "FAT12 ", 8))
msdosfatbits = 12;
else
{
free (buf);
return -1;
}
msdosressector = OSSwapLittleToHostInt16(b33->bpbResSectors);
msdosnfats = b33->bpbFATs;
msdosfatsecs = OSSwapLittleToHostInt16(b33->bpbFATsecs);
msdosrootcluster = 0;
msdosrootDirSectors = ((OSSwapLittleToHostInt16(b50->bpbRootDirEnts) * sizeof(struct direntry)) +
(msdosbps-1)) / msdosbps;
} else {
free (buf);
return -1;
}
msdosclustersize = msdosbps * spc;
msdoscurrent = ih;
CacheInit(ih, MSDOS_CACHE_BLOCKSIZE);
free (buf);
return 0;
}
static int
readSector(CICell ih, off_t readOffset, char *buf, int size)
{
// Caching only FAT entries (4 bytes) by utlizing the cache with sector aligned read requests.
if (size < BPS)
{
long long sectorOffset = (uint64_t)readOffset / BPS * BPS;
long relOffset = readOffset % BPS;
char *cacheBuffer;
cacheBuffer = malloc(MSDOS_CACHE_BLOCKSIZE);
CacheRead(ih, cacheBuffer, sectorOffset, MSDOS_CACHE_BLOCKSIZE, true);
bcopy(cacheBuffer + relOffset, buf, size);
free(cacheBuffer);
}
else
{
Seek(ih, readOffset);
Read(ih, (long)buf, size);
}
return 0;
}
static int
msdosreadcluster (CICell ih, uint8_t *buf, int size, off_t *cluster)
{
off_t readOffset;
char tmpbuf[8];
off_t clusn;
switch (msdosfatbits) {
case 32:
if (*cluster < CLUST_FIRST ||*cluster >= CLUST_RSRVD32)
return 0;
clusn = *cluster - CLUST_FIRST;
break;
case 16:
if (*cluster < CLUST_FIRST ||*cluster >= CLUST_RSRVD16)
return 0;
clusn = *cluster - CLUST_FIRST;
break;
case 12:
if (*cluster < CLUST_FIRST ||*cluster >= CLUST_RSRVD12)
return 0;
clusn = *cluster - CLUST_FIRST;
break;
default:
return 0;
}
/* Find sector where clusters start */
readOffset = (msdosressector +
(msdosnfats * msdosfatsecs)+msdosrootDirSectors)*msdosbps;
/* Find sector where "cluster" starts */
readOffset += clusn * msdosclustersize;
/* Read in "cluster" */
if (buf)
{
Seek(ih, readOffset);
Read(ih, (long)buf, size);
}
/* Find first sector of FAT */
readOffset = msdosressector * msdosbps;
/* Find sector containing "cluster" entry in FAT */
readOffset += ((uint64_t)*cluster * (uint64_t)msdosfatbits) / 8;
/* Read one sector of the FAT */
readSector(ih, readOffset, tmpbuf, 4);
switch (msdosfatbits) {
case 32:
*cluster = OSReadLittleInt32(tmpbuf, 0);
*cluster &= 0x0FFFFFFF;// ignore reserved upper bits
return 1;
case 16:
*cluster = OSReadLittleInt16(tmpbuf, 0);
return 1;
case 12:
*cluster = OSReadLittleInt16(tmpbuf, 0)>>(((uint64_t)*cluster * (uint64_t)msdosfatbits)%8);
*cluster &= 0xfff;
return 1;
default:
return 0;
}
}
struct msdosdirstate
{
struct direntry *buf;
uint8_t vfatchecksum;
int root16;
off_t cluster;
int nument;
int vfatnumber;
};
static struct direntry *
getnextdirent (CICell ih, uint16_t *longname, struct msdosdirstate *st)
{
struct direntry *dirp;
while (1)
{
if (st->root16)
{
if (st->cluster >= msdosrootDirSectors && st->nument == 0)
return 0;
if (st->nument == 0)
{
Seek(ih, (msdosressector +
(msdosnfats * msdosfatsecs)+st->cluster)*msdosbps);
Read(ih, (long)st->buf, msdosbps);
st->cluster++;
}
} else if (st->nument == 0 && !msdosreadcluster (ih, (uint8_t *)st->buf, msdosclustersize, &(st->cluster)))
return 0;
dirp=st->buf+st->nument;
if (dirp->deName[0] == SLOT_EMPTY)
return 0;
else if (dirp->deName[0] == SLOT_DELETED)
st->vfatnumber = 0;
else if (dirp->deAttributes == ATTR_WIN95)
{
struct winentry *wdirp = (struct winentry *)dirp;
int num;
if (wdirp->weCnt & 0x80)
continue;
num=(wdirp->weCnt&0x3f);
if (WIN_CHARS * num > WIN_MAXLEN)
continue;
if (st->vfatchecksum!=wdirp->weChksum)
{
st->vfatnumber = 0;
st->vfatchecksum = wdirp->weChksum;
}
if (st->vfatnumber < num)
st->vfatnumber = num;
bcopy (&(wdirp->wePart1),longname+WIN_CHARS*(num-1),sizeof (wdirp->wePart1));
bcopy (&(wdirp->wePart2),longname+WIN_CHARS*(num-1)+5,sizeof (wdirp->wePart2));
bcopy (&(wdirp->wePart3),longname+WIN_CHARS*(num-1)+11,sizeof (wdirp->wePart3));
} else {
uint8_t labelchecksum;
int i;
longname[st->vfatnumber*WIN_CHARS]=0;
labelchecksum=0;
for(i=0;i<LABEL_LENGTH;i++)
labelchecksum=(labelchecksum>>1)+(labelchecksum<<7)+dirp->deName[i];
if (!(labelchecksum==st->vfatchecksum && st->vfatnumber))
longname[0]=0;
st->vfatnumber = 0;
st->vfatchecksum = 0;
st->vfatnumber = 0;
st->nument++;
if ((!st->root16 &&st->nument * sizeof (struct direntry)>=msdosclustersize)
|| (st->root16 &&st->nument * sizeof (struct direntry)>=msdosbps))
st->nument = 0;
return dirp;
}
st->nument++;
if ((!st->root16 &&st->nument * sizeof (struct direntry)>=msdosclustersize)
|| (st->root16 &&st->nument * sizeof (struct direntry)>=msdosbps))
st->nument = 0;
}
}
static void
initRoot (struct msdosdirstate *st)
{
if (msdosrootDirSectors) {/* FAT12 or FAT16 */
st->root16 = 1;
st->vfatchecksum = 0;
st->nument = 0;
st->cluster = 0;
st->vfatnumber = 0;
} else {/* FAT32 */
st->root16 = 0;
st->vfatchecksum = 0;
st->nument = 0;
st->cluster = msdosrootcluster;
st->vfatnumber = 0;
}
}
/* First comes lowercase, then uppercase*/
static uint16_t cp850[128][2]=
{
{0x00E7,0x00C7},
{0x00FC,0x00DC},
{0x00E9,0x00C9},
{0x00E2,0x00C2},
{0x00E4,0x00C4},
{0x00E0,0x00C0},
{0x00E5,0x00C5},
{0x00E7,0x00C7},
{0x00EA,0x00CA},
{0x00EB,0x00CB},
{0x00E8,0x00C8},
{0x00EF,0x00CF},
{0x00EE,0x00CE},
{0x00EC,0x00CC},
{0x00E4,0x00C4},
{0x00E5,0x00C5},
{0x00E9,0x00C9},
{0x00E6,0x00C6},
{0x00E6,0x00C6},
{0x00F4,0x00D4},
{0x00F6,0x00D6},
{0x00F2,0x00D2},
{0x00FB,0x00DB},
{0x00F9,0x00D9},
{0x00FF,0x0178},
{0x00F6,0x00D6},
{0x00FC,0x00DC},
{0x00F8,0x00D8},
{0x00A3,0x00A3},
{0x00F8,0x00D8},
{0x00D7,0x00D7},
{0x0192,0x0191},
{0x00E1,0x00C1},
{0x00ED,0x00CD},
{0x00F3,0x00D3},
{0x00FA,0x00DA},
{0x00F1,0x00D1},
{0x00F1,0x00D1},
{0x00AA,0x00AA},
{0x00BA,0x00BA},
{0x00BF,0x00BF},
{0x00AE,0x00AE},
{0x00AC,0x00AC},
{0x00BD,0x00BD},
{0x00BC,0x00BC},
{0x00A1,0x00A1},
{0x00AB,0x00AB},
{0x00BB,0x00BB},
{0x2591,0x2591},
{0x2592,0x2592},
{0x2593,0x2593},
{0x2502,0x2502},
{0x2524,0x2524},
{0x00E1,0x00C1},
{0x00E2,0x00C2},
{0x00E0,0x00C0},
{0x00A9,0x00A9},
{0x2563,0x2563},
{0x2551,0x2551},
{0x2557,0x2557},
{0x255D,0x255D},
{0x00A2,0x00A2},
{0x00A5,0x00A5},
{0x2510,0x2510},
{0x2514,0x2514},
{0x2534,0x2534},
{0x252C,0x252C},
{0x251C,0x251C},
{0x2500,0x2500},
{0x253C,0x253C},
{0x00E3,0x00C3},
{0x00E3,0x00C3},
{0x255A,0x255A},
{0x2554,0x2554},
{0x2569,0x2569},
{0x2566,0x2566},
{0x2560,0x2560},
{0x2550,0x2550},
{0x256C,0x256C},
{0x00A4,0x00A4},
{0x00F0,0x00D0},
{0x00F0,0x00D0},
{0x00EA,0x00CA},
{0x00EB,0x00CB},
{0x00E8,0x00C8},
{0x0131,0x0049},
{0x00ED,0x00CD},
{0x00EE,0x00CE},
{0x00EF,0x00CF},
{0x2518,0x2518},
{0x250C,0x250C},
{0x2588,0x2588},
{0x2584,0x2584},
{0x00A6,0x00A6},
{0x00EC,0x00CC},
{0x2580,0x2580},
{0x00F3,0x00D3},
{0x00DF,0x00DF},
{0x00F4,0x00D4},
{0x00F2,0x00D2},
{0x00F5,0x00D5},
{0x00F5,0x00D5},
{0x00B5,0x00B5},
{0x00FE,0x00DE},
{0x00FE,0x00DE},
{0x00FA,0x00DA},
{0x00FB,0x00DB},
{0x00F9,0x00D9},
{0x00FD,0x00DD},
{0x00FD,0x00DD},
{0x00AF,0x00AF},
{0x00B4,0x00B4},
{0x00AD,0x00AD},
{0x00B1,0x00B1},
{0x2017,0x2017},
{0x00BE,0x00BE},
{0x00B6,0x00B6},
{0x00A7,0x00A7},
{0x00F7,0x00F7},
{0x00B8,0x00B8},
{0x00B0,0x00B0},
{0x00A8,0x00A8},
{0x00B7,0x00B7},
{0x00B9,0x00B9},
{0x00B3,0x00B3},
{0x00B2,0x00B2},
{0x25A0,0x25A0},
{0x00A0,0x00A0}
};
static int
checkname (uint16_t *ucsname, int ucslen, struct direntry *dirp, uint16_t *vfatname)
{
uint16_t tmp[15];
if (vfatname[0])
{
int i;
for (i=0;vfatname[i];i++);
return !FastUnicodeCompare (ucsname, ucslen, vfatname, i, OSLittleEndian);
}
else
{
int i, j, k;
for (i=7;i>=0;i--)
if (dirp->deName[i]!=' ')
break;
j=i+1;
tmp[i+1]=0;
for(;i>=0;i--)
tmp[i]=SWAP_LE16((dirp->deName[i]>=128)?cp850[dirp->deName[i]-128][0]:tolower(dirp->deName[i]));
for (i=2;i>=0;i--)
if (dirp->deName[8+i]!=' ')
break;
if (i>=0)
{
tmp[j++]='.';
tmp[j+i+1]=0;
k=j+i+1;
for(;i>=0;i--)
tmp[j+i]=SWAP_LE16((dirp->deName[i+8]>=128)?cp850[dirp->deName[i+8]-128][0]:tolower(dirp->deName[i+8]));
j=k;
}
return !FastUnicodeCompare (ucsname, ucslen, tmp, j, OSLittleEndian);
}
}
static struct direntry *
getdirpfrompath (CICell ih, char *dirspec, uint8_t *buf)
{
struct msdosdirstate st;
struct direntry *dirp;
uint8_t * ptr;
uint8_t *slash;
char c;
uint16_tvfatname[WIN_MAXLEN+2*WIN_CHARS];
uint16_t ucsname[WIN_MAXLEN+1];
uint16_t ucslen;
int ucslenhost;
initRoot (&st);
st.buf = (struct direntry *)buf;
ptr=(uint8_t*)dirspec;
for (slash=ptr;*slash && *slash!='/';slash++);
c=*slash;
*slash=0;
utf_decodestr (ptr, ucsname, &ucslen, WIN_MAXLEN, OSLittleEndian);
ucslenhost = OSReadLittleInt16 (&ucslen,0);
ucsname[ucslenhost]=0;
*slash=c;
while ((dirp = getnextdirent (ih, vfatname, &st)))
{
if (checkname (ucsname, ucslenhost, dirp, vfatname))
{
for (;*ptr && *ptr!='/';ptr++);
if (!*ptr)
return dirp;
ptr++;
if (!*ptr)
return dirp;
for (slash=ptr;*slash && *slash!='/';slash++);
c=*slash;
*slash=0;
utf_decodestr (ptr, ucsname, &ucslen, WIN_MAXLEN, OSLittleEndian);
ucslenhost = OSReadLittleInt16 (&ucslen,0);
ucsname[ucslenhost]=0;
*slash=c;
if (!(dirp->deAttributes & ATTR_DIRECTORY))
return 0;
st.root16 = 0;
st.vfatchecksum = 0;
st.nument = 0;
st.cluster = OSReadLittleInt16 ((dirp->deStartCluster),0);
if (msdosfatbits == 32)
st.cluster |= ((uint32_t)OSReadLittleInt16 ((dirp->deHighClust),0)) <<16;
st.vfatnumber = 0;
}
}
return 0;
}
long MSDOSGetDirEntry(CICell ih, char * dirPath, long long * dirIndex,
char ** name, long * flags, long * time,
FinderInfo * finderInfo, long * infoValid)
{
struct msdosdirstate *st;
struct direntry *dirp;
uint16_tvfatname[WIN_MAXLEN+2*WIN_CHARS];
if (MSDOSInitPartition (ih)<0)
return -1;
if (dirPath[0] == '/')
dirPath++;
st = (struct msdosdirstate *)(long) *dirIndex;
if (!st)
{
st=malloc (sizeof (*st));
if (dirPath[0])
{
uint8_t *buf=malloc(msdosclustersize);
dirp = getdirpfrompath (ih, dirPath, buf);
if (!dirp || !(dirp->deAttributes & ATTR_DIRECTORY))
{
free (buf);
free (st);
return -1;
}
st->buf = (struct direntry *)buf;
st->root16 = 0;
st->vfatchecksum = 0;
st->nument = 0;
st->cluster = OSReadLittleInt16 ((dirp->deStartCluster),0);
st->vfatnumber = 0;
if (msdosfatbits == 32)
st->cluster |= ((uint32_t)OSReadLittleInt16 ((dirp->deHighClust),0)) <<16;
}
else
initRoot (st);
*dirIndex = (long long) (long) st;
}
while((dirp = getnextdirent (ih, vfatname, st))&& (dirp->deAttributes & ATTR_VOLUME));
if (!dirp)
{
free (st->buf);
free (st);
return -1;
}
if (vfatname[0])
{
int i;
for (i=0;vfatname[i];i++);
*name = malloc (256);
utf_encodestr(vfatname, i, (u_int8_t *)*name, 255, OSLittleEndian );
}
else
{
int i, j, k;
uint16_t tmp[13];
*name = malloc (26);
for (i=7;i>=0;i--)
if (dirp->deName[i]!=' ')
break;
j=i+1;
tmp[i+1]=0;
for(;i>=0;i--)
tmp[i]=(dirp->deName[i]>=128)?cp850[dirp->deName[i]-128][0]:tolower(dirp->deName[i]);
for (i=2;i>=0;i--)
if (dirp->deName[8+i]!=' ')
break;
if (i>=0)
{
tmp[j++]='.';
tmp[j+i+1]=0;
k=j+i+1;
for(;i>=0;i--)
tmp[j+i]=(dirp->deName[i]>=128)?cp850[dirp->deName[i+8]-128][0]:tolower(dirp->deName[i+8]);
j=k;
}
utf_encodestr(tmp, j, (uint8_t*)*name, 25, OSHostByteOrder() );
}
if (dirp->deAttributes & ATTR_DIRECTORY)
*flags = kFileTypeDirectory;
else
*flags = kFileTypeFlat;
// Calculate a fake timestamp using modification date and time values.
*time = (dirp->deMDate & 0x7FFF) << 16 + dirp->deMTime;
if (infoValid)
*infoValid = 1;
return 0;
}
long
MSDOSReadFile(CICell ih, char * filePath, void *base, uint64_t offset, uint64_t length)
{
uint8_t *buf;
off_t cluster;
uint64_t size;
uint64_t nskip;
int toread, wastoread;
char *ptr = (char *)base;
struct direntry *dirp;
int i;
char devStr[12];
if (MSDOSInitPartition (ih)<0)
return -1;
if (filePath[0] == '/')
filePath++;
buf = malloc(msdosclustersize);
dirp = getdirpfrompath (ih, filePath, buf);
if (!dirp || (dirp->deAttributes & ATTR_DIRECTORY))
{
free (buf);
return -1;
}
cluster = OSReadLittleInt16 ((dirp->deStartCluster),0);
if (msdosfatbits == 32)
cluster |= ((uint32_t)OSReadLittleInt16 ((dirp->deHighClust),0)) <<16;
size = (uint32_t)OSReadLittleInt32 ((dirp->deFileSize),0);
if (size<=offset)
return -1;
nskip=offset/msdosclustersize;
for (i=0;i<nskip;i++)
msdosreadcluster (ih, 0, 0, &cluster);
msdosreadcluster (ih, buf, msdosclustersize, &cluster);
toread=length;
if (length==0 || length>size-offset)
toread=size-offset;
wastoread=toread;
bcopy (buf+(offset%msdosclustersize),ptr,MIN(msdosclustersize-(offset%msdosclustersize), toread));
ptr+=msdosclustersize-(offset%msdosclustersize);
toread-=msdosclustersize-(offset%msdosclustersize);
while (toread>0 && msdosreadcluster (ih, (uint8_t *)ptr, MIN(msdosclustersize,toread), &cluster))
{
ptr+=msdosclustersize;
toread-=msdosclustersize;
}
getDeviceDescription(ih, devStr);
verbose("Read FAT%d file: [%s/%s] %d bytes.\n",
msdosfatbits, devStr, filePath, (uint32_t)( toread<0 ) ? wastoread : wastoread-toread);
free (buf);
if (toread<0)
return wastoread;
else
return wastoread-toread;
}
long
MSDOSGetFileBlock(CICell ih, char *filePath, unsigned long long *firstBlock)
{
uint8_t *buf;
off_t cluster;
struct direntry *dirp;
if (MSDOSInitPartition (ih)<0)
return -1;
if (filePath[0] == '/')
filePath++;
buf = malloc(msdosclustersize);
dirp = getdirpfrompath (ih, filePath, buf);
if (!dirp || (dirp->deAttributes & ATTR_DIRECTORY))
{
free (buf);
return -1;
}
cluster = OSReadLittleInt16 ((dirp->deStartCluster),0);
if (msdosfatbits == 32)
cluster |= ((uint32_t)OSReadLittleInt16 ((dirp->deHighClust),0)) <<16;
off_t clusn;
switch (msdosfatbits) {
case 32:
if (cluster < CLUST_FIRST ||cluster >= CLUST_RSRVD32)
return -1;
clusn = cluster - CLUST_FIRST;
break;
case 16:
if (cluster < CLUST_FIRST ||cluster >= CLUST_RSRVD16)
return 0;
clusn = cluster - CLUST_FIRST;
break;
case 12:
if (cluster < CLUST_FIRST ||cluster >= CLUST_RSRVD12)
return 0;
clusn = cluster - CLUST_FIRST;
break;
default:
return 0;
}
*firstBlock = ((msdosressector +
(msdosnfats * msdosfatsecs))*msdosbps + clusn * msdosclustersize)/512;
free (buf);
return 0;
}
long MSDOSLoadFile(CICell ih, char * filePath)
{
return MSDOSReadFile(ih, filePath, (void *)gFSLoadAddress, 0, 0);
}
/* Fix up volume label. */
static void
fixLabel(uint8_t *label, char *str, long strMaxLen)
{
inti, len;
uint16_tlabelucs[13];
//unsigned charlabelUTF8[LABEL_LENGTH*3];
/* Convert leading 0x05 to 0xE5 for multibyte languages like Japanese */
if (label[0] == 0x05)
label[0] = 0xE5;
/* Remove any trailing spaces */
for (i=LABEL_LENGTH-1; i>=0; --i) {
if (label[i] == ' ')
label[i] = 0;
else
break;
}
labelucs[i++]=0;
len=i;
for (;i>=0;--i)
labelucs[i]=label[i]>=128?cp850[label[i]-128][1]:(label[i]);
utf_encodestr(labelucs, len, (uint8_t *)str, strMaxLen, OSHostByteOrder() );
}
void
MSDOSGetDescription(CICell ih, char *str, long strMaxLen)
{
struct direntry *dirp;
uint8_t label[LABEL_LENGTH+1];
uint16_tvfatlabel[WIN_MAXLEN+2*WIN_CHARS];
struct msdosdirstate st;
int labelfound = 0;
if (MSDOSInitPartition (ih)<0)
{
str[0]=0;
return;
}
label[0] = '\0';
initRoot (&st);
st.buf = malloc(msdosclustersize);
while ((dirp = getnextdirent (ih, vfatlabel, &st)))
if (dirp->deAttributes & ATTR_VOLUME) {
strncpy((char *)label, (char *)dirp->deName, LABEL_LENGTH);
labelfound = 1;
break;
}
free(st.buf);
if (vfatlabel[0] && labelfound)
{
int i;
for (i=0;vfatlabel[i];i++);
utf_encodestr(vfatlabel, i, (u_int8_t *)str, strMaxLen, OSLittleEndian );
}
else if (labelfound)
fixLabel(label, str, strMaxLen);
/* else look in the boot blocks */
if (!labelfound || str[0] == '\0') {
char *buf = malloc (512);
union bootsector *bsp = (union bootsector *)buf;
Seek(ih, 0);
Read(ih, (long)buf, 512);
if (msdosfatbits == 32) { /* It's FAT32 */
strncpy((char *)label, (char *)((struct extboot *)bsp->bs710.bsExt)->exVolumeLabel, LABEL_LENGTH);
}
else if (msdosfatbits == 16) {
strncpy((char *)label, (char *)((struct extboot *)bsp->bs50.bsExt)->exVolumeLabel, LABEL_LENGTH);
}
free (buf);
fixLabel(label, str, strMaxLen);
}
return;
}
long
MSDOSGetUUID(CICell ih, char *uuidStr)
{
char *buf = malloc (512);
union bootsector *bsp = (union bootsector *)buf;
if (MSDOSInitPartition (ih)<0)
{
return -1;
}
bzero (uuidStr, 16);
Seek(ih, 0);
Read(ih, (long)buf, 512);
if (msdosfatbits == 32) { /* It's FAT32 */
memcpy(uuidStr+12, (char *)((struct extboot *)bsp->bs710.bsExt)->exVolumeID, 4);
}
else if (msdosfatbits == 16) {
memcpy(uuidStr+12, (char *)((struct extboot *)bsp->bs50.bsExt)->exVolumeID, 4);
}
free (buf);
return 0;
}
branches/rewrite/i386/libsaio/msdos.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) 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 MSDOSGetDescription(CICell ih, char *str, long strMaxLen);
extern long MSDOSInitPartition(CICell ih);
extern long MSDOSLoadFile(CICell ih, char * filePath);
extern long MSDOSReadFile(CICell ih, char * filePath, void *base, uint64_t offset, uint64_t length);
extern long MSDOSGetDirEntry(CICell ih, char * dirPath, long long * dirIndex,
char ** name, long * flags, long * time,
FinderInfo * finderInfo, long * infoValid);
extern long MSDOSGetFileBlock(CICell ih, char *str, unsigned long long *firstBlock);
extern long MSDOSGetUUID(CICell ih, char *uuidStr);
extern void MSDOSFree(CICell ih);
extern int MSDOSProbe (const void *buf);
branches/rewrite/i386/libsaio/sys.c
762762
763763
764764
765
765
766766
767
768
769
770
771
767
772768
773
774
775
776
777769
778770
779771
......
792784
793785
794786
795
796
797
798
799
800
801787
802788
803789
BVRef bvr = 0;
bvr = diskScanBootVolumes(biosdev, count);
if (bvr == NULL)
if (bvr != NULL)
{
bvr = nbpScanBootVolumes(biosdev, count);
if (bvr != NULL)
{
gBootFileType = kNetworkDeviceType;
}
gBootFileType = kBlockDeviceType;
}
else
{
gBootFileType = kBlockDeviceType;
}
}
//==========================================================================
hd++;
}
// Also scanning CD/DVD drive.
if (biosDevIsCDROM(gBIOSDev))
{
bvCount = 0;
scanBootVolumes(gBIOSDev, &bvCount);
}
}
//==========================================================================
branches/rewrite/i386/libsaio/saio_types.h
3030
3131
3232
33
3433
3534
3635
#include <sys/types.h>
#include <sys/param.h>
#include "bios.h"
#include "nbp_cmd.h"
#include "bootargs.h"
#if DEBUG
branches/rewrite/i386/libsaio/Makefile
2929
3030
3131
32
33
34
35
36
32
33
34
35
36
3737
3838
3939
INC = -I. -I$(SYMROOT) -I$(LIBSADIR) -I$(BOOT2DIR) -I${SRCROOT}/i386/include
SAIO_OBJS = table.o asm.o bios.o biosfn.o \
disk.o sys.o cache.o \
stringTable.o misc.o \
vbe.o nbp.o hfs.o hfs_compare.o \
xml.o ntfs.o msdos.o md5c.o \
ext2fs.o load.o\
cache.o \
misc.o \
vbe.o \
xml.o md5c.o \
load.o\
console.o
LIBS = libsaio.a
branches/rewrite/i386/libsaio/saio_internal.h
3232
3333
3434
35
35
3636
3737
3838
......
7272
7373
7474
75
76
77
78
79
80
8175
8276
8377
......
141135
142136
143137
144
145
146
147
148138
149139
150140
extern void prot_to_real(void);
extern void halt(void);
extern void startprog(unsigned int address, void *arg);
extern void loader(UInt32 code, UInt32 cmdptr);
//extern void loader(UInt32 code, UInt32 cmdptr);
/* bios.s */
extern void bios(biosBuf_t *bb);
extern unsigned long getConventionalMemorySize();
extern void sleep(int n);
/* bootstruct.c */
extern void initKernBootStruct(void);
extern void reserveKernBootStruct(void);
extern void copyKernBootStruct(void);
extern void finalizeBootStruct(void);
/* cache.c */
extern void CacheReset();
extern void CacheInit(CICell ih, long blockSize);
extern int isLaptop();
extern void getPlatformName(char *nameBuf);
/* nbp.c */
extern UInt32 nbpUnloadBaseCode();
extern BVRef nbpScanBootVolumes(int biosdev, int *count);
/* stringTable.c */
extern char * newStringFromList(char **list, int *size);
extern int stringLength(const char *table, int compress);
branches/rewrite/i386/boot2/modules_support.s
1
2
3
4
5
6
7
8
9
10
#ifdef CONFIG_MODULES
#include <architecture/i386/asm_help.h>
LABEL(dyld_stub_binder)
jmp_dyld_stub_binder
LABEL(dyld_void_start)
ret
#endif
branches/rewrite/i386/boot2/modules.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
/*
* Copyright 2010 Evan Lojewski. All rights reserved.
*
*/
#ifdef CONFIG_MODULES
#ifndef CONFIG_MODULE_DEBUG
#define CONFIG_MODULE_DEBUG 0
#endif
#include "boot.h"
#include "modules.h"
#include "boot_modules.h"
#include <vers.h>
#if CONFIG_MODULE_DEBUG
#define DBG(x...)printf(x);
#define DBGPAUSE()getchar()
#else
#define DBG(x...)
#define DBGPAUSE()
#endif
// NOTE: Global so that modules can link with this
UInt64 textAddress = 0;
UInt64 textSection = 0;
void* symbols_module_start = (void*)0xFFFFFFFF;// Global, value is populated by the makefile with actual address
/** Internal symbols, however there are accessor methods **/
moduleHook_t* moduleCallbacks = NULL;
moduleList_t* loadedModules = NULL;
symbolList_t* moduleSymbols = NULL;
unsigned int (*lookup_symbol)(const char*) = NULL;
/*
* Initialize the module system by loading the Symbols.dylib module.
* Once loaded, locate the _lookup_symbol function so that internal
* symbols can be resolved.
*/
int init_module_system()
{
// Start any modules that were compiled in first.
start_built_in_modules();
int retVal = 0;
void (*module_start)(void) = NULL;
char* module_data = symbols_module_start + BOOT2_ADDR;
// Intialize module system
if(symbols_module_start != (void*)0xFFFFFFFF)
{
// Module system was compiled in (Symbols.dylib addr known)
module_start = parse_mach(module_data, &load_module, &add_symbol, NULL);
if(module_start && module_start != (void*)0xFFFFFFFF)
{
// Notify the system that it was laoded
module_loaded(SYMBOLS_MODULE, SYMBOLS_AUTHOR, SYMBOLS_DESCRIPTION, SYMBOLS_VERSION, SYMBOLS_COMPAT);
(*module_start)();// Start the module. This will point to load_all_modules due to the way the dylib was constructed.
execute_hook("ModulesLoaded", NULL, NULL, NULL, NULL);
DBG("Module %s Loaded.\n", SYMBOLS_MODULE);
retVal = 1;
}
else
{
module_data -= 0x10; // XCODE 4 HACK
module_start = parse_mach(module_data, &load_module, &add_symbol, NULL);
if(module_start && module_start != (void*)0xFFFFFFFF)
{
// Notify the system that it was laoded
module_loaded(SYMBOLS_MODULE, SYMBOLS_AUTHOR, SYMBOLS_DESCRIPTION, SYMBOLS_VERSION, SYMBOLS_COMPAT);
(*module_start)();// Start the module. This will point to load_all_modules due to the way the dylib was constructed.
execute_hook("ModulesLoaded", NULL, NULL, NULL, NULL);
DBG("Module %s Loaded.\n", SYMBOLS_MODULE);
retVal = 1;
}
else
{
// The module does not have a valid start function
printf("Unable to start %s\n", SYMBOLS_MODULE); getchar();
}
}
}
return retVal;
}
void start_built_in_module(const char* name,
const char* author,
const char* description,
UInt32 version,
UInt32 compat,
void(*start_function)(void))
{
start_function();
// Notify the module system that this module really exists, specificaly, let other module link with it
module_loaded(name, author, description, version, compat);
}
/*
* Load all modules in the /Extra/modules/ directory
* Module depencdies will be loaded first
* Modules will only be loaded once. When loaded a module must
* setup apropriete function calls and hooks as required.
* NOTE: To ensure a module loads after another you may
* link one module with the other. For dyld to allow this, you must
* reference at least one symbol within the module.
*/
void load_all_modules()
{
char* name;
long flags;
long time;
struct dirstuff* moduleDir = opendir("/Extra/modules/");
while(readdir(moduleDir, (const char**)&name, &flags, &time) >= 0)
{
if(strcmp(&name[strlen(name) - sizeof("dylib")], ".dylib") == 0)
{
char* tmp = malloc(strlen(name) + 1);
strcpy(tmp, name);
if(!load_module(tmp))
{
// failed to load
// free(tmp);
}
}
else
{
DBG("Ignoring %s\n", name);
}
}
}
/*
* Load a module file in /Extra/modules/
*/
int load_module(char* module)
{
int retVal = 1;
void (*module_start)(void) = NULL;
char modString[128];
int fh = -1;
// Check to see if the module has already been loaded
if(is_module_loaded(module))
{
return 1;
}
sprintf(modString, MODULE_PATH "%s", module);
fh = open(modString, 0);
if(fh < 0)
{
DBG("WARNING: Unable to locate module %s\n", modString); DBGPAUSE();
return 0;
}
unsigned int moduleSize = file_size(fh);
char* module_base = (char*) malloc(moduleSize);
if (moduleSize && read(fh, module_base, moduleSize) == moduleSize)
{
// Module loaded into memory, parse it
module_start = parse_mach(module_base, &load_module, &add_symbol, NULL);
if(module_start && module_start != (void*)0xFFFFFFFF)
{
// Notify the system that it was laoded
module_loaded(module, NULL, NULL, 0, 0 /*moduleName, moduleVersion, moduleCompat*/);
(*module_start)();// Start the module
DBG("Module %s Loaded.\n", module); DBGPAUSE();
}
#if CONFIG_MODULE_DEBUG
else // The module does not have a valid start function. This may be a library.
{
printf("WARNING: Unable to start %s\n", module);
getchar();
}
#else
else msglog("WARNING: Unable to start %s\n", module);
#endif
}
else
{
DBG("Unable to read in module %s\n.", module); DBGPAUSE();
retVal = 0;
}
close(fh);
return retVal;
}
/*
* add_symbol
* This function adds a symbol from a module to the list of known symbols
* possibly change to a pointer and add this to the Symbol module so that it can
* adjust it's internal symbol list (sort) to optimize locating new symbols
* NOTE: returns the address if the symbol is "start", else returns 0xFFFFFFFF
*/
long long add_symbol(char* symbol, long long addr, char is64)
{
if(is64) return 0xFFFFFFFF; // Fixme
// This only can handle 32bit symbols
symbolList_t* entry;
//DBG("Adding symbol %s at 0x%X\n", symbol, addr);
entry = malloc(sizeof(symbolList_t));
entry->next = moduleSymbols;
moduleSymbols = entry;
entry->addr = (UInt32)addr;
entry->symbol = symbol;
if(strcmp(symbol, "start") == 0)
{
return addr;
}
else
{
return 0xFFFFFFFF; // fixme
}
}
/*
* print out the information about the loaded module
*/
void module_loaded(const char* name, const char* author, const char* description, UInt32 version, UInt32 compat)
{
moduleList_t* new_entry = malloc(sizeof(moduleList_t));
new_entry->next = loadedModules;
loadedModules = new_entry;
if(!name) name = "Unknown";
if(!author) author = "Unknown";
if(!description) description = "";
new_entry->name = name;
new_entry->author = author;
new_entry->description = description;
new_entry->version = version;
new_entry->compat = compat;
msglog("Module '%s' by '%s' Loaded.\n", name, author);
msglog("\tDescription: %s\n", description);
msglog("\tVersion: %d\n", version); // todo: sperate to major.minor.bugfix
msglog("\tCompat: %d\n", compat); // todo: ^^^ major.minor.bugfix
}
int is_module_loaded(const char* name)
{
// todo sorted search
moduleList_t* entry = loadedModules;
while(entry)
{
if(strcmp(entry->name, name) == 0)
{
DBG("Located module %s\n", name); DBGPAUSE();
return 1;
}
else
{
entry = entry->next;
}
}
DBG("Module %s not found\n", name); DBGPAUSE();
return 0;
}
/*
*lookup symbols in all loaded modules. Thins inludes boot syms due to Symbols.dylib construction
*
*/
unsigned int lookup_all_symbols(const char* name)
{
symbolList_t* entry = moduleSymbols;
while(entry)
{
if(strcmp(entry->symbol, name) == 0)
{
//DBG("External symbol %s located at 0x%X\n", name, entry->addr);
return entry->addr;
}
else
{
entry = entry->next;
}
}
#if CONFIG_MODULE_DEBUG
printf("Unable to locate symbol %s\n", name);
getchar();
#endif
if(strcmp(name, VOID_SYMBOL) == 0) return 0xFFFFFFFF;
// In the event that a symbol does not exist
// Return a pointer to a void function.
else return lookup_all_symbols(VOID_SYMBOL);
}
/********************************************************************************/
/*Macho Parser*/
/********************************************************************************/
/*
* Parse through a macho module. The module will be rebased and binded
* as specified in the macho header. If the module is sucessfuly laoded
* the module iinit address will be returned.
* NOTE; all dependecies will be loaded before this module is started
* NOTE: If the module is unable to load ot completeion, the modules
* symbols will still be available.
*/
void* parse_mach(void* binary,
int(*dylib_loader)(char*),
long long(*symbol_handler)(char*, long long, char),
void (*section_handler)(char* section, char* segment, long long offset, long long address)
)
{
char is64 = false;
void (*module_start)(void) = NULL;
// Module info
/*char* moduleName = NULL;
UInt32 moduleVersion = 0;
UInt32 moduleCompat = 0;
*/
// TODO convert all of the structs to a union
struct load_command *loadCommand = NULL;
struct dylib_command* dylibCommand = NULL;
struct dyld_info_command* dyldInfoCommand = NULL;
struct symtab_command* symtabCommand = NULL;
struct segment_command *segCommand = NULL;
struct segment_command_64 *segCommand64 = NULL;
//struct dysymtab_command* dysymtabCommand = NULL;
UInt32 binaryIndex = 0;
UInt16 cmd = 0;
textSection = 0;
textAddress = 0;// reinitialize text location in case it doesn't exist;
// Parse through the load commands
if(((struct mach_header*)binary)->magic == MH_MAGIC)
{
is64 = false;
binaryIndex += sizeof(struct mach_header);
}
else if(((struct mach_header_64*)binary)->magic == MH_MAGIC_64)
{
// NOTE: modules cannot be 64bit...
is64 = true;
binaryIndex += sizeof(struct mach_header_64);
}
else
{
verbose("Invalid mach magic 0x%X\n", ((struct mach_header*)binary)->magic);
//getchar();
return NULL;
}
/*if(((struct mach_header*)binary)->filetype != MH_DYLIB)
{
printf("Module is not a dylib. Unable to load.\n");
getchar();
return NULL; // Module is in the incorrect format
}*/
while(cmd < ((struct mach_header*)binary)->ncmds)
{
cmd++;
loadCommand = binary + binaryIndex;
UInt32 cmdSize = loadCommand->cmdsize;
switch ((loadCommand->cmd & 0x7FFFFFFF))
{
case LC_SYMTAB:
symtabCommand = binary + binaryIndex;
break;
case LC_SEGMENT: // 32bit macho
{
segCommand = binary + binaryIndex;
UInt32 sectionIndex;
sectionIndex = sizeof(struct segment_command);
struct section *sect;
while(sectionIndex < segCommand->cmdsize)
{
sect = binary + binaryIndex + sectionIndex;
sectionIndex += sizeof(struct section);
if(section_handler) section_handler(sect->sectname, segCommand->segname, sect->offset, sect->addr);
if((strcmp("__TEXT", segCommand->segname) == 0) && (strcmp("__text", sect->sectname) == 0))
{
// __TEXT,__text found, save the offset and address for when looking for the calls.
textSection = sect->offset;
textAddress = sect->addr;
}
}
}
break;
case LC_SEGMENT_64:// 64bit macho's
{
segCommand64 = binary + binaryIndex;
UInt32 sectionIndex;
sectionIndex = sizeof(struct segment_command_64);
struct section_64 *sect;
while(sectionIndex < segCommand64->cmdsize)
{
sect = binary + binaryIndex + sectionIndex;
sectionIndex += sizeof(struct section_64);
if(section_handler) section_handler(sect->sectname, segCommand->segname, sect->offset, sect->addr);
if((strcmp("__TEXT", segCommand->segname) == 0) && (strcmp("__text", sect->sectname) == 0))
{
// __TEXT,__text found, save the offset and address for when looking for the calls.
textSection = sect->offset;
textAddress = sect->addr;
}
}
}
break;
case LC_LOAD_DYLIB:
case LC_LOAD_WEAK_DYLIB ^ LC_REQ_DYLD:
dylibCommand = binary + binaryIndex;
char* module = binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
// Possible enhancments: verify version
// =dylibCommand->dylib.current_version;
// =dylibCommand->dylib.compatibility_version;
if(dylib_loader)
{
char* name = malloc(strlen(module) + strlen(".dylib") + 1);
sprintf(name, "%s.dylib", module);
if (!dylib_loader(name))
{
// NOTE: any symbols exported by dep will be replace with the void function
free(name);
}
}
break;
case LC_ID_DYLIB:
dylibCommand = binary + binaryIndex;
/*moduleName =binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
moduleVersion =dylibCommand->dylib.current_version;
moduleCompat =dylibCommand->dylib.compatibility_version;
*/
break;
case LC_DYLD_INFO:
//case LC_DYLD_INFO_ONLY:// compressed info, 10.6+ macho files, already handeled
// Bind and rebase info is stored here
dyldInfoCommand = binary + binaryIndex;
break;
case LC_DYSYMTAB:
case LC_UUID:
case LC_UNIXTHREAD:
break;
default:
DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);
break;
}
binaryIndex += cmdSize;
}
// bind_macho uses the symbols, if the textAdd does not exist (Symbols.dylib, no code), addresses are static and not relative
module_start = (void*)handle_symtable((UInt32)binary, symtabCommand, symbol_handler, is64);
if(dyldInfoCommand)
{
// Rebase the module before binding it.
if(dyldInfoCommand->rebase_off)rebase_macho(binary, (char*)dyldInfoCommand->rebase_off,dyldInfoCommand->rebase_size);
// Bind all symbols.
if(dyldInfoCommand->bind_off)bind_macho(binary, (UInt8*)dyldInfoCommand->bind_off,dyldInfoCommand->bind_size);
if(dyldInfoCommand->weak_bind_off)bind_macho(binary, (UInt8*)dyldInfoCommand->weak_bind_off,dyldInfoCommand->weak_bind_size);
if(dyldInfoCommand->lazy_bind_off)bind_macho(binary, (UInt8*)dyldInfoCommand->lazy_bind_off,dyldInfoCommand->lazy_bind_size);
}
return module_start;
}
/*
* parse the symbol table
* Lookup any undefined symbols
*/
unsigned int handle_symtable(UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, long long, char), char is64)
{
unsigned int module_start= 0xFFFFFFFF;
UInt32 symbolIndex= 0;
char* symbolString= base + (char*)symtabCommand->stroff;
if(!is64)
{
struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;
while(symbolIndex < symtabCommand->nsyms)
{
// If the symbol is exported by this module
if(symbolEntry->n_value &&
symbol_handler(symbolString + symbolEntry->n_un.n_strx, textAddress ? (long long)base + symbolEntry->n_value : symbolEntry->n_value, is64) != 0xFFFFFFFF)
{
// Module start located. Start is an alias so don't register it
module_start = textAddress ? base + symbolEntry->n_value : symbolEntry->n_value;
}
symbolEntry++;
symbolIndex++;// TODO remove
}
}
else
{
struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;
// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now, verify later)
while(symbolIndex < symtabCommand->nsyms)
{
// If the symbol is exported by this module
if(symbolEntry->n_value &&
symbol_handler(symbolString + symbolEntry->n_un.n_strx, textAddress ? (long long)base + symbolEntry->n_value : symbolEntry->n_value, is64) != 0xFFFFFFFF)
{
// Module start located. Start is an alias so don't register it
module_start = textAddress ? base + symbolEntry->n_value : symbolEntry->n_value;
}
symbolEntry++;
symbolIndex++;// TODO remove
}
}
return module_start;
}
// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
void rebase_macho(void* base, char* rebase_stream, UInt32 size)
{
rebase_stream += (UInt32)base;
UInt8 immediate = 0;
UInt8 opcode = 0;
UInt8 type = 0;
UInt32 segmentAddress = 0;
UInt32 tmp = 0;
UInt32 tmp2 = 0;
UInt8 bits = 0;
int index = 0;
unsigned int i = 0;
while(i < size)
{
immediate = rebase_stream[i] & REBASE_IMMEDIATE_MASK;
opcode = rebase_stream[i] & REBASE_OPCODE_MASK;
switch(opcode)
{
case REBASE_OPCODE_DONE:
// Rebase complete, reset vars
immediate = 0;
opcode = 0;
type = 0;
segmentAddress = 0;
default:
break;
case REBASE_OPCODE_SET_TYPE_IMM:
type = immediate;
break;
case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
// Locate address to begin rebasing
segmentAddress = 0;
struct segment_command* segCommand = NULL; // NOTE: 32bit only
unsigned int binIndex = 0;
index = 0;
do
{
segCommand = base + sizeof(struct mach_header) + binIndex;
binIndex += segCommand->cmdsize;
index++;
}
while(index <= immediate);
segmentAddress = segCommand->fileoff;
tmp = 0;
bits = 0;
do
{
tmp |= (rebase_stream[++i] & 0x7f) << bits;
bits += 7;
}
while(rebase_stream[i] & 0x80);
segmentAddress += tmp;
break;
case REBASE_OPCODE_ADD_ADDR_ULEB:
// Add value to rebase address
tmp = 0;
bits = 0;
do
{
tmp <<= bits;
tmp |= rebase_stream[++i] & 0x7f;
bits += 7;
}
while(rebase_stream[i] & 0x80);
segmentAddress +=tmp;
break;
case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
segmentAddress += immediate * sizeof(void*);
break;
case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
index = 0;
for (index = 0; index < immediate; ++index) {
rebase_location(base + segmentAddress, (char*)base, type);
segmentAddress += sizeof(void*);
}
break;
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
tmp = 0;
bits = 0;
do
{
tmp |= (rebase_stream[++i] & 0x7f) << bits;
bits += 7;
}
while(rebase_stream[i] & 0x80);
index = 0;
for (index = 0; index < tmp; ++index) {
//DBG("\tRebasing 0x%X\n", segmentAddress);
rebase_location(base + segmentAddress, (char*)base, type);
segmentAddress += sizeof(void*);
}
break;
case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
tmp = 0;
bits = 0;
do
{
tmp |= (rebase_stream[++i] & 0x7f) << bits;
bits += 7;
}
while(rebase_stream[i] & 0x80);
rebase_location(base + segmentAddress, (char*)base, type);
segmentAddress += tmp + sizeof(void*);
break;
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
tmp = 0;
bits = 0;
do
{
tmp |= (rebase_stream[++i] & 0x7f) << bits;
bits += 7;
}
while(rebase_stream[i] & 0x80);
tmp2 = 0;
bits = 0;
do
{
tmp2 |= (rebase_stream[++i] & 0x7f) << bits;
bits += 7;
}
while(rebase_stream[i] & 0x80);
index = 0;
for (index = 0; index < tmp; ++index) {
rebase_location(base + segmentAddress, (char*)base, type);
segmentAddress += tmp2 + sizeof(void*);
}
break;
}
i++;
}
}
inline void rebase_location(UInt32* location, char* base, int type)
{
switch(type)
{
case REBASE_TYPE_POINTER:
case REBASE_TYPE_TEXT_ABSOLUTE32:
*location += (UInt32)base;
break;
default:
break;
}
}
UInt32 read_uleb(UInt8* bind_stream, unsigned int* i)
{
// Read in offset
UInt32 tmp = 0;
UInt8 bits = 0;
do
{
if(bits < sizeof(UInt32)*8) // hack
{
tmp |= (bind_stream[++(*i)] & 0x7f) << bits;
bits += 7;
}
else
{
++(*i);
}
}
while(bind_stream[*i] & 0x80);
return tmp;
}
// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
// NOTE: this uses 32bit values, and not 64bit values.
// There is a possibility that this could cause issues,
// however the modules are 32 bits, so it shouldn't matter too much
void bind_macho(void* base, UInt8* bind_stream, UInt32 size)
{
bind_stream += (UInt32)base;
UInt8 immediate = 0;
UInt8 opcode = 0;
UInt8 type = BIND_TYPE_POINTER;
UInt32 segmentAddress = 0;
UInt32 address = 0;
SInt32 addend = 0;
SInt32 libraryOrdinal = 0;
const char* symbolName = NULL;
UInt8 symboFlags = 0;
UInt32 symbolAddr = 0xFFFFFFFF;
// Temperary variables
UInt32 tmp = 0;
UInt32 tmp2 = 0;
UInt32 index = 0;
unsigned int i = 0;
while(i < size)
{
immediate = bind_stream[i] & BIND_IMMEDIATE_MASK;
opcode = bind_stream[i] & BIND_OPCODE_MASK;
switch(opcode)
{
case BIND_OPCODE_DONE:
// reset vars
type = BIND_TYPE_POINTER;
segmentAddress = 0;
address = 0;
addend = 0;
libraryOrdinal = 0;
symbolAddr = 0xFFFFFFFF;
default:
break;
case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
libraryOrdinal = immediate;
break;
case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
libraryOrdinal = read_uleb(bind_stream, &i);
break;
case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
libraryOrdinal = immediate ? (SInt8)(BIND_OPCODE_MASK | immediate) : immediate;
break;
case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
symboFlags = immediate;
symbolName = (char*)&bind_stream[++i];
i += strlen((char*)&bind_stream[i]);
symbolAddr = lookup_all_symbols(symbolName);
break;
case BIND_OPCODE_SET_TYPE_IMM:
type = immediate;
break;
case BIND_OPCODE_SET_ADDEND_SLEB:
addend = read_uleb(bind_stream, &i);
if(!(bind_stream[i-1] & 0x40)) addend *= -1;
break;
case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
segmentAddress = 0;
// Locate address
struct segment_command* segCommand = NULL;// NOTE: 32bit only
unsigned int binIndex = 0;
index = 0;
do
{
segCommand = base + sizeof(struct mach_header) + binIndex;
binIndex += segCommand->cmdsize;
index++;
}
while(index <= immediate);
segmentAddress = segCommand->fileoff;
segmentAddress += read_uleb(bind_stream, &i);
break;
case BIND_OPCODE_ADD_ADDR_ULEB:
segmentAddress += read_uleb(bind_stream, &i);
break;
case BIND_OPCODE_DO_BIND:
if(symbolAddr != 0xFFFFFFFF)
{
address = segmentAddress + (UInt32)base;
bind_location((UInt32*)address, (char*)symbolAddr, addend, type);
}
else
{
printf("Unable to bind symbol %s\n", symbolName);
getchar();
}
segmentAddress += sizeof(void*);
break;
case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
// Read in offset
tmp = read_uleb(bind_stream, &i);
if(symbolAddr != 0xFFFFFFFF)
{
address = segmentAddress + (UInt32)base;
bind_location((UInt32*)address, (char*)symbolAddr, addend, type);
}
else
{
printf("Unable to bind symbol %s\n", symbolName);
getchar();
}
segmentAddress += tmp + sizeof(void*);
break;
case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
if(symbolAddr != 0xFFFFFFFF)
{
address = segmentAddress + (UInt32)base;
bind_location((UInt32*)address, (char*)symbolAddr, addend, type);
}
else
{
printf("Unable to bind symbol %s\n", symbolName);
getchar();
}
segmentAddress += (immediate * sizeof(void*)) + sizeof(void*);
break;
case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
tmp = read_uleb(bind_stream, &i);
tmp2 = read_uleb(bind_stream, &i);
if(symbolAddr != 0xFFFFFFFF)
{
for(index = 0; index < tmp; index++)
{
address = segmentAddress + (UInt32)base;
bind_location((UInt32*)address, (char*)symbolAddr, addend, type);
segmentAddress += tmp2 + sizeof(void*);
}
}
else
{
printf("Unable to bind symbol %s\n", symbolName);
getchar();
}
break;
}
i++;
}
}
inline void bind_location(UInt32* location, char* value, UInt32 addend, int type)
{
// do actual update
char* newValue = value + addend;
switch (type) {
case BIND_TYPE_POINTER:
case BIND_TYPE_TEXT_ABSOLUTE32:
break;
case BIND_TYPE_TEXT_PCREL32:
newValue -= ((UInt32)location + 4);
break;
default:
return;
}
//DBG("Binding 0x%X to 0x%X (was 0x%X)\n", location, newValue, *location);
*location = (UInt32)newValue;
}
/********************************************************************************/
/*Module Hook Interface*/
/********************************************************************************/
/*
* Locate the symbol for an already loaded function and modify the beginning of
* the function to jump directly to the new one
* example: replace_function("_HelloWorld_start", &replacement_start);
*/
int replace_function(const char* symbol, void* newAddress)
{
UInt32* jumpPointer = malloc(sizeof(UInt32*));
UInt32 addr = lookup_all_symbols(symbol);
char* binary = (char*)addr;
if(addr != 0xFFFFFFFF)
{
//DBG("Replacing %s to point to 0x%x\n", symbol, newAddress);
*binary++ = 0xFF;// Jump
*binary++ = 0x25;// Long Jump
*((UInt32*)binary) = (UInt32)jumpPointer;
*jumpPointer = (UInt32)newAddress;
return 1;
}
return 0;
}
/*
*execute_hook( const char* name )
*name - Name of the module hook
*If any callbacks have been registered for this hook
*they will be executed now in the same order that the
*hooks were added.
*/
int execute_hook(const char* name, void* arg1, void* arg2, void* arg3, void* arg4)
{
DBG("Attempting to execute hook '%s'\n", name); DBGPAUSE();
moduleHook_t* hook = hook_exists(name);
if(hook)
{
// Loop through all callbacks for this module
callbackList_t* callbacks = hook->callbacks;
while(callbacks)
{
// Execute callback
callbacks->callback(arg1, arg2, arg3, arg4);
callbacks = callbacks->next;
}
DBG("Hook '%s' executed.\n", name); DBGPAUSE();
return 1;
}
else
{
// Callback for this hook doesn't exist;
DBG("No callbacks for '%s' hook.\n", name);
return 0;
}
}
/*
*register_hook_callback( const char* name, void(*callback)())
*name - Name of the module hook to attach to.
*callbacks - The funciton pointer that will be called when the
*hook is executed. When registering a new callback name, the callback is added sorted.
*NOTE: the hooks take four void* arguments.
*/
void register_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*))
{
DBG("Adding callback for '%s' hook.\n", name); DBGPAUSE();
moduleHook_t* hook = hook_exists(name);
if(hook)
{
// append
callbackList_t* newCallback = malloc(sizeof(callbackList_t));
newCallback->next = hook->callbacks;
hook->callbacks = newCallback;
newCallback->callback = callback;
}
else
{
// create new hook
moduleHook_t* newHook = malloc(sizeof(moduleHook_t));
newHook->name = name;
newHook->callbacks = malloc(sizeof(callbackList_t));
newHook->callbacks->callback = callback;
newHook->callbacks->next = NULL;
newHook->next = moduleCallbacks;
moduleCallbacks = newHook;
}
#if CONFIG_MODULE_DEBUG
//print_hook_list();
//getchar();
#endif
}
moduleHook_t* hook_exists(const char* name)
{
moduleHook_t* hooks = moduleCallbacks;
// look for a hook. If it exists, return the moduleHook_t*,
// If not, return NULL.
while(hooks)
{
if(strcmp(name, hooks->name) == 0)
{
//DBG("Located hook %s\n", name);
return hooks;
}
hooks = hooks->next;
}
//DBG("Hook %s does not exist\n", name);
return NULL;
}
#if CONFIG_MODULE_DEBUG
void print_hook_list()
{
printf("---Hook Table---\n");
moduleHook_t* hooks = moduleCallbacks;
while(hooks)
{
printf("Hook: %s\n", hooks->name);
hooks = hooks->next;
}
}
#endif
/********************************************************************************/
/*dyld / Linker Interface*/
/********************************************************************************/
void dyld_stub_binder()
{
printf("ERROR: dyld_stub_binder was called, should have been take care of by the linker.\n");
getchar();
}
#else /* CONFIG_MODULES */
int init_module_system()
{
return 0;
}
void load_all_modules()
{
}
int execute_hook(const char* name, void* arg1, void* arg2, void* arg3, void* arg4)
{
return 0;
}
#endif
branches/rewrite/i386/boot2/modules.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
/*
* Module Loading functionality
* Copyright 2009 Evan Lojewski. All rights reserved.
*
*/
#include <saio_types.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#ifndef __BOOT_MODULES_H
#define __BOOT_MODULES_H
#define MODULE_PATH"/Extra/modules/"
#define SYMBOLS_MODULE "Symbols.dylib"
#define SYMBOLS_AUTHOR "Chameleon"
#define SYMBOLS_DESCRIPTION "Chameleon symbols for linking"
#define SYMBOLS_VERSION 0
#define SYMBOLS_COMPAT 0
#define VOID_SYMBOL"dyld_void_start"
extern UInt64 textAddress;
extern UInt64 textSection;
typedef struct symbolList_t
{
char* symbol;
UInt64 addr;
struct symbolList_t* next;
} symbolList_t;
typedef struct callbackList_t
{
void(*callback)(void*, void*, void*, void*);
struct callbackList_t* next;
} callbackList_t;
typedef struct moduleHook_t
{
const char* name;
callbackList_t* callbacks;
struct moduleHook_t* next;
} moduleHook_t;
typedef struct modulesList_t
{
const char*name;
const char* author;
const char* description;
UInt32version;
UInt32compat;
struct modulesList_t* next;
} moduleList_t;
int init_module_system();
void load_all_modules();
void start_built_in_module(const char* name,
const char* author,
const char* description,
UInt32 version,
UInt32 compat,
void(*start_function)(void));
int load_module(char* module);
int is_module_loaded(const char* name);
void module_loaded(const char* name, const char* author, const char* description, UInt32 version, UInt32 compat);
/********************************************************************************/
/*Symbol Functions*/
/********************************************************************************/
long longadd_symbol(char* symbol, long long addr, char is64);
unsigned intlookup_all_symbols(const char* name);
/********************************************************************************/
/*Macho Parser*/
/********************************************************************************/
void*parse_mach(void* binary,
int(*dylib_loader)(char*),
long long(*symbol_handler)(char*, long long, char),
void (*section_handler)(char* section, char* segment, long long offset, long long address)
);
unsigned inthandle_symtable(UInt32 base,
struct symtab_command* symtabCommand,
long long(*symbol_handler)(char*, long long, char),
char is64);
voidrebase_macho(void* base, char* rebase_stream, UInt32 size);
inline voidrebase_location(UInt32* location, char* base, int type);
voidbind_macho(void* base, UInt8* bind_stream, UInt32 size);
inline voidbind_location(UInt32* location, char* value, UInt32 addend, int type);
/********************************************************************************/
/*Module Interface*/
/********************************************************************************/
intreplace_function(const char* symbol, void* newAddress);
intexecute_hook(const char* name, void*, void*, void*, void*);
voidregister_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*));
moduleHook_t*hook_exists(const char* name);
#if DEBUG_MODULES
voidprint_hook_list();
#endif
/********************************************************************************/
/*dyld Interface*/
/********************************************************************************/
void dyld_stub_binder();
#endif /* __BOOT_MODULES_H */
branches/rewrite/i386/boot2/mboot.c
4545
4646
4747
48
48
49
4950
5051
5152
52
53
54
5355
5456
5557
......
332334
333335
334336
335
336
337
338
337339
338340
339341
......
376378
377379
378380
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
422381
423382
424383
......
427386
428387
429388
430
389
431390
432391
433392
......
460419
461420
462421
463
464422
465423
466424
void chainLoad();
void waitThenReload();
int multibootRamdiskReadBytes( int biosdev, unsigned int blkno,
/*
int multibootRamdiskReadBytes( int biosdev, unsigned int blkno,
unsigned int byteoff,
unsigned int byteCount, void * buffer );
int multiboot_get_ramdisk_info(int biosdev, struct driveInfo *dip);
//static long multiboot_LoadExtraDrivers(FileLoadDrivers_t FileLoadDrivers_p);
static long multiboot_LoadExtraDrivers(FileLoadDrivers_t FileLoadDrivers_p);
*/
// Starts off in the multiboot context 1 MB high but eventually gets into low memory
// and winds up with a bootdevice in eax which is all that boot() wants
// bootArgs->Video.v_display = VGA_TEXT_MODE;
// Install ramdisk and extra driver hooks
p_get_ramdisk_info = &multiboot_get_ramdisk_info;
p_ramdiskReadBytes = &multibootRamdiskReadBytes;
//p_get_ramdisk_info = &multiboot_get_ramdisk_info;
//p_ramdiskReadBytes = &multibootRamdiskReadBytes;
//LoadExtraDrivers_p = &multiboot_LoadExtraDrivers;
// Since we call multiboot ourselves, its return address will be correct.
doSelectDevice = true;
bootdevice = BAD_BOOT_DEVICE;
}
if(mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE)
{
const char *val;
int size;
if(getValueForBootKey(mi->mi_cmdline, "biosdev", &val, &size))
{
char *endptr;
int intVal = strtol(val, &endptr, 16 /* always hex */);
if(*val != '\0' && (*endptr == '\0' || *endptr == ' ' || *endptr == '\t'))
{
printf("Boot device overridden to %02x with biosdev=%s\n", intVal, val);
bootdevice = intVal;
doSelectDevice = false;
}
else
doSelectDevice = true;
}
if(getValueForBootKey(mi->mi_cmdline, "timeout", &val, &size))
{
char *endptr;
int intVal = strtol(val, &endptr, 0);
if(*val != '\0' && (*endptr == '\0' || *endptr == ' ' || *endptr == '\t'))
{
printf("Timeout overridden to %d with timeout=%s\n", intVal, val);
multiboot_timeout = intVal;
multiboot_timeout_set = 1;
}
}
if(getValueForBootKey(mi->mi_cmdline, "partno", &val, &size))
{
char *endptr;
int intVal = strtol(val, &endptr, 0);
if(*val != '\0' && (*endptr == '\0' || *endptr == ' ' || *endptr == '\t'))
{
printf("Default partition overridden to %d with timeout=%s\n", intVal, val);
multiboot_partition = intVal;
multiboot_partition_set = 1;
}
}
}
if(bootdevice == BAD_BOOT_DEVICE)
sleep(2); // pause for a second before halting
///////////////////////////////////////////////////////////////////////////
// Ramdisk and extra drivers code
#if 0
int multibootRamdiskReadBytes( int biosdev, unsigned int blkno,
unsigned int byteoff,
unsigned int byteCount, void * buffer )
dip->valid = true;
return 0;
}
#if 0
static long multiboot_LoadExtraDrivers(FileLoadDrivers_t FileLoadDrivers_p)
{
char extensionsSpec[1024];
branches/rewrite/i386/boot2/boot.c
5353
5454
5555
56
5756
57
58
59
60
5861
5962
6063
......
144147
145148
146149
147
150
148151
149152
150153
#include "boot.h"
#include "sl.h"
#include "libsa.h"
#include "modules.h"
extern void init_module_system();
extern int execute_hook(const char* name, void*, void*, void*, void*);
long gBootMode; /* defaults to 0 == kBootModeNormal */
bool gOverrideKernel;
char *gPlatformName;
// Intialize module system
init_module_system();
UInt32 loopCount = 0;
int loopCount = 0;
while(1)
{
execute_hook("WorkLoop", (void*)loopCount++, NULL, NULL, NULL);// Main work loop
branches/rewrite/i386/boot2/Cconfig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
config MODULES
bool "Module System"
default y
---help---
Say Y here if you want to enable to use of modules.
config MODULE_DEBUG
bool "debug support"
default n
depends on MODULES
---help---
Say Y here if you want to enable debug mode for the
module system.
source "i386/modules/Cconfig"
branches/rewrite/i386/boot2/Makefile
4242
4343
4444
45
45
4646
4747
4848
# The ordering is important;
# boot2.o must be first.
OBJS = boot2.o boot.o mboot.o modules.o modules_support.o boot_modules.o
OBJS = boot2.o boot.o mboot.o boot_modules.o
# button.o browser.o scrollbar.o == NOTYET bmdecompress.o graphic_utils.o prompt.o options.o lzss.o
UTILDIR = ../util
branches/rewrite/i386/Cconfig
1616
1717
1818
19
20
1921
2022
2123
source "i386/boot2/Cconfig"
source "i386/modules/Cconfig"
source "i386/libsa/Cconfig"
source "i386/libsaio/Cconfig"
branches/rewrite/i386/modules/include/modules
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
extern "C" {
/*
* Module Loading functionality
* Copyright 2009 Evan Lojewski. All rights reserved.
*
*/
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
// There is a bug with the module system / rebasing / binding
// that causes static variables to be incorrectly rebased or bound
// Disable static variables for the moment
// #define static
#ifndef __BOOT_MODULES_H
#define __BOOT_MODULES_H
#define SYMBOLS_MODULE "Symbols.dylib"
#define SYMBOL_LOOKUP_SYMBOL"_lookup_symbol"
#define STUB_ENTRY_SIZE6
#define SECT_NON_LAZY_SYMBOL_PTR"__nl_symbol_ptr"
#define SECT_SYMBOL_STUBS"__symbol_stub"
#define VALID_FUNCTION(__x__)(__x__ && (void*)__x__ != (void*)0xFFFFFFFF)
extern unsigned long long textAddress;
extern unsigned long long textSection;
typedef struct symbolList_t
{
char* symbol;
unsigned int addr;
struct symbolList_t* next;
} symbolList_t;
typedef struct moduleList_t
{
char* module;
unsigned int version;
unsigned int compat;
struct moduleList_t* next;
} moduleList_t;
typedef struct callbackList_t
{
void(*callback)(void*, void*, void*, void*);
struct callbackList_t* next;
} callbackList_t;
typedef struct moduleHook_t
{
const char* name;
callbackList_t* callbacks;
struct moduleHook_t* next;
} moduleHook_t;
int init_module_system();
void load_all_modules();
/*
* Modules Interface
* execute_hook
*Exexutes a registered hook. All callbaks are
*called in the same order that they were added
*
* register_hook_callback
*registers a void function to be executed when a
*hook is executed.
*/
int execute_hook(const char* name, void*, void*, void*, void*);
void register_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*));
int load_module(char* module);
int is_module_loaded(const char* name);
void module_loaded(const char* name/*, uint32_t version, uint32_t compat*/);
long long add_symbol(char* symbol, long long addr, char is64);
void* parse_mach(void* binary,
int(*dylib_loader)(char*),
long long(*symbol_handler)(char*, long long, char)
);
unsigned int handle_symtable(uint32_t base, struct symtab_command* symtabCommand,
long long(*symbol_handler)(char*, long long, char),
char is64);
unsigned int lookup_all_symbols(const char* name);
int replace_function(const char* symbol, void* newAddress);
//extern unsigned int (*lookup_symbol)(const char*);
#endif /* __BOOT_MODULES_H */
}
branches/rewrite/i386/modules/FileSystem/FileSystem.cpp
22
33
44
5
6
7
8
9
10
11
12
13
14
15
16
* Copyright (c) 2011 Evan Lojewski. All rights reserved.
*
*/
#include <cstdlib>
#include <iostream>
#include <modules>
extern "C"
{
void FileSystem_start();
}
void FileSystem_start()
{
}
branches/rewrite/i386/modules/FileSystem/Makefile
99
1010
1111
12
12
1313
1414
DIR = HelloWorld
SUBDIRS = HFS
MODULE_OBJS = FileSystem.o
MODULE_OBJS = Main.o FileSystem.o
include ../MakeInc.dir
branches/rewrite/i386/modules/MakeInc.dir
5151
5252
5353
54
54
5555
5656
57
57
5858
5959
6060
LIBSAIODIR = ../../libsaio
BOOT2DIR = ../../boot2
MODULE_INCLUDES := $(foreach x,$(MODULE_DEPENDENCIES),-I$(SRCROOT)/i386/modules/$(x)/include/)
MODULE_INCLUDES := $(foreach x,ModuleSystem $(MODULE_DEPENDENCIES),-I$(SRCROOT)/i386/modules/$(x)/include/)
INC = -I$(SRCROOT)/i386/modules/include/ -Iinclude/ -I$(SRCROOT)/i386/libsaio/ -I$(SRCROOT)/i386/libsa/ -I$(SRCROOT)/i386/include/ -I$(SRCROOT)/i386/boot2/ $(MODULE_INCLUDES)
INC = -I$(SRCROOT)/sym/i386/ -I$(SRCROOT)/i386/modules/include/ -Iinclude/ -I$(SRCROOT)/i386/libsaio/ -I$(SRCROOT)/i386/libsa/ -I$(SRCROOT)/i386/include/ -I$(SRCROOT)/i386/boot2/ $(MODULE_INCLUDES)
DEFINES := -D__KLIBC__ $(DEFINES)
MODULE_DEPENDENCIES := $(wildcard $(foreach x,$(MODULE_DEPENDENCIES),$(SYMROOT)/modules/$(x).dylib)) \
branches/rewrite/i386/modules/Cconfig
22
33
44
5
6
7
8
9
10
11
12
13
14
15
16
17
18
519
20
21
22
623
724
825
# Chameleon Modules
#
config MODULESYSTEM_MODULE
bool "Module System"
default y
---help---
Say Y here if you want to enable to use of modules.
config MODULE_DEBUG
bool "debug support"
default n
depends on MODULES
---help---
Say Y here if you want to enable debug mode for the
module system.
menu "Modules"
# NOTE: ModuleSystem should always be compiled in
source "i386/modules/ModuleSystem/Cconfig"
# NOTE BiosDisk, FileSystem should both be enabled as well as at least one file system driver
source "i386/modules/klibc/Cconfig"
source "i386/modules/uClibcxx/Cconfig"
branches/rewrite/i386/modules/Makefile
1111
1212
1313
14
14
1515
1616
1717
......
2121
2222
2323
24
24
2525
2626
2727
......
6060
6161
6262
63
63
6464
6565
6666
include ${SRCROOT}/Make.rules
# The order of building is important.
SUBDIRS = klibc uClibcxx Resolution HelloWorld BiosDisk FileSystem
SUBDIRS = ModuleSystem klibc uClibcxx Resolution HelloWorld BiosDisk FileSystem
CFLAGS= -O3 $(MORECPP) -arch i386 -g -static
INC = -I$(LIBSAIODIR)
ifeq (${CONFIG_MODULES}, y)
ifeq (${CONFIG_MODULESYSTEM_MODULE}, y)
all: $(SYMROOT) $(OBJROOT) objroot_dirs $(SYMROOT)/boot_modules.c $(SYMROOT)/boot_modules.h
@for i in ${SUBDIRS}; \
do \
$(SYMROOT)/boot_modules.c: ${OBJROOT} ${SYMROOT}/modules/ ${OBJROOT} $(addprefix $(OBJROOT)/, ${MODULE_OBJS})
ifeq ($(BUILT_IN),yes)
@echo "// Autogenerated - do not modify" > $@
@echo "#include <modules.h>" >> $@
@echo "#include \"../../i386/modules/ModuleSystem/include/modules.h\"" >> $@
@echo "#include \"boot_modules.h\"" >> $@
@echo "void start_built_in_modules() {" >> $@
endif

Archive Download the corresponding diff file

Revision: 1076