]> git.saurik.com Git - apple/hfs.git/commitdiff
hfs-183.tar.gz mac-os-x-106 mac-os-x-1061 mac-os-x-1062 v183
authorApple <opensource@apple.com>
Thu, 2 Apr 2009 00:12:22 +0000 (00:12 +0000)
committerApple <opensource@apple.com>
Thu, 2 Apr 2009 00:12:22 +0000 (00:12 +0000)
Makefile
hfs_util/Info.plist
hfs_util/hfs.util.8
hfs_util/hfsutil_jnl.c
hfs_util/hfsutil_main.c

index f4a89c6daa80e6c6a1a19177dbb6ce6febb3d8b6..786ad47a3cc339c34dae93e182e327ae16527750 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@ DEBUG_LIBS = $(LIBS)
 PROF_LIBS = $(LIBS)
 
 
-NEXTSTEP_PB_CFLAGS = -Wno-four-char-constants -Wall -Werror
+NEXTSTEP_PB_CFLAGS = -Wno-four-char-constants -Wall -Werror -D_DARWIN_USE_64_BIT_INODE
 
 
 NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
index 25d070e4defe796c522ab658eaba8c9e89f03ebe..0b88b4ca71547862604c0d839ce80fa9471100f2 100644 (file)
        <key>CFBundlePackageType</key>
        <string>fs  </string>
        <key>CFBundleShortVersionString</key>
-       <string>1.5.1</string>
+       <string>1.6.0</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>1.5</string>
+       <string>1.6</string>
        <key>FSMediaTypes</key>
        <dict>
-                <key>Apple_Boot</key>
-                <dict>
-                        <key>FSMediaProperties</key>
-                        <dict>
-                                <key>Content Hint</key>
-                                <string>Apple_Boot</string>
-                                <key>Leaf</key>
-                                <true/>
-                        </dict>
-                        <key>FSProbeArguments</key>
-                        <string>-p</string>
-                        <key>FSProbeExecutable</key>
-                        <string>../../hfs.util</string>
-                        <key>FSProbeOrder</key>
-                        <integer>1000</integer>
-                        <key>autodiskmount</key>
-                        <false/>
-                </dict>
+               <key>Apple_Boot</key>
+               <dict>
+                       <key>FSMediaProperties</key>
+                       <dict>
+                               <key>Content Hint</key>
+                               <string>Apple_Boot</string>
+                               <key>Leaf</key>
+                               <true/>
+                       </dict>
+                       <key>FSProbeArguments</key>
+                       <string>-p</string>
+                       <key>FSProbeExecutable</key>
+                       <string>../../hfs.util</string>
+                       <key>FSProbeOrder</key>
+                       <integer>1000</integer>
+                       <key>autodiskmount</key>
+                       <false/>
+               </dict>
                <key>426F6F74-0000-11AA-AA11-00306543ECAC</key>
-                <dict>
-                        <key>FSMediaProperties</key>
-                        <dict>
-                                <key>Content Hint</key>
-                                <string>426F6F74-0000-11AA-AA11-00306543ECAC</string>
-                                <key>Leaf</key>
-                                <true/>
-                        </dict>
-                        <key>FSProbeArguments</key>
-                        <string>-p</string>
-                        <key>FSProbeExecutable</key>
-                        <string>../../hfs.util</string>
-                        <key>FSProbeOrder</key>
-                        <integer>1000</integer>
-                        <key>autodiskmount</key>
-                        <false/>
-                </dict>
+               <dict>
+                       <key>FSMediaProperties</key>
+                       <dict>
+                               <key>Content Hint</key>
+                               <string>426F6F74-0000-11AA-AA11-00306543ECAC</string>
+                               <key>Leaf</key>
+                               <true/>
+                       </dict>
+                       <key>FSProbeArguments</key>
+                       <string>-p</string>
+                       <key>FSProbeExecutable</key>
+                       <string>../../hfs.util</string>
+                       <key>FSProbeOrder</key>
+                       <integer>1000</integer>
+                       <key>autodiskmount</key>
+                       <false/>
+               </dict>
                <key>48465300-0000-11AA-AA11-00306543ECAC</key>
                <dict>
                        <key>FSMediaProperties</key>
        <dict>
                <key>HFS</key>
                <dict>
-                       <key>FSFormatArguments</key>
-                       <string>-h</string>
-                       <key>FSFormatContentMask</key>
-                       <string>Apple_HFS</string>
-                       <key>FSFormatExecutable</key>
-                       <string>../../../../../../sbin/newfs_hfs</string>
-                       <key>FSFormatMinimumSize</key>
-                       <integer>524288</integer>
-                       <key>FSFormatMaximumSize</key>
-                       <integer>1073741824</integer>
                        <key>FSMountArguments</key>
                        <string></string>
                        <key>FSMountExecutable</key>
                        <string>-n</string>
                        <key>FSVerificationExecutable</key>
                        <string>../../../../../../sbin/fsck_hfs</string>
-                       <key>FSDoesVerifyLive</key>
-                       <false/>
                </dict>
                <key>HFS+</key>
                <dict>
                        <string>-fn</string>
                        <key>FSVerificationExecutable</key>
                        <string>../../../../../../sbin/fsck_hfs</string>
-                       <key>FSDoesVerifyLive</key>
-                       <false/>
                </dict>
                <key>Journaled HFS+</key>
                <dict>
                        <string>-fn</string>
                        <key>FSVerificationExecutable</key>
                        <string>../../../../../../sbin/fsck_hfs</string>
-                       <key>FSDoesVerifyLive</key>
-                       <true/>
                        <key>FSLiveVerificationArguments</key>
                        <string>-l</string>
                </dict>
                        <string>-fn</string>
                        <key>FSVerificationExecutable</key>
                        <string>../../../../../../sbin/fsck_hfs</string>
-                       <key>FSDoesVerifyLive</key>
-                       <false/>
                </dict>
                <key>Case-sensitive Journaled HFS+</key>
                <dict>
                        <string>-fn</string>
                        <key>FSVerificationExecutable</key>
                        <string>../../../../../../sbin/fsck_hfs</string>
-                       <key>FSDoesVerifyLive</key>
-                       <true/>
                        <key>FSLiveVerificationArguments</key>
                        <string>-l</string>
                </dict>
index dd6ab4c10ed39ebaef2ad6c34cedea25510400f5..4e73fffa3be35ffda141e74458ff4055f6c2a426 100644 (file)
@@ -1,4 +1,4 @@
-.\""Copyright (c) 2001 Apple Computer, Inc. All Rights Reserved.
+.\""Copyright (c) 2001-2008 Apple Inc. All Rights Reserved.
 .\"The contents of this file constitute Original Code as defined in and are 
 .\"subject to the Apple Public Source License Version 1.2 (the 'License'). 
 .\"You may not use this file except in compliance with the
 .Ar mountpoint
 .Pp
 .Nm
+.Fl N
+.Ar device
+.Pp
+.Nm
 .Fl I
 .Ar mountpoint
 .Pp
@@ -88,6 +92,9 @@ onto
 with the flags
 .Ar mountflag1 mountflag2 mountflag3 mountflag4 .
 This is a deprecated option.
+.It Fl N
+Disable journaling on a HFS+ file system located at 
+.Ar device
 .It Fl p
 Probe the
 .Ar device
@@ -101,7 +108,7 @@ HFS file system at
 Unmount the HFS file system located at
 .Ar device
 .It Fl U 
-Disable journaling on the HFS file system mounted on
+Disable journaling on the HFS+ file system mounted on
 .Ar mountpoint
 .El
 .Pp
index f83536dfdbc2c4ec7917caaf5bd7a0cb5e642108..babee482709e684b442ce32b81d8ec44ca4fc2d3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2001 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2008 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -44,6 +44,8 @@
 #include <hfs/hfs_format.h>
 #include <hfs/hfs_mount.h>    /* for hfs sysctl values */
 
+#include <System/hfs/hfs_fsctl.h>
+
 #include <errno.h>
 #include <fcntl.h>
 #include <libgen.h>
@@ -73,6 +75,14 @@ struct ExtentsAttrBuf {
 };
 typedef struct ExtentsAttrBuf ExtentsAttrBuf;
 
+#ifndef HFSIOC_GET_JOURNAL_INFO
+# include <sys/ioctl.h>
+struct hfs_journal_info {
+       off_t   jstart;
+       off_t   jsize;
+};
+# define HFSIOC_GET_JOURNAL_INFO       _IOR('h', 17, struct hfs_journal_info)
+#endif
 
 
 #define kIsInvisible 0x4000
@@ -168,7 +178,7 @@ get_start_block(const char *file, uint32_t fs_block_size)
     //printf("%s start offset %lld; byte len %lld (blksize %d)\n",
     // file, phys_start, len, fs_block_size);
 
-    if ((phys_start / (unsigned)fs_block_size) & 0xffffffff00000000LL) {
+    if ((phys_start / (unsigned int)fs_block_size) & 0xffffffff00000000LL) {
        fprintf(stderr, "%s : starting block is > 32bits!\n", file);
        return -1;
     }
@@ -190,8 +200,11 @@ get_start_block(const char *file, uint32_t fs_block_size)
 #define HFS_PRI_SECTOR(blksize)          (1024 / (blksize))
 #define HFS_PRI_OFFSET(blksize)          ((blksize) > 1024 ? 1024 : 0)
 
+#include <libkern/OSByteOrder.h>
+
 #define SWAP_BE16(x) ntohs(x)
 #define SWAP_BE32(x) ntohl(x)
+#define SWAP_BE64(x) OSSwapConstInt64(x)
 
 
 off_t
@@ -224,10 +237,9 @@ get_embedded_offset(char *devname)
            goto out;
        }
 
-       // copy the "/dev/"
-       strncpy(rawdev, sfs.f_mntfromname, 5);
-       rawdev[5] = 'r';
-       strcpy(&rawdev[6], &sfs.f_mntfromname[5]);
+       // This assumes it begins with "/dev/".  The old code assumed
+       // it began with five characters.  Should probably use strrchr or equivalent.
+       snprintf(rawdev, sizeof(rawdev), "/dev/r%s", &sfs.f_mntfromname[5]);
        devname = &rawdev[0];
        goto restart;
     }
@@ -350,7 +362,11 @@ DoMakeJournaled(char *volname, int jsize)
     // If that's ok then we try to create a symlink (which won't
     // work on plain hfs volumes but will work on hfs+ volumes).
     //
-    sprintf(tmpname, "%s/is_vol_hfs_plus", volname);
+    if (strcmp(sfs.f_fstypename, "devfs") == 0) {
+       fprintf (stderr, "%s is a device node.  Journal enable only works on a mounted HFS+ volume.\n", volname);
+               return 10;
+    }
+    snprintf(tmpname, sizeof(tmpname), "%s/is_vol_hfs_plus", volname);
     if (strcmp(sfs.f_fstypename, "hfs") != 0 ||
        ((ret = symlink(tmpname, tmpname)) != 0 && errno == ENOTSUP)) {
        fprintf(stderr, "%s is not an HFS+ volume.  Journaling only works on HFS+ volumes.\n",
@@ -373,7 +389,7 @@ DoMakeJournaled(char *volname, int jsize)
        // we want at least 8 megs of journal for each 100 gigs of
        // disk space.  We cap the size at 512 megs though.
        //
-       scale = ((long long)sfs.f_bsize * (long long)((unsigned)sfs.f_blocks)) / (100*1024*1024*1024ULL);
+       scale = ((long long)sfs.f_bsize * (long long)((unsigned int)sfs.f_blocks)) / (100*1024*1024*1024ULL);
        journal_size *= (scale + 1);
        if (journal_size > 512 * 1024 * 1024) {
            journal_size = 512 * 1024 * 1024;
@@ -474,8 +490,8 @@ DoMakeJournaled(char *volname, int jsize)
 
     memset(&jib, 'Z', sizeof(jib));
     jib.flags  = kJIJournalInFSMask;
-    jib.offset = (off_t)((unsigned)jstart_block) * (off_t)((unsigned)block_size);
-    jib.size   = (off_t)((unsigned)journal_size);
+    jib.offset = (off_t)((unsigned int)jstart_block) * (off_t)((unsigned int)block_size);
+    jib.size   = (off_t)((unsigned int)journal_size);
 
     fd = open(jib_fname, O_CREAT|O_TRUNC|O_RDWR, 000);
     if (fd < 0) {
@@ -561,8 +577,13 @@ DoUnJournal(char *volname)
        return 10;
     }
 
+    if (strcmp(sfs.f_fstypename, "hfs") != 0) {
+       fprintf(stderr, "Volume %s (%s) is not a HFS volume.\n", volname, sfs.f_mntfromname);
+               return 1;
+    }
+
     if ((sfs.f_flags & MNT_JOURNALED) == 0) {
-       fprintf(stderr, "Volume %s is not journaled.\n", volname);
+       fprintf(stderr, "Volume %s (%s) is not journaled.\n", volname, sfs.f_mntfromname);
        return 1;
     }
 
@@ -584,35 +605,240 @@ DoUnJournal(char *volname)
        return 20;
     }
 
-    sprintf(jbuf, "%s/%s", volname, journal_fname);
+    snprintf(jbuf, sizeof(jbuf), "%s/%s", volname, journal_fname);
     if (unlink(jbuf) != 0) {
        fprintf(stderr, "Failed to remove the journal %s (%s)\n",
                jbuf, strerror(errno));
     }
 
-    sprintf(jbuf, "%s/%s", volname, jib_fname);
+    snprintf(jbuf, sizeof(jbuf), "%s/%s", volname, jib_fname);
     if (unlink(jbuf) != 0) {
        fprintf(stderr, "Failed to remove the journal info block %s (%s)\n",
                jbuf, strerror(errno));
     }
 
-    printf("Journaling disabled on %s\n", volname);
+    printf("Journaling disabled on %s mounted at %s.\n", sfs.f_mntfromname, volname);
            
     return 0;
 }
 
 
+
+
+int
+get_journal_info(char *devname, struct JournalInfoBlock *jib)
+{
+       int fd = -1, ret = 0;
+       char *buff = NULL, *buff2 = NULL;
+       u_int64_t disksize;
+       u_int64_t blkcnt;
+       u_int32_t blksize;
+       daddr_t   mdb_offset;
+       HFSMasterDirectoryBlock *mdbp;
+       HFSPlusVolumeHeader *vhp;
+       off_t embeddedOffset, pos;
+       struct JournalInfoBlock *myjib;
+
+       fd = open(devname, O_RDONLY);
+       if (fd < 0) {
+               printf("can't open: %s (%s)\n", devname, strerror(errno));
+               ret = -5;
+               goto out;
+       }
+
+       /* Get the real physical block size. */
+       if (ioctl(fd, DKIOCGETBLOCKSIZE, (caddr_t)&blksize) != 0) {
+               printf("can't get the device block size (%s). assuming 512\n", strerror(errno));
+               blksize = 512;
+               ret = -1;
+               goto out;
+       }
+
+       /* Get the number of physical blocks. */
+       if (ioctl(fd, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt)) {
+               struct stat st;
+               printf("failed to get block count. trying stat().\n");
+               if (fstat(fd, &st) != 0) {
+                       ret = -1;
+                       goto out;
+               }
+
+               blkcnt = st.st_size / blksize;
+       }
+
+       /* Compute an accurate disk size */
+       disksize = blkcnt * (u_int64_t)blksize;
+
+       /*
+        * There are only 31 bits worth of block count in
+        * the buffer cache.  So for large volumes a 4K
+        * physical block size is needed.
+        */
+       if (blksize == 512 && blkcnt > (u_int64_t)0x000000007fffffff) {
+               blksize = 4096;
+       }
+
+       /*
+        * At this point:
+        *   blksize has our prefered physical block size
+        *   blkcnt has the total number of physical blocks
+        */
+
+       buff  = (char *)malloc(blksize);
+       buff2 = (char *)malloc(blksize);
+       
+       if (pread(fd, buff, blksize, HFS_PRI_SECTOR(blksize)*blksize) != blksize) {
+               printf("failed to read volume header @ offset %d (%s)\n",
+                      HFS_PRI_SECTOR(blksize), strerror(errno));
+               ret = -1;
+               goto out;
+       }
+
+       if (blksize == 512) {
+               mdbp = (HFSMasterDirectoryBlock *)buff;
+       } else {
+               mdbp = (HFSMasterDirectoryBlock *)(buff + 1024);
+       }
+
+       mdbp->drSigWord = SWAP_BE16(mdbp->drSigWord);
+       mdbp->drEmbedSigWord = SWAP_BE16(mdbp->drEmbedSigWord);
+       mdbp->drAlBlSt = SWAP_BE16(mdbp->drAlBlSt);
+       mdbp->drEmbedExtent.startBlock = SWAP_BE16(mdbp->drEmbedExtent.startBlock);
+       mdbp->drAlBlkSiz = SWAP_BE32(mdbp->drAlBlkSiz);
+       mdbp->drEmbedExtent.blockCount = SWAP_BE16(mdbp->drEmbedExtent.blockCount);
+       
+       // first check if it's even hfs at all...
+       if (   mdbp->drSigWord != kHFSSigWord
+              && mdbp->drSigWord != kHFSPlusSigWord
+              && mdbp->drSigWord != kHFSXSigWord) {
+
+               ret = -1;
+               goto out;
+       }
+
+       if ((mdbp->drSigWord == kHFSSigWord) && (mdbp->drEmbedSigWord != kHFSPlusSigWord)) {
+               // normal hfs can not ever be journaled
+               goto out;
+       } 
+       
+       /* Get the embedded Volume Header */
+       if (mdbp->drEmbedSigWord == kHFSPlusSigWord) {
+               embeddedOffset = mdbp->drAlBlSt * 512;
+               embeddedOffset += (u_int64_t)mdbp->drEmbedExtent.startBlock *
+                       (u_int64_t)mdbp->drAlBlkSiz;
+
+               /*
+                * If the embedded volume doesn't start on a block
+                * boundary, then switch the device to a 512-byte
+                * block size so everything will line up on a block
+                * boundary.
+                */
+               if ((embeddedOffset % blksize) != 0) {
+                       printf("HFS Mount: embedded volume offset not"
+                              " a multiple of physical block size (%d);"
+                              " switching to 512\n", blksize);
+               
+                       blkcnt  *= (blksize / 512);
+                       blksize  = 512;
+               }
+
+               disksize = (u_int64_t)mdbp->drEmbedExtent.blockCount *
+                       (u_int64_t)mdbp->drAlBlkSiz;
+
+               mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize);
+               if (pread(fd, buff, blksize, mdb_offset * blksize) != blksize) {
+                       printf("failed to read the embedded vhp @ offset %d\n", mdb_offset * blksize);
+                       ret = -1;
+                       goto out;
+               }
+
+               vhp = (HFSPlusVolumeHeader*) buff;
+       } else /* pure HFS+ */ {
+               embeddedOffset = 0;
+               vhp = (HFSPlusVolumeHeader*) mdbp;
+       }
+
+       if ((SWAP_BE32(vhp->attributes) & kHFSVolumeJournaledMask) == 0) {
+               ret = 0;
+               goto out;
+       }
+
+       //
+       // Now read the journal info block... (when calculating the
+       // position, make sure to cast to unsigned first, then to
+       // off_t so that things don't get sign-extended improperly
+       // or truncated).
+       //
+       pos = (off_t)((off_t)embeddedOffset +
+                     (off_t)((unsigned int)SWAP_BE32(vhp->journalInfoBlock))*(off_t)((unsigned int)SWAP_BE32(vhp->blockSize)));
+
+       if (pread(fd, buff2, blksize, pos) != blksize) {
+               printf("failed to read the journal info block (%s).\n", strerror(errno));
+               ret = -1;
+               goto out;
+       }
+
+       myjib = (struct JournalInfoBlock *)buff2;
+       myjib->flags  = SWAP_BE32(myjib->flags);
+       myjib->offset = SWAP_BE64(myjib->offset);
+       myjib->size   = SWAP_BE64(myjib->size);
+       
+       memcpy(jib, myjib, sizeof(*myjib));
+       
+       ret = 1;
+
+out:
+       if (buff)
+               free(buff);
+       if (buff2)
+               free(buff2);
+       if (fd >= 0) 
+               close(fd);
+
+       return ret;
+}
+
+
 int
 DoGetJournalInfo(char *volname)
 {
-    int           result;
-    int           sysctl_info[8];
     struct statfs sfs;
-    off_t         jstart, jsize;
+    struct hfs_journal_info jinfo;
        
+    if (strncmp(volname, "/dev/", 5) == 0 || strncmp(volname, "disk", 4) == 0 || strncmp(volname, "rdisk", 5) == 0) {
+           struct JournalInfoBlock jib;
+           int ret;
+           char fulldevname[256];
+
+           if (strncmp(volname, "disk", 4) == 0 || strncmp(volname, "rdisk", 5) == 0) {
+                   snprintf(fulldevname, sizeof(fulldevname), "/dev/%s", volname);
+                   volname = &fulldevname[0];
+           }
+           
+           // try the name as a device name...
+           ret = get_journal_info(volname, &jib);
+           if (ret == 0) {
+                   printf("Volume %s is not journaled.\n", volname);
+                   return 0;
+           } else if (ret < 0) {
+                   printf("Volume %s does not appear to be an HFS+ volume.\n", volname);
+                   return 10;
+           } else {
+               if (jib.flags & kJIJournalInFSMask) {
+                       printf("%s : journal size %lld k at offset 0x%llx\n", volname, jib.size/1024, jib.offset);
+               } else {
+                       printf("%s: external journal stored on partition with uuid %s on machine w/serial number %s\n",
+                              volname, jib.ext_jnl_uuid, jib.machine_serial_num);
+               }
+
+               return 0;
+           }
+
+    }
+
     if (statfs(volname, &sfs) != 0) {
-       fprintf(stderr, "Can't stat volume %s (%s).\n", volname, strerror(errno));
-       return 10;
+           fprintf(stderr, "Unable to get fs info for %s\n", volname);
+           return 10;
     }
 
     if ((sfs.f_flags & MNT_JOURNALED) == 0) {
@@ -620,30 +846,26 @@ DoGetJournalInfo(char *volname)
        return 1;
     }
 
-    if (chdir(volname) != 0) {
-       fprintf(stderr, "Can't cd to volume %s to get journal info (%s).\n",
-               volname, strerror(errno));
-       return 10;
-    }
-       
-    memset(sysctl_info, 0, sizeof(sysctl_info));
-    sysctl_info[0] = CTL_VFS;
-    sysctl_info[1] = sfs.f_fsid.val[1];
-    sysctl_info[2] = HFS_GET_JOURNAL_INFO;
-    sysctl_info[3] = (int)&jstart;
-    sysctl_info[4] = (int)&jsize;
-       
-    result = sysctl((void *)sysctl_info, 5, NULL, NULL, NULL, 0);
-    if (result != 0) {
+    if (fsctl(volname, HFSIOC_GET_JOURNAL_INFO,  &jinfo, 0) != 0) {
        fprintf(stderr, "Failed to get journal info for volume %s (%s)\n",
                volname, strerror(errno));
        return 20;
     }
 
-    if (jsize == 0) {
+    if (jinfo.jstart == 0) {
+           char rawdev[256];
+
+           snprintf(rawdev, sizeof(rawdev), "/dev/r%s", &sfs.f_mntfromname[5]);
+
+           // it's an external journal so get the info the
+           // other way.
+           return DoGetJournalInfo(&rawdev[0]);
+    }
+
+    if (jinfo.jsize == 0) {
        printf("%s : not journaled.\n", volname);
     } else {
-       printf("%s : journal size %lld k at offset 0x%llx\n", volname, jsize/1024, jstart);
+       printf("%s : journal size %lld k at offset 0x%llx\n", volname, jinfo.jsize/1024, jinfo.jstart);
     }
 
     return 0;
@@ -654,7 +876,7 @@ int
 RawDisableJournaling(char *devname)
 {
     int fd = -1, ret = 0;
-    char *buff = NULL, rawdev[256];
+    char *buff = NULL, rawdev[256], unrawdev[256];
     u_int64_t disksize;
     u_int64_t blkcnt;
     u_int32_t blksize;
@@ -662,41 +884,51 @@ RawDisableJournaling(char *devname)
     HFSMasterDirectoryBlock *mdbp;
     HFSPlusVolumeHeader *vhp;
     off_t embeddedOffset, hdr_offset;
-    struct statfs sfs;
     struct stat   st;
+    struct statfs *fsinfo;
        
-  restart:
-    if (stat(devname, &st) != 0) {
-       fprintf(stderr, "Could not access %s (%s)\n", devname, strerror(errno));
-       ret = -1;
-       goto out;
-    }
+       // assume that the name provided is a raw device name
+       strlcpy(rawdev, devname, sizeof(rawdev));
 
-    if (S_ISCHR(st.st_mode) == 0) {
-       // hmmm, it's not the character special raw device so we
-       // should try to figure out the real device.
-       if (S_ISBLK(st.st_mode)) {
-           strcpy(rawdev, "/dev/r");
-           strcat(rawdev, devname + 5);
+restart:
+       if (stat(rawdev, &st) != 0) {
+               fprintf(stderr, "Could not access %s (%s)\n", devname, strerror(errno));
+               ret = -1;
+               goto out;
+       }
+       
+       if (S_ISCHR(st.st_mode) == 0) {
+               if (S_ISBLK(st.st_mode)) {
+                       // this is a block device, convert the name to 
+                       // raw character device and try again
+                       snprintf(rawdev, sizeof(rawdev), "/dev/r%s", devname + 5);
+                       goto restart;
+               } else {
+                       // probably it is a mount point 
+                       return DoUnJournal(devname);
+               }
        } else {
-           if (statfs(devname, &sfs) != 0) {
-               fprintf(stderr, "Can't find out any info about the fs for path %s (%s)\n",
-                   devname, strerror(errno));
+               // convert the character raw device name to 
+               // block device name to compare with getmntinfo output
+               snprintf(unrawdev, sizeof(unrawdev), "/dev/%s", rawdev + 6);
+       }
+       
+       // make sure that the file system on the device node is not mounted
+       ret = getmntinfo(&fsinfo, MNT_NOWAIT);
+       if (ret == 0) {
+               fprintf (stderr, "Error getting list of mounted filesystems\n"); 
                ret = -1;
                goto out;
-           }
-
-           // copy the "/dev/"
-           strncpy(rawdev, sfs.f_mntfromname, 5);
-           rawdev[5] = 'r';
-           strcpy(&rawdev[6], &sfs.f_mntfromname[5]);
+       }
+       
+       while (ret--) {
+               // the file system on this device node is currently mounted
+               if (strcmp(unrawdev, fsinfo[ret].f_mntfromname) == 0) {
+                       return DoUnJournal(fsinfo[ret].f_mntonname);
+               }
        }
 
-       devname = &rawdev[0];
-       goto restart;
-    }
-
-    fd = open(devname, O_RDWR);
+    fd = open(rawdev, O_RDWR);
     if (fd < 0) {
        fprintf(stderr, "can't open: %s (%s)\n", devname, strerror(errno));
        ret = -1;
@@ -821,7 +1053,7 @@ RawDisableJournaling(char *devname)
            fprintf(stderr, "Turned off the journaling bit for %s\n", devname);
        }
     } else {
-       fprintf(stderr, "disable_journaling: volume was not journaled.\n");
+       fprintf(stderr, "disable_journaling: %s is not journaled.\n", devname);
     }
 
        
@@ -833,3 +1065,179 @@ RawDisableJournaling(char *devname)
 
     return ret;
 }
+
+
+
+int
+SetJournalInFSState(const char *devname, int journal_in_fs)
+{
+       int fd = -1, ret = 0;
+       char *buff = NULL, *buff2 = NULL;
+       u_int64_t blkcnt;
+       u_int32_t blksize;
+       daddr_t   mdb_offset;
+       HFSMasterDirectoryBlock *mdbp;
+       HFSPlusVolumeHeader *vhp;
+       off_t embeddedOffset, pos;
+       struct JournalInfoBlock *myjib;
+
+       fd = open(devname, O_RDWR);
+       if (fd < 0) {
+               printf("can't open: %s (%s)\n", devname, strerror(errno));
+               ret = -1;
+               goto out;
+       }
+
+       /* Get the real physical block size. */
+       if (ioctl(fd, DKIOCGETBLOCKSIZE, (caddr_t)&blksize) != 0) {
+               printf("can't get the device block size (%s). assuming 512\n", strerror(errno));
+               blksize = 512;
+               ret = -1;
+               goto out;
+       }
+
+       /* Get the number of physical blocks. */
+       if (ioctl(fd, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt)) {
+               struct stat st;
+               printf("failed to get block count. trying stat().\n");
+               if (fstat(fd, &st) != 0) {
+                       ret = -1;
+                       goto out;
+               }
+
+               blkcnt = st.st_size / blksize;
+       }
+
+       /*
+        * There used to only be 31 bits worth of block count in
+        * the buffer cache.  So for large volumes a 4K
+        * physical block size is needed.
+        */
+       if (blksize == 512 && blkcnt > (u_int64_t)0x000000007fffffff) {
+               blksize = 4096;
+       }
+
+       /*
+        * At this point:
+        *   blksize has our prefered physical block size
+        *   blkcnt has the total number of physical blocks
+        */
+
+       buff  = (char *)malloc(blksize);
+       buff2 = (char *)malloc(blksize);
+       
+       if (pread(fd, buff, blksize, HFS_PRI_SECTOR(blksize)*blksize) != blksize) {
+               printf("failed to read volume header @ offset %d (%s)\n",
+                          HFS_PRI_SECTOR(blksize), strerror(errno));
+               ret = -1;
+               goto out;
+       }
+
+       if (blksize == 512) {
+           mdbp = (HFSMasterDirectoryBlock *)buff;
+       } else {
+           mdbp = (HFSMasterDirectoryBlock *)(buff + 1024);
+       }
+
+       // first check if it's even hfs at all...
+       if (   SWAP_BE16(mdbp->drSigWord) != kHFSSigWord
+           && SWAP_BE16(mdbp->drSigWord) != kHFSPlusSigWord
+           && SWAP_BE16(mdbp->drSigWord) != kHFSXSigWord) {
+
+           ret = -1;
+           goto out;
+       }
+
+       if ((SWAP_BE16(mdbp->drSigWord) == kHFSSigWord) && (SWAP_BE16(mdbp->drEmbedSigWord) != kHFSPlusSigWord)) {
+               // normal hfs can not ever be journaled
+               goto out;
+       } 
+       
+       /* Get the embedded Volume Header */
+       if (SWAP_BE16(mdbp->drEmbedSigWord) == kHFSPlusSigWord) {
+           embeddedOffset = SWAP_BE16(mdbp->drAlBlSt) * 512;
+           embeddedOffset += (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.startBlock) *
+                             (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
+
+           /*
+            * If the embedded volume doesn't start on a block
+            * boundary, then switch the device to a 512-byte
+            * block size so everything will line up on a block
+            * boundary.
+            */
+           if ((embeddedOffset % blksize) != 0) {
+               printf("HFS Mount: embedded volume offset not"
+                      " a multiple of physical block size (%d);"
+                      " switching to 512\n", blksize);
+               
+               blkcnt  *= (blksize / 512);
+               blksize  = 512;
+           }
+
+           mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize);
+           if (pread(fd, buff, blksize, mdb_offset * blksize) != blksize) {
+               printf("failed to read the embedded vhp @ offset %d\n", mdb_offset * blksize);
+               ret = -1;
+               goto out;
+           }
+
+           vhp = (HFSPlusVolumeHeader*) buff;
+       } else /* pure HFS+ */ {
+           embeddedOffset = 0;
+           vhp = (HFSPlusVolumeHeader*) mdbp;
+       }
+
+       //printf("vol header attributes: 0x%x\n", SWAP_BE32(vhp->attributes));
+       if ((SWAP_BE32(vhp->attributes) & kHFSVolumeJournaledMask) == 0) {
+           ret = 0;
+           goto out;
+       }
+
+       //
+       // Now read the journal info block... (when calculating the
+       // position, make sure to cast to unsigned first, then to
+       // off_t so that things don't get sign-extended improperly
+       // or truncated).
+       //
+       pos = (off_t)((off_t)embeddedOffset +
+                     (off_t)((unsigned int )SWAP_BE32(vhp->journalInfoBlock))*(off_t)((unsigned int)SWAP_BE32(vhp->blockSize)));
+
+       if (pread(fd, buff2, blksize, pos) != blksize) {
+           printf("failed to read the journal info block (%s).\n", strerror(errno));
+           ret = -1;
+           goto out;
+       }
+
+       myjib = (struct JournalInfoBlock *)buff2;
+
+       // swap this to host native format so we can diddle with the bits
+       myjib->flags  = SWAP_BE32(myjib->flags);
+       
+       if (journal_in_fs) {
+               myjib->flags |= kJIJournalInFSMask;
+       } else {
+               myjib->flags &= ~kJIJournalInFSMask;
+       }
+       myjib->flags |= kJIJournalNeedInitMask;
+
+       // and now swap back before writing it out
+       myjib->flags  = SWAP_BE32(myjib->flags);
+       
+       if (pwrite(fd, buff2, blksize, pos) != blksize) {
+           printf("failed to re-write the journal info block (%s).\n", strerror(errno));
+           ret = -1;
+           goto out;
+       }
+
+       ret = 0;
+
+  out:
+       if (buff)
+               free(buff);
+       if (buff2)
+               free(buff2);
+       if (fd >= 0) 
+               close(fd);
+
+       return ret;
+}
index b39cbc3a1e21698233819d739f23a95a808abb46..22902a5c3d7d25e7358136e4c881e2d626cc5f22 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #define FSUC_UNJNL_RAW 'N'
 #endif
 
+#ifndef FSUC_JNLINFS_RAW
+#define FSUC_JNLINFS_RAW 'e'
+#endif
+
+#ifndef FSUC_EXTJNL_RAW
+#define FSUC_EXTJNL_RAW 'E'
+#endif
+
 #ifndef FSUC_JNLINFO
 #define FSUC_JNLINFO 'I'
 #endif
@@ -149,17 +157,17 @@ int gJournalSize = 0;
 
 
 struct FinderAttrBuf {
-       unsigned long info_length;
-       unsigned long finderinfo[8];
+       u_int32_t info_length;
+       u_int32_t finderinfo[8];
 };
 
 
 #define VOLUMEUUIDVALUESIZE 2
 typedef union VolumeUUID {
-       unsigned long value[VOLUMEUUIDVALUESIZE];
+       u_int32_t value[VOLUMEUUIDVALUESIZE];
        struct {
-               unsigned long high;
-               unsigned long low;
+               u_int32_t high;
+               u_int32_t low;
        } v;
 } VolumeUUID;
 
@@ -195,6 +203,7 @@ extern int  DoMakeJournaled( const char * volNamePtr, int journalSize );  // XXX
 extern int  DoUnJournal( const char * volNamePtr );      // XXXdbg
 extern int  DoGetJournalInfo( const char * volNamePtr );
 extern int  RawDisableJournaling( const char *devname );
+extern int  SetJournalInFSState( const char *devname, int journal_in_fs);
 
 static int     ParseArgs( int argc, const char * argv[], const char ** actionPtr, const char ** mountPointPtr, boolean_t * isEjectablePtr, boolean_t * isLockedPtr, boolean_t * isSetuidPtr, boolean_t * isDevPtr );
 
@@ -244,8 +253,8 @@ static unsigned int __CFStringGetDefaultEncodingForHFSUtil() {
         char buffer[MAXPATHLEN + 1];
         int fd;
 
-        strcpy(buffer, passwdp->pw_dir);
-        strcat(buffer, __kCFUserEncodingFileName);
+        strlcpy(buffer, passwdp->pw_dir, sizeof(buffer));
+        strlcat(buffer, __kCFUserEncodingFileName, sizeof(buffer));
 
         if ((fd = open(buffer, O_RDONLY, 0)) > 0) {
             size_t readSize;
@@ -341,7 +350,7 @@ static int load_encoding(CFStringEncoding encoding)
                return FSUR_LOADERR;
        }
        
-       sprintf(kmodfile, "%sHFS_Mac%s.kext", ENCODING_MODULE_PATH, encodingName);
+       snprintf(kmodfile, sizeof(kmodfile), "%sHFS_Mac%s.kext", ENCODING_MODULE_PATH, encodingName);
        if (stat(kmodfile, &sb) == -1)
        {
                /* We recognized the encoding, but couldn't find the KEXT */
@@ -407,8 +416,8 @@ int main (int argc, const char *argv[])
     --   "/dev/disk0s2"
     */
 
-    sprintf(rawDeviceName, "/dev/r%s", argv[2]);
-    sprintf(blockDeviceName, "/dev/%s", argv[2]);
+    snprintf(rawDeviceName, sizeof(rawDeviceName), "/dev/r%s", argv[2]);
+    snprintf(blockDeviceName, sizeof(blockDeviceName), "/dev/%s", argv[2]);
 
     /* call the appropriate routine to handle the given action argument after becoming root */
 
@@ -456,6 +465,19 @@ int main (int argc, const char *argv[])
                        result = RawDisableJournaling( argv[2] );
                        break;
                        
+               case FSUC_JNLINFS_RAW:
+                       // argv[2] has the device for the external journal.  however
+                       // we don't need it so we ignore it and just pass argv[3]
+                       // which is the hfs volume whose state we're going to change
+                       //
+                       result = SetJournalInFSState( argv[3], 1 );
+                       break;
+                       
+               case FSUC_EXTJNL_RAW:
+                       // see the comment for FSUC_JNLINFS_RAW
+                       result = SetJournalInFSState( argv[3], 0 );
+                       break;
+                       
                case FSUC_JNLINFO:
                        result = DoGetJournalInfo( argv[2] );
                        break;
@@ -583,7 +605,7 @@ DoMount(char *deviceNamePtr, const char *mountPointPtr, boolean_t isLocked, bool
 #else
                encoding = CFStringGetSystemEncoding();
 #endif
-               sprintf(encodeopt, "-e=%d", (int)encoding);
+               snprintf(encodeopt, sizeof(encodeopt), "-e=%d", (int)encoding);
 #if TRACE_HFS_UTIL
                fprintf(stderr, "hfs.util: %s %s -o -x -o %s -o %s -o -u=unknown,-g=unknown,-m=0777 -t %s %s %s ...\n",
                                                        gMountCommand, isLockedstr, encodeopt, permissionsOption, gHFS_FS_NAME, deviceNamePtr, mountPointPtr);
@@ -788,6 +810,10 @@ DoProbe(char *rawDeviceNamePtr, char *blockDeviceNamePtr)
 
                cfstr = CFStringCreateWithPascalString(kCFAllocatorDefault,
                            mdbPtr->drVN, encoding);
+               if (cfstr == NULL) {
+                       result = FSUR_INVAL;
+                       goto Return;
+               }
                cfOK = _CFStringGetFileSystemRepresentation(cfstr, volnameUTF8, NAME_MAX);
                CFRelease(cfstr);
 
@@ -834,14 +860,6 @@ DoProbe(char *rawDeviceNamePtr, char *blockDeviceNamePtr)
        }
 
        if (FSUR_IO_SUCCESS == result) {
-               unsigned char *s;
-               
-               /* Change slashes to colons in the volume name */
-               for (s=volnameUTF8; *s; ++s) {
-                       if (*s == '/')
-                               *s = ':';
-               }
-
                /* Print the volume name to standard output */
                write(1, volnameUTF8, strlen((char *)volnameUTF8));
                result = FSUR_RECOGNIZED;
@@ -1173,6 +1191,16 @@ ParseArgs(int argc, const char *argv[], const char ** actionPtr,
                        doLengthCheck = 0;
                        break;
 
+               case FSUC_JNLINFS_RAW:
+                       index = 0;
+                       doLengthCheck = 0;
+                       break;
+
+               case FSUC_EXTJNL_RAW:
+                       index = 0;
+                       doLengthCheck = 0;
+                       break;
+
                case FSUC_JNLINFO:
                        index = 0;
                        doLengthCheck = 0;
@@ -1267,6 +1295,8 @@ DoDisplayUsage(const char *argv[])
        printf("       -%c (Make a file system journaled)\n", FSUC_MKJNL);
        printf("       -%c (Turn off journaling on a file system)\n", FSUC_UNJNL);
        printf("       -%c (Turn off journaling on a raw device)\n", FSUC_UNJNL_RAW);
+       printf("       -%c (Disable use of an external journal on a raw device)\n", FSUC_JNLINFS_RAW);
+       printf("       -%c (Enable the use of an external journal on a raw device)\n", FSUC_EXTJNL_RAW);
        printf("       -%c (Get size & location of journaling on a file system)\n", FSUC_JNLINFO);
     printf("device_arg:\n");
     printf("       device we are acting upon (for example, 'disk0s2')\n");
@@ -1874,6 +1904,16 @@ GetNameFromHFSPlusVolumeStartingAt(int fd, off_t hfsPlusVolumeOffset, unsigned c
             goto Return;
         }
 
+       if ((OSSwapBigToHostInt16(k->nodeName.length) >
+               (sizeof(k->nodeName.unicode) / sizeof(k->nodeName.unicode[0]))) ||
+               OSSwapBigToHostInt16(k->nodeName.length) < 0) {
+               result = FSUR_IO_FAIL;
+#if TRACE_HFS_UTIL
+               fprintf(stderr, "hfs.util: ERROR:  k->nodeName.length is a bad size (%d)\n", OSSwapBigToHostInt16(k->nodeName.length));
+#endif
+               goto Return;
+       }
+
        /* Extract the name of the root directory */
 
        {
@@ -1915,12 +1955,10 @@ Return:
 } /* GetNameFromHFSPlusVolumeStartingAt */
 
 
-#pragma options align=mac68k
 typedef struct {
        BTNodeDescriptor        node;
        BTHeaderRec             header;
-} HeaderRec, *HeaderPtr;
-#pragma options align=reset
+} __attribute__((aligned(2), packed)) HeaderRec, *HeaderPtr;
 
 /*
  --    
@@ -2531,10 +2569,10 @@ void GenerateVolumeUUID(VolumeUUID *newVolumeID) {
 void ConvertVolumeUUIDStringToUUID(const char *UUIDString, VolumeUUID *volumeID) {
        int i;
        char c;
-       unsigned long nextdigit;
-       unsigned long high = 0;
-       unsigned long low = 0;
-       unsigned long carry;
+       u_int32_t nextdigit;
+       u_int32_t high = 0;
+       u_int32_t low = 0;
+       u_int32_t carry;
        
        for (i = 0; (i < VOLUMEUUIDLENGTH) && ((c = UUIDString[i]) != (char)0) ; ++i) {
                if ((c >= '0') && (c <= '9')) {