From ab40a2da39ee6a5080bc926494d42a74970ff044 Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 2 Apr 2009 00:12:22 +0000 Subject: [PATCH 1/1] hfs-183.tar.gz --- Makefile | 2 +- hfs_util/Info.plist | 94 +++---- hfs_util/hfs.util.8 | 11 +- hfs_util/hfsutil_jnl.c | 538 +++++++++++++++++++++++++++++++++++----- hfs_util/hfsutil_main.c | 92 +++++-- 5 files changed, 585 insertions(+), 152 deletions(-) diff --git a/Makefile b/Makefile index f4a89c6..786ad47 100644 --- 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 diff --git a/hfs_util/Info.plist b/hfs_util/Info.plist index 25d070e..0b88b4c 100644 --- a/hfs_util/Info.plist +++ b/hfs_util/Info.plist @@ -13,49 +13,49 @@ CFBundlePackageType fs CFBundleShortVersionString - 1.5.1 + 1.6.0 CFBundleSignature ???? CFBundleVersion - 1.5 + 1.6 FSMediaTypes - Apple_Boot - - FSMediaProperties - - Content Hint - Apple_Boot - Leaf - - - FSProbeArguments - -p - FSProbeExecutable - ../../hfs.util - FSProbeOrder - 1000 - autodiskmount - - + Apple_Boot + + FSMediaProperties + + Content Hint + Apple_Boot + Leaf + + + FSProbeArguments + -p + FSProbeExecutable + ../../hfs.util + FSProbeOrder + 1000 + autodiskmount + + 426F6F74-0000-11AA-AA11-00306543ECAC - - FSMediaProperties - - Content Hint - 426F6F74-0000-11AA-AA11-00306543ECAC - Leaf - - - FSProbeArguments - -p - FSProbeExecutable - ../../hfs.util - FSProbeOrder - 1000 - autodiskmount - - + + FSMediaProperties + + Content Hint + 426F6F74-0000-11AA-AA11-00306543ECAC + Leaf + + + FSProbeArguments + -p + FSProbeExecutable + ../../hfs.util + FSProbeOrder + 1000 + autodiskmount + + 48465300-0000-11AA-AA11-00306543ECAC FSMediaProperties @@ -141,16 +141,6 @@ HFS - FSFormatArguments - -h - FSFormatContentMask - Apple_HFS - FSFormatExecutable - ../../../../../../sbin/newfs_hfs - FSFormatMinimumSize - 524288 - FSFormatMaximumSize - 1073741824 FSMountArguments FSMountExecutable @@ -167,8 +157,6 @@ -n FSVerificationExecutable ../../../../../../sbin/fsck_hfs - FSDoesVerifyLive - HFS+ @@ -198,8 +186,6 @@ -fn FSVerificationExecutable ../../../../../../sbin/fsck_hfs - FSDoesVerifyLive - Journaled HFS+ @@ -229,8 +215,6 @@ -fn FSVerificationExecutable ../../../../../../sbin/fsck_hfs - FSDoesVerifyLive - FSLiveVerificationArguments -l @@ -262,8 +246,6 @@ -fn FSVerificationExecutable ../../../../../../sbin/fsck_hfs - FSDoesVerifyLive - Case-sensitive Journaled HFS+ @@ -293,8 +275,6 @@ -fn FSVerificationExecutable ../../../../../../sbin/fsck_hfs - FSDoesVerifyLive - FSLiveVerificationArguments -l diff --git a/hfs_util/hfs.util.8 b/hfs_util/hfs.util.8 index dd6ab4c..4e73fff 100644 --- a/hfs_util/hfs.util.8 +++ b/hfs_util/hfs.util.8 @@ -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 @@ -45,6 +45,10 @@ .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 diff --git a/hfs_util/hfsutil_jnl.c b/hfs_util/hfsutil_jnl.c index f83536d..babee48 100644 --- a/hfs_util/hfsutil_jnl.c +++ b/hfs_util/hfsutil_jnl.c @@ -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 #include /* for hfs sysctl values */ +#include + #include #include #include @@ -73,6 +75,14 @@ struct ExtentsAttrBuf { }; typedef struct ExtentsAttrBuf ExtentsAttrBuf; +#ifndef HFSIOC_GET_JOURNAL_INFO +# include +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 + #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; +} diff --git a/hfs_util/hfsutil_main.c b/hfs_util/hfsutil_main.c index b39cbc3..22902a5 100644 --- a/hfs_util/hfsutil_main.c +++ b/hfs_util/hfsutil_main.c @@ -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@ * @@ -110,6 +110,14 @@ #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')) { -- 2.45.2