diff -Naur fs/hfsplus.bak/Makefile fs/hfsplus/Makefile --- fs/hfsplus.bak/Makefile 2006-02-16 22:25:49.000000000 -0500 +++ fs/hfsplus/Makefile 2006-02-16 22:24:44.000000000 -0500 @@ -4,6 +4,7 @@ obj-$(CONFIG_HFSPLUS_FS) += hfsplus.o -hfsplus-objs := super.o options.o inode.o ioctl.o extents.o catalog.o dir.o btree.o \ - bnode.o brec.o bfind.o tables.o unicode.o wrapper.o bitmap.o part_tbl.o +hfsplus-objs := super.o options.o inode.o ioctl.o extents.o catalog.o dir.o \ + btree.o bnode.o brec.o bfind.o tables.o unicode.o wrapper.o \ + bitmap.o part_tbl.o journal.o diff -Naur fs/hfsplus.bak/hfsplus_fs.h fs/hfsplus/hfsplus_fs.h --- fs/hfsplus.bak/hfsplus_fs.h 2006-02-16 22:25:49.000000000 -0500 +++ fs/hfsplus/hfsplus_fs.h 2006-02-16 22:24:44.000000000 -0500 @@ -121,6 +121,7 @@ int fs_shift; /* Stuff in host order from Vol Header */ + u32 journal_info_block; u32 alloc_blksz; int alloc_blksz_shift; u32 total_blocks; @@ -342,6 +343,9 @@ void *value, size_t size); ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size); +/* journal.c */ +int hfsplus_check_journal(struct super_block *); + /* options.c */ int hfsplus_parse_options(char *, struct hfsplus_sb_info *); void hfsplus_fill_defaults(struct hfsplus_sb_info *); diff -Naur fs/hfsplus.bak/hfsplus_raw.h fs/hfsplus/hfsplus_raw.h --- fs/hfsplus.bak/hfsplus_raw.h 2006-02-16 22:25:49.000000000 -0500 +++ fs/hfsplus/hfsplus_raw.h 2006-02-16 22:24:44.000000000 -0500 @@ -91,7 +91,7 @@ __be16 version; __be32 attributes; __be32 last_mount_vers; - u32 reserved; + __be32 journal_info_block; __be32 create_date; __be32 modify_date; @@ -325,4 +325,33 @@ struct hfsplus_ext_key ext; } __packed hfsplus_btree_key; +/* HFS+ Journal Info Block */ +struct hfsplus_journal_info_block { + __be32 flags; + __be32 device_signature[8]; + __be64 offset; + __be64 size; + u32 reserved[32]; +} __packed; + +#define HFSPLUS_JOURNAL_IN_FS 1 +#define HFSPLUS_JOURNAL_ON_OTHER_DEVICE 2 +#define HFSPLUS_JOURNAL_NEEDS_INIT 3 + +/* HFS+ Journal Header */ +struct hfsplus_journal_header { + __be32 magic; + __be32 endian; + __be64 start; + __be64 end; + __be64 size; + __be32 blhdr_size; + __be32 checksum; + __be32 jhdr_size; + +} __packed; + +#define HFSPLUS_JOURNAL_HEADER_MAGIC 0x4a4e4c78 +#define HFSPLUS_ENDIAN_MAGIC 0x12345678 + #endif diff -Naur fs/hfsplus.bak/journal.c fs/hfsplus/journal.c --- fs/hfsplus.bak/journal.c 1969-12-31 19:00:00.000000000 -0500 +++ fs/hfsplus/journal.c 2006-02-16 22:24:44.000000000 -0500 @@ -0,0 +1,86 @@ +/* + * HFS+ Journaling Support + * + */ + +#include +#include +#include + +#include "hfsplus_fs.h" +#include "hfsplus_raw.h" + + +/* + * Check if the journal is consistent + * Returns 0 if consistent + * Return non-zero if there are problems + * + * Assumes that we've already checked for the presence of a journal + * + * */ + +int hfsplus_check_journal(struct super_block *sb) { + struct buffer_head *bh; + struct hfsplus_journal_info_block *jib; + __be64 journal_offset; + struct hfsplus_journal_header *jh; + + /* Check the journal info block to find the block # of the journal */ + bh = sb_bread(sb, HFSPLUS_SB(sb).blockoffset + HFSPLUS_SB(sb).journal_info_block); + if (!bh) + /* Error */ + return -1; + + jib = (struct hfsplus_journal_info_block *)bh; + /* Consistant if the journal isn't created yet */ + if(be32_to_cpu(jib->flags) & HFSPLUS_JOURNAL_NEEDS_INIT) { + /* FIXME Create the journal? */ + goto success; + } + + /* Journal is on another volume, or the "on this volume" flag + * isn't set */ + if(be32_to_cpu(jib->flags) & HFSPLUS_JOURNAL_ON_OTHER_DEVICE || + !(be32_to_cpu(jib->flags) & HFSPLUS_JOURNAL_IN_FS)) { + printk("HFS+-fs: Unable to access the journal.\n"); + goto fail; + } + + journal_offset = be64_to_cpu(jib->offset); + /* Size? */ + + brelse(bh); + + /* Find the journal using the Journal Info Block Data */ + bh = sb_bread(sb, HFSPLUS_SB(sb).blockoffset + journal_offset); + if(!bh) + return -1; + jh = (struct hfsplus_journal_header *)bh; + + /* Verify the journal header */ + if(be32_to_cpu(jh->magic) != HFSPLUS_JOURNAL_HEADER_MAGIC || + be32_to_cpu(jh->endian) != HFSPLUS_ENDIAN_MAGIC){ + printk("HFS+-fs: Journal header verification failed.\n"); + goto fail; + } + + /* Compare start to end */ + if(be64_to_cpu(jh->start) == be64_to_cpu(jh->end)) { + /* If they're the same, we can mount, it's clean */ + goto success; + } + else { + /* If they're different, we need to playback the journal */ + /* Or just tell the user to run fsck */ + printk("HFS+-fs: Journal and fs are inconsistant, please run fsck.hfsplus\n"); + goto fail; + } +fail: + brelse(bh); + return -1; +success: + brelse(bh); + return 0; + +} diff -Naur fs/hfsplus.bak/super.c fs/hfsplus/super.c --- fs/hfsplus.bak/super.c 2006-02-16 22:25:49.000000000 -0500 +++ fs/hfsplus/super.c 2006-02-16 22:24:44.000000000 -0500 @@ -270,9 +270,11 @@ sb->s_flags |= MS_RDONLY; *flags |= MS_RDONLY; } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { - printk("HFS+-fs: Filesystem is marked journaled, leaving read-only.\n"); - sb->s_flags |= MS_RDONLY; - *flags |= MS_RDONLY; + if(hfsplus_check_journal(sb)) { + printk("HFS+-fs: Filesystem is marked journaled, leaving read-only.\n"); + sb->s_flags |= MS_RDONLY; + *flags |= MS_RDONLY; + } } } return 0; @@ -342,6 +344,8 @@ printk("HFS+-fs: wrong filesystem version\n"); goto cleanup; } + HFSPLUS_SB(sb).journal_info_block = + be32_to_cpu(vhdr->journal_info_block); HFSPLUS_SB(sb).total_blocks = be32_to_cpu(vhdr->total_blocks); HFSPLUS_SB(sb).free_blocks = be32_to_cpu(vhdr->free_blocks); HFSPLUS_SB(sb).next_alloc = be32_to_cpu(vhdr->next_alloc); @@ -371,10 +375,11 @@ printk("HFS+-fs: Filesystem is marked locked, mounting read-only.\n"); sb->s_flags |= MS_RDONLY; } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { - if (!silent) - printk("HFS+-fs: write access to a jounaled filesystem is not supported, " - "use the force option at your own risk, mounting read-only.\n"); - sb->s_flags |= MS_RDONLY; + if(hfsplus_check_journal(sb)) { + if (!silent) + printk("HFS+-fs: mounting read-only.\n"); + sb->s_flags |= MS_RDONLY; + } } sbi->flags &= ~HFSPLUS_SB_FORCE;