X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/143cc14e17b26a90f1f4060725df7ea635161581..b4c24cb9d3df001f2892dc4ed451bc769ff28a9f:/bsd/hfs/hfs_vfsutils.c diff --git a/bsd/hfs/hfs_vfsutils.c b/bsd/hfs/hfs_vfsutils.c index c45f8a898..386acae02 100644 --- a/bsd/hfs/hfs_vfsutils.c +++ b/bsd/hfs/hfs_vfsutils.c @@ -55,6 +55,7 @@ extern uid_t console_user; static void ReleaseMetaFileVNode(struct vnode *vp); +static int hfs_late_journal_init(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, void *_args); u_int32_t GetLogicalBlockSize(struct vnode *vp); @@ -246,7 +247,7 @@ CmdDone: //******************************************************************************* OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, - off_t embeddedOffset, u_int64_t disksize, struct proc *p) + off_t embeddedOffset, u_int64_t disksize, struct proc *p, void *args) { register ExtendedVCB *vcb; struct cat_desc cndesc; @@ -254,9 +255,15 @@ OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, UInt32 blockSize; OSErr retval; - if (SWAP_BE16(vhp->signature) != kHFSPlusSigWord || - SWAP_BE16(vhp->version) != kHFSPlusVersion) - return (EINVAL); + // XXXdbg - added the kHFSJSigWord case + if ((SWAP_BE16(vhp->signature) != kHFSPlusSigWord && + SWAP_BE16(vhp->signature) != kHFSJSigWord) || + SWAP_BE16(vhp->version) != kHFSPlusVersion) { + // XXXdbg + printf("hfs: mount: sig 0x%x and version 0x%x are not HFS or HFS+.\n", + vhp->signature, vhp->version); + return (EINVAL); + } /* Block size must be at least 512 and a power of 2 */ blockSize = SWAP_BE32(vhp->blockSize); @@ -264,7 +271,7 @@ OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, return (EINVAL); /* don't mount a writable volume if its dirty, it must be cleaned by fsck_hfs */ - if (hfsmp->hfs_fs_ronly == 0 && (SWAP_BE32(vhp->attributes) & kHFSVolumeUnmountedMask) == 0) + if (hfsmp->hfs_fs_ronly == 0 && hfsmp->jnl == NULL && (SWAP_BE32(vhp->attributes) & kHFSVolumeUnmountedMask) == 0) return (EINVAL); /* Make sure we can live with the physical block size. */ @@ -280,6 +287,13 @@ OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, vcb = HFSTOVCB(hfsmp); vcb->vcbSigWord = SWAP_BE16(vhp->signature); + + // XXXdbg - remap this in case we've mounted a dirty journaled volume + if (vcb->vcbSigWord == kHFSJSigWord) { + vcb->vcbSigWord = kHFSPlusSigWord; + } + + vcb->vcbJinfoBlock = SWAP_BE32(vhp->journalInfoBlock); vcb->vcbLsMod = to_bsd_time(SWAP_BE32(vhp->modifyDate)); vcb->vcbAtrb = (UInt16)SWAP_BE32(vhp->attributes); vcb->vcbClpSiz = SWAP_BE32(vhp->rsrcClumpSize); @@ -413,6 +427,9 @@ OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, /* mark the volume dirty (clear clean unmount bit) */ vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask; + if (hfsmp->jnl && hfsmp->hfs_fs_ronly == 0) { + hfs_flushvolumeheader(hfsmp, TRUE, TRUE); + } /* * all done with metadata files so we can unlock now... @@ -423,12 +440,46 @@ OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, /* setup private/hidden directory for unlinked files */ hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb); + if (hfsmp->jnl && (hfsmp->hfs_fs_ronly == 0)) + hfs_remove_orphans(hfsmp); if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected { MarkVCBDirty( vcb ); // mark VCB dirty so it will be written } + + // + // Check if we need to do late journal initialization. This only + // happens if a previous version of MacOS X (or 9) touched the disk. + // In that case hfs_late_journal_init() will go re-locate the journal + // and journal_info_block files and validate that they're still kosher. + // + if ( (vcb->vcbAtrb & kHFSVolumeJournaledMask) + && (SWAP_BE32(vhp->lastMountedVersion) != kHFSJMountVersion) + && (hfsmp->jnl == NULL)) { + + retval = hfs_late_journal_init(hfsmp, vhp, args); + if (retval != 0) { + hfsmp->jnl = NULL; + goto ErrorExit; + } else if (hfsmp->jnl) { + hfsmp->hfs_mp->mnt_flag |= MNT_JOURNALED; + } + } else if (hfsmp->jnl) { + struct cat_attr jinfo_attr, jnl_attr; + + // if we're here we need to fill in the fileid's for the + // journal and journal_info_block. + hfsmp->hfs_jnlinfoblkid = GetFileInfo(vcb, kRootDirID, ".journal_info_block", &jinfo_attr, NULL); + hfsmp->hfs_jnlfileid = GetFileInfo(vcb, kRootDirID, ".journal", &jnl_attr, NULL); + if (hfsmp->hfs_jnlinfoblkid == 0 || hfsmp->hfs_jnlfileid == 0) { + printf("hfs: danger! couldn't find the file-id's for the journal or journal_info_block\n"); + printf("hfs: jnlfileid %d, jnlinfoblkid %d\n", hfsmp->hfs_jnlfileid, hfsmp->hfs_jnlinfoblkid); + } + } + + return (0); ErrorExit: @@ -759,13 +810,28 @@ FindMetaDataDirectory(ExtendedVCB *vcb) fndrinfo->frLocation.h = SWAP_BE16 (22460); fndrinfo->frFlags |= SWAP_BE16 (kIsInvisible + kNameLocked); + // XXXdbg + hfs_global_shared_lock_acquire(hfsmp); + if (hfsmp->jnl) { + if ((error = journal_start_transaction(hfsmp->jnl)) != 0) { + hfs_global_shared_lock_release(hfsmp); + return (0); + } + } + error = cat_create(hfsmp, &hfsmp->hfs_privdir_desc, &hfsmp->hfs_privdir_attr, &out_desc); /* Unlock catalog b-tree */ (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, current_proc()); - if (error) - return (0); + if (error) { + if (hfsmp->jnl) { + journal_end_transaction(hfsmp->jnl); + } + hfs_global_shared_lock_release(hfsmp); + + return (0); + } hfsmp->hfs_privdir_desc.cd_hint = out_desc.cd_hint; hfsmp->hfs_privdir_desc.cd_cnid = out_desc.cd_cnid; @@ -783,11 +849,209 @@ FindMetaDataDirectory(ExtendedVCB *vcb) vput(dvp); } hfs_volupdate(hfsmp, VOL_MKDIR, 1); + if (hfsmp->jnl) { + journal_end_transaction(hfsmp->jnl); + } + hfs_global_shared_lock_release(hfsmp); + cat_releasedesc(&out_desc); return (out_desc.cd_cnid); } +__private_extern__ +u_long +GetFileInfo(ExtendedVCB *vcb, u_int32_t dirid, char *name, + struct cat_attr *fattr, struct cat_fork *forkinfo) +{ + struct hfsmount * hfsmp; + struct vnode * dvp = NULL; + struct cnode * dcp = NULL; + struct FndrDirInfo * fndrinfo; + struct cat_desc jdesc; + struct timeval tv; + int error; + + if (vcb->vcbSigWord != kHFSPlusSigWord) + return (0); + + hfsmp = VCBTOHFS(vcb); + + memset(&jdesc, 0, sizeof(struct cat_desc)); + jdesc.cd_parentcnid = kRootDirID; + jdesc.cd_nameptr = name; + jdesc.cd_namelen = strlen(name); + + /* Lock catalog b-tree */ + error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, current_proc()); + if (error) + return (0); + + error = cat_lookup(hfsmp, &jdesc, 0, NULL, fattr, forkinfo); + + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, current_proc()); + + if (error == 0) { + return (fattr->ca_fileid); + } else if (hfsmp->hfs_fs_ronly) { + return (0); + } +} + + +/* + * On Journaled HFS, there can be orphaned files. These + * are files that were unlinked while busy. If the volume + * was not cleanly unmounted then some of these files may + * have persisted and need to be removed. + */ +__private_extern__ +void +hfs_remove_orphans(struct hfsmount * hfsmp) +{ + struct BTreeIterator * iterator = NULL; + struct FSBufferDescriptor btdata; + struct HFSPlusCatalogFile filerec; + struct HFSPlusCatalogKey * keyp; + FCB *fcb; + ExtendedVCB *vcb; + char filename[32]; + char tempname[32]; + size_t namelen; + int catlock = 0; + int result, started_tr = 0; + + if (hfsmp->hfs_orphans_cleaned) + return; + + vcb = HFSTOVCB(hfsmp); + fcb = VTOF(vcb->catalogRefNum); + + btdata.bufferAddress = &filerec; + btdata.itemSize = sizeof(filerec); + btdata.itemCount = 1; + + MALLOC(iterator, struct BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK); + bzero(iterator, sizeof(*iterator)); + keyp = (HFSPlusCatalogKey*)&iterator->key; + keyp->parentID = hfsmp->hfs_private_metadata_dir; + + // XXXdbg + hfs_global_shared_lock_acquire(hfsmp); + if (hfsmp->jnl) { + if (journal_start_transaction(hfsmp->jnl) != 0) { + hfs_global_shared_lock_release(hfsmp); + return; + } + started_tr = 1; + } + + /* Lock catalog b-tree */ + result = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, current_proc()); + if (result) + goto exit; + catlock = 1; + + /* + * Position the iterator at the folder thread record. + * (i.e. one record before first child) + */ + result = BTSearchRecord(fcb, iterator, NULL, NULL, iterator); + if (result) + goto exit; + + /* Visit all the children in the HFS+ private directory. */ + for (;;) { + result = BTIterateRecord(fcb, kBTreeNextRecord, iterator, &btdata, NULL); + if (result) + break; + if (keyp->parentID != hfsmp->hfs_private_metadata_dir) + break; + if (filerec.recordType != kHFSPlusFileRecord) + continue; + + (void) utf8_encodestr(keyp->nodeName.unicode, keyp->nodeName.length * 2, + filename, &namelen, sizeof(filename), 0, 0); + + (void) sprintf(tempname, "%s%d", HFS_DELETE_PREFIX, filerec.fileID); + + /* + * Delete all files named "tempxxx", where + * xxx is the file's cnid in decimal. + * + * Delete all files named "iNodexxx", that + * have a link count of zero. + */ + if (bcmp(tempname, filename, namelen) == 0) { + struct filefork fork = {0}; + struct cnode cnode = {0}; + + // XXXdebug + //printf("hfs_remove_orphans: removing %s\n", filename); + + /* Build a fake cnode */ + cnode.c_desc.cd_parentcnid = hfsmp->hfs_private_metadata_dir; + cnode.c_desc.cd_nameptr = filename; + cnode.c_desc.cd_namelen = namelen; + cnode.c_desc.cd_cnid = filerec.fileID; + cnode.c_attr.ca_fileid = filerec.fileID; + cnode.c_blocks = filerec.dataFork.totalBlocks + + filerec.resourceFork.totalBlocks; + + /* Position iterator at previous entry */ + if (BTIterateRecord(fcb, kBTreePrevRecord, iterator, + NULL, NULL) != 0) + break; + + /* Truncate the file to zero (both forks) */ + if (filerec.dataFork.totalBlocks > 0) { + fork.ff_cp = &cnode; + cnode.c_datafork = ⋔ + bcopy(&filerec.dataFork, &fork.ff_data, sizeof(struct cat_fork)); + if (TruncateFileC(vcb, (FCB*)&fork, 0, false) != 0) { + printf("error truncting data fork!\n"); + break; + } + } + if (filerec.resourceFork.totalBlocks > 0) { + fork.ff_cp = &cnode; + cnode.c_datafork = NULL; + cnode.c_rsrcfork = ⋔ + bcopy(&filerec.resourceFork, &fork.ff_data, sizeof(struct cat_fork)); + if (TruncateFileC(vcb, (FCB*)&fork, 0, false) != 0) { + printf("error truncting rsrc fork!\n"); + break; + } + } + + /* Remove the file record from the Catalog */ + if (cat_delete(hfsmp, &cnode.c_desc, &cnode.c_attr) != 0) { + printf("error deleting cat rec!\n"); + break; + } + + /* Update parent and volume counts */ + hfsmp->hfs_privdir_attr.ca_entries--; + (void)cat_update(hfsmp, &hfsmp->hfs_privdir_desc, + &hfsmp->hfs_privdir_attr, NULL, NULL); + hfs_volupdate(hfsmp, VOL_RMFILE, 0); + } + } + +exit: + /* Unlock catalog b-tree */ + if (catlock) + (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, current_proc()); + + if (started_tr) { + journal_end_transaction(hfsmp->jnl); + } + hfs_global_shared_lock_release(hfsmp); + + FREE(iterator, M_TEMP); + hfsmp->hfs_orphans_cleaned = 1; +} + /* * This will return the correct logical block size for a given vnode. @@ -860,12 +1124,14 @@ short MacToVFSError(OSErr err) switch (err) { case dskFulErr: /* -34 */ - case btNoSpaceAvail: /* -32733 */ + return ENOSPC; + case btNoSpaceAvail: /* -32733 */ + return EFBIG; case fxOvFlErr: /* -32750 */ - return ENOSPC; /* +28 */ + return EOVERFLOW; case btBadNode: /* -32731 */ - return EIO; /* +5 */ + return EBADF; case memFullErr: /* -108 */ return ENOMEM; /* +12 */ @@ -885,7 +1151,7 @@ short MacToVFSError(OSErr err) return EISDIR; /* 21 */ case fxRangeErr: /* -32751 */ - return EIO; /* 5 */ + return ERANGE; case bdNamErr: /* -37 */ return ENAMETOOLONG; /* 63 */ @@ -995,4 +1261,299 @@ hfs_relnamehints(struct cnode *dcp) } +__private_extern__ +int +hfs_early_journal_init(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, + void *_args, int embeddedOffset, int mdb_offset, + HFSMasterDirectoryBlock *mdbp, struct ucred *cred) +{ + JournalInfoBlock *jibp; + struct buf *jinfo_bp, *bp; + int sectors_per_fsblock, arg_flags=0, arg_tbufsz=0; + int retval, blksize = hfsmp->hfs_phys_block_size; + struct vnode *devvp; + struct hfs_mount_args *args = _args; + + devvp = hfsmp->hfs_devvp; + + if (args != NULL && (args->flags & HFSFSMNT_EXTENDED_ARGS)) { + arg_flags = args->journal_flags; + arg_tbufsz = args->journal_tbuffer_size; + } + + sectors_per_fsblock = SWAP_BE32(vhp->blockSize) / blksize; + + retval = meta_bread(devvp, + embeddedOffset/blksize + + (SWAP_BE32(vhp->journalInfoBlock)*sectors_per_fsblock), + SWAP_BE32(vhp->blockSize), cred, &jinfo_bp); + if (retval) + return retval; + + jibp = (JournalInfoBlock *)jinfo_bp->b_data; + jibp->flags = SWAP_BE32(jibp->flags); + jibp->offset = SWAP_BE64(jibp->offset); + jibp->size = SWAP_BE64(jibp->size); + + if (jibp->flags & kJIJournalInFSMask) { + hfsmp->jvp = hfsmp->hfs_devvp; + } else { + printf("hfs: journal not stored in fs! don't know what to do.\n"); + brelse(jinfo_bp); + return EINVAL; + } + + // save this off for the hack-y check in hfs_remove() + hfsmp->jnl_start = jibp->offset / SWAP_BE32(vhp->blockSize); + + if (jibp->flags & kJIJournalNeedInitMask) { + printf("hfs: Initializing the journal (joffset 0x%llx sz 0x%llx)...\n", + jibp->offset + (off_t)embeddedOffset, jibp->size); + hfsmp->jnl = journal_create(hfsmp->jvp, + jibp->offset + (off_t)embeddedOffset, + jibp->size, + devvp, + blksize, + arg_flags, + arg_tbufsz, + hfs_sync_metadata, hfsmp->hfs_mp); + + // no need to start a transaction here... if this were to fail + // we'd just re-init it on the next mount. + jibp->flags &= ~kJIJournalNeedInitMask; + jibp->flags = SWAP_BE32(jibp->flags); + bwrite(jinfo_bp); + jinfo_bp = NULL; + jibp = NULL; + } else { + //printf("hfs: Opening the journal (joffset 0x%llx sz 0x%llx vhp_blksize %d)...\n", + // jibp->offset + (off_t)embeddedOffset, + // jibp->size, SWAP_BE32(vhp->blockSize)); + + hfsmp->jnl = journal_open(hfsmp->jvp, + jibp->offset + (off_t)embeddedOffset, + jibp->size, + devvp, + blksize, + arg_flags, + arg_tbufsz, + hfs_sync_metadata, hfsmp->hfs_mp); + + brelse(jinfo_bp); + jinfo_bp = NULL; + jibp = NULL; + + if (hfsmp->jnl && mdbp) { + // reload the mdb because it could have changed + // if the journal had to be replayed. + retval = meta_bread(devvp, mdb_offset, blksize, cred, &bp); + if (retval) { + brelse(bp); + printf("hfs: failed to reload the mdb after opening the journal (retval %d)!\n", + retval); + return retval; + } + bcopy(bp->b_data + HFS_PRI_OFFSET(blksize), mdbp, 512); + brelse(bp); + bp = NULL; + } + } + + + //printf("journal @ 0x%x\n", hfsmp->jnl); + + // if we expected the journal to be there and we couldn't + // create it or open it then we have to bail out. + if (hfsmp->jnl == NULL) { + hfsmp->jnl_start = 0; + + printf("hfs: failed to open/create the journal (retval %d).\n", retval); + return EINVAL; + } + return 0; +} + + +// +// This function will go and re-locate the .journal_info_block and +// the .journal files in case they moved (which can happen if you +// run Norton SpeedDisk). If we fail to find either file we just +// disable journaling for this volume and return. We turn off the +// journaling bit in the vcb and assume it will get written to disk +// later (if it doesn't on the next mount we'd do the same thing +// again which is harmless). If we disable journaling we don't +// return an error so that the volume is still mountable. +// +// If the info we find for the .journal_info_block and .journal files +// isn't what we had stored, we re-set our cached info and proceed +// with opening the journal normally. +// +static int +hfs_late_journal_init(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, void *_args) +{ + JournalInfoBlock *jibp; + struct buf *jinfo_bp, *bp; + int sectors_per_fsblock, arg_flags=0, arg_tbufsz=0; + int retval, need_flush = 0, write_jibp = 0; + struct vnode *devvp; + struct cat_attr jib_attr, jattr; + struct cat_fork jib_fork, jfork; + ExtendedVCB *vcb; + u_long fid; + struct hfs_mount_args *args = _args; + + devvp = hfsmp->hfs_devvp; + vcb = HFSTOVCB(hfsmp); + + if (args != NULL && (args->flags & HFSFSMNT_EXTENDED_ARGS)) { + if (args->journal_disable) { + return 0; + } + + arg_flags = args->journal_flags; + arg_tbufsz = args->journal_tbuffer_size; + } + + fid = GetFileInfo(vcb, kRootDirID, ".journal_info_block", &jib_attr, &jib_fork); + if (fid == 0 || jib_fork.cf_extents[0].startBlock == 0 || jib_fork.cf_size == 0) { + printf("hfs: can't find the .journal_info_block! disabling journaling (start: %d).\n", + jib_fork.cf_extents[0].startBlock); + vcb->vcbAtrb &= ~kHFSVolumeJournaledMask; + return 0; + } + hfsmp->hfs_jnlinfoblkid = fid; + + // make sure the journal_info_block begins where we think it should. + if (SWAP_BE32(vhp->journalInfoBlock) != jib_fork.cf_extents[0].startBlock) { + printf("hfs: The journal_info_block moved (was: %d; is: %d). Fixing up\n", + SWAP_BE32(vhp->journalInfoBlock), jib_fork.cf_extents[0].startBlock); + + vcb->vcbJinfoBlock = jib_fork.cf_extents[0].startBlock; + vhp->journalInfoBlock = SWAP_BE32(jib_fork.cf_extents[0].startBlock); + } + + + sectors_per_fsblock = SWAP_BE32(vhp->blockSize) / hfsmp->hfs_phys_block_size; + retval = meta_bread(devvp, + vcb->hfsPlusIOPosOffset / hfsmp->hfs_phys_block_size + + (SWAP_BE32(vhp->journalInfoBlock)*sectors_per_fsblock), + SWAP_BE32(vhp->blockSize), NOCRED, &jinfo_bp); + if (retval) { + printf("hfs: can't read journal info block. disabling journaling.\n"); + vcb->vcbAtrb &= ~kHFSVolumeJournaledMask; + return 0; + } + + jibp = (JournalInfoBlock *)jinfo_bp->b_data; + jibp->flags = SWAP_BE32(jibp->flags); + jibp->offset = SWAP_BE64(jibp->offset); + jibp->size = SWAP_BE64(jibp->size); + + fid = GetFileInfo(vcb, kRootDirID, ".journal", &jattr, &jfork); + if (fid == 0 || jfork.cf_extents[0].startBlock == 0 || jfork.cf_size == 0) { + printf("hfs: can't find the journal file! disabling journaling (start: %d)\n", + jfork.cf_extents[0].startBlock); + brelse(jinfo_bp); + vcb->vcbAtrb &= ~kHFSVolumeJournaledMask; + return 0; + } + hfsmp->hfs_jnlfileid = fid; + + // make sure the journal file begins where we think it should. + if ((jibp->offset / (u_int64_t)vcb->blockSize) != jfork.cf_extents[0].startBlock) { + printf("hfs: The journal file moved (was: %lld; is: %d). Fixing up\n", + (jibp->offset / (u_int64_t)vcb->blockSize), jfork.cf_extents[0].startBlock); + + jibp->offset = (u_int64_t)jfork.cf_extents[0].startBlock * (u_int64_t)vcb->blockSize; + write_jibp = 1; + } + + // check the size of the journal file. + if (jibp->size != (u_int64_t)jfork.cf_extents[0].blockCount*vcb->blockSize) { + printf("hfs: The journal file changed size! (was %lld; is %lld). Fixing up.\n", + jibp->size, (u_int64_t)jfork.cf_extents[0].blockCount*vcb->blockSize); + + jibp->size = (u_int64_t)jfork.cf_extents[0].blockCount * vcb->blockSize; + write_jibp = 1; + } + + if (jibp->flags & kJIJournalInFSMask) { + hfsmp->jvp = hfsmp->hfs_devvp; + } else { + printf("hfs: journal not stored in fs! don't know what to do.\n"); + brelse(jinfo_bp); + return EINVAL; + } + + // save this off for the hack-y check in hfs_remove() + hfsmp->jnl_start = jibp->offset / SWAP_BE32(vhp->blockSize); + + if (jibp->flags & kJIJournalNeedInitMask) { + printf("hfs: Initializing the journal (joffset 0x%llx sz 0x%llx)...\n", + jibp->offset + (off_t)vcb->hfsPlusIOPosOffset, jibp->size); + hfsmp->jnl = journal_create(hfsmp->jvp, + jibp->offset + (off_t)vcb->hfsPlusIOPosOffset, + jibp->size, + devvp, + hfsmp->hfs_phys_block_size, + arg_flags, + arg_tbufsz, + hfs_sync_metadata, hfsmp->hfs_mp); + + // no need to start a transaction here... if this were to fail + // we'd just re-init it on the next mount. + jibp->flags &= ~kJIJournalNeedInitMask; + write_jibp = 1; + + } else { + // + // if we weren't the last person to mount this volume + // then we need to throw away the journal because it + // is likely that someone else mucked with the disk. + // if the journal is empty this is no big deal. if the + // disk is dirty this prevents us from replaying the + // journal over top of changes that someone else made. + // + arg_flags |= JOURNAL_RESET; + + //printf("hfs: Opening the journal (joffset 0x%llx sz 0x%llx vhp_blksize %d)...\n", + // jibp->offset + (off_t)vcb->hfsPlusIOPosOffset, + // jibp->size, SWAP_BE32(vhp->blockSize)); + + hfsmp->jnl = journal_open(hfsmp->jvp, + jibp->offset + (off_t)vcb->hfsPlusIOPosOffset, + jibp->size, + devvp, + hfsmp->hfs_phys_block_size, + arg_flags, + arg_tbufsz, + hfs_sync_metadata, hfsmp->hfs_mp); + } + + + if (write_jibp) { + jibp->flags = SWAP_BE32(jibp->flags); + jibp->offset = SWAP_BE64(jibp->offset); + jibp->size = SWAP_BE64(jibp->size); + + bwrite(jinfo_bp); + } else { + brelse(jinfo_bp); + } + jinfo_bp = NULL; + jibp = NULL; + + //printf("journal @ 0x%x\n", hfsmp->jnl); + + // if we expected the journal to be there and we couldn't + // create it or open it then we have to bail out. + if (hfsmp->jnl == NULL) { + hfsmp->jnl_start = 0; + + printf("hfs: failed to open/create the journal (retval %d).\n", retval); + return EINVAL; + } + + return 0; +}