From 08cdaae86a275aee493717d81387ca6b8f81800b Mon Sep 17 00:00:00 2001 From: Apple Date: Fri, 25 Oct 2002 19:51:46 +0000 Subject: [PATCH] hfs-116.10.tar.gz --- hfs_util/Info.plist | 31 +++- hfs_util/InfoPlist.strings | 5 + hfs_util/Makefile | 2 +- hfs_util/Makefile.postamble | 2 +- hfs_util/PB.project | 2 +- hfs_util/hfsutil_jnl.c | 359 ++++++++++++++++++++++++++++++++++++ hfs_util/hfsutil_main.c | 68 ++++++- 7 files changed, 461 insertions(+), 8 deletions(-) create mode 100644 hfs_util/hfsutil_jnl.c diff --git a/hfs_util/Info.plist b/hfs_util/Info.plist index 26b938c..f794579 100644 --- a/hfs_util/Info.plist +++ b/hfs_util/Info.plist @@ -13,11 +13,11 @@ CFBundlePackageType fs CFBundleShortVersionString - 1.1 + 1.2 CFBundleSignature ???? CFBundleVersion - 1.1 + 1.2 FSMediaTypes Apple_HFS @@ -96,6 +96,31 @@ FSVerificationExecutable ../../../../../../sbin/fsck_hfs + Journaled HFS+ + + FSFormatArguments + -J + FSFormatContentMask + Apple_HFS + FSFormatExecutable + ../../../../../../sbin/newfs_hfs + FSFormatMinimumSize + 4194304 + FSMountArguments + + FSMountExecutable + ../../../../../../sbin/mount_hfs + FSName + Mac OS Extended (Journaled) + FSRepairArguments + -y + FSRepairExecutable + ../../../../../../sbin/fsck_hfs + FSVerificationArguments + -fn + FSVerificationExecutable + ../../../../../../sbin/fsck_hfs + HFS+ FSFormatArguments @@ -117,7 +142,7 @@ FSRepairExecutable ../../../../../../sbin/fsck_hfs FSVerificationArguments - -n + -fn FSVerificationExecutable ../../../../../../sbin/fsck_hfs diff --git a/hfs_util/InfoPlist.strings b/hfs_util/InfoPlist.strings index 5a09ea5..a108b20 100644 --- a/hfs_util/InfoPlist.strings +++ b/hfs_util/InfoPlist.strings @@ -16,6 +16,11 @@ FSName Mac OS Extended + Journaled HFS+ + + FSName + Mac OS Extended (Journaled) + diff --git a/hfs_util/Makefile b/hfs_util/Makefile index e8bcb61..25e7f90 100644 --- a/hfs_util/Makefile +++ b/hfs_util/Makefile @@ -12,7 +12,7 @@ NAME = hfs.util PROJECTVERSION = 2.8 PROJECT_TYPE = Tool -CFILES = hfsutil_main.c +CFILES = hfsutil_main.c hfsutil_jnl.c OTHERSRCS = Makefile.preamble Makefile Makefile.postamble\ hfs_CD.fs.tiff hfs_CD.openfs.tiff hfs_FD.fs.tiff\ diff --git a/hfs_util/Makefile.postamble b/hfs_util/Makefile.postamble index 4b80f13..001327f 100644 --- a/hfs_util/Makefile.postamble +++ b/hfs_util/Makefile.postamble @@ -80,7 +80,7 @@ INSTALL_AS_USER = root # User/group ownership #INSTALL_AS_GROUP = wheel # (probably want to set both of these) -INSTALL_PERMISSIONS = 4555 +#INSTALL_PERMISSIONS = 4555 # If set, 'install' chmod's executable to this diff --git a/hfs_util/PB.project b/hfs_util/PB.project index b2c82cb..146a30e 100644 --- a/hfs_util/PB.project +++ b/hfs_util/PB.project @@ -8,7 +8,7 @@ FRAMEWORKSEARCH = (); H_FILES = (); M_FILES = (); - OTHER_LINKED = (hfsutil_main.c); + OTHER_LINKED = (hfsutil_main.c hfsutil_jnl.c); OTHER_SOURCES = ( Makefile.preamble, Makefile, diff --git a/hfs_util/hfsutil_jnl.c b/hfs_util/hfsutil_jnl.c new file mode 100644 index 0000000..c4b6b6e --- /dev/null +++ b/hfs_util/hfsutil_jnl.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 1999-2001 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + Copyright (c) 2002 Apple Computer, Inc. + All Rights Reserved. + + This file contains the routine to make an HFS+ volume journaled + and a corresponding routine to turn it off. + + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// +// Secret HFS sysctl's to instruct it to turn +// journaling on/off for a volume. +// +#define HFS_BECOME_JOURNALED 0x082969 +#define HFS_BECOME_UNJOURNALED 0x031272 + + +/* getattrlist buffers start with an extra length field */ +struct ExtentsAttrBuf { + unsigned long infoLength; + HFSPlusExtentRecord extents; +}; +typedef struct ExtentsAttrBuf ExtentsAttrBuf; + + + +#define kIsInvisible 0x4000 + +/* + * Generic Finder file/dir data + */ +struct FinderInfo { + u_int32_t opaque_1[2]; + u_int16_t fdFlags; /* Finder flags */ + int16_t opaque_2[11]; +}; +typedef struct FinderInfo FinderInfo; + +/* getattrlist buffers start with an extra length field */ +struct FinderAttrBuf { + unsigned long infoLength; + FinderInfo finderInfo; +}; +typedef struct FinderAttrBuf FinderAttrBuf; + + +int hide_file(const char * file) +{ + struct attrlist alist = {0}; + FinderAttrBuf finderInfoBuf = {0}; + int result; + + alist.bitmapcount = ATTR_BIT_MAP_COUNT; + alist.commonattr = ATTR_CMN_FNDRINFO; + + result = getattrlist(file, &alist, &finderInfoBuf, sizeof(finderInfoBuf), 0); + if (result) { + return (errno); + } + + if (finderInfoBuf.finderInfo.fdFlags & kIsInvisible) { + printf("hide: %s is alreadly invisible\n", file); + return (0); + } + + finderInfoBuf.finderInfo.fdFlags |= kIsInvisible; + + result = setattrlist(file, &alist, &finderInfoBuf.finderInfo, sizeof(FinderInfo), 0); + + return (result == -1 ? errno : result); +} + +int +get_start_block(const char *file) +{ + struct attrlist alist = {0}; + ExtentsAttrBuf extentsbuf = {0}; + + alist.bitmapcount = ATTR_BIT_MAP_COUNT; + alist.fileattr = ATTR_FILE_DATAEXTENTS; + + if (getattrlist(file, &alist, &extentsbuf, sizeof(extentsbuf), 0)) { + fprintf(stderr, "could not get attrlist for %s (%s)", file, strerror(errno)); + return -1; + } + + if (extentsbuf.extents[1].startBlock != 0) { + fprintf(stderr, "Journal File not contiguous!\n"); + return -1; + } + + return extentsbuf.extents[0].startBlock; +} + +static const char *journal_fname = ".journal"; +static const char *jib_fname = ".journal_info_block"; + +int +DoMakeJournaled(char *volname, int jsize) +{ + int fd, i, block_size, journal_size = 8*1024*1024; + char *buf; + int ret; + fstore_t fst; + int jstart_block, jinfo_block, sysctl_info[8]; + JournalInfoBlock jib; + struct statfs sfs; + static char tmpname[MAXPATHLEN]; + + if (jsize != 0) { + journal_size = jsize; + } + + if (statfs(volname, &sfs) != 0) { + fprintf(stderr, "Can't stat volume %s (%s).\n", volname, strerror(errno)); + return 10; + } + + // Make sure that we're HFS+. First we check the fstypename. + // 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, "hfs") != 0 || + ((ret = symlink(tmpname, tmpname)) != 0 && errno == ENOTSUP)) { + fprintf(stderr, "%s is not an HFS+ volume. Journaling only works on HFS+ volumes.\n", + volname); + return 10; + } + unlink(tmpname); + + if (sfs.f_flags & MNT_JOURNALED) { + fprintf(stderr, "Volume %s is already journaled.\n", volname); + return 1; + } + + if (chdir(volname) != 0) { + fprintf(stderr, "Can't locate volume %s to make it journaled (%s).\n", + volname, strerror(errno)); + return 10; + } + + fd = open(journal_fname, O_CREAT|O_TRUNC|O_RDWR, 000); + if (fd < 0) { + fprintf(stderr, "Can't create journal file on volume %s (%s)\n", + volname, strerror(errno)); + return 5; + } + + // make sure that it has no r/w/x privs (only could happen if + // the file already existed since open() doesn't reset the mode + // bits). + // + fchmod(fd, 0); + + block_size = sfs.f_bsize; + if ((journal_size % block_size) != 0) { + fprintf(stderr, "Journal size %dk is not a multiple of volume %s block size (%d).\n", + journal_size/1024, volname, block_size); + close(fd); + unlink(journal_fname); + return 5; + } + + memset(&fst, 0, sizeof(fst)); + fst.fst_flags = F_ALLOCATECONTIG|F_ALLOCATEALL; + fst.fst_length = journal_size; + fst.fst_posmode = F_PEOFPOSMODE; + + ret = fcntl(fd, F_PREALLOCATE, &fst); + if (ret < 0) { + fprintf(stderr, "Pre-allocating the journal file failed on volume %s (%s)\n", + volname, strerror(errno)); + fprintf(stderr, "Try using a smaller (%d k) journal size\n", journal_size/2/1024); + close(fd); + unlink(journal_fname); + return 10; + } + + printf("Allocated %lldK for journal file.\n", fst.fst_bytesalloc/1024LL); + buf = (char *)calloc(block_size, 1); + if (buf) { + for(i=0; i < journal_size/block_size; i++) { + ret = write(fd, buf, block_size); + if (ret != block_size) { + break; + } + } + + if (i*block_size != journal_size) { + fprintf(stderr, "Failed to write %dk to journal on volume %s (%s)\n", + journal_size/1024, volname, strerror(errno)); + } + } else { + printf("Could not allocate memory to write to the journal on volume %s (%s)\n", + volname, strerror(errno)); + } + + fsync(fd); + close(fd); + hide_file(journal_fname); + + jstart_block = get_start_block(journal_fname); + + memset(&jib, 0, sizeof(jib)); + jib.flags = kJIJournalInFSMask; + jib.offset = (off_t)jstart_block * (off_t)block_size; + jib.size = (off_t)journal_size; + + fd = open(jib_fname, O_CREAT|O_TRUNC|O_RDWR, 000); + if (fd < 0) { + fprintf(stderr, "Could not create journal info block file on volume %s (%s)\n", + volname, strerror(errno)); + unlink(journal_fname); + return 5; + } + + memcpy(buf, &jib, sizeof(jib)); + if (write(fd, buf, block_size) != block_size) { + fprintf(stderr, "Failed to write journal info block on volume %s (%s)!\n", + volname, strerror(errno)); + unlink(journal_fname); + return 10; + } + + fsync(fd); + close(fd); + hide_file(jib_fname); + + jinfo_block = get_start_block(jib_fname); + + + // + // Now make the volume journaled! + // + memset(sysctl_info, 0, sizeof(sysctl_info)); + sysctl_info[0] = CTL_VFS; + sysctl_info[1] = sfs.f_fsid.val[1]; + sysctl_info[2] = HFS_BECOME_JOURNALED; + sysctl_info[3] = jinfo_block; + sysctl_info[4] = jstart_block; + sysctl_info[5] = journal_size; + + //printf("fs type: 0x%x\n", sysctl_info[1]); + //printf("jinfo block : 0x%x\n", jinfo_block); + //printf("jstart block: 0x%x\n", jstart_block); + //printf("journal size: 0x%x\n", journal_size); + + ret = sysctl((void *)sysctl_info, 6, NULL, NULL, NULL, 0); + if (ret != 0) { + fprintf(stderr, "Failed to make volume %s journaled (%s)\n", + volname, strerror(errno)); + unlink(journal_fname); + unlink(jib_fname); + return 20; + } + + return 0; +} + + +int +DoUnJournal(char *volname) +{ + int result; + int sysctl_info[8]; + struct statfs sfs; + char jbuf[MAXPATHLEN]; + + if (statfs(volname, &sfs) != 0) { + fprintf(stderr, "Can't stat volume %s (%s).\n", volname, strerror(errno)); + return 10; + } + + if ((sfs.f_flags & MNT_JOURNALED) == 0) { + fprintf(stderr, "Volume %s is not journaled.\n", volname); + return 1; + } + + if (chdir(volname) != 0) { + fprintf(stderr, "Can't locate volume %s to turn off journaling (%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_BECOME_UNJOURNALED; + + result = sysctl((void *)sysctl_info, 6, NULL, NULL, NULL, 0); + if (result != 0) { + fprintf(stderr, "Failed to make volume %s UN-journaled (%s)\n", + volname, strerror(errno)); + return 20; + } + + sprintf(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); + 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); + + return 0; +} diff --git a/hfs_util/hfsutil_main.c b/hfs_util/hfsutil_main.c index a9f2f35..e500d06 100644 --- a/hfs_util/hfsutil_main.c +++ b/hfs_util/hfsutil_main.c @@ -52,6 +52,7 @@ #include #include +#include #include #include #include @@ -84,6 +85,13 @@ #define FSUC_SETUUID 's' #endif +#ifndef FSUC_MKJNL +#define FSUC_MKJNL 'J' +#endif + +#ifndef FSUC_UNJNL +#define FSUC_UNJNL 'U' +#endif /* **************************************** L O C A L S ******************************************* */ @@ -113,6 +121,8 @@ char gIgnorePermissionsOption[] = "noperm"; boolean_t gIsEjectable = 0; +int gJournalSize = 0; + #define AUTO_ADOPT_FIXED 1 #define AUTO_ENTER_FIXED 0 @@ -154,6 +164,10 @@ static int DoGetUUIDKey( const char * theDeviceNamePtr ); static int DoChangeUUIDKey( const char * theDeviceNamePtr ); static int DoAdopt( const char * theDeviceNamePtr ); static int DoDisown( const char * theDeviceNamePtr ); + +extern int DoMakeJournaled( const char * volNamePtr, int journalSize ); // XXXdbg +extern int DoUnJournal( const char * volNamePtr ); // XXXdbg + 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 ); static int GetVolumeUUID(const char *deviceNamePtr, VolumeUUID *volumeUUIDPtr, boolean_t generate); @@ -245,6 +259,7 @@ int main (int argc, const char *argv[]) result = seteuid( 0 ); if ( result ) { + fprintf(stderr, "You must be root to run %s.\n", argv[0]); result = FSUR_INVAL; goto AllDone; } @@ -278,6 +293,18 @@ int main (int argc, const char *argv[]) case FSUC_DISOWN: result = DoDisown( blockDeviceName ); break; + + case FSUC_MKJNL: + if (gJournalSize) { + result = DoMakeJournaled( argv[3], gJournalSize ); + } else { + result = DoMakeJournaled( argv[2], gJournalSize ); + } + break; + + case FSUC_UNJNL: + result = DoUnJournal( argv[2] ); + break; default: /* should never get here since ParseArgs should handle this situation */ @@ -760,6 +787,19 @@ Err_Return: } +static int +get_multiplier(char c) +{ + if (tolower(c) == 'k') { + return 1024; + } else if (tolower(c) == 'm') { + return 1024 * 1024; + } else if (tolower(c) == 'g') { + return 1024 * 1024 * 1024; + } + + return 1; +} /* **************************************** ParseArgs ******************************************** Purpose - @@ -805,7 +845,7 @@ ParseArgs(int argc, const char *argv[], const char ** actionPtr, boolean_t * isLockedPtr, boolean_t * isSetuidPtr, boolean_t * isDevPtr) { int result = FSUR_INVAL; - int deviceLength; + int deviceLength, doLengthCheck = 1; int index; int mounting = 0; @@ -865,6 +905,26 @@ ParseArgs(int argc, const char *argv[], const char ** actionPtr, index = 0; break; + // XXXdbg + case FSUC_MKJNL: + index = 0; + doLengthCheck = 0; + if (isdigit(argv[2][0])) { + char *ptr; + gJournalSize = strtoul(argv[2], &ptr, 0); + if (ptr) { + gJournalSize *= get_multiplier(*ptr); + } + return 0; + } + break; + + case FSUC_UNJNL: + index = 0; + doLengthCheck = 0; + break; + // XXXdbg + default: DoDisplayUsage( argv ); goto Return; @@ -873,7 +933,7 @@ ParseArgs(int argc, const char *argv[], const char ** actionPtr, /* Make sure device (argv[2]) is something reasonable */ deviceLength = strlen( argv[2] ); - if ( deviceLength < 3 || deviceLength > NAME_MAX ) { + if ( doLengthCheck && (deviceLength < 3 || deviceLength > NAME_MAX) ) { DoDisplayUsage( argv ); goto Return; } @@ -950,8 +1010,12 @@ DoDisplayUsage(const char *argv[]) printf(" -%c (Set UUID Key)\n", FSUC_SETUUID); #endif HFS_UUID_SUPPORT printf(" -%c (Adopt permissions)\n", FSUC_ADOPT); + printf(" -%c (Make a volume journaled)\n", FSUC_MKJNL); + printf(" -%c (Turn off journaling on a volume)\n", FSUC_UNJNL); printf("device_arg:\n"); printf(" device we are acting upon (for example, 'disk0s2')\n"); + printf(" if '-%c' or '-%c' is specified, this should be the\n", FSUC_MKJNL, FSUC_UNJNL); + printf(" name of the volume we to act on (for example, '/Volumes/foo' or '/')\n"); printf("mount_point_arg:\n"); printf(" required for Mount and Force Mount \n"); printf("Flags:\n"); -- 2.45.2