Blame view

fs/hfsplus/super.c 15 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
  /*
   *  linux/fs/hfsplus/super.c
   *
   * Copyright (C) 2001
   * Brad Boyer (flar@allandria.com)
   * (C) 2003 Ardis Technologies <roman@ardistech.com>
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/pagemap.h>
  #include <linux/fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
20
  #include <linux/vfs.h>
  #include <linux/nls.h>
  
  static struct inode *hfsplus_alloc_inode(struct super_block *sb);
  static void hfsplus_destroy_inode(struct inode *inode);
  
  #include "hfsplus_fs.h"
635253915   David Howells   iget: stop HFSPLU...
21
  struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
  {
  	struct hfs_find_data fd;
  	struct hfsplus_vh *vhdr;
635253915   David Howells   iget: stop HFSPLU...
25
26
27
28
29
30
31
32
  	struct inode *inode;
  	long err = -EIO;
  
  	inode = iget_locked(sb, ino);
  	if (!inode)
  		return ERR_PTR(-ENOMEM);
  	if (!(inode->i_state & I_NEW))
  		return inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  	INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
895c23f8c   Matthias Kaehlcke   hfsplus: convert ...
35
  	mutex_init(&HFSPLUS_I(inode).extents_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
  	HFSPLUS_I(inode).flags = 0;
  	HFSPLUS_I(inode).rsrc_inode = NULL;
94c1d3184   Peter Wainwright   [PATCH] Fix HFS+ ...
38
  	atomic_set(&HFSPLUS_I(inode).opencnt, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
42
43
44
45
46
47
48
  
  	if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID) {
  	read_inode:
  		hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd);
  		err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
  		if (!err)
  			err = hfsplus_cat_read_inode(inode, &fd);
  		hfs_find_exit(&fd);
  		if (err)
  			goto bad_inode;
635253915   David Howells   iget: stop HFSPLU...
49
  		goto done;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  	}
  	vhdr = HFSPLUS_SB(inode->i_sb).s_vhdr;
  	switch(inode->i_ino) {
  	case HFSPLUS_ROOT_CNID:
  		goto read_inode;
  	case HFSPLUS_EXT_CNID:
  		hfsplus_inode_read_fork(inode, &vhdr->ext_file);
  		inode->i_mapping->a_ops = &hfsplus_btree_aops;
  		break;
  	case HFSPLUS_CAT_CNID:
  		hfsplus_inode_read_fork(inode, &vhdr->cat_file);
  		inode->i_mapping->a_ops = &hfsplus_btree_aops;
  		break;
  	case HFSPLUS_ALLOC_CNID:
  		hfsplus_inode_read_fork(inode, &vhdr->alloc_file);
  		inode->i_mapping->a_ops = &hfsplus_aops;
  		break;
  	case HFSPLUS_START_CNID:
  		hfsplus_inode_read_fork(inode, &vhdr->start_file);
  		break;
  	case HFSPLUS_ATTR_CNID:
  		hfsplus_inode_read_fork(inode, &vhdr->attr_file);
  		inode->i_mapping->a_ops = &hfsplus_btree_aops;
  		break;
  	default:
  		goto bad_inode;
  	}
635253915   David Howells   iget: stop HFSPLU...
77
78
79
  done:
  	unlock_new_inode(inode);
  	return inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80

635253915   David Howells   iget: stop HFSPLU...
81
82
83
  bad_inode:
  	iget_failed(inode);
  	return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  }
  
  static int hfsplus_write_inode(struct inode *inode, int unused)
  {
  	struct hfsplus_vh *vhdr;
  	int ret = 0;
  
  	dprint(DBG_INODE, "hfsplus_write_inode: %lu
  ", inode->i_ino);
  	hfsplus_ext_write_extent(inode);
  	if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID) {
  		return hfsplus_cat_write_inode(inode);
  	}
  	vhdr = HFSPLUS_SB(inode->i_sb).s_vhdr;
  	switch (inode->i_ino) {
  	case HFSPLUS_ROOT_CNID:
  		ret = hfsplus_cat_write_inode(inode);
  		break;
  	case HFSPLUS_EXT_CNID:
  		if (vhdr->ext_file.total_size != cpu_to_be64(inode->i_size)) {
  			HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
  			inode->i_sb->s_dirt = 1;
  		}
  		hfsplus_inode_write_fork(inode, &vhdr->ext_file);
  		hfs_btree_write(HFSPLUS_SB(inode->i_sb).ext_tree);
  		break;
  	case HFSPLUS_CAT_CNID:
  		if (vhdr->cat_file.total_size != cpu_to_be64(inode->i_size)) {
  			HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
  			inode->i_sb->s_dirt = 1;
  		}
  		hfsplus_inode_write_fork(inode, &vhdr->cat_file);
  		hfs_btree_write(HFSPLUS_SB(inode->i_sb).cat_tree);
  		break;
  	case HFSPLUS_ALLOC_CNID:
  		if (vhdr->alloc_file.total_size != cpu_to_be64(inode->i_size)) {
  			HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
  			inode->i_sb->s_dirt = 1;
  		}
  		hfsplus_inode_write_fork(inode, &vhdr->alloc_file);
  		break;
  	case HFSPLUS_START_CNID:
  		if (vhdr->start_file.total_size != cpu_to_be64(inode->i_size)) {
  			HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
  			inode->i_sb->s_dirt = 1;
  		}
  		hfsplus_inode_write_fork(inode, &vhdr->start_file);
  		break;
  	case HFSPLUS_ATTR_CNID:
  		if (vhdr->attr_file.total_size != cpu_to_be64(inode->i_size)) {
  			HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
  			inode->i_sb->s_dirt = 1;
  		}
  		hfsplus_inode_write_fork(inode, &vhdr->attr_file);
  		hfs_btree_write(HFSPLUS_SB(inode->i_sb).attr_tree);
  		break;
  	}
  	return ret;
  }
  
  static void hfsplus_clear_inode(struct inode *inode)
  {
  	dprint(DBG_INODE, "hfsplus_clear_inode: %lu
  ", inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
151
  	if (HFSPLUS_IS_RSRC(inode)) {
  		HFSPLUS_I(HFSPLUS_I(inode).rsrc_inode).rsrc_inode = NULL;
  		iput(HFSPLUS_I(inode).rsrc_inode);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  }
  
  static void hfsplus_write_super(struct super_block *sb)
  {
  	struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr;
  
  	dprint(DBG_SUPER, "hfsplus_write_super
  ");
  	sb->s_dirt = 0;
  	if (sb->s_flags & MS_RDONLY)
  		/* warn? */
  		return;
  
  	vhdr->free_blocks = cpu_to_be32(HFSPLUS_SB(sb).free_blocks);
  	vhdr->next_alloc = cpu_to_be32(HFSPLUS_SB(sb).next_alloc);
  	vhdr->next_cnid = cpu_to_be32(HFSPLUS_SB(sb).next_cnid);
  	vhdr->folder_count = cpu_to_be32(HFSPLUS_SB(sb).folder_count);
  	vhdr->file_count = cpu_to_be32(HFSPLUS_SB(sb).file_count);
  
  	mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh);
  	if (HFSPLUS_SB(sb).flags & HFSPLUS_SB_WRITEBACKUP) {
  		if (HFSPLUS_SB(sb).sect_count) {
  			struct buffer_head *bh;
  			u32 block, offset;
  
  			block = HFSPLUS_SB(sb).blockoffset;
  			block += (HFSPLUS_SB(sb).sect_count - 2) >> (sb->s_blocksize_bits - 9);
  			offset = ((HFSPLUS_SB(sb).sect_count - 2) << 9) & (sb->s_blocksize - 1);
634725a92   Roman Zippel   [PATCH] hfs: clea...
180
181
  			printk(KERN_DEBUG "hfs: backup: %u,%u,%u,%u
  ", HFSPLUS_SB(sb).blockoffset,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
184
185
186
187
188
189
190
  				HFSPLUS_SB(sb).sect_count, block, offset);
  			bh = sb_bread(sb, block);
  			if (bh) {
  				vhdr = (struct hfsplus_vh *)(bh->b_data + offset);
  				if (be16_to_cpu(vhdr->signature) == HFSPLUS_VOLHEAD_SIG) {
  					memcpy(vhdr, HFSPLUS_SB(sb).s_vhdr, sizeof(*vhdr));
  					mark_buffer_dirty(bh);
  					brelse(bh);
  				} else
634725a92   Roman Zippel   [PATCH] hfs: clea...
191
192
  					printk(KERN_WARNING "hfs: backup not found!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
195
196
197
198
199
200
201
202
  			}
  		}
  		HFSPLUS_SB(sb).flags &= ~HFSPLUS_SB_WRITEBACKUP;
  	}
  }
  
  static void hfsplus_put_super(struct super_block *sb)
  {
  	dprint(DBG_SUPER, "hfsplus_put_super
  ");
945b09201   Colin Leroy   [PATCH] hfs, hfsp...
203
204
205
  	if (!sb->s_fs_info)
  		return;
  	if (!(sb->s_flags & MS_RDONLY) && HFSPLUS_SB(sb).s_vhdr) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
207
208
209
210
211
  		struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr;
  
  		vhdr->modify_date = hfsp_now2mt();
  		vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_UNMNT);
  		vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_INCNSTNT);
  		mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh);
e39f07c83   Jan Kara   [PATCH] Change HF...
212
  		sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
215
216
217
218
219
220
221
  	}
  
  	hfs_btree_close(HFSPLUS_SB(sb).cat_tree);
  	hfs_btree_close(HFSPLUS_SB(sb).ext_tree);
  	iput(HFSPLUS_SB(sb).alloc_file);
  	iput(HFSPLUS_SB(sb).hidden_dir);
  	brelse(HFSPLUS_SB(sb).s_vhbh);
  	if (HFSPLUS_SB(sb).nls)
  		unload_nls(HFSPLUS_SB(sb).nls);
945b09201   Colin Leroy   [PATCH] hfs, hfsp...
222
223
  	kfree(sb->s_fs_info);
  	sb->s_fs_info = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
  }
726c33422   David Howells   [PATCH] VFS: Perm...
225
  static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
  {
726c33422   David Howells   [PATCH] VFS: Perm...
227
  	struct super_block *sb = dentry->d_sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
  	buf->f_type = HFSPLUS_SUPER_MAGIC;
  	buf->f_bsize = sb->s_blocksize;
  	buf->f_blocks = HFSPLUS_SB(sb).total_blocks << HFSPLUS_SB(sb).fs_shift;
  	buf->f_bfree = HFSPLUS_SB(sb).free_blocks << HFSPLUS_SB(sb).fs_shift;
  	buf->f_bavail = buf->f_bfree;
  	buf->f_files = 0xFFFFFFFF;
  	buf->f_ffree = 0xFFFFFFFF - HFSPLUS_SB(sb).next_cnid;
  	buf->f_namelen = HFSPLUS_MAX_STRLEN;
  
  	return 0;
  }
  
  static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
  {
  	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
  		return 0;
  	if (!(*flags & MS_RDONLY)) {
  		struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr;
b0b623c3b   Roman Zippel   [PATCH] hfsplus: ...
246
247
248
249
250
251
  		struct hfsplus_sb_info sbi;
  
  		memset(&sbi, 0, sizeof(struct hfsplus_sb_info));
  		sbi.nls = HFSPLUS_SB(sb).nls;
  		if (!hfsplus_parse_options(data, &sbi))
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
  
  		if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
634725a92   Roman Zippel   [PATCH] hfs: clea...
254
  			printk(KERN_WARNING "hfs: filesystem was not cleanly unmounted, "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
257
258
  			       "running fsck.hfsplus is recommended.  leaving read-only.
  ");
  			sb->s_flags |= MS_RDONLY;
  			*flags |= MS_RDONLY;
b0b623c3b   Roman Zippel   [PATCH] hfsplus: ...
259
260
  		} else if (sbi.flags & HFSPLUS_SB_FORCE) {
  			/* nothing */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
  		} else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
634725a92   Roman Zippel   [PATCH] hfs: clea...
262
263
  			printk(KERN_WARNING "hfs: filesystem is marked locked, leaving read-only.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
  			sb->s_flags |= MS_RDONLY;
  			*flags |= MS_RDONLY;
b0b623c3b   Roman Zippel   [PATCH] hfsplus: ...
266
  		} else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) {
634725a92   Roman Zippel   [PATCH] hfs: clea...
267
268
  			printk(KERN_WARNING "hfs: filesystem is marked journaled, leaving read-only.
  ");
b0b623c3b   Roman Zippel   [PATCH] hfsplus: ...
269
270
  			sb->s_flags |= MS_RDONLY;
  			*flags |= MS_RDONLY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
  		}
  	}
  	return 0;
  }
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
275
  static const struct super_operations hfsplus_sops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
  	.alloc_inode	= hfsplus_alloc_inode,
  	.destroy_inode	= hfsplus_destroy_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
280
281
282
283
  	.write_inode	= hfsplus_write_inode,
  	.clear_inode	= hfsplus_clear_inode,
  	.put_super	= hfsplus_put_super,
  	.write_super	= hfsplus_write_super,
  	.statfs		= hfsplus_statfs,
  	.remount_fs	= hfsplus_remount,
717dd80e9   Roman Zippel   [PATCH] hfs: show...
284
  	.show_options	= hfsplus_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
287
288
289
290
291
292
  };
  
  static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
  {
  	struct hfsplus_vh *vhdr;
  	struct hfsplus_sb_info *sbi;
  	hfsplus_cat_entry entry;
  	struct hfs_find_data fd;
635253915   David Howells   iget: stop HFSPLU...
293
  	struct inode *root, *inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
296
  	struct qstr str;
  	struct nls_table *nls = NULL;
  	int err = -EINVAL;
a5001a278   Wyatt Banks   HFSPlus: change k...
297
  	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
  	if (!sbi)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
  	sb->s_fs_info = sbi;
  	INIT_HLIST_HEAD(&sbi->rsrc_inodes);
717dd80e9   Roman Zippel   [PATCH] hfs: show...
302
303
  	hfsplus_fill_defaults(sbi);
  	if (!hfsplus_parse_options(data, sbi)) {
634725a92   Roman Zippel   [PATCH] hfs: clea...
304
305
  		printk(KERN_ERR "hfs: unable to parse mount options
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
309
310
311
312
  		err = -EINVAL;
  		goto cleanup;
  	}
  
  	/* temporarily use utf8 to correctly find the hidden dir below */
  	nls = sbi->nls;
  	sbi->nls = load_nls("utf8");
bd6a59b22   Joshua Kwan   [PATCH] hfsplus o...
313
  	if (!sbi->nls) {
634725a92   Roman Zippel   [PATCH] hfs: clea...
314
315
  		printk(KERN_ERR "hfs: unable to load nls for utf8
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
319
320
321
322
  		err = -EINVAL;
  		goto cleanup;
  	}
  
  	/* Grab the volume header */
  	if (hfsplus_read_wrapper(sb)) {
  		if (!silent)
634725a92   Roman Zippel   [PATCH] hfs: clea...
323
324
  			printk(KERN_WARNING "hfs: unable to find HFS+ superblock
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
326
327
328
329
330
  		err = -EINVAL;
  		goto cleanup;
  	}
  	vhdr = HFSPLUS_SB(sb).s_vhdr;
  
  	/* Copy parts of the volume header into the superblock */
2179d372d   David Elliott   [PATCH] hfs: add ...
331
332
333
  	sb->s_magic = HFSPLUS_VOLHEAD_SIG;
  	if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION ||
  	    be16_to_cpu(vhdr->version) > HFSPLUS_CURRENT_VERSION) {
634725a92   Roman Zippel   [PATCH] hfs: clea...
334
335
  		printk(KERN_ERR "hfs: wrong filesystem version
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  		goto cleanup;
  	}
  	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);
  	HFSPLUS_SB(sb).next_cnid = be32_to_cpu(vhdr->next_cnid);
  	HFSPLUS_SB(sb).file_count = be32_to_cpu(vhdr->file_count);
  	HFSPLUS_SB(sb).folder_count = be32_to_cpu(vhdr->folder_count);
  	HFSPLUS_SB(sb).data_clump_blocks = be32_to_cpu(vhdr->data_clump_sz) >> HFSPLUS_SB(sb).alloc_blksz_shift;
  	if (!HFSPLUS_SB(sb).data_clump_blocks)
  		HFSPLUS_SB(sb).data_clump_blocks = 1;
  	HFSPLUS_SB(sb).rsrc_clump_blocks = be32_to_cpu(vhdr->rsrc_clump_sz) >> HFSPLUS_SB(sb).alloc_blksz_shift;
  	if (!HFSPLUS_SB(sb).rsrc_clump_blocks)
  		HFSPLUS_SB(sb).rsrc_clump_blocks = 1;
  
  	/* Set up operations so we can load metadata */
  	sb->s_op = &hfsplus_sops;
  	sb->s_maxbytes = MAX_LFS_FILESIZE;
  
  	if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
634725a92   Roman Zippel   [PATCH] hfs: clea...
356
357
358
  		printk(KERN_WARNING "hfs: Filesystem was not cleanly unmounted, "
  		       "running fsck.hfsplus is recommended.  mounting read-only.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
  		sb->s_flags |= MS_RDONLY;
b0b623c3b   Roman Zippel   [PATCH] hfsplus: ...
360
361
  	} else if (sbi->flags & HFSPLUS_SB_FORCE) {
  		/* nothing */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
  	} else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
634725a92   Roman Zippel   [PATCH] hfs: clea...
363
364
  		printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
  		sb->s_flags |= MS_RDONLY;
b0b623c3b   Roman Zippel   [PATCH] hfsplus: ...
366
  	} else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) {
355a46961   Dave Jones   trivial: fix user...
367
  		printk(KERN_WARNING "hfs: write access to a journaled filesystem is not supported, "
634725a92   Roman Zippel   [PATCH] hfs: clea...
368
369
  		       "use the force option at your own risk, mounting read-only.
  ");
b0b623c3b   Roman Zippel   [PATCH] hfsplus: ...
370
  		sb->s_flags |= MS_RDONLY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  	}
b0b623c3b   Roman Zippel   [PATCH] hfsplus: ...
372
  	sbi->flags &= ~HFSPLUS_SB_FORCE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
376
  
  	/* Load metadata objects (B*Trees) */
  	HFSPLUS_SB(sb).ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID);
  	if (!HFSPLUS_SB(sb).ext_tree) {
634725a92   Roman Zippel   [PATCH] hfs: clea...
377
378
  		printk(KERN_ERR "hfs: failed to load extents file
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
381
382
  		goto cleanup;
  	}
  	HFSPLUS_SB(sb).cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID);
  	if (!HFSPLUS_SB(sb).cat_tree) {
634725a92   Roman Zippel   [PATCH] hfs: clea...
383
384
  		printk(KERN_ERR "hfs: failed to load catalog file
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
  		goto cleanup;
  	}
635253915   David Howells   iget: stop HFSPLU...
387
388
  	inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID);
  	if (IS_ERR(inode)) {
634725a92   Roman Zippel   [PATCH] hfs: clea...
389
390
  		printk(KERN_ERR "hfs: failed to load allocation file
  ");
635253915   David Howells   iget: stop HFSPLU...
391
  		err = PTR_ERR(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
  		goto cleanup;
  	}
635253915   David Howells   iget: stop HFSPLU...
394
  	HFSPLUS_SB(sb).alloc_file = inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
  
  	/* Load the root directory */
635253915   David Howells   iget: stop HFSPLU...
397
398
399
400
401
402
403
  	root = hfsplus_iget(sb, HFSPLUS_ROOT_CNID);
  	if (IS_ERR(root)) {
  		printk(KERN_ERR "hfs: failed to load root directory
  ");
  		err = PTR_ERR(root);
  		goto cleanup;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
  	sb->s_root = d_alloc_root(root);
  	if (!sb->s_root) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
  		iput(root);
635253915   David Howells   iget: stop HFSPLU...
407
  		err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
  		goto cleanup;
  	}
d45bce8fa   Duane Griffin   HFS+: add custom ...
410
  	sb->s_root->d_op = &hfsplus_dentry_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
414
415
416
417
418
419
  
  	str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
  	str.name = HFSP_HIDDENDIR_NAME;
  	hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
  	hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str);
  	if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
  		hfs_find_exit(&fd);
  		if (entry.type != cpu_to_be16(HFSPLUS_FOLDER))
  			goto cleanup;
635253915   David Howells   iget: stop HFSPLU...
420
421
422
  		inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id));
  		if (IS_ERR(inode)) {
  			err = PTR_ERR(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  			goto cleanup;
635253915   David Howells   iget: stop HFSPLU...
424
425
  		}
  		HFSPLUS_SB(sb).hidden_dir = inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
427
428
429
430
431
432
433
434
435
436
  	} else
  		hfs_find_exit(&fd);
  
  	if (sb->s_flags & MS_RDONLY)
  		goto out;
  
  	/* H+LX == hfsplusutils, H+Lx == this driver, H+lx is unused
  	 * all three are registered with Apple for our use
  	 */
  	vhdr->last_mount_vers = cpu_to_be32(HFSP_MOUNT_VERSION);
  	vhdr->modify_date = hfsp_now2mt();
20c79e785   Marcin Slusarz   hfs/hfsplus: be*_...
437
  	be32_add_cpu(&vhdr->write_count, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
440
  	vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT);
  	vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT);
  	mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh);
e39f07c83   Jan Kara   [PATCH] Change HF...
441
  	sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
  
  	if (!HFSPLUS_SB(sb).hidden_dir) {
634725a92   Roman Zippel   [PATCH] hfs: clea...
444
445
  		printk(KERN_DEBUG "hfs: create hidden dir...
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
  		HFSPLUS_SB(sb).hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
  		hfsplus_create_cat(HFSPLUS_SB(sb).hidden_dir->i_ino, sb->s_root->d_inode,
  				   &str, HFSPLUS_SB(sb).hidden_dir);
  		mark_inode_dirty(HFSPLUS_SB(sb).hidden_dir);
  	}
  out:
  	unload_nls(sbi->nls);
  	sbi->nls = nls;
  	return 0;
  
  cleanup:
  	hfsplus_put_super(sb);
  	if (nls)
  		unload_nls(nls);
  	return err;
  }
  
  MODULE_AUTHOR("Brad Boyer");
  MODULE_DESCRIPTION("Extended Macintosh Filesystem");
  MODULE_LICENSE("GPL");
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
466
  static struct kmem_cache *hfsplus_inode_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
469
470
  
  static struct inode *hfsplus_alloc_inode(struct super_block *sb)
  {
  	struct hfsplus_inode_info *i;
e94b17660   Christoph Lameter   [PATCH] slab: rem...
471
  	i = kmem_cache_alloc(hfsplus_inode_cachep, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
474
475
476
477
478
479
480
  	return i ? &i->vfs_inode : NULL;
  }
  
  static void hfsplus_destroy_inode(struct inode *inode)
  {
  	kmem_cache_free(hfsplus_inode_cachep, &HFSPLUS_I(inode));
  }
  
  #define HFSPLUS_INODE_SIZE	sizeof(struct hfsplus_inode_info)
454e2398b   David Howells   [PATCH] VFS: Perm...
481
482
483
  static int hfsplus_get_sb(struct file_system_type *fs_type,
  			  int flags, const char *dev_name, void *data,
  			  struct vfsmount *mnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
  {
454e2398b   David Howells   [PATCH] VFS: Perm...
485
486
  	return get_sb_bdev(fs_type, flags, dev_name, data, hfsplus_fill_super,
  			   mnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
489
490
491
492
493
494
495
  }
  
  static struct file_system_type hfsplus_fs_type = {
  	.owner		= THIS_MODULE,
  	.name		= "hfsplus",
  	.get_sb		= hfsplus_get_sb,
  	.kill_sb	= kill_block_super,
  	.fs_flags	= FS_REQUIRES_DEV,
  };
51cc50685   Alexey Dobriyan   SL*B: drop kmem c...
496
  static void hfsplus_init_once(void *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
  {
  	struct hfsplus_inode_info *i = p;
a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
499
  	inode_init_once(&i->vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
501
502
503
504
505
506
507
  }
  
  static int __init init_hfsplus_fs(void)
  {
  	int err;
  
  	hfsplus_inode_cachep = kmem_cache_create("hfsplus_icache",
  		HFSPLUS_INODE_SIZE, 0, SLAB_HWCACHE_ALIGN,
20c2df83d   Paul Mundt   mm: Remove slab d...
508
  		hfsplus_init_once);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
511
512
513
514
515
516
517
518
519
  	if (!hfsplus_inode_cachep)
  		return -ENOMEM;
  	err = register_filesystem(&hfsplus_fs_type);
  	if (err)
  		kmem_cache_destroy(hfsplus_inode_cachep);
  	return err;
  }
  
  static void __exit exit_hfsplus_fs(void)
  {
  	unregister_filesystem(&hfsplus_fs_type);
1a1d92c10   Alexey Dobriyan   [PATCH] Really ig...
520
  	kmem_cache_destroy(hfsplus_inode_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
522
523
524
  }
  
  module_init(init_hfsplus_fs)
  module_exit(exit_hfsplus_fs)