2 * Copyright (c) 1999-2015 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.2 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 Copyright (c) 2002 Apple Computer, Inc.
26 This file contains the routine to make an HFS+ volume journaled
27 and a corresponding routine to turn it off.
31 #include <sys/types.h>
35 #include <sys/sysctl.h>
36 #include <sys/resource.h>
37 #include <sys/vmmeter.h>
38 #include <sys/mount.h>
40 #include <sys/ioctl.h>
43 #include <sys/loadable_fs.h>
44 #include <hfs/hfs_format.h>
45 #include <hfs/hfs_mount.h> /* for hfs sysctl values */
47 #include "../core/hfs_fsctl.h"
49 #include <System/sys/content_protection.h>
50 #include <TargetConditionals.h>
61 #include <architecture/byte_order.h>
63 // just in case these aren't in <hfs/hfs_mount.h> yet
64 #ifndef HFS_ENABLE_JOURNALING
65 #define HFS_ENABLE_JOURNALING 0x082969
67 #ifndef HFS_DISABLE_JOURNALING
68 #define HFS_DISABLE_JOURNALING 0x031272
70 #ifndef HFS_GET_JOURNAL_INFO
71 #define HFS_GET_JOURNAL_INFO 0x6a6e6c69
74 /* getattrlist buffers start with an extra length field */
75 struct ExtentsAttrBuf
{
76 unsigned long infoLength
;
77 HFSPlusExtentRecord extents
;
79 typedef struct ExtentsAttrBuf ExtentsAttrBuf
;
81 #ifndef HFSIOC_GET_JOURNAL_INFO
82 # include <sys/ioctl.h>
83 struct hfs_journal_info
{
87 # define HFSIOC_GET_JOURNAL_INFO _IOR('h', 17, struct hfs_journal_info)
91 #define kIsInvisible 0x4000
94 * Generic Finder file/dir data
97 u_int32_t opaque_1
[2];
98 u_int16_t fdFlags
; /* Finder flags */
101 typedef struct FinderInfo FinderInfo
;
103 /* getattrlist buffers start with an extra length field */
104 struct FinderAttrBuf
{
105 unsigned long infoLength
;
106 FinderInfo finderInfo
;
108 typedef struct FinderAttrBuf FinderAttrBuf
;
111 int hide_file(const char * file
)
113 struct attrlist alist
= {0};
114 FinderAttrBuf finderInfoBuf
= {0};
117 alist
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
118 alist
.commonattr
= ATTR_CMN_FNDRINFO
;
120 result
= getattrlist(file
, &alist
, &finderInfoBuf
, sizeof(finderInfoBuf
), 0);
125 if (finderInfoBuf
.finderInfo
.fdFlags
& kIsInvisible
) {
126 printf("hide: %s is alreadly invisible\n", file
);
130 finderInfoBuf
.finderInfo
.fdFlags
|= kIsInvisible
;
132 result
= setattrlist(file
, &alist
, &finderInfoBuf
.finderInfo
, sizeof(FinderInfo
), 0);
134 return (result
== -1 ? errno
: result
);
138 get_start_block(const char *file
, uint32_t fs_block_size
)
140 off_t cur_pos
, phys_start
, len
;
145 fd
= open(file
, O_RDONLY
);
150 if (fstat(fd
, &st
) < 0) {
151 fprintf(stderr
, "can't stat %s (%s)\n", file
, strerror(errno
));
156 fs_block_size
= st
.st_blksize
; // XXXdbg quick hack for now
158 phys_start
= len
= 0;
159 for(cur_pos
=0; cur_pos
< st
.st_size
; cur_pos
+= fs_block_size
) {
160 memset(&l2p
, 0, sizeof(l2p
));
161 lseek(fd
, cur_pos
, SEEK_SET
);
162 err
= fcntl(fd
, F_LOG2PHYS
, &l2p
);
164 if (phys_start
== 0) {
165 phys_start
= l2p
.l2p_devoffset
;
167 } else if (l2p
.l2p_devoffset
!= (phys_start
+ len
)) {
168 // printf(" %lld : %lld - %lld\n", cur_pos, phys_start / fs_block_size, len / fs_block_size);
169 fprintf(stderr
, "%s : is not contiguous!\n", file
);
172 // phys_start = l2p.l2p_devoffset;
173 // len = fs_block_size;
175 len
+= fs_block_size
;
181 //printf("%s start offset %lld; byte len %lld (blksize %d)\n",
182 // file, phys_start, len, fs_block_size);
184 if ((phys_start
/ (unsigned int)fs_block_size
) & 0xffffffff00000000LL
) {
185 fprintf(stderr
, "%s : starting block is > 32bits!\n", file
);
194 // Get the embedded offset (if any) for an hfs+ volume.
195 // This is pretty skanky that we have to do this but
198 #include <sys/disk.h>
199 #include <hfs/hfs_format.h>
201 #include <machine/endian.h>
203 #define HFS_PRI_SECTOR(blksize) (1024 / (blksize))
204 #define HFS_PRI_OFFSET(blksize) ((blksize) > 1024 ? 1024 : 0)
206 #include <libkern/OSByteOrder.h>
208 #define SWAP_BE16(x) ntohs(x)
209 #define SWAP_BE32(x) ntohl(x)
210 #define SWAP_BE64(x) OSSwapConstInt64(x)
214 get_embedded_offset(char *devname
)
218 char *buff
= NULL
, rawdev
[256];
221 HFSMasterDirectoryBlock
*mdbp
;
222 off_t embeddedOffset
;
227 if (stat(devname
, &st
) != 0) {
228 fprintf(stderr
, "Could not access %s (%s)\n", devname
, strerror(errno
));
233 if (S_ISCHR(st
.st_mode
) == 0) {
234 // hmmm, it's not the character special raw device so we
235 // should try to figure out the real device.
236 if (statfs(devname
, &sfs
) != 0) {
237 fprintf(stderr
, "Can't find out any info about the fs for path %s (%s)\n",
238 devname
, strerror(errno
));
243 // This assumes it begins with "/dev/". The old code assumed
244 // it began with five characters. Should probably use strrchr or equivalent.
245 snprintf(rawdev
, sizeof(rawdev
), "/dev/r%s", &sfs
.f_mntfromname
[5]);
246 devname
= &rawdev
[0];
250 fd
= open(devname
, O_RDONLY
);
252 fprintf(stderr
, "can't open: %s (%s)\n", devname
, strerror(errno
));
257 /* Get the real physical block size. */
258 if (ioctl(fd
, DKIOCGETBLOCKSIZE
, (caddr_t
)&blksize
) != 0) {
259 fprintf(stderr
, "can't get the device block size (%s). assuming 512\n", strerror(errno
));
265 /* Get the number of physical blocks. */
266 if (ioctl(fd
, DKIOCGETBLOCKCOUNT
, (caddr_t
)&blkcnt
)) {
268 fprintf(stderr
, "failed to get block count. trying stat().\n");
269 if (fstat(fd
, &st
) != 0) {
274 blkcnt
= st
.st_size
/ blksize
;
279 * blksize has our prefered physical block size
280 * blkcnt has the total number of physical blocks
283 buff
= (char *)malloc(blksize
);
285 if (pread(fd
, buff
, blksize
, HFS_PRI_SECTOR(blksize
)*blksize
) != blksize
) {
286 fprintf(stderr
, "failed to read volume header @ offset %d (%s)\n",
287 HFS_PRI_SECTOR(blksize
), strerror(errno
));
292 mdbp
= (HFSMasterDirectoryBlock
*)(buff
+ HFS_PRI_OFFSET(blksize
));
293 if ( (SWAP_BE16(mdbp
->drSigWord
) != kHFSSigWord
)
294 && (SWAP_BE16(mdbp
->drSigWord
) != kHFSPlusSigWord
)
295 && (SWAP_BE16(mdbp
->drSigWord
) != kHFSXSigWord
)) {
296 printf ("get_embedded_offset: invalid volume signature \n");
301 if ((SWAP_BE16(mdbp
->drSigWord
) == kHFSSigWord
) && (SWAP_BE16(mdbp
->drEmbedSigWord
) != kHFSPlusSigWord
)) {
304 } else if (SWAP_BE16(mdbp
->drEmbedSigWord
) == kHFSPlusSigWord
) {
305 /* Get the embedded Volume Header */
306 embeddedOffset
= SWAP_BE16(mdbp
->drAlBlSt
) * 512;
307 embeddedOffset
+= (u_int64_t
)SWAP_BE16(mdbp
->drEmbedExtent
.startBlock
) *
308 (u_int64_t
)SWAP_BE32(mdbp
->drAlBlkSiz
);
311 * If the embedded volume doesn't start on a block
312 * boundary, then switch the device to a 512-byte
313 * block size so everything will line up on a block
316 if ((embeddedOffset
% blksize
) != 0) {
317 fprintf(stderr
, "HFS Mount: embedded volume offset not"
318 " a multiple of physical block size (%d);"
319 " switching to 512\n", blksize
);
321 blkcnt
*= (blksize
/ 512);
325 } else { /* pure HFS+ */
329 ret
= embeddedOffset
;
343 static const char *journal_fname
= ".journal";
344 static const char *jib_fname
= ".journal_info_block";
347 DoMakeJournaled(char *volname
, int jsize
) {
348 int fd
, i
, block_size
, journal_size
= 8*1024*1024;
352 int32_t jstart_block
, jinfo_block
;
354 JournalInfoBlock jib
;
356 static char tmpname
[MAXPATHLEN
];
357 off_t start_block
, embedded_offset
;
359 if (statfs(volname
, &sfs
) != 0) {
360 fprintf(stderr
, "Can't stat volume %s (%s).\n", volname
, strerror(errno
));
364 // Make sure that we're HFS+. First we check the fstypename.
365 // If that's ok then we try to create a symlink (which won't
366 // work on plain hfs volumes but will work on hfs+ volumes).
368 if (strcmp(sfs
.f_fstypename
, "devfs") == 0) {
369 fprintf (stderr
, "%s is a device node. Journal enable only works on a mounted HFS+ volume.\n", volname
);
372 snprintf(tmpname
, sizeof(tmpname
), "%s/is_vol_hfs_plus", volname
);
373 if (strcmp(sfs
.f_fstypename
, "hfs") != 0 ||
374 ((ret
= symlink(tmpname
, tmpname
)) != 0 && errno
== ENOTSUP
)) {
375 fprintf(stderr
, "%s is not an HFS+ volume. Journaling only works on HFS+ volumes.\n",
381 if (sfs
.f_flags
& MNT_JOURNALED
) {
382 fprintf(stderr
, "Volume %s is already journaled.\n", volname
);
387 journal_size
= jsize
;
392 // we want at least 8 megs of journal for each 100 gigs of
393 // disk space. We cap the size at 512 megs though.
395 scale
= ((long long)sfs
.f_bsize
* (long long)((unsigned int)sfs
.f_blocks
)) / (100*1024*1024*1024ULL);
396 journal_size
*= (scale
+ 1);
397 if (journal_size
> 512 * 1024 * 1024) {
398 journal_size
= 512 * 1024 * 1024;
402 if (chdir(volname
) != 0) {
403 fprintf(stderr
, "Can't locate volume %s to make it journaled (%s).\n",
404 volname
, strerror(errno
));
409 embedded_offset
= get_embedded_offset(volname
);
410 if (embedded_offset
< 0) {
411 fprintf(stderr
, "Can't calculate the embedded offset (if any) for %s.\n", volname
);
412 fprintf(stderr
, "Journal creation failure.\n");
415 // printf("Embedded offset == 0x%llx\n", embedded_offset);
418 * Must use open_dprotected_np to create a class D file. This will
419 * be the same as standard open(2) on systems that do not support content protection
421 fd
= open_dprotected_np (journal_fname
, O_CREAT
|O_TRUNC
|O_RDWR
, PROTECTION_CLASS_D
, 0, 000);
423 fprintf(stderr
, "Can't create journal file on volume %s (%s)\n",
424 volname
, strerror(errno
));
428 if (fcntl(fd
, F_NOCACHE
, 1)) {
429 fprintf(stderr
, "Can't create journal file (NC) on volume %s (%s)\n",
430 volname
, strerror(errno
));
435 // make sure that it has no r/w/x privs (only could happen if
436 // the file already existed since open() doesn't reset the mode
441 block_size
= sfs
.f_bsize
;
442 if ((journal_size
% block_size
) != 0) {
443 fprintf(stderr
, "Journal size %dk is not a multiple of volume %s block size (%d).\n",
444 journal_size
/1024, volname
, block_size
);
446 unlink(journal_fname
);
451 memset(&fst
, 0, sizeof(fst
));
452 fst
.fst_flags
= F_ALLOCATECONTIG
|F_ALLOCATEALL
;
453 fst
.fst_length
= journal_size
;
454 fst
.fst_posmode
= F_PEOFPOSMODE
;
456 ret
= fcntl(fd
, F_PREALLOCATE
, &fst
);
458 if (journal_size
>= 2*1024*1024) {
459 fprintf(stderr
, "Not enough contiguous space for a %d k journal. Retrying.\n",
462 ftruncate(fd
, 0); // make sure the file is zero bytes long.
465 fprintf(stderr
, "Disk too fragmented to enable journaling.\n");
466 fprintf(stderr
, "Please run a defragmenter on %s.\n", volname
);
468 unlink(journal_fname
);
473 printf("Allocated %lldK for journal file.\n", fst
.fst_bytesalloc
/1024LL);
474 buf
= (char *)calloc(block_size
, 1);
476 for(i
=0; i
< journal_size
/block_size
; i
++) {
477 ret
= write(fd
, buf
, block_size
);
478 if (ret
!= block_size
) {
483 if (i
*block_size
!= journal_size
) {
484 fprintf(stderr
, "Failed to write %dk to journal on volume %s (%s)\n",
485 journal_size
/1024, volname
, strerror(errno
));
488 printf("Could not allocate memory to write to the journal on volume %s (%s)\n",
489 volname
, strerror(errno
));
494 hide_file(journal_fname
);
496 start_block
= get_start_block(journal_fname
, block_size
);
497 if (start_block
== (off_t
)-1) {
498 fprintf(stderr
, "Failed to get start block for %s (%s)\n",
499 journal_fname
, strerror(errno
));
500 unlink(journal_fname
);
505 jstart_block
= (start_block
/ block_size
) - (embedded_offset
/ block_size
);
507 memset(&jib
, 'Z', sizeof(jib
));
508 jib
.flags
= kJIJournalInFSMask
;
509 jib
.offset
= (off_t
)((unsigned int)jstart_block
) * (off_t
)((unsigned int)block_size
);
510 jib
.size
= (off_t
)((unsigned int)journal_size
);
513 * Use open_dprotected_np to create JIB as a class D file. This will
514 * behave the same as a standard open(2) on systems that do not support content protection
516 fd
= open_dprotected_np(jib_fname
, O_CREAT
|O_TRUNC
|O_RDWR
, PROTECTION_CLASS_D
, 0, 000);
518 fprintf(stderr
, "Could not create journal info block file on volume %s (%s)\n",
519 volname
, strerror(errno
));
520 unlink(journal_fname
);
526 if (fcntl(fd
, F_NOCACHE
, 1)) {
527 fprintf(stderr
, "Could not create journal info block (NC) file on volume %s (%s)\n",
528 volname
, strerror(errno
));
534 // swap the data before we copy it
535 jib
.flags
= OSSwapBigToHostInt32(jib
.flags
);
536 jib
.offset
= OSSwapBigToHostInt64(jib
.offset
);
537 jib
.size
= OSSwapBigToHostInt64(jib
.size
);
539 memcpy(buf
, &jib
, sizeof(jib
));
541 // now put it back the way it was
542 jib
.size
= OSSwapBigToHostInt64(jib
.size
);
543 jib
.offset
= OSSwapBigToHostInt64(jib
.offset
);
544 jib
.flags
= OSSwapBigToHostInt32(jib
.flags
);
546 if (write(fd
, buf
, block_size
) != block_size
) {
547 fprintf(stderr
, "Failed to write journal info block on volume %s (%s)!\n",
548 volname
, strerror(errno
));
549 unlink(journal_fname
);
557 hide_file(jib_fname
);
559 start_block
= get_start_block(jib_fname
, block_size
);
560 if (start_block
== (off_t
)-1) {
561 fprintf(stderr
, "Failed to get start block for %s (%s)\n",
562 jib_fname
, strerror(errno
));
563 unlink(journal_fname
);
569 jinfo_block
= (start_block
/ block_size
) - (embedded_offset
/ block_size
);
573 // Now make the volume journaled!
575 memset(sysctl_info
, 0, sizeof(sysctl_info
));
576 sysctl_info
[0] = CTL_VFS
;
577 sysctl_info
[1] = sfs
.f_fsid
.val
[1];
578 sysctl_info
[2] = HFS_ENABLE_JOURNALING
;
579 sysctl_info
[3] = jinfo_block
;
580 sysctl_info
[4] = jstart_block
;
581 sysctl_info
[5] = journal_size
;
583 //printf("fs type: 0x%x\n", sysctl_info[1]);
584 //printf("jinfo block : 0x%x\n", jinfo_block);
585 //printf("jstart block: 0x%x\n", jstart_block);
586 //printf("journal size: 0x%x\n", journal_size);
588 ret
= sysctl((void *)sysctl_info
, 6, NULL
, NULL
, NULL
, 0);
590 fprintf(stderr
, "Failed to make volume %s journaled (%s)\n",
591 volname
, strerror(errno
));
592 unlink(journal_fname
);
606 DoUnJournal(char *volname
) {
610 char jbuf
[MAXPATHLEN
];
612 if (statfs(volname
, &sfs
) != 0) {
613 fprintf(stderr
, "Can't stat volume %s (%s).\n", volname
, strerror(errno
));
617 if (strcmp(sfs
.f_fstypename
, "hfs") != 0) {
618 fprintf(stderr
, "Volume %s (%s) is not a HFS volume.\n", volname
, sfs
.f_mntfromname
);
622 if ((sfs
.f_flags
& MNT_JOURNALED
) == 0) {
623 fprintf(stderr
, "Volume %s (%s) is not journaled.\n", volname
, sfs
.f_mntfromname
);
627 if (chdir(volname
) != 0) {
628 fprintf(stderr
, "Can't locate volume %s to turn off journaling (%s).\n",
629 volname
, strerror(errno
));
633 memset(sysctl_info
, 0, sizeof(sysctl_info
));
634 sysctl_info
[0] = CTL_VFS
;
635 sysctl_info
[1] = sfs
.f_fsid
.val
[1];
636 sysctl_info
[2] = HFS_DISABLE_JOURNALING
;
638 result
= sysctl((void *)sysctl_info
, 3, NULL
, NULL
, NULL
, 0);
640 fprintf(stderr
, "Failed to make volume %s UN-journaled (%s)\n",
641 volname
, strerror(errno
));
645 snprintf(jbuf
, sizeof(jbuf
), "%s/%s", volname
, journal_fname
);
646 if (unlink(jbuf
) != 0) {
647 fprintf(stderr
, "Failed to remove the journal %s (%s)\n",
648 jbuf
, strerror(errno
));
651 snprintf(jbuf
, sizeof(jbuf
), "%s/%s", volname
, jib_fname
);
652 if (unlink(jbuf
) != 0) {
653 fprintf(stderr
, "Failed to remove the journal info block %s (%s)\n",
654 jbuf
, strerror(errno
));
657 printf("Journaling disabled on %s mounted at %s.\n", sfs
.f_mntfromname
, volname
);
666 get_journal_info(char *devname
, struct JournalInfoBlock
*jib
)
668 int fd
= -1, ret
= 0;
669 char *buff
= NULL
, *buff2
= NULL
;
674 HFSMasterDirectoryBlock
*mdbp
;
675 HFSPlusVolumeHeader
*vhp
;
676 off_t embeddedOffset
, pos
;
677 struct JournalInfoBlock
*myjib
;
679 fd
= open(devname
, O_RDONLY
);
681 printf("can't open: %s (%s)\n", devname
, strerror(errno
));
686 /* Get the real physical block size. */
687 if (ioctl(fd
, DKIOCGETBLOCKSIZE
, (caddr_t
)&blksize
) != 0) {
688 printf("can't get the device block size (%s). assuming 512\n", strerror(errno
));
694 /* Get the number of physical blocks. */
695 if (ioctl(fd
, DKIOCGETBLOCKCOUNT
, (caddr_t
)&blkcnt
)) {
697 printf("failed to get block count. trying stat().\n");
698 if (fstat(fd
, &st
) != 0) {
703 blkcnt
= st
.st_size
/ blksize
;
706 /* Compute an accurate disk size */
707 disksize
= blkcnt
* (u_int64_t
)blksize
;
710 * There are only 31 bits worth of block count in
711 * the buffer cache. So for large volumes a 4K
712 * physical block size is needed.
714 if (blksize
== 512 && blkcnt
> (u_int64_t
)0x000000007fffffff) {
720 * blksize has our prefered physical block size
721 * blkcnt has the total number of physical blocks
724 buff
= (char *)malloc(blksize
);
725 buff2
= (char *)malloc(blksize
);
727 if (pread(fd
, buff
, blksize
, HFS_PRI_SECTOR(blksize
)*blksize
) != blksize
) {
728 printf("failed to read volume header @ offset %d (%s)\n",
729 HFS_PRI_SECTOR(blksize
), strerror(errno
));
734 mdbp
= (HFSMasterDirectoryBlock
*)(buff
+ HFS_PRI_OFFSET(blksize
));
736 if ( (SWAP_BE16(mdbp
->drSigWord
) != kHFSSigWord
)
737 && (SWAP_BE16(mdbp
->drSigWord
) != kHFSPlusSigWord
)
738 && (SWAP_BE16(mdbp
->drSigWord
) != kHFSXSigWord
)) {
740 printf("get_journal_info: invalid volume signature\n");
744 mdbp
->drSigWord
= SWAP_BE16(mdbp
->drSigWord
);
745 mdbp
->drEmbedSigWord
= SWAP_BE16(mdbp
->drEmbedSigWord
);
746 mdbp
->drAlBlSt
= SWAP_BE16(mdbp
->drAlBlSt
);
747 mdbp
->drEmbedExtent
.startBlock
= SWAP_BE16(mdbp
->drEmbedExtent
.startBlock
);
748 mdbp
->drAlBlkSiz
= SWAP_BE32(mdbp
->drAlBlkSiz
);
749 mdbp
->drEmbedExtent
.blockCount
= SWAP_BE16(mdbp
->drEmbedExtent
.blockCount
);
752 if ((mdbp
->drSigWord
== kHFSSigWord
) && (mdbp
->drEmbedSigWord
!= kHFSPlusSigWord
)) {
753 // normal hfs can not ever be journaled
757 /* Get the embedded Volume Header */
758 if (mdbp
->drEmbedSigWord
== kHFSPlusSigWord
) {
759 embeddedOffset
= mdbp
->drAlBlSt
* 512;
760 embeddedOffset
+= (u_int64_t
)mdbp
->drEmbedExtent
.startBlock
*
761 (u_int64_t
)mdbp
->drAlBlkSiz
;
764 * If the embedded volume doesn't start on a block
765 * boundary, then switch the device to a 512-byte
766 * block size so everything will line up on a block
769 if ((embeddedOffset
% blksize
) != 0) {
770 printf("HFS Mount: embedded volume offset not"
771 " a multiple of physical block size (%d);"
772 " switching to 512\n", blksize
);
774 blkcnt
*= (blksize
/ 512);
778 disksize
= (u_int64_t
)mdbp
->drEmbedExtent
.blockCount
*
779 (u_int64_t
)mdbp
->drAlBlkSiz
;
781 mdb_offset
= (embeddedOffset
/ blksize
) + HFS_PRI_SECTOR(blksize
);
782 if (pread(fd
, buff
, blksize
, mdb_offset
* blksize
) != blksize
) {
783 printf("failed to read the embedded vhp @ offset %d\n", mdb_offset
* blksize
);
788 vhp
= (HFSPlusVolumeHeader
*) (buff
+ HFS_PRI_OFFSET(blksize
));
790 mdbp
= (HFSMasterDirectoryBlock
*)vhp
;
791 if ( (SWAP_BE16(mdbp
->drSigWord
) != kHFSSigWord
)
792 && (SWAP_BE16(mdbp
->drSigWord
) != kHFSPlusSigWord
)
793 && (SWAP_BE16(mdbp
->drSigWord
) != kHFSXSigWord
)) {
796 printf("get_journal_info: invalid embedded volume signature \n");
800 } else /* pure HFS+ */ {
802 vhp
= (HFSPlusVolumeHeader
*) mdbp
;
805 if ((SWAP_BE32(vhp
->attributes
) & kHFSVolumeJournaledMask
) == 0) {
811 // Now read the journal info block... (when calculating the
812 // position, make sure to cast to unsigned first, then to
813 // off_t so that things don't get sign-extended improperly
816 pos
= (off_t
)((off_t
)embeddedOffset
+
817 (off_t
)((unsigned int)SWAP_BE32(vhp
->journalInfoBlock
))*(off_t
)((unsigned int)SWAP_BE32(vhp
->blockSize
)));
819 if (pread(fd
, buff2
, blksize
, pos
) != blksize
) {
820 printf("failed to read the journal info block (%s).\n", strerror(errno
));
825 myjib
= (struct JournalInfoBlock
*)buff2
;
826 myjib
->flags
= SWAP_BE32(myjib
->flags
);
827 myjib
->offset
= SWAP_BE64(myjib
->offset
);
828 myjib
->size
= SWAP_BE64(myjib
->size
);
830 memcpy(jib
, myjib
, sizeof(*myjib
));
847 DoGetJournalInfo(char *volname
)
850 struct hfs_journal_info jinfo
;
852 if (strncmp(volname
, "/dev/", 5) == 0 || strncmp(volname
, "disk", 4) == 0 || strncmp(volname
, "rdisk", 5) == 0) {
853 struct JournalInfoBlock jib
;
855 char fulldevname
[256];
857 if (strncmp(volname
, "disk", 4) == 0 || strncmp(volname
, "rdisk", 5) == 0) {
858 snprintf(fulldevname
, sizeof(fulldevname
), "/dev/%s", volname
);
859 volname
= &fulldevname
[0];
862 // try the name as a device name...
863 ret
= get_journal_info(volname
, &jib
);
865 printf("Volume %s is not journaled.\n", volname
);
867 } else if (ret
< 0) {
868 printf("Volume %s does not appear to be an HFS+ volume.\n", volname
);
871 if (jib
.flags
& kJIJournalInFSMask
) {
872 printf("%s : journal size %lld k at offset 0x%llx\n", volname
, jib
.size
/1024, jib
.offset
);
874 printf("%s: external journal stored on partition with uuid %s on machine w/serial number %s\n",
875 volname
, jib
.ext_jnl_uuid
, jib
.machine_serial_num
);
883 if (statfs(volname
, &sfs
) != 0) {
884 fprintf(stderr
, "Unable to get fs info for %s\n", volname
);
888 if ((sfs
.f_flags
& MNT_JOURNALED
) == 0) {
889 fprintf(stderr
, "Volume %s is not journaled.\n", volname
);
893 if (fsctl(volname
, HFSIOC_GET_JOURNAL_INFO
, &jinfo
, 0) != 0) {
894 fprintf(stderr
, "Failed to get journal info for volume %s (%s)\n",
895 volname
, strerror(errno
));
899 if (jinfo
.jstart
== 0) {
902 snprintf(rawdev
, sizeof(rawdev
), "/dev/r%s", &sfs
.f_mntfromname
[5]);
904 // it's an external journal so get the info the
906 return DoGetJournalInfo(&rawdev
[0]);
909 if (jinfo
.jsize
== 0) {
910 printf("%s : not journaled.\n", volname
);
912 printf("%s : journal size %lld k at offset 0x%llx\n", volname
, jinfo
.jsize
/1024, jinfo
.jstart
);
920 RawDisableJournaling(char *devname
)
922 int fd
= -1, ret
= 0;
923 char *buff
= NULL
, rawdev
[256], unrawdev
[256];
928 HFSMasterDirectoryBlock
*mdbp
;
929 HFSPlusVolumeHeader
*vhp
;
930 off_t embeddedOffset
, hdr_offset
;
932 struct statfs
*fsinfo
;
934 // assume that the name provided is a raw device name
935 strlcpy(rawdev
, devname
, sizeof(rawdev
));
938 if (stat(rawdev
, &st
) != 0) {
939 fprintf(stderr
, "Could not access %s (%s)\n", devname
, strerror(errno
));
944 if (S_ISCHR(st
.st_mode
) == 0) {
945 if (S_ISBLK(st
.st_mode
)) {
946 // this is a block device, convert the name to
947 // raw character device and try again
948 snprintf(rawdev
, sizeof(rawdev
), "/dev/r%s", devname
+ 5);
951 // probably it is a mount point
952 return DoUnJournal(devname
);
955 // convert the character raw device name to
956 // block device name to compare with getmntinfo output
957 snprintf(unrawdev
, sizeof(unrawdev
), "/dev/%s", rawdev
+ 6);
960 // make sure that the file system on the device node is not mounted
961 ret
= getmntinfo(&fsinfo
, MNT_NOWAIT
);
963 fprintf (stderr
, "Error getting list of mounted filesystems\n");
969 // the file system on this device node is currently mounted
970 if (strcmp(unrawdev
, fsinfo
[ret
].f_mntfromname
) == 0) {
971 return DoUnJournal(fsinfo
[ret
].f_mntonname
);
975 fd
= open(rawdev
, O_RDWR
);
977 fprintf(stderr
, "can't open: %s (%s)\n", devname
, strerror(errno
));
982 /* Get the real physical block size. */
983 if (ioctl(fd
, DKIOCGETBLOCKSIZE
, (caddr_t
)&blksize
) != 0) {
984 fprintf(stderr
, "can't get the device block size (%s). assuming 512\n", strerror(errno
));
990 /* Get the number of physical blocks. */
991 if (ioctl(fd
, DKIOCGETBLOCKCOUNT
, (caddr_t
)&blkcnt
)) {
994 if (fstat(fd
, &st
) != 0) {
999 blkcnt
= st
.st_size
/ blksize
;
1002 /* Compute an accurate disk size */
1003 disksize
= blkcnt
* (u_int64_t
)blksize
;
1006 * There are only 31 bits worth of block count in
1007 * the buffer cache. So for large volumes a 4K
1008 * physical block size is needed.
1010 if (blksize
== 512 && blkcnt
> (u_int64_t
)0x000000007fffffff) {
1016 * blksize has our prefered physical block size
1017 * blkcnt has the total number of physical blocks
1020 buff
= (char *)malloc(blksize
);
1022 hdr_offset
= HFS_PRI_SECTOR(blksize
)*blksize
;
1023 if (pread(fd
, buff
, blksize
, hdr_offset
) != blksize
) {
1024 fprintf(stderr
, "RawDisableJournaling: failed to read volume header @ offset %lld (%s)\n",
1025 hdr_offset
, strerror(errno
));
1030 mdbp
= (HFSMasterDirectoryBlock
*)(buff
+ HFS_PRI_OFFSET(blksize
));
1031 if ( (SWAP_BE16(mdbp
->drSigWord
) != kHFSSigWord
)
1032 && (SWAP_BE16(mdbp
->drSigWord
) != kHFSPlusSigWord
)
1033 && (SWAP_BE16(mdbp
->drSigWord
) != kHFSXSigWord
)) {
1035 printf("RawDisableJournaling: Invalid Volume Signature \n");
1039 if ((SWAP_BE16(mdbp
->drSigWord
) == kHFSSigWord
) && (SWAP_BE16(mdbp
->drEmbedSigWord
) != kHFSPlusSigWord
)) {
1040 // normal hfs can not ever be journaled
1041 fprintf(stderr
, "disable_journaling: volume is only regular HFS, not HFS+\n");
1045 /* Get the embedded Volume Header */
1046 if (SWAP_BE16(mdbp
->drEmbedSigWord
) == kHFSPlusSigWord
) {
1047 embeddedOffset
= SWAP_BE16(mdbp
->drAlBlSt
) * 512;
1048 embeddedOffset
+= (u_int64_t
)SWAP_BE16(mdbp
->drEmbedExtent
.startBlock
) * (u_int64_t
)SWAP_BE32(mdbp
->drAlBlkSiz
);
1051 * If the embedded volume doesn't start on a block
1052 * boundary, then switch the device to a 512-byte
1053 * block size so everything will line up on a block
1056 if ((embeddedOffset
% blksize
) != 0) {
1057 fprintf(stderr
, "HFS Mount: embedded volume offset not"
1058 " a multiple of physical block size (%d);"
1059 " switching to 512\n", blksize
);
1061 blkcnt
*= (blksize
/ 512);
1065 disksize
= (u_int64_t
)SWAP_BE16(mdbp
->drEmbedExtent
.blockCount
) * (u_int64_t
)SWAP_BE32(mdbp
->drAlBlkSiz
);
1067 mdb_offset
= (embeddedOffset
/ blksize
) + HFS_PRI_SECTOR(blksize
);
1068 hdr_offset
= mdb_offset
* blksize
;
1069 if (pread(fd
, buff
, blksize
, hdr_offset
) != blksize
) {
1070 fprintf(stderr
, "failed to read the embedded vhp @ offset %d\n", mdb_offset
* blksize
);
1075 vhp
= (HFSPlusVolumeHeader
*) (buff
+ HFS_PRI_OFFSET(blksize
));
1077 mdbp
= (HFSMasterDirectoryBlock
*)vhp
;
1078 if ( (SWAP_BE16(mdbp
->drSigWord
) != kHFSSigWord
)
1079 && (SWAP_BE16(mdbp
->drSigWord
) != kHFSPlusSigWord
)
1080 && (SWAP_BE16(mdbp
->drSigWord
) != kHFSXSigWord
)) {
1083 printf("RawDisableJournaling: invalid embedded volume signature \n");
1087 } else /* pure HFS+ */ {
1089 vhp
= (HFSPlusVolumeHeader
*) mdbp
;
1093 if ((SWAP_BE32(vhp
->attributes
) & kHFSVolumeJournaledMask
) != 0) {
1094 unsigned int tmp
= SWAP_BE32(vhp
->attributes
);
1096 tmp
&= ~kHFSVolumeJournaledMask
;
1097 vhp
->attributes
= SWAP_BE32(tmp
);
1098 if ((tmp
= pwrite(fd
, buff
, blksize
, hdr_offset
)) != blksize
) {
1099 fprintf(stderr
, "Update of super-block on %s failed! (%d != %d, %s)\n",
1100 devname
, tmp
, blksize
, strerror(errno
));
1102 fprintf(stderr
, "Turned off the journaling bit for %s\n", devname
);
1105 fprintf(stderr
, "disable_journaling: %s is not journaled.\n", devname
);
1121 SetJournalInFSState(const char *devname
, int journal_in_fs
)
1123 int fd
= -1, ret
= 0;
1124 char *buff
= NULL
, *buff2
= NULL
;
1128 HFSMasterDirectoryBlock
*mdbp
;
1129 HFSPlusVolumeHeader
*vhp
;
1130 off_t embeddedOffset
, pos
;
1131 struct JournalInfoBlock
*myjib
;
1133 fd
= open(devname
, O_RDWR
);
1135 printf("can't open: %s (%s)\n", devname
, strerror(errno
));
1140 /* Get the real physical block size. */
1141 if (ioctl(fd
, DKIOCGETBLOCKSIZE
, (caddr_t
)&blksize
) != 0) {
1142 printf("can't get the device block size (%s). assuming 512\n", strerror(errno
));
1148 /* Get the number of physical blocks. */
1149 if (ioctl(fd
, DKIOCGETBLOCKCOUNT
, (caddr_t
)&blkcnt
)) {
1151 printf("failed to get block count. trying stat().\n");
1152 if (fstat(fd
, &st
) != 0) {
1157 blkcnt
= st
.st_size
/ blksize
;
1161 * There used to only be 31 bits worth of block count in
1162 * the buffer cache. So for large volumes a 4K
1163 * physical block size is needed.
1165 if (blksize
== 512 && blkcnt
> (u_int64_t
)0x000000007fffffff) {
1171 * blksize has our prefered physical block size
1172 * blkcnt has the total number of physical blocks
1175 buff
= (char *)malloc(blksize
);
1176 buff2
= (char *)malloc(blksize
);
1178 if (pread(fd
, buff
, blksize
, HFS_PRI_SECTOR(blksize
)*blksize
) != blksize
) {
1179 printf("failed to read volume header @ offset %d (%s)\n",
1180 HFS_PRI_SECTOR(blksize
), strerror(errno
));
1185 mdbp
= (HFSMasterDirectoryBlock
*)(buff
+ HFS_PRI_OFFSET(blksize
));
1188 if ( (SWAP_BE16(mdbp
->drSigWord
) != kHFSSigWord
)
1189 && (SWAP_BE16(mdbp
->drSigWord
) != kHFSPlusSigWord
)
1190 && (SWAP_BE16(mdbp
->drSigWord
) != kHFSXSigWord
)) {
1192 printf ("SetJournalInFSState: Invalid Volume Signature \n");
1196 if ((SWAP_BE16(mdbp
->drSigWord
) == kHFSSigWord
) && (SWAP_BE16(mdbp
->drEmbedSigWord
) != kHFSPlusSigWord
)) {
1197 // normal hfs can not ever be journaled
1201 /* Get the embedded Volume Header */
1202 if (SWAP_BE16(mdbp
->drEmbedSigWord
) == kHFSPlusSigWord
) {
1203 embeddedOffset
= SWAP_BE16(mdbp
->drAlBlSt
) * 512;
1204 embeddedOffset
+= (u_int64_t
)SWAP_BE16(mdbp
->drEmbedExtent
.startBlock
) *
1205 (u_int64_t
)SWAP_BE32(mdbp
->drAlBlkSiz
);
1208 * If the embedded volume doesn't start on a block
1209 * boundary, then switch the device to a 512-byte
1210 * block size so everything will line up on a block
1213 if ((embeddedOffset
% blksize
) != 0) {
1214 printf("HFS Mount: embedded volume offset not"
1215 " a multiple of physical block size (%d);"
1216 " switching to 512\n", blksize
);
1218 blkcnt
*= (blksize
/ 512);
1222 mdb_offset
= (embeddedOffset
/ blksize
) + HFS_PRI_SECTOR(blksize
);
1223 if (pread(fd
, buff
, blksize
, mdb_offset
* blksize
) != blksize
) {
1224 printf("failed to read the embedded vhp @ offset %d\n", mdb_offset
* blksize
);
1229 vhp
= (HFSPlusVolumeHeader
*) (buff
+ HFS_PRI_OFFSET(blksize
));
1231 mdbp
= (HFSMasterDirectoryBlock
*)(vhp
);
1232 if ( (SWAP_BE16(mdbp
->drSigWord
) != kHFSSigWord
)
1233 && (SWAP_BE16(mdbp
->drSigWord
) != kHFSPlusSigWord
)
1234 && (SWAP_BE16(mdbp
->drSigWord
) != kHFSXSigWord
)) {
1236 printf("SetJournalInFSState: Invalid Embedded Volume Signature \n");
1241 } else /* pure HFS+ */ {
1243 vhp
= (HFSPlusVolumeHeader
*) mdbp
;
1246 //printf("vol header attributes: 0x%x\n", SWAP_BE32(vhp->attributes));
1247 if ((SWAP_BE32(vhp
->attributes
) & kHFSVolumeJournaledMask
) == 0) {
1253 // Now read the journal info block... (when calculating the
1254 // position, make sure to cast to unsigned first, then to
1255 // off_t so that things don't get sign-extended improperly
1258 pos
= (off_t
)((off_t
)embeddedOffset
+
1259 (off_t
)((unsigned int )SWAP_BE32(vhp
->journalInfoBlock
))*(off_t
)((unsigned int)SWAP_BE32(vhp
->blockSize
)));
1261 if (pread(fd
, buff2
, blksize
, pos
) != blksize
) {
1262 printf("failed to read the journal info block (%s).\n", strerror(errno
));
1267 myjib
= (struct JournalInfoBlock
*)buff2
;
1269 // swap this to host native format so we can diddle with the bits
1270 myjib
->flags
= SWAP_BE32(myjib
->flags
);
1272 if (journal_in_fs
) {
1273 myjib
->flags
|= kJIJournalInFSMask
;
1275 myjib
->flags
&= ~kJIJournalInFSMask
;
1277 myjib
->flags
|= kJIJournalNeedInitMask
;
1279 // and now swap back before writing it out
1280 myjib
->flags
= SWAP_BE32(myjib
->flags
);
1282 if (pwrite(fd
, buff2
, blksize
, pos
) != blksize
) {
1283 printf("failed to re-write the journal info block (%s).\n", strerror(errno
));