plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

hfs.c (55378B)


      1 /*
      2 	Copyright (c) 2007 David Swasey; see COPYRIGHT.
      3 	Limitations:
      4 		Hfsreaddir skips entries whose names contain NUL.
      5 		Hfsbadblock is untested.
      6 */
      7 
      8 #include <u.h>
      9 #include <libc.h>
     10 #include <thread.h>
     11 #include <sunrpc.h>
     12 #include <nfs3.h>
     13 #include <diskfs.h>
     14 #include "hfs.h"
     15 
     16 #define debug 0
     17 
     18 static char Rprefix[] = "._";
     19 enum { Rplen = nelem(Rprefix)-1 };
     20 
     21 static int hfssync(Fsys*);
     22 static int hfswrapper(Fsys*);
     23 static int hfstreesync(Hfs*, Fork*, Tree*, int);
     24 static u32int hfsmetadir(Hfs*);
     25 static void hfsclose(Fsys*);
     26 static Block* hfsblockread(Fsys*, u64int);
     27 
     28 static Nfs3Status hfsroot(Fsys*, Nfs3Handle*);
     29 static Nfs3Status hfsgetattr(Fsys*, SunAuthUnix*, Nfs3Handle*, Nfs3Attr*);
     30 static Nfs3Status hfsaccess(Fsys *fsys, SunAuthUnix*, Nfs3Handle *, u32int, u32int*, Nfs3Attr *attr);
     31 static Nfs3Status hfslookup(Fsys*, SunAuthUnix*, Nfs3Handle*, char*, Nfs3Handle*);
     32 static Nfs3Status _hfslookup(Hfs*, u32int, char*, Treeref*);
     33 static Nfs3Status hfsreaddir(Fsys *fsys, SunAuthUnix*, Nfs3Handle *h, u32int, u64int, uchar**, u32int*, u1int*);
     34 static Nfs3Status hfsreadfile(Fsys*, SunAuthUnix*, Nfs3Handle*, u32int, u64int, uchar**, u32int*, u1int*);
     35 static Nfs3Status hfsreadlink(Fsys*, SunAuthUnix*, Nfs3Handle*, char**);
     36 
     37 static int hfsextentsearch(Hfs*, u32int, int, u32int, u32int*, Extent*);
     38 static int hfscatsearch(Hfs*, Catalogkey*, Treeref*);
     39 static int _hfscatalogkeycmp(uchar*, int, int*, Key*, int);
     40 static int hfstreesearch(Tree*, Key*, int*, Treeref*);
     41 static void hfsref(Tree*, Treeref*);
     42 static void hfsrefput(Treeref*);
     43 static int hfsrefnode(Treeref*, u32int);
     44 static int hfsrefrec(Treeref*, int);
     45 static int hfsrefnextrec(Treeref*);
     46 
     47 static int hfsforkread(Hfs*, Fork*, uchar*, u32int, u64int);
     48 static Block* hfsforkblock(Hfs*, Fork*, u32int);
     49 static Block* hfsblock(Hfs*, u32int);
     50 
     51 static void getnodedesc(Node*, uchar*);
     52 static void getfork(Fork*, u32int, int, uchar*);
     53 static void getextents(Extent*, uchar*);
     54 static void getextent(Extent*, uchar*);
     55 static int getextentkey(Extentkey*, uchar*, int);
     56 static int getcatalogrecord(Inode*, uchar*, int);
     57 static int getcatalogthread(Catalogkey*, uchar*, int);
     58 static int getcatalogkey(Catalogkey*, uchar*, int, int);
     59 static int getname(Name*, uchar*);
     60 static u32int gettime(uchar*);
     61 static u64int get64(uchar*);
     62 static u32int get32(uchar*);
     63 static int get16(uchar*);
     64 static void put32(uchar*, u32int);
     65 
     66 static int hfsinamecmp(Name*, Name*);
     67 static int hfsnamecmp(Name*, Name*);
     68 
     69 Fsys*
     70 fsysopenhfs(Disk *disk)
     71 {
     72 	Hfs *fs;
     73 	Fsys *fsys;
     74 
     75 	fsys = emalloc(sizeof(Fsys));
     76 	fs = emalloc(sizeof(Hfs));
     77 	fsys->priv = fs;
     78 	fs->fsys = fsys;
     79 	fs->disk = disk;
     80 	fsys->type = "hfs";
     81 	fsys->_readblock = hfsblockread;
     82 	fsys->_sync = hfssync;
     83 	fsys->_root = hfsroot;
     84 	fsys->_getattr = hfsgetattr;
     85 	fsys->_access = hfsaccess;
     86 	fsys->_lookup = hfslookup;
     87 	fsys->_readfile = hfsreadfile;
     88 	fsys->_readlink = hfsreadlink;
     89 	fsys->_readdir = hfsreaddir;
     90 	fsys->_close = hfsclose;
     91 	fsys->disk = disk;
     92 
     93 	if(hfswrapper(fsys) < 0 || hfssync(fsys) < 0)
     94 		goto error;
     95 
     96 	return fsys;
     97 
     98 error:
     99 	hfsclose(fsys);
    100 	return nil;
    101 }
    102 
    103 static void
    104 hfsclose(Fsys *fsys)
    105 {
    106 	Hfs *fs;
    107 
    108 	fs = fsys->priv;
    109 	/*
    110 	 * We're not supposed to close the disk passed to
    111 	 * hfsopen, but if we created our own partition disk
    112 	 * we need to close that.  It will close its subdisk
    113 	 * unless we call diskpartabandon.  Bad planning.
    114 	 */
    115 	if(fs->disk && fs->disk != fsys->disk){
    116 		diskpartabandon(fs->disk);
    117 		diskclose(fs->disk);
    118 	}
    119 	free(fs);
    120 	free(fsys);
    121 }
    122 
    123 static int
    124 hfswrapper(Fsys *fsys)
    125 {
    126 	Hfs *fs;
    127 	Disk *disk;
    128 	Block *b;
    129 	uchar *mdb;
    130 	int magic, hfsstart, subsig, substart, subnblocks;
    131 	u32int hfsblocksize;
    132 	u64int offset, size;
    133 
    134 	fs = fsys->priv;
    135 	disk = fsys->disk;
    136 	if((b = diskread(disk, 162, 1024)) == nil)
    137 		return -1;
    138 	mdb = b->data;
    139 	magic = get16(mdb);
    140 	hfsblocksize = get32(mdb+20);
    141 	hfsstart = get16(mdb+28);
    142 	subsig = get16(mdb+124);
    143 	substart = get16(mdb+126);
    144 	subnblocks = get16(mdb+128);
    145 	blockput(b);
    146 
    147 	if(magic != Hfssig)
    148 		return 0;
    149 	if(subsig != Hfsplussig && subsig != Hfsxsig)
    150 		return 0;
    151 
    152 	offset = hfsstart*512 + substart*hfsblocksize;
    153 	size = subnblocks*hfsblocksize;
    154 
    155 	if((fs->disk = diskpart(disk, offset, size)) == nil)
    156 		return -1;
    157 	if(debug) fprint(2, "wrapped hfs size 0x%ullx offset 0x%ullx\n", size, offset);
    158 	return 0;
    159 }
    160 
    161 static int
    162 checkvolhdr(uchar *vh)
    163 {
    164 	u32int magic;
    165 
    166 	magic = get32(vh);
    167 	switch(magic){
    168 	case Hfsplusmagic:
    169 		return 0;
    170 	case Hfsxmagic:
    171 		return 1;
    172 	default:
    173 		werrstr("bad volume header magic 0x%ux", magic);
    174 		return -1;
    175 	}
    176 }
    177 
    178 static int
    179 hfssync(Fsys *fsys)
    180 {
    181 	Hfs *fs;
    182 	Disk *disk;
    183 	Block *b;
    184 	uchar *vh;
    185 	int sensitive;
    186 
    187 	fs = fsys->priv;
    188 	disk = fs->disk;
    189 
    190 	if((b = diskread(disk, 512, 1024)) == nil)
    191 		goto error;
    192 	vh = b->data;
    193 	if((sensitive = checkvolhdr(vh)) < 0)
    194 		goto error;
    195 	fs->blocksize = get32(vh+40);
    196 	fs->nblock = get32(vh+44);
    197 	fs->nfree = get32(vh+48);
    198 	fs->hasbadblocks = get32(vh+4) & (1<<9);
    199 	getfork(&fs->alloc, AllocId, Dfork, vh+112);
    200 	getfork(&fs->extentsfork, ExtentsId, Dfork, vh+192);
    201 	getfork(&fs->catalogfork, CatalogId, Dfork, vh+272);
    202 	blockput(b);
    203 	b = nil;
    204 
    205 	if(hfstreesync(fs, &fs->extentsfork, &fs->extents, 0) < 0)
    206 		goto error;
    207 	if(hfstreesync(fs, &fs->catalogfork, &fs->catalog, sensitive) < 0)
    208 		goto error;
    209 	fs->hlinkparent = hfsmetadir(fs);
    210 
    211 	fsys->blocksize = fs->blocksize;
    212 	fsys->nblock = fs->nblock;
    213 	if(debug) fprint(2, "hfs %ud %ud-byte blocks (%ud free, %s bad)\n",
    214 			fs->nblock, fs->blocksize, fs->nfree, fs->hasbadblocks?"some":"none");
    215 	return 0;
    216 
    217 error:
    218 	blockput(b);
    219 	return -1;
    220 }
    221 
    222 static int
    223 hfstreesync(Hfs *fs, Fork *fork, Tree *tree, int sensitive)
    224 {
    225 	Block *b;
    226 	uchar *hr;
    227 	Node node;
    228 
    229 	b = nil;
    230 	if(fork->extent[0].count == 0){
    231 		if(debug) fprint(2, "tree fork empty\n");
    232 		goto error;
    233 	}
    234 	if((b = hfsblock(fs,fork->extent[0].start)) == nil)
    235 		goto error;
    236 	getnodedesc(&node, b->data);
    237 	if(node.type != HeaderNode){
    238 		if(debug) fprint(2, "bad header node type %d\n", node.type);
    239 		goto error;
    240 	}
    241 	hr = b->data+Ndlen;
    242 	tree->nodesize = get16(hr+18);
    243 	tree->nnodes = get32(hr+22);
    244 	tree->root = get32(hr+2);
    245 	tree->height = get16(hr);
    246 	tree->maxkeylen = get16(hr+20);
    247 	tree->indexkeylen = (get32(hr+38)&4) ? 0 : tree->maxkeylen;
    248 	tree->sensitive = sensitive && hr[37]==0xBC;
    249 	blockput(b);
    250 	tree->fs = fs;
    251 	tree->fork = fork;
    252 	if(debug) fprint(2, "tree %ud %ud %d-byte nodes\n",
    253 		fork->cnid, tree->nnodes, tree->nodesize);
    254 	return 0;
    255 
    256 error:
    257 	werrstr("bad tree %ud header", fork->cnid);
    258 	blockput(b);
    259 	return -1;
    260 }
    261 
    262 static u32int
    263 hfsmetadir(Hfs *fs)
    264 {
    265 	static Rune name[] = {0,0,0,0,'H','F','S','+',' ','P','r','i','v','a','t','e',' ','D','a','t','a'};
    266 	Catalogkey key;
    267 	Treeref ref;
    268 	Inode ino;
    269 
    270 	key.parent = RootId;
    271 	key.u.name.len = nelem(name);
    272 	memcpy(key.u.name.name, name, sizeof name);
    273 	if(hfscatsearch(fs, &key, &ref) < 0)
    274 		goto notfound;
    275 	if(getcatalogrecord(&ino, ref.data, ref.dlen) < 0)
    276 		goto notfound;
    277 	if((ino.mode&IFMT) != IFDIR)
    278 		goto notfound;
    279 	hfsrefput(&ref);
    280 	if(debug) fprint(2, "metadata directory %ud\n", ino.cnid);
    281 	return ino.cnid;
    282 
    283 notfound:
    284 	if(debug) fprint(2, "metadata directory not found\n");
    285 	hfsrefput(&ref);
    286 	return 0;
    287 }
    288 
    289 static int
    290 hfsbadblock(Hfs *fs, u32int bno)
    291 {
    292 	Extent e[NEXTENTS];
    293 	int i;
    294 
    295 	if(hfsextentsearch(fs, BadblockId, Dfork, bno, nil, e) < 0)
    296 		return 0;
    297 	/*
    298 		Don't lightly throw away a block.
    299 	*/
    300 	for(i=0; i<NEXTENTS; i++)
    301 		if(e[i].start <= bno && bno < e[i].start+e[i].count)
    302 			return 1;
    303 	if(debug) fprint(2, "corrupt badblock record, block %ud\n", bno);
    304 	return 0;
    305 }
    306 
    307 static Block*
    308 hfsblockread(Fsys *fsys, u64int vbno)
    309 {
    310 	Hfs *fs;
    311 	u32int bno;
    312 	Block *b;
    313 	int n, alloc;
    314 
    315 	fs = fsys->priv;
    316 	if(vbno >= fs->nblock){
    317 		if(debug) fprint(2, "block %llud past end of volume\n", vbno);
    318 		return nil;
    319 	}
    320 	bno = vbno;
    321 
    322 	n = bno>>3;
    323 	if((b = hfsforkblock(fs, &fs->alloc, n/fs->blocksize)) == nil){
    324 		if(debug) fprint(2, "can't read alloc bitmap for block %ud\n", bno);
    325 		/* assume it's used */
    326 	}
    327 	else{
    328 		alloc = b->data[n%fs->blocksize] & (1<<(7-(bno&7)));
    329 		blockput(b);
    330 		if(!alloc)
    331 			return nil;
    332 	}
    333 
    334 	if(fs->hasbadblocks && hfsbadblock(fs, bno)){
    335 		if(debug) fprint(2, "bad block %ud\n", bno);
    336 		return nil;
    337 	}
    338 
    339 	b = hfsblock(fs, bno);
    340 	if(debug && b == nil) fprint(2, "can't read block %ud\n", bno);
    341 	return b;
    342 }
    343 
    344 static int
    345 hasresource(Inode *ino)
    346 {
    347 	return (ino->mode&IFMT)==IFREG && ino->u.f.rfork.size>0;
    348 }
    349 
    350 static void
    351 useresource(Inode *ino)
    352 {
    353 	ino->fileid = ((u64int)1)<<32 | ino->cnid;
    354 	ino->u.f.nhdr = Adlen;
    355 	ino->u.f.fork = &ino->u.f.rfork;
    356 }
    357 
    358 static int
    359 ref2ino(Hfs *fs, Treeref *ref, Inode *ino)
    360 {
    361 	static uchar magic[] = {'h','l','n','k','h','f','s','+'};
    362 	Catalogkey key;
    363 	Treeref hlink;
    364 	u32int cnid;
    365 
    366 	if(getcatalogrecord(ino, ref->data, ref->dlen) < 0)
    367 		return -1;
    368 
    369 	if((ino->mode&IFMT) == IFREG
    370 	&& memcmp(ino->u.f.info, magic, nelem(magic)) == 0){
    371 		if(debug) print("iNode%ud...", ino->special);
    372 		if(fs->hlinkparent == 0)
    373 			return -1;
    374 		key.parent = fs->hlinkparent;
    375 		key.u.name.len = runesnprint(key.u.name.name, sizeof key.u.name.name,
    376 			"iNode%ud", ino->special);
    377 		if(hfscatsearch(fs, &key, &hlink) < 0)
    378 			goto error;
    379 		cnid = ino->cnid;
    380 		if(getcatalogrecord(ino, hlink.data, hlink.dlen) < 0)
    381 			goto error;
    382 		hfsrefput(&hlink);
    383 		ino->cnid = cnid;
    384 		ino->fileid = cnid;
    385 		ino->nlink = ino->special;
    386 	}
    387 	return 0;
    388 
    389 error:
    390 	hfsrefput(&hlink);
    391 	return -1;
    392 }
    393 
    394 static void
    395 mkhandle(Nfs3Handle *h, int rsrc, u32int cnid)
    396 {
    397 	h->h[0] = rsrc;
    398 	put32(h->h+1, cnid);
    399 	h->len = 5;
    400 }
    401 
    402 static Nfs3Status
    403 hfsroot(Fsys *fsys, Nfs3Handle *h)
    404 {
    405 	USED(fsys);
    406 	mkhandle(h, 0, RootId);
    407 	return Nfs3Ok;
    408 }
    409 
    410 static Nfs3Status
    411 handle2ino(Hfs *fs, Nfs3Handle *h, Treeref *ref, Catalogkey *key, Inode *ino)
    412 {
    413 	Treeref refbuf;
    414 	u32int cnid;
    415 	Catalogkey keybuf;
    416 	int rsrc;
    417 
    418 	if(h->len != 5)
    419 		return Nfs3ErrBadHandle;
    420 	rsrc = h->h[0];
    421 	cnid = get32(h->h+1);
    422 	if(debug) print("cnid %ud%s...", cnid, rsrc ? " rsrc" : "");
    423 
    424 	if(ref == nil)
    425 		ref = &refbuf;
    426 	if(key == nil)
    427 		key = &keybuf;
    428 
    429 	/* map cnid to full catalog key */
    430 	key->parent = cnid;
    431 	key->u.name.len = 0;
    432 	if(hfscatsearch(fs, key, ref) < 0)
    433 		goto error;
    434 	if(getcatalogthread(key, ref->data, ref->dlen) < 0)
    435 		goto error;
    436 	hfsrefput(ref);
    437 
    438 	if(debug) print("{%ud,%.*S}...", key->parent, key->u.name.len, key->u.name.name);
    439 
    440 	/* map full key to catalog info */
    441 	if(hfscatsearch(fs, key, ref) < 0)
    442 		goto error;
    443 	if(ino != nil){
    444 		if(ref2ino(fs, ref, ino) < 0)
    445 			goto error;
    446 		if(rsrc){
    447 			if(!hasresource(ino)){
    448 				hfsrefput(ref);
    449 				return Nfs3ErrBadHandle;
    450 			}
    451 			useresource(ino);
    452 		}
    453 	}
    454 	if(ref == &refbuf)
    455 		hfsrefput(ref);
    456 
    457 	return Nfs3Ok;
    458 
    459 error:
    460 	hfsrefput(ref);
    461 	return Nfs3ErrIo;
    462 }
    463 
    464 static Nfs3Status
    465 ino2attr(Hfs *fs, Inode *ino, Nfs3Attr *attr)
    466 {
    467 	u32int rdev;
    468 
    469 	switch(ino->mode&IFMT){
    470 	case IFIFO:
    471 		attr->type = Nfs3FileFifo;
    472 		break;
    473 	case IFCHR:
    474 		attr->type = Nfs3FileChar;
    475 		break;
    476 	case IFDIR:
    477 		attr->type = Nfs3FileDir;
    478 		break;
    479 	case IFBLK:
    480 		attr->type = Nfs3FileBlock;
    481 		break;
    482 	case IFREG:
    483 		attr->type = Nfs3FileReg;
    484 		break;
    485 	case IFLNK:
    486 		attr->type = Nfs3FileSymlink;
    487 		break;
    488 	case IFSOCK:
    489 		attr->type = Nfs3FileSocket;
    490 		break;
    491 	case IFWHT:
    492 	default:
    493 		if(debug) fprint(2, "bad format %uo\n", ino->mode&IFMT);
    494 		return Nfs3ErrBadHandle;
    495 	}
    496 
    497 	attr->mode = ino->mode&07777;
    498 	attr->nlink = ino->nlink;
    499 	attr->uid = ino->uid;
    500 	attr->gid = ino->gid;
    501 	if(attr->type==Nfs3FileReg || attr->type==Nfs3FileSymlink){
    502 		attr->size = ino->u.f.nhdr+ino->u.f.fork->size;
    503 		attr->used = (u64int)ino->u.f.fork->nblocks*fs->blocksize;
    504 	}
    505 	else{
    506 		attr->size = 0;
    507 		attr->used = 0;
    508 	}
    509 	if(attr->type==Nfs3FileBlock || attr->type==Nfs3FileChar){
    510 		rdev = ino->special;
    511 		attr->major = (rdev>>8)&0xFF;	/* not mentioned in the tech note */
    512 		attr->minor = rdev & 0xFFFF00FF;
    513 	}else{
    514 		attr->major = 0;
    515 		attr->minor = 0;
    516 	}
    517 	attr->fsid = 0;
    518 	attr->fileid = ino->fileid;
    519 	attr->atime.sec = ino->atime;
    520 	attr->atime.nsec = 0;
    521 	attr->mtime.sec = ino->mtime;
    522 	attr->mtime.nsec = 0;
    523 	attr->ctime.sec = ino->ctime;
    524 	attr->ctime.nsec = 0;
    525 	return Nfs3Ok;
    526 }
    527 
    528 static int
    529 ingroup(SunAuthUnix *au, uint gid)
    530 {
    531 	int i;
    532 
    533 	for(i=0; i<au->ng; i++)
    534 		if(au->g[i] == gid)
    535 			return 1;
    536 	return 0;
    537 }
    538 
    539 static Nfs3Status
    540 inoperm(Inode *ino, SunAuthUnix *au, int need)
    541 {
    542 	int have;
    543 
    544 	if(allowall)
    545 		return Nfs3Ok;
    546 
    547 	have = ino->mode&0777;
    548 	if(ino->uid == au->uid)
    549 		have >>= 6;
    550 	else if(ino->gid == au->gid || ingroup(au, ino->gid))
    551 		have >>= 3;
    552 
    553 	if((have&need) != need)
    554 		return Nfs3ErrNotOwner;	/* really EPERM */
    555 	return Nfs3Ok;
    556 }
    557 
    558 static Nfs3Status
    559 hfsgetattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr)
    560 {
    561 	Inode ino;
    562 	Hfs *fs;
    563 	Nfs3Status ok;
    564 
    565 	fs = fsys->priv;
    566 	if((ok = handle2ino(fs, h, nil, nil, &ino)) != Nfs3Ok)
    567 		return ok;
    568 
    569 	USED(au);	/* anyone can getattr */
    570 	return ino2attr(fs, &ino, attr);
    571 }
    572 
    573 static Nfs3Status
    574 hfsaccess(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr)
    575 {
    576 	int have;
    577 	Inode ino;
    578 	Hfs *fs;
    579 	Nfs3Status ok;
    580 
    581 	fs = fsys->priv;
    582 	if((ok = handle2ino(fs, h, nil, nil, &ino)) != Nfs3Ok)
    583 		return ok;
    584 
    585 	have = ino.mode&0777;
    586 	if(ino.uid == au->uid)
    587 		have >>= 6;
    588 	else if(ino.gid == au->gid || ingroup(au, ino.gid))
    589 		have >>= 3;
    590 
    591 	*got = 0;
    592 	if((want&Nfs3AccessRead) && (have&AREAD))
    593 		*got |= Nfs3AccessRead;
    594 	if((want&Nfs3AccessLookup) && (ino.mode&IFMT)==IFDIR && (have&AEXEC))
    595 		*got |= Nfs3AccessLookup;
    596 	if((want&Nfs3AccessExecute) && (ino.mode&IFMT)!=IFDIR && (have&AEXEC))
    597 		*got |= Nfs3AccessExecute;
    598 
    599 	return ino2attr(fs, &ino, attr);
    600 }
    601 
    602 static Nfs3Status
    603 utf2name(Name *n, char *name)
    604 {
    605 	int len;
    606 	Rune *p;
    607 
    608 	p = n->name;
    609 	len = 0;
    610 	while(*name){
    611 		if(len == NAMELEN)
    612 			return Nfs3ErrNameTooLong;
    613 		name += chartorune(p, name);
    614 		if(*p == ':')
    615 			*p = '/';	/* not mentioned in the tech note */
    616 		p++;
    617 		len++;
    618 	}
    619 	n->len = len;
    620 	return Nfs3Ok;
    621 }
    622 
    623 static int
    624 name2utf(char *buf, Name *name)
    625 {
    626 	int len, i;
    627 
    628 	len = 0;
    629 	for(i=0; i<name->len; i++){
    630 		if(name->name[i] == '/'){	/* not mentioned in the tech note */
    631 			buf[len] = ':';
    632 			len++;
    633 		}
    634 		else
    635 			len += runetochar(buf+len, name->name+i);
    636 	}
    637 	return len;
    638 }
    639 
    640 static Nfs3Status
    641 hfslookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh)
    642 {
    643 	Hfs *fs;
    644 	Inode ino, target;
    645 	Nfs3Status ok;
    646 	Catalogkey key;
    647 	Treeref ref;
    648 	int rsrc;
    649 
    650 	fs = fsys->priv;
    651 	if((ok = handle2ino(fs, h, nil, &key, &ino)) != Nfs3Ok)
    652 		return ok;
    653 
    654 	if((ino.mode&IFMT) != IFDIR)
    655 		return Nfs3ErrNotDir;
    656 
    657 	if((ok = inoperm(&ino, au, AEXEC)) != Nfs3Ok)
    658 		return ok;
    659 
    660 	if(strcmp(name, ".") == 0){
    661 		mkhandle(nh, 0, ino.cnid);
    662 		return Nfs3Ok;
    663 	}
    664 	if(strcmp(name, "..") == 0){
    665 		mkhandle(nh, 0, key.parent);
    666 		return Nfs3Ok;
    667 	}
    668 
    669 	rsrc = 0;
    670 	if((ok = _hfslookup(fs, ino.cnid, name, &ref)) != Nfs3Ok){
    671 		if(memcmp(name, Rprefix, Rplen)==0
    672 		&& _hfslookup(fs, ino.cnid, name+Rplen, &ref)==Nfs3Ok)
    673 			rsrc = 1;
    674 		else
    675 			return ok;
    676 	}
    677 	if(ref2ino(fs, &ref, &target) < 0)
    678 		goto error;
    679 	hfsrefput(&ref);
    680 	if(rsrc && !hasresource(&target))
    681 		return Nfs3ErrNoEnt;
    682 	mkhandle(nh, rsrc, target.cnid);
    683 	return Nfs3Ok;
    684 
    685 error:
    686 	hfsrefput(&ref);
    687 	return Nfs3ErrIo;
    688 }
    689 
    690 static Nfs3Status
    691 _hfslookup(Hfs *fs, u32int parent, char *name, Treeref *ref)
    692 {
    693 	Catalogkey key;
    694 	Nfs3Status ok;
    695 
    696 	key.parent = parent;
    697 	if((ok = utf2name(&key.u.name, name)) != Nfs3Ok)
    698 		return ok;
    699 	if(hfscatsearch(fs, &key, ref) < 0)
    700 		return Nfs3ErrNoEnt;
    701 	return Nfs3Ok;
    702 }
    703 
    704 
    705 /*
    706 	For the moment, hfsreaddir does not return entries whose names
    707 	contain NUL, avoiding errors like "ls: : No such file or
    708 	directory" when listing a mounted root.
    709 */
    710 static int
    711 hfshidename(Name *n)
    712 {
    713 	int i;
    714 
    715 	for(i=0; i<n->len; i++)
    716 		if(n->name[i] == 0)
    717 			return 1;
    718 	return 0;
    719 }
    720 
    721 static Nfs3Status
    722 hfsreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
    723 	u64int cookie, uchar **pdata, u32int *pcount, u1int *peof)
    724 {
    725 	Nfs3Handle ch;
    726 	u32int i, cnid;
    727 	Treeref ref;
    728 	Catalogkey key;
    729 	Nfs3Entry e;
    730 	int rsrc;
    731 	char name[Rplen+UTFNAMELEN];
    732 	uchar *dp, *dep, *ndp, *data;
    733 	Hfs *fs;
    734 	Inode ino, child;
    735 	Nfs3Status ok;
    736 	u32int nentries;
    737 
    738 	fs = fsys->priv;
    739 	if((ok = handle2ino(fs, h, nil, nil, &ino)) != Nfs3Ok)
    740 		return ok;
    741 
    742 	if((ino.mode&IFMT) != IFDIR)
    743 		return Nfs3ErrNotDir;
    744 
    745 	if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
    746 		return ok;
    747 
    748 	if(ino.u.nentries>>31)
    749 		return Nfs3ErrIo;
    750 	nentries = ino.u.nentries*2;	/* even data, odd resource */
    751 
    752 	i = cookie>>32;
    753 	cnid = cookie&0xFFFFFFFF;
    754 	if(debug) print("readdir %ud %ud %ud...", cnid, i, nentries);
    755 	if(i >= nentries){
    756 		*peof = 1;
    757 		*pcount = 0;
    758 		*pdata = nil;
    759 		return Nfs3Ok;
    760 	}
    761 
    762 	dp = mallocz(count, 1);
    763 	if(dp == nil)
    764 		return Nfs3ErrNoMem;
    765 	data = dp;
    766 	dep = dp+count;
    767 
    768 	/*
    769 		The catalog order relation ensures that records for a
    770 		dir's children are contiguous and preceded by its
    771 		thread record.
    772 	*/
    773 	if(cnid == 0){
    774 		key.parent = ino.cnid;
    775 		key.u.name.len = 0;
    776 		if(hfscatsearch(fs, &key, &ref) < 0)
    777 			goto error;
    778 	}
    779 	else{
    780 		mkhandle(&ch, i&1, cnid);
    781 		if((ok = handle2ino(fs, &ch, &ref, &key, &child)) != Nfs3Ok)
    782 			return ok;
    783 		if(key.parent != ino.cnid)
    784 			goto badparent;
    785 		i++;
    786 	}
    787 
    788 	memset(&e, 0, sizeof e);
    789 	for(; i<nentries; i++){
    790 		rsrc = i&1;
    791 		if(!rsrc){
    792 			if(hfsrefnextrec(&ref) < 0)
    793 				goto error;
    794 			if(getcatalogkey(&key, ref.key, ref.klen, 1) < 0)
    795 				goto error;
    796 			if(key.parent != ino.cnid)
    797 				goto badparent;
    798 			if(ref2ino(fs, &ref, &child) < 0)
    799 				goto error;
    800 		}
    801 		else if(!hasresource(&child))
    802 			continue;
    803 		else
    804 			useresource(&child);
    805 		if(hfshidename(&key.u.name))
    806 			continue;
    807 		e.fileid = child.fileid;
    808 		e.name = name;
    809 		if(rsrc){
    810 			memcpy(name, Rprefix, Rplen);
    811 			e.namelen = Rplen+name2utf(name+Rplen, &key.u.name);
    812 		}
    813 		else
    814 			e.namelen = name2utf(name, &key.u.name);
    815 		e.cookie = ((u64int)i)<<32 | child.cnid;
    816 		e.haveAttr = (ino2attr(fs, &child, &e.attr) == Nfs3Ok);
    817 		e.haveHandle = 1;
    818 		mkhandle(&e.handle, rsrc, child.cnid);
    819 		if(debug) print("%s/0x%llux ", e.name, e.fileid);
    820 		if(nfs3entrypack(dp, dep, &ndp, &e) < 0)
    821 			break;
    822 		dp = ndp;
    823 	}
    824 	hfsrefput(&ref);
    825 	if(i == nentries)
    826 		*peof = 1;
    827 	*pcount = dp - data;
    828 	*pdata = data;
    829 	return Nfs3Ok;
    830 
    831 badparent:
    832 	if(debug) fprint(2, "%.*S: bad parent %ud != %ud\n",
    833 		key.u.name.len, key.u.name.name, key.parent, ino.cnid);
    834 error:
    835 	hfsrefput(&ref);
    836 	return Nfs3ErrIo;
    837 }
    838 
    839 /* See RFC 1740. */
    840 static int
    841 appledouble(Inode *ino, uchar *ad)
    842 {
    843 	static uchar Adhdr[Adlen-4-Filen] =
    844 	{
    845 		0,5,22,7,0,2,0,0,		/* magic */
    846 		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* filler */
    847 		0,2,		/* nentries */
    848 			0,0,0,9,		/* magic: finder info */
    849 			0,0,0,Fioff,		/* offset */
    850 			0,0,0,Filen,		/* length */
    851 			0,0,0,2,		/* magic: rfork */
    852 			0,0,0,Adlen,		/* offset */
    853 	};
    854 
    855 	if(ino->u.f.rfork.size>>32){
    856 		if(debug) fprint(2, "resource fork %ud too large\n", ino->cnid);
    857 		return -1;
    858 	}
    859 	memcpy(ad, Adhdr, nelem(Adhdr));
    860 	put32(ad+nelem(Adhdr), ino->u.f.rfork.size);
    861 	memcpy(ad+Fioff, ino->u.f.info, Filen);
    862 	return 0;
    863 }
    864 
    865 static Nfs3Status
    866 hfsreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count,
    867 	u64int offset, uchar **pdata, u32int *pcount, u1int *peof)
    868 {
    869 	u64int size;
    870 	int skip;
    871 	uchar *data, prefix[Adlen];
    872 	Hfs *fs;
    873 	Inode ino;
    874 	Nfs3Status ok;
    875 
    876 	fs = fsys->priv;
    877 	if((ok = handle2ino(fs, h, nil, nil, &ino)) != Nfs3Ok)
    878 		return ok;
    879 
    880 	if((ino.mode&IFMT) != IFREG)
    881 		return Nfs3ErrInval;
    882 
    883 	if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
    884 		return ok;
    885 
    886 	size = ino.u.f.nhdr+ino.u.f.fork->size;
    887 	if(offset >= size){
    888 		*pdata = 0;
    889 		*pcount = 0;
    890 		*peof = 1;
    891 		return Nfs3Ok;
    892 	}
    893 	if(offset+count > size)
    894 		count = size-offset;
    895 	data = mallocz(count, 1);
    896 	if(data == nil)
    897 		return Nfs3ErrNoMem;
    898 	if(offset < ino.u.f.nhdr){
    899 		if(appledouble(&ino, prefix) < 0)
    900 			goto error;
    901 		skip = Adlen-offset;
    902 		if(skip > count)
    903 			skip = count;
    904 		memcpy(data, prefix+offset, skip);
    905 		offset = 0;
    906 	}
    907 	else{
    908 		offset -= ino.u.f.nhdr;
    909 		skip = 0;
    910 	}
    911 	if(hfsforkread(fs, ino.u.f.fork, data+skip, count-skip, offset) < 0)
    912 		goto error;
    913 
    914 	*peof = (offset+count == size);
    915 	*pcount = count;
    916 	*pdata = data;
    917 	return Nfs3Ok;
    918 
    919 error:
    920 	free(data);
    921 	return Nfs3ErrIo;
    922 }
    923 
    924 static Nfs3Status
    925 hfsreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link)
    926 {
    927 	int len;
    928 	uchar *data;
    929 	Hfs *fs;
    930 	Nfs3Status ok;
    931 	Inode ino;
    932 
    933 	fs = fsys->priv;
    934 	if((ok = handle2ino(fs, h, nil, nil, &ino)) != Nfs3Ok)
    935 		return ok;
    936 
    937 	if((ino.mode&IFMT) != IFLNK)
    938 		return Nfs3ErrInval;
    939 
    940 	if((ok = inoperm(&ino, au, AREAD)) != Nfs3Ok)
    941 		return ok;
    942 
    943 	len = ino.u.f.dfork.size;
    944 	if(len > 10240)	/* arbitrary limit */
    945 		return Nfs3ErrIo;
    946 
    947 	data = mallocz(len+1, 1);
    948 	if(data == nil)
    949 		return Nfs3ErrNoMem;
    950 	if(hfsforkread(fs, &ino.u.f.dfork, data, len, 0) < 0){
    951 		free(data);
    952 		return Nfs3ErrIo;
    953 	}
    954 
    955 	*link = (char*)data;
    956 	return Nfs3Ok;
    957 }
    958 
    959 static int
    960 hfsextentkeycmp(uchar *buf, int len, int *order, Key *key)
    961 {
    962 	Extentkey a, *b;
    963 	int diff;
    964 
    965 	if(getextentkey(&a, buf, len) < 0)
    966 		return -1;
    967 	b = key->priv;
    968 
    969 	diff = a.cnid - b->cnid;
    970 	if(diff == 0){
    971 		diff = a.type - b->type;
    972 		if(diff == 0)
    973 			diff = a.bno - b->bno;
    974 	}
    975 	*order = diff;
    976 	return 0;
    977 }
    978 
    979 static int
    980 hfsextentsearch(Hfs *fs, u32int cnid, int type, u32int bno, u32int *startblock, Extent *e)
    981 {
    982 	Extentkey k;
    983 	Key key;
    984 	Treeref ref;
    985 
    986 	key._cmp = hfsextentkeycmp;
    987 	key.priv = &k;
    988 	k.cnid = cnid;
    989 	k.type = type;
    990 	k.bno = bno;
    991 	if(hfstreesearch(&fs->extents, &key, nil, &ref) < 0)
    992 		goto notfound;
    993 	if(ref.dlen != NEXTENTS*Extentlen){
    994 		if(debug) fprint(2, "extents for fork %ud %d block %ud malformed (%d bytes)\n",
    995 			cnid, type, bno, ref.dlen);
    996 		goto notfound;
    997 	}
    998 	getextentkey(&k, ref.key, ref.klen);
    999 	if(k.cnid != cnid || k.type != type)
   1000 		goto notfound;
   1001 	if(startblock)
   1002 		*startblock = k.bno;
   1003 	getextents(e, ref.data);
   1004 	hfsrefput(&ref);
   1005 	return 0;
   1006 
   1007 notfound:
   1008 	hfsrefput(&ref);
   1009 	return -1;
   1010 }
   1011 
   1012 static int
   1013 hfscatalogkeycmp(uchar *buf, int len, int *order, Key *key)
   1014 {
   1015 	return _hfscatalogkeycmp(buf, len, order, key, 1);
   1016 }
   1017 
   1018 static int
   1019 hfscatalogikeycmp(uchar *buf, int len, int *order, Key *key)
   1020 {
   1021 	return _hfscatalogkeycmp(buf, len, order, key, 0);
   1022 }
   1023 
   1024 static int
   1025 hfscatsearch(Hfs *fs, Catalogkey *k, Treeref *ref)
   1026 {
   1027 	Key key;
   1028 	int order;
   1029 
   1030 	key._cmp = fs->catalog.sensitive ? hfscatalogkeycmp : hfscatalogikeycmp;
   1031 	key.priv = k;
   1032 	if(hfstreesearch(&fs->catalog, &key, &order, ref) < 0 || order != 0){
   1033 		hfsrefput(ref);
   1034 		return -1;
   1035 	}
   1036 	return 0;
   1037 }
   1038 
   1039 static int
   1040 _hfscatalogkeycmp(uchar *buf, int len, int *order, Key *key, int sensitive)
   1041 {
   1042 	Catalogkey a, *b;
   1043 	int diff;
   1044 
   1045 	if(getcatalogkey(&a, buf, len, 0) < 0)
   1046 		return -1;
   1047 	b = key->priv;
   1048 
   1049 	diff = a.parent - b->parent;
   1050 	if(diff == 0){
   1051 		if(getname(&a.u.name, a.u.b) < 0)
   1052 			return -1;
   1053 		if(sensitive)
   1054 			diff = hfsnamecmp(&a.u.name, &b->u.name);
   1055 		else
   1056 			diff = hfsinamecmp(&a.u.name, &b->u.name);
   1057 	}
   1058 	*order = diff;
   1059 	return 0;
   1060 }
   1061 
   1062 static int
   1063 hfskeycmp(uchar *k, int len, int *order, Key *key)
   1064 {
   1065 	return (*key->_cmp)(k, len, order, key);
   1066 }
   1067 
   1068 /*
   1069 	Find the record with the largest key k' <= key.
   1070 */
   1071 static int
   1072 hfstreesearch(Tree *tree, Key *key, int *porder, Treeref *ref)
   1073 {
   1074 	u32int nno;
   1075 	int h, i, found, order, rel;
   1076 
   1077 	hfsref(tree, ref);
   1078 	nno = tree->root;
   1079 	rel = 0;	/* silence a warning */
   1080 	for(h=tree->height; h>0; h--){
   1081 		if(hfsrefnode(ref, nno) < 0)
   1082 			goto error;
   1083 		found = -1;
   1084 		/*
   1085 			We could use binary search.
   1086 		*/
   1087 		for(i=0; i < ref->node.nrec; i++){
   1088 			if(hfsrefrec(ref, i) < 0)
   1089 				goto error;
   1090 			if(hfskeycmp(ref->key, ref->klen, &order, key) < 0)
   1091 				goto error;
   1092 			if(order > 0)
   1093 				break;
   1094 			found = i;
   1095 			rel = order;
   1096 			if(order == 0)
   1097 				break;
   1098 		}
   1099 		if(found < 0 || hfsrefrec(ref, found) < 0)
   1100 			goto error;
   1101 		if(h == 1){
   1102 			if(porder)
   1103 				*porder = rel;
   1104 			return 0;
   1105 		}
   1106 		if(ref->dlen != 4){
   1107 			if(debug) fprint(2, "tree %ud node %ud rec %d bad %d-byte pointer\n",
   1108 				ref->cnid, ref->nno, ref->rno, ref->dlen);
   1109 			goto error;
   1110 		}
   1111 		nno = get32(ref->data);
   1112 	}
   1113 
   1114 error:
   1115 	hfsrefput(ref);
   1116 	return -1;
   1117 }
   1118 
   1119 static void
   1120 hfstreenodeclose(Block *b)
   1121 {
   1122 	free(b);
   1123 }
   1124 
   1125 static Block*
   1126 hfstreenode(Tree *tree, u32int nno)
   1127 {
   1128 	Hfs *fs;
   1129 	Fork *fork;
   1130 	Block *b;
   1131 	int len;
   1132 
   1133 	fs = tree->fs;
   1134 	fork = tree->fork;
   1135 	len = tree->nodesize;
   1136 	if(nno >= tree->nnodes){
   1137 		if(debug) fprint(2, "bad tree %ud node %ud\n", tree->fork->cnid, nno);
   1138 		return nil;
   1139 	}
   1140 
   1141 	if(len == fs->blocksize)
   1142 		return hfsforkblock(fs, fork, nno);
   1143 
   1144 	b = mallocz(sizeof(Block)+len, 1);
   1145 	if(b == nil)
   1146 		return nil;
   1147 	b->data = (uchar*)&b[1];
   1148 	b->len = len;
   1149 	if(hfsforkread(fs, fork, b->data, len, (u64int)nno*len) < 0){
   1150 		free(b);
   1151 		return nil;
   1152 	}
   1153 	b->_close = hfstreenodeclose;
   1154 
   1155 	return b;
   1156 }
   1157 
   1158 /*
   1159 	After hfsref:
   1160 
   1161 	if rno >= 0, then every field is valid.
   1162 	if block != nil, then tree through node are valid.
   1163 	tree and cnid are valid.
   1164 */
   1165 static void
   1166 hfsref(Tree *tree, Treeref *ref)
   1167 {
   1168 	memset(ref, 0, sizeof(Treeref));
   1169 	ref->tree = tree;
   1170 	ref->cnid = ref->tree->fork->cnid;
   1171 	ref->rno = -1;
   1172 }
   1173 
   1174 static void
   1175 hfsrefput(Treeref *ref)
   1176 {
   1177 	blockput(ref->block);
   1178 	ref->block = nil;
   1179 	ref->rno = -1;
   1180 }
   1181 
   1182 static int
   1183 hfsrefnode(Treeref *ref, u32int nno)
   1184 {
   1185 	if(ref->block && ref->nno==nno)
   1186 		return 0;
   1187 
   1188 	ref->rno = -1;
   1189 	blockput(ref->block);
   1190 	if((ref->block = hfstreenode(ref->tree, nno)) == nil)
   1191 		return -1;
   1192 	ref->nno = nno;
   1193 	getnodedesc(&ref->node, ref->block->data);
   1194 	/*
   1195 		Hfsrefrec assumes all record offsets lie in the block.
   1196 	*/
   1197 	if(ref->node.nrec > (ref->tree->nodesize-Ndlen-2)/2){
   1198 		if(debug) fprint(2, "tree %ud node %ud bad nrec %d\n",
   1199 			ref->cnid, ref->nno, ref->node.nrec);
   1200 		blockput(ref->block);
   1201 		ref->block = nil;
   1202 		return -1;
   1203 	}
   1204 	return 0;
   1205 }
   1206 
   1207 static int
   1208 hfsrefrec(Treeref *ref, int rno)
   1209 {
   1210 	uchar *node, *o, *r, *n;
   1211 	int klen;
   1212 
   1213 	if(ref->block == nil || rno < 0 || rno >= ref->node.nrec)
   1214 		return -1;
   1215 
   1216 	if(ref->rno == rno)
   1217 		return 0;
   1218 
   1219 	/*
   1220 		We could use Tree.indexkeylen to avoid reading offsets
   1221 		from extent tree nodes.
   1222 	*/
   1223 	node = ref->block->data;
   1224 	o = node+ref->tree->nodesize-2*(rno+1);
   1225 	r = node+get16(o);
   1226 	n = node+get16(o-2);
   1227 	if(r < node+Ndlen || n <= r+2 || o < n){
   1228 		if(debug) fprint(2, "tree %ud node %ud rec %d bad offsets %d %d %d\n",
   1229 			ref->cnid, ref->nno, rno, r-node, n-node, o-node);
   1230 		return -1;
   1231 	}
   1232 	ref->rno = rno;
   1233 	klen = 2+get16(r);	/* actual length */
   1234 	ref->klen = klen;
   1235 	ref->key = r;
   1236 	ref->data = r+klen+(klen&1);
   1237 	ref->dlen = n-ref->data;	/* includes any pad byte */
   1238 	return 0;
   1239 }
   1240 
   1241 static int
   1242 hfsrefnextrec(Treeref *ref)
   1243 {
   1244 	int rno;
   1245 	u32int nno;
   1246 
   1247 	if(ref->block == nil)
   1248 		return -1;
   1249 	rno = ref->rno < 0 ? 0 : ref->rno+1;
   1250 	if(rno < ref->node.nrec)
   1251 		return hfsrefrec(ref, rno);
   1252 	nno = ref->node.next;
   1253 	if(nno==0 || hfsrefnode(ref, nno) < 0 || ref->node.nrec==0)
   1254 		return -1;
   1255 	return hfsrefrec(ref, 0);
   1256 }
   1257 
   1258 static int
   1259 hfsforkread(Hfs *fs, Fork *fork, uchar *data, u32int count, u64int offset)
   1260 {
   1261 	u32int bno;
   1262 	int skip, frag;
   1263 	Block *b;
   1264 
   1265 	if(offset+count > fork->size){
   1266 		if(debug) fprint(2, "read past end of fork\n");
   1267 		return -1;
   1268 	}
   1269 
   1270 	if(count == 0)
   1271 		return 0;
   1272 
   1273 	bno = offset/fs->blocksize;
   1274 	skip = offset%fs->blocksize;
   1275 	frag = fs->blocksize - skip;
   1276 	if(frag > count)
   1277 		frag = count;
   1278 	if((b = hfsforkblock(fs, fork, bno)) == nil)
   1279 		return -1;
   1280 	memmove(data, b->data+skip, frag);
   1281 	blockput(b);
   1282 	data += frag;
   1283 	count -= frag;
   1284 	bno++;
   1285 	while(count > fs->blocksize){
   1286 		if((b = hfsforkblock(fs, fork, bno)) == nil)
   1287 			return -1;
   1288 		memmove(data, b->data, fs->blocksize);
   1289 		blockput(b);
   1290 		data += fs->blocksize;
   1291 		count -= fs->blocksize;
   1292 		bno++;
   1293 	}
   1294 	if(count > 0){
   1295 		if((b = hfsforkblock(fs, fork, bno)) == nil)
   1296 			return -1;
   1297 		memmove(data, b->data, count);
   1298 		blockput(b);
   1299 	}
   1300 	return 0;
   1301 }
   1302 
   1303 static Block*
   1304 hfsforkblock(Hfs *fs, Fork *fork, u32int bno)
   1305 {
   1306 	u32int skip, start;
   1307 	int i;
   1308 	Extent *e;
   1309 	Extent other[NEXTENTS];
   1310 
   1311 	if(bno >= fork->nblocks){
   1312 		if(debug) fprint(2, "bad fork %ud %d block %ud\n",
   1313 			fork->cnid, fork->type, bno);
   1314 		return nil;
   1315 	}
   1316 	skip = bno;
   1317 	e = fork->extent;
   1318 	for(i=0; i<NEXTENTS; i++, e++){
   1319 		if(skip < e->count)
   1320 			return hfsblock(fs, e->start+skip);
   1321 		else
   1322 			skip -= e->count;
   1323 	}
   1324 	if(fork->cnid == ExtentsId){
   1325 		if(debug) fprint(2, "extents fork overflow\n");
   1326 		return nil;
   1327 	}
   1328 	if(hfsextentsearch(fs, fork->cnid, fork->type, bno, &start, other) < 0)
   1329 		return nil;
   1330 	skip = bno-start;
   1331 	e = other;
   1332 	for(i=0; i<NEXTENTS; i++, e++){
   1333 		if(skip < e->count)
   1334 			return hfsblock(fs, e->start+skip);
   1335 		else
   1336 			skip -= e->count;
   1337 	}
   1338 	if(debug) fprint(2, "bad extents overflow fork %ud %d block %ud skip %ud\n",
   1339 		fork->cnid, fork->type, bno, skip);
   1340 	return nil;
   1341 }
   1342 
   1343 static Block*
   1344 hfsblock(Hfs *fs, u32int bno)
   1345 {
   1346 	if(bno >= fs->nblock){
   1347 		if(debug) fprint(2, "bad block %ud\n", bno);
   1348 		return nil;
   1349 	}
   1350 	return diskread(fs->disk, fs->blocksize, (u64int)bno*fs->blocksize);
   1351 }
   1352 
   1353 static void
   1354 getnodedesc(Node *n, uchar *b)
   1355 {
   1356 	n->type = (s8int)b[8];
   1357 	n->next = get32(b);
   1358 	n->nrec = get16(b+10);
   1359 }
   1360 
   1361 static void
   1362 getfork(Fork *f, u32int cnid, int type, uchar *b)
   1363 {
   1364 	f->cnid = cnid;
   1365 	f->type = type;
   1366 	f->size = get64(b);
   1367 	f->nblocks = get32(b+12);
   1368 	getextents(f->extent, b+16);
   1369 }
   1370 
   1371 static void
   1372 getextents(Extent *e, uchar *b)
   1373 {
   1374 	int i;
   1375 
   1376 	for(i=0; i<NEXTENTS; i++){
   1377 		getextent(e+i, b);
   1378 		b += Extentlen;
   1379 	}
   1380 }
   1381 
   1382 static void
   1383 getextent(Extent *e, uchar *b)
   1384 {
   1385 	e->start = get32(b);
   1386 	e->count = get32(b+4);
   1387 }
   1388 
   1389 static int
   1390 getextentkey(Extentkey *k, uchar *b, int len)
   1391 {
   1392 	if(len != 12){
   1393 		if(debug) fprint(2, "bad extents key length %d\n", len);
   1394 		return -1;
   1395 	}
   1396 	k->cnid = get32(b+4);
   1397 	k->type = b[2];
   1398 	k->bno = get32(b+8);
   1399 	return 0;
   1400 }
   1401 
   1402 static int
   1403 getcatalogrecord(Inode *ino, uchar *b, int blen)
   1404 {
   1405 	int t;
   1406 	uchar *p;
   1407 
   1408 	if(blen != Folderlen && blen != Filelen){
   1409 		if(debug) fprint(2, "bad catalog entry length %d\n", blen);
   1410 		return -1;
   1411 	}
   1412 	t = get16(b);
   1413 	if((blen == Folderlen && t != Folder)
   1414 	|| (blen == Filelen && t != File)){
   1415 		if(debug) fprint(2, "catalog entry type %d length %d mismatch\n", t, blen);
   1416 		return -1;
   1417 	}
   1418 	ino->cnid = get32(b+8);
   1419 	ino->fileid = ino->cnid;
   1420 	ino->mtime = gettime(b+16);
   1421 	ino->ctime = gettime(b+20);
   1422 	ino->atime = gettime(b+24);
   1423 	p = b+32;
   1424 	ino->nlink = 1;
   1425 	ino->uid = get32(p+0);
   1426 	ino->gid = get32(p+4);
   1427 	ino->mode = get16(p+10);
   1428 	ino->special = get32(p+12);
   1429 	if(t == Folder)
   1430 		ino->u.nentries = get32(b+4);
   1431 	else{
   1432 		getfork(&ino->u.f.dfork, ino->cnid, Dfork, b+88);
   1433 		getfork(&ino->u.f.rfork, ino->cnid, Rfork, b+168);
   1434 		memcpy(ino->u.f.info, b+48, Filen);
   1435 		ino->u.f.nhdr = 0;
   1436 		ino->u.f.fork = &ino->u.f.dfork;
   1437 	}
   1438 	return 0;
   1439 }
   1440 
   1441 static int
   1442 getcatalogthread(Catalogkey *k, uchar *b, int blen)
   1443 {
   1444 	int t;
   1445 
   1446 	if(blen > 10+2*NAMELEN){
   1447 		if(debug) fprint(2, "bad catalog thread length %d\n", blen);
   1448 		return -1;
   1449 	}
   1450 	t = get16(b);
   1451 	if(t != FolderThread && t != FileThread){
   1452 		if(debug) fprint(2, "bad catalog thread type %d\n", t);
   1453 		return -1;
   1454 	}
   1455 	return getcatalogkey(k, b+2, blen-2, 1);
   1456 }
   1457 
   1458 static int
   1459 getcatalogkey(Catalogkey *k, uchar *b, int blen, int decode)
   1460 {
   1461 	if(blen > 8+2*NAMELEN){
   1462 		if(debug) fprint(2, "bad catalog key length %d\n", blen);
   1463 		return -1;
   1464 	}
   1465 	k->parent = get32(b+2);
   1466 	if(decode)
   1467 		return getname(&k->u.name, b+6);
   1468 	k->u.b = b+6;
   1469 	return 0;
   1470 }
   1471 
   1472 static int
   1473 getname(Name *n, uchar *b)
   1474 {
   1475 	int i;
   1476 
   1477 	n->len = get16(b);
   1478 	if(n->len > NAMELEN){
   1479 		if(debug) fprint(2, "bad name length %d\n", n->len);
   1480 		return -1;
   1481 	}
   1482 	b += 2;
   1483 	for(i=0; i<n->len; i++, b += 2)
   1484 		n->name[i] = get16(b);
   1485 	return 0;
   1486 }
   1487 
   1488 static u32int
   1489 gettime(uchar *b)
   1490 {
   1491 	return get32(b) - 2082844800;
   1492 }
   1493 
   1494 static u64int
   1495 get64(uchar *b)
   1496 {
   1497 	return ((u64int)get32(b))<<32 | get32(b+4);
   1498 }
   1499 
   1500 static u32int
   1501 get32(uchar *b)
   1502 {
   1503 	return b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3];
   1504 }
   1505 
   1506 static int
   1507 get16(uchar *b)
   1508 {
   1509 	return b[0]<<8 | b[1];
   1510 }
   1511 
   1512 static void
   1513 put32(uchar *b, u32int n)
   1514 {
   1515 	b[0] = n>>24;
   1516 	b[1] = n>>16;
   1517 	b[2] = n>>8;
   1518 	b[3] = n;
   1519 }
   1520 
   1521 /*
   1522 	Adapted from FastUnicodeCompare in Apple technical note 1150.
   1523 */
   1524 static u16int
   1525 hfslcase[] =
   1526 {
   1527 	/* High-byte indices ( == 0 iff no case mapping and no ignorables ) */
   1528 
   1529 	0x0100, 0x0200, 0x0000, 0x0300, 0x0400, 0x0500, 0x0000, 0x0000,
   1530 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1531 	0x0600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1532 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1533 	0x0700, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1534 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1535 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1536 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1537 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1538 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1539 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1540 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1541 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1542 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1543 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1544 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1545 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1546 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1547 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1548 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1549 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1550 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1551 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1552 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1553 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1554 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1555 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1556 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1557 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1558 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1559 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1560 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0900, 0x0A00,
   1561 
   1562 	/* Table 1 (for high byte 0x00) */
   1563 
   1564 	0xFFFF, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
   1565 	0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
   1566 	0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
   1567 	0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
   1568 	0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
   1569 	0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
   1570 	0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
   1571 	0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
   1572 	0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
   1573 	0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
   1574 	0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
   1575 	0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
   1576 	0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
   1577 	0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
   1578 	0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
   1579 	0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
   1580 	0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
   1581 	0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
   1582 	0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
   1583 	0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
   1584 	0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
   1585 	0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
   1586 	0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
   1587 	0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
   1588 	0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00E6, 0x00C7,
   1589 	0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
   1590 	0x00F0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
   1591 	0x00F8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00FE, 0x00DF,
   1592 	0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
   1593 	0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
   1594 	0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
   1595 	0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
   1596 
   1597 	/* Table 2 (for high byte 0x01) */
   1598 
   1599 	0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107,
   1600 	0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F,
   1601 	0x0111, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117,
   1602 	0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, 0x011F,
   1603 	0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0127, 0x0127,
   1604 	0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F,
   1605 	0x0130, 0x0131, 0x0133, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137,
   1606 	0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x0140,
   1607 	0x0140, 0x0142, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147,
   1608 	0x0148, 0x0149, 0x014B, 0x014B, 0x014C, 0x014D, 0x014E, 0x014F,
   1609 	0x0150, 0x0151, 0x0153, 0x0153, 0x0154, 0x0155, 0x0156, 0x0157,
   1610 	0x0158, 0x0159, 0x015A, 0x015B, 0x015C, 0x015D, 0x015E, 0x015F,
   1611 	0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165, 0x0167, 0x0167,
   1612 	0x0168, 0x0169, 0x016A, 0x016B, 0x016C, 0x016D, 0x016E, 0x016F,
   1613 	0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177,
   1614 	0x0178, 0x0179, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x017F,
   1615 	0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188,
   1616 	0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259,
   1617 	0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268,
   1618 	0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275,
   1619 	0x01A0, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x01A6, 0x01A8,
   1620 	0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01AF,
   1621 	0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292,
   1622 	0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF,
   1623 	0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9,
   1624 	0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC, 0x01CD, 0x01CE, 0x01CF,
   1625 	0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6, 0x01D7,
   1626 	0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, 0x01DD, 0x01DE, 0x01DF,
   1627 	0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E5, 0x01E5, 0x01E6, 0x01E7,
   1628 	0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x01EC, 0x01ED, 0x01EE, 0x01EF,
   1629 	0x01F0, 0x01F3, 0x01F3, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7,
   1630 	0x01F8, 0x01F9, 0x01FA, 0x01FB, 0x01FC, 0x01FD, 0x01FE, 0x01FF,
   1631 
   1632 	/* Table 3 (for high byte 0x03) */
   1633 
   1634 	0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307,
   1635 	0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F,
   1636 	0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317,
   1637 	0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F,
   1638 	0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327,
   1639 	0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F,
   1640 	0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337,
   1641 	0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F,
   1642 	0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347,
   1643 	0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F,
   1644 	0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357,
   1645 	0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F,
   1646 	0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367,
   1647 	0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F,
   1648 	0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377,
   1649 	0x0378, 0x0379, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x037F,
   1650 	0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387,
   1651 	0x0388, 0x0389, 0x038A, 0x038B, 0x038C, 0x038D, 0x038E, 0x038F,
   1652 	0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
   1653 	0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
   1654 	0x03C0, 0x03C1, 0x03A2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
   1655 	0x03C8, 0x03C9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
   1656 	0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
   1657 	0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
   1658 	0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
   1659 	0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x03CF,
   1660 	0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7,
   1661 	0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF,
   1662 	0x03E0, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7,
   1663 	0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF,
   1664 	0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7,
   1665 	0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF,
   1666 
   1667 	/* Table 4 (for high byte 0x04) */
   1668 
   1669 	0x0400, 0x0401, 0x0452, 0x0403, 0x0454, 0x0455, 0x0456, 0x0407,
   1670 	0x0458, 0x0459, 0x045A, 0x045B, 0x040C, 0x040D, 0x040E, 0x045F,
   1671 	0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
   1672 	0x0438, 0x0419, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
   1673 	0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
   1674 	0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
   1675 	0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
   1676 	0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
   1677 	0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
   1678 	0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
   1679 	0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
   1680 	0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045D, 0x045E, 0x045F,
   1681 	0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467,
   1682 	0x0469, 0x0469, 0x046B, 0x046B, 0x046D, 0x046D, 0x046F, 0x046F,
   1683 	0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0476, 0x0477,
   1684 	0x0479, 0x0479, 0x047B, 0x047B, 0x047D, 0x047D, 0x047F, 0x047F,
   1685 	0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487,
   1686 	0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F,
   1687 	0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497,
   1688 	0x0499, 0x0499, 0x049B, 0x049B, 0x049D, 0x049D, 0x049F, 0x049F,
   1689 	0x04A1, 0x04A1, 0x04A3, 0x04A3, 0x04A5, 0x04A5, 0x04A7, 0x04A7,
   1690 	0x04A9, 0x04A9, 0x04AB, 0x04AB, 0x04AD, 0x04AD, 0x04AF, 0x04AF,
   1691 	0x04B1, 0x04B1, 0x04B3, 0x04B3, 0x04B5, 0x04B5, 0x04B7, 0x04B7,
   1692 	0x04B9, 0x04B9, 0x04BB, 0x04BB, 0x04BD, 0x04BD, 0x04BF, 0x04BF,
   1693 	0x04C0, 0x04C1, 0x04C2, 0x04C4, 0x04C4, 0x04C5, 0x04C6, 0x04C8,
   1694 	0x04C8, 0x04C9, 0x04CA, 0x04CC, 0x04CC, 0x04CD, 0x04CE, 0x04CF,
   1695 	0x04D0, 0x04D1, 0x04D2, 0x04D3, 0x04D4, 0x04D5, 0x04D6, 0x04D7,
   1696 	0x04D8, 0x04D9, 0x04DA, 0x04DB, 0x04DC, 0x04DD, 0x04DE, 0x04DF,
   1697 	0x04E0, 0x04E1, 0x04E2, 0x04E3, 0x04E4, 0x04E5, 0x04E6, 0x04E7,
   1698 	0x04E8, 0x04E9, 0x04EA, 0x04EB, 0x04EC, 0x04ED, 0x04EE, 0x04EF,
   1699 	0x04F0, 0x04F1, 0x04F2, 0x04F3, 0x04F4, 0x04F5, 0x04F6, 0x04F7,
   1700 	0x04F8, 0x04F9, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF,
   1701 
   1702 	/* Table 5 (for high byte 0x05) */
   1703 
   1704 	0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507,
   1705 	0x0508, 0x0509, 0x050A, 0x050B, 0x050C, 0x050D, 0x050E, 0x050F,
   1706 	0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517,
   1707 	0x0518, 0x0519, 0x051A, 0x051B, 0x051C, 0x051D, 0x051E, 0x051F,
   1708 	0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527,
   1709 	0x0528, 0x0529, 0x052A, 0x052B, 0x052C, 0x052D, 0x052E, 0x052F,
   1710 	0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
   1711 	0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
   1712 	0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
   1713 	0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
   1714 	0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557,
   1715 	0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F,
   1716 	0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
   1717 	0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
   1718 	0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
   1719 	0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
   1720 	0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587,
   1721 	0x0588, 0x0589, 0x058A, 0x058B, 0x058C, 0x058D, 0x058E, 0x058F,
   1722 	0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597,
   1723 	0x0598, 0x0599, 0x059A, 0x059B, 0x059C, 0x059D, 0x059E, 0x059F,
   1724 	0x05A0, 0x05A1, 0x05A2, 0x05A3, 0x05A4, 0x05A5, 0x05A6, 0x05A7,
   1725 	0x05A8, 0x05A9, 0x05AA, 0x05AB, 0x05AC, 0x05AD, 0x05AE, 0x05AF,
   1726 	0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7,
   1727 	0x05B8, 0x05B9, 0x05BA, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
   1728 	0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05C4, 0x05C5, 0x05C6, 0x05C7,
   1729 	0x05C8, 0x05C9, 0x05CA, 0x05CB, 0x05CC, 0x05CD, 0x05CE, 0x05CF,
   1730 	0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
   1731 	0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
   1732 	0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
   1733 	0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC, 0x05ED, 0x05EE, 0x05EF,
   1734 	0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x05F5, 0x05F6, 0x05F7,
   1735 	0x05F8, 0x05F9, 0x05FA, 0x05FB, 0x05FC, 0x05FD, 0x05FE, 0x05FF,
   1736 
   1737 	/* Table 6 (for high byte 0x10) */
   1738 
   1739 	0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007,
   1740 	0x1008, 0x1009, 0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F,
   1741 	0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017,
   1742 	0x1018, 0x1019, 0x101A, 0x101B, 0x101C, 0x101D, 0x101E, 0x101F,
   1743 	0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027,
   1744 	0x1028, 0x1029, 0x102A, 0x102B, 0x102C, 0x102D, 0x102E, 0x102F,
   1745 	0x1030, 0x1031, 0x1032, 0x1033, 0x1034, 0x1035, 0x1036, 0x1037,
   1746 	0x1038, 0x1039, 0x103A, 0x103B, 0x103C, 0x103D, 0x103E, 0x103F,
   1747 	0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047,
   1748 	0x1048, 0x1049, 0x104A, 0x104B, 0x104C, 0x104D, 0x104E, 0x104F,
   1749 	0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057,
   1750 	0x1058, 0x1059, 0x105A, 0x105B, 0x105C, 0x105D, 0x105E, 0x105F,
   1751 	0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067,
   1752 	0x1068, 0x1069, 0x106A, 0x106B, 0x106C, 0x106D, 0x106E, 0x106F,
   1753 	0x1070, 0x1071, 0x1072, 0x1073, 0x1074, 0x1075, 0x1076, 0x1077,
   1754 	0x1078, 0x1079, 0x107A, 0x107B, 0x107C, 0x107D, 0x107E, 0x107F,
   1755 	0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087,
   1756 	0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x108F,
   1757 	0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097,
   1758 	0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x109F,
   1759 	0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7,
   1760 	0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
   1761 	0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7,
   1762 	0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
   1763 	0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10C6, 0x10C7,
   1764 	0x10C8, 0x10C9, 0x10CA, 0x10CB, 0x10CC, 0x10CD, 0x10CE, 0x10CF,
   1765 	0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7,
   1766 	0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
   1767 	0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7,
   1768 	0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
   1769 	0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10F6, 0x10F7,
   1770 	0x10F8, 0x10F9, 0x10FA, 0x10FB, 0x10FC, 0x10FD, 0x10FE, 0x10FF,
   1771 
   1772 	/* Table 7 (for high byte 0x20) */
   1773 
   1774 	0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007,
   1775 	0x2008, 0x2009, 0x200A, 0x200B, 0x0000, 0x0000, 0x0000, 0x0000,
   1776 	0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017,
   1777 	0x2018, 0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F,
   1778 	0x2020, 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027,
   1779 	0x2028, 0x2029, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x202F,
   1780 	0x2030, 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037,
   1781 	0x2038, 0x2039, 0x203A, 0x203B, 0x203C, 0x203D, 0x203E, 0x203F,
   1782 	0x2040, 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047,
   1783 	0x2048, 0x2049, 0x204A, 0x204B, 0x204C, 0x204D, 0x204E, 0x204F,
   1784 	0x2050, 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057,
   1785 	0x2058, 0x2059, 0x205A, 0x205B, 0x205C, 0x205D, 0x205E, 0x205F,
   1786 	0x2060, 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067,
   1787 	0x2068, 0x2069, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   1788 	0x2070, 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077,
   1789 	0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F,
   1790 	0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087,
   1791 	0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x208F,
   1792 	0x2090, 0x2091, 0x2092, 0x2093, 0x2094, 0x2095, 0x2096, 0x2097,
   1793 	0x2098, 0x2099, 0x209A, 0x209B, 0x209C, 0x209D, 0x209E, 0x209F,
   1794 	0x20A0, 0x20A1, 0x20A2, 0x20A3, 0x20A4, 0x20A5, 0x20A6, 0x20A7,
   1795 	0x20A8, 0x20A9, 0x20AA, 0x20AB, 0x20AC, 0x20AD, 0x20AE, 0x20AF,
   1796 	0x20B0, 0x20B1, 0x20B2, 0x20B3, 0x20B4, 0x20B5, 0x20B6, 0x20B7,
   1797 	0x20B8, 0x20B9, 0x20BA, 0x20BB, 0x20BC, 0x20BD, 0x20BE, 0x20BF,
   1798 	0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7,
   1799 	0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x20CF,
   1800 	0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7,
   1801 	0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x20DF,
   1802 	0x20E0, 0x20E1, 0x20E2, 0x20E3, 0x20E4, 0x20E5, 0x20E6, 0x20E7,
   1803 	0x20E8, 0x20E9, 0x20EA, 0x20EB, 0x20EC, 0x20ED, 0x20EE, 0x20EF,
   1804 	0x20F0, 0x20F1, 0x20F2, 0x20F3, 0x20F4, 0x20F5, 0x20F6, 0x20F7,
   1805 	0x20F8, 0x20F9, 0x20FA, 0x20FB, 0x20FC, 0x20FD, 0x20FE, 0x20FF,
   1806 
   1807 	/* Table 8 (for high byte 0x21) */
   1808 
   1809 	0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107,
   1810 	0x2108, 0x2109, 0x210A, 0x210B, 0x210C, 0x210D, 0x210E, 0x210F,
   1811 	0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117,
   1812 	0x2118, 0x2119, 0x211A, 0x211B, 0x211C, 0x211D, 0x211E, 0x211F,
   1813 	0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127,
   1814 	0x2128, 0x2129, 0x212A, 0x212B, 0x212C, 0x212D, 0x212E, 0x212F,
   1815 	0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137,
   1816 	0x2138, 0x2139, 0x213A, 0x213B, 0x213C, 0x213D, 0x213E, 0x213F,
   1817 	0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147,
   1818 	0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F,
   1819 	0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157,
   1820 	0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F,
   1821 	0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
   1822 	0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
   1823 	0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
   1824 	0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
   1825 	0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187,
   1826 	0x2188, 0x2189, 0x218A, 0x218B, 0x218C, 0x218D, 0x218E, 0x218F,
   1827 	0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197,
   1828 	0x2198, 0x2199, 0x219A, 0x219B, 0x219C, 0x219D, 0x219E, 0x219F,
   1829 	0x21A0, 0x21A1, 0x21A2, 0x21A3, 0x21A4, 0x21A5, 0x21A6, 0x21A7,
   1830 	0x21A8, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21AE, 0x21AF,
   1831 	0x21B0, 0x21B1, 0x21B2, 0x21B3, 0x21B4, 0x21B5, 0x21B6, 0x21B7,
   1832 	0x21B8, 0x21B9, 0x21BA, 0x21BB, 0x21BC, 0x21BD, 0x21BE, 0x21BF,
   1833 	0x21C0, 0x21C1, 0x21C2, 0x21C3, 0x21C4, 0x21C5, 0x21C6, 0x21C7,
   1834 	0x21C8, 0x21C9, 0x21CA, 0x21CB, 0x21CC, 0x21CD, 0x21CE, 0x21CF,
   1835 	0x21D0, 0x21D1, 0x21D2, 0x21D3, 0x21D4, 0x21D5, 0x21D6, 0x21D7,
   1836 	0x21D8, 0x21D9, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21DE, 0x21DF,
   1837 	0x21E0, 0x21E1, 0x21E2, 0x21E3, 0x21E4, 0x21E5, 0x21E6, 0x21E7,
   1838 	0x21E8, 0x21E9, 0x21EA, 0x21EB, 0x21EC, 0x21ED, 0x21EE, 0x21EF,
   1839 	0x21F0, 0x21F1, 0x21F2, 0x21F3, 0x21F4, 0x21F5, 0x21F6, 0x21F7,
   1840 	0x21F8, 0x21F9, 0x21FA, 0x21FB, 0x21FC, 0x21FD, 0x21FE, 0x21FF,
   1841 
   1842 	/* Table 9 (for high byte 0xFE) */
   1843 
   1844 	0xFE00, 0xFE01, 0xFE02, 0xFE03, 0xFE04, 0xFE05, 0xFE06, 0xFE07,
   1845 	0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F,
   1846 	0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, 0xFE16, 0xFE17,
   1847 	0xFE18, 0xFE19, 0xFE1A, 0xFE1B, 0xFE1C, 0xFE1D, 0xFE1E, 0xFE1F,
   1848 	0xFE20, 0xFE21, 0xFE22, 0xFE23, 0xFE24, 0xFE25, 0xFE26, 0xFE27,
   1849 	0xFE28, 0xFE29, 0xFE2A, 0xFE2B, 0xFE2C, 0xFE2D, 0xFE2E, 0xFE2F,
   1850 	0xFE30, 0xFE31, 0xFE32, 0xFE33, 0xFE34, 0xFE35, 0xFE36, 0xFE37,
   1851 	0xFE38, 0xFE39, 0xFE3A, 0xFE3B, 0xFE3C, 0xFE3D, 0xFE3E, 0xFE3F,
   1852 	0xFE40, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE45, 0xFE46, 0xFE47,
   1853 	0xFE48, 0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F,
   1854 	0xFE50, 0xFE51, 0xFE52, 0xFE53, 0xFE54, 0xFE55, 0xFE56, 0xFE57,
   1855 	0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, 0xFE5E, 0xFE5F,
   1856 	0xFE60, 0xFE61, 0xFE62, 0xFE63, 0xFE64, 0xFE65, 0xFE66, 0xFE67,
   1857 	0xFE68, 0xFE69, 0xFE6A, 0xFE6B, 0xFE6C, 0xFE6D, 0xFE6E, 0xFE6F,
   1858 	0xFE70, 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE75, 0xFE76, 0xFE77,
   1859 	0xFE78, 0xFE79, 0xFE7A, 0xFE7B, 0xFE7C, 0xFE7D, 0xFE7E, 0xFE7F,
   1860 	0xFE80, 0xFE81, 0xFE82, 0xFE83, 0xFE84, 0xFE85, 0xFE86, 0xFE87,
   1861 	0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 0xFE8D, 0xFE8E, 0xFE8F,
   1862 	0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, 0xFE96, 0xFE97,
   1863 	0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, 0xFE9E, 0xFE9F,
   1864 	0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, 0xFEA6, 0xFEA7,
   1865 	0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, 0xFEAE, 0xFEAF,
   1866 	0xFEB0, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, 0xFEB6, 0xFEB7,
   1867 	0xFEB8, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, 0xFEBE, 0xFEBF,
   1868 	0xFEC0, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, 0xFEC5, 0xFEC6, 0xFEC7,
   1869 	0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, 0xFECD, 0xFECE, 0xFECF,
   1870 	0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 0xFED5, 0xFED6, 0xFED7,
   1871 	0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, 0xFEDE, 0xFEDF,
   1872 	0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, 0xFEE6, 0xFEE7,
   1873 	0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, 0xFEEE, 0xFEEF,
   1874 	0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, 0xFEF6, 0xFEF7,
   1875 	0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0xFEFD, 0xFEFE, 0x0000,
   1876 
   1877 	/* Table 10 (for high byte 0xFF) */
   1878 
   1879 	0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07,
   1880 	0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F,
   1881 	0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17,
   1882 	0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F,
   1883 	0xFF20, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47,
   1884 	0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
   1885 	0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57,
   1886 	0xFF58, 0xFF59, 0xFF5A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F,
   1887 	0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47,
   1888 	0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
   1889 	0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57,
   1890 	0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E, 0xFF5F,
   1891 	0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67,
   1892 	0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F,
   1893 	0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77,
   1894 	0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F,
   1895 	0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87,
   1896 	0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F,
   1897 	0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97,
   1898 	0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F,
   1899 	0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0xFFA6, 0xFFA7,
   1900 	0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0xFFAE, 0xFFAF,
   1901 	0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, 0xFFB6, 0xFFB7,
   1902 	0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, 0xFFBE, 0xFFBF,
   1903 	0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC6, 0xFFC7,
   1904 	0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF,
   1905 	0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, 0xFFD6, 0xFFD7,
   1906 	0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, 0xFFDE, 0xFFDF,
   1907 	0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, 0xFFE6, 0xFFE7,
   1908 	0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, 0xFFEE, 0xFFEF,
   1909 	0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7,
   1910 	0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF,
   1911 };
   1912 
   1913 static int
   1914 hfsfold(int c)
   1915 {
   1916 	int i;
   1917 
   1918 	i = hfslcase[(c>>8)&255];
   1919 	if(i == 0)
   1920 		return c;
   1921 	return hfslcase[i+(c&255)];
   1922 }
   1923 
   1924 static int
   1925 hfsinamecmp(Name *a, Name *b)
   1926 {
   1927 	int an, bn, ac, bc, diff;
   1928 	Rune *ap, *bp;
   1929 
   1930 	an = a->len;
   1931 	ap = a->name;
   1932 	bn = b->len;
   1933 	bp = b->name;
   1934 	for(;;){
   1935 		ac = 0;
   1936 		while(an && !ac){
   1937 			ac = hfsfold(*ap);
   1938 			ap++;
   1939 			an--;
   1940 		}
   1941 		bc = 0;
   1942 		while(bn && !bc){
   1943 			bc = hfsfold(*bp);
   1944 			bp++;
   1945 			bn--;
   1946 		}
   1947 		diff = ac - bc;
   1948 		if(diff)
   1949 			return diff;
   1950 		if(ac == 0)
   1951 			return 0;
   1952 	}
   1953 }
   1954 
   1955 static int
   1956 hfsnamecmp(Name *a, Name *b)
   1957 {
   1958 	int n, diff;
   1959 	Rune *ap, *bp;
   1960 
   1961 	n = a->len;
   1962 	if(n > b->len)
   1963 		n = b->len;
   1964 	ap = a->name;
   1965 	bp = b->name;
   1966 	diff = 0;
   1967 	for(; n>0; n--, ap++, bp++){
   1968 		diff = *ap - *bp;
   1969 		if(diff)
   1970 			break;
   1971 	}
   1972 	if(diff == 0)
   1973 		diff = a->len - b->len;
   1974 	return diff;
   1975 }