+
+
+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;
+}
+
+