#include <sys/types.h>
#include <sys/attr.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/sysctl.h>
#include <sys/resource.h>
#include <sys/vmmeter.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/disk.h>
#include <sys/loadable_fs.h>
#include <hfs/hfs_format.h>
#include <hfs/hfs_mount.h>
#include <System/hfs/hfs_fsctl.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <architecture/byte_order.h>
#ifndef HFS_ENABLE_JOURNALING
#define HFS_ENABLE_JOURNALING 0x082969
#endif
#ifndef HFS_DISABLE_JOURNALING
#define HFS_DISABLE_JOURNALING 0x031272
#endif
#ifndef HFS_GET_JOURNAL_INFO
#define HFS_GET_JOURNAL_INFO 0x6a6e6c69
#endif
struct ExtentsAttrBuf {
unsigned long infoLength;
HFSPlusExtentRecord extents;
};
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
struct FinderInfo {
u_int32_t opaque_1[2];
u_int16_t fdFlags;
int16_t opaque_2[11];
};
typedef struct FinderInfo FinderInfo;
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);
}
off_t
get_start_block(const char *file, uint32_t fs_block_size)
{
off_t cur_pos, phys_start, len;
int fd, err;
struct log2phys l2p;
struct stat st;
fd = open(file, O_RDONLY);
if (fd < 0) {
return -1;
}
if (fstat(fd, &st) < 0) {
fprintf(stderr, "can't stat %s (%s)\n", file, strerror(errno));
close(fd);
return -1;
}
fs_block_size = st.st_blksize;
phys_start = len = 0;
for(cur_pos=0; cur_pos < st.st_size; cur_pos += fs_block_size) {
memset(&l2p, 0, sizeof(l2p));
lseek(fd, cur_pos, SEEK_SET);
err = fcntl(fd, F_LOG2PHYS, &l2p);
if (phys_start == 0) {
phys_start = l2p.l2p_devoffset;
len = fs_block_size;
} else if (l2p.l2p_devoffset != (phys_start + len)) {
fprintf(stderr, "%s : is not contiguous!\n", file);
close(fd);
return -1;
} else {
len += fs_block_size;
}
}
close(fd);
if ((phys_start / (unsigned int)fs_block_size) & 0xffffffff00000000LL) {
fprintf(stderr, "%s : starting block is > 32bits!\n", file);
return -1;
}
return phys_start;
}
#include <sys/disk.h>
#include <hfs/hfs_format.h>
#include <machine/endian.h>
#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
get_embedded_offset(char *devname)
{
int fd = -1;
off_t ret = 0;
char *buff = NULL, rawdev[256];
u_int64_t blkcnt;
u_int32_t blksize;
HFSMasterDirectoryBlock *mdbp;
off_t embeddedOffset;
struct statfs sfs;
struct stat st;
restart:
if (stat(devname, &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 (statfs(devname, &sfs) != 0) {
fprintf(stderr, "Can't find out any info about the fs for path %s (%s)\n",
devname, strerror(errno));
ret = -1;
goto out;
}
snprintf(rawdev, sizeof(rawdev), "/dev/r%s", &sfs.f_mntfromname[5]);
devname = &rawdev[0];
goto restart;
}
fd = open(devname, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "can't open: %s (%s)\n", devname, strerror(errno));
ret = -1;
goto out;
}
if (ioctl(fd, DKIOCGETBLOCKSIZE, (caddr_t)&blksize) != 0) {
fprintf(stderr, "can't get the device block size (%s). assuming 512\n", strerror(errno));
blksize = 512;
ret = -1;
goto out;
}
if (ioctl(fd, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt)) {
struct stat st;
fprintf(stderr, "failed to get block count. trying stat().\n");
if (fstat(fd, &st) != 0) {
ret = -1;
goto out;
}
blkcnt = st.st_size / blksize;
}
buff = (char *)malloc(blksize);
if (pread(fd, buff, blksize, HFS_PRI_SECTOR(blksize)*blksize) != blksize) {
fprintf(stderr, "failed to read volume header @ offset %d (%s)\n",
HFS_PRI_SECTOR(blksize), strerror(errno));
ret = -1;
goto out;
}
mdbp = (HFSMasterDirectoryBlock *)(buff + HFS_PRI_OFFSET(blksize));
if ( (SWAP_BE16(mdbp->drSigWord) != kHFSSigWord)
&& (SWAP_BE16(mdbp->drSigWord) != kHFSPlusSigWord)
&& (SWAP_BE16(mdbp->drSigWord) != kHFSXSigWord)) {
printf ("get_embedded_offset: invalid volume signature \n");
ret = -1;
goto out;
}
if ((SWAP_BE16(mdbp->drSigWord) == kHFSSigWord) && (SWAP_BE16(mdbp->drEmbedSigWord) != kHFSPlusSigWord)) {
ret = -1;
goto out;
} else 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 ((embeddedOffset % blksize) != 0) {
fprintf(stderr, "HFS Mount: embedded volume offset not"
" a multiple of physical block size (%d);"
" switching to 512\n", blksize);
blkcnt *= (blksize / 512);
blksize = 512;
}
} else {
embeddedOffset = 0;
}
ret = embeddedOffset;
out:
if (buff) {
free(buff);
}
if (fd >= 0)
close(fd);
return ret;
}
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;
int32_t jstart_block, jinfo_block;
int sysctl_info[8];
JournalInfoBlock jib;
struct statfs sfs;
static char tmpname[MAXPATHLEN];
off_t start_block, embedded_offset;
if (statfs(volname, &sfs) != 0) {
fprintf(stderr, "Can't stat volume %s (%s).\n", volname, strerror(errno));
return 10;
}
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",
volname);
return 10;
}
unlink(tmpname);
if (sfs.f_flags & MNT_JOURNALED) {
fprintf(stderr, "Volume %s is already journaled.\n", volname);
return 1;
}
if (jsize != 0) {
journal_size = jsize;
} else {
int scale;
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;
}
}
if (chdir(volname) != 0) {
fprintf(stderr, "Can't locate volume %s to make it journaled (%s).\n",
volname, strerror(errno));
return 10;
}
embedded_offset = get_embedded_offset(volname);
if (embedded_offset < 0) {
fprintf(stderr, "Can't calculate the embedded offset (if any) for %s.\n", volname);
fprintf(stderr, "Journal creation failure.\n");
return 15;
}
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;
}
if (fcntl(fd, F_NOCACHE, 1)) {
fprintf(stderr, "Can't create journal file (NC) on volume %s (%s)\n",
volname, strerror(errno));
return 5;
}
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;
}
retry:
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) {
if (journal_size >= 2*1024*1024) {
fprintf(stderr, "Not enough contiguous space for a %d k journal. Retrying.\n",
journal_size/1024);
journal_size /= 2;
ftruncate(fd, 0); goto retry;
} else {
fprintf(stderr, "Disk too fragmented to enable journaling.\n");
fprintf(stderr, "Please run a defragmenter on %s.\n", volname);
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);
start_block = get_start_block(journal_fname, block_size);
if (start_block == (off_t)-1) {
fprintf(stderr, "Failed to get start block for %s (%s)\n",
journal_fname, strerror(errno));
unlink(journal_fname);
return 20;
}
jstart_block = (start_block / block_size) - (embedded_offset / block_size);
memset(&jib, 'Z', sizeof(jib));
jib.flags = kJIJournalInFSMask;
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) {
fprintf(stderr, "Could not create journal info block file on volume %s (%s)\n",
volname, strerror(errno));
unlink(journal_fname);
return 5;
}
if (fcntl(fd, F_NOCACHE, 1)) {
fprintf(stderr, "Could not create journal info block (NC) file on volume %s (%s)\n",
volname, strerror(errno));
return 5;
}
jib.flags = OSSwapBigToHostInt32(jib.flags);
jib.offset = OSSwapBigToHostInt64(jib.offset);
jib.size = OSSwapBigToHostInt64(jib.size);
memcpy(buf, &jib, sizeof(jib));
jib.size = OSSwapBigToHostInt64(jib.size);
jib.offset = OSSwapBigToHostInt64(jib.offset);
jib.flags = OSSwapBigToHostInt32(jib.flags);
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);
start_block = get_start_block(jib_fname, block_size);
if (start_block == (off_t)-1) {
fprintf(stderr, "Failed to get start block for %s (%s)\n",
jib_fname, strerror(errno));
unlink(journal_fname);
unlink(jib_fname);
return 20;
}
jinfo_block = (start_block / block_size) - (embedded_offset / block_size);
memset(sysctl_info, 0, sizeof(sysctl_info));
sysctl_info[0] = CTL_VFS;
sysctl_info[1] = sfs.f_fsid.val[1];
sysctl_info[2] = HFS_ENABLE_JOURNALING;
sysctl_info[3] = jinfo_block;
sysctl_info[4] = jstart_block;
sysctl_info[5] = 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 (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 (%s) is not journaled.\n", volname, sfs.f_mntfromname);
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_DISABLE_JOURNALING;
result = sysctl((void *)sysctl_info, 3, NULL, NULL, NULL, 0);
if (result != 0) {
fprintf(stderr, "Failed to make volume %s UN-journaled (%s)\n",
volname, strerror(errno));
return 20;
}
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));
}
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 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;
}
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;
}
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;
}
disksize = blkcnt * (u_int64_t)blksize;
if (blksize == 512 && blkcnt > (u_int64_t)0x000000007fffffff) {
blksize = 4096;
}
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;
}
mdbp = (HFSMasterDirectoryBlock *)(buff + HFS_PRI_OFFSET(blksize));
if ( (SWAP_BE16(mdbp->drSigWord) != kHFSSigWord)
&& (SWAP_BE16(mdbp->drSigWord) != kHFSPlusSigWord)
&& (SWAP_BE16(mdbp->drSigWord) != kHFSXSigWord)) {
ret = -1;
printf("get_journal_info: invalid volume signature\n");
goto out;
}
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);
if ((mdbp->drSigWord == kHFSSigWord) && (mdbp->drEmbedSigWord != kHFSPlusSigWord)) {
goto out;
}
if (mdbp->drEmbedSigWord == kHFSPlusSigWord) {
embeddedOffset = mdbp->drAlBlSt * 512;
embeddedOffset += (u_int64_t)mdbp->drEmbedExtent.startBlock *
(u_int64_t)mdbp->drAlBlkSiz;
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 + HFS_PRI_OFFSET(blksize));
mdbp = (HFSMasterDirectoryBlock *)vhp;
if ( (SWAP_BE16(mdbp->drSigWord) != kHFSSigWord)
&& (SWAP_BE16(mdbp->drSigWord) != kHFSPlusSigWord)
&& (SWAP_BE16(mdbp->drSigWord) != kHFSXSigWord)) {
ret = -1;
printf("get_journal_info: invalid embedded volume signature \n");
goto out;
}
} else {
embeddedOffset = 0;
vhp = (HFSPlusVolumeHeader*) mdbp;
}
if ((SWAP_BE32(vhp->attributes) & kHFSVolumeJournaledMask) == 0) {
ret = 0;
goto out;
}
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)
{
struct statfs sfs;
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];
}
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, "Unable to get fs info for %s\n", volname);
return 10;
}
if ((sfs.f_flags & MNT_JOURNALED) == 0) {
fprintf(stderr, "Volume %s is not journaled.\n", volname);
return 1;
}
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 (jinfo.jstart == 0) {
char rawdev[256];
snprintf(rawdev, sizeof(rawdev), "/dev/r%s", &sfs.f_mntfromname[5]);
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, jinfo.jsize/1024, jinfo.jstart);
}
return 0;
}
int
RawDisableJournaling(char *devname)
{
int fd = -1, ret = 0;
char *buff = NULL, rawdev[256], unrawdev[256];
u_int64_t disksize;
u_int64_t blkcnt;
u_int32_t blksize;
daddr_t mdb_offset;
HFSMasterDirectoryBlock *mdbp;
HFSPlusVolumeHeader *vhp;
off_t embeddedOffset, hdr_offset;
struct stat st;
struct statfs *fsinfo;
strlcpy(rawdev, devname, sizeof(rawdev));
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)) {
snprintf(rawdev, sizeof(rawdev), "/dev/r%s", devname + 5);
goto restart;
} else {
return DoUnJournal(devname);
}
} else {
snprintf(unrawdev, sizeof(unrawdev), "/dev/%s", rawdev + 6);
}
ret = getmntinfo(&fsinfo, MNT_NOWAIT);
if (ret == 0) {
fprintf (stderr, "Error getting list of mounted filesystems\n");
ret = -1;
goto out;
}
while (ret--) {
if (strcmp(unrawdev, fsinfo[ret].f_mntfromname) == 0) {
return DoUnJournal(fsinfo[ret].f_mntonname);
}
}
fd = open(rawdev, O_RDWR);
if (fd < 0) {
fprintf(stderr, "can't open: %s (%s)\n", devname, strerror(errno));
ret = -1;
goto out;
}
if (ioctl(fd, DKIOCGETBLOCKSIZE, (caddr_t)&blksize) != 0) {
fprintf(stderr, "can't get the device block size (%s). assuming 512\n", strerror(errno));
blksize = 512;
ret = -1;
goto out;
}
if (ioctl(fd, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt)) {
struct stat st;
if (fstat(fd, &st) != 0) {
ret = -1;
goto out;
}
blkcnt = st.st_size / blksize;
}
disksize = blkcnt * (u_int64_t)blksize;
if (blksize == 512 && blkcnt > (u_int64_t)0x000000007fffffff) {
blksize = 4096;
}
buff = (char *)malloc(blksize);
hdr_offset = HFS_PRI_SECTOR(blksize)*blksize;
if (pread(fd, buff, blksize, hdr_offset) != blksize) {
fprintf(stderr, "RawDisableJournaling: failed to read volume header @ offset %lld (%s)\n",
hdr_offset, strerror(errno));
ret = -1;
goto out;
}
mdbp = (HFSMasterDirectoryBlock *)(buff + HFS_PRI_OFFSET(blksize));
if ( (SWAP_BE16(mdbp->drSigWord) != kHFSSigWord)
&& (SWAP_BE16(mdbp->drSigWord) != kHFSPlusSigWord)
&& (SWAP_BE16(mdbp->drSigWord) != kHFSXSigWord)) {
ret = -1;
printf("RawDisableJournaling: Invalid Volume Signature \n");
goto out;
}
if ((SWAP_BE16(mdbp->drSigWord) == kHFSSigWord) && (SWAP_BE16(mdbp->drEmbedSigWord) != kHFSPlusSigWord)) {
fprintf(stderr, "disable_journaling: volume is only regular HFS, not HFS+\n");
goto out;
}
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 ((embeddedOffset % blksize) != 0) {
fprintf(stderr, "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)SWAP_BE16(mdbp->drEmbedExtent.blockCount) * (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize);
hdr_offset = mdb_offset * blksize;
if (pread(fd, buff, blksize, hdr_offset) != blksize) {
fprintf(stderr, "failed to read the embedded vhp @ offset %d\n", mdb_offset * blksize);
ret = -1;
goto out;
}
vhp = (HFSPlusVolumeHeader*) (buff + HFS_PRI_OFFSET(blksize));
mdbp = (HFSMasterDirectoryBlock *)vhp;
if ( (SWAP_BE16(mdbp->drSigWord) != kHFSSigWord)
&& (SWAP_BE16(mdbp->drSigWord) != kHFSPlusSigWord)
&& (SWAP_BE16(mdbp->drSigWord) != kHFSXSigWord)) {
ret = -1;
printf("RawDisableJournaling: invalid embedded volume signature \n");
goto out;
}
} else {
embeddedOffset = 0;
vhp = (HFSPlusVolumeHeader*) mdbp;
}
if ((SWAP_BE32(vhp->attributes) & kHFSVolumeJournaledMask) != 0) {
unsigned int tmp = SWAP_BE32(vhp->attributes);
tmp &= ~kHFSVolumeJournaledMask;
vhp->attributes = SWAP_BE32(tmp);
if ((tmp = pwrite(fd, buff, blksize, hdr_offset)) != blksize) {
fprintf(stderr, "Update of super-block on %s failed! (%d != %d, %s)\n",
devname, tmp, blksize, strerror(errno));
} else {
fprintf(stderr, "Turned off the journaling bit for %s\n", devname);
}
} else {
fprintf(stderr, "disable_journaling: %s is not journaled.\n", devname);
}
out:
if (buff)
free(buff);
if (fd >= 0)
close(fd);
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;
}
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;
}
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;
}
if (blksize == 512 && blkcnt > (u_int64_t)0x000000007fffffff) {
blksize = 4096;
}
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;
}
mdbp = (HFSMasterDirectoryBlock *)(buff + HFS_PRI_OFFSET(blksize));
if ( (SWAP_BE16(mdbp->drSigWord) != kHFSSigWord)
&& (SWAP_BE16(mdbp->drSigWord) != kHFSPlusSigWord)
&& (SWAP_BE16(mdbp->drSigWord) != kHFSXSigWord)) {
ret = -1;
printf ("SetJournalInFSState: Invalid Volume Signature \n");
goto out;
}
if ((SWAP_BE16(mdbp->drSigWord) == kHFSSigWord) && (SWAP_BE16(mdbp->drEmbedSigWord) != kHFSPlusSigWord)) {
goto out;
}
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 ((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 + HFS_PRI_OFFSET(blksize));
mdbp = (HFSMasterDirectoryBlock *)(vhp);
if ( (SWAP_BE16(mdbp->drSigWord) != kHFSSigWord)
&& (SWAP_BE16(mdbp->drSigWord) != kHFSPlusSigWord)
&& (SWAP_BE16(mdbp->drSigWord) != kHFSXSigWord)) {
ret = -1;
printf("SetJournalInFSState: Invalid Embedded Volume Signature \n");
goto out;
}
} else {
embeddedOffset = 0;
vhp = (HFSPlusVolumeHeader*) mdbp;
}
if ((SWAP_BE32(vhp->attributes) & kHFSVolumeJournaledMask) == 0) {
ret = 0;
goto out;
}
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);
if (journal_in_fs) {
myjib->flags |= kJIJournalInFSMask;
} else {
myjib->flags &= ~kJIJournalInFSMask;
}
myjib->flags |= kJIJournalNeedInitMask;
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;
}