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);
//*******************************************************************************
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;
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);
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. */
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);
/* 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...
/* 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:
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;
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.
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 */
return EISDIR; /* 21 */
case fxRangeErr: /* -32751 */
- return EIO; /* 5 */
+ return ERANGE;
case bdNamErr: /* -37 */
return ENAMETOOLONG; /* 63 */
}
+__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;
+}