]> git.saurik.com Git - apple/hfs.git/blob - livefiles_hfs_plugin/lf_hfs_vfsops.c
hfs-522.0.9.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 if ( retval )
843 {
844 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: hfs_CollectBtreeStats encountered failure %d \n", retval);
845 goto error_exit;
846 }
847
848 // save off a snapshot of the mtime from the previous mount
849 // (for matador).
850 hfsmp->hfs_last_mounted_mtime = hfsmp->hfs_mtime;
851
852 if ( retval )
853 {
854 LFHFS_LOG(LEVEL_DEBUG, "hfs_mountfs: encountered failure %d \n", retval);
855 goto error_exit;
856 }
857
858 LFHFS_LOG(LEVEL_DEFAULT, "hfs_mountfs: mounted %s on device %s\n", (hfsmp->vcbVN[0] ? (const char*) hfsmp->vcbVN : "unknown"), "unknown device");
859
860 hfs_flushvolumeheader(hfsmp, 0);
861
862 return (0);
863
864 error_exit:
865 if (vhp) free(vhp);
866
867 if (hfsmp)
868 {
869 hfsUnmount(hfsmp);
870
871 hfs_locks_destroy(hfsmp);
872 hfs_delete_chash(hfsmp);
873 hfs_idhash_destroy (hfsmp);
874
875 hfs_free(hfsmp);
876 hfsmp = NULL;
877 }
878 return (retval);
879 }
880
881 /*
882 * Destroy all locks, mutexes and spinlocks in hfsmp on unmount or failed mount
883 */
884 static void
885 hfs_locks_destroy(struct hfsmount *hfsmp)
886 {
887
888 lf_lck_mtx_destroy(&hfsmp->hfs_mutex);
889 lf_lck_mtx_destroy(&hfsmp->sync_mutex);
890 lf_lck_rw_destroy(&hfsmp->hfs_global_lock);
891 lf_lck_spin_destroy(&hfsmp->vcbFreeExtLock);
892
893 return;
894 }
895
896
897 /*
898 * Flush any dirty in-memory mount data to the on-disk
899 * volume header.
900 *
901 * Note: the on-disk volume signature is intentionally
902 * not flushed since the on-disk "H+" and "HX" signatures
903 * are always stored in-memory as "H+".
904 */
905 int
906 hfs_flushvolumeheader(struct hfsmount *hfsmp, hfs_flush_volume_header_options_t options)
907 {
908 int retval = 0;
909
910 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
911 bool critical = false;
912 daddr64_t avh_sector;
913 bool altflush = ISSET(options, HFS_FVH_WRITE_ALT);
914
915 void *pvVolHdrData = NULL;
916 GenericLFBuf *psVolHdrBuf = NULL;
917 void *pvVolHdr2Data = NULL;
918 GenericLFBuf *psVolHdr2Buf = NULL;
919 void *pvAltHdrData = NULL;
920 GenericLFBuf *psAltHdrBuf = NULL;
921
922
923 if (ISSET(options, HFS_FVH_FLUSH_IF_DIRTY) && !hfs_header_needs_flushing(hfsmp)) {
924 return 0;
925 }
926
927 if (hfsmp->hfs_flags & HFS_READ_ONLY) {
928 return 0;
929 }
930
931 if (options & HFS_FVH_MARK_UNMOUNT) {
932 HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask;
933 } else {
934 HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
935 }
936
937 daddr64_t priIDSector = (daddr64_t)((vcb->hfsPlusIOPosOffset / hfsmp->hfs_logical_block_size) + HFS_PRI_SECTOR(hfsmp->hfs_logical_block_size));
938
939 if (!(options & HFS_FVH_SKIP_TRANSACTION)) {
940 if (hfs_start_transaction(hfsmp) != 0) {
941 return EINVAL;
942 }
943 }
944
945 psVolHdrBuf = lf_hfs_generic_buf_allocate(hfsmp->hfs_devvp,
946 HFS_PHYSBLK_ROUNDDOWN(priIDSector, hfsmp->hfs_log_per_phys),
947 hfsmp->hfs_physical_block_size, GEN_BUF_PHY_BLOCK);
948 if (psVolHdrBuf == NULL) {
949 retval = ENOMEM;
950 goto err_exit;
951 }
952 pvVolHdrData = psVolHdrBuf->pvData;
953
954 retval = lf_hfs_generic_buf_read(psVolHdrBuf);
955 if (retval) {
956 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d reading VH blk (vol=%s)\n", retval, vcb->vcbVN);
957 goto err_exit;
958 }
959
960 HFSPlusVolumeHeader* volumeHeader = (HFSPlusVolumeHeader *)(pvVolHdrData + HFS_PRI_OFFSET(hfsmp->hfs_physical_block_size));
961
962 /*
963 * Sanity check what we just read. If it's bad, try the alternate instead.
964 */
965 u_int16_t signature = SWAP_BE16 (volumeHeader->signature);
966 u_int16_t hfsversion = SWAP_BE16 (volumeHeader->version);
967
968 if ((signature != kHFSPlusSigWord && signature != kHFSXSigWord) ||
969 (hfsversion < kHFSPlusVersion) || (hfsversion > 100) ||
970 (SWAP_BE32 (volumeHeader->blockSize) != vcb->blockSize))
971 {
972 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));
973 hfs_mark_inconsistent(hfsmp, HFS_INCONSISTENCY_DETECTED);
974
975 /* Almost always we read AVH relative to the partition size */
976 avh_sector = hfsmp->hfs_partition_avh_sector;
977
978 if (hfsmp->hfs_partition_avh_sector != hfsmp->hfs_fs_avh_sector)
979 {
980 /*
981 * The two altVH offsets do not match --- which means that a smaller file
982 * system exists in a larger partition. Verify that we have the correct
983 * alternate volume header sector as per the current parititon size.
984 * The GPT device that we are mounted on top could have changed sizes
985 * without us knowing.
986 *
987 * We're in a transaction, so it's safe to modify the partition_avh_sector
988 * field if necessary.
989 */
990
991 uint64_t sector_count = 0;
992
993 /* Get underlying device block count */
994 retval = ioctl(hfsmp->hfs_devvp->psFSRecord->iFD, DKIOCGETBLOCKCOUNT, &sector_count);
995 if (retval)
996 {
997 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d getting block count (%s) \n", retval, vcb->vcbVN);
998 retval = ENXIO;
999 goto err_exit;
1000 }
1001
1002 /* Partition size was changed without our knowledge */
1003 if (sector_count != (uint64_t)hfsmp->hfs_logical_block_count)
1004 {
1005 hfsmp->hfs_partition_avh_sector = (hfsmp->hfsPlusIOPosOffset / hfsmp->hfs_logical_block_size) + HFS_ALT_SECTOR(hfsmp->hfs_logical_block_size, sector_count);
1006 /* Note: hfs_fs_avh_sector will remain unchanged */
1007 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);
1008
1009 /*
1010 * We just updated the offset for AVH relative to
1011 * the partition size, so the content of that AVH
1012 * will be invalid. But since we are also maintaining
1013 * a valid AVH relative to the file system size, we
1014 * can read it since primary VH and partition AVH
1015 * are not valid.
1016 */
1017 avh_sector = hfsmp->hfs_fs_avh_sector;
1018 }
1019 }
1020
1021 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);
1022
1023 if (avh_sector)
1024 {
1025 psAltHdrBuf = lf_hfs_generic_buf_allocate(hfsmp->hfs_devvp,
1026 HFS_PHYSBLK_ROUNDDOWN(avh_sector, hfsmp->hfs_log_per_phys),
1027 hfsmp->hfs_physical_block_size, GEN_BUF_PHY_BLOCK);
1028 if (psAltHdrBuf == NULL) {
1029 retval = ENOMEM;
1030 goto err_exit;
1031 }
1032 pvAltHdrData = psAltHdrBuf->pvData;
1033
1034 retval = lf_hfs_generic_buf_read(psAltHdrBuf);
1035
1036 if (retval)
1037 {
1038 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d reading alternate VH blk (vol=%s)\n", retval, vcb->vcbVN);
1039 goto err_exit;
1040 }
1041
1042 HFSPlusVolumeHeader * altVH = (HFSPlusVolumeHeader *)(pvAltHdrData + HFS_ALT_OFFSET(hfsmp->hfs_physical_block_size));
1043 signature = SWAP_BE16(altVH->signature);
1044 hfsversion = SWAP_BE16(altVH->version);
1045
1046 if ((signature != kHFSPlusSigWord && signature != kHFSXSigWord) ||
1047 (hfsversion < kHFSPlusVersion) || (kHFSPlusVersion > 100) ||
1048 (SWAP_BE32(altVH->blockSize) != vcb->blockSize))
1049 {
1050 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));
1051 retval = EIO;
1052 goto err_exit;
1053 }
1054
1055 /* The alternate is plausible, so use it. */
1056 bcopy(altVH, volumeHeader, kMDBSize);
1057 lf_hfs_generic_buf_release(psAltHdrBuf);
1058 pvAltHdrData = NULL;
1059 }
1060 else
1061 {
1062 /* No alternate VH, nothing more we can do. */
1063 retval = EIO;
1064 goto err_exit;
1065 }
1066 }
1067
1068 if (hfsmp->jnl)
1069 {
1070 journal_modify_block_start(hfsmp->jnl, psVolHdrBuf);
1071 }
1072
1073 /*
1074 * For embedded HFS+ volumes, update create date if it changed
1075 * (ie from a setattrlist call)
1076 */
1077 if ((vcb->hfsPlusIOPosOffset != 0) && (SWAP_BE32 (volumeHeader->createDate) != vcb->localCreateDate))
1078 {
1079 HFSMasterDirectoryBlock *mdb;
1080
1081 psVolHdr2Buf = lf_hfs_generic_buf_allocate(hfsmp->hfs_devvp,
1082 HFS_PHYSBLK_ROUNDDOWN(HFS_PRI_SECTOR(hfsmp->hfs_logical_block_size), hfsmp->hfs_log_per_phys),
1083 hfsmp->hfs_physical_block_size, GEN_BUF_PHY_BLOCK);
1084 if (psVolHdr2Buf == NULL) {
1085 retval = ENOMEM;
1086 goto err_exit;
1087 }
1088 void *pvVolHdr2Data = psVolHdr2Buf->pvData;
1089
1090 retval = lf_hfs_generic_buf_read(psVolHdr2Buf);
1091
1092 if (retval)
1093 {
1094 lf_hfs_generic_buf_release(psVolHdr2Buf);
1095 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d reading alternate VH blk (vol=%s)\n", retval, vcb->vcbVN);
1096 goto err_exit;
1097 }
1098
1099 mdb = (HFSMasterDirectoryBlock *)(pvVolHdr2Data + HFS_PRI_OFFSET(hfsmp->hfs_physical_block_size));
1100
1101 if ( SWAP_BE32 (mdb->drCrDate) != vcb->localCreateDate )
1102 {
1103 if (hfsmp->jnl)
1104 {
1105 journal_modify_block_start(hfsmp->jnl, psVolHdr2Buf);
1106 }
1107 mdb->drCrDate = SWAP_BE32 (vcb->localCreateDate); /* pick up the new create date */
1108 if (hfsmp->jnl)
1109 {
1110 journal_modify_block_end(hfsmp->jnl, psVolHdr2Buf, NULL, NULL);
1111 }
1112 else
1113 {
1114 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);
1115
1116 lf_hfs_generic_buf_release(psVolHdr2Buf);
1117 pvVolHdr2Data = NULL;
1118 if (retval)
1119 {
1120 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d writing VH blk (vol=%s)\n", retval, vcb->vcbVN);
1121 goto err_exit;
1122 }
1123 }
1124 }
1125 else
1126 {
1127 lf_hfs_generic_buf_release(psVolHdr2Buf); /* just release it */
1128 pvVolHdr2Data = NULL;
1129 }
1130 }
1131
1132 hfs_lock_mount (hfsmp);
1133
1134 /* Note: only update the lower 16 bits worth of attributes */
1135 volumeHeader->attributes = SWAP_BE32 (vcb->vcbAtrb);
1136 volumeHeader->journalInfoBlock = SWAP_BE32 (vcb->vcbJinfoBlock);
1137 if (hfsmp->jnl)
1138 {
1139 volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSJMountVersion);
1140 }
1141 else
1142 {
1143 volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSPlusMountVersion);
1144 }
1145 volumeHeader->createDate = SWAP_BE32 (vcb->localCreateDate); /* volume create date is in local time */
1146 volumeHeader->modifyDate = SWAP_BE32 (to_hfs_time(vcb->vcbLsMod));
1147 volumeHeader->backupDate = SWAP_BE32 (to_hfs_time(vcb->vcbVolBkUp));
1148 volumeHeader->fileCount = SWAP_BE32 (vcb->vcbFilCnt);
1149 volumeHeader->folderCount = SWAP_BE32 (vcb->vcbDirCnt);
1150 volumeHeader->totalBlocks = SWAP_BE32 (vcb->totalBlocks);
1151 volumeHeader->freeBlocks = SWAP_BE32 (vcb->freeBlocks + vcb->reclaimBlocks);
1152 volumeHeader->nextAllocation = SWAP_BE32 (vcb->nextAllocation);
1153 volumeHeader->rsrcClumpSize = SWAP_BE32 (vcb->vcbClpSiz);
1154 volumeHeader->dataClumpSize = SWAP_BE32 (vcb->vcbClpSiz);
1155 volumeHeader->nextCatalogID = SWAP_BE32 (vcb->vcbNxtCNID);
1156 volumeHeader->writeCount = SWAP_BE32 (vcb->vcbWrCnt);
1157 volumeHeader->encodingsBitmap = SWAP_BE64 (vcb->encodingsBitmap);
1158
1159 if (bcmp(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo)) != 0)
1160 {
1161 bcopy(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo));
1162 critical = true;
1163 }
1164
1165 if (!altflush && !ISSET(options, HFS_FVH_FLUSH_IF_DIRTY))
1166 {
1167 goto done;
1168 }
1169
1170 /* Sync Extents over-flow file meta data */
1171 struct filefork * fp = VTOF(vcb->extentsRefNum);
1172 if (FTOC(fp)->c_flag & C_MODIFIED)
1173 {
1174 for (int iExtentCounter = 0; iExtentCounter < kHFSPlusExtentDensity; iExtentCounter++)
1175 {
1176 volumeHeader->extentsFile.extents[iExtentCounter].startBlock = SWAP_BE32 (fp->ff_extents[iExtentCounter].startBlock);
1177 volumeHeader->extentsFile.extents[iExtentCounter].blockCount = SWAP_BE32 (fp->ff_extents[iExtentCounter].blockCount);
1178 }
1179 volumeHeader->extentsFile.logicalSize = SWAP_BE64 (fp->ff_size);
1180 volumeHeader->extentsFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
1181 volumeHeader->extentsFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
1182 FTOC(fp)->c_flag &= ~C_MODIFIED;
1183 altflush = true;
1184 }
1185
1186 /* Sync Catalog file meta data */
1187 fp = VTOF(vcb->catalogRefNum);
1188 if (FTOC(fp)->c_flag & C_MODIFIED)
1189 {
1190 for (int iExtentCounter = 0; iExtentCounter < kHFSPlusExtentDensity; iExtentCounter++)
1191 {
1192 volumeHeader->catalogFile.extents[iExtentCounter].startBlock = SWAP_BE32 (fp->ff_extents[iExtentCounter].startBlock);
1193 volumeHeader->catalogFile.extents[iExtentCounter].blockCount = SWAP_BE32 (fp->ff_extents[iExtentCounter].blockCount);
1194 }
1195 volumeHeader->catalogFile.logicalSize = SWAP_BE64 (fp->ff_size);
1196 volumeHeader->catalogFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
1197 volumeHeader->catalogFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
1198 FTOC(fp)->c_flag &= ~C_MODIFIED;
1199 altflush = true;
1200 }
1201
1202 /* Sync Allocation file meta data */
1203 fp = VTOF(vcb->allocationsRefNum);
1204 if (FTOC(fp)->c_flag & C_MODIFIED)
1205 {
1206 for (int iExtentCounter = 0; iExtentCounter < kHFSPlusExtentDensity; iExtentCounter++)
1207 {
1208 volumeHeader->allocationFile.extents[iExtentCounter].startBlock = SWAP_BE32 (fp->ff_extents[iExtentCounter].startBlock);
1209 volumeHeader->allocationFile.extents[iExtentCounter].blockCount = SWAP_BE32 (fp->ff_extents[iExtentCounter].blockCount);
1210 }
1211 volumeHeader->allocationFile.logicalSize = SWAP_BE64 (fp->ff_size);
1212 volumeHeader->allocationFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
1213 volumeHeader->allocationFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
1214 FTOC(fp)->c_flag &= ~C_MODIFIED;
1215 altflush = true;
1216 }
1217
1218 /* Sync Attribute file meta data */
1219 if (hfsmp->hfs_attribute_vp)
1220 {
1221 fp = VTOF(hfsmp->hfs_attribute_vp);
1222 for (int iExtentCounter = 0; iExtentCounter < kHFSPlusExtentDensity; iExtentCounter++)
1223 {
1224 volumeHeader->attributesFile.extents[iExtentCounter].startBlock = SWAP_BE32 (fp->ff_extents[iExtentCounter].startBlock);
1225 volumeHeader->attributesFile.extents[iExtentCounter].blockCount = SWAP_BE32 (fp->ff_extents[iExtentCounter].blockCount);
1226 }
1227 if (ISSET(FTOC(fp)->c_flag, C_MODIFIED))
1228 {
1229 FTOC(fp)->c_flag &= ~C_MODIFIED;
1230 altflush = true;
1231 }
1232 volumeHeader->attributesFile.logicalSize = SWAP_BE64 (fp->ff_size);
1233 volumeHeader->attributesFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
1234 volumeHeader->attributesFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
1235 }
1236
1237 /* Sync Startup file meta data */
1238 if (hfsmp->hfs_startup_vp)
1239 {
1240 fp = VTOF(hfsmp->hfs_startup_vp);
1241 if (FTOC(fp)->c_flag & C_MODIFIED)
1242 {
1243 for (int iExtentCounter = 0; iExtentCounter < kHFSPlusExtentDensity; iExtentCounter++)
1244 {
1245 volumeHeader->startupFile.extents[iExtentCounter].startBlock = SWAP_BE32 (fp->ff_extents[iExtentCounter].startBlock);
1246 volumeHeader->startupFile.extents[iExtentCounter].blockCount = SWAP_BE32 (fp->ff_extents[iExtentCounter].blockCount);
1247 }
1248 volumeHeader->startupFile.logicalSize = SWAP_BE64 (fp->ff_size);
1249 volumeHeader->startupFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
1250 volumeHeader->startupFile.clumpSize = SWAP_BE32 (fp->ff_clumpsize);
1251 FTOC(fp)->c_flag &= ~C_MODIFIED;
1252 altflush = true;
1253 }
1254 }
1255
1256 if (altflush)
1257 critical = true;
1258
1259 done:
1260 MarkVCBClean(hfsmp);
1261 hfs_unlock_mount (hfsmp);
1262
1263 /* If requested, flush out the alternate volume header */
1264 if (altflush) {
1265 /*
1266 * The two altVH offsets do not match --- which means that a smaller file
1267 * system exists in a larger partition. Verify that we have the correct
1268 * alternate volume header sector as per the current parititon size.
1269 * The GPT device that we are mounted on top could have changed sizes
1270 * without us knowning.
1271 *
1272 * We're in a transaction, so it's safe to modify the partition_avh_sector
1273 * field if necessary.
1274 */
1275 if (hfsmp->hfs_partition_avh_sector != hfsmp->hfs_fs_avh_sector)
1276 {
1277 uint64_t sector_count;
1278
1279 /* Get underlying device block count */
1280 retval = ioctl(hfsmp->hfs_devvp->psFSRecord->iFD, DKIOCGETBLOCKCOUNT, &sector_count);
1281 if (retval)
1282 {
1283 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d getting block count (%s) \n", retval, vcb->vcbVN);
1284 retval = ENXIO;
1285 goto err_exit;
1286 }
1287
1288 /* Partition size was changed without our knowledge */
1289 if (sector_count != (uint64_t)hfsmp->hfs_logical_block_count)
1290 {
1291 hfsmp->hfs_partition_avh_sector = (hfsmp->hfsPlusIOPosOffset / hfsmp->hfs_logical_block_size) + HFS_ALT_SECTOR(hfsmp->hfs_logical_block_size, sector_count);
1292 /* Note: hfs_fs_avh_sector will remain unchanged */
1293 LFHFS_LOG(LEVEL_DEFAULT, "hfs_flushvolumeheader: altflush: partition size changed, partition_avh_sector=%qu, fs_avh_sector=%qu\n",
1294 hfsmp->hfs_partition_avh_sector, hfsmp->hfs_fs_avh_sector);
1295 }
1296 }
1297
1298 /*
1299 * First see if we need to write I/O to the "secondary" AVH
1300 * located at FS Size - 1024 bytes, because this one will
1301 * always go into the journal. We put this AVH into the journal
1302 * because even if the filesystem size has shrunk, this LBA should be
1303 * reachable after the partition-size modification has occurred.
1304 * The one where we need to be careful is partitionsize-1024, since the
1305 * partition size should hopefully shrink.
1306 *
1307 * Most of the time this block will not execute.
1308 */
1309 if ((hfsmp->hfs_fs_avh_sector) && (hfsmp->hfs_partition_avh_sector != hfsmp->hfs_fs_avh_sector))
1310 {
1311 if (pvAltHdrData != NULL)
1312 {
1313 panic("We shouldn't be here!");
1314 hfs_assert(0);
1315 }
1316
1317 psAltHdrBuf = lf_hfs_generic_buf_allocate(hfsmp->hfs_devvp,
1318 HFS_PHYSBLK_ROUNDDOWN(hfsmp->hfs_fs_avh_sector, hfsmp->hfs_log_per_phys),
1319 hfsmp->hfs_physical_block_size, GEN_BUF_PHY_BLOCK);
1320
1321 if (psAltHdrBuf == NULL) {
1322 retval = ENOMEM;
1323 goto err_exit;
1324 }
1325 pvAltHdrData = psAltHdrBuf->pvData;
1326
1327 retval = lf_hfs_generic_buf_read(psAltHdrBuf);
1328 if (retval)
1329 {
1330 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d reading alternate VH blk (vol=%s)\n", retval, vcb->vcbVN);
1331 goto err_exit;
1332 }
1333
1334 if (hfsmp->jnl)
1335 {
1336 journal_modify_block_start(hfsmp->jnl, psAltHdrBuf);
1337 }
1338
1339 bcopy(volumeHeader, pvAltHdrData + HFS_ALT_OFFSET(hfsmp->hfs_physical_block_size), kMDBSize);
1340
1341 if (hfsmp->jnl)
1342 {
1343 journal_modify_block_end(hfsmp->jnl, psAltHdrBuf, NULL, NULL);
1344 }
1345 else
1346 {
1347 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);
1348 if (retval)
1349 {
1350 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d writing VH blk (vol=%s)\n", retval, vcb->vcbVN);
1351 goto err_exit;
1352 }
1353 lf_hfs_generic_buf_release(psAltHdrBuf);
1354 pvAltHdrData = NULL;
1355 }
1356 }
1357
1358 /*
1359 * Flush out alternate volume header located at 1024 bytes before
1360 * end of the partition as part of journal transaction. In
1361 * most cases, this will be the only alternate volume header
1362 * that we need to worry about because the file system size is
1363 * same as the partition size, therefore hfs_fs_avh_sector is
1364 * same as hfs_partition_avh_sector. This is the "priority" AVH.
1365 *
1366 * However, do not always put this I/O into the journal. If we skipped the
1367 * FS-Size AVH write above, then we will put this I/O into the journal as
1368 * that indicates the two were in sync. However, if the FS size is
1369 * not the same as the partition size, we are tracking two. We don't
1370 * put it in the journal in that case, since if the partition
1371 * size changes between uptimes, and we need to replay the journal,
1372 * this I/O could generate an EIO if during replay it is now trying
1373 * to access blocks beyond the device EOF.
1374 */
1375 if (hfsmp->hfs_partition_avh_sector)
1376 {
1377 if (pvAltHdrData != NULL)
1378 {
1379 panic("We shouldn't be here!");
1380 hfs_assert(0);
1381 }
1382
1383 psAltHdrBuf = lf_hfs_generic_buf_allocate(hfsmp->hfs_devvp,
1384 HFS_PHYSBLK_ROUNDDOWN(hfsmp->hfs_fs_avh_sector, hfsmp->hfs_log_per_phys),
1385 hfsmp->hfs_physical_block_size, GEN_BUF_PHY_BLOCK);
1386 if (psAltHdrBuf == NULL) {
1387 retval = ENOMEM;
1388 goto err_exit;
1389 }
1390 pvAltHdrData = psAltHdrBuf->pvData;
1391
1392 retval = lf_hfs_generic_buf_read(psAltHdrBuf);
1393
1394 if (retval)
1395 {
1396 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d reading alternate VH blk (vol=%s)\n", retval, vcb->vcbVN);
1397 goto err_exit;
1398 }
1399
1400 /* only one AVH, put this I/O in the journal. */
1401 if ((hfsmp->jnl) && (hfsmp->hfs_partition_avh_sector == hfsmp->hfs_fs_avh_sector)) {
1402 journal_modify_block_start(hfsmp->jnl, psAltHdrBuf);
1403 }
1404
1405 bcopy(volumeHeader, pvAltHdrData + HFS_ALT_OFFSET(hfsmp->hfs_physical_block_size), kMDBSize);
1406
1407 /* If journaled and we only have one AVH to track */
1408 if ((hfsmp->jnl) && (hfsmp->hfs_partition_avh_sector == hfsmp->hfs_fs_avh_sector)) {
1409 journal_modify_block_end (hfsmp->jnl, psAltHdrBuf, NULL, NULL);
1410 }
1411 else
1412 {
1413 /*
1414 * If we don't have a journal or there are two AVH's at the
1415 * moment, then this one doesn't go in the journal. Note that
1416 * this one may generate I/O errors, since the partition
1417 * can be resized behind our backs at any moment and this I/O
1418 * may now appear to be beyond the device EOF.
1419 */
1420 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);
1421 if (retval)
1422 {
1423 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d writing VH blk (vol=%s)\n", retval, vcb->vcbVN);
1424 goto err_exit;
1425 }
1426 lf_hfs_generic_buf_release(psAltHdrBuf);
1427 pvAltHdrData = NULL;
1428 hfs_flush(hfsmp, HFS_FLUSH_CACHE);
1429 }
1430 }
1431 }
1432
1433 /* Finish modifying the block for the primary VH */
1434 if (hfsmp->jnl) {
1435 journal_modify_block_end(hfsmp->jnl, psVolHdrBuf, NULL, NULL);
1436 }
1437 else
1438 {
1439 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);
1440 /* When critical data changes, flush the device cache */
1441 if (critical && (retval == 0))
1442 {
1443 hfs_flush(hfsmp, HFS_FLUSH_CACHE);
1444 }
1445
1446 lf_hfs_generic_buf_release(psVolHdrBuf);
1447 pvVolHdrData = NULL;
1448 if (retval)
1449 {
1450 LFHFS_LOG(LEVEL_ERROR, "hfs_flushvolumeheader: err %d reading VH blk (vol=%s)\n", retval, vcb->vcbVN);
1451 goto err_exit;
1452 }
1453 }
1454 if (!(options & HFS_FVH_SKIP_TRANSACTION)) {
1455 hfs_end_transaction(hfsmp);
1456 }
1457
1458 return (retval);
1459
1460 err_exit:
1461 if (pvVolHdrData)
1462 lf_hfs_generic_buf_release(psVolHdrBuf);
1463 if (pvVolHdr2Data)
1464 lf_hfs_generic_buf_release(psVolHdr2Buf);
1465 if (pvAltHdrData)
1466 lf_hfs_generic_buf_release(psAltHdrBuf);
1467
1468 if (!(options & HFS_FVH_SKIP_TRANSACTION)) {
1469 hfs_end_transaction(hfsmp);
1470 }
1471 return retval;
1472 }
1473
1474 /* If a runtime corruption is detected, set the volume inconsistent
1475 * bit in the volume attributes. The volume inconsistent bit is a persistent
1476 * bit which represents that the volume is corrupt and needs repair.
1477 * The volume inconsistent bit can be set from the kernel when it detects
1478 * runtime corruption or from file system repair utilities like fsck_hfs when
1479 * a repair operation fails. The bit should be cleared only from file system
1480 * verify/repair utility like fsck_hfs when a verify/repair succeeds.
1481 */
1482 void hfs_mark_inconsistent(struct hfsmount *hfsmp, hfs_inconsistency_reason_t reason)
1483 {
1484 hfs_lock_mount (hfsmp);
1485 if ((hfsmp->vcbAtrb & kHFSVolumeInconsistentMask) == 0)
1486 {
1487 hfsmp->vcbAtrb |= kHFSVolumeInconsistentMask;
1488 MarkVCBDirty(hfsmp);
1489 }
1490 if ((hfsmp->hfs_flags & HFS_READ_ONLY)==0)
1491 {
1492 switch (reason)
1493 {
1494 case HFS_INCONSISTENCY_DETECTED:
1495 LFHFS_LOG(LEVEL_ERROR, "hfs_mark_inconsistent: Runtime corruption detected on %s, fsck will be forced on next mount.\n",hfsmp->vcbVN);
1496 break;
1497 case HFS_ROLLBACK_FAILED:
1498 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);
1499 break;
1500 case HFS_OP_INCOMPLETE:
1501 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);
1502 break;
1503 case HFS_FSCK_FORCED:
1504 LFHFS_LOG(LEVEL_ERROR, "hfs_mark_inconsistent: fsck requested for `%s'; fsck will be forced on next mount.\n",hfsmp->vcbVN);
1505 break;
1506 }
1507 }
1508 hfs_unlock_mount (hfsmp);
1509 }
1510
1511 /*
1512 * Creates a UUID from a unique "name" in the HFS UUID Name space.
1513 * See version 3 UUID.
1514 */
1515 void
1516 hfs_getvoluuid(struct hfsmount *hfsmp, uuid_t result_uuid)
1517 {
1518
1519 if (uuid_is_null(hfsmp->hfs_full_uuid)) {
1520 uuid_t result;
1521
1522 CC_MD5_CTX md5c;
1523 uint8_t rawUUID[8];
1524
1525 ((uint32_t *)rawUUID)[0] = hfsmp->vcbFndrInfo[6];
1526 ((uint32_t *)rawUUID)[1] = hfsmp->vcbFndrInfo[7];
1527
1528 CC_MD5_Init( &md5c );
1529 CC_MD5_Update( &md5c, HFS_UUID_NAMESPACE_ID, sizeof( uuid_t ) );
1530 CC_MD5_Update( &md5c, rawUUID, sizeof (rawUUID) );
1531 CC_MD5_Final( result, &md5c );
1532
1533 result[6] = 0x30 | ( result[6] & 0x0F );
1534 result[8] = 0x80 | ( result[8] & 0x3F );
1535
1536 uuid_copy(hfsmp->hfs_full_uuid, result);
1537 }
1538 uuid_copy (result_uuid, hfsmp->hfs_full_uuid);
1539
1540 }
1541
1542 /*
1543 * Call into the allocator code and perform a full scan of the bitmap file.
1544 *
1545 * This allows us to TRIM unallocated ranges if needed, and also to build up
1546 * an in-memory summary table of the state of the allocated blocks.
1547 */
1548 void hfs_scan_blocks (struct hfsmount *hfsmp)
1549 {
1550 /*
1551 * Take the allocation file lock. Journal transactions will block until
1552 * we're done here.
1553 */
1554 int flags = hfs_systemfile_lock(hfsmp, SFL_BITMAP, HFS_EXCLUSIVE_LOCK);
1555
1556 /*
1557 * We serialize here with the HFS mount lock as we're mounting.
1558 *
1559 * The mount can only proceed once this thread has acquired the bitmap
1560 * lock, since we absolutely do not want someone else racing in and
1561 * getting the bitmap lock, doing a read/write of the bitmap file,
1562 * then us getting the bitmap lock.
1563 *
1564 * To prevent this, the mount thread takes the HFS mount mutex, starts us
1565 * up, then immediately msleeps on the scan_var variable in the mount
1566 * point as a condition variable. This serialization is safe since
1567 * if we race in and try to proceed while they're still holding the lock,
1568 * we'll block trying to acquire the global lock. Since the mount thread
1569 * acquires the HFS mutex before starting this function in a new thread,
1570 * any lock acquisition on our part must be linearizably AFTER the mount thread's.
1571 *
1572 * Note that the HFS mount mutex is always taken last, and always for only
1573 * a short time. In this case, we just take it long enough to mark the
1574 * scan-in-flight bit.
1575 */
1576 (void) hfs_lock_mount (hfsmp);
1577 hfsmp->scan_var |= HFS_ALLOCATOR_SCAN_INFLIGHT;
1578 hfs_unlock_mount (hfsmp);
1579
1580 /* Initialize the summary table */
1581 if (hfs_init_summary (hfsmp))
1582 {
1583 LFHFS_LOG(LEVEL_DEBUG, "hfs_scan_blocks: could not initialize summary table for %s\n", hfsmp->vcbVN);
1584 }
1585
1586 /*
1587 * ScanUnmapBlocks assumes that the bitmap lock is held when you
1588 * call the function. We don't care if there were any errors issuing unmaps.
1589 *
1590 * It will also attempt to build up the summary table for subsequent
1591 * allocator use, as configured.
1592 */
1593 (void) ScanUnmapBlocks(hfsmp);
1594
1595 (void) hfs_lock_mount (hfsmp);
1596 hfsmp->scan_var &= ~HFS_ALLOCATOR_SCAN_INFLIGHT;
1597 hfsmp->scan_var |= HFS_ALLOCATOR_SCAN_COMPLETED;
1598 hfs_unlock_mount (hfsmp);
1599
1600 hfs_systemfile_unlock(hfsmp, flags);
1601 }
1602
1603 int
1604 hfs_GetInfoByID(struct hfsmount *hfsmp, cnid_t cnid, UVFSFileAttributes *file_attrs, char pcName[MAX_UTF8_NAME_LENGTH])
1605 {
1606 u_int32_t linkref = 0;
1607 struct vnode *psVnode = NULL;
1608 struct cat_desc cndesc;
1609 struct cat_attr cnattr;
1610 struct cat_fork cnfork;
1611 int error = 0;
1612
1613 /* Check for cnids that should't be exported. */
1614 if ((cnid < kHFSFirstUserCatalogNodeID) &&
1615 (cnid != kHFSRootFolderID && cnid != kHFSRootParentID)) {
1616 return (ENOENT);
1617 }
1618 /* Don't export our private directories. */
1619 if (cnid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid ||
1620 cnid == hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid) {
1621 return (ENOENT);
1622 }
1623 /*
1624 * Check the hash first
1625 */
1626 psVnode = hfs_chash_getvnode(hfsmp, cnid, 0, 0, 0);
1627 if (psVnode) {
1628 goto getAttrAndDone;
1629 }
1630
1631 bzero(&cndesc, sizeof(cndesc));
1632 bzero(&cnattr, sizeof(cnattr));
1633 bzero(&cnfork, sizeof(cnfork));
1634
1635 /*
1636 * Not in hash, lookup in catalog
1637 */
1638 if (cnid == kHFSRootParentID) {
1639 static char hfs_rootname[] = "/";
1640
1641 cndesc.cd_nameptr = (const u_int8_t *)&hfs_rootname[0];
1642 cndesc.cd_namelen = 1;
1643 cndesc.cd_parentcnid = kHFSRootParentID;
1644 cndesc.cd_cnid = kHFSRootFolderID;
1645 cndesc.cd_flags = CD_ISDIR;
1646
1647 cnattr.ca_fileid = kHFSRootFolderID;
1648 cnattr.ca_linkcount = 1;
1649 cnattr.ca_entries = 1;
1650 cnattr.ca_dircount = 1;
1651 cnattr.ca_mode = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
1652 } else {
1653 int lockflags;
1654 cnid_t pid;
1655 const char *nameptr;
1656
1657 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
1658 error = cat_idlookup(hfsmp, cnid, 0, 0, &cndesc, &cnattr, &cnfork);
1659 hfs_systemfile_unlock(hfsmp, lockflags);
1660
1661 if (error) {
1662 return (error);
1663 }
1664
1665 /*
1666 * Check for a raw hardlink inode and save its linkref.
1667 */
1668 pid = cndesc.cd_parentcnid;
1669 nameptr = (const char *)cndesc.cd_nameptr;
1670 if ((pid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid) &&
1671 cndesc.cd_namelen > HFS_INODE_PREFIX_LEN &&
1672 (bcmp(nameptr, HFS_INODE_PREFIX, HFS_INODE_PREFIX_LEN) == 0)) {
1673 linkref = (uint32_t) strtoul(&nameptr[HFS_INODE_PREFIX_LEN], NULL, 10);
1674
1675 } else if ((pid == hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid) &&
1676 cndesc.cd_namelen > HFS_DIRINODE_PREFIX_LEN &&
1677 (bcmp(nameptr, HFS_DIRINODE_PREFIX, HFS_DIRINODE_PREFIX_LEN) == 0)) {
1678 linkref = (uint32_t) strtoul(&nameptr[HFS_DIRINODE_PREFIX_LEN], NULL, 10);
1679
1680 } else if ((pid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid) &&
1681 cndesc.cd_namelen > HFS_DELETE_PREFIX_LEN &&
1682 (bcmp(nameptr, HFS_DELETE_PREFIX, HFS_DELETE_PREFIX_LEN) == 0)) {
1683 cat_releasedesc(&cndesc);
1684 return (ENOENT); /* open unlinked file */
1685 }
1686 }
1687
1688 /*
1689 * Finish initializing cnode descriptor for hardlinks.
1690 *
1691 * We need a valid name and parent for reverse lookups.
1692 */
1693 if (linkref) {
1694 cnid_t lastid;
1695 struct cat_desc linkdesc;
1696 int linkerr = 0;
1697
1698 cnattr.ca_linkref = linkref;
1699 bzero (&linkdesc, sizeof (linkdesc));
1700
1701 /*
1702 * If the caller supplied the raw inode value, then we don't know exactly
1703 * which hardlink they wanted. It's likely that they acquired the raw inode
1704 * value BEFORE the item became a hardlink, in which case, they probably
1705 * want the oldest link. So request the oldest link from the catalog.
1706 *
1707 * Unfortunately, this requires that we iterate through all N hardlinks. On the plus
1708 * side, since we know that we want the last linkID, we can also have this one
1709 * call give us back the name of the last ID, since it's going to have it in-hand...
1710 */
1711 linkerr = hfs_lookup_lastlink (hfsmp, linkref, &lastid, &linkdesc);
1712 if ((linkerr == 0) && (lastid != 0)) {
1713 /*
1714 * Release any lingering buffers attached to our local descriptor.
1715 * Then copy the name and other business into the cndesc
1716 */
1717 cat_releasedesc (&cndesc);
1718 bcopy (&linkdesc, &cndesc, sizeof(linkdesc));
1719 }
1720 /* If it failed, the linkref code will just use whatever it had in-hand below. */
1721
1722 int newvnode_flags = 0;
1723 error = hfs_getnewvnode(hfsmp, NULL, NULL, &cndesc, 0, &cnattr, &cnfork, &psVnode, &newvnode_flags);
1724 if (error == 0) {
1725 VTOC(psVnode)->c_flag |= C_HARDLINK;
1726 }
1727 }
1728 else
1729 {
1730 int newvnode_flags = 0;
1731
1732 void *buf = hfs_malloc(MAX_UTF8_NAME_LENGTH);
1733 if (buf == NULL) {
1734 return (ENOMEM);
1735 }
1736
1737 /* Supply hfs_getnewvnode with a component name. */
1738 struct componentname cn = {
1739 .cn_nameiop = LOOKUP,
1740 .cn_flags = ISLASTCN,
1741 .cn_pnlen = MAXPATHLEN,
1742 .cn_namelen = cndesc.cd_namelen,
1743 .cn_pnbuf = buf,
1744 .cn_nameptr = buf
1745 };
1746
1747 bcopy(cndesc.cd_nameptr, cn.cn_nameptr, cndesc.cd_namelen + 1);
1748 error = hfs_getnewvnode(hfsmp, NULL, &cn, &cndesc, 0, &cnattr, &cnfork, &psVnode, &newvnode_flags);
1749 if (error == 0 && (VTOC(psVnode)->c_flag & C_HARDLINK)) {
1750 hfs_savelinkorigin(VTOC(psVnode), cndesc.cd_parentcnid);
1751 }
1752
1753 hfs_free(buf);
1754 }
1755 cat_releasedesc(&cndesc);
1756
1757 getAttrAndDone:
1758 if (!error) vnode_GetAttrInternal (psVnode, file_attrs);
1759 if (psVnode != NULL) hfs_unlock(VTOC(psVnode));
1760
1761 if (error || psVnode == NULL || psVnode->sFSParams.vnfs_cnp->cn_nameptr == NULL){
1762 hfs_vnop_reclaim(psVnode);
1763 return EFAULT;
1764 }
1765
1766 if (cnid == kHFSRootFolderID)
1767 pcName[0] = 0;
1768 else {
1769 strlcpy(pcName, (char*) psVnode->sFSParams.vnfs_cnp->cn_nameptr, MAX_UTF8_NAME_LENGTH);
1770 }
1771
1772 error = hfs_vnop_reclaim(psVnode);
1773
1774 return (error);
1775 }
1776
1777 /*
1778 * Look up an HFS object by ID.
1779 *
1780 * The object is returned with an iocount reference and the cnode locked.
1781 *
1782 * If the object is a file then it will represent the data fork.
1783 */
1784 int
1785 hfs_vget(struct hfsmount *hfsmp, cnid_t cnid, struct vnode **vpp, int skiplock, int allow_deleted)
1786 {
1787 struct vnode *vp = NULL;
1788 struct cat_desc cndesc;
1789 struct cat_attr cnattr;
1790 struct cat_fork cnfork;
1791
1792 u_int32_t linkref = 0;
1793
1794 int error;
1795
1796 /* Check for cnids that should't be exported. */
1797 if ((cnid < kHFSFirstUserCatalogNodeID) &&
1798 (cnid != kHFSRootFolderID && cnid != kHFSRootParentID)) {
1799 return (ENOENT);
1800 }
1801 /* Don't export our private directories. */
1802 if (cnid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid ||
1803 cnid == hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid) {
1804 return (ENOENT);
1805 }
1806 /*
1807 * Check the hash first
1808 */
1809 vp = hfs_chash_getvnode(hfsmp, cnid, 0, skiplock, allow_deleted);
1810 if (vp) {
1811 *vpp = vp;
1812 return(0);
1813 }
1814
1815 bzero(&cndesc, sizeof(cndesc));
1816 bzero(&cnattr, sizeof(cnattr));
1817 bzero(&cnfork, sizeof(cnfork));
1818
1819 /*
1820 * Not in hash, lookup in catalog
1821 */
1822 if (cnid == kHFSRootParentID) {
1823 static char hfs_rootname[] = "/";
1824
1825 cndesc.cd_nameptr = (const u_int8_t *)&hfs_rootname[0];
1826 cndesc.cd_namelen = 1;
1827 cndesc.cd_parentcnid = kHFSRootParentID;
1828 cndesc.cd_cnid = kHFSRootFolderID;
1829 cndesc.cd_flags = CD_ISDIR;
1830
1831 cnattr.ca_fileid = kHFSRootFolderID;
1832 cnattr.ca_linkcount = 1;
1833 cnattr.ca_entries = 1;
1834 cnattr.ca_dircount = 1;
1835 cnattr.ca_mode = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
1836 } else {
1837 int lockflags;
1838 cnid_t pid;
1839 const char *nameptr;
1840
1841 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
1842 error = cat_idlookup(hfsmp, cnid, 0, 0, &cndesc, &cnattr, &cnfork);
1843 hfs_systemfile_unlock(hfsmp, lockflags);
1844
1845 if (error) {
1846 *vpp = NULL;
1847 return (error);
1848 }
1849
1850 /*
1851 * Check for a raw hardlink inode and save its linkref.
1852 */
1853 pid = cndesc.cd_parentcnid;
1854 nameptr = (const char *)cndesc.cd_nameptr;
1855 if ((pid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid) &&
1856 cndesc.cd_namelen > HFS_INODE_PREFIX_LEN &&
1857 (bcmp(nameptr, HFS_INODE_PREFIX, HFS_INODE_PREFIX_LEN) == 0)) {
1858 linkref = (uint32_t) strtoul(&nameptr[HFS_INODE_PREFIX_LEN], NULL, 10);
1859
1860 } else if ((pid == hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid) &&
1861 cndesc.cd_namelen > HFS_DIRINODE_PREFIX_LEN &&
1862 (bcmp(nameptr, HFS_DIRINODE_PREFIX, HFS_DIRINODE_PREFIX_LEN) == 0)) {
1863 linkref = (uint32_t) strtoul(&nameptr[HFS_DIRINODE_PREFIX_LEN], NULL, 10);
1864
1865 } else if ((pid == hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid) &&
1866 cndesc.cd_namelen > HFS_DELETE_PREFIX_LEN &&
1867 (bcmp(nameptr, HFS_DELETE_PREFIX, HFS_DELETE_PREFIX_LEN) == 0)) {
1868 *vpp = NULL;
1869 cat_releasedesc(&cndesc);
1870 return (ENOENT); /* open unlinked file */
1871 }
1872 }
1873
1874 /*
1875 * Finish initializing cnode descriptor for hardlinks.
1876 *
1877 * We need a valid name and parent for reverse lookups.
1878 */
1879 if (linkref) {
1880 cnid_t lastid;
1881 struct cat_desc linkdesc;
1882 int linkerr = 0;
1883
1884 cnattr.ca_linkref = linkref;
1885 bzero (&linkdesc, sizeof (linkdesc));
1886
1887 /*
1888 * If the caller supplied the raw inode value, then we don't know exactly
1889 * which hardlink they wanted. It's likely that they acquired the raw inode
1890 * value BEFORE the item became a hardlink, in which case, they probably
1891 * want the oldest link. So request the oldest link from the catalog.
1892 *
1893 * Unfortunately, this requires that we iterate through all N hardlinks. On the plus
1894 * side, since we know that we want the last linkID, we can also have this one
1895 * call give us back the name of the last ID, since it's going to have it in-hand...
1896 */
1897 linkerr = hfs_lookup_lastlink (hfsmp, linkref, &lastid, &linkdesc);
1898 if ((linkerr == 0) && (lastid != 0)) {
1899 /*
1900 * Release any lingering buffers attached to our local descriptor.
1901 * Then copy the name and other business into the cndesc
1902 */
1903 cat_releasedesc (&cndesc);
1904 bcopy (&linkdesc, &cndesc, sizeof(linkdesc));
1905 }
1906 /* If it failed, the linkref code will just use whatever it had in-hand below. */
1907 }
1908
1909 if (linkref) {
1910 int newvnode_flags = 0;
1911 error = hfs_getnewvnode(hfsmp, NULL, NULL, &cndesc, 0, &cnattr, &cnfork, &vp, &newvnode_flags);
1912 if (error == 0) {
1913 VTOC(vp)->c_flag |= C_HARDLINK;
1914
1915 //TBD - this set is for vfs -> since we have the C_HARDLINK
1916 // currently disable this set.
1917 //vnode_setmultipath(vp);
1918 }
1919 }
1920 else
1921 {
1922 int newvnode_flags = 0;
1923
1924 void *buf = hfs_malloc(MAXPATHLEN);
1925
1926 /* Supply hfs_getnewvnode with a component name. */
1927 struct componentname cn = {
1928 .cn_nameiop = LOOKUP,
1929 .cn_flags = ISLASTCN,
1930 .cn_pnlen = MAXPATHLEN,
1931 .cn_namelen = cndesc.cd_namelen,
1932 .cn_pnbuf = buf,
1933 .cn_nameptr = buf
1934 };
1935
1936 bcopy(cndesc.cd_nameptr, cn.cn_nameptr, cndesc.cd_namelen + 1);
1937 error = hfs_getnewvnode(hfsmp, NULL, &cn, &cndesc, 0, &cnattr, &cnfork, &vp, &newvnode_flags);
1938
1939 if (error == 0 && (VTOC(vp)->c_flag & C_HARDLINK)) {
1940 hfs_savelinkorigin(VTOC(vp), cndesc.cd_parentcnid);
1941 }
1942
1943 hfs_free(buf);
1944 }
1945 cat_releasedesc(&cndesc);
1946
1947 *vpp = vp;
1948 if (vp && skiplock) {
1949 hfs_unlock(VTOC(vp));
1950 }
1951 return (error);
1952 }
1953
1954 /*
1955 * Return the root of a filesystem.
1956 */
1957 int hfs_vfs_root(struct mount *mp, struct vnode **vpp)
1958 {
1959 return hfs_vget(VFSTOHFS(mp), (cnid_t)kHFSRootFolderID, vpp, 1, 0);
1960 }
1961
1962 /*
1963 * unmount system call
1964 */
1965 int hfs_unmount(struct mount *mp)
1966 {
1967 struct hfsmount *hfsmp = VFSTOHFS(mp);
1968 int retval = E_NONE;
1969
1970 if (hfsmp->hfs_flags & HFS_SUMMARY_TABLE)
1971 {
1972 if (hfsmp->hfs_summary_table)
1973 {
1974 int err = 0;
1975 /*
1976 * Take the bitmap lock to serialize against a concurrent bitmap scan still in progress
1977 */
1978 if (hfsmp->hfs_allocation_vp)
1979 {
1980 err = hfs_lock (VTOC(hfsmp->hfs_allocation_vp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT);
1981 }
1982 hfs_free(hfsmp->hfs_summary_table);
1983 hfsmp->hfs_summary_table = NULL;
1984 hfsmp->hfs_flags &= ~HFS_SUMMARY_TABLE;
1985
1986 if (err == 0 && hfsmp->hfs_allocation_vp)
1987 {
1988 hfs_unlock (VTOC(hfsmp->hfs_allocation_vp));
1989 }
1990 }
1991 }
1992
1993 /*
1994 * Invalidate our caches and release metadata vnodes
1995 */
1996 if (hfsmp->jnl) {
1997 journal_release(hfsmp->jnl);
1998 hfsmp->jnl = NULL;
1999 }
2000
2001 hfsUnmount(hfsmp);
2002 int iFD = hfsmp->hfs_devvp->psFSRecord->iFD;
2003 // Remove Buffer cache entries realted to the mount
2004 lf_hfs_generic_buf_cache_clear_by_iFD(iFD);
2005
2006 vnode_rele(hfsmp->hfs_devvp);
2007
2008 hfs_locks_destroy(hfsmp);
2009 hfs_delete_chash(hfsmp);
2010 hfs_idhash_destroy(hfsmp);
2011
2012 hfs_assert(TAILQ_EMPTY(&hfsmp->hfs_reserved_ranges[HFS_TENTATIVE_BLOCKS]) && TAILQ_EMPTY(&hfsmp->hfs_reserved_ranges[HFS_LOCKED_BLOCKS]));
2013 hfs_assert(!hfsmp->lockedBlocks);
2014
2015 hfs_free(hfsmp);
2016
2017 return (retval);
2018 }
2019 /* Update volume encoding bitmap (HFS Plus only)
2020 *
2021 * Mark a legacy text encoding as in-use (as needed)
2022 * in the volume header of this HFS+ filesystem.
2023 */
2024 void
2025 hfs_setencodingbits(struct hfsmount *hfsmp, u_int32_t encoding)
2026 {
2027 #define kIndexMacUkrainian 48 /* MacUkrainian encoding is 152 */
2028 #define kIndexMacFarsi 49 /* MacFarsi encoding is 140 */
2029
2030 u_int32_t index;
2031
2032 switch (encoding)
2033 {
2034 case kTextEncodingMacUkrainian:
2035 index = kIndexMacUkrainian;
2036 break;
2037 case kTextEncodingMacFarsi:
2038 index = kIndexMacFarsi;
2039 break;
2040 default:
2041 index = encoding;
2042 break;
2043 }
2044
2045 /* Only mark the encoding as in-use if it wasn't already set */
2046 if (index < 64 && (hfsmp->encodingsBitmap & (u_int64_t)(1ULL << index)) == 0) {
2047 hfs_lock_mount (hfsmp);
2048 hfsmp->encodingsBitmap |= (u_int64_t)(1ULL << index);
2049 MarkVCBDirty(hfsmp);
2050 hfs_unlock_mount(hfsmp);
2051 }
2052 }
2053
2054 /*
2055 * Update volume stats
2056 *
2057 * On journal volumes this will cause a volume header flush
2058 */
2059 int
2060 hfs_volupdate(struct hfsmount *hfsmp, enum volop op, int inroot)
2061 {
2062 struct timeval tv;
2063 microtime(&tv);
2064 hfs_lock_mount (hfsmp);
2065
2066 MarkVCBDirty(hfsmp);
2067 hfsmp->hfs_mtime = tv.tv_sec;
2068
2069 switch (op) {
2070 case VOL_UPDATE:
2071 break;
2072 case VOL_MKDIR:
2073 if (hfsmp->hfs_dircount != 0xFFFFFFFF)
2074 ++hfsmp->hfs_dircount;
2075 if (inroot && hfsmp->vcbNmRtDirs != 0xFFFF)
2076 ++hfsmp->vcbNmRtDirs;
2077 break;
2078 case VOL_RMDIR:
2079 if (hfsmp->hfs_dircount != 0)
2080 --hfsmp->hfs_dircount;
2081 if (inroot && hfsmp->vcbNmRtDirs != 0xFFFF)
2082 --hfsmp->vcbNmRtDirs;
2083 break;
2084 case VOL_MKFILE:
2085 if (hfsmp->hfs_filecount != 0xFFFFFFFF)
2086 ++hfsmp->hfs_filecount;
2087 if (inroot && hfsmp->vcbNmFls != 0xFFFF)
2088 ++hfsmp->vcbNmFls;
2089 break;
2090 case VOL_RMFILE:
2091 if (hfsmp->hfs_filecount != 0)
2092 --hfsmp->hfs_filecount;
2093 if (inroot && hfsmp->vcbNmFls != 0xFFFF)
2094 --hfsmp->vcbNmFls;
2095 break;
2096 }
2097
2098 hfs_unlock_mount (hfsmp);
2099 hfs_flushvolumeheader(hfsmp, 0);
2100
2101 return (0);
2102 }
2103