]> git.saurik.com Git - apple/hfs.git/blob - livefiles_hfs_plugin/lf_hfs_vfsops.c
hfs-522.100.5.tar.gz
[apple/hfs.git] / livefiles_hfs_plugin / lf_hfs_vfsops.c
1 /* Copyright © 2017-2018 Apple Inc. All rights reserved.
2 *
3 * lf_hfs_vfsops.c
4 * livefiles_hfs
5 *
6 * Created by Or Haimovich on 18/3/18.
7 */
8
9 #include "lf_hfs_common.h"
10 #include <CommonCrypto/CommonDigest.h>
11 #include <stdatomic.h>
12 #include <sys/ioctl.h>
13 #include <sys/mount.h>
14 #include <sys/disk.h>
15 #include <sys/stat.h>
16 #include <stdlib.h>
17 #include "lf_hfs_logger.h"
18 #include "lf_hfs_mount.h"
19 #include "lf_hfs.h"
20 #include "lf_hfs_catalog.h"
21 #include "lf_hfs_cnode.h"
22 #include "lf_hfs_chash.h"
23 #include "lf_hfs_format.h"
24 #include "lf_hfs_locks.h"
25 #include "lf_hfs_endian.h"
26 #include "lf_hfs_locks.h"
27 #include "lf_hfs_utils.h"
28 #include "lf_hfs_raw_read_write.h"
29 #include "lf_hfs_vfsutils.h"
30 #include "lf_hfs_vfsops.h"
31 #include "lf_hfs_volume_allocation.h"
32 #include "lf_hfs_catalog.h"
33 #include "lf_hfs_link.h"
34 #include "lf_hfs_vnops.h"
35 #include "lf_hfs_generic_buf.h"
36 #include "lf_hfs_fsops_handler.h"
37 #include "lf_hfs_journal.h"
38 #include "lf_hfs_fileops_handler.h"
39
40 #include <spawn.h>
41
42 static void hfs_locks_destroy(struct hfsmount *hfsmp);
43 static int hfs_mountfs(struct vnode *devvp, struct mount *mp, struct hfs_mount_args *args);
44
45
46 static int
47 setup_posix_file_action_for_fsck(posix_spawn_file_actions_t *file_actions, int fd)
48 {
49 int error;
50
51 if (file_actions == NULL || fd < 0)
52 {
53 return EINVAL;
54 }
55
56 error = posix_spawn_file_actions_init(file_actions);
57 if (error)
58 {
59 goto out;
60 }
61
62 error = posix_spawn_file_actions_addinherit_np(file_actions, 0);
63 if (error)
64 {
65 goto out;
66 }
67
68 error = posix_spawn_file_actions_addinherit_np(file_actions, 1);
69 if (error)
70 {
71 goto out;
72 }
73
74 error = posix_spawn_file_actions_addinherit_np(file_actions, 2);
75 if (error)
76 {
77 goto out;
78 }
79
80 error = posix_spawn_file_actions_addinherit_np(file_actions, fd);
81
82 out:
83 return error;
84 }
85
86 static int
87 setup_spawnattr_for_fsck(posix_spawnattr_t *spawn_attr)
88 {
89 int error;
90
91 error = posix_spawnattr_init(spawn_attr);
92 if (error)
93 {
94 goto out;
95 }
96 error = posix_spawnattr_setflags(spawn_attr, POSIX_SPAWN_CLOEXEC_DEFAULT);
97
98 out:
99 return error;
100 }
101
102
103 // fsck_mount_and_replay: executed on fsck_hfs -quick
104 // Try to mount, and if a journaled volume, play the journal.
105 // Returned values:
106 // OK if:
107 // 1) On journaled volumes, the journal has been replayed and the dirty bit cleared.
108 // 2) On non-journalled volumes, the dirty is cleared.
109 // EINVAL if:
110 // 1) On non-journalled volumes the dirty bit is set. Please run fsck_hfs to fix.
111 // 2) On journalled volume, the replay failed. Try fsck_hfs.
112 int fsck_mount_and_replay(int iFd) {
113 int iErr = 0;
114
115 LFHFS_LOG(LEVEL_DEBUG, "fsck_mount_and_replay %d", iFd);
116
117 UVFSFileNode sRootNode;
118
119 iErr = LFHFS_Taste(iFd);
120 if (iErr) {
121 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_Taste returned %d", iErr);
122 return iErr;
123 }
124
125 UVFSScanVolsRequest sScanVolsReq = {0};
126 UVFSScanVolsReply sScanVolsReply = {0};
127 iErr = LFHFS_ScanVols(iFd, &sScanVolsReq, &sScanVolsReply);
128 if (iErr) {
129 LFHFS_LOG(LEVEL_DEBUG, "LFHFS_ScanVol returned %d", iErr);
130 return iErr;
131 }
132
133 // Mount and replay journal if possible
134 iErr = LFHFS_Mount(iFd, 0, 0, NULL, &sRootNode); // On journaled volumes, this replays the journal.
135 // Non-journaled volumes fails to mount if dirty (Unmounted == 0).
136 if (iErr) {
137 LFHFS_LOG(LEVEL_DEBUG, "fsck_mount_and_replay: LFHFS_Mount returned %d", iErr);
138 return EINVAL;
139 }
140
141 LFHFS_Unmount (sRootNode, UVFSUnmountHintNone);
142
143 return iErr;
144 }
145
146 #define PATH_TO_FSCK "/System/Library/Filesystems/hfs.fs/Contents/Resources/fsck_hfs"
147
148 int
149 fsck_hfs(int fd, check_flags_t how)
150 {
151 pid_t child;
152 pid_t child_found;
153 int child_status;
154 extern char **environ;
155 char fdescfs_path[24];
156 posix_spawn_file_actions_t file_actions;
157 int result;
158 posix_spawnattr_t spawn_attr;
159
160 /*
161 * XXXJRT There are dragons related to how the journal is replayed in
162 * fsck_hfs. Until we can sort out the mess, disable running fsck_hfs.
163 * <rdar://problem/47262605> USB: Re-enable Detonator fsck_hfs
164 */
165 if (how == QUICK_CHECK) {
166 if (fsck_mount_and_replay(fd) == 0) {
167 return(0);
168 }
169 }
170
171 LFHFS_LOG(LEVEL_DEFAULT, "fsck_hfs - fsck start for %d", fd);
172 snprintf(fdescfs_path, sizeof(fdescfs_path), "/dev/fd/%d", fd);
173 const char * argv[] = {"fsck_hfs", "-q", fdescfs_path, NULL};
174
175 switch (how)
176 {
177 case QUICK_CHECK:
178 /* Do nothing, already setup for this */
179 break;
180 case CHECK:
181 argv[1] = "-n";
182 break;
183 case CHECK_AND_REPAIR:
184 argv[1] = "-y";
185 break;
186 default:
187 LFHFS_LOG(LEVEL_ERROR, "Invalid how flags for the check, ignoring; %d", how);
188 break;
189 }
190
191 LFHFS_LOG(LEVEL_DEBUG, "fsck_hfs params: %s %s %s", argv[1], argv[2], argv[3]);
192 result = setup_posix_file_action_for_fsck(&file_actions, fd);
193 if (result)
194 {
195 goto out;
196 }
197
198 result = setup_spawnattr_for_fsck(&spawn_attr);
199 if (result)
200 {
201 posix_spawn_file_actions_destroy(&file_actions);
202 goto out;
203 }
204
205 result = posix_spawn(&child,
206 PATH_TO_FSCK,
207 &file_actions,
208 &spawn_attr,
209 (char * const *)argv,
210 environ);
211
212 posix_spawn_file_actions_destroy(&file_actions);
213 posix_spawnattr_destroy(&spawn_attr);
214 if (result)
215 {
216 LFHFS_LOG(LEVEL_ERROR, "posix_spawn fsck_hfs: error=%d", result);
217 goto out;
218 }
219
220 // Wait for child to finish, XXXab: revisit, need sensible timeout?
221 do {
222 child_found = waitpid(child, &child_status, 0);
223 } while (child_found == -1 && errno == EINTR);
224
225 if (child_found == -1)
226 {
227 result = errno;
228 LFHFS_LOG(LEVEL_ERROR, "waitpid fsck_hfs: errno=%d", result);
229 goto out;
230 }
231
232 if (WIFEXITED(child_status))
233 {
234 result = WEXITSTATUS(child_status);
235 if (result)
236 {
237 LFHFS_LOG(LEVEL_ERROR, "fsck_hfs: exited with status %d", result);
238 result = EILSEQ;
239 } else {
240 LFHFS_LOG(LEVEL_ERROR, "fsck_hfs: exited with status %d", result);
241 }
242 }
243 else
244 {
245 result = WTERMSIG(child_status);
246 LFHFS_LOG(LEVEL_ERROR, "fsck_hfs: terminated by signal %d", result);
247 result = EINTR;
248 }
249
250 out:
251 LFHFS_LOG(LEVEL_DEFAULT, "fsck_hfs - fsck finish for %d with err %d", fd, result);
252 return result;
253 }
254
255 int
256 hfs_mount(struct mount *mp, vnode_t devvp, user_addr_t data)
257 {
258 struct hfsmount *hfsmp = NULL;
259 int retval = 0;
260 if ( devvp == NULL )
261 {
262 retval = EINVAL;
263 goto fail;
264 }
265
266 retval = hfs_mountfs(devvp, mp, NULL);
267 if (retval)
268 {
269 // ENOTSUP is for regular HFS -> just fail
270 if (retval != ENOTSUP)
271 {
272 //Failed during mount, try to run fsck to fix and try mount again
273 retval = fsck_hfs(devvp->psFSRecord->iFD, CHECK_AND_REPAIR);
274
275 // fsck succeeded, try to mount
276 if (!retval) {
277 retval = hfs_mountfs(devvp, mp, NULL);
278 if (!retval)
279 goto mount_passed;
280 }
281 }
282
283 LFHFS_LOG(LEVEL_ERROR, "hfs_mount: hfs_mountfs returned error=%d\n", retval);
284 goto fail;
285 }
286 mount_passed:
287 /* After hfs_mountfs succeeds, we should have valid hfsmp */
288 hfsmp = VFSTOHFS(mp);
289
290 /* Set up the maximum defrag file size */
291 hfsmp->hfs_defrag_max = HFS_INITIAL_DEFRAG_SIZE;
292
293 if (!data)
294 {
295 // Root mount
296 hfsmp->hfs_uid = UNKNOWNUID;
297 hfsmp->hfs_gid = UNKNOWNGID;
298 hfsmp->hfs_dir_mask = (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); /* 0755 */
299 hfsmp->hfs_file_mask = (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); /* 0755 */
300
301 /* Establish the free block reserve. */
302 hfsmp->reserveBlocks = (uint32_t) ((u_int64_t)hfsmp->totalBlocks * HFS_MINFREE) / 100;
303 hfsmp->reserveBlocks = MIN(hfsmp->reserveBlocks, HFS_MAXRESERVE / hfsmp->blockSize);
304 }
305
306 fail:
307 return (retval);
308 }
309
310 static int hfs_InitialMount(struct vnode *devvp, struct mount *mp, struct hfs_mount_args *args, HFSPlusVolumeHeader **vhp, off_t *embeddedOffset, struct hfsmount **hfsmp, bool bFailForDirty)
311 {
312 int retval = 0;
313 HFSMasterDirectoryBlock *mdbp = NULL;
314 void* pvBuffer = NULL;
315 int mntwrapper;
316 u_int64_t disksize;
317 u_int64_t log_blkcnt;
318 u_int32_t log_blksize;
319 u_int32_t phys_blksize;
320 u_int32_t minblksize;
321 u_int32_t iswritable;
322 u_int64_t mdb_offset;
323 u_int32_t device_features = 0;
324
325 mntwrapper = 0;
326 minblksize = kHFSBlockSize;
327
328 /* Get the logical block size (treated as physical block size everywhere) */
329 if (ioctl(devvp->psFSRecord->iFD, DKIOCGETBLOCKSIZE, &log_blksize))
330 {
331 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: DKIOCGETBLOCKSIZE failed\n");
332 retval = ENXIO;
333 goto error_exit;
334 }
335 if (log_blksize == 0 || log_blksize > 1024*1024*1024)
336 {
337 LFHFS_LOG(LEVEL_ERROR, "hfs_mountfs: logical block size 0x%x looks bad. Not mounting.\n", log_blksize);
338 retval = ENXIO;
339 goto error_exit;
340 }
341
342 /* Get the physical block size. */
343 if (ioctl(devvp->psFSRecord->iFD, DKIOCGETPHYSICALBLOCKSIZE, &phys_blksize))
344 {
345 if ((retval != ENOTSUP) && (retval != ENOTTY))
346 {
347 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: DKIOCGETPHYSICALBLOCKSIZE failed\n");
348 retval = ENXIO;
349 goto error_exit;
350 }
351 /* If device does not support this ioctl, assume that physical
352 * block size is same as logical block size
353 */
354 phys_blksize = log_blksize;
355 }
356
357 if (phys_blksize == 0 || phys_blksize > MAXBSIZE)
358 {
359 LFHFS_LOG(LEVEL_ERROR, "hfs_mountfs: physical block size 0x%x looks bad. Not mounting.\n", phys_blksize);
360 retval = ENXIO;
361 goto error_exit;
362 }
363
364 /* Get the number of physical blocks. */
365 if (ioctl(devvp->psFSRecord->iFD, DKIOCGETBLOCKCOUNT, &log_blkcnt))
366 {
367 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: DKIOCGETBLOCKCOUNT failed\n");
368 retval = ENXIO;
369 goto error_exit;
370 }
371
372 /* Compute an accurate disk size (i.e. within 512 bytes) */
373 disksize = (u_int64_t)log_blkcnt * (u_int64_t)log_blksize;
374
375 /*
376 * At this point:
377 * minblksize is the minimum physical block size
378 * log_blksize has our preferred physical block size
379 * log_blkcnt has the total number of physical blocks
380 */
381 mdbp = hfs_mallocz(kMDBSize);
382 if (mdbp == NULL)
383 {
384 retval = ENOMEM;
385 goto error_exit;
386 }
387
388 pvBuffer = hfs_malloc(phys_blksize);
389 if (pvBuffer == NULL)
390 {
391 retval = ENOMEM;
392 goto error_exit;
393 }
394
395 mdb_offset = (uint64_t) HFS_PRI_SECTOR(log_blksize);
396 retval = raw_readwrite_read_mount( devvp, HFS_PHYSBLK_ROUNDDOWN(mdb_offset, (phys_blksize/log_blksize)), phys_blksize, pvBuffer, phys_blksize, NULL, NULL);
397 if (retval)
398 {
399 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: raw_readwrite_read_mount failed with %d\n", retval);
400 goto error_exit;
401 }
402
403 bcopy(pvBuffer + HFS_PRI_OFFSET(phys_blksize), mdbp, kMDBSize);
404 hfs_free(pvBuffer);
405 pvBuffer = NULL;
406
407 *hfsmp = hfs_malloc(sizeof(struct hfsmount));
408 if (*hfsmp == NULL)
409 {
410 retval = ENOMEM;
411 goto error_exit;
412 }
413 memset( *hfsmp, 0, sizeof(struct hfsmount) );
414
415 //Copy read only flag
416 if (mp->mnt_flag == MNT_RDONLY) (*hfsmp)->hfs_flags = HFS_READ_ONLY;
417
418 hfs_chashinit_finish(*hfsmp);
419
420 /* Init the ID lookup hashtable */
421 hfs_idhash_init (*hfsmp);
422
423 /*
424 * See if the disk supports unmap (trim).
425 *
426 * NOTE: vfs_init_io_attributes has not been called yet, so we can't use the io_flags field
427 * returned by vfs_ioattr. We need to call VNOP_IOCTL ourselves.
428 */
429 if (ioctl(devvp->psFSRecord->iFD, DKIOCGETFEATURES, &device_features) == 0)
430 {
431 if (device_features & DK_FEATURE_UNMAP)
432 {
433 (*hfsmp)->hfs_flags |= HFS_UNMAP;
434 }
435
436 if(device_features & DK_FEATURE_BARRIER)
437 {
438 (*hfsmp)->hfs_flags |= HFS_FEATURE_BARRIER;
439 }
440 }
441
442 /*
443 * Init the volume information structure
444 */
445 lf_lck_mtx_init(&(*hfsmp)->hfs_mutex);
446 lf_lck_mtx_init(&(*hfsmp)->sync_mutex);
447 lf_lck_rw_init(&(*hfsmp)->hfs_global_lock);
448 lf_lck_spin_init(&(*hfsmp)->vcbFreeExtLock);
449
450 if (mp)
451 {
452 mp->psHfsmount = (*hfsmp);
453 }
454
455 (*hfsmp)->hfs_mp = mp; /* Make VFSTOHFS work */
456 (*hfsmp)->hfs_raw_dev = 0; //vnode_specrdev(devvp);
457 (*hfsmp)->hfs_devvp = devvp;
458 (*hfsmp)->hfs_logical_block_size = log_blksize;
459 (*hfsmp)->hfs_logical_block_count = log_blkcnt;
460 (*hfsmp)->hfs_logical_bytes = (uint64_t) log_blksize * (uint64_t) log_blkcnt;
461 (*hfsmp)->hfs_physical_block_size = phys_blksize;
462 (*hfsmp)->hfs_log_per_phys = (phys_blksize / log_blksize);
463 (*hfsmp)->hfs_flags |= HFS_WRITEABLE_MEDIA;
464
465 if (mp && (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS))
466 {
467 (*hfsmp)->hfs_flags |= HFS_UNKNOWN_PERMS;
468 }
469
470 /* MNT_UNKNOWNPERMISSIONS requires setting up uid, gid, and mask: */
471 if (mp && (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS))
472 {
473 (*hfsmp)->hfs_uid = UNKNOWNUID;
474 (*hfsmp)->hfs_gid = UNKNOWNGID;
475 // vfs_setowner(mp, hfsmp->hfs_uid, hfsmp->hfs_gid); /* tell the VFS */
476 (*hfsmp)->hfs_dir_mask = UNKNOWNPERMISSIONS & ALLPERMS; /* 0777: rwx---rwx */
477 (*hfsmp)->hfs_file_mask = UNKNOWNPERMISSIONS & DEFFILEMODE; /* 0666: no --x by default? */
478 }
479
480 /* Find out if disk media is writable. */
481 if (ioctl(devvp->psFSRecord->iFD, DKIOCISWRITABLE, &iswritable) == 0)
482 {
483 if (iswritable)
484 {
485 (*hfsmp)->hfs_flags |= HFS_WRITEABLE_MEDIA;
486 }
487 else
488 {
489 (*hfsmp)->hfs_flags &= ~HFS_WRITEABLE_MEDIA;
490 }
491 }
492
493 // Reservations
494 rl_init(&(*hfsmp)->hfs_reserved_ranges[0]);
495 rl_init(&(*hfsmp)->hfs_reserved_ranges[1]);
496
497 // record the current time at which we're mounting this volume
498 struct timeval tv;
499 microuptime(&tv);
500 (*hfsmp)->hfs_mount_time = tv.tv_sec;
501
502 /* Mount an HFS Plus disk */
503 int jnl_disable = 0;
504
505 /* Mount a standard HFS disk */
506 if ((SWAP_BE16(mdbp->drSigWord) == kHFSSigWord) && (mntwrapper || (SWAP_BE16(mdbp->drEmbedSigWord) != kHFSPlusSigWord)))
507 {
508 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: Not supporting standard HFS\n");
509 retval = ENOTSUP;
510 goto error_exit;
511 }
512 /* Get the embedded Volume Header */
513 else if (SWAP_BE16(mdbp->drEmbedSigWord) == kHFSPlusSigWord)
514 {
515 *embeddedOffset = SWAP_BE16(mdbp->drAlBlSt) * kHFSBlockSize;
516 *embeddedOffset += (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.startBlock) * (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
517
518 /*
519 * If the embedded volume doesn't start on a block
520 * boundary, then switch the device to a 512-byte
521 * block size so everything will line up on a block
522 * boundary.
523 */
524 if ((*embeddedOffset % log_blksize) != 0)
525 {
526 // LF not support DKIOCSETBLOCKSIZE, return error.
527 LFHFS_LOG(LEVEL_DEFAULT, "hfs_mountfs: embedded volume offset not a multiple of physical block size (%d); switching to 512\n", log_blksize);
528 retval = ENXIO;
529 goto error_exit;
530 }
531
532 disksize = (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.blockCount) * (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
533
534 (*hfsmp)->hfs_logical_block_count = disksize / log_blksize;
535
536 (*hfsmp)->hfs_logical_bytes = (uint64_t) (*hfsmp)->hfs_logical_block_count * (uint64_t) (*hfsmp)->hfs_logical_block_size;
537
538 mdb_offset = (uint64_t)((*embeddedOffset / log_blksize) + HFS_PRI_SECTOR(log_blksize));
539
540 pvBuffer = hfs_malloc(phys_blksize);
541 if (pvBuffer == NULL)
542 {
543 retval = ENOMEM;
544 goto error_exit;
545 }
546
547 retval = raw_readwrite_read_mount( devvp, HFS_PHYSBLK_ROUNDDOWN(mdb_offset, (phys_blksize/log_blksize)), phys_blksize, pvBuffer, phys_blksize, NULL, NULL);
548 if (retval)
549 {
550 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: raw_readwrite_read_mount (2) failed with %d\n", retval);
551 goto error_exit;
552 }
553
554 bcopy(pvBuffer + HFS_PRI_OFFSET(phys_blksize), mdbp, kMDBSize);
555 *vhp = (HFSPlusVolumeHeader*) mdbp;
556 hfs_free(pvBuffer);
557 pvBuffer = NULL;
558 }
559 else
560 { /* pure HFS+ */
561 *embeddedOffset = 0;
562 *vhp = (HFSPlusVolumeHeader*) mdbp;
563 }
564
565 retval = hfs_ValidateHFSPlusVolumeHeader(*hfsmp, *vhp);
566 if (retval)
567 goto error_exit;
568
569 /*
570 * If allocation block size is less than the physical block size,
571 * invalidate the buffer read in using native physical block size
572 * to ensure data consistency.
573 *
574 * HFS Plus reserves one allocation block for the Volume Header.
575 * If the physical size is larger, then when we read the volume header,
576 * we will also end up reading in the next allocation block(s).
577 * If those other allocation block(s) is/are modified, and then the volume
578 * header is modified, the write of the volume header's buffer will write
579 * out the old contents of the other allocation blocks.
580 *
581 * We assume that the physical block size is same as logical block size.
582 * The physical block size value is used to round down the offsets for
583 * reading and writing the primary and alternate volume headers.
584 *
585 * The same logic is also in hfs_MountHFSPlusVolume to ensure that
586 * hfs_mountfs, hfs_MountHFSPlusVolume and later are doing the I/Os
587 * using same block size.
588 */
589 if (SWAP_BE32((*vhp)->blockSize) < (*hfsmp)->hfs_physical_block_size)
590 {
591 phys_blksize = (*hfsmp)->hfs_logical_block_size;
592 (*hfsmp)->hfs_physical_block_size = (*hfsmp)->hfs_logical_block_size;
593 (*hfsmp)->hfs_log_per_phys = 1;
594
595 if (retval)
596 goto error_exit;
597 }
598
599 /*
600 * On inconsistent disks, do not allow read-write mount
601 * unless it is the boot volume being mounted. We also
602 * always want to replay the journal if the journal_replay_only
603 * flag is set because that will (most likely) get the
604 * disk into a consistent state before fsck_hfs starts
605 * looking at it.
606 */
607 if ( (mp && !(mp->mnt_flag & MNT_ROOTFS))
608 && (SWAP_BE32((*vhp)->attributes) & kHFSVolumeInconsistentMask)
609 && !((*hfsmp)->hfs_flags & HFS_READ_ONLY))
610 {
611 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: failed to mount non-root inconsistent disk\n");
612 retval = EINVAL;
613 goto error_exit;
614 }
615
616 (*hfsmp)->jnl = NULL;
617 (*hfsmp)->jvp = NULL;
618 if (args != NULL && (args->flags & HFSFSMNT_EXTENDED_ARGS) && args->journal_disable)
619 {
620 jnl_disable = 1;
621 }
622
623 /*
624 * We only initialize the journal here if the last person
625 * to mount this volume was journaling aware. Otherwise
626 * we delay journal initialization until later at the end
627 * of hfs_MountHFSPlusVolume() because the last person who
628 * mounted it could have messed things up behind our back
629 * (so we need to go find the .journal file, make sure it's
630 * the right size, re-sync up if it was moved, etc).
631 */
632 uint32_t lastMountedVersion = SWAP_BE32((*vhp)->lastMountedVersion);
633 uint32_t attributes = SWAP_BE32((*vhp)->attributes);
634 if ( (lastMountedVersion == kHFSJMountVersion) &&
635 (attributes & kHFSVolumeJournaledMask) &&
636 !jnl_disable)
637 {
638
639 // if we're able to init the journal, mark the mount
640 // point as journaled.
641 if ((retval = hfs_early_journal_init(*hfsmp, *vhp, args, *embeddedOffset, mdb_offset, mdbp)) != 0)
642 {
643 if (retval == EROFS)
644 {
645 // EROFS is a special error code that means the volume has an external
646 // journal which we couldn't find. in that case we do not want to
647 // rewrite the volume header - we'll just refuse to mount the volume.
648 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: hfs_early_journal_init indicated external jnl \n");
649 retval = EINVAL;
650 goto error_exit;
651 }
652
653 // if the journal failed to open, then set the lastMountedVersion
654 // to be "FSK!" which fsck_hfs will see and force the fsck instead
655 // of just bailing out because the volume is journaled.
656 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: hfs_early_journal_init failed, setting to FSK \n");
657 HFSPlusVolumeHeader *jvhp;
658
659 (*hfsmp)->hfs_flags |= HFS_NEED_JNL_RESET;
660
661 if (mdb_offset == 0)
662 {
663 mdb_offset = (uint64_t)((*embeddedOffset / log_blksize) + HFS_PRI_SECTOR(log_blksize));
664 }
665
666 pvBuffer = hfs_malloc(phys_blksize);
667 if (pvBuffer == NULL)
668 {
669 retval = ENOMEM;
670 goto error_exit;
671 }
672
673 retval = raw_readwrite_read_mount( devvp, HFS_PHYSBLK_ROUNDDOWN(mdb_offset, (*hfsmp)->hfs_log_per_phys), phys_blksize, pvBuffer, phys_blksize, NULL, NULL);
674 if (retval)
675 {
676 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: raw_readwrite_read_mount (3) failed with %d\n", retval);
677 goto error_exit;
678 }
679
680 jvhp = (HFSPlusVolumeHeader *)(pvBuffer + HFS_PRI_OFFSET(phys_blksize));
681
682 if (SWAP_BE16(jvhp->signature) == kHFSPlusSigWord || SWAP_BE16(jvhp->signature) == kHFSXSigWord)
683 {
684 LFHFS_LOG(LEVEL_DEFAULT, "hfs_mountfs: Journal replay fail. Writing lastMountVersion as FSK!\n");
685
686 jvhp->lastMountedVersion = SWAP_BE32(kFSKMountVersion);
687 retval = raw_readwrite_write_mount( devvp, HFS_PHYSBLK_ROUNDDOWN(mdb_offset, (*hfsmp)->hfs_log_per_phys), phys_blksize, pvBuffer, phys_blksize, NULL, NULL );
688 if (retval)
689 {
690 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: raw_readwrite_write_mount (1) failed with %d\n", retval);
691 goto error_exit;
692 }
693 hfs_free(pvBuffer);
694 pvBuffer = NULL;
695 }
696
697 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: hfs_early_journal_init failed, erroring out \n");
698 retval = EINVAL;
699 goto error_exit;
700 }
701 }
702
703 retval = hfs_MountHFSPlusVolume(*hfsmp, *vhp, *embeddedOffset, disksize, bFailForDirty);
704 /*
705 * If the backend didn't like our physical blocksize
706 * then retry with physical blocksize of 512.
707 */
708 if ((retval == ENXIO) && (log_blksize > 512) && (log_blksize != minblksize))
709 {
710 // LF not support DKIOCSETBLOCKSIZE, return error.
711 LFHFS_LOG(LEVEL_DEFAULT, "hfs_mountfs: could not use physical block size (%d).\n", log_blksize);
712 goto error_exit;
713 }
714 else if ( retval )
715 {
716 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: hfs_MountHFSPlusVolume encountered failure %d \n", retval);
717 goto error_exit;
718 }
719
720 return (retval);
721
722 error_exit:
723 if (pvBuffer)
724 hfs_free(pvBuffer);
725
726 hfs_free(mdbp);
727
728 if (*hfsmp)
729 {
730 hfs_locks_destroy(*hfsmp);
731 hfs_delete_chash(*hfsmp);
732 hfs_idhash_destroy (*hfsmp);
733
734 hfs_free(*hfsmp);
735 *hfsmp = NULL;
736 }
737 return (retval);
738 }
739
740
741 int hfs_ScanVolGetVolName(int iFd, char* pcVolumeName)
742 {
743 int retval = 0;
744
745 HFSPlusVolumeHeader *vhp;
746 off_t embeddedOffset;
747 struct hfsmount *hfsmp;
748 struct mount* psMount = hfs_mallocz(sizeof(struct mount));
749 struct vnode* psDevVnode = hfs_mallocz(sizeof(struct vnode));
750 struct cnode* psDevCnode = hfs_mallocz(sizeof(struct cnode));
751 struct filefork* psDevFileFork = hfs_mallocz(sizeof(struct filefork));
752 FileSystemRecord_s *psFSRecord = hfs_mallocz(sizeof(FileSystemRecord_s));
753
754 if ( psMount == NULL || psDevVnode == NULL || psDevCnode == NULL || psDevFileFork == NULL || psFSRecord == NULL )
755 {
756 retval = ENOMEM;
757 LFHFS_LOG(LEVEL_ERROR, "hfs_ScanVolGetVolName: failed to malloc initial system files\n");
758 goto exit;
759 }
760
761 psFSRecord->iFD = iFd;
762 psDevVnode->psFSRecord = psFSRecord;
763 psDevVnode->sFSParams.vnfs_marksystem = 1;
764 psDevVnode->bIsMountVnode = true;
765
766 // Initializing inputs for hfs_mount
767 psDevFileFork->ff_data.cf_blocks = 3;
768 psDevFileFork->ff_data.cf_extents[0].blockCount = 1;
769 psDevFileFork->ff_data.cf_extents[0].startBlock = 0;
770
771 psDevVnode->sFSParams.vnfs_fsnode = psDevCnode;
772 psDevCnode->c_vp = psDevVnode;
773 psDevVnode->is_rsrc = false;
774 psDevCnode->c_datafork = psDevFileFork;
775 psDevVnode->sFSParams.vnfs_mp = psMount;
776
777 retval = hfs_InitialMount(psDevVnode, psMount, 0, &vhp, &embeddedOffset, &hfsmp, false);
778
779 if (retval)
780 {
781 goto exit;
782 }
783 else
784 {
785 strlcpy(pcVolumeName, (char*) hfsmp->vcbVN, UVFS_SCANVOLS_VOLNAME_MAX);
786 }
787
788 if (vhp) free(vhp);
789 if (hfsmp)
790 {
791 if (hfsmp->jnl) {
792 journal_release(hfsmp->jnl);
793 hfsmp->jnl = NULL;
794 }
795
796 hfsUnmount(hfsmp);
797
798 hfs_locks_destroy(hfsmp);
799 hfs_delete_chash(hfsmp);
800 hfs_idhash_destroy (hfsmp);
801
802 hfs_free(hfsmp);
803 hfsmp = NULL;
804 }
805
806 exit:
807 if (retval) {
808 LFHFS_LOG(LEVEL_ERROR, "hfs_ScanVolGetVolName: failed with error %d, returning empty name and no error\n",retval);
809 pcVolumeName[0] = '\0';
810 }
811
812 if (psMount) free (psMount);
813 if (psDevVnode) free (psDevVnode);
814 if (psDevCnode) free (psDevCnode);
815 if (psDevFileFork) free (psDevFileFork);
816 if (psFSRecord) free (psFSRecord);
817
818 return 0;
819 }
820
821 /*
822 * Common code for mount and mountroot
823 */
824 static int
825 hfs_mountfs(struct vnode *devvp, struct mount *mp, struct hfs_mount_args *args)
826 {
827 int retval = 0;
828
829 HFSPlusVolumeHeader *vhp;
830 off_t embeddedOffset;
831 struct hfsmount *hfsmp;
832 retval = hfs_InitialMount(devvp, mp, args, &vhp, &embeddedOffset, &hfsmp, true);
833 if ( retval )
834 {
835 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: hfs_InitialMount encountered failure %d \n", retval);
836 //No need to go to error_exit, since everything got reset at the Initial Mount
837 return retval;
838 }
839
840 retval = hfs_CollectBtreeStats(hfsmp, vhp, embeddedOffset, args);
841 free(vhp);
842 vhp = NULL;
843 if ( retval )
844 {
845 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: hfs_CollectBtreeStats encountered failure %d \n", retval);
846 goto error_exit;
847 }
848
849 // save off a snapshot of the mtime from the previous mount
850 // (for matador).
851 hfsmp->hfs_last_mounted_mtime = hfsmp->hfs_mtime;
852
853 if ( retval )
854 {
855 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: encountered failure %d \n", retval);
856 goto error_exit;
857 }
858
859 LFHFS_LOG(LEVEL_DEFAULT, "hfs_mountfs: mounted %s on device %s\n", (hfsmp->vcbVN[0] ? (const char*) hfsmp->vcbVN : "unknown"), "unknown device");
860
861 hfs_flushvolumeheader(hfsmp, 0);
862
863 return (0);
864
865 error_exit:
866 if (vhp) free(vhp);
867
868 if (hfsmp)
869 {
870 hfsUnmount(hfsmp);
871
872 hfs_locks_destroy(hfsmp);
873 hfs_delete_chash(hfsmp);
874 hfs_idhash_destroy (hfsmp);
875
876 hfs_free(hfsmp);
877 hfsmp = NULL;
878 }
879 return (retval);
880 }
881
882 /*
883 * Destroy all locks, mutexes and spinlocks in hfsmp on unmount or failed mount
884 */
885 static void
886 hfs_locks_destroy(struct hfsmount *hfsmp)
887 {
888
889 lf_lck_mtx_destroy(&hfsmp->hfs_mutex);
890 lf_lck_mtx_destroy(&hfsmp->sync_mutex);
891 lf_lck_rw_destroy(&hfsmp->hfs_global_lock);
892 lf_lck_spin_destroy(&hfsmp->vcbFreeExtLock);
893
894 return;
895 }
896
897
898 /*
899 * Flush any dirty in-memory mount data to the on-disk
900 * volume header.
901 *
902 * Note: the on-disk volume signature is intentionally
903 * not flushed since the on-disk "H+" and "HX" signatures
904 * are always stored in-memory as "H+".
905 */
906 int
907 hfs_flushvolumeheader(struct hfsmount *hfsmp, hfs_flush_volume_header_options_t options)
908 {
909 int retval = 0;
910
911 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
912 bool critical = false;
913 daddr64_t avh_sector;
914 bool altflush = ISSET(options, HFS_FVH_WRITE_ALT);
915
916 void *pvVolHdrData = NULL;
917 GenericLFBuf *psVolHdrBuf = NULL;
918 void *pvVolHdr2Data = NULL;
919 GenericLFBuf *psVolHdr2Buf = NULL;
920 void *pvAltHdrData = NULL;
921 GenericLFBuf *psAltHdrBuf = NULL;
922
923
924 if (ISSET(options, HFS_FVH_FLUSH_IF_DIRTY) && !hfs_header_needs_flushing(hfsmp)) {
925 return 0;
926 }
927
928 if (hfsmp->hfs_flags & HFS_READ_ONLY) {
929 return 0;
930 }
931
932 if (options & HFS_FVH_MARK_UNMOUNT) {
933 HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask;
934 } else {
935 HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
936 }
937
938 daddr64_t priIDSector = (daddr64_t)((vcb->hfsPlusIOPosOffset / hfsmp->hfs_logical_block_size) + HFS_PRI_SECTOR(hfsmp->hfs_logical_block_size));
939
940 if (!(options & HFS_FVH_SKIP_TRANSACTION)) {
941 if (hfs_start_transaction(hfsmp) != 0) {
942 return EINVAL;
943 }
944 }
945
946 psVolHdrBuf = lf_hfs_generic_buf_allocate(hfsmp->hfs_devvp,
947 HFS_PHYSBLK_ROUNDDOWN(priIDSector, hfsmp->hfs_log_per_phys),
948 hfsmp->hfs_physical_block_size, GEN_BUF_PHY_BLOCK);
949 if (psVolHdrBuf == NULL) {
950 retval = ENOMEM;
951 goto err_exit;
952 }
953 pvVolHdrData = psVolHdrBuf->pvData;
954
955 retval = lf_hfs_generic_buf_read(psVolHdrBuf);
956 if (retval) {
957 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d reading VH blk (vol=%s)\n", retval, vcb->vcbVN);
958 goto err_exit;
959 }
960
961 HFSPlusVolumeHeader* volumeHeader = (HFSPlusVolumeHeader *)(pvVolHdrData + HFS_PRI_OFFSET(hfsmp->hfs_physical_block_size));
962
963 /*
964 * Sanity check what we just read. If it's bad, try the alternate instead.
965 */
966 u_int16_t signature = SWAP_BE16 (volumeHeader->signature);
967 u_int16_t hfsversion = SWAP_BE16 (volumeHeader->version);
968
969 if ((signature != kHFSPlusSigWord && signature != kHFSXSigWord) ||
970 (hfsversion < kHFSPlusVersion) || (hfsversion > 100) ||
971 (SWAP_BE32 (volumeHeader->blockSize) != vcb->blockSize))
972 {
973 LFHFS_LOG(LEVEL_DEFAULT, "hfs_flushvolumeheader: corrupt VH on %s, sig 0x%04x, ver %d, blksize %d\n", vcb->vcbVN, signature, hfsversion, SWAP_BE32 (volumeHeader->blockSize));
974 hfs_mark_inconsistent(hfsmp, HFS_INCONSISTENCY_DETECTED);
975
976 /* Almost always we read AVH relative to the partition size */
977 avh_sector = hfsmp->hfs_partition_avh_sector;
978
979 if (hfsmp->hfs_partition_avh_sector != hfsmp->hfs_fs_avh_sector)
980 {
981 /*
982 * The two altVH offsets do not match --- which means that a smaller file
983 * system exists in a larger partition. Verify that we have the correct
984 * alternate volume header sector as per the current parititon size.
985 * The GPT device that we are mounted on top could have changed sizes
986 * without us knowing.
987 *
988 * We're in a transaction, so it's safe to modify the partition_avh_sector
989 * field if necessary.
990 */
991
992 uint64_t sector_count = 0;
993
994 /* Get underlying device block count */
995 retval = ioctl(hfsmp->hfs_devvp->psFSRecord->iFD, DKIOCGETBLOCKCOUNT, &sector_count);
996 if (retval)
997 {
998 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d getting block count (%s) \n", retval, vcb->vcbVN);
999 retval = ENXIO;
1000 goto err_exit;
1001 }
1002
1003 /* Partition size was changed without our knowledge */
1004 if (sector_count != (uint64_t)hfsmp->hfs_logical_block_count)
1005 {
1006 hfsmp->hfs_partition_avh_sector = (hfsmp->hfsPlusIOPosOffset / hfsmp->hfs_logical_block_size) + HFS_ALT_SECTOR(hfsmp->hfs_logical_block_size, sector_count);
1007 /* Note: hfs_fs_avh_sector will remain unchanged */
1008 LFHFS_LOG(LEVEL_DEFAULT, "hfs_flushvolumeheader: partition size changed, partition_avh_sector=%qu, fs_avh_sector=%qu\n", hfsmp->hfs_partition_avh_sector, hfsmp->hfs_fs_avh_sector);
1009
1010 /*
1011 * We just updated the offset for AVH relative to
1012 * the partition size, so the content of that AVH
1013 * will be invalid. But since we are also maintaining
1014 * a valid AVH relative to the file system size, we
1015 * can read it since primary VH and partition AVH
1016 * are not valid.
1017 */
1018 avh_sector = hfsmp->hfs_fs_avh_sector;
1019 }
1020 }
1021
1022 LFHFS_LOG(LEVEL_DEFAULT, "hfs_flushvolumeheader: trying alternate (for %s) avh_sector=%qu\n", (avh_sector == hfsmp->hfs_fs_avh_sector) ? "file system" : "partition", avh_sector);
1023
1024 if (avh_sector)
1025 {
1026 psAltHdrBuf = lf_hfs_generic_buf_allocate(hfsmp->hfs_devvp,
1027 HFS_PHYSBLK_ROUNDDOWN(avh_sector, hfsmp->hfs_log_per_phys),
1028 hfsmp->hfs_physical_block_size, GEN_BUF_PHY_BLOCK);
1029 if (psAltHdrBuf == NULL) {
1030 retval = ENOMEM;
1031 goto err_exit;
1032 }
1033 pvAltHdrData = psAltHdrBuf->pvData;
1034
1035 retval = lf_hfs_generic_buf_read(psAltHdrBuf);
1036
1037 if (retval)
1038 {
1039 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d reading alternate VH blk (vol=%s)\n", retval, vcb->vcbVN);
1040 goto err_exit;
1041 }
1042
1043 HFSPlusVolumeHeader * altVH = (HFSPlusVolumeHeader *)(pvAltHdrData + HFS_ALT_OFFSET(hfsmp->hfs_physical_block_size));
1044 signature = SWAP_BE16(altVH->signature);
1045 hfsversion = SWAP_BE16(altVH->version);
1046
1047 if ((signature != kHFSPlusSigWord && signature != kHFSXSigWord) ||
1048 (hfsversion < kHFSPlusVersion) || (kHFSPlusVersion > 100) ||
1049 (SWAP_BE32(altVH->blockSize) != vcb->blockSize))
1050 {
1051 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: corrupt alternate VH on %s, sig 0x%04x, ver %d, blksize %d\n", vcb->vcbVN, signature, hfsversion, SWAP_BE32(altVH->blockSize));
1052 retval = EIO;
1053 goto err_exit;
1054 }
1055
1056 /* The alternate is plausible, so use it. */
1057 bcopy(altVH, volumeHeader, kMDBSize);
1058 lf_hfs_generic_buf_release(psAltHdrBuf);
1059 pvAltHdrData = NULL;
1060 }
1061 else
1062 {
1063 /* No alternate VH, nothing more we can do. */
1064 retval = EIO;
1065 goto err_exit;
1066 }
1067 }
1068
1069 if (hfsmp->jnl)
1070 {
1071 journal_modify_block_start(hfsmp->jnl, psVolHdrBuf);
1072 }
1073
1074 /*
1075 * For embedded HFS+ volumes, update create date if it changed
1076 * (ie from a setattrlist call)
1077 */
1078 if ((vcb->hfsPlusIOPosOffset != 0) && (SWAP_BE32 (volumeHeader->createDate) != vcb->localCreateDate))
1079 {
1080 HFSMasterDirectoryBlock *mdb;
1081
1082 psVolHdr2Buf = lf_hfs_generic_buf_allocate(hfsmp->hfs_devvp,
1083 HFS_PHYSBLK_ROUNDDOWN(HFS_PRI_SECTOR(hfsmp->hfs_logical_block_size), hfsmp->hfs_log_per_phys),
1084 hfsmp->hfs_physical_block_size, GEN_BUF_PHY_BLOCK);
1085 if (psVolHdr2Buf == NULL) {
1086 retval = ENOMEM;
1087 goto err_exit;
1088 }
1089 void *pvVolHdr2Data = psVolHdr2Buf->pvData;
1090
1091 retval = lf_hfs_generic_buf_read(psVolHdr2Buf);
1092
1093 if (retval)
1094 {
1095 lf_hfs_generic_buf_release(psVolHdr2Buf);
1096 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d reading alternate VH blk (vol=%s)\n", retval, vcb->vcbVN);
1097 goto err_exit;
1098 }
1099
1100 mdb = (HFSMasterDirectoryBlock *)(pvVolHdr2Data + HFS_PRI_OFFSET(hfsmp->hfs_physical_block_size));
1101
1102 if ( SWAP_BE32 (mdb->drCrDate) != vcb->localCreateDate )
1103 {
1104 if (hfsmp->jnl)
1105 {
1106 journal_modify_block_start(hfsmp->jnl, psVolHdr2Buf);
1107 }
1108 mdb->drCrDate = SWAP_BE32 (vcb->localCreateDate); /* pick up the new create date */
1109 if (hfsmp->jnl)
1110 {
1111 journal_modify_block_end(hfsmp->jnl, psVolHdr2Buf, NULL, NULL);
1112 }
1113 else
1114 {
1115 retval = raw_readwrite_write_mount( hfsmp->hfs_devvp, HFS_PHYSBLK_ROUNDDOWN(HFS_PRI_SECTOR(hfsmp->hfs_logical_block_size), hfsmp->hfs_log_per_phys), hfsmp->hfs_physical_block_size, pvVolHdr2Data, hfsmp->hfs_physical_block_size, NULL, NULL);
1116
1117 lf_hfs_generic_buf_release(psVolHdr2Buf);
1118 pvVolHdr2Data = NULL;
1119 if (retval)
1120 {
1121 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d writing VH blk (vol=%s)\n", retval, vcb->vcbVN);
1122 goto err_exit;
1123 }
1124 }
1125 }
1126 else
1127 {
1128 lf_hfs_generic_buf_release(psVolHdr2Buf); /* just release it */
1129 pvVolHdr2Data = NULL;
1130 }
1131 }
1132
1133 hfs_lock_mount (hfsmp);
1134
1135 /* Note: only update the lower 16 bits worth of attributes */
1136 volumeHeader->attributes = SWAP_BE32 (vcb->vcbAtrb);
1137 volumeHeader->journalInfoBlock = SWAP_BE32 (vcb->vcbJinfoBlock);
1138 if (hfsmp->jnl)
1139 {
1140 volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSJMountVersion);
1141 }
1142 else
1143 {
1144 volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSPlusMountVersion);
1145 }
1146 volumeHeader->createDate = SWAP_BE32 (vcb->localCreateDate); /* volume create date is in local time */
1147 volumeHeader->modifyDate = SWAP_BE32 (to_hfs_time(vcb->vcbLsMod));
1148 volumeHeader->backupDate = SWAP_BE32 (to_hfs_time(vcb->vcbVolBkUp));
1149 volumeHeader->fileCount = SWAP_BE32 (vcb->vcbFilCnt);
1150 volumeHeader->folderCount = SWAP_BE32 (vcb->vcbDirCnt);
1151 volumeHeader->totalBlocks = SWAP_BE32 (vcb->totalBlocks);
1152 volumeHeader->freeBlocks = SWAP_BE32 (vcb->freeBlocks + vcb->reclaimBlocks);
1153 volumeHeader->nextAllocation = SWAP_BE32 (vcb->nextAllocation);
1154 volumeHeader->rsrcClumpSize = SWAP_BE32 (vcb->vcbClpSiz);
1155 volumeHeader->dataClumpSize = SWAP_BE32 (vcb->vcbClpSiz);
1156 volumeHeader->nextCatalogID = SWAP_BE32 (vcb->vcbNxtCNID);
1157 volumeHeader->writeCount = SWAP_BE32 (vcb->vcbWrCnt);
1158 volumeHeader->encodingsBitmap = SWAP_BE64 (vcb->encodingsBitmap);
1159
1160 if (bcmp(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo)) != 0)
1161 {
1162 bcopy(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo));
1163 critical = true;
1164 }
1165
1166 if (!altflush && !ISSET(options, HFS_FVH_FLUSH_IF_DIRTY))
1167 {
1168 goto done;
1169 }
1170
1171 /* Sync Extents over-flow file meta data */
1172 struct filefork * fp = VTOF(vcb->extentsRefNum);
1173 if (FTOC(fp)->c_flag & C_MODIFIED)
1174 {
1175 for (int iExtentCounter = 0; iExtentCounter < kHFSPlusExtentDensity; iExtentCounter++)
1176 {
1177 volumeHeader->extentsFile.extents[iExtentCounter].startBlock = SWAP_BE32 (fp->ff_extents[iExtentCounter].startBlock);
1178 volumeHeader->extentsFile.extents[iExtentCounter].blockCount = SWAP_BE32 (fp->ff_extents[iExtentCounter].blockCount);
1179 }
1180 volumeHeader->extentsFile.logicalSize = SWAP_BE64 (fp->ff_size);
1181 volumeHeader->extentsFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
1182 volumeHeader->extentsFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
1183 FTOC(fp)->c_flag &= ~C_MODIFIED;
1184 altflush = true;
1185 }
1186
1187 /* Sync Catalog file meta data */
1188 fp = VTOF(vcb->catalogRefNum);
1189 if (FTOC(fp)->c_flag & C_MODIFIED)
1190 {
1191 for (int iExtentCounter = 0; iExtentCounter < kHFSPlusExtentDensity; iExtentCounter++)
1192 {
1193 volumeHeader->catalogFile.extents[iExtentCounter].startBlock = SWAP_BE32 (fp->ff_extents[iExtentCounter].startBlock);
1194 volumeHeader->catalogFile.extents[iExtentCounter].blockCount = SWAP_BE32 (fp->ff_extents[iExtentCounter].blockCount);
1195 }
1196 volumeHeader->catalogFile.logicalSize = SWAP_BE64 (fp->ff_size);
1197 volumeHeader->catalogFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
1198 volumeHeader->catalogFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
1199 FTOC(fp)->c_flag &= ~C_MODIFIED;
1200 altflush = true;
1201 }
1202
1203 /* Sync Allocation file meta data */
1204 fp = VTOF(vcb->allocationsRefNum);
1205 if (FTOC(fp)->c_flag & C_MODIFIED)
1206 {
1207 for (int iExtentCounter = 0; iExtentCounter < kHFSPlusExtentDensity; iExtentCounter++)
1208 {
1209 volumeHeader->allocationFile.extents[iExtentCounter].startBlock = SWAP_BE32 (fp->ff_extents[iExtentCounter].startBlock);
1210 volumeHeader->allocationFile.extents[iExtentCounter].blockCount = SWAP_BE32 (fp->ff_extents[iExtentCounter].blockCount);
1211 }
1212 volumeHeader->allocationFile.logicalSize = SWAP_BE64 (fp->ff_size);
1213 volumeHeader->allocationFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
1214 volumeHeader->allocationFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
1215 FTOC(fp)->c_flag &= ~C_MODIFIED;
1216 altflush = true;
1217 }
1218
1219 /* Sync Attribute file meta data */
1220 if (hfsmp->hfs_attribute_vp)
1221 {
1222 fp = VTOF(hfsmp->hfs_attribute_vp);
1223 for (int iExtentCounter = 0; iExtentCounter < kHFSPlusExtentDensity; iExtentCounter++)
1224 {
1225 volumeHeader->attributesFile.extents[iExtentCounter].startBlock = SWAP_BE32 (fp->ff_extents[iExtentCounter].startBlock);
1226 volumeHeader->attributesFile.extents[iExtentCounter].blockCount = SWAP_BE32 (fp->ff_extents[iExtentCounter].blockCount);
1227 }
1228 if (ISSET(FTOC(fp)->c_flag, C_MODIFIED))
1229 {
1230 FTOC(fp)->c_flag &= ~C_MODIFIED;
1231 altflush = true;
1232 }
1233 volumeHeader->attributesFile.logicalSize = SWAP_BE64 (fp->ff_size);
1234 volumeHeader->attributesFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
1235 volumeHeader->attributesFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
1236 }
1237
1238 /* Sync Startup file meta data */
1239 if (hfsmp->hfs_startup_vp)
1240 {
1241 fp = VTOF(hfsmp->hfs_startup_vp);
1242 if (FTOC(fp)->c_flag & C_MODIFIED)
1243 {
1244 for (int iExtentCounter = 0; iExtentCounter < kHFSPlusExtentDensity; iExtentCounter++)
1245 {
1246 volumeHeader->startupFile.extents[iExtentCounter].startBlock = SWAP_BE32 (fp->ff_extents[iExtentCounter].startBlock);
1247 volumeHeader->startupFile.extents[iExtentCounter].blockCount = SWAP_BE32 (fp->ff_extents[iExtentCounter].blockCount);
1248 }
1249 volumeHeader->startupFile.logicalSize = SWAP_BE64 (fp->ff_size);
1250 volumeHeader->startupFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
1251 volumeHeader->startupFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
1252 FTOC(fp)->c_flag &= ~C_MODIFIED;
1253 altflush = true;
1254 }
1255 }
1256
1257 if (altflush)
1258 critical = true;
1259
1260 done:
1261 MarkVCBClean(hfsmp);
1262 hfs_unlock_mount (hfsmp);
1263
1264 /* If requested, flush out the alternate volume header */
1265 if (altflush) {
1266 /*
1267 * The two altVH offsets do not match --- which means that a smaller file
1268 * system exists in a larger partition. Verify that we have the correct
1269 * alternate volume header sector as per the current parititon size.
1270 * The GPT device that we are mounted on top could have changed sizes
1271 * without us knowning.
1272 *
1273 * We're in a transaction, so it's safe to modify the partition_avh_sector
1274 * field if necessary.
1275 */
1276 if (hfsmp->hfs_partition_avh_sector != hfsmp->hfs_fs_avh_sector)
1277 {
1278 uint64_t sector_count;
1279
1280 /* Get underlying device block count */
1281 retval = ioctl(hfsmp->hfs_devvp->psFSRecord->iFD, DKIOCGETBLOCKCOUNT, &sector_count);
1282 if (retval)
1283 {
1284 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d getting block count (%s) \n", retval, vcb->vcbVN);
1285 retval = ENXIO;
1286 goto err_exit;
1287 }
1288
1289 /* Partition size was changed without our knowledge */
1290 if (sector_count != (uint64_t)hfsmp->hfs_logical_block_count)
1291 {
1292 hfsmp->hfs_partition_avh_sector = (hfsmp->hfsPlusIOPosOffset / hfsmp->hfs_logical_block_size) + HFS_ALT_SECTOR(hfsmp->hfs_logical_block_size, sector_count);
1293 /* Note: hfs_fs_avh_sector will remain unchanged */
1294 LFHFS_LOG(LEVEL_DEFAULT, "hfs_flushvolumeheader: altflush: partition size changed, partition_avh_sector=%qu, fs_avh_sector=%qu\n",
1295 hfsmp->hfs_partition_avh_sector, hfsmp->hfs_fs_avh_sector);
1296 }
1297 }
1298
1299 /*
1300 * First see if we need to write I/O to the "secondary" AVH
1301 * located at FS Size - 1024 bytes, because this one will
1302 * always go into the journal. We put this AVH into the journal
1303 * because even if the filesystem size has shrunk, this LBA should be
1304 * reachable after the partition-size modification has occurred.
1305 * The one where we need to be careful is partitionsize-1024, since the
1306 * partition size should hopefully shrink.
1307 *
1308 * Most of the time this block will not execute.
1309 */
1310 if ((hfsmp->hfs_fs_avh_sector) && (hfsmp->hfs_partition_avh_sector != hfsmp->hfs_fs_avh_sector))
1311 {
1312 if (pvAltHdrData != NULL)
1313 {
1314 panic("We shouldn't be here!");
1315 hfs_assert(0);
1316 }
1317
1318 psAltHdrBuf = lf_hfs_generic_buf_allocate(hfsmp->hfs_devvp,
1319 HFS_PHYSBLK_ROUNDDOWN(hfsmp->hfs_fs_avh_sector, hfsmp->hfs_log_per_phys),
1320 hfsmp->hfs_physical_block_size, GEN_BUF_PHY_BLOCK);
1321
1322 if (psAltHdrBuf == NULL) {
1323 retval = ENOMEM;
1324 goto err_exit;
1325 }
1326 pvAltHdrData = psAltHdrBuf->pvData;
1327
1328 retval = lf_hfs_generic_buf_read(psAltHdrBuf);
1329 if (retval)
1330 {
1331 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d reading alternate VH blk (vol=%s)\n", retval, vcb->vcbVN);
1332 goto err_exit;
1333 }
1334
1335 if (hfsmp->jnl)
1336 {
1337 journal_modify_block_start(hfsmp->jnl, psAltHdrBuf);
1338 }
1339
1340 bcopy(volumeHeader, pvAltHdrData + HFS_ALT_OFFSET(hfsmp->hfs_physical_block_size), kMDBSize);
1341
1342 if (hfsmp->jnl)
1343 {
1344 journal_modify_block_end(hfsmp->jnl, psAltHdrBuf, NULL, NULL);
1345 }
1346 else
1347 {
1348 retval = raw_readwrite_write_mount( hfsmp->hfs_devvp, HFS_PHYSBLK_ROUNDDOWN(hfsmp->hfs_fs_avh_sector, hfsmp->hfs_log_per_phys), hfsmp->hfs_physical_block_size, pvAltHdrData, hfsmp->hfs_physical_block_size, NULL, NULL);
1349 if (retval)
1350 {
1351 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d writing VH blk (vol=%s)\n", retval, vcb->vcbVN);
1352 goto err_exit;
1353 }
1354 lf_hfs_generic_buf_release(psAltHdrBuf);
1355 pvAltHdrData = NULL;
1356 }
1357 }
1358
1359 /*
1360 * Flush out alternate volume header located at 1024 bytes before
1361 * end of the partition as part of journal transaction. In
1362 * most cases, this will be the only alternate volume header
1363 * that we need to worry about because the file system size is
1364 * same as the partition size, therefore hfs_fs_avh_sector is
1365 * same as hfs_partition_avh_sector. This is the "priority" AVH.
1366 *
1367 * However, do not always put this I/O into the journal. If we skipped the
1368 * FS-Size AVH write above, then we will put this I/O into the journal as
1369 * that indicates the two were in sync. However, if the FS size is
1370 * not the same as the partition size, we are tracking two. We don't
1371 * put it in the journal in that case, since if the partition
1372 * size changes between uptimes, and we need to replay the journal,
1373 * this I/O could generate an EIO if during replay it is now trying
1374 * to access blocks beyond the device EOF.
1375 */
1376 if (hfsmp->hfs_partition_avh_sector)
1377 {
1378 if (pvAltHdrData != NULL)
1379 {
1380 panic("We shouldn't be here!");
1381 hfs_assert(0);
1382 }
1383
1384 psAltHdrBuf = lf_hfs_generic_buf_allocate(hfsmp->hfs_devvp,
1385 HFS_PHYSBLK_ROUNDDOWN(hfsmp->hfs_fs_avh_sector, hfsmp->hfs_log_per_phys),
1386 hfsmp->hfs_physical_block_size, GEN_BUF_PHY_BLOCK);
1387 if (psAltHdrBuf == NULL) {
1388 retval = ENOMEM;
1389 goto err_exit;
1390 }
1391 pvAltHdrData = psAltHdrBuf->pvData;
1392
1393 retval = lf_hfs_generic_buf_read(psAltHdrBuf);
1394
1395 if (retval)
1396 {
1397 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d reading alternate VH blk (vol=%s)\n", retval, vcb->vcbVN);
1398 goto err_exit;
1399 }
1400
1401 /* only one AVH, put this I/O in the journal. */
1402 if ((hfsmp->jnl) && (hfsmp->hfs_partition_avh_sector == hfsmp->hfs_fs_avh_sector)) {
1403 journal_modify_block_start(hfsmp->jnl, psAltHdrBuf);
1404 }
1405
1406 bcopy(volumeHeader, pvAltHdrData + HFS_ALT_OFFSET(hfsmp->hfs_physical_block_size), kMDBSize);
1407
1408 /* If journaled and we only have one AVH to track */
1409 if ((hfsmp->jnl) && (hfsmp->hfs_partition_avh_sector == hfsmp->hfs_fs_avh_sector)) {
1410 journal_modify_block_end (hfsmp->jnl, psAltHdrBuf, NULL, NULL);
1411 }
1412 else
1413 {
1414 /*
1415 * If we don't have a journal or there are two AVH's at the
1416 * moment, then this one doesn't go in the journal. Note that
1417 * this one may generate I/O errors, since the partition
1418 * can be resized behind our backs at any moment and this I/O
1419 * may now appear to be beyond the device EOF.
1420 */
1421 retval = raw_readwrite_write_mount( hfsmp->hfs_devvp, HFS_PHYSBLK_ROUNDDOWN(hfsmp->hfs_fs_avh_sector, hfsmp->hfs_log_per_phys), hfsmp->hfs_physical_block_size, pvAltHdrData, hfsmp->hfs_physical_block_size, NULL, NULL);
1422 if (retval)
1423 {
1424 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d writing VH blk (vol=%s)\n", retval, vcb->vcbVN);
1425 goto err_exit;
1426 }
1427 lf_hfs_generic_buf_release(psAltHdrBuf);
1428 pvAltHdrData = NULL;
1429 hfs_flush(hfsmp, HFS_FLUSH_CACHE);
1430 }
1431 }
1432 }
1433
1434 /* Finish modifying the block for the primary VH */
1435 if (hfsmp->jnl) {
1436 journal_modify_block_end(hfsmp->jnl, psVolHdrBuf, NULL, NULL);
1437 }
1438 else
1439 {
1440 retval = raw_readwrite_write_mount( hfsmp->hfs_devvp, HFS_PHYSBLK_ROUNDDOWN(priIDSector, hfsmp->hfs_log_per_phys), hfsmp->hfs_physical_block_size, pvVolHdrData, hfsmp->hfs_physical_block_size, NULL, NULL);
1441 /* When critical data changes, flush the device cache */
1442 if (critical && (retval == 0))
1443 {
1444 hfs_flush(hfsmp, HFS_FLUSH_CACHE);
1445 }
1446
1447 lf_hfs_generic_buf_release(psVolHdrBuf);
1448 pvVolHdrData = NULL;
1449 if (retval)
1450 {
1451 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d reading VH blk (vol=%s)\n", retval, vcb->vcbVN);
1452 goto err_exit;
1453 }
1454 }
1455 if (!(options & HFS_FVH_SKIP_TRANSACTION)) {
1456 hfs_end_transaction(hfsmp);
1457 }
1458
1459 return (retval);
1460
1461 err_exit:
1462 if (pvVolHdrData)
1463 lf_hfs_generic_buf_release(psVolHdrBuf);
1464 if (pvVolHdr2Data)
1465 lf_hfs_generic_buf_release(psVolHdr2Buf);
1466 if (pvAltHdrData)
1467 lf_hfs_generic_buf_release(psAltHdrBuf);
1468
1469 if (!(options & HFS_FVH_SKIP_TRANSACTION)) {
1470 hfs_end_transaction(hfsmp);
1471 }
1472 return retval;
1473 }
1474
1475 /* If a runtime corruption is detected, set the volume inconsistent
1476 * bit in the volume attributes. The volume inconsistent bit is a persistent
1477 * bit which represents that the volume is corrupt and needs repair.
1478 * The volume inconsistent bit can be set from the kernel when it detects
1479 * runtime corruption or from file system repair utilities like fsck_hfs when
1480 * a repair operation fails. The bit should be cleared only from file system
1481 * verify/repair utility like fsck_hfs when a verify/repair succeeds.
1482 */
1483 void hfs_mark_inconsistent(struct hfsmount *hfsmp, hfs_inconsistency_reason_t reason)
1484 {
1485 hfs_lock_mount (hfsmp);
1486 if ((hfsmp->vcbAtrb & kHFSVolumeInconsistentMask) == 0)
1487 {
1488 hfsmp->vcbAtrb |= kHFSVolumeInconsistentMask;
1489 MarkVCBDirty(hfsmp);
1490 }
1491 if ((hfsmp->hfs_flags & HFS_READ_ONLY)==0)
1492 {
1493 switch (reason)
1494 {
1495 case HFS_INCONSISTENCY_DETECTED:
1496 LFHFS_LOG(LEVEL_ERROR, "hfs_mark_inconsistent: Runtime corruption detected on %s, fsck will be forced on next mount.\n",hfsmp->vcbVN);
1497 break;
1498 case HFS_ROLLBACK_FAILED:
1499 LFHFS_LOG(LEVEL_ERROR, "hfs_mark_inconsistent: Failed to roll back; volume `%s' might be inconsistent; fsck will be forced on next mount.\n", hfsmp->vcbVN);
1500 break;
1501 case HFS_OP_INCOMPLETE:
1502 LFHFS_LOG(LEVEL_ERROR, "hfs_mark_inconsistent: Failed to complete operation; volume `%s' might be inconsistent; fsck will be forced on next mount.\n",hfsmp->vcbVN);
1503 break;
1504 case HFS_FSCK_FORCED:
1505 LFHFS_LOG(LEVEL_ERROR, "hfs_mark_inconsistent: fsck requested for `%s'; fsck will be forced on next mount.\n",hfsmp->vcbVN);
1506 break;
1507 }
1508 }
1509 hfs_unlock_mount (hfsmp);
1510 }
1511
1512 /*
1513 * Creates a UUID from a unique "name" in the HFS UUID Name space.
1514 * See version 3 UUID.
1515 */
1516 void
1517 hfs_getvoluuid(struct hfsmount *hfsmp, uuid_t result_uuid)
1518 {
1519
1520 if (uuid_is_null(hfsmp->hfs_full_uuid)) {
1521 uuid_t result;
1522
1523 CC_MD5_CTX md5c;
1524 uint8_t rawUUID[8];
1525
1526 ((uint32_t *)rawUUID)[0] = hfsmp->vcbFndrInfo[6];
1527 ((uint32_t *)rawUUID)[1] = hfsmp->vcbFndrInfo[7];
1528
1529 CC_MD5_Init( &md5c );
1530 CC_MD5_Update( &md5c, HFS_UUID_NAMESPACE_ID, sizeof( uuid_t ) );
1531 CC_MD5_Update( &md5c, rawUUID, sizeof (rawUUID) );
1532 CC_MD5_Final( result, &md5c );
1533
1534 result[6] = 0x30 | ( result[6] & 0x0F );
1535 result[8] = 0x80 | ( result[8] & 0x3F );
1536
1537 uuid_copy(hfsmp->hfs_full_uuid, result);
1538 }
1539 uuid_copy (result_uuid, hfsmp->hfs_full_uuid);
1540
1541 }
1542
1543 /*
1544 * Call into the allocator code and perform a full scan of the bitmap file.
1545 *
1546 * This allows us to TRIM unallocated ranges if needed, and also to build up
1547 * an in-memory summary table of the state of the allocated blocks.
1548 */
1549 void hfs_scan_blocks (struct hfsmount *hfsmp)
1550 {
1551 /*
1552 * Take the allocation file lock. Journal transactions will block until
1553 * we're done here.
1554 */
1555 int flags = hfs_systemfile_lock(hfsmp, SFL_BITMAP, HFS_EXCLUSIVE_LOCK);
1556
1557 /*
1558 * We serialize here with the HFS mount lock as we're mounting.
1559 *
1560 * The mount can only proceed once this thread has acquired the bitmap
1561 * lock, since we absolutely do not want someone else racing in and
1562 * getting the bitmap lock, doing a read/write of the bitmap file,
1563 * then us getting the bitmap lock.
1564 *
1565 * To prevent this, the mount thread takes the HFS mount mutex, starts us
1566 * up, then immediately msleeps on the scan_var variable in the mount
1567 * point as a condition variable. This serialization is safe since
1568 * if we race in and try to proceed while they're still holding the lock,
1569 * we'll block trying to acquire the global lock. Since the mount thread
1570 * acquires the HFS mutex before starting this function in a new thread,
1571 * any lock acquisition on our part must be linearizably AFTER the mount thread's.
1572 *
1573 * Note that the HFS mount mutex is always taken last, and always for only
1574 * a short time. In this case, we just take it long enough to mark the
1575 * scan-in-flight bit.
1576 */
1577 (void) hfs_lock_mount (hfsmp);
1578 hfsmp->scan_var |= HFS_ALLOCATOR_SCAN_INFLIGHT;
1579 hfs_unlock_mount (hfsmp);
1580
1581 /* Initialize the summary table */
1582 if (hfs_init_summary (hfsmp))
1583 {
1584 LFHFS_LOG(LEVEL_DEBUG, "hfs_scan_blocks: could not initialize summary table for %s\n", hfsmp->vcbVN);
1585 }
1586
1587 /*
1588 * ScanUnmapBlocks assumes that the bitmap lock is held when you
1589 * call the function. We don't care if there were any errors issuing unmaps.
1590 *
1591 * It will also attempt to build up the summary table for subsequent
1592 * allocator use, as configured.
1593 */
1594 (void) ScanUnmapBlocks(hfsmp);
1595
1596 (void) hfs_lock_mount (hfsmp);
1597 hfsmp->scan_var &= ~HFS_ALLOCATOR_SCAN_INFLIGHT;
1598 hfsmp->scan_var |= HFS_ALLOCATOR_SCAN_COMPLETED;
1599 hfs_unlock_mount (hfsmp);
1600
1601 hfs_systemfile_unlock(hfsmp, flags);
1602 }
1603
1604 int
1605 hfs_GetInfoByID(struct hfsmount *hfsmp, cnid_t cnid, UVFSFileAttributes *file_attrs, char pcName[MAX_UTF8_NAME_LENGTH])
1606 {
1607 u_int32_t linkref = 0;
1608 struct vnode *psVnode = NULL;
1609 struct cat_desc cndesc;
1610 struct cat_attr cnattr;
1611 struct cat_fork cnfork;
1612 int error = 0;
1613
1614 /* Check for cnids that should't be exported. */
1615 if ((cnid < kHFSFirstUserCatalogNodeID) &&
1616 (cnid != kHFSRootFolderID && cnid != kHFSRootParentID)) {
1617 return (ENOENT);
1618 }
1619 /* Don't export our private directories. */
1620 if (cnid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid ||
1621 cnid == hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid) {
1622 return (ENOENT);
1623 }
1624 /*
1625 * Check the hash first
1626 */
1627 psVnode = hfs_chash_getvnode(hfsmp, cnid, 0, 0, 0);
1628 if (psVnode) {
1629 goto getAttrAndDone;
1630 }
1631
1632 bzero(&cndesc, sizeof(cndesc));
1633 bzero(&cnattr, sizeof(cnattr));
1634 bzero(&cnfork, sizeof(cnfork));
1635
1636 /*
1637 * Not in hash, lookup in catalog
1638 */
1639 if (cnid == kHFSRootParentID) {
1640 static char hfs_rootname[] = "/";
1641
1642 cndesc.cd_nameptr = (const u_int8_t *)&hfs_rootname[0];
1643 cndesc.cd_namelen = 1;
1644 cndesc.cd_parentcnid = kHFSRootParentID;
1645 cndesc.cd_cnid = kHFSRootFolderID;
1646 cndesc.cd_flags = CD_ISDIR;
1647
1648 cnattr.ca_fileid = kHFSRootFolderID;
1649 cnattr.ca_linkcount = 1;
1650 cnattr.ca_entries = 1;
1651 cnattr.ca_dircount = 1;
1652 cnattr.ca_mode = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
1653 } else {
1654 int lockflags;
1655 cnid_t pid;
1656 const char *nameptr;
1657
1658 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
1659 error = cat_idlookup(hfsmp, cnid, 0, 0, &cndesc, &cnattr, &cnfork);
1660 hfs_systemfile_unlock(hfsmp, lockflags);
1661
1662 if (error) {
1663 return (error);
1664 }
1665
1666 /*
1667 * Check for a raw hardlink inode and save its linkref.
1668 */
1669 pid = cndesc.cd_parentcnid;
1670 nameptr = (const char *)cndesc.cd_nameptr;
1671 if ((pid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid) &&
1672 cndesc.cd_namelen > HFS_INODE_PREFIX_LEN &&
1673 (bcmp(nameptr, HFS_INODE_PREFIX, HFS_INODE_PREFIX_LEN) == 0)) {
1674 linkref = (uint32_t) strtoul(&nameptr[HFS_INODE_PREFIX_LEN], NULL, 10);
1675
1676 } else if ((pid == hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid) &&
1677 cndesc.cd_namelen > HFS_DIRINODE_PREFIX_LEN &&
1678 (bcmp(nameptr, HFS_DIRINODE_PREFIX, HFS_DIRINODE_PREFIX_LEN) == 0)) {
1679 linkref = (uint32_t) strtoul(&nameptr[HFS_DIRINODE_PREFIX_LEN], NULL, 10);
1680
1681 } else if ((pid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid) &&
1682 cndesc.cd_namelen > HFS_DELETE_PREFIX_LEN &&
1683 (bcmp(nameptr, HFS_DELETE_PREFIX, HFS_DELETE_PREFIX_LEN) == 0)) {
1684 cat_releasedesc(&cndesc);
1685 return (ENOENT); /* open unlinked file */
1686 }
1687 }
1688
1689 /*
1690 * Finish initializing cnode descriptor for hardlinks.
1691 *
1692 * We need a valid name and parent for reverse lookups.
1693 */
1694 if (linkref) {
1695 cnid_t lastid;
1696 struct cat_desc linkdesc;
1697 int linkerr = 0;
1698
1699 cnattr.ca_linkref = linkref;
1700 bzero (&linkdesc, sizeof (linkdesc));
1701
1702 /*
1703 * If the caller supplied the raw inode value, then we don't know exactly
1704 * which hardlink they wanted. It's likely that they acquired the raw inode
1705 * value BEFORE the item became a hardlink, in which case, they probably
1706 * want the oldest link. So request the oldest link from the catalog.
1707 *
1708 * Unfortunately, this requires that we iterate through all N hardlinks. On the plus
1709 * side, since we know that we want the last linkID, we can also have this one
1710 * call give us back the name of the last ID, since it's going to have it in-hand...
1711 */
1712 linkerr = hfs_lookup_lastlink (hfsmp, linkref, &lastid, &linkdesc);
1713 if ((linkerr == 0) && (lastid != 0)) {
1714 /*
1715 * Release any lingering buffers attached to our local descriptor.
1716 * Then copy the name and other business into the cndesc
1717 */
1718 cat_releasedesc (&cndesc);
1719 bcopy (&linkdesc, &cndesc, sizeof(linkdesc));
1720 }
1721 /* If it failed, the linkref code will just use whatever it had in-hand below. */
1722
1723 int newvnode_flags = 0;
1724 error = hfs_getnewvnode(hfsmp, NULL, NULL, &cndesc, 0, &cnattr, &cnfork, &psVnode, &newvnode_flags);
1725 if (error == 0) {
1726 VTOC(psVnode)->c_flag |= C_HARDLINK;
1727 }
1728 }
1729 else
1730 {
1731 int newvnode_flags = 0;
1732
1733 void *buf = hfs_malloc(MAX_UTF8_NAME_LENGTH);
1734 if (buf == NULL) {
1735 return (ENOMEM);
1736 }
1737
1738 /* Supply hfs_getnewvnode with a component name. */
1739 struct componentname cn = {
1740 .cn_nameiop = LOOKUP,
1741 .cn_flags = ISLASTCN,
1742 .cn_pnlen = MAXPATHLEN,
1743 .cn_namelen = cndesc.cd_namelen,
1744 .cn_pnbuf = buf,
1745 .cn_nameptr = buf
1746 };
1747
1748 bcopy(cndesc.cd_nameptr, cn.cn_nameptr, cndesc.cd_namelen + 1);
1749 error = hfs_getnewvnode(hfsmp, NULL, &cn, &cndesc, 0, &cnattr, &cnfork, &psVnode, &newvnode_flags);
1750 if (error == 0 && (VTOC(psVnode)->c_flag & C_HARDLINK)) {
1751 hfs_savelinkorigin(VTOC(psVnode), cndesc.cd_parentcnid);
1752 }
1753
1754 hfs_free(buf);
1755 }
1756 cat_releasedesc(&cndesc);
1757
1758 getAttrAndDone:
1759 if (!error) vnode_GetAttrInternal (psVnode, file_attrs);
1760 if (psVnode != NULL) hfs_unlock(VTOC(psVnode));
1761
1762 if (error || psVnode == NULL || psVnode->sFSParams.vnfs_cnp->cn_nameptr == NULL){
1763 hfs_vnop_reclaim(psVnode);
1764 return EFAULT;
1765 }
1766
1767 if (cnid == kHFSRootFolderID)
1768 pcName[0] = 0;
1769 else {
1770 strlcpy(pcName, (char*) psVnode->sFSParams.vnfs_cnp->cn_nameptr, MAX_UTF8_NAME_LENGTH);
1771 }
1772
1773 error = hfs_vnop_reclaim(psVnode);
1774
1775 return (error);
1776 }
1777
1778 /*
1779 * Look up an HFS object by ID.
1780 *
1781 * The object is returned with an iocount reference and the cnode locked.
1782 *
1783 * If the object is a file then it will represent the data fork.
1784 */
1785 int
1786 hfs_vget(struct hfsmount *hfsmp, cnid_t cnid, struct vnode **vpp, int skiplock, int allow_deleted)
1787 {
1788 struct vnode *vp = NULL;
1789 struct cat_desc cndesc;
1790 struct cat_attr cnattr;
1791 struct cat_fork cnfork;
1792
1793 u_int32_t linkref = 0;
1794
1795 int error;
1796
1797 /* Check for cnids that should't be exported. */
1798 if ((cnid < kHFSFirstUserCatalogNodeID) &&
1799 (cnid != kHFSRootFolderID && cnid != kHFSRootParentID)) {
1800 return (ENOENT);
1801 }
1802 /* Don't export our private directories. */
1803 if (cnid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid ||
1804 cnid == hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid) {
1805 return (ENOENT);
1806 }
1807 /*
1808 * Check the hash first
1809 */
1810 vp = hfs_chash_getvnode(hfsmp, cnid, 0, skiplock, allow_deleted);
1811 if (vp) {
1812 *vpp = vp;
1813 return(0);
1814 }
1815
1816 bzero(&cndesc, sizeof(cndesc));
1817 bzero(&cnattr, sizeof(cnattr));
1818 bzero(&cnfork, sizeof(cnfork));
1819
1820 /*
1821 * Not in hash, lookup in catalog
1822 */
1823 if (cnid == kHFSRootParentID) {
1824 static char hfs_rootname[] = "/";
1825
1826 cndesc.cd_nameptr = (const u_int8_t *)&hfs_rootname[0];
1827 cndesc.cd_namelen = 1;
1828 cndesc.cd_parentcnid = kHFSRootParentID;
1829 cndesc.cd_cnid = kHFSRootFolderID;
1830 cndesc.cd_flags = CD_ISDIR;
1831
1832 cnattr.ca_fileid = kHFSRootFolderID;
1833 cnattr.ca_linkcount = 1;
1834 cnattr.ca_entries = 1;
1835 cnattr.ca_dircount = 1;
1836 cnattr.ca_mode = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
1837 } else {
1838 int lockflags;
1839 cnid_t pid;
1840 const char *nameptr;
1841
1842 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
1843 error = cat_idlookup(hfsmp, cnid, 0, 0, &cndesc, &cnattr, &cnfork);
1844 hfs_systemfile_unlock(hfsmp, lockflags);
1845
1846 if (error) {
1847 *vpp = NULL;
1848 return (error);
1849 }
1850
1851 /*
1852 * Check for a raw hardlink inode and save its linkref.
1853 */
1854 pid = cndesc.cd_parentcnid;
1855 nameptr = (const char *)cndesc.cd_nameptr;
1856 if ((pid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid) &&
1857 cndesc.cd_namelen > HFS_INODE_PREFIX_LEN &&
1858 (bcmp(nameptr, HFS_INODE_PREFIX, HFS_INODE_PREFIX_LEN) == 0)) {
1859 linkref = (uint32_t) strtoul(&nameptr[HFS_INODE_PREFIX_LEN], NULL, 10);
1860
1861 } else if ((pid == hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid) &&
1862 cndesc.cd_namelen > HFS_DIRINODE_PREFIX_LEN &&
1863 (bcmp(nameptr, HFS_DIRINODE_PREFIX, HFS_DIRINODE_PREFIX_LEN) == 0)) {
1864 linkref = (uint32_t) strtoul(&nameptr[HFS_DIRINODE_PREFIX_LEN], NULL, 10);
1865
1866 } else if ((pid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid) &&
1867 cndesc.cd_namelen > HFS_DELETE_PREFIX_LEN &&
1868 (bcmp(nameptr, HFS_DELETE_PREFIX, HFS_DELETE_PREFIX_LEN) == 0)) {
1869 *vpp = NULL;
1870 cat_releasedesc(&cndesc);
1871 return (ENOENT); /* open unlinked file */
1872 }
1873 }
1874
1875 /*
1876 * Finish initializing cnode descriptor for hardlinks.
1877 *
1878 * We need a valid name and parent for reverse lookups.
1879 */
1880 if (linkref) {
1881 cnid_t lastid;
1882 struct cat_desc linkdesc;
1883 int linkerr = 0;
1884
1885 cnattr.ca_linkref = linkref;
1886 bzero (&linkdesc, sizeof (linkdesc));
1887
1888 /*
1889 * If the caller supplied the raw inode value, then we don't know exactly
1890 * which hardlink they wanted. It's likely that they acquired the raw inode
1891 * value BEFORE the item became a hardlink, in which case, they probably
1892 * want the oldest link. So request the oldest link from the catalog.
1893 *
1894 * Unfortunately, this requires that we iterate through all N hardlinks. On the plus
1895 * side, since we know that we want the last linkID, we can also have this one
1896 * call give us back the name of the last ID, since it's going to have it in-hand...
1897 */
1898 linkerr = hfs_lookup_lastlink (hfsmp, linkref, &lastid, &linkdesc);
1899 if ((linkerr == 0) && (lastid != 0)) {
1900 /*
1901 * Release any lingering buffers attached to our local descriptor.
1902 * Then copy the name and other business into the cndesc
1903 */
1904 cat_releasedesc (&cndesc);
1905 bcopy (&linkdesc, &cndesc, sizeof(linkdesc));
1906 }
1907 /* If it failed, the linkref code will just use whatever it had in-hand below. */
1908 }
1909
1910 if (linkref) {
1911 int newvnode_flags = 0;
1912 error = hfs_getnewvnode(hfsmp, NULL, NULL, &cndesc, 0, &cnattr, &cnfork, &vp, &newvnode_flags);
1913 if (error == 0) {
1914 VTOC(vp)->c_flag |= C_HARDLINK;
1915
1916 //TBD - this set is for vfs -> since we have the C_HARDLINK
1917 // currently disable this set.
1918 //vnode_setmultipath(vp);
1919 }
1920 }
1921 else
1922 {
1923 int newvnode_flags = 0;
1924
1925 void *buf = hfs_malloc(MAXPATHLEN);
1926
1927 /* Supply hfs_getnewvnode with a component name. */
1928 struct componentname cn = {
1929 .cn_nameiop = LOOKUP,
1930 .cn_flags = ISLASTCN,
1931 .cn_pnlen = MAXPATHLEN,
1932 .cn_namelen = cndesc.cd_namelen,
1933 .cn_pnbuf = buf,
1934 .cn_nameptr = buf
1935 };
1936
1937 bcopy(cndesc.cd_nameptr, cn.cn_nameptr, cndesc.cd_namelen + 1);
1938 error = hfs_getnewvnode(hfsmp, NULL, &cn, &cndesc, 0, &cnattr, &cnfork, &vp, &newvnode_flags);
1939
1940 if (error == 0 && (VTOC(vp)->c_flag & C_HARDLINK)) {
1941 hfs_savelinkorigin(VTOC(vp), cndesc.cd_parentcnid);
1942 }
1943
1944 hfs_free(buf);
1945 }
1946 cat_releasedesc(&cndesc);
1947
1948 *vpp = vp;
1949 if (vp && skiplock) {
1950 hfs_unlock(VTOC(vp));
1951 }
1952 return (error);
1953 }
1954
1955 /*
1956 * Return the root of a filesystem.
1957 */
1958 int hfs_vfs_root(struct mount *mp, struct vnode **vpp)
1959 {
1960 return hfs_vget(VFSTOHFS(mp), (cnid_t)kHFSRootFolderID, vpp, 1, 0);
1961 }
1962
1963 /*
1964 * unmount system call
1965 */
1966 int hfs_unmount(struct mount *mp)
1967 {
1968 struct hfsmount *hfsmp = VFSTOHFS(mp);
1969 int retval = E_NONE;
1970
1971 if (hfsmp->hfs_flags & HFS_SUMMARY_TABLE)
1972 {
1973 if (hfsmp->hfs_summary_table)
1974 {
1975 int err = 0;
1976 /*
1977 * Take the bitmap lock to serialize against a concurrent bitmap scan still in progress
1978 */
1979 if (hfsmp->hfs_allocation_vp)
1980 {
1981 err = hfs_lock (VTOC(hfsmp->hfs_allocation_vp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT);
1982 }
1983 hfs_free(hfsmp->hfs_summary_table);
1984 hfsmp->hfs_summary_table = NULL;
1985 hfsmp->hfs_flags &= ~HFS_SUMMARY_TABLE;
1986
1987 if (err == 0 && hfsmp->hfs_allocation_vp)
1988 {
1989 hfs_unlock (VTOC(hfsmp->hfs_allocation_vp));
1990 }
1991 }
1992 }
1993
1994 /*
1995 * Invalidate our caches and release metadata vnodes
1996 */
1997 if (hfsmp->jnl) {
1998 journal_release(hfsmp->jnl);
1999 hfsmp->jnl = NULL;
2000 }
2001
2002 hfsUnmount(hfsmp);
2003 int iFD = hfsmp->hfs_devvp->psFSRecord->iFD;
2004 // Remove Buffer cache entries realted to the mount
2005 lf_hfs_generic_buf_cache_clear_by_iFD(iFD);
2006
2007 vnode_rele(hfsmp->hfs_devvp);
2008
2009 hfs_locks_destroy(hfsmp);
2010 hfs_delete_chash(hfsmp);
2011 hfs_idhash_destroy(hfsmp);
2012
2013 hfs_assert(TAILQ_EMPTY(&hfsmp->hfs_reserved_ranges[HFS_TENTATIVE_BLOCKS]) && TAILQ_EMPTY(&hfsmp->hfs_reserved_ranges[HFS_LOCKED_BLOCKS]));
2014 hfs_assert(!hfsmp->lockedBlocks);
2015
2016 hfs_free(hfsmp);
2017
2018 return (retval);
2019 }
2020 /* Update volume encoding bitmap (HFS Plus only)
2021 *
2022 * Mark a legacy text encoding as in-use (as needed)
2023 * in the volume header of this HFS+ filesystem.
2024 */
2025 void
2026 hfs_setencodingbits(struct hfsmount *hfsmp, u_int32_t encoding)
2027 {
2028 #define kIndexMacUkrainian 48 /* MacUkrainian encoding is 152 */
2029 #define kIndexMacFarsi 49 /* MacFarsi encoding is 140 */
2030
2031 u_int32_t index;
2032
2033 switch (encoding)
2034 {
2035 case kTextEncodingMacUkrainian:
2036 index = kIndexMacUkrainian;
2037 break;
2038 case kTextEncodingMacFarsi:
2039 index = kIndexMacFarsi;
2040 break;
2041 default:
2042 index = encoding;
2043 break;
2044 }
2045
2046 /* Only mark the encoding as in-use if it wasn't already set */
2047 if (index < 64 && (hfsmp->encodingsBitmap & (u_int64_t)(1ULL << index)) == 0) {
2048 hfs_lock_mount (hfsmp);
2049 hfsmp->encodingsBitmap |= (u_int64_t)(1ULL << index);
2050 MarkVCBDirty(hfsmp);
2051 hfs_unlock_mount(hfsmp);
2052 }
2053 }
2054
2055 /*
2056 * Update volume stats
2057 *
2058 * On journal volumes this will cause a volume header flush
2059 */
2060 int
2061 hfs_volupdate(struct hfsmount *hfsmp, enum volop op, int inroot)
2062 {
2063 struct timeval tv;
2064 microtime(&tv);
2065 hfs_lock_mount (hfsmp);
2066
2067 MarkVCBDirty(hfsmp);
2068 hfsmp->hfs_mtime = tv.tv_sec;
2069
2070 switch (op) {
2071 case VOL_UPDATE:
2072 break;
2073 case VOL_MKDIR:
2074 if (hfsmp->hfs_dircount != 0xFFFFFFFF)
2075 ++hfsmp->hfs_dircount;
2076 if (inroot && hfsmp->vcbNmRtDirs != 0xFFFF)
2077 ++hfsmp->vcbNmRtDirs;
2078 break;
2079 case VOL_RMDIR:
2080 if (hfsmp->hfs_dircount != 0)
2081 --hfsmp->hfs_dircount;
2082 if (inroot && hfsmp->vcbNmRtDirs != 0xFFFF)
2083 --hfsmp->vcbNmRtDirs;
2084 break;
2085 case VOL_MKFILE:
2086 if (hfsmp->hfs_filecount != 0xFFFFFFFF)
2087 ++hfsmp->hfs_filecount;
2088 if (inroot && hfsmp->vcbNmFls != 0xFFFF)
2089 ++hfsmp->vcbNmFls;
2090 break;
2091 case VOL_RMFILE:
2092 if (hfsmp->hfs_filecount != 0)
2093 --hfsmp->hfs_filecount;
2094 if (inroot && hfsmp->vcbNmFls != 0xFFFF)
2095 --hfsmp->vcbNmFls;
2096 break;
2097 }
2098
2099 hfs_unlock_mount (hfsmp);
2100 hfs_flushvolumeheader(hfsmp, 0);
2101
2102 return (0);
2103 }
2104