1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <sys/systm.h>
24#include <sys/kernel.h>
25#include <sys/malloc.h>
26#include <sys/stat.h>
27#include <sys/mount.h>
28#include <sys/vnode.h>
29#include <sys/dirent.h>
30#include <vfs/vfs_support.h>
31#include <libkern/libkern.h>
32
33#include <sys/utfconv.h>
34
35#include "hfs.h"
36#include "hfs_catalog.h"
37#include "hfs_format.h"
38#include "hfs_endian.h"
39
40#include "hfscommon/headers/BTreesInternal.h"
41#include "hfscommon/headers/HFSUnicodeWrappers.h"
42
43
44
45
46
47#define BDINIT(bd, addr) { \
48 (bd).bufferAddress = (addr); \
49 (bd).itemSize = sizeof(*(addr)); \
50 (bd).itemCount = 1; \
51}
52
53
54struct btobj {
55 BTreeIterator iterator;
56 HFSPlusCatalogKey key;
57 CatalogRecord data;
58};
59
60struct update_state {
61 struct cat_desc * s_desc;
62 struct cat_attr * s_attr;
63 struct cat_fork * s_datafork;
64 struct cat_fork * s_rsrcfork;
65 struct hfsmount * s_hfsmp;
66};
67
68struct position_state {
69 int error;
70 u_int32_t count;
71 u_int32_t index;
72 u_int32_t parentID;
73 struct hfsmount *hfsmp;
74};
75
76
77u_char modetodirtype[16] = {
78 DT_REG, DT_FIFO, DT_CHR, DT_UNKNOWN,
79 DT_DIR, DT_UNKNOWN, DT_BLK, DT_UNKNOWN,
80 DT_REG, DT_UNKNOWN, DT_LNK, DT_UNKNOWN,
81 DT_SOCK, DT_UNKNOWN, DT_WHT, DT_UNKNOWN
82};
83#define MODE_TO_DT(mode) (modetodirtype[((mode) & S_IFMT) >> 12])
84
85
86static int cat_lookupbykey(struct hfsmount *hfsmp, CatalogKey *keyp, u_long hint, int wantrsrc,
87 struct cat_desc *descp, struct cat_attr *attrp, struct cat_fork *forkp, cnid_t *desc_cnid);
88
89static int cat_lookupmangled(struct hfsmount *hfsmp, struct cat_desc *descp, int wantrsrc,
90 struct cat_desc *outdescp, struct cat_attr *attrp, struct cat_fork *forkp);
91
92extern int mac_roman_to_unicode(const Str31 hfs_str, UniChar *uni_str,
93 UInt32 maxCharLen, UInt32 *unicodeChars);
94
95extern int unicode_to_hfs(ExtendedVCB *vcb, ByteCount srcLen,
96 const u_int16_t* srcStr, Str31 dstStr, int retry);
97
98
99
100
101static int cat_findposition(const CatalogKey *ckp, const CatalogRecord *crp,
102 struct position_state *state);
103
104static int resolvelinkid(struct hfsmount *hfsmp, u_long linkref, ino_t *ino);
105
106static int getkey(struct hfsmount *hfsmp, cnid_t cnid, CatalogKey * key);
107
108static int buildkey(struct hfsmount *hfsmp, struct cat_desc *descp,
109 HFSPlusCatalogKey *key, int retry);
110
111static void buildthreadkey(HFSCatalogNodeID parentID, int std_hfs, CatalogKey *key);
112
113static void buildrecord(struct cat_attr *attrp, cnid_t cnid, int std_hfs, u_int32_t encoding, CatalogRecord *crp, int *recordSize);
114
115static int catrec_update(const CatalogKey *ckp, CatalogRecord *crp, struct update_state *state);
116
117static int builddesc(const HFSPlusCatalogKey *key, cnid_t cnid, u_long hint, u_long encoding,
118 int isdir, struct cat_desc *descp);
119
120static void getbsdattr(struct hfsmount *hfsmp, const struct HFSPlusCatalogFile *crp, struct cat_attr * attrp);
121
122static void promotekey(struct hfsmount *hfsmp, const HFSCatalogKey *hfskey, HFSPlusCatalogKey *keyp, u_long *encoding);
123static void promotefork(struct hfsmount *hfsmp, const struct HFSCatalogFile *file, int resource, struct cat_fork * forkp);
124static void promoteattr(struct hfsmount *hfsmp, const CatalogRecord *dataPtr, struct HFSPlusCatalogFile *crp);
125
126static cnid_t getcnid(const CatalogRecord *crp);
127static u_long getencoding(const CatalogRecord *crp);
128static cnid_t getparentcnid(const CatalogRecord *recp);
129
130static int isadir(const CatalogRecord *crp);
131
132static int buildthread(void *keyp, void *recp, int std_hfs, int directory);
133
134
135__private_extern__
136int
137cat_preflight(struct hfsmount *hfsmp, catops_t ops, cat_cookie_t *cookie, struct proc *p)
138{
139 FCB *fcb;
140 int lockflags;
141 int result;
142
143 fcb = GetFileControlBlock(hfsmp->hfs_catalog_vp);
144
145 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK);
146
147 result = BTReserveSpace(fcb, ops, (void*)cookie);
148
149 hfs_systemfile_unlock(hfsmp, lockflags);
150
151 return MacToVFSError(result);
152}
153
154__private_extern__
155void
156cat_postflight(struct hfsmount *hfsmp, cat_cookie_t *cookie, struct proc *p)
157{
158 FCB *fcb;
159 int lockflags;
160
161 fcb = GetFileControlBlock(hfsmp->hfs_catalog_vp);
162
163 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK);
164
165 (void) BTReleaseReserve(fcb, (void*)cookie);
166
167 hfs_systemfile_unlock(hfsmp, lockflags);
168}
169
170
171__private_extern__
172void
173cat_convertattr(
174 struct hfsmount *hfsmp,
175 CatalogRecord * recp,
176 struct cat_attr *attrp,
177 struct cat_fork *datafp,
178 struct cat_fork *rsrcfp)
179{
180 int std_hfs = HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord;
181
182 if (std_hfs) {
183 struct HFSPlusCatalogFile cnoderec;
184
185 promoteattr(hfsmp, recp, &cnoderec);
186 getbsdattr(hfsmp, &cnoderec, attrp);
187 } else {
188 getbsdattr(hfsmp, (struct HFSPlusCatalogFile *)recp, attrp);
189 }
190
191 if (isadir(recp))
192 bzero(datafp, sizeof(*datafp));
193 else if (std_hfs) {
194 promotefork(hfsmp, (HFSCatalogFile *)&recp->hfsFile, 0, datafp);
195 promotefork(hfsmp, (HFSCatalogFile *)&recp->hfsFile, 1, rsrcfp);
196 } else {
197
198 datafp->cf_size = recp->hfsPlusFile.dataFork.logicalSize;
199 datafp->cf_blocks = recp->hfsPlusFile.dataFork.totalBlocks;
200 if ((hfsmp->hfc_stage == HFC_RECORDING) &&
201 (attrp->ca_atime >= hfsmp->hfc_timebase)) {
202 datafp->cf_bytesread =
203 recp->hfsPlusFile.dataFork.clumpSize *
204 HFSTOVCB(hfsmp)->blockSize;
205 } else {
206 datafp->cf_bytesread = 0;
207 }
208 datafp->cf_vblocks = 0;
209 bcopy(&recp->hfsPlusFile.dataFork.extents[0],
210 &datafp->cf_extents[0], sizeof(HFSPlusExtentRecord));
211
212
213 rsrcfp->cf_size = recp->hfsPlusFile.resourceFork.logicalSize;
214 rsrcfp->cf_blocks = recp->hfsPlusFile.resourceFork.totalBlocks;
215 if ((hfsmp->hfc_stage == HFC_RECORDING) &&
216 (attrp->ca_atime >= hfsmp->hfc_timebase)) {
217 datafp->cf_bytesread =
218 recp->hfsPlusFile.resourceFork.clumpSize *
219 HFSTOVCB(hfsmp)->blockSize;
220 } else {
221 datafp->cf_bytesread = 0;
222 }
223 rsrcfp->cf_vblocks = 0;
224 bcopy(&recp->hfsPlusFile.resourceFork.extents[0],
225 &rsrcfp->cf_extents[0], sizeof(HFSPlusExtentRecord));
226 }
227}
228
229__private_extern__
230int
231cat_convertkey(
232 struct hfsmount *hfsmp,
233 CatalogKey *key,
234 CatalogRecord * recp,
235 struct cat_desc *descp)
236{
237 int std_hfs = HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord;
238 HFSPlusCatalogKey * pluskey = NULL;
239 u_long encoding;
240
241 if (std_hfs) {
242 MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK);
243 promotekey(hfsmp, (HFSCatalogKey *)key, pluskey, &encoding);
244
245 } else {
246 pluskey = (HFSPlusCatalogKey *)key;
247 encoding = getencoding(recp);
248 }
249
250 builddesc(pluskey, getcnid(recp), 0, encoding, isadir(recp), descp);
251 if (std_hfs) {
252 FREE(pluskey, M_TEMP);
253 }
254 return (0);
255}
256
257
258
259
260
261__private_extern__
262void
263cat_releasedesc(struct cat_desc *descp)
264{
265 char * name;
266
267 if (descp == NULL)
268 return;
269
270 if ((descp->cd_flags & CD_HASBUF) &&
271 (descp->cd_nameptr != NULL)) {
272 name = descp->cd_nameptr;
273 descp->cd_nameptr = NULL;
274 descp->cd_namelen = 0;
275 descp->cd_flags &= ~CD_HASBUF;
276 vfs_removename(name);
277 }
278 descp->cd_nameptr = NULL;
279 descp->cd_namelen = 0;
280}
281
282
283
284
285
286
287
288
289
290__private_extern__
291int
292cat_lookup(struct hfsmount *hfsmp, struct cat_desc *descp, int wantrsrc,
293 struct cat_desc *outdescp, struct cat_attr *attrp,
294 struct cat_fork *forkp, cnid_t *desc_cnid)
295{
296 CatalogKey * keyp;
297 int std_hfs;
298 int result;
299
300 std_hfs = (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord);
301
302 MALLOC(keyp, CatalogKey *, sizeof(CatalogKey), M_TEMP, M_WAITOK);
303
304 result = buildkey(hfsmp, descp, (HFSPlusCatalogKey *)keyp, 1);
305 if (result)
306 goto exit;
307
308 result = cat_lookupbykey(hfsmp, keyp, descp->cd_hint, wantrsrc, outdescp, attrp, forkp, desc_cnid);
309
310 if (result == ENOENT) {
311 if (!std_hfs) {
312 struct cat_desc temp_desc;
313 if (outdescp == NULL) {
314 bzero(&temp_desc, sizeof(temp_desc));
315 outdescp = &temp_desc;
316 }
317 result = cat_lookupmangled(hfsmp, descp, wantrsrc, outdescp, attrp, forkp);
318 if (desc_cnid) {
319 *desc_cnid = outdescp->cd_cnid;
320 }
321 if (outdescp == &temp_desc) {
322
323 cat_releasedesc(outdescp);
324 }
325 } else if (hfsmp->hfs_encoding != kTextEncodingMacRoman) {
326
327
328
329 }
330 }
331exit:
332 FREE(keyp, M_TEMP);
333
334 return (result);
335}
336
337__private_extern__
338int
339cat_insertfilethread(struct hfsmount *hfsmp, struct cat_desc *descp)
340{
341 struct BTreeIterator *iterator;
342 struct FSBufferDescriptor file_data;
343 struct HFSCatalogFile file_rec;
344 UInt16 datasize;
345 FCB *fcb;
346 int result;
347
348 if (HFSTOVCB(hfsmp)->vcbSigWord != kHFSSigWord)
349 return (EINVAL);
350
351 fcb = GetFileControlBlock(HFSTOVCB(hfsmp)->catalogRefNum);
352
353 MALLOC(iterator, BTreeIterator *, 2 * sizeof(*iterator), M_TEMP, M_WAITOK);
354 bzero(&iterator[0], 2* sizeof(*iterator));
355 result = buildkey(hfsmp, descp, (HFSPlusCatalogKey *)&iterator[0].key, 0);
356 if (result)
357 goto exit;
358
359 BDINIT(file_data, &file_rec);
360 result = BTSearchRecord(fcb, &iterator[0], &file_data, &datasize, &iterator[0]);
361 if (result)
362 goto exit;
363
364 if (file_rec.recordType != kHFSFileRecord) {
365 result = EISDIR;
366 goto exit;
367 }
368
369 if ((file_rec.flags & kHFSThreadExistsMask) == 0) {
370 struct FSBufferDescriptor thread_data;
371 struct HFSCatalogThread thread_rec;
372
373 file_rec.flags |= kHFSThreadExistsMask;
374 BDINIT(thread_data, &thread_rec);
375 thread_data.itemSize = buildthread(&iterator[0].key, &thread_rec, 1, 0);
376 buildthreadkey(file_rec.fileID, 1, (CatalogKey *)&iterator[1].key);
377
378 result = BTInsertRecord(fcb, &iterator[1], &thread_data, thread_data.itemSize);
379 if (result)
380 goto exit;
381
382 (void) BTReplaceRecord(fcb, &iterator[0], &file_data, datasize);
383 (void) BTFlushPath(fcb);
384 }
385exit:
386 (void) BTFlushPath(fcb);
387 FREE(iterator, M_TEMP);
388
389 return MacToVFSError(result);
390}
391
392
393
394
395
396
397
398__private_extern__
399int
400cat_findname(struct hfsmount *hfsmp, cnid_t cnid, struct cat_desc *outdescp)
401{
402 struct BTreeIterator * iterator;
403 FSBufferDescriptor btdata;
404 CatalogKey * keyp;
405 CatalogRecord * recp;
406 int isdir;
407 int result;
408 int std_hfs;
409
410 isdir = 0;
411 std_hfs = (hfsmp->hfs_flags & HFS_STANDARD);
412
413 MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
414 buildthreadkey(cnid, std_hfs, (CatalogKey *)&iterator->key);
415 iterator->hint.nodeNum = 0;
416
417 MALLOC(recp, CatalogRecord *, sizeof(CatalogRecord), M_TEMP, M_WAITOK);
418 BDINIT(btdata, recp);
419
420 result = BTSearchRecord(VTOF(hfsmp->hfs_catalog_vp), iterator, &btdata, NULL, NULL);
421 if (result)
422 goto exit;
423
424
425 switch (recp->recordType) {
426 case kHFSFolderThreadRecord:
427 isdir = 1;
428
429 case kHFSFileThreadRecord:
430 keyp = (CatalogKey *)((char *)&recp->hfsThread.reserved + 6);
431 keyp->hfs.keyLength = kHFSCatalogKeyMinimumLength + keyp->hfs.nodeName[0];
432 break;
433
434 case kHFSPlusFolderThreadRecord:
435 isdir = 1;
436
437 case kHFSPlusFileThreadRecord:
438 keyp = (CatalogKey *)&recp->hfsPlusThread.reserved;
439 keyp->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength +
440 (keyp->hfsPlus.nodeName.length * 2);
441 break;
442 default:
443 result = ENOENT;
444 goto exit;
445 }
446 if (std_hfs) {
447 HFSPlusCatalogKey * pluskey = NULL;
448 u_long encoding;
449
450 MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK);
451 promotekey(hfsmp, &keyp->hfs, pluskey, &encoding);
452 builddesc(pluskey, cnid, 0, encoding, isdir, outdescp);
453 FREE(pluskey, M_TEMP);
454
455 } else {
456 builddesc((HFSPlusCatalogKey *)keyp, cnid, 0, 0, isdir, outdescp);
457 }
458exit:
459 FREE(recp, M_TEMP);
460 FREE(iterator, M_TEMP);
461
462 return MacToVFSError(result);
463}
464
465
466
467
468__private_extern__
469int
470cat_idlookup(struct hfsmount *hfsmp, cnid_t cnid, struct cat_desc *outdescp,
471 struct cat_attr *attrp, struct cat_fork *forkp)
472{
473 struct BTreeIterator * iterator;
474 FSBufferDescriptor btdata;
475 UInt16 datasize;
476 CatalogKey * keyp;
477 CatalogRecord * recp;
478 int result;
479 int std_hfs;
480
481 std_hfs = (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord);
482
483 MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
484 bzero(iterator, sizeof(*iterator));
485 buildthreadkey(cnid, std_hfs, (CatalogKey *)&iterator->key);
486
487 MALLOC(recp, CatalogRecord *, sizeof(CatalogRecord), M_TEMP, M_WAITOK);
488 BDINIT(btdata, recp);
489
490 result = BTSearchRecord(VTOF(HFSTOVCB(hfsmp)->catalogRefNum), iterator,
491 &btdata, &datasize, iterator);
492 if (result)
493 goto exit;
494
495
496 switch (recp->recordType) {
497 case kHFSFileThreadRecord:
498 case kHFSFolderThreadRecord:
499 keyp = (CatalogKey *)((char *)&recp->hfsThread.reserved + 6);
500 keyp->hfs.keyLength = kHFSCatalogKeyMinimumLength + keyp->hfs.nodeName[0];
501 break;
502
503 case kHFSPlusFileThreadRecord:
504 case kHFSPlusFolderThreadRecord:
505 keyp = (CatalogKey *)&recp->hfsPlusThread.reserved;
506 keyp->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength +
507 (keyp->hfsPlus.nodeName.length * 2);
508 break;
509
510 default:
511 result = ENOENT;
512 goto exit;
513 }
514
515 result = cat_lookupbykey(hfsmp, keyp, 0, 0, outdescp, attrp, forkp, NULL);
516exit:
517 FREE(recp, M_TEMP);
518 FREE(iterator, M_TEMP);
519
520 return MacToVFSError(result);
521}
522
523
524
525
526
527static int
528cat_lookupmangled(struct hfsmount *hfsmp, struct cat_desc *descp, int wantrsrc,
529 struct cat_desc *outdescp, struct cat_attr *attrp, struct cat_fork *forkp)
530{
531 cnid_t fileID;
532 int prefixlen;
533 int result;
534
535 if (wantrsrc)
536 return (ENOENT);
537
538 fileID = GetEmbeddedFileID(descp->cd_nameptr, descp->cd_namelen, &prefixlen);
539 if (fileID < kHFSFirstUserCatalogNodeID)
540 return (ENOENT);
541
542 result = cat_idlookup(hfsmp, fileID, outdescp, attrp, forkp);
543 if (result)
544 return (ENOENT);
545
546
547 if (descp->cd_parentcnid != outdescp->cd_parentcnid)
548 goto falsematch;
549
550 if ((outdescp->cd_namelen < prefixlen) ||
551 bcmp(outdescp->cd_nameptr, descp->cd_nameptr, prefixlen-6) != 0)
552 goto falsematch;
553
554 return (0);
555
556falsematch:
557 cat_releasedesc(outdescp);
558 return (ENOENT);
559}
560
561
562
563
564
565static int
566cat_lookupbykey(struct hfsmount *hfsmp, CatalogKey *keyp, u_long hint, int wantrsrc,
567 struct cat_desc *descp, struct cat_attr *attrp, struct cat_fork *forkp, cnid_t *desc_cnid)
568{
569 struct BTreeIterator * iterator;
570 FSBufferDescriptor btdata;
571 CatalogRecord * recp;
572 UInt16 datasize;
573 int result;
574 int std_hfs;
575 u_long ilink = 0;
576 cnid_t cnid = 0;
577 u_long encoding = 0;
578
579 std_hfs = (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord);
580
581 MALLOC(recp, CatalogRecord *, sizeof(CatalogRecord), M_TEMP, M_WAITOK);
582 BDINIT(btdata, recp);
583 MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
584 bzero(iterator, sizeof(*iterator));
585 iterator->hint.nodeNum = hint;
586 bcopy(keyp, &iterator->key, sizeof(CatalogKey));
587
588 result = BTSearchRecord(VTOF(HFSTOVCB(hfsmp)->catalogRefNum), iterator,
589 &btdata, &datasize, iterator);
590 if (result)
591 goto exit;
592
593
594 cnid = getcnid(recp);
595 encoding = getencoding(recp);
596 hint = iterator->hint.nodeNum;
597
598
599 if ((hfsmp->jnl || ((HFSTOVCB(hfsmp)->vcbAtrb & kHFSVolumeJournaledMask) && (hfsmp->hfs_flags & HFS_READ_ONLY))) &&
600 ((cnid == hfsmp->hfs_jnlfileid) ||
601 (cnid == hfsmp->hfs_jnlinfoblkid))) {
602
603 result = ENOENT;
604 goto exit;
605 }
606
607
608
609
610 if (!std_hfs
611 && (attrp || forkp)
612 && (recp->recordType == kHFSPlusFileRecord)
613 && (SWAP_BE32(recp->hfsPlusFile.userInfo.fdType) == kHardLinkFileType)
614 && (SWAP_BE32(recp->hfsPlusFile.userInfo.fdCreator) == kHFSPlusCreator)
615 && ((to_bsd_time(recp->hfsPlusFile.createDate) == (time_t)HFSTOVCB(hfsmp)->vcbCrDate) ||
616 (to_bsd_time(recp->hfsPlusFile.createDate) == (time_t)hfsmp->hfs_metadata_createdate))) {
617
618 ilink = recp->hfsPlusFile.bsdInfo.special.iNodeNum;
619
620 (void) resolvelink(hfsmp, ilink, (struct HFSPlusCatalogFile *)recp);
621 }
622
623 if (attrp != NULL) {
624 if (std_hfs) {
625 struct HFSPlusCatalogFile cnoderec;
626
627 promoteattr(hfsmp, recp, &cnoderec);
628 getbsdattr(hfsmp, &cnoderec, attrp);
629 } else {
630 getbsdattr(hfsmp, (struct HFSPlusCatalogFile *)recp, attrp);
631 if (ilink)
632 attrp->ca_rdev = ilink;
633 }
634 }
635 if (forkp != NULL) {
636 if (isadir(recp)) {
637 bzero(forkp, sizeof(*forkp));
638 } else if (std_hfs) {
639 promotefork(hfsmp, (HFSCatalogFile *)&recp->hfsFile, wantrsrc, forkp);
640 } else if (wantrsrc) {
641
642 forkp->cf_size = recp->hfsPlusFile.resourceFork.logicalSize;
643 forkp->cf_blocks = recp->hfsPlusFile.resourceFork.totalBlocks;
644 if ((hfsmp->hfc_stage == HFC_RECORDING) &&
645 (to_bsd_time(recp->hfsPlusFile.accessDate) >= hfsmp->hfc_timebase)) {
646 forkp->cf_bytesread =
647 recp->hfsPlusFile.resourceFork.clumpSize *
648 HFSTOVCB(hfsmp)->blockSize;
649 } else {
650 forkp->cf_bytesread = 0;
651 }
652 forkp->cf_vblocks = 0;
653 bcopy(&recp->hfsPlusFile.resourceFork.extents[0],
654 &forkp->cf_extents[0], sizeof(HFSPlusExtentRecord));
655 } else {
656
657 forkp->cf_size = recp->hfsPlusFile.dataFork.logicalSize;
658 forkp->cf_blocks = recp->hfsPlusFile.dataFork.totalBlocks;
659 if ((hfsmp->hfc_stage == HFC_RECORDING) &&
660 (to_bsd_time(recp->hfsPlusFile.accessDate) >= hfsmp->hfc_timebase)) {
661 forkp->cf_bytesread =
662 recp->hfsPlusFile.dataFork.clumpSize *
663 HFSTOVCB(hfsmp)->blockSize;
664 } else {
665 forkp->cf_bytesread = 0;
666 }
667 forkp->cf_vblocks = 0;
668 bcopy(&recp->hfsPlusFile.dataFork.extents[0],
669 &forkp->cf_extents[0], sizeof(HFSPlusExtentRecord));
670 }
671 }
672 if (descp != NULL) {
673 HFSPlusCatalogKey * pluskey = NULL;
674
675 if (std_hfs) {
676 MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK);
677 promotekey(hfsmp, (HFSCatalogKey *)&iterator->key, pluskey, &encoding);
678
679 } else
680 pluskey = (HFSPlusCatalogKey *)&iterator->key;
681
682 builddesc(pluskey, cnid, hint, encoding, isadir(recp), descp);
683 if (std_hfs) {
684 FREE(pluskey, M_TEMP);
685 }
686 }
687
688 if (desc_cnid != NULL) {
689 *desc_cnid = cnid;
690 }
691exit:
692 FREE(iterator, M_TEMP);
693 FREE(recp, M_TEMP);
694
695 return MacToVFSError(result);
696}
697
698
699
700
701
702__private_extern__
703int
704cat_create(struct hfsmount *hfsmp, struct cat_desc *descp, struct cat_attr *attrp,
705 struct cat_desc *out_descp)
706{
707 ExtendedVCB * vcb;
708 FCB * fcb;
709 struct btobj * bto;
710 FSBufferDescriptor btdata;
711 u_int32_t nextCNID;
712 u_int32_t datalen;
713 int std_hfs;
714 int result = 0;
715 u_long encoding;
716 int modeformat;
717 int mntlock = 0;
718
719 modeformat = attrp->ca_mode & S_IFMT;
720
721 vcb = HFSTOVCB(hfsmp);
722 fcb = GetFileControlBlock(vcb->catalogRefNum);
723 std_hfs = (vcb->vcbSigWord == kHFSSigWord);
724
725
726
727
728
729 HFS_MOUNT_LOCK(hfsmp, TRUE);
730 mntlock = 1;
731 nextCNID = hfsmp->vcbNxtCNID;
732 if (nextCNID == 0xFFFFFFFF) {
733 if (std_hfs) {
734 result = ENOSPC;
735 } else {
736 hfsmp->vcbNxtCNID = kHFSFirstUserCatalogNodeID;
737 hfsmp->vcbAtrb |= kHFSCatalogNodeIDsReusedMask;
738 }
739 } else {
740 hfsmp->vcbNxtCNID++;
741 }
742 hfsmp->vcbFlags |= 0xFF00;
743
744 if ((hfsmp->vcbAtrb & kHFSCatalogNodeIDsReusedMask) == 0) {
745 HFS_MOUNT_UNLOCK(hfsmp, TRUE);
746 mntlock = 0;
747 if (result)
748 return (result);
749 }
750
751
752 MALLOC(bto, struct btobj *, sizeof(struct btobj), M_TEMP, M_WAITOK);
753 bto->iterator.hint.nodeNum = 0;
754
755 result = buildkey(hfsmp, descp, &bto->key, 0);
756 if (result)
757 goto exit;
758
759 if (!std_hfs) {
760 encoding = hfs_pickencoding(bto->key.nodeName.unicode,
761 bto->key.nodeName.length);
762 hfs_setencodingbits(hfsmp, encoding);
763 }
764
765
766
767
768 if (!std_hfs || (modeformat == S_IFDIR)) {
769 datalen = buildthread((void*)&bto->key, &bto->data, std_hfs,
770 S_ISDIR(attrp->ca_mode));
771 btdata.bufferAddress = &bto->data;
772 btdata.itemSize = datalen;
773 btdata.itemCount = 1;
774
775 for (;;) {
776 buildthreadkey(nextCNID, std_hfs, (CatalogKey *) &bto->iterator.key);
777
778 result = BTInsertRecord(fcb, &bto->iterator, &btdata, datalen);
779 if ((result == btExists) && !std_hfs && mntlock) {
780
781
782
783 if (++nextCNID < kHFSFirstUserCatalogNodeID) {
784 nextCNID = kHFSFirstUserCatalogNodeID;
785 }
786 continue;
787 }
788 break;
789 }
790 if (result) goto exit;
791 }
792
793
794
795
796
797 if (mntlock) {
798 hfsmp->vcbNxtCNID = nextCNID + 1;
799 if (hfsmp->vcbNxtCNID < kHFSFirstUserCatalogNodeID) {
800 hfsmp->vcbNxtCNID = kHFSFirstUserCatalogNodeID;
801 }
802 HFS_MOUNT_UNLOCK(hfsmp, TRUE);
803 mntlock = 0;
804 }
805
806
807
808
809 buildrecord(attrp, nextCNID, std_hfs, encoding, &bto->data, &datalen);
810 btdata.bufferAddress = &bto->data;
811 btdata.itemSize = datalen;
812 btdata.itemCount = 1;
813
814 bcopy(&bto->key, &bto->iterator.key, sizeof(bto->key));
815
816 result = BTInsertRecord(fcb, &bto->iterator, &btdata, datalen);
817 if (result) {
818 if (result == btExists)
819 result = EEXIST;
820
821
822 if (!std_hfs || S_ISDIR(attrp->ca_mode)) {
823 buildthreadkey(nextCNID, std_hfs, (CatalogKey *)&bto->iterator.key);
824 (void) BTDeleteRecord(fcb, &bto->iterator);
825 }
826 goto exit;
827 }
828
829
830
831
832
833
834 if (out_descp != NULL) {
835 HFSPlusCatalogKey * pluskey = NULL;
836
837 if (std_hfs) {
838 MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK);
839 promotekey(hfsmp, (HFSCatalogKey *)&bto->iterator.key, pluskey, &encoding);
840
841 } else
842 pluskey = (HFSPlusCatalogKey *)&bto->iterator.key;
843
844 builddesc(pluskey, nextCNID, bto->iterator.hint.nodeNum,
845 encoding, S_ISDIR(attrp->ca_mode), out_descp);
846 if (std_hfs) {
847 FREE(pluskey, M_TEMP);
848 }
849 }
850 attrp->ca_fileid = nextCNID;
851
852exit:
853 if (mntlock)
854 HFS_MOUNT_UNLOCK(hfsmp, TRUE);
855
856 (void) BTFlushPath(fcb);
857 FREE(bto, M_TEMP);
858
859 return MacToVFSError(result);
860}
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875__private_extern__
876int
877cat_rename (
878 struct hfsmount * hfsmp,
879 struct cat_desc * from_cdp,
880 struct cat_desc * todir_cdp,
881 struct cat_desc * to_cdp,
882 struct cat_desc * out_cdp )
883{
884 struct BTreeIterator * to_iterator = NULL;
885 struct BTreeIterator * from_iterator = NULL;
886 FSBufferDescriptor btdata;
887 CatalogRecord * recp = NULL;
888 HFSPlusCatalogKey * to_key;
889 ExtendedVCB * vcb;
890 FCB * fcb;
891 UInt16 datasize;
892 int result = 0;
893 int sourcegone = 0;
894 int skipthread = 0;
895 int directory = from_cdp->cd_flags & CD_ISDIR;
896 int std_hfs;
897 u_long encoding = 0;
898
899 vcb = HFSTOVCB(hfsmp);
900 fcb = GetFileControlBlock(vcb->catalogRefNum);
901 std_hfs = (vcb->vcbSigWord == kHFSSigWord);
902
903 if (from_cdp->cd_namelen == 0 || to_cdp->cd_namelen == 0)
904 return (EINVAL);
905
906 MALLOC(from_iterator, BTreeIterator *, sizeof(*from_iterator), M_TEMP, M_WAITOK);
907 bzero(from_iterator, sizeof(*from_iterator));
908 if ((result = buildkey(hfsmp, from_cdp, (HFSPlusCatalogKey *)&from_iterator->key, 0)))
909 goto exit;
910
911 MALLOC(to_iterator, BTreeIterator *, sizeof(*to_iterator), M_TEMP, M_WAITOK);
912 bzero(to_iterator, sizeof(*to_iterator));
913 if ((result = buildkey(hfsmp, to_cdp, (HFSPlusCatalogKey *)&to_iterator->key, 0)))
914 goto exit;
915
916 to_key = (HFSPlusCatalogKey *)&to_iterator->key;
917 MALLOC(recp, CatalogRecord *, sizeof(CatalogRecord), M_TEMP, M_WAITOK);
918 BDINIT(btdata, recp);
919
920
921
922
923 if (directory && (from_cdp->cd_parentcnid != to_cdp->cd_parentcnid)) {
924 struct BTreeIterator iterator;
925 cnid_t cnid = from_cdp->cd_cnid;
926 cnid_t pathcnid = todir_cdp->cd_parentcnid;
927
928
929 if (cnid == fsRtDirID ||
930 cnid == to_cdp->cd_parentcnid ||
931 cnid == pathcnid) {
932 result = EINVAL;
933 goto exit;
934 }
935 bzero(&iterator, sizeof(iterator));
936
937
938
939
940
941 while (pathcnid > fsRtDirID) {
942 buildthreadkey(pathcnid, std_hfs,
943 (CatalogKey *)&iterator.key);
944 result = BTSearchRecord(fcb, &iterator, &btdata,
945 &datasize, NULL);
946 if (result) goto exit;
947
948 pathcnid = getparentcnid(recp);
949 if (pathcnid == cnid) {
950 result = EINVAL;
951 goto exit;
952 }
953 }
954 }
955
956
957
958
959 result = BTSearchRecord(fcb, from_iterator, &btdata,
960 &datasize, from_iterator);
961 if (result) {
962 if (std_hfs || (result != btNotFound))
963 goto exit;
964
965 struct cat_desc temp_desc;
966
967
968 result = cat_lookupmangled(hfsmp, from_cdp, 0, &temp_desc, NULL, NULL);
969 if (result)
970 goto exit;
971
972
973 bzero(from_iterator, sizeof(*from_iterator));
974 result = buildkey(hfsmp, &temp_desc, (HFSPlusCatalogKey *)&from_iterator->key, 0);
975 if (result) {
976 cat_releasedesc(&temp_desc);
977 goto exit;
978 }
979
980 result = BTSearchRecord(fcb, from_iterator, &btdata, &datasize, from_iterator);
981 if (result) {
982 cat_releasedesc(&temp_desc);
983 goto exit;
984 }
985
986 cat_releasedesc(&temp_desc);
987 }
988
989
990 if (!std_hfs) {
991 encoding = hfs_pickencoding(to_key->nodeName.unicode,
992 to_key->nodeName.length);
993 hfs_setencodingbits(hfsmp, encoding);
994 recp->hfsPlusFile.textEncoding = encoding;
995 if (out_cdp)
996 out_cdp->cd_encoding = encoding;
997 }
998
999 if (std_hfs && !directory &&
1000 !(recp->hfsFile.flags & kHFSThreadExistsMask))
1001 skipthread = 1;
1002#if 0
1003
1004
1005
1006
1007
1008
1009 if (std_hfs && hfskeycompare(to_key, iter->key) == 0)
1010 goto exit;
1011 if (!std_hfs && hfspluskeycompare(to_key, iter->key) == 0)
1012 goto exit;
1013#endif
1014
1015
1016 result = BTInsertRecord(fcb, to_iterator, &btdata, datasize);
1017 if (result == btExists) {
1018 int fromtype = recp->recordType;
1019
1020 if (from_cdp->cd_parentcnid != to_cdp->cd_parentcnid)
1021 goto exit;
1022
1023
1024 result = BTSearchRecord(fcb, to_iterator, &btdata, &datasize, NULL);
1025 if (result)
1026 goto exit;
1027
1028 if ((fromtype != recp->recordType) ||
1029 (from_cdp->cd_cnid != getcnid(recp))) {
1030 result = EEXIST;
1031 goto exit;
1032 }
1033
1034 result = BTDeleteRecord(fcb, from_iterator);
1035 if (result)
1036 goto exit;
1037
1038
1039 result = BTInsertRecord(fcb, to_iterator, &btdata, datasize);
1040 if (result) {
1041
1042
1043 #if 1
1044 {
1045 int err;
1046 err = BTInsertRecord(fcb, from_iterator, &btdata, datasize);
1047 if (err)
1048 panic("cat_create: could not undo (BTInsert = %d)", err);
1049 }
1050 #else
1051 (void) BTInsertRecord(fcb, from_iterator, &btdata, datasize);
1052 #endif
1053 goto exit;
1054 }
1055 sourcegone = 1;
1056 }
1057 if (result)
1058 goto exit;
1059
1060
1061 if (!sourcegone) {
1062 result = BTDeleteRecord(fcb, from_iterator);
1063 if (result) {
1064
1065
1066 #if 1
1067 {
1068 int err;
1069 err = BTDeleteRecord(fcb, to_iterator);
1070 if (err)
1071 panic("cat_create: could not undo (BTDelete = %d)", err);
1072 }
1073 #else
1074 (void) BTDeleteRecord(fcb, to_iterator);
1075 #endif
1076 goto exit;
1077 }
1078 }
1079
1080
1081
1082
1083
1084
1085 buildthreadkey(from_cdp->cd_cnid, std_hfs, (CatalogKey *)&from_iterator->key);
1086 (void) BTDeleteRecord(fcb, from_iterator);
1087
1088
1089
1090
1091
1092 if (!skipthread) {
1093 datasize = buildthread(&to_iterator->key, recp, std_hfs, directory);
1094 btdata.itemSize = datasize;
1095 buildthreadkey(from_cdp->cd_cnid, std_hfs, (CatalogKey *)&from_iterator->key);
1096 result = BTInsertRecord(fcb, from_iterator, &btdata, datasize);
1097 }
1098
1099 if (out_cdp) {
1100 HFSPlusCatalogKey * pluskey = NULL;
1101
1102 if (std_hfs) {
1103 MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK);
1104 promotekey(hfsmp, (HFSCatalogKey *)&to_iterator->key, pluskey, &encoding);
1105
1106
1107 if (directory && from_cdp->cd_cnid == kHFSRootFolderID) {
1108 u_long realhint;
1109
1110 realhint = hfs_pickencoding(pluskey->nodeName.unicode, pluskey->nodeName.length);
1111 vcb->vcbFndrInfo[4] = SET_HFS_TEXT_ENCODING(realhint);
1112 }
1113
1114 } else
1115 pluskey = (HFSPlusCatalogKey *)&to_iterator->key;
1116
1117 builddesc(pluskey, from_cdp->cd_cnid, to_iterator->hint.nodeNum,
1118 encoding, directory, out_cdp);
1119 if (std_hfs) {
1120 FREE(pluskey, M_TEMP);
1121 }
1122 }
1123exit:
1124 (void) BTFlushPath(fcb);
1125 if (from_iterator)
1126 FREE(from_iterator, M_TEMP);
1127 if (to_iterator)
1128 FREE(to_iterator, M_TEMP);
1129 if (recp)
1130 FREE(recp, M_TEMP);
1131 return MacToVFSError(result);
1132}
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143__private_extern__
1144int
1145cat_delete(struct hfsmount *hfsmp, struct cat_desc *descp, struct cat_attr *attrp)
1146{
1147 ExtendedVCB * vcb;
1148 FCB * fcb;
1149 BTreeIterator *iterator;
1150 cnid_t cnid;
1151 int std_hfs;
1152 int result;
1153
1154 vcb = HFSTOVCB(hfsmp);
1155 fcb = GetFileControlBlock(vcb->catalogRefNum);
1156 std_hfs = (vcb->vcbSigWord == kHFSSigWord);
1157
1158
1159
1160
1161
1162
1163
1164 if (descp->cd_cnid < kHFSFirstUserCatalogNodeID ||
1165 descp->cd_parentcnid == kHFSRootParentID)
1166 return (EINVAL);
1167
1168
1169
1170
1171 MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
1172 iterator->hint.nodeNum = 0;
1173
1174
1175
1176
1177
1178 if (descp->cd_namelen == 0) {
1179 result = getkey(hfsmp, attrp->ca_fileid, (CatalogKey *)&iterator->key);
1180 cnid = attrp->ca_fileid;
1181 } else {
1182 result = buildkey(hfsmp, descp, (HFSPlusCatalogKey *)&iterator->key, 0);
1183 cnid = descp->cd_cnid;
1184 }
1185 if (result)
1186 goto exit;
1187
1188
1189 result = BTDeleteRecord(fcb, iterator);
1190 if (result) {
1191 if (std_hfs || (result != btNotFound))
1192 goto exit;
1193
1194 struct cat_desc temp_desc;
1195
1196
1197 result = cat_lookupmangled(hfsmp, descp, 0, &temp_desc, attrp, NULL);
1198 if (result)
1199 goto exit;
1200
1201
1202 bzero(iterator, sizeof(*iterator));
1203 result = buildkey(hfsmp, &temp_desc, (HFSPlusCatalogKey *)&iterator->key, 0);
1204 cnid = temp_desc.cd_cnid;
1205 if (result) {
1206 cat_releasedesc(&temp_desc);
1207 goto exit;
1208 }
1209
1210 result = BTDeleteRecord(fcb, iterator);
1211 if (result) {
1212 cat_releasedesc(&temp_desc);
1213 goto exit;
1214 }
1215
1216 cat_releasedesc(&temp_desc);
1217 }
1218
1219
1220 buildthreadkey(cnid, std_hfs, (CatalogKey *)&iterator->key);
1221 (void) BTDeleteRecord(fcb, iterator);
1222
1223exit:
1224 (void) BTFlushPath(fcb);
1225 FREE(iterator, M_TEMP);
1226
1227 return MacToVFSError(result);
1228}
1229
1230
1231
1232
1233
1234
1235__private_extern__
1236int
1237cat_update(struct hfsmount *hfsmp, struct cat_desc *descp, struct cat_attr *attrp,
1238 struct cat_fork *dataforkp, struct cat_fork *rsrcforkp)
1239{
1240 ExtendedVCB * vcb;
1241 FCB * fcb;
1242 BTreeIterator * iterator;
1243 struct update_state state;
1244 int std_hfs;
1245 int result;
1246
1247 vcb = HFSTOVCB(hfsmp);
1248 fcb = GetFileControlBlock(vcb->catalogRefNum);
1249 std_hfs = (vcb->vcbSigWord == kHFSSigWord);
1250
1251 state.s_desc = descp;
1252 state.s_attr = attrp;
1253 state.s_datafork = dataforkp;
1254 state.s_rsrcfork = rsrcforkp;
1255 state.s_hfsmp = hfsmp;
1256
1257
1258 MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268 if ((descp->cd_cnid != attrp->ca_fileid) || (descp->cd_namelen == 0))
1269 result = getkey(hfsmp, attrp->ca_fileid, (CatalogKey *)&iterator->key);
1270 else
1271 result = buildkey(hfsmp, descp, (HFSPlusCatalogKey *)&iterator->key, 0);
1272 if (result)
1273 goto exit;
1274
1275
1276 iterator->hint.nodeNum = descp->cd_hint;
1277
1278 result = BTUpdateRecord(fcb, iterator,
1279 (IterateCallBackProcPtr)catrec_update, &state);
1280 if (result)
1281 goto exit;
1282
1283
1284 descp->cd_hint = iterator->hint.nodeNum;
1285
1286exit:
1287 (void) BTFlushPath(fcb);
1288 FREE(iterator, M_TEMP);
1289
1290 return MacToVFSError(result);
1291}
1292
1293
1294
1295
1296
1297static int
1298catrec_update(const CatalogKey *ckp, CatalogRecord *crp, struct update_state *state)
1299{
1300 struct cat_desc *descp;
1301 struct cat_attr *attrp;
1302 struct cat_fork *forkp;
1303 struct hfsmount *hfsmp;
1304 long blksize;
1305 int i;
1306
1307 descp = state->s_desc;
1308 attrp = state->s_attr;
1309 hfsmp = state->s_hfsmp;
1310 blksize = HFSTOVCB(hfsmp)->blockSize;
1311
1312 switch (crp->recordType) {
1313 case kHFSFolderRecord: {
1314 HFSCatalogFolder *dir;
1315
1316 dir = (struct HFSCatalogFolder *)crp;
1317
1318 if ((ckp->hfs.parentID != descp->cd_parentcnid) ||
1319 (dir->folderID != descp->cd_cnid))
1320 return (btNotFound);
1321 dir->valence = attrp->ca_entries;
1322 dir->createDate = UTCToLocal(to_hfs_time(attrp->ca_itime));
1323 dir->modifyDate = UTCToLocal(to_hfs_time(attrp->ca_mtime));
1324 dir->backupDate = UTCToLocal(to_hfs_time(attrp->ca_btime));
1325 bcopy(&attrp->ca_finderinfo[0], &dir->userInfo, 16);
1326 bcopy(&attrp->ca_finderinfo[16], &dir->finderInfo, 16);
1327 break;
1328 }
1329 case kHFSFileRecord: {
1330 HFSCatalogFile *file;
1331
1332 file = (struct HFSCatalogFile *)crp;
1333
1334 if ((ckp->hfs.parentID != descp->cd_parentcnid) ||
1335 (file->fileID != attrp->ca_fileid))
1336 return (btNotFound);
1337 file->createDate = UTCToLocal(to_hfs_time(attrp->ca_itime));
1338 file->modifyDate = UTCToLocal(to_hfs_time(attrp->ca_mtime));
1339 file->backupDate = UTCToLocal(to_hfs_time(attrp->ca_btime));
1340 bcopy(&attrp->ca_finderinfo[0], &file->userInfo, 16);
1341 bcopy(&attrp->ca_finderinfo[16], &file->finderInfo, 16);
1342 if (state->s_rsrcfork) {
1343 forkp = state->s_rsrcfork;
1344 file->rsrcLogicalSize = forkp->cf_size;
1345 file->rsrcPhysicalSize = forkp->cf_blocks * blksize;
1346 for (i = 0; i < kHFSExtentDensity; ++i) {
1347 file->rsrcExtents[i].startBlock =
1348 (u_int16_t)forkp->cf_extents[i].startBlock;
1349 file->rsrcExtents[i].blockCount =
1350 (u_int16_t)forkp->cf_extents[i].blockCount;
1351 }
1352 }
1353 if (state->s_datafork) {
1354 forkp = state->s_datafork;
1355 file->dataLogicalSize = forkp->cf_size;
1356 file->dataPhysicalSize = forkp->cf_blocks * blksize;
1357 for (i = 0; i < kHFSExtentDensity; ++i) {
1358 file->dataExtents[i].startBlock =
1359 (u_int16_t)forkp->cf_extents[i].startBlock;
1360 file->dataExtents[i].blockCount =
1361 (u_int16_t)forkp->cf_extents[i].blockCount;
1362 }
1363 }
1364 break;
1365 }
1366 case kHFSPlusFolderRecord: {
1367 HFSPlusCatalogFolder *dir;
1368
1369 dir = (struct HFSPlusCatalogFolder *)crp;
1370
1371 if ((ckp->hfsPlus.parentID != descp->cd_parentcnid) ||
1372 (dir->folderID != descp->cd_cnid))
1373 return (btNotFound);
1374 dir->flags = attrp->ca_recflags;
1375 dir->valence = attrp->ca_entries;
1376 dir->createDate = to_hfs_time(attrp->ca_itime);
1377 dir->contentModDate = to_hfs_time(attrp->ca_mtime);
1378 dir->backupDate = to_hfs_time(attrp->ca_btime);
1379 dir->accessDate = to_hfs_time(attrp->ca_atime);
1380 attrp->ca_atimeondisk = attrp->ca_atime;
1381 dir->attributeModDate = to_hfs_time(attrp->ca_ctime);
1382 dir->textEncoding = descp->cd_encoding;
1383 dir->attrBlocks = attrp->ca_attrblks;
1384 bcopy(&attrp->ca_finderinfo[0], &dir->userInfo, 32);
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406 if ((dir->bsdInfo.fileMode != 0) ||
1407 (attrp->ca_flags != 0) ||
1408 (attrp->ca_uid != hfsmp->hfs_uid) ||
1409 (attrp->ca_gid != hfsmp->hfs_gid) ||
1410 ((attrp->ca_mode & ALLPERMS) !=
1411 (hfsmp->hfs_dir_mask & ACCESSPERMS))) {
1412 if ((dir->bsdInfo.fileMode == 0) ||
1413 (((unsigned int)vfs_flags(HFSTOVFS(hfsmp))) & MNT_UNKNOWNPERMISSIONS) == 0) {
1414 dir->bsdInfo.ownerID = attrp->ca_uid;
1415 dir->bsdInfo.groupID = attrp->ca_gid;
1416 }
1417 dir->bsdInfo.ownerFlags = attrp->ca_flags & 0x000000FF;
1418 dir->bsdInfo.adminFlags = attrp->ca_flags >> 16;
1419 dir->bsdInfo.fileMode = attrp->ca_mode;
1420 }
1421 break;
1422 }
1423 case kHFSPlusFileRecord: {
1424 HFSPlusCatalogFile *file;
1425
1426 file = (struct HFSPlusCatalogFile *)crp;
1427
1428 if (file->fileID != attrp->ca_fileid)
1429 return (btNotFound);
1430 file->flags = attrp->ca_recflags;
1431 file->createDate = to_hfs_time(attrp->ca_itime);
1432 file->contentModDate = to_hfs_time(attrp->ca_mtime);
1433 file->backupDate = to_hfs_time(attrp->ca_btime);
1434 file->accessDate = to_hfs_time(attrp->ca_atime);
1435 attrp->ca_atimeondisk = attrp->ca_atime;
1436 file->attributeModDate = to_hfs_time(attrp->ca_ctime);
1437 file->textEncoding = descp->cd_encoding;
1438 file->attrBlocks = attrp->ca_attrblks;
1439 bcopy(&attrp->ca_finderinfo[0], &file->userInfo, 32);
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461 if ((file->bsdInfo.fileMode != 0) ||
1462 (attrp->ca_flags != 0) ||
1463 (attrp->ca_uid != hfsmp->hfs_uid) ||
1464 (attrp->ca_gid != hfsmp->hfs_gid) ||
1465 ((attrp->ca_mode & ALLPERMS) !=
1466 (hfsmp->hfs_file_mask & ACCESSPERMS))) {
1467 if ((file->bsdInfo.fileMode == 0) ||
1468 (((unsigned int)vfs_flags(HFSTOVFS(hfsmp))) & MNT_UNKNOWNPERMISSIONS) == 0) {
1469 file->bsdInfo.ownerID = attrp->ca_uid;
1470 file->bsdInfo.groupID = attrp->ca_gid;
1471 }
1472 file->bsdInfo.ownerFlags = attrp->ca_flags & 0x000000FF;
1473 file->bsdInfo.adminFlags = attrp->ca_flags >> 16;
1474 file->bsdInfo.fileMode = attrp->ca_mode;
1475 }
1476 if (state->s_rsrcfork) {
1477 forkp = state->s_rsrcfork;
1478 file->resourceFork.logicalSize = forkp->cf_size;
1479 file->resourceFork.totalBlocks = forkp->cf_blocks;
1480 bcopy(&forkp->cf_extents[0], &file->resourceFork.extents,
1481 sizeof(HFSPlusExtentRecord));
1482
1483 file->resourceFork.clumpSize =
1484 howmany(forkp->cf_bytesread, blksize);
1485 }
1486 if (state->s_datafork) {
1487 forkp = state->s_datafork;
1488 file->dataFork.logicalSize = forkp->cf_size;
1489 file->dataFork.totalBlocks = forkp->cf_blocks;
1490 bcopy(&forkp->cf_extents[0], &file->dataFork.extents,
1491 sizeof(HFSPlusExtentRecord));
1492
1493 file->dataFork.clumpSize =
1494 howmany(forkp->cf_bytesread, blksize);
1495 }
1496
1497 if ((file->resourceFork.extents[0].startBlock != 0) &&
1498 (file->resourceFork.extents[0].startBlock ==
1499 file->dataFork.extents[0].startBlock))
1500 panic("catrec_update: rsrc fork == data fork");
1501
1502
1503 if (attrp->ca_flags & (SF_IMMUTABLE | UF_IMMUTABLE))
1504 file->flags |= kHFSFileLockedMask;
1505 else
1506 file->flags &= ~kHFSFileLockedMask;
1507
1508
1509 if (S_ISBLK(attrp->ca_mode) || S_ISCHR(attrp->ca_mode))
1510 file->bsdInfo.special.rawDevice = attrp->ca_rdev;
1511 else if (descp->cd_cnid != attrp->ca_fileid
1512 || attrp->ca_nlink == 2)
1513 file->bsdInfo.special.linkCount = attrp->ca_nlink;
1514 break;
1515 }
1516 default:
1517 return (btNotFound);
1518 }
1519 return (0);
1520}
1521
1522
1523
1524
1525
1526struct readattr_state {
1527 struct hfsmount *hfsmp;
1528 struct cat_entrylist *list;
1529 cnid_t dir_cnid;
1530 int stdhfs;
1531 int error;
1532};
1533
1534static int
1535cat_readattr(const CatalogKey *key, const CatalogRecord *rec,
1536 struct readattr_state *state)
1537{
1538 struct cat_entrylist *list = state->list;
1539 struct hfsmount *hfsmp = state->hfsmp;
1540 struct cat_entry *cep;
1541 cnid_t parentcnid;
1542
1543 if (list->realentries >= list->maxentries)
1544 return (0);
1545
1546 parentcnid = state->stdhfs ? key->hfs.parentID : key->hfsPlus.parentID;
1547
1548 switch(rec->recordType) {
1549 case kHFSPlusFolderRecord:
1550 case kHFSPlusFileRecord:
1551 case kHFSFolderRecord:
1552 case kHFSFileRecord:
1553 if (parentcnid != state->dir_cnid) {
1554 state->error = ENOENT;
1555 return (0);
1556 }
1557 break;
1558 default:
1559 state->error = ENOENT;
1560 return (0);
1561 }
1562
1563
1564 if (parentcnid == kHFSRootFolderID) {
1565 if ((rec->recordType == kHFSPlusFolderRecord) &&
1566 (rec->hfsPlusFolder.folderID == hfsmp->hfs_privdir_desc.cd_cnid)) {
1567 return (1);
1568 }
1569 if ((hfsmp->jnl || ((HFSTOVCB(hfsmp)->vcbAtrb & kHFSVolumeJournaledMask) && (hfsmp->hfs_flags & HFS_READ_ONLY))) &&
1570 (rec->recordType == kHFSPlusFileRecord) &&
1571 ((rec->hfsPlusFile.fileID == hfsmp->hfs_jnlfileid) ||
1572 (rec->hfsPlusFile.fileID == hfsmp->hfs_jnlinfoblkid))) {
1573
1574 return (1);
1575 }
1576 }
1577
1578 cep = &list->entry[list->realentries++];
1579
1580 if (state->stdhfs) {
1581 struct HFSPlusCatalogFile cnoderec;
1582 HFSPlusCatalogKey * pluskey;
1583 long encoding;
1584
1585 promoteattr(hfsmp, rec, &cnoderec);
1586 getbsdattr(hfsmp, &cnoderec, &cep->ce_attr);
1587
1588 MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK);
1589 promotekey(hfsmp, (HFSCatalogKey *)key, pluskey, &encoding);
1590 builddesc(pluskey, getcnid(rec), 0, encoding, isadir(rec), &cep->ce_desc);
1591 FREE(pluskey, M_TEMP);
1592
1593 if (rec->recordType == kHFSFileRecord) {
1594 int blksize = HFSTOVCB(hfsmp)->blockSize;
1595
1596 cep->ce_datasize = rec->hfsFile.dataLogicalSize;
1597 cep->ce_datablks = rec->hfsFile.dataPhysicalSize / blksize;
1598 cep->ce_rsrcsize = rec->hfsFile.rsrcLogicalSize;
1599 cep->ce_rsrcblks = rec->hfsFile.rsrcPhysicalSize / blksize;
1600 }
1601 } else {
1602 getbsdattr(hfsmp, (struct HFSPlusCatalogFile *)rec, &cep->ce_attr);
1603 builddesc((HFSPlusCatalogKey *)key, getcnid(rec), 0, getencoding(rec),
1604 isadir(rec), &cep->ce_desc);
1605
1606 if (rec->recordType == kHFSPlusFileRecord) {
1607 cep->ce_datasize = rec->hfsPlusFile.dataFork.logicalSize;
1608 cep->ce_datablks = rec->hfsPlusFile.dataFork.totalBlocks;
1609 cep->ce_rsrcsize = rec->hfsPlusFile.resourceFork.logicalSize;
1610 cep->ce_rsrcblks = rec->hfsPlusFile.resourceFork.totalBlocks;
1611
1612
1613 if ((SWAP_BE32(rec->hfsPlusFile.userInfo.fdType) == kHardLinkFileType)
1614 && (SWAP_BE32(rec->hfsPlusFile.userInfo.fdCreator) == kHFSPlusCreator))
1615 cep->ce_attr.ca_rdev = rec->hfsPlusFile.bsdInfo.special.iNodeNum;
1616 }
1617 }
1618
1619 return (list->realentries < list->maxentries);
1620}
1621
1622
1623
1624
1625
1626
1627__private_extern__
1628int
1629cat_getentriesattr(struct hfsmount *hfsmp, directoryhint_t *dirhint, struct cat_entrylist *ce_list)
1630{
1631 FCB* fcb;
1632 CatalogKey * key;
1633 BTreeIterator * iterator;
1634 struct readattr_state state;
1635 cnid_t parentcnid;
1636 int i;
1637 int std_hfs;
1638 int index;
1639 int have_key;
1640 int result = 0;
1641
1642 ce_list->realentries = 0;
1643
1644 fcb = GetFileControlBlock(HFSTOVCB(hfsmp)->catalogRefNum);
1645 std_hfs = (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord);
1646 parentcnid = dirhint->dh_desc.cd_parentcnid;
1647
1648 state.hfsmp = hfsmp;
1649 state.list = ce_list;
1650 state.dir_cnid = parentcnid;
1651 state.stdhfs = std_hfs;
1652 state.error = 0;
1653
1654 MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
1655 bzero(iterator, sizeof(*iterator));
1656 key = (CatalogKey *)&iterator->key;
1657 have_key = 0;
1658 iterator->hint.nodeNum = dirhint->dh_desc.cd_hint;
1659 index = dirhint->dh_index + 1;
1660
1661
1662
1663
1664 if (dirhint->dh_desc.cd_namelen != 0) {
1665 if (buildkey(hfsmp, &dirhint->dh_desc, (HFSPlusCatalogKey *)key, 0) == 0) {
1666 have_key = 1;
1667 }
1668 }
1669
1670
1671
1672
1673 if ((index == 0) || !have_key) {
1674
1675
1676
1677
1678 buildthreadkey(dirhint->dh_desc.cd_parentcnid, (hfsmp->hfs_flags & HFS_STANDARD), key);
1679 result = BTSearchRecord(fcb, iterator, NULL, NULL, iterator);
1680 if (result) {
1681 result = MacToVFSError(result);
1682 goto exit;
1683 }
1684
1685
1686
1687
1688
1689 if (index > 0) {
1690 struct position_state ps;
1691
1692 ps.error = 0;
1693 ps.count = 0;
1694 ps.index = index;
1695 ps.parentID = dirhint->dh_desc.cd_parentcnid;
1696 ps.hfsmp = hfsmp;
1697
1698 result = BTIterateRecords(fcb, kBTreeNextRecord, iterator,
1699 (IterateCallBackProcPtr)cat_findposition, &ps);
1700 if (ps.error)
1701 result = ps.error;
1702 else
1703 result = MacToVFSError(result);
1704 if (result) {
1705 result = MacToVFSError(result);
1706 goto exit;
1707 }
1708 }
1709 }
1710
1711
1712 result = BTIterateRecords(fcb, kBTreeNextRecord, iterator,
1713 (IterateCallBackProcPtr)cat_readattr, &state);
1714
1715 if (state.error)
1716 result = state.error;
1717 else if (ce_list->realentries == 0)
1718 result = ENOENT;
1719 else
1720 result = MacToVFSError(result);
1721
1722 if (std_hfs)
1723 goto exit;
1724
1725
1726
1727
1728 for (i = 0; i < (int)ce_list->realentries; ++i) {
1729 struct FndrFileInfo *fip;
1730 struct cat_entry *cep;
1731 struct HFSPlusCatalogFile filerec;
1732
1733 cep = &ce_list->entry[i];
1734 if (!S_ISREG(cep->ce_attr.ca_mode))
1735 continue;
1736
1737
1738 fip = (struct FndrFileInfo *)&cep->ce_attr.ca_finderinfo;
1739
1740
1741 if ((cep->ce_attr.ca_rdev != 0)
1742 && (SWAP_BE32(fip->fdType) == kHardLinkFileType)
1743 && (SWAP_BE32(fip->fdCreator) == kHFSPlusCreator)
1744 && ((cep->ce_attr.ca_itime == (time_t)HFSTOVCB(hfsmp)->vcbCrDate) ||
1745 (cep->ce_attr.ca_itime == (time_t)hfsmp->hfs_metadata_createdate))) {
1746
1747 if (resolvelink(hfsmp, cep->ce_attr.ca_rdev, &filerec) != 0)
1748 continue;
1749
1750 getbsdattr(hfsmp, &filerec, &cep->ce_attr);
1751 cep->ce_datasize = filerec.dataFork.logicalSize;
1752 cep->ce_datablks = filerec.dataFork.totalBlocks;
1753 cep->ce_rsrcsize = filerec.resourceFork.logicalSize;
1754 cep->ce_rsrcblks = filerec.resourceFork.totalBlocks;
1755 }
1756 }
1757exit:
1758 FREE(iterator, M_TEMP);
1759
1760 return MacToVFSError(result);
1761}
1762
1763#define SMALL_DIRENTRY_SIZE (int)(sizeof(struct dirent) - (MAXNAMLEN + 1) + 8)
1764
1765
1766
1767
1768
1769
1770
1771struct linkinfo {
1772 u_long link_ref;
1773 user_addr_t dirent_addr;
1774};
1775typedef struct linkinfo linkinfo_t;
1776
1777
1778struct packdirentry_state {
1779 int cbs_extended;
1780 u_int32_t cbs_parentID;
1781 u_int32_t cbs_index;
1782 uio_t cbs_uio;
1783 ExtendedVCB * cbs_hfsmp;
1784 int cbs_result;
1785 int32_t cbs_nlinks;
1786 int32_t cbs_maxlinks;
1787 linkinfo_t * cbs_linkinfo;
1788 struct cat_desc * cbs_desc;
1789
1790
1791 struct direntry * cbs_direntry;
1792 struct direntry * cbs_prevdirentry;
1793 u_int32_t cbs_previlinkref;
1794 Boolean cbs_hasprevdirentry;
1795 Boolean cbs_eof;
1796};
1797
1798static int
1799cat_packdirentry(const CatalogKey *ckp, const CatalogRecord *crp,
1800 struct packdirentry_state *state)
1801{
1802 struct hfsmount *hfsmp;
1803 CatalogName *cnp;
1804 cnid_t curID;
1805 OSErr result;
1806 struct dirent catent;
1807 struct direntry * entry = NULL;
1808 time_t itime;
1809 u_int32_t ilinkref = 0;
1810 u_int32_t curlinkref = 0;
1811 cnid_t cnid;
1812 int hide = 0;
1813 u_int8_t type;
1814 u_int8_t is_mangled = 0;
1815 char *nameptr;
1816 user_addr_t uiobase;
1817 size_t namelen = 0;
1818 size_t maxnamelen;
1819 size_t uiosize = 0;
1820 caddr_t uioaddr;
1821 Boolean stop_after_pack = false;
1822
1823 hfsmp = state->cbs_hfsmp;
1824
1825 if (hfsmp->hfs_flags & HFS_STANDARD)
1826 curID = ckp->hfs.parentID;
1827 else
1828 curID = ckp->hfsPlus.parentID;
1829
1830
1831 if (state->cbs_parentID != curID) {
1832 if (state->cbs_extended) {
1833 if (state->cbs_hasprevdirentry) {
1834
1835 stop_after_pack = true;
1836 } else {
1837 state->cbs_result = ENOENT;
1838 return (0);
1839 }
1840 } else {
1841 state->cbs_result = ENOENT;
1842 return (0);
1843 }
1844 }
1845
1846 if (state->cbs_extended) {
1847 entry = state->cbs_direntry;
1848 nameptr = &entry->d_name[0];
1849 maxnamelen = NAME_MAX;
1850 } else {
1851 nameptr = &catent.d_name[0];
1852 maxnamelen = NAME_MAX;
1853 }
1854
1855 if (state->cbs_extended && stop_after_pack) {
1856 cnid = INT_MAX;
1857 } else {
1858 if (!(hfsmp->hfs_flags & HFS_STANDARD)) {
1859 switch(crp->recordType) {
1860 case kHFSPlusFolderRecord:
1861 type = DT_DIR;
1862 cnid = crp->hfsPlusFolder.folderID;
1863
1864 if ((curID == kHFSRootFolderID) &&
1865 (cnid == hfsmp->hfs_privdir_desc.cd_cnid)) {
1866 hide = 1;
1867 }
1868
1869 break;
1870 case kHFSPlusFileRecord:
1871 itime = to_bsd_time(crp->hfsPlusFile.createDate);
1872
1873
1874
1875 if ((SWAP_BE32(crp->hfsPlusFile.userInfo.fdType) == kHardLinkFileType) &&
1876 (SWAP_BE32(crp->hfsPlusFile.userInfo.fdCreator) == kHFSPlusCreator) &&
1877 ((itime == (time_t)hfsmp->hfs_itime) ||
1878 (itime == (time_t)hfsmp->hfs_metadata_createdate))) {
1879 ilinkref = crp->hfsPlusFile.bsdInfo.special.iNodeNum;
1880 }
1881 type = MODE_TO_DT(crp->hfsPlusFile.bsdInfo.fileMode);
1882 cnid = crp->hfsPlusFile.fileID;
1883
1884 if ((curID == kHFSRootFolderID) &&
1885 ((hfsmp->jnl || ((HFSTOVCB(hfsmp)->vcbAtrb & kHFSVolumeJournaledMask) && (hfsmp->hfs_flags & HFS_READ_ONLY)))) &&
1886 ((cnid == hfsmp->hfs_jnlfileid) ||
1887 (cnid == hfsmp->hfs_jnlinfoblkid))) {
1888 hide = 1;
1889 }
1890 break;
1891 default:
1892 return (0);
1893 };
1894
1895 cnp = (CatalogName*) &ckp->hfsPlus.nodeName;
1896 result = utf8_encodestr(cnp->ustr.unicode, cnp->ustr.length * sizeof(UniChar),
1897 nameptr, &namelen, maxnamelen + 1, ':', 0);
1898 if (result == ENAMETOOLONG) {
1899 result = ConvertUnicodeToUTF8Mangled(cnp->ustr.length * sizeof(UniChar),
1900 cnp->ustr.unicode, maxnamelen + 1,
1901 (ByteCount*)&namelen, nameptr,
1902 cnid);
1903 is_mangled = 1;
1904 }
1905 } else {
1906 switch(crp->recordType) {
1907 case kHFSFolderRecord:
1908 type = DT_DIR;
1909 cnid = crp->hfsFolder.folderID;
1910 break;
1911 case kHFSFileRecord:
1912 type = DT_REG;
1913 cnid = crp->hfsFile.fileID;
1914 break;
1915 default:
1916 return (0);
1917 };
1918
1919 cnp = (CatalogName*) ckp->hfs.nodeName;
1920 result = hfs_to_utf8(hfsmp, cnp->pstr, maxnamelen + 1,
1921 (ByteCount *)&namelen, nameptr);
1922
1923
1924
1925
1926 if (result)
1927 result = mac_roman_to_utf8(cnp->pstr, maxnamelen + 1,
1928 (ByteCount *)&namelen, nameptr);
1929 }
1930 }
1931
1932 if (state->cbs_extended) {
1933
1934
1935
1936
1937
1938
1939 state->cbs_prevdirentry->d_seekoff = (state->cbs_index + 3) | ((u_int64_t)cnid << 32);
1940 uiosize = state->cbs_prevdirentry->d_reclen;
1941 uioaddr = (caddr_t) state->cbs_prevdirentry;
1942 } else {
1943 catent.d_type = type;
1944 catent.d_namlen = namelen;
1945 catent.d_reclen = uiosize = STD_DIRENT_LEN(namelen);
1946 if (hide)
1947 catent.d_fileno = 0;
1948 else
1949 catent.d_fileno = cnid;
1950 uioaddr = (caddr_t) &catent;
1951 }
1952
1953
1954 uiobase = uio_curriovbase(state->cbs_uio);
1955
1956
1957 if ((uiosize > uio_resid(state->cbs_uio)) ||
1958 (ilinkref != 0 && state->cbs_nlinks == state->cbs_maxlinks)) {
1959 return (0);
1960 }
1961
1962 if (!state->cbs_extended || state->cbs_hasprevdirentry) {
1963 state->cbs_result = uiomove(uioaddr, uiosize, state->cbs_uio);
1964 if (state->cbs_result == 0) {
1965 ++state->cbs_index;
1966
1967
1968 state->cbs_desc->cd_cnid = cnid;
1969 if (type == DT_DIR) {
1970 state->cbs_desc->cd_flags |= CD_ISDIR;
1971 } else {
1972 state->cbs_desc->cd_flags &= ~CD_ISDIR;
1973 }
1974 if (state->cbs_desc->cd_nameptr != NULL) {
1975 vfs_removename(state->cbs_desc->cd_nameptr);
1976 }
1977#if 0
1978 state->cbs_desc->cd_encoding = xxxx;
1979#endif
1980 if (!is_mangled) {
1981 state->cbs_desc->cd_namelen = namelen;
1982 state->cbs_desc->cd_nameptr = vfs_addname(nameptr, namelen, 0, 0);
1983 } else {
1984
1985
1986
1987 char *new_nameptr;
1988 size_t bufsize;
1989 size_t tmp_namelen = 0;
1990
1991 cnp = (CatalogName *)&ckp->hfsPlus.nodeName;
1992 bufsize = 1 + utf8_encodelen(cnp->ustr.unicode,
1993 cnp->ustr.length * sizeof(UniChar),
1994 ':', 0);
1995 MALLOC(new_nameptr, char *, bufsize, M_TEMP, M_WAITOK);
1996 result = utf8_encodestr(cnp->ustr.unicode,
1997 cnp->ustr.length * sizeof(UniChar),
1998 new_nameptr, &tmp_namelen,
1999 bufsize, ':', 0);
2000
2001 state->cbs_desc->cd_namelen = tmp_namelen;
2002 state->cbs_desc->cd_nameptr = vfs_addname(new_nameptr, tmp_namelen, 0, 0);
2003
2004 FREE(new_nameptr, M_TEMP);
2005 }
2006 }
2007 if (state->cbs_hasprevdirentry) {
2008 curlinkref = ilinkref;
2009 ilinkref = state->cbs_previlinkref;
2010 }
2011
2012
2013
2014 if ((ilinkref != 0) &&
2015 (state->cbs_result == 0) &&
2016 (state->cbs_nlinks < state->cbs_maxlinks)) {
2017 state->cbs_linkinfo[state->cbs_nlinks].dirent_addr = uiobase;
2018 state->cbs_linkinfo[state->cbs_nlinks].link_ref = ilinkref;
2019 state->cbs_nlinks++;
2020 }
2021 if (state->cbs_hasprevdirentry) {
2022 ilinkref = curlinkref;
2023 }
2024 }
2025
2026 if (state->cbs_extended) {
2027 if (stop_after_pack) {
2028 state->cbs_eof = true;
2029 return (0);
2030 }
2031 entry->d_type = type;
2032 entry->d_namlen = namelen;
2033 entry->d_reclen = EXT_DIRENT_LEN(namelen);
2034 if (hide)
2035 entry->d_fileno = 0;
2036 else
2037 entry->d_fileno = cnid;
2038
2039 struct direntry * tmp;
2040 tmp = state->cbs_direntry;
2041 state->cbs_direntry = state->cbs_prevdirentry;
2042 state->cbs_prevdirentry = tmp;
2043 state->cbs_hasprevdirentry = true;
2044 state->cbs_previlinkref = ilinkref;
2045 }
2046
2047
2048 return (state->cbs_result == 0 &&
2049 uio_resid(state->cbs_uio) >= SMALL_DIRENTRY_SIZE);
2050}
2051
2052
2053
2054
2055
2056__private_extern__
2057int
2058cat_getdirentries(struct hfsmount *hfsmp, int entrycnt, directoryhint_t *dirhint,
2059 uio_t uio, int extended, int * items, int * eofflag)
2060{
2061 FCB* fcb;
2062 BTreeIterator * iterator;
2063 CatalogKey * key;
2064 struct packdirentry_state state;
2065 void * buffer;
2066 int bufsize;
2067 int maxlinks;
2068 int result;
2069 int index;
2070 int have_key;
2071
2072 fcb = GetFileControlBlock(hfsmp->hfs_catalog_vp);
2073
2074
2075
2076
2077 maxlinks = MIN(entrycnt, uio_resid(uio) / SMALL_DIRENTRY_SIZE);
2078 bufsize = (maxlinks * sizeof(linkinfo_t)) + sizeof(*iterator);
2079 if (extended) {
2080 bufsize += 2*sizeof(struct direntry);
2081 }
2082 MALLOC(buffer, void *, bufsize, M_TEMP, M_WAITOK);
2083 bzero(buffer, bufsize);
2084
2085 state.cbs_extended = extended;
2086 state.cbs_hasprevdirentry = false;
2087 state.cbs_previlinkref = 0;
2088 state.cbs_nlinks = 0;
2089 state.cbs_maxlinks = maxlinks;
2090 state.cbs_linkinfo = (linkinfo_t *) buffer;
2091
2092 iterator = (BTreeIterator *) ((char *)buffer + (maxlinks * sizeof(linkinfo_t)));
2093 key = (CatalogKey *)&iterator->key;
2094 have_key = 0;
2095 index = dirhint->dh_index + 1;
2096 if (extended) {
2097 state.cbs_direntry = (struct direntry *)((char *)iterator + sizeof(BTreeIterator));
2098 state.cbs_prevdirentry = state.cbs_direntry + 1;
2099 state.cbs_eof = false;
2100 }
2101
2102
2103
2104 if (dirhint->dh_desc.cd_namelen != 0) {
2105 if (buildkey(hfsmp, &dirhint->dh_desc, (HFSPlusCatalogKey *)key, 0) == 0) {
2106 have_key = 1;
2107 }
2108 }
2109
2110
2111
2112
2113 if ((index == 0) || !have_key) {
2114
2115
2116
2117
2118 buildthreadkey(dirhint->dh_desc.cd_parentcnid, (hfsmp->hfs_flags & HFS_STANDARD), key);
2119 result = BTSearchRecord(fcb, iterator, NULL, NULL, iterator);
2120 if (result) {
2121 result = MacToVFSError(result);
2122 goto cleanup;
2123 }
2124
2125
2126
2127
2128
2129 if (index > 0) {
2130 struct position_state ps;
2131
2132 ps.error = 0;
2133 ps.count = 0;
2134 ps.index = index;
2135 ps.parentID = dirhint->dh_desc.cd_parentcnid;
2136 ps.hfsmp = hfsmp;
2137
2138 result = BTIterateRecords(fcb, kBTreeNextRecord, iterator,
2139 (IterateCallBackProcPtr)cat_findposition, &ps);
2140 if (ps.error)
2141 result = ps.error;
2142 else
2143 result = MacToVFSError(result);
2144 if (result) {
2145 result = MacToVFSError(result);
2146 goto cleanup;
2147 }
2148 }
2149 }
2150
2151 state.cbs_index = index;
2152 state.cbs_hfsmp = hfsmp;
2153 state.cbs_uio = uio;
2154 state.cbs_desc = &dirhint->dh_desc;
2155 state.cbs_result = 0;
2156 state.cbs_parentID = dirhint->dh_desc.cd_parentcnid;
2157
2158 enum BTreeIterationOperations op;
2159 if (extended && index != 0 && have_key)
2160 op = kBTreeCurrentRecord;
2161 else
2162 op = kBTreeNextRecord;
2163
2164
2165
2166
2167 result = BTIterateRecords(fcb, op, iterator,
2168 (IterateCallBackProcPtr)cat_packdirentry, &state);
2169
2170
2171 *items = state.cbs_index - index;
2172 index = state.cbs_index;
2173
2174 if (state.cbs_eof) {
2175 *eofflag = 1;
2176 }
2177
2178
2179 dirhint->dh_desc.cd_hint = iterator->hint.nodeNum;
2180 dirhint->dh_desc.cd_flags |= CD_DECOMPOSED;
2181 dirhint->dh_index = index - 1;
2182
2183
2184
2185
2186 if (state.cbs_nlinks > 0) {
2187 u_int32_t fileid = 0;
2188 user_addr_t address;
2189 int i;
2190
2191 for (i = 0; i < state.cbs_nlinks; ++i) {
2192 if (resolvelinkid(hfsmp, state.cbs_linkinfo[i].link_ref, &fileid) != 0)
2193 continue;
2194
2195 address = state.cbs_linkinfo[i].dirent_addr;
2196 if (address == (user_addr_t)0)
2197 continue;
2198 if (uio_isuserspace(uio)) {
2199 (void) copyout(&fileid, address,
2200 extended ? sizeof(ino64_t) : sizeof(ino_t));
2201 } else {
2202 ino64_t *inoptr = (ino64_t *)CAST_DOWN(caddr_t, address);
2203 *inoptr = fileid;
2204 }
2205 }
2206 }
2207
2208 if (state.cbs_result)
2209 result = state.cbs_result;
2210 else
2211 result = MacToVFSError(result);
2212
2213 if (result == ENOENT) {
2214 result = 0;
2215 }
2216
2217cleanup:
2218 FREE(buffer, M_TEMP);
2219
2220 return (result);
2221}
2222
2223
2224
2225
2226
2227
2228static int
2229cat_findposition(const CatalogKey *ckp, const CatalogRecord *crp,
2230 struct position_state *state)
2231{
2232 cnid_t curID;
2233
2234 if (state->hfsmp->hfs_flags & HFS_STANDARD)
2235 curID = ckp->hfs.parentID;
2236 else
2237 curID = ckp->hfsPlus.parentID;
2238
2239
2240 if (state->parentID != curID) {
2241 state->error = EINVAL;
2242 return (0);
2243 }
2244
2245
2246 switch(crp->recordType) {
2247 case kHFSPlusFolderRecord:
2248 case kHFSPlusFileRecord:
2249 case kHFSFolderRecord:
2250 case kHFSFileRecord:
2251 ++state->count;
2252 break;
2253 default:
2254 printf("cat_findposition: invalid record type %d in dir %d\n",
2255 crp->recordType, curID);
2256 state->error = EINVAL;
2257 return (0);
2258 };
2259
2260 return (state->count < state->index);
2261}
2262
2263
2264
2265
2266
2267
2268
2269
2270__private_extern__
2271int
2272cat_binarykeycompare(HFSPlusCatalogKey *searchKey, HFSPlusCatalogKey *trialKey)
2273{
2274 u_int32_t searchParentID, trialParentID;
2275 int result;
2276
2277 searchParentID = searchKey->parentID;
2278 trialParentID = trialKey->parentID;
2279 result = 0;
2280
2281 if (searchParentID > trialParentID) {
2282 ++result;
2283 } else if (searchParentID < trialParentID) {
2284 --result;
2285 } else {
2286 u_int16_t * str1 = &searchKey->nodeName.unicode[0];
2287 u_int16_t * str2 = &trialKey->nodeName.unicode[0];
2288 int length1 = searchKey->nodeName.length;
2289 int length2 = trialKey->nodeName.length;
2290 u_int16_t c1, c2;
2291 int length;
2292
2293 if (length1 < length2) {
2294 length = length1;
2295 --result;
2296 } else if (length1 > length2) {
2297 length = length2;
2298 ++result;
2299 } else {
2300 length = length1;
2301 }
2302
2303 while (length--) {
2304 c1 = *(str1++);
2305 c2 = *(str2++);
2306
2307 if (c1 > c2) {
2308 result = 1;
2309 break;
2310 }
2311 if (c1 < c2) {
2312 result = -1;
2313 break;
2314 }
2315 }
2316 }
2317
2318 return result;
2319}
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329int
2330CompareCatalogKeys(HFSCatalogKey *searchKey, HFSCatalogKey *trialKey)
2331{
2332 cnid_t searchParentID, trialParentID;
2333 int result;
2334
2335 searchParentID = searchKey->parentID;
2336 trialParentID = trialKey->parentID;
2337
2338 if (searchParentID > trialParentID)
2339 result = 1;
2340 else if (searchParentID < trialParentID)
2341 result = -1;
2342 else
2343 result = FastRelString(searchKey->nodeName, trialKey->nodeName);
2344
2345 return result;
2346}
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356int
2357CompareExtendedCatalogKeys(HFSPlusCatalogKey *searchKey, HFSPlusCatalogKey *trialKey)
2358{
2359 cnid_t searchParentID, trialParentID;
2360 int result;
2361
2362 searchParentID = searchKey->parentID;
2363 trialParentID = trialKey->parentID;
2364
2365 if (searchParentID > trialParentID) {
2366 result = 1;
2367 }
2368 else if (searchParentID < trialParentID) {
2369 result = -1;
2370 } else {
2371
2372 if ( searchKey->nodeName.length == 0 || trialKey->nodeName.length == 0 )
2373 result = searchKey->nodeName.length - trialKey->nodeName.length;
2374 else
2375 result = FastUnicodeCompare(&searchKey->nodeName.unicode[0],
2376 searchKey->nodeName.length,
2377 &trialKey->nodeName.unicode[0],
2378 trialKey->nodeName.length);
2379 }
2380
2381 return result;
2382}
2383
2384
2385
2386
2387
2388static int
2389buildkey(struct hfsmount *hfsmp, struct cat_desc *descp,
2390 HFSPlusCatalogKey *key, int retry)
2391{
2392 int utf8_flags = 0;
2393 int result = 0;
2394 size_t unicodeBytes = 0;
2395
2396 if (descp->cd_namelen == 0 || descp->cd_nameptr[0] == '\0')
2397 return (EINVAL);
2398
2399 key->parentID = descp->cd_parentcnid;
2400 key->nodeName.length = 0;
2401
2402
2403
2404
2405 if ((descp->cd_flags & CD_DECOMPOSED) == 0)
2406 utf8_flags |= UTF_DECOMPOSED;
2407 result = utf8_decodestr(descp->cd_nameptr, descp->cd_namelen,
2408 key->nodeName.unicode, &unicodeBytes,
2409 sizeof(key->nodeName.unicode), ':', utf8_flags);
2410 key->nodeName.length = unicodeBytes / sizeof(UniChar);
2411 key->keyLength = kHFSPlusCatalogKeyMinimumLength + unicodeBytes;
2412 if (result) {
2413 if (result != ENAMETOOLONG)
2414 result = EINVAL;
2415 return (result);
2416 }
2417
2418
2419
2420
2421
2422
2423 if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) {
2424 HFSCatalogKey hfskey;
2425
2426 bzero(&hfskey, sizeof(hfskey));
2427 hfskey.keyLength = kHFSCatalogKeyMinimumLength;
2428 hfskey.parentID = key->parentID;
2429 hfskey.nodeName[0] = 0;
2430 if (key->nodeName.length > 0) {
2431 if (unicode_to_hfs(HFSTOVCB(hfsmp),
2432 key->nodeName.length * 2,
2433 key->nodeName.unicode,
2434 &hfskey.nodeName[0], retry) != 0) {
2435 return (EINVAL);
2436 }
2437 hfskey.keyLength += hfskey.nodeName[0];
2438 }
2439 bcopy(&hfskey, key, sizeof(hfskey));
2440 }
2441 return (0);
2442 }
2443
2444
2445
2446
2447
2448__private_extern__
2449int
2450resolvelink(struct hfsmount *hfsmp, u_long linkref, struct HFSPlusCatalogFile *recp)
2451{
2452 FSBufferDescriptor btdata;
2453 struct BTreeIterator *iterator;
2454 struct cat_desc idesc;
2455 char inodename[32];
2456 int result = 0;
2457
2458 BDINIT(btdata, recp);
2459 MAKE_INODE_NAME(inodename, linkref);
2460
2461
2462 MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
2463 bzero(iterator, sizeof(*iterator));
2464
2465
2466 idesc.cd_parentcnid = hfsmp->hfs_privdir_desc.cd_cnid;
2467 idesc.cd_nameptr = inodename;
2468 idesc.cd_namelen = strlen(inodename);
2469 idesc.cd_flags = 0;
2470 idesc.cd_hint = 0;
2471 idesc.cd_encoding = 0;
2472 (void) buildkey(hfsmp, &idesc, (HFSPlusCatalogKey *)&iterator->key, 0);
2473
2474 result = BTSearchRecord(VTOF(HFSTOVCB(hfsmp)->catalogRefNum), iterator,
2475 &btdata, NULL, NULL);
2476
2477 if (result == 0) {
2478
2479 if (recp->bsdInfo.special.linkCount == 0)
2480 recp->bsdInfo.special.linkCount = 2;
2481 } else {
2482 printf("HFS resolvelink: can't find %s\n", inodename);
2483 }
2484
2485 FREE(iterator, M_TEMP);
2486
2487 return (result ? ENOENT : 0);
2488}
2489
2490
2491
2492
2493static int
2494resolvelinkid(struct hfsmount *hfsmp, u_long linkref, ino_t *ino)
2495{
2496 struct HFSPlusCatalogFile record;
2497 int error;
2498
2499 error = resolvelink(hfsmp, linkref, &record);
2500 if (error == 0) {
2501 if (record.fileID == 0)
2502 error = ENOENT;
2503 else
2504 *ino = record.fileID;
2505 }
2506 return (error);
2507}
2508
2509
2510
2511
2512static int
2513getkey(struct hfsmount *hfsmp, cnid_t cnid, CatalogKey * key)
2514{
2515 struct BTreeIterator * iterator;
2516 FSBufferDescriptor btdata;
2517 UInt16 datasize;
2518 CatalogKey * keyp;
2519 CatalogRecord * recp;
2520 int result;
2521 int std_hfs;
2522
2523 std_hfs = (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord);
2524
2525 MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
2526 bzero(iterator, sizeof(*iterator));
2527 buildthreadkey(cnid, std_hfs, (CatalogKey *)&iterator->key);
2528
2529 MALLOC(recp, CatalogRecord *, sizeof(CatalogRecord), M_TEMP, M_WAITOK);
2530 BDINIT(btdata, recp);
2531
2532 result = BTSearchRecord(VTOF(HFSTOVCB(hfsmp)->catalogRefNum), iterator,
2533 &btdata, &datasize, iterator);
2534 if (result)
2535 goto exit;
2536
2537
2538 switch (recp->recordType) {
2539 case kHFSFileThreadRecord:
2540 case kHFSFolderThreadRecord:
2541 keyp = (CatalogKey *)((char *)&recp->hfsThread.reserved + 6);
2542 keyp->hfs.keyLength = kHFSCatalogKeyMinimumLength + keyp->hfs.nodeName[0];
2543 bcopy(keyp, key, keyp->hfs.keyLength + 1);
2544 break;
2545
2546 case kHFSPlusFileThreadRecord:
2547 case kHFSPlusFolderThreadRecord:
2548 keyp = (CatalogKey *)&recp->hfsPlusThread.reserved;
2549 keyp->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength +
2550 (keyp->hfsPlus.nodeName.length * 2);
2551 bcopy(keyp, key, keyp->hfsPlus.keyLength + 2);
2552 break;
2553
2554 default:
2555 result = ENOENT;
2556 break;
2557 }
2558
2559exit:
2560 FREE(iterator, M_TEMP);
2561 FREE(recp, M_TEMP);
2562
2563 return MacToVFSError(result);
2564}
2565
2566
2567
2568
2569
2570
2571__private_extern__
2572int
2573cat_getkeyplusattr(struct hfsmount *hfsmp, cnid_t cnid, CatalogKey * key, struct cat_attr *attrp)
2574{
2575 int result;
2576
2577 result = getkey(hfsmp, cnid, key);
2578
2579 if (result == 0) {
2580 result = cat_lookupbykey(hfsmp, key, 0, 0, NULL, attrp, NULL, NULL);
2581 }
2582
2583 return MacToVFSError(result);
2584}
2585
2586
2587
2588
2589
2590static void
2591buildrecord(struct cat_attr *attrp, cnid_t cnid, int std_hfs, u_int32_t encoding,
2592 CatalogRecord *crp, int *recordSize)
2593{
2594 int type = attrp->ca_mode & S_IFMT;
2595 u_int32_t createtime = to_hfs_time(attrp->ca_itime);
2596
2597 if (std_hfs) {
2598 createtime = UTCToLocal(createtime);
2599 if (type == S_IFDIR) {
2600 bzero(crp, sizeof(HFSCatalogFolder));
2601 crp->recordType = kHFSFolderRecord;
2602 crp->hfsFolder.folderID = cnid;
2603 crp->hfsFolder.createDate = createtime;
2604 crp->hfsFolder.modifyDate = createtime;
2605 bcopy(attrp->ca_finderinfo, &crp->hfsFolder.userInfo, 32);
2606 *recordSize = sizeof(HFSCatalogFolder);
2607 } else {
2608 bzero(crp, sizeof(HFSCatalogFile));
2609 crp->recordType = kHFSFileRecord;
2610 crp->hfsFile.fileID = cnid;
2611 crp->hfsFile.createDate = createtime;
2612 crp->hfsFile.modifyDate = createtime;
2613 bcopy(attrp->ca_finderinfo, &crp->hfsFile.userInfo, 16);
2614 bcopy(&attrp->ca_finderinfo[16], &crp->hfsFile.finderInfo, 16);
2615 *recordSize = sizeof(HFSCatalogFile);
2616 }
2617 } else {
2618 struct HFSPlusBSDInfo * bsdp = NULL;
2619 struct FndrFileInfo * fip = NULL;
2620
2621 if (type == S_IFDIR) {
2622 crp->recordType = kHFSPlusFolderRecord;
2623 crp->hfsPlusFolder.flags = 0;
2624 crp->hfsPlusFolder.valence = 0;
2625 crp->hfsPlusFolder.folderID = cnid;
2626 crp->hfsPlusFolder.createDate = createtime;
2627 crp->hfsPlusFolder.contentModDate = createtime;
2628 crp->hfsPlusFolder.attributeModDate = createtime;
2629 crp->hfsPlusFolder.accessDate = createtime;
2630 crp->hfsPlusFolder.backupDate = 0;
2631 crp->hfsPlusFolder.textEncoding = encoding;
2632 crp->hfsPlusFolder.attrBlocks = 0;
2633 bcopy(attrp->ca_finderinfo, &crp->hfsPlusFolder.userInfo, 32);
2634 bsdp = &crp->hfsPlusFolder.bsdInfo;
2635 bsdp->special.rawDevice = 0;
2636 *recordSize = sizeof(HFSPlusCatalogFolder);
2637 } else {
2638 crp->recordType = kHFSPlusFileRecord;
2639 crp->hfsPlusFile.flags = kHFSThreadExistsMask;
2640 crp->hfsPlusFile.reserved1 = 0;
2641 crp->hfsPlusFile.fileID = cnid;
2642 crp->hfsPlusFile.createDate = createtime;
2643 crp->hfsPlusFile.contentModDate = createtime;
2644 crp->hfsPlusFile.accessDate = createtime;
2645 crp->hfsPlusFile.attributeModDate = createtime;
2646 crp->hfsPlusFile.backupDate = 0;
2647 crp->hfsPlusFile.textEncoding = encoding;
2648 crp->hfsPlusFile.attrBlocks = 0;
2649 bsdp = &crp->hfsPlusFile.bsdInfo;
2650 bsdp->special.rawDevice = 0;
2651 switch(type) {
2652 case S_IFBLK:
2653 case S_IFCHR:
2654
2655 bsdp->special.rawDevice = attrp->ca_rdev;
2656 bzero(&crp->hfsPlusFile.userInfo, 32);
2657 break;
2658 case S_IFREG:
2659
2660 fip = (FndrFileInfo *)&attrp->ca_finderinfo;
2661 if ((SWAP_BE32(fip->fdType) == kHardLinkFileType) &&
2662 (SWAP_BE32(fip->fdCreator) == kHFSPlusCreator)) {
2663 bsdp->special.iNodeNum = attrp->ca_rdev;
2664 }
2665 bcopy(attrp->ca_finderinfo, &crp->hfsPlusFile.userInfo, 32);
2666 break;
2667 case S_IFLNK:
2668
2669 bcopy(attrp->ca_finderinfo, &crp->hfsPlusFile.userInfo, 32);
2670 break;
2671 }
2672 bzero(&crp->hfsPlusFile.dataFork, 2*sizeof(HFSPlusForkData));
2673 *recordSize = sizeof(HFSPlusCatalogFile);
2674 }
2675 bsdp->ownerID = attrp->ca_uid;
2676 bsdp->groupID = attrp->ca_gid;
2677 bsdp->fileMode = attrp->ca_mode;
2678 bsdp->adminFlags = attrp->ca_flags >> 16;
2679 bsdp->ownerFlags = attrp->ca_flags & 0x000000FF;
2680 }
2681}
2682
2683
2684
2685
2686
2687static int
2688builddesc(const HFSPlusCatalogKey *key, cnid_t cnid, u_long hint, u_long encoding,
2689 int isdir, struct cat_desc *descp)
2690{
2691 int result = 0;
2692 char * nameptr;
2693 size_t bufsize;
2694 size_t utf8len;
2695 char tmpbuff[128];
2696
2697
2698 bufsize = (3 * key->nodeName.length) + 1;
2699 if (bufsize >= sizeof(tmpbuff) - 1) {
2700 MALLOC(nameptr, char *, bufsize, M_TEMP, M_WAITOK);
2701 } else {
2702 nameptr = &tmpbuff[0];
2703 }
2704
2705 result = utf8_encodestr(key->nodeName.unicode,
2706 key->nodeName.length * sizeof(UniChar),
2707 nameptr, (size_t *)&utf8len,
2708 bufsize, ':', 0);
2709
2710 if (result == ENAMETOOLONG) {
2711 bufsize = 1 + utf8_encodelen(key->nodeName.unicode,
2712 key->nodeName.length * sizeof(UniChar),
2713 ':', 0);
2714 FREE(nameptr, M_TEMP);
2715 MALLOC(nameptr, char *, bufsize, M_TEMP, M_WAITOK);
2716
2717 result = utf8_encodestr(key->nodeName.unicode,
2718 key->nodeName.length * sizeof(UniChar),
2719 nameptr, (size_t *)&utf8len,
2720 bufsize, ':', 0);
2721 }
2722 descp->cd_parentcnid = key->parentID;
2723 descp->cd_nameptr = vfs_addname(nameptr, utf8len, 0, 0);
2724 descp->cd_namelen = utf8len;
2725 descp->cd_cnid = cnid;
2726 descp->cd_hint = hint;
2727 descp->cd_flags = CD_DECOMPOSED | CD_HASBUF;
2728 if (isdir)
2729 descp->cd_flags |= CD_ISDIR;
2730 descp->cd_encoding = encoding;
2731 if (nameptr != &tmpbuff[0]) {
2732 FREE(nameptr, M_TEMP);
2733 }
2734 return result;
2735}
2736
2737
2738
2739
2740
2741
2742static void
2743getbsdattr(struct hfsmount *hfsmp, const struct HFSPlusCatalogFile *crp, struct cat_attr * attrp)
2744{
2745 int isDirectory = (crp->recordType == kHFSPlusFolderRecord);
2746 const struct HFSPlusBSDInfo *bsd = &crp->bsdInfo;
2747
2748 attrp->ca_recflags = crp->flags;
2749 attrp->ca_nlink = 1;
2750 attrp->ca_atime = to_bsd_time(crp->accessDate);
2751 attrp->ca_atimeondisk = attrp->ca_atime;
2752 attrp->ca_mtime = to_bsd_time(crp->contentModDate);
2753 attrp->ca_ctime = to_bsd_time(crp->attributeModDate);
2754 attrp->ca_itime = to_bsd_time(crp->createDate);
2755 attrp->ca_btime = to_bsd_time(crp->backupDate);
2756
2757 if ((bsd->fileMode & S_IFMT) == 0) {
2758 attrp->ca_flags = 0;
2759 attrp->ca_uid = hfsmp->hfs_uid;
2760 attrp->ca_gid = hfsmp->hfs_gid;
2761 if (isDirectory)
2762 attrp->ca_mode = S_IFDIR | (hfsmp->hfs_dir_mask & ACCESSPERMS);
2763 else
2764 attrp->ca_mode = S_IFREG | (hfsmp->hfs_file_mask & ACCESSPERMS);
2765 attrp->ca_rdev = 0;
2766 } else {
2767 attrp->ca_rdev = 0;
2768 attrp->ca_uid = bsd->ownerID;
2769 attrp->ca_gid = bsd->groupID;
2770 attrp->ca_flags = bsd->ownerFlags | (bsd->adminFlags << 16);
2771 attrp->ca_mode = (mode_t)bsd->fileMode;
2772 switch (attrp->ca_mode & S_IFMT) {
2773 case S_IFCHR:
2774 case S_IFBLK:
2775 attrp->ca_rdev = bsd->special.rawDevice;
2776 break;
2777 case S_IFREG:
2778
2779 if (bsd->special.linkCount > 0)
2780 attrp->ca_nlink = bsd->special.linkCount;
2781 break;
2782 }
2783
2784 if (((unsigned int)vfs_flags(HFSTOVFS(hfsmp))) & MNT_UNKNOWNPERMISSIONS) {
2785
2786
2787
2788
2789
2790
2791
2792 attrp->ca_uid = hfsmp->hfs_uid;
2793 attrp->ca_gid = hfsmp->hfs_gid;
2794 }
2795 }
2796
2797 if (isDirectory) {
2798 if (!S_ISDIR(attrp->ca_mode)) {
2799 attrp->ca_mode &= ~S_IFMT;
2800 attrp->ca_mode |= S_IFDIR;
2801 }
2802 attrp->ca_nlink = 2 + ((HFSPlusCatalogFolder *)crp)->valence;
2803 attrp->ca_entries = ((HFSPlusCatalogFolder *)crp)->valence;
2804 attrp->ca_attrblks = ((HFSPlusCatalogFolder *)crp)->attrBlocks;
2805 } else {
2806
2807 if (crp->flags & kHFSFileLockedMask) {
2808
2809
2810 if ((attrp->ca_flags & (SF_IMMUTABLE | UF_IMMUTABLE)) == 0)
2811 attrp->ca_flags |= UF_IMMUTABLE;
2812 } else {
2813
2814 attrp->ca_flags &= ~(SF_IMMUTABLE | UF_IMMUTABLE);
2815 }
2816
2817 attrp->ca_blocks = crp->dataFork.totalBlocks + crp->resourceFork.totalBlocks;
2818 attrp->ca_attrblks = crp->attrBlocks;
2819
2820 if ((hfsmp->hfs_flags & HFS_STANDARD) == 0)
2821 attrp->ca_recflags |= kHFSThreadExistsMask;
2822 }
2823
2824 attrp->ca_fileid = crp->fileID;
2825
2826 bcopy(&crp->userInfo, attrp->ca_finderinfo, 32);
2827}
2828
2829
2830
2831
2832
2833static void
2834promotekey(struct hfsmount *hfsmp, const HFSCatalogKey *hfskey,
2835 HFSPlusCatalogKey *keyp, u_long *encoding)
2836{
2837 hfs_to_unicode_func_t hfs_get_unicode = hfsmp->hfs_get_unicode;
2838 UInt32 uniCount;
2839 int error;
2840
2841 *encoding = hfsmp->hfs_encoding;
2842
2843 error = hfs_get_unicode(hfskey->nodeName, keyp->nodeName.unicode,
2844 kHFSPlusMaxFileNameChars, &uniCount);
2845
2846
2847
2848
2849 if (error && hfsmp->hfs_encoding != kTextEncodingMacRoman) {
2850 *encoding = 0;
2851 (void) mac_roman_to_unicode(hfskey->nodeName,
2852 keyp->nodeName.unicode,
2853 kHFSPlusMaxFileNameChars,
2854 &uniCount);
2855 }
2856
2857 keyp->nodeName.length = uniCount;
2858 keyp->parentID = hfskey->parentID;
2859}
2860
2861
2862
2863
2864
2865static void
2866promotefork(struct hfsmount *hfsmp, const struct HFSCatalogFile *filep,
2867 int resource, struct cat_fork * forkp)
2868{
2869 struct HFSPlusExtentDescriptor *xp;
2870 u_long blocksize = HFSTOVCB(hfsmp)->blockSize;
2871
2872 bzero(forkp, sizeof(*forkp));
2873 xp = &forkp->cf_extents[0];
2874 if (resource) {
2875 forkp->cf_size = filep->rsrcLogicalSize;
2876 forkp->cf_blocks = filep->rsrcPhysicalSize / blocksize;
2877 forkp->cf_bytesread = 0;
2878 forkp->cf_vblocks = 0;
2879 xp[0].startBlock = (u_int32_t)filep->rsrcExtents[0].startBlock;
2880 xp[0].blockCount = (u_int32_t)filep->rsrcExtents[0].blockCount;
2881 xp[1].startBlock = (u_int32_t)filep->rsrcExtents[1].startBlock;
2882 xp[1].blockCount = (u_int32_t)filep->rsrcExtents[1].blockCount;
2883 xp[2].startBlock = (u_int32_t)filep->rsrcExtents[2].startBlock;
2884 xp[2].blockCount = (u_int32_t)filep->rsrcExtents[2].blockCount;
2885 } else {
2886 forkp->cf_size = filep->dataLogicalSize;
2887 forkp->cf_blocks = filep->dataPhysicalSize / blocksize;
2888 forkp->cf_bytesread = 0;
2889 forkp->cf_vblocks = 0;
2890 xp[0].startBlock = (u_int32_t)filep->dataExtents[0].startBlock;
2891 xp[0].blockCount = (u_int32_t)filep->dataExtents[0].blockCount;
2892 xp[1].startBlock = (u_int32_t)filep->dataExtents[1].startBlock;
2893 xp[1].blockCount = (u_int32_t)filep->dataExtents[1].blockCount;
2894 xp[2].startBlock = (u_int32_t)filep->dataExtents[2].startBlock;
2895 xp[2].blockCount = (u_int32_t)filep->dataExtents[2].blockCount;
2896 }
2897}
2898
2899
2900
2901
2902
2903static void
2904promoteattr(struct hfsmount *hfsmp, const CatalogRecord *dataPtr, struct HFSPlusCatalogFile *crp)
2905{
2906 u_long blocksize = HFSTOVCB(hfsmp)->blockSize;
2907
2908 if (dataPtr->recordType == kHFSFolderRecord) {
2909 struct HFSCatalogFolder * folder;
2910
2911 folder = (struct HFSCatalogFolder *) dataPtr;
2912 crp->recordType = kHFSPlusFolderRecord;
2913 crp->flags = folder->flags;
2914 crp->fileID = folder->folderID;
2915 crp->createDate = LocalToUTC(folder->createDate);
2916 crp->contentModDate = LocalToUTC(folder->modifyDate);
2917 crp->backupDate = LocalToUTC(folder->backupDate);
2918 crp->reserved1 = folder->valence;
2919 bcopy(&folder->userInfo, &crp->userInfo, 32);
2920 } else {
2921 struct HFSCatalogFile * file;
2922
2923 file = (struct HFSCatalogFile *) dataPtr;
2924 crp->recordType = kHFSPlusFileRecord;
2925 crp->flags = file->flags;
2926 crp->fileID = file->fileID;
2927 crp->createDate = LocalToUTC(file->createDate);
2928 crp->contentModDate = LocalToUTC(file->modifyDate);
2929 crp->backupDate = LocalToUTC(file->backupDate);
2930 crp->reserved1 = 0;
2931 bcopy(&file->userInfo, &crp->userInfo, 16);
2932 bcopy(&file->finderInfo, &crp->finderInfo, 16);
2933 crp->dataFork.totalBlocks = file->dataPhysicalSize / blocksize;
2934 crp->resourceFork.totalBlocks = file->rsrcPhysicalSize / blocksize;
2935 }
2936 crp->textEncoding = 0;
2937 crp->attributeModDate = crp->contentModDate;
2938 crp->accessDate = crp->contentModDate;
2939 bzero(&crp->bsdInfo, sizeof(HFSPlusBSDInfo));
2940 crp->attrBlocks = 0;
2941}
2942
2943
2944
2945
2946
2947static int
2948buildthread(void *keyp, void *recp, int std_hfs, int directory)
2949{
2950 int size = 0;
2951
2952 if (std_hfs) {
2953 HFSCatalogKey *key = (HFSCatalogKey *)keyp;
2954 HFSCatalogThread *rec = (HFSCatalogThread *)recp;
2955
2956 size = sizeof(HFSCatalogThread);
2957 bzero(rec, size);
2958 if (directory)
2959 rec->recordType = kHFSFolderThreadRecord;
2960 else
2961 rec->recordType = kHFSFileThreadRecord;
2962 rec->parentID = key->parentID;
2963 bcopy(key->nodeName, rec->nodeName, key->nodeName[0]+1);
2964
2965 } else {
2966 HFSPlusCatalogKey *key = (HFSPlusCatalogKey *)keyp;
2967 HFSPlusCatalogThread *rec = (HFSPlusCatalogThread *)recp;
2968
2969 size = sizeof(HFSPlusCatalogThread);
2970 if (directory)
2971 rec->recordType = kHFSPlusFolderThreadRecord;
2972 else
2973 rec->recordType = kHFSPlusFileThreadRecord;
2974 rec->reserved = 0;
2975 rec->parentID = key->parentID;
2976 bcopy(&key->nodeName, &rec->nodeName,
2977 sizeof(UniChar) * (key->nodeName.length + 1));
2978
2979
2980 size -= (sizeof(rec->nodeName.unicode) -
2981 (rec->nodeName.length * sizeof(UniChar)));
2982 }
2983
2984 return (size);
2985}
2986
2987
2988
2989
2990static void
2991buildthreadkey(HFSCatalogNodeID parentID, int std_hfs, CatalogKey *key)
2992{
2993 if (std_hfs) {
2994 key->hfs.keyLength = kHFSCatalogKeyMinimumLength;
2995 key->hfs.reserved = 0;
2996 key->hfs.parentID = parentID;
2997 key->hfs.nodeName[0] = 0;
2998 } else {
2999 key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength;
3000 key->hfsPlus.parentID = parentID;
3001 key->hfsPlus.nodeName.length = 0;
3002 }
3003}
3004
3005
3006
3007
3008static u_long
3009getencoding(const CatalogRecord *crp)
3010{
3011 u_long encoding;
3012
3013 if (crp->recordType == kHFSPlusFolderRecord)
3014 encoding = crp->hfsPlusFolder.textEncoding;
3015 else if (crp->recordType == kHFSPlusFileRecord)
3016 encoding = crp->hfsPlusFile.textEncoding;
3017 else
3018 encoding = 0;
3019
3020 return (encoding);
3021}
3022
3023
3024
3025
3026static cnid_t
3027getcnid(const CatalogRecord *crp)
3028{
3029 cnid_t cnid = 0;
3030
3031 switch (crp->recordType) {
3032 case kHFSFolderRecord:
3033 cnid = crp->hfsFolder.folderID;
3034 break;
3035 case kHFSFileRecord:
3036 cnid = crp->hfsFile.fileID;
3037 break;
3038 case kHFSPlusFolderRecord:
3039 cnid = crp->hfsPlusFolder.folderID;
3040 break;
3041 case kHFSPlusFileRecord:
3042 cnid = crp->hfsPlusFile.fileID;
3043 break;
3044 default:
3045 printf("hfs: getcnid: unknown recordType (crp @ 0x%x)\n", crp);
3046 break;
3047 }
3048
3049 return (cnid);
3050}
3051
3052
3053
3054
3055static cnid_t
3056getparentcnid(const CatalogRecord *recp)
3057{
3058 cnid_t cnid = 0;
3059
3060 switch (recp->recordType) {
3061 case kHFSFileThreadRecord:
3062 case kHFSFolderThreadRecord:
3063 cnid = recp->hfsThread.parentID;
3064 break;
3065
3066 case kHFSPlusFileThreadRecord:
3067 case kHFSPlusFolderThreadRecord:
3068 cnid = recp->hfsPlusThread.parentID;
3069 break;
3070 default:
3071 panic("hfs: getparentcnid: unknown recordType (crp @ 0x%x)\n", recp);
3072 break;
3073 }
3074
3075 return (cnid);
3076}
3077
3078
3079
3080
3081static int
3082isadir(const CatalogRecord *crp)
3083{
3084 return (crp->recordType == kHFSFolderRecord ||
3085 crp->recordType == kHFSPlusFolderRecord);
3086}
3087
3088