]> git.saurik.com Git - apple/hfs.git/blame - hfs_util/hfsutil_jnl.c
hfs-305.10.1.tar.gz
[apple/hfs.git] / hfs_util / hfsutil_jnl.c
CommitLineData
08cdaae8 1/*
41dcebd9 2 * Copyright (c) 1999-2014 Apple Inc. All rights reserved.
08cdaae8
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
635a1ee0
A
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.
08cdaae8 11 *
635a1ee0
A
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
08cdaae8
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
635a1ee0
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
08cdaae8
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 Copyright (c) 2002 Apple Computer, Inc.
24 All Rights Reserved.
25
26 This file contains the routine to make an HFS+ volume journaled
27 and a corresponding routine to turn it off.
28
29 */
30
31#include <sys/types.h>
32#include <sys/attr.h>
33#include <sys/stat.h>
34#include <sys/time.h>
35#include <sys/sysctl.h>
36#include <sys/resource.h>
37#include <sys/vmmeter.h>
38#include <sys/mount.h>
39#include <sys/wait.h>
16f263f5 40#include <sys/ioctl.h>
08cdaae8 41
19348fcb 42#include <sys/disk.h>
08cdaae8
A
43#include <sys/loadable_fs.h>
44#include <hfs/hfs_format.h>
19348fcb 45#include <hfs/hfs_mount.h> /* for hfs sysctl values */
08cdaae8 46
ab40a2da
A
47#include <System/hfs/hfs_fsctl.h>
48
41dcebd9
A
49#include <System/sys/content_protection.h>
50#include <TargetConditionals.h>
51
08cdaae8
A
52#include <errno.h>
53#include <fcntl.h>
54#include <libgen.h>
55#include <pwd.h>
56#include <stdio.h>
57#include <stdlib.h>
58#include <string.h>
59#include <unistd.h>
60
61#include <architecture/byte_order.h>
62
19348fcb
A
63// just in case these aren't in <hfs/hfs_mount.h> yet
64#ifndef HFS_ENABLE_JOURNALING
65#define HFS_ENABLE_JOURNALING 0x082969
66#endif
67#ifndef HFS_DISABLE_JOURNALING
68#define HFS_DISABLE_JOURNALING 0x031272
69#endif
70#ifndef HFS_GET_JOURNAL_INFO
71#define HFS_GET_JOURNAL_INFO 0x6a6e6c69
72#endif
08cdaae8
A
73
74/* getattrlist buffers start with an extra length field */
75struct ExtentsAttrBuf {
76 unsigned long infoLength;
77 HFSPlusExtentRecord extents;
78};
79typedef struct ExtentsAttrBuf ExtentsAttrBuf;
80
ab40a2da
A
81#ifndef HFSIOC_GET_JOURNAL_INFO
82# include <sys/ioctl.h>
83struct hfs_journal_info {
84 off_t jstart;
85 off_t jsize;
86};
87# define HFSIOC_GET_JOURNAL_INFO _IOR('h', 17, struct hfs_journal_info)
88#endif
08cdaae8
A
89
90
91#define kIsInvisible 0x4000
92
93/*
94 * Generic Finder file/dir data
95 */
96struct FinderInfo {
97 u_int32_t opaque_1[2];
98 u_int16_t fdFlags; /* Finder flags */
99 int16_t opaque_2[11];
100};
101typedef struct FinderInfo FinderInfo;
102
103/* getattrlist buffers start with an extra length field */
104struct FinderAttrBuf {
105 unsigned long infoLength;
106 FinderInfo finderInfo;
107};
108typedef struct FinderAttrBuf FinderAttrBuf;
109
110
111int hide_file(const char * file)
112{
113 struct attrlist alist = {0};
114 FinderAttrBuf finderInfoBuf = {0};
115 int result;
116
117 alist.bitmapcount = ATTR_BIT_MAP_COUNT;
118 alist.commonattr = ATTR_CMN_FNDRINFO;
119
120 result = getattrlist(file, &alist, &finderInfoBuf, sizeof(finderInfoBuf), 0);
121 if (result) {
19348fcb
A
122 return (errno);
123 }
08cdaae8
A
124
125 if (finderInfoBuf.finderInfo.fdFlags & kIsInvisible) {
19348fcb
A
126 printf("hide: %s is alreadly invisible\n", file);
127 return (0);
08cdaae8
A
128 }
129
130 finderInfoBuf.finderInfo.fdFlags |= kIsInvisible;
131
132 result = setattrlist(file, &alist, &finderInfoBuf.finderInfo, sizeof(FinderInfo), 0);
133
134 return (result == -1 ? errno : result);
135}
136
16f263f5
A
137off_t
138get_start_block(const char *file, uint32_t fs_block_size)
08cdaae8 139{
16f263f5
A
140 off_t cur_pos, phys_start, len;
141 int fd, err;
142 struct log2phys l2p;
143 struct stat st;
08cdaae8 144
16f263f5
A
145 fd = open(file, O_RDONLY);
146 if (fd < 0) {
147 return -1;
148 }
08cdaae8 149
16f263f5
A
150 if (fstat(fd, &st) < 0) {
151 fprintf(stderr, "can't stat %s (%s)\n", file, strerror(errno));
152 close(fd);
19348fcb 153 return -1;
08cdaae8
A
154 }
155
16f263f5
A
156 fs_block_size = st.st_blksize; // XXXdbg quick hack for now
157
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);
163
164 if (phys_start == 0) {
165 phys_start = l2p.l2p_devoffset;
166 len = fs_block_size;
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);
170 close(fd);
171 return -1;
172 // phys_start = l2p.l2p_devoffset;
173 // len = fs_block_size;
174 } else {
175 len += fs_block_size;
176 }
177 }
178
179 close(fd);
180
181 //printf("%s start offset %lld; byte len %lld (blksize %d)\n",
182 // file, phys_start, len, fs_block_size);
183
ab40a2da 184 if ((phys_start / (unsigned int)fs_block_size) & 0xffffffff00000000LL) {
16f263f5 185 fprintf(stderr, "%s : starting block is > 32bits!\n", file);
19348fcb 186 return -1;
08cdaae8 187 }
16f263f5
A
188
189 return phys_start;
190}
191
192
193//
194// Get the embedded offset (if any) for an hfs+ volume.
195// This is pretty skanky that we have to do this but
196// that's life...
197//
198#include <sys/disk.h>
199#include <hfs/hfs_format.h>
200
201#include <machine/endian.h>
202
203#define HFS_PRI_SECTOR(blksize) (1024 / (blksize))
204#define HFS_PRI_OFFSET(blksize) ((blksize) > 1024 ? 1024 : 0)
205
ab40a2da
A
206#include <libkern/OSByteOrder.h>
207
16f263f5
A
208#define SWAP_BE16(x) ntohs(x)
209#define SWAP_BE32(x) ntohl(x)
ab40a2da 210#define SWAP_BE64(x) OSSwapConstInt64(x)
16f263f5
A
211
212
213off_t
214get_embedded_offset(char *devname)
215{
216 int fd = -1;
217 off_t ret = 0;
218 char *buff = NULL, rawdev[256];
219 u_int64_t blkcnt;
220 u_int32_t blksize;
221 HFSMasterDirectoryBlock *mdbp;
222 off_t embeddedOffset;
223 struct statfs sfs;
224 struct stat st;
225
226 restart:
227 if (stat(devname, &st) != 0) {
228 fprintf(stderr, "Could not access %s (%s)\n", devname, strerror(errno));
229 ret = -1;
230 goto out;
231 }
232
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));
239 ret = -1;
240 goto out;
241 }
242
ab40a2da
A
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]);
16f263f5
A
246 devname = &rawdev[0];
247 goto restart;
248 }
08cdaae8 249
16f263f5
A
250 fd = open(devname, O_RDONLY);
251 if (fd < 0) {
252 fprintf(stderr, "can't open: %s (%s)\n", devname, strerror(errno));
253 ret = -1;
254 goto out;
255 }
256
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));
260 blksize = 512;
261 ret = -1;
262 goto out;
263 }
264
265 /* Get the number of physical blocks. */
266 if (ioctl(fd, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt)) {
267 struct stat st;
268 fprintf(stderr, "failed to get block count. trying stat().\n");
269 if (fstat(fd, &st) != 0) {
270 ret = -1;
271 goto out;
272 }
273
274 blkcnt = st.st_size / blksize;
275 }
276
16f263f5
A
277 /*
278 * At this point:
279 * blksize has our prefered physical block size
280 * blkcnt has the total number of physical blocks
281 */
282
283 buff = (char *)malloc(blksize);
284
285 if (pread(fd, buff, blksize, HFS_PRI_SECTOR(blksize)*blksize) != blksize) {
04a16b11
A
286 fprintf(stderr, "failed to read volume header @ offset %d (%s)\n",
287 HFS_PRI_SECTOR(blksize), strerror(errno));
288 ret = -1;
289 goto out;
16f263f5
A
290 }
291
04a16b11
A
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");
297 ret = -1;
298 goto out;
299 }
16f263f5
A
300
301 if ((SWAP_BE16(mdbp->drSigWord) == kHFSSigWord) && (SWAP_BE16(mdbp->drEmbedSigWord) != kHFSPlusSigWord)) {
302 ret = -1;
303 goto out;
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);
309
310 /*
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
314 * boundary.
315 */
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);
320
321 blkcnt *= (blksize / 512);
322 blksize = 512;
323 }
324
325 } else { /* pure HFS+ */
326 embeddedOffset = 0;
327 }
328
329 ret = embeddedOffset;
330
331 out:
332 if (buff) {
333 free(buff);
334 }
335 if (fd >= 0)
336 close(fd);
337
338 return ret;
08cdaae8
A
339}
340
16f263f5
A
341
342
08cdaae8
A
343static const char *journal_fname = ".journal";
344static const char *jib_fname = ".journal_info_block";
345
51e135ce
A
346int
347DoMakeJournaled(char *volname, int jsize) {
348 int fd, i, block_size, journal_size = 8*1024*1024;
349 char *buf;
350 int ret;
351 fstore_t fst;
352 int32_t jstart_block, jinfo_block;
353 int sysctl_info[8];
354 JournalInfoBlock jib;
355 struct statfs sfs;
356 static char tmpname[MAXPATHLEN];
357 off_t start_block, embedded_offset;
358
359 if (statfs(volname, &sfs) != 0) {
360 fprintf(stderr, "Can't stat volume %s (%s).\n", volname, strerror(errno));
361 return 10;
362 }
08cdaae8 363
51e135ce
A
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).
367 //
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);
ab40a2da 370 return 10;
51e135ce
A
371 }
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",
376 volname);
377 return 10;
378 }
379 unlink(tmpname);
08cdaae8 380
51e135ce
A
381 if (sfs.f_flags & MNT_JOURNALED) {
382 fprintf(stderr, "Volume %s is already journaled.\n", volname);
383 return 1;
384 }
19348fcb 385
51e135ce
A
386 if (jsize != 0) {
387 journal_size = jsize;
388 } else {
389 int scale;
390
391 //
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.
394 //
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;
399 }
400 }
08cdaae8 401
51e135ce
A
402 if (chdir(volname) != 0) {
403 fprintf(stderr, "Can't locate volume %s to make it journaled (%s).\n",
404 volname, strerror(errno));
405 return 10;
08cdaae8
A
406 }
407
08cdaae8 408
51e135ce
A
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");
413 return 15;
414 }
415 // printf("Embedded offset == 0x%llx\n", embedded_offset);
416
41dcebd9
A
417 /*
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
420 */
421 fd = open_dprotected_np (journal_fname, O_CREAT|O_TRUNC|O_RDWR, PROTECTION_CLASS_D, 0, 000);
51e135ce
A
422 if (fd < 0) {
423 fprintf(stderr, "Can't create journal file on volume %s (%s)\n",
424 volname, strerror(errno));
425 return 5;
426 }
16f263f5 427
51e135ce
A
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));
431 return 5;
432 }
16f263f5 433
08cdaae8 434
51e135ce
A
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
437 // bits).
438 //
439 fchmod(fd, 0);
440
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);
445 close(fd);
446 unlink(journal_fname);
447 return 5;
448 }
08cdaae8 449
51e135ce
A
450retry:
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;
455
456 ret = fcntl(fd, F_PREALLOCATE, &fst);
457 if (ret < 0) {
458 if (journal_size >= 2*1024*1024) {
459 fprintf(stderr, "Not enough contiguous space for a %d k journal. Retrying.\n",
460 journal_size/1024);
461 journal_size /= 2;
462 ftruncate(fd, 0); // make sure the file is zero bytes long.
463 goto retry;
464 } else {
465 fprintf(stderr, "Disk too fragmented to enable journaling.\n");
466 fprintf(stderr, "Please run a defragmenter on %s.\n", volname);
467 close(fd);
468 unlink(journal_fname);
469 return 10;
470 }
471 }
08cdaae8 472
51e135ce
A
473 printf("Allocated %lldK for journal file.\n", fst.fst_bytesalloc/1024LL);
474 buf = (char *)calloc(block_size, 1);
475 if (buf) {
476 for(i=0; i < journal_size/block_size; i++) {
477 ret = write(fd, buf, block_size);
478 if (ret != block_size) {
479 break;
480 }
481 }
482
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));
486 }
19348fcb 487 } else {
51e135ce
A
488 printf("Could not allocate memory to write to the journal on volume %s (%s)\n",
489 volname, strerror(errno));
19348fcb 490 }
08cdaae8 491
51e135ce
A
492 fsync(fd);
493 close(fd);
494 hide_file(journal_fname);
495
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);
501 return 20;
19348fcb 502 }
51e135ce
A
503 jstart_block = (start_block / block_size) - (embedded_offset / block_size);
504
505 memset(&jib, 'Z', sizeof(jib));
506 jib.flags = kJIJournalInFSMask;
507 jib.offset = (off_t)((unsigned int)jstart_block) * (off_t)((unsigned int)block_size);
508 jib.size = (off_t)((unsigned int)journal_size);
509
41dcebd9
A
510 /*
511 * Use open_dprotected_np to create JIB as a class D file. This will
512 * behave the same as a standard open(2) on systems that do not support content protection
513 */
514 fd = open_dprotected_np(jib_fname, O_CREAT|O_TRUNC|O_RDWR, PROTECTION_CLASS_D, 0, 000);
51e135ce
A
515 if (fd < 0) {
516 fprintf(stderr, "Could not create journal info block file on volume %s (%s)\n",
517 volname, strerror(errno));
518 unlink(journal_fname);
519 return 5;
19348fcb 520 }
08cdaae8 521
51e135ce
A
522 if (fcntl(fd, F_NOCACHE, 1)) {
523 fprintf(stderr, "Could not create journal info block (NC) file on volume %s (%s)\n",
524 volname, strerror(errno));
525 return 5;
526 }
08cdaae8 527
51e135ce
A
528 // swap the data before we copy it
529 jib.flags = OSSwapBigToHostInt32(jib.flags);
530 jib.offset = OSSwapBigToHostInt64(jib.offset);
531 jib.size = OSSwapBigToHostInt64(jib.size);
08cdaae8 532
51e135ce 533 memcpy(buf, &jib, sizeof(jib));
08cdaae8 534
51e135ce
A
535 // now put it back the way it was
536 jib.size = OSSwapBigToHostInt64(jib.size);
537 jib.offset = OSSwapBigToHostInt64(jib.offset);
538 jib.flags = OSSwapBigToHostInt32(jib.flags);
539
540 if (write(fd, buf, block_size) != block_size) {
541 fprintf(stderr, "Failed to write journal info block on volume %s (%s)!\n",
542 volname, strerror(errno));
543 unlink(journal_fname);
544 return 10;
545 }
546
547 fsync(fd);
548 close(fd);
549 hide_file(jib_fname);
550
551 start_block = get_start_block(jib_fname, block_size);
552 if (start_block == (off_t)-1) {
553 fprintf(stderr, "Failed to get start block for %s (%s)\n",
554 jib_fname, strerror(errno));
555 unlink(journal_fname);
556 unlink(jib_fname);
557 return 20;
558 }
559 jinfo_block = (start_block / block_size) - (embedded_offset / block_size);
560
561
562 //
563 // Now make the volume journaled!
564 //
565 memset(sysctl_info, 0, sizeof(sysctl_info));
566 sysctl_info[0] = CTL_VFS;
567 sysctl_info[1] = sfs.f_fsid.val[1];
568 sysctl_info[2] = HFS_ENABLE_JOURNALING;
569 sysctl_info[3] = jinfo_block;
570 sysctl_info[4] = jstart_block;
571 sysctl_info[5] = journal_size;
572
573 //printf("fs type: 0x%x\n", sysctl_info[1]);
574 //printf("jinfo block : 0x%x\n", jinfo_block);
575 //printf("jstart block: 0x%x\n", jstart_block);
576 //printf("journal size: 0x%x\n", journal_size);
577
578 ret = sysctl((void *)sysctl_info, 6, NULL, NULL, NULL, 0);
579 if (ret != 0) {
580 fprintf(stderr, "Failed to make volume %s journaled (%s)\n",
581 volname, strerror(errno));
582 unlink(journal_fname);
583 unlink(jib_fname);
584 return 20;
585 }
586
587 return 0;
08cdaae8
A
588}
589
590
591int
51e135ce
A
592DoUnJournal(char *volname) {
593 int result;
594 int sysctl_info[8];
595 struct statfs sfs;
596 char jbuf[MAXPATHLEN];
597
598 if (statfs(volname, &sfs) != 0) {
599 fprintf(stderr, "Can't stat volume %s (%s).\n", volname, strerror(errno));
600 return 10;
601 }
08cdaae8 602
51e135ce
A
603 if (strcmp(sfs.f_fstypename, "hfs") != 0) {
604 fprintf(stderr, "Volume %s (%s) is not a HFS volume.\n", volname, sfs.f_mntfromname);
ab40a2da 605 return 1;
51e135ce 606 }
ab40a2da 607
51e135ce
A
608 if ((sfs.f_flags & MNT_JOURNALED) == 0) {
609 fprintf(stderr, "Volume %s (%s) is not journaled.\n", volname, sfs.f_mntfromname);
610 return 1;
611 }
08cdaae8 612
51e135ce
A
613 if (chdir(volname) != 0) {
614 fprintf(stderr, "Can't locate volume %s to turn off journaling (%s).\n",
615 volname, strerror(errno));
616 return 10;
617 }
08cdaae8 618
51e135ce
A
619 memset(sysctl_info, 0, sizeof(sysctl_info));
620 sysctl_info[0] = CTL_VFS;
621 sysctl_info[1] = sfs.f_fsid.val[1];
622 sysctl_info[2] = HFS_DISABLE_JOURNALING;
08cdaae8 623
51e135ce
A
624 result = sysctl((void *)sysctl_info, 3, NULL, NULL, NULL, 0);
625 if (result != 0) {
626 fprintf(stderr, "Failed to make volume %s UN-journaled (%s)\n",
627 volname, strerror(errno));
628 return 20;
629 }
630
631 snprintf(jbuf, sizeof(jbuf), "%s/%s", volname, journal_fname);
632 if (unlink(jbuf) != 0) {
633 fprintf(stderr, "Failed to remove the journal %s (%s)\n",
634 jbuf, strerror(errno));
635 }
636
637 snprintf(jbuf, sizeof(jbuf), "%s/%s", volname, jib_fname);
638 if (unlink(jbuf) != 0) {
639 fprintf(stderr, "Failed to remove the journal info block %s (%s)\n",
640 jbuf, strerror(errno));
641 }
642
643 printf("Journaling disabled on %s mounted at %s.\n", sfs.f_mntfromname, volname);
08cdaae8 644
51e135ce 645 return 0;
19348fcb
A
646}
647
648
ab40a2da
A
649
650
651int
652get_journal_info(char *devname, struct JournalInfoBlock *jib)
653{
654 int fd = -1, ret = 0;
655 char *buff = NULL, *buff2 = NULL;
656 u_int64_t disksize;
657 u_int64_t blkcnt;
658 u_int32_t blksize;
659 daddr_t mdb_offset;
660 HFSMasterDirectoryBlock *mdbp;
661 HFSPlusVolumeHeader *vhp;
662 off_t embeddedOffset, pos;
663 struct JournalInfoBlock *myjib;
664
665 fd = open(devname, O_RDONLY);
666 if (fd < 0) {
667 printf("can't open: %s (%s)\n", devname, strerror(errno));
668 ret = -5;
669 goto out;
670 }
671
672 /* Get the real physical block size. */
673 if (ioctl(fd, DKIOCGETBLOCKSIZE, (caddr_t)&blksize) != 0) {
674 printf("can't get the device block size (%s). assuming 512\n", strerror(errno));
675 blksize = 512;
676 ret = -1;
677 goto out;
678 }
679
680 /* Get the number of physical blocks. */
681 if (ioctl(fd, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt)) {
682 struct stat st;
683 printf("failed to get block count. trying stat().\n");
684 if (fstat(fd, &st) != 0) {
685 ret = -1;
686 goto out;
687 }
688
689 blkcnt = st.st_size / blksize;
690 }
691
692 /* Compute an accurate disk size */
693 disksize = blkcnt * (u_int64_t)blksize;
694
695 /*
696 * There are only 31 bits worth of block count in
697 * the buffer cache. So for large volumes a 4K
698 * physical block size is needed.
699 */
700 if (blksize == 512 && blkcnt > (u_int64_t)0x000000007fffffff) {
701 blksize = 4096;
702 }
703
704 /*
705 * At this point:
706 * blksize has our prefered physical block size
707 * blkcnt has the total number of physical blocks
708 */
709
710 buff = (char *)malloc(blksize);
711 buff2 = (char *)malloc(blksize);
712
713 if (pread(fd, buff, blksize, HFS_PRI_SECTOR(blksize)*blksize) != blksize) {
714 printf("failed to read volume header @ offset %d (%s)\n",
715 HFS_PRI_SECTOR(blksize), strerror(errno));
716 ret = -1;
717 goto out;
718 }
719
04a16b11
A
720 mdbp = (HFSMasterDirectoryBlock *)(buff + HFS_PRI_OFFSET(blksize));
721
722 if ( (SWAP_BE16(mdbp->drSigWord) != kHFSSigWord)
723 && (SWAP_BE16(mdbp->drSigWord) != kHFSPlusSigWord)
724 && (SWAP_BE16(mdbp->drSigWord) != kHFSXSigWord)) {
725 ret = -1;
726 printf("get_journal_info: invalid volume signature\n");
727 goto out;
ab40a2da
A
728 }
729
730 mdbp->drSigWord = SWAP_BE16(mdbp->drSigWord);
731 mdbp->drEmbedSigWord = SWAP_BE16(mdbp->drEmbedSigWord);
732 mdbp->drAlBlSt = SWAP_BE16(mdbp->drAlBlSt);
733 mdbp->drEmbedExtent.startBlock = SWAP_BE16(mdbp->drEmbedExtent.startBlock);
734 mdbp->drAlBlkSiz = SWAP_BE32(mdbp->drAlBlkSiz);
735 mdbp->drEmbedExtent.blockCount = SWAP_BE16(mdbp->drEmbedExtent.blockCount);
ab40a2da 736
ab40a2da
A
737
738 if ((mdbp->drSigWord == kHFSSigWord) && (mdbp->drEmbedSigWord != kHFSPlusSigWord)) {
739 // normal hfs can not ever be journaled
740 goto out;
741 }
742
743 /* Get the embedded Volume Header */
744 if (mdbp->drEmbedSigWord == kHFSPlusSigWord) {
745 embeddedOffset = mdbp->drAlBlSt * 512;
746 embeddedOffset += (u_int64_t)mdbp->drEmbedExtent.startBlock *
747 (u_int64_t)mdbp->drAlBlkSiz;
748
749 /*
750 * If the embedded volume doesn't start on a block
751 * boundary, then switch the device to a 512-byte
752 * block size so everything will line up on a block
753 * boundary.
754 */
755 if ((embeddedOffset % blksize) != 0) {
756 printf("HFS Mount: embedded volume offset not"
757 " a multiple of physical block size (%d);"
758 " switching to 512\n", blksize);
759
760 blkcnt *= (blksize / 512);
761 blksize = 512;
762 }
763
764 disksize = (u_int64_t)mdbp->drEmbedExtent.blockCount *
765 (u_int64_t)mdbp->drAlBlkSiz;
766
767 mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize);
768 if (pread(fd, buff, blksize, mdb_offset * blksize) != blksize) {
769 printf("failed to read the embedded vhp @ offset %d\n", mdb_offset * blksize);
770 ret = -1;
771 goto out;
772 }
773
04a16b11
A
774 vhp = (HFSPlusVolumeHeader*) (buff + HFS_PRI_OFFSET(blksize));
775
776 mdbp = (HFSMasterDirectoryBlock *)vhp;
777 if ( (SWAP_BE16(mdbp->drSigWord) != kHFSSigWord)
778 && (SWAP_BE16(mdbp->drSigWord) != kHFSPlusSigWord)
779 && (SWAP_BE16(mdbp->drSigWord) != kHFSXSigWord)) {
780 ret = -1;
781
782 printf("get_journal_info: invalid embedded volume signature \n");
783 goto out;
784 }
785
ab40a2da
A
786 } else /* pure HFS+ */ {
787 embeddedOffset = 0;
788 vhp = (HFSPlusVolumeHeader*) mdbp;
789 }
790
791 if ((SWAP_BE32(vhp->attributes) & kHFSVolumeJournaledMask) == 0) {
792 ret = 0;
793 goto out;
794 }
795
796 //
797 // Now read the journal info block... (when calculating the
798 // position, make sure to cast to unsigned first, then to
799 // off_t so that things don't get sign-extended improperly
800 // or truncated).
801 //
802 pos = (off_t)((off_t)embeddedOffset +
803 (off_t)((unsigned int)SWAP_BE32(vhp->journalInfoBlock))*(off_t)((unsigned int)SWAP_BE32(vhp->blockSize)));
804
805 if (pread(fd, buff2, blksize, pos) != blksize) {
806 printf("failed to read the journal info block (%s).\n", strerror(errno));
807 ret = -1;
808 goto out;
809 }
810
811 myjib = (struct JournalInfoBlock *)buff2;
812 myjib->flags = SWAP_BE32(myjib->flags);
813 myjib->offset = SWAP_BE64(myjib->offset);
814 myjib->size = SWAP_BE64(myjib->size);
815
816 memcpy(jib, myjib, sizeof(*myjib));
817
818 ret = 1;
819
820out:
821 if (buff)
822 free(buff);
823 if (buff2)
824 free(buff2);
825 if (fd >= 0)
826 close(fd);
827
828 return ret;
829}
830
831
19348fcb
A
832int
833DoGetJournalInfo(char *volname)
834{
19348fcb 835 struct statfs sfs;
ab40a2da 836 struct hfs_journal_info jinfo;
19348fcb 837
ab40a2da
A
838 if (strncmp(volname, "/dev/", 5) == 0 || strncmp(volname, "disk", 4) == 0 || strncmp(volname, "rdisk", 5) == 0) {
839 struct JournalInfoBlock jib;
840 int ret;
841 char fulldevname[256];
842
843 if (strncmp(volname, "disk", 4) == 0 || strncmp(volname, "rdisk", 5) == 0) {
844 snprintf(fulldevname, sizeof(fulldevname), "/dev/%s", volname);
845 volname = &fulldevname[0];
846 }
847
848 // try the name as a device name...
849 ret = get_journal_info(volname, &jib);
850 if (ret == 0) {
851 printf("Volume %s is not journaled.\n", volname);
852 return 0;
853 } else if (ret < 0) {
854 printf("Volume %s does not appear to be an HFS+ volume.\n", volname);
855 return 10;
856 } else {
857 if (jib.flags & kJIJournalInFSMask) {
858 printf("%s : journal size %lld k at offset 0x%llx\n", volname, jib.size/1024, jib.offset);
859 } else {
860 printf("%s: external journal stored on partition with uuid %s on machine w/serial number %s\n",
861 volname, jib.ext_jnl_uuid, jib.machine_serial_num);
862 }
863
864 return 0;
865 }
866
867 }
868
19348fcb 869 if (statfs(volname, &sfs) != 0) {
ab40a2da
A
870 fprintf(stderr, "Unable to get fs info for %s\n", volname);
871 return 10;
19348fcb
A
872 }
873
874 if ((sfs.f_flags & MNT_JOURNALED) == 0) {
875 fprintf(stderr, "Volume %s is not journaled.\n", volname);
876 return 1;
877 }
878
ab40a2da 879 if (fsctl(volname, HFSIOC_GET_JOURNAL_INFO, &jinfo, 0) != 0) {
19348fcb
A
880 fprintf(stderr, "Failed to get journal info for volume %s (%s)\n",
881 volname, strerror(errno));
882 return 20;
883 }
884
ab40a2da
A
885 if (jinfo.jstart == 0) {
886 char rawdev[256];
887
888 snprintf(rawdev, sizeof(rawdev), "/dev/r%s", &sfs.f_mntfromname[5]);
889
890 // it's an external journal so get the info the
891 // other way.
892 return DoGetJournalInfo(&rawdev[0]);
893 }
894
895 if (jinfo.jsize == 0) {
19348fcb
A
896 printf("%s : not journaled.\n", volname);
897 } else {
ab40a2da 898 printf("%s : journal size %lld k at offset 0x%llx\n", volname, jinfo.jsize/1024, jinfo.jstart);
19348fcb
A
899 }
900
901 return 0;
08cdaae8 902}
e74bfeef
A
903
904
905int
906RawDisableJournaling(char *devname)
907{
908 int fd = -1, ret = 0;
ab40a2da 909 char *buff = NULL, rawdev[256], unrawdev[256];
e74bfeef
A
910 u_int64_t disksize;
911 u_int64_t blkcnt;
912 u_int32_t blksize;
913 daddr_t mdb_offset;
914 HFSMasterDirectoryBlock *mdbp;
915 HFSPlusVolumeHeader *vhp;
916 off_t embeddedOffset, hdr_offset;
e74bfeef 917 struct stat st;
ab40a2da 918 struct statfs *fsinfo;
e74bfeef 919
ab40a2da
A
920 // assume that the name provided is a raw device name
921 strlcpy(rawdev, devname, sizeof(rawdev));
e74bfeef 922
ab40a2da
A
923restart:
924 if (stat(rawdev, &st) != 0) {
925 fprintf(stderr, "Could not access %s (%s)\n", devname, strerror(errno));
926 ret = -1;
927 goto out;
928 }
929
930 if (S_ISCHR(st.st_mode) == 0) {
931 if (S_ISBLK(st.st_mode)) {
932 // this is a block device, convert the name to
933 // raw character device and try again
934 snprintf(rawdev, sizeof(rawdev), "/dev/r%s", devname + 5);
935 goto restart;
936 } else {
937 // probably it is a mount point
938 return DoUnJournal(devname);
939 }
e74bfeef 940 } else {
ab40a2da
A
941 // convert the character raw device name to
942 // block device name to compare with getmntinfo output
943 snprintf(unrawdev, sizeof(unrawdev), "/dev/%s", rawdev + 6);
944 }
945
946 // make sure that the file system on the device node is not mounted
947 ret = getmntinfo(&fsinfo, MNT_NOWAIT);
948 if (ret == 0) {
949 fprintf (stderr, "Error getting list of mounted filesystems\n");
e74bfeef
A
950 ret = -1;
951 goto out;
ab40a2da
A
952 }
953
954 while (ret--) {
955 // the file system on this device node is currently mounted
956 if (strcmp(unrawdev, fsinfo[ret].f_mntfromname) == 0) {
957 return DoUnJournal(fsinfo[ret].f_mntonname);
958 }
e74bfeef
A
959 }
960
ab40a2da 961 fd = open(rawdev, O_RDWR);
e74bfeef
A
962 if (fd < 0) {
963 fprintf(stderr, "can't open: %s (%s)\n", devname, strerror(errno));
964 ret = -1;
965 goto out;
966 }
967
968 /* Get the real physical block size. */
969 if (ioctl(fd, DKIOCGETBLOCKSIZE, (caddr_t)&blksize) != 0) {
970 fprintf(stderr, "can't get the device block size (%s). assuming 512\n", strerror(errno));
971 blksize = 512;
972 ret = -1;
973 goto out;
974 }
975
976 /* Get the number of physical blocks. */
977 if (ioctl(fd, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt)) {
978 struct stat st;
979
980 if (fstat(fd, &st) != 0) {
981 ret = -1;
982 goto out;
983 }
984
985 blkcnt = st.st_size / blksize;
986 }
987
988 /* Compute an accurate disk size */
989 disksize = blkcnt * (u_int64_t)blksize;
990
991 /*
992 * There are only 31 bits worth of block count in
993 * the buffer cache. So for large volumes a 4K
994 * physical block size is needed.
995 */
996 if (blksize == 512 && blkcnt > (u_int64_t)0x000000007fffffff) {
997 blksize = 4096;
998 }
999
1000 /*
1001 * At this point:
1002 * blksize has our prefered physical block size
1003 * blkcnt has the total number of physical blocks
1004 */
1005
1006 buff = (char *)malloc(blksize);
1007
1008 hdr_offset = HFS_PRI_SECTOR(blksize)*blksize;
1009 if (pread(fd, buff, blksize, hdr_offset) != blksize) {
04a16b11
A
1010 fprintf(stderr, "RawDisableJournaling: failed to read volume header @ offset %lld (%s)\n",
1011 hdr_offset, strerror(errno));
1012 ret = -1;
1013 goto out;
e74bfeef
A
1014 }
1015
04a16b11
A
1016 mdbp = (HFSMasterDirectoryBlock *)(buff + HFS_PRI_OFFSET(blksize));
1017 if ( (SWAP_BE16(mdbp->drSigWord) != kHFSSigWord)
1018 && (SWAP_BE16(mdbp->drSigWord) != kHFSPlusSigWord)
1019 && (SWAP_BE16(mdbp->drSigWord) != kHFSXSigWord)) {
1020 ret = -1;
1021 printf("RawDisableJournaling: Invalid Volume Signature \n");
1022 goto out;
e74bfeef 1023 }
04a16b11 1024
e74bfeef
A
1025 if ((SWAP_BE16(mdbp->drSigWord) == kHFSSigWord) && (SWAP_BE16(mdbp->drEmbedSigWord) != kHFSPlusSigWord)) {
1026 // normal hfs can not ever be journaled
1027 fprintf(stderr, "disable_journaling: volume is only regular HFS, not HFS+\n");
1028 goto out;
1029 }
1030
1031 /* Get the embedded Volume Header */
1032 if (SWAP_BE16(mdbp->drEmbedSigWord) == kHFSPlusSigWord) {
04a16b11
A
1033 embeddedOffset = SWAP_BE16(mdbp->drAlBlSt) * 512;
1034 embeddedOffset += (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.startBlock) * (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
1035
1036 /*
1037 * If the embedded volume doesn't start on a block
1038 * boundary, then switch the device to a 512-byte
1039 * block size so everything will line up on a block
1040 * boundary.
1041 */
1042 if ((embeddedOffset % blksize) != 0) {
1043 fprintf(stderr, "HFS Mount: embedded volume offset not"
1044 " a multiple of physical block size (%d);"
1045 " switching to 512\n", blksize);
1046
1047 blkcnt *= (blksize / 512);
1048 blksize = 512;
1049 }
1050
1051 disksize = (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.blockCount) * (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
1052
1053 mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize);
1054 hdr_offset = mdb_offset * blksize;
1055 if (pread(fd, buff, blksize, hdr_offset) != blksize) {
1056 fprintf(stderr, "failed to read the embedded vhp @ offset %d\n", mdb_offset * blksize);
1057 ret = -1;
1058 goto out;
1059 }
1060
1061 vhp = (HFSPlusVolumeHeader*) (buff + HFS_PRI_OFFSET(blksize));
1062
1063 mdbp = (HFSMasterDirectoryBlock *)vhp;
1064 if ( (SWAP_BE16(mdbp->drSigWord) != kHFSSigWord)
1065 && (SWAP_BE16(mdbp->drSigWord) != kHFSPlusSigWord)
1066 && (SWAP_BE16(mdbp->drSigWord) != kHFSXSigWord)) {
1067 ret = -1;
1068
1069 printf("RawDisableJournaling: invalid embedded volume signature \n");
1070 goto out;
1071 }
e74bfeef 1072
e74bfeef 1073 } else /* pure HFS+ */ {
04a16b11
A
1074 embeddedOffset = 0;
1075 vhp = (HFSPlusVolumeHeader*) mdbp;
e74bfeef
A
1076 }
1077
1078
1079 if ((SWAP_BE32(vhp->attributes) & kHFSVolumeJournaledMask) != 0) {
04a16b11
A
1080 unsigned int tmp = SWAP_BE32(vhp->attributes);
1081
1082 tmp &= ~kHFSVolumeJournaledMask;
1083 vhp->attributes = SWAP_BE32(tmp);
1084 if ((tmp = pwrite(fd, buff, blksize, hdr_offset)) != blksize) {
1085 fprintf(stderr, "Update of super-block on %s failed! (%d != %d, %s)\n",
1086 devname, tmp, blksize, strerror(errno));
1087 } else {
1088 fprintf(stderr, "Turned off the journaling bit for %s\n", devname);
1089 }
e74bfeef 1090 } else {
04a16b11 1091 fprintf(stderr, "disable_journaling: %s is not journaled.\n", devname);
e74bfeef 1092 }
04a16b11 1093
e74bfeef
A
1094
1095 out:
1096 if (buff)
1097 free(buff);
1098 if (fd >= 0)
1099 close(fd);
1100
1101 return ret;
1102}
ab40a2da
A
1103
1104
1105
1106int
1107SetJournalInFSState(const char *devname, int journal_in_fs)
1108{
1109 int fd = -1, ret = 0;
1110 char *buff = NULL, *buff2 = NULL;
1111 u_int64_t blkcnt;
1112 u_int32_t blksize;
1113 daddr_t mdb_offset;
1114 HFSMasterDirectoryBlock *mdbp;
1115 HFSPlusVolumeHeader *vhp;
1116 off_t embeddedOffset, pos;
1117 struct JournalInfoBlock *myjib;
1118
1119 fd = open(devname, O_RDWR);
1120 if (fd < 0) {
1121 printf("can't open: %s (%s)\n", devname, strerror(errno));
1122 ret = -1;
1123 goto out;
1124 }
1125
1126 /* Get the real physical block size. */
1127 if (ioctl(fd, DKIOCGETBLOCKSIZE, (caddr_t)&blksize) != 0) {
1128 printf("can't get the device block size (%s). assuming 512\n", strerror(errno));
1129 blksize = 512;
1130 ret = -1;
1131 goto out;
1132 }
1133
1134 /* Get the number of physical blocks. */
1135 if (ioctl(fd, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt)) {
1136 struct stat st;
1137 printf("failed to get block count. trying stat().\n");
1138 if (fstat(fd, &st) != 0) {
1139 ret = -1;
1140 goto out;
1141 }
1142
1143 blkcnt = st.st_size / blksize;
1144 }
1145
1146 /*
1147 * There used to only be 31 bits worth of block count in
1148 * the buffer cache. So for large volumes a 4K
1149 * physical block size is needed.
1150 */
1151 if (blksize == 512 && blkcnt > (u_int64_t)0x000000007fffffff) {
1152 blksize = 4096;
1153 }
1154
1155 /*
1156 * At this point:
1157 * blksize has our prefered physical block size
1158 * blkcnt has the total number of physical blocks
1159 */
1160
1161 buff = (char *)malloc(blksize);
1162 buff2 = (char *)malloc(blksize);
1163
1164 if (pread(fd, buff, blksize, HFS_PRI_SECTOR(blksize)*blksize) != blksize) {
1165 printf("failed to read volume header @ offset %d (%s)\n",
1166 HFS_PRI_SECTOR(blksize), strerror(errno));
1167 ret = -1;
1168 goto out;
1169 }
1170
04a16b11 1171 mdbp = (HFSMasterDirectoryBlock *)(buff + HFS_PRI_OFFSET(blksize));
ab40a2da 1172
ab40a2da 1173
04a16b11
A
1174 if ( (SWAP_BE16(mdbp->drSigWord) != kHFSSigWord)
1175 && (SWAP_BE16(mdbp->drSigWord) != kHFSPlusSigWord)
1176 && (SWAP_BE16(mdbp->drSigWord) != kHFSXSigWord)) {
1177 ret = -1;
1178 printf ("SetJournalInFSState: Invalid Volume Signature \n");
1179 goto out;
ab40a2da
A
1180 }
1181
1182 if ((SWAP_BE16(mdbp->drSigWord) == kHFSSigWord) && (SWAP_BE16(mdbp->drEmbedSigWord) != kHFSPlusSigWord)) {
1183 // normal hfs can not ever be journaled
1184 goto out;
1185 }
1186
1187 /* Get the embedded Volume Header */
1188 if (SWAP_BE16(mdbp->drEmbedSigWord) == kHFSPlusSigWord) {
1189 embeddedOffset = SWAP_BE16(mdbp->drAlBlSt) * 512;
1190 embeddedOffset += (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.startBlock) *
1191 (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
1192
1193 /*
1194 * If the embedded volume doesn't start on a block
1195 * boundary, then switch the device to a 512-byte
1196 * block size so everything will line up on a block
1197 * boundary.
1198 */
1199 if ((embeddedOffset % blksize) != 0) {
1200 printf("HFS Mount: embedded volume offset not"
1201 " a multiple of physical block size (%d);"
1202 " switching to 512\n", blksize);
1203
1204 blkcnt *= (blksize / 512);
1205 blksize = 512;
1206 }
1207
1208 mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize);
1209 if (pread(fd, buff, blksize, mdb_offset * blksize) != blksize) {
1210 printf("failed to read the embedded vhp @ offset %d\n", mdb_offset * blksize);
1211 ret = -1;
1212 goto out;
1213 }
1214
04a16b11
A
1215 vhp = (HFSPlusVolumeHeader*) (buff + HFS_PRI_OFFSET(blksize));
1216
1217 mdbp = (HFSMasterDirectoryBlock *)(vhp);
1218 if ( (SWAP_BE16(mdbp->drSigWord) != kHFSSigWord)
1219 && (SWAP_BE16(mdbp->drSigWord) != kHFSPlusSigWord)
1220 && (SWAP_BE16(mdbp->drSigWord) != kHFSXSigWord)) {
1221 ret = -1;
1222 printf("SetJournalInFSState: Invalid Embedded Volume Signature \n");
1223 goto out;
1224 }
1225
1226
ab40a2da
A
1227 } else /* pure HFS+ */ {
1228 embeddedOffset = 0;
1229 vhp = (HFSPlusVolumeHeader*) mdbp;
1230 }
1231
1232 //printf("vol header attributes: 0x%x\n", SWAP_BE32(vhp->attributes));
1233 if ((SWAP_BE32(vhp->attributes) & kHFSVolumeJournaledMask) == 0) {
1234 ret = 0;
1235 goto out;
1236 }
1237
1238 //
1239 // Now read the journal info block... (when calculating the
1240 // position, make sure to cast to unsigned first, then to
1241 // off_t so that things don't get sign-extended improperly
1242 // or truncated).
1243 //
1244 pos = (off_t)((off_t)embeddedOffset +
1245 (off_t)((unsigned int )SWAP_BE32(vhp->journalInfoBlock))*(off_t)((unsigned int)SWAP_BE32(vhp->blockSize)));
1246
1247 if (pread(fd, buff2, blksize, pos) != blksize) {
1248 printf("failed to read the journal info block (%s).\n", strerror(errno));
1249 ret = -1;
1250 goto out;
1251 }
1252
1253 myjib = (struct JournalInfoBlock *)buff2;
1254
1255 // swap this to host native format so we can diddle with the bits
1256 myjib->flags = SWAP_BE32(myjib->flags);
1257
1258 if (journal_in_fs) {
1259 myjib->flags |= kJIJournalInFSMask;
1260 } else {
1261 myjib->flags &= ~kJIJournalInFSMask;
1262 }
1263 myjib->flags |= kJIJournalNeedInitMask;
1264
1265 // and now swap back before writing it out
1266 myjib->flags = SWAP_BE32(myjib->flags);
1267
1268 if (pwrite(fd, buff2, blksize, pos) != blksize) {
1269 printf("failed to re-write the journal info block (%s).\n", strerror(errno));
1270 ret = -1;
1271 goto out;
1272 }
1273
1274 ret = 0;
1275
1276 out:
1277 if (buff)
1278 free(buff);
1279 if (buff2)
1280 free(buff2);
1281 if (fd >= 0)
1282 close(fd);
1283
1284 return ret;
1285}