]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfs_vfsutils.c
xnu-792.17.14.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_vfsutils.c
index 710e4922868690a85f5ce825751d3ca589ab0b4e..6024b382d54dd1cb1a17255dfb93f92b4d770779 100644 (file)
@@ -1,14 +1,19 @@
 /*
  * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ * 
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
  * 
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
@@ -18,7 +23,7 @@
  * Please see the License for the specific language governing rights and
  * limitations under the License.
  * 
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*     @(#)hfs_vfsutils.c      4.0
 *
@@ -246,6 +251,11 @@ OSErr hfs_MountHFSVolume(struct hfsmount *hfsmp, HFSMasterDirectoryBlock *mdb,
        hfs_unlock(VTOC(hfsmp->hfs_catalog_vp));
        hfs_unlock(VTOC(hfsmp->hfs_extents_vp));
 
+       if (error == noErr)
+         {
+           error = cat_idlookup(hfsmp, kHFSRootFolderID, NULL, NULL, NULL);
+         }
+
     if ( error == noErr )
       {
         if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) )            //      if the disk is not write protected
@@ -530,6 +540,8 @@ OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp,
        /* Pick up volume name and create date */
        retval = cat_idlookup(hfsmp, kHFSRootFolderID, &cndesc, &cnattr, NULL);
        if (retval) {
+               if (hfsmp->hfs_attribute_vp)
+                       hfs_unlock(VTOC(hfsmp->hfs_attribute_vp));
                hfs_unlock(VTOC(hfsmp->hfs_allocation_vp));
                hfs_unlock(VTOC(hfsmp->hfs_catalog_vp));
                hfs_unlock(VTOC(hfsmp->hfs_extents_vp));
@@ -563,7 +575,7 @@ OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp,
        //
        if (   (vcb->vcbAtrb & kHFSVolumeJournaledMask)
                && (SWAP_BE32(vhp->lastMountedVersion) != kHFSJMountVersion)
-               && (hfsmp->jnl == NULL)) {
+               && (hfsmp->jnl == NULL)) {
 
                retval = hfs_late_journal_init(hfsmp, vhp, args);
                if (retval != 0) {
@@ -605,9 +617,13 @@ OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp,
                } else if (hfsmp->jnl) {
                        vfs_setflags(hfsmp->hfs_mp, (uint64_t)((unsigned int)MNT_JOURNALED));
                }
-       } else if (hfsmp->jnl) {
+       } else if (hfsmp->jnl || ((vcb->vcbAtrb & kHFSVolumeJournaledMask) && (hfsmp->hfs_flags & HFS_READ_ONLY))) {
                struct cat_attr jinfo_attr, jnl_attr;
                
+               if (hfsmp->hfs_flags & HFS_READ_ONLY) {
+                   vcb->vcbAtrb &= ~kHFSVolumeJournaledMask;
+               }
+
                // 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);
@@ -616,6 +632,10 @@ OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp,
                        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);
                }
+
+               if (hfsmp->hfs_flags & HFS_READ_ONLY) {
+                   vcb->vcbAtrb |= kHFSVolumeJournaledMask;
+               }
        }
 
        /*
@@ -1729,6 +1749,28 @@ hfs_early_journal_init(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp,
        hfsmp->jnl_start = jibp->offset / SWAP_BE32(vhp->blockSize);
        hfsmp->jnl_size  = jibp->size;
 
+       if ((hfsmp->hfs_flags & HFS_READ_ONLY) && (vfs_flags(hfsmp->hfs_mp) & MNT_ROOTFS) == 0) {
+           // if the file system is read-only, check if the journal is empty.
+           // if it is, then we can allow the mount.  otherwise we have to
+           // return failure.
+           retval = journal_is_clean(hfsmp->jvp,
+                                     jibp->offset + embeddedOffset,
+                                     jibp->size,
+                                     devvp,
+                                     hfsmp->hfs_phys_block_size);
+
+           hfsmp->jnl = NULL;
+
+           buf_brelse(jinfo_bp);
+
+           if (retval) {
+             printf("hfs: early journal init: volume on %s is read-only and journal is dirty.  Can not mount volume.\n",
+                     vnode_name(devvp));
+           }
+
+           return retval;
+       }
+
        if (jibp->flags & kJIJournalNeedInitMask) {
                printf("hfs: Initializing the journal (joffset 0x%llx sz 0x%llx)...\n",
                           jibp->offset + embeddedOffset, jibp->size);
@@ -1916,6 +1958,28 @@ hfs_late_journal_init(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, void *_a
        hfsmp->jnl_start = jibp->offset / SWAP_BE32(vhp->blockSize);
        hfsmp->jnl_size  = jibp->size;
 
+       if ((hfsmp->hfs_flags & HFS_READ_ONLY) && (vfs_flags(hfsmp->hfs_mp) & MNT_ROOTFS) == 0) {
+           // if the file system is read-only, check if the journal is empty.
+           // if it is, then we can allow the mount.  otherwise we have to
+           // return failure.
+           retval = journal_is_clean(hfsmp->jvp,
+                                     jibp->offset + (off_t)vcb->hfsPlusIOPosOffset,
+                                     jibp->size,
+                                     devvp,
+                                     hfsmp->hfs_phys_block_size);
+
+           hfsmp->jnl = NULL;
+
+           buf_brelse(jinfo_bp);
+
+           if (retval) {
+             printf("hfs: late journal init: volume on %s is read-only and journal is dirty.  Can not mount volume.\n",
+                    vnode_name(devvp));
+           }
+
+           return retval;
+       }
+
        if (jibp->flags & kJIJournalNeedInitMask) {
                printf("hfs: Initializing the journal (joffset 0x%llx sz 0x%llx)...\n",
                           jibp->offset + (off_t)vcb->hfsPlusIOPosOffset, jibp->size);