Blame view

fs/hfsplus/inode.c 16.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
  /*
   *  linux/fs/hfsplus/inode.c
   *
   * Copyright (C) 2001
   * Brad Boyer (flar@allandria.com)
   * (C) 2003 Ardis Technologies <roman@ardistech.com>
   *
   * Inode handling routines
   */
34a2d313c   Christoph Hellwig   hfsplus: flush di...
10
  #include <linux/blkdev.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
  #include <linux/mm.h>
  #include <linux/fs.h>
  #include <linux/pagemap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
  #include <linux/mpage.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
15
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
19
20
21
  
  #include "hfsplus_fs.h"
  #include "hfsplus_raw.h"
  
  static int hfsplus_readpage(struct file *file, struct page *page)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
  	return block_read_full_page(page, hfsplus_get_block);
  }
  
  static int hfsplus_writepage(struct page *page, struct writeback_control *wbc)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
  	return block_write_full_page(page, hfsplus_get_block, wbc);
  }
7c0efc627   Nick Piggin   hfsplus: convert ...
29
30
31
  static int hfsplus_write_begin(struct file *file, struct address_space *mapping,
  			loff_t pos, unsigned len, unsigned flags,
  			struct page **pagep, void **fsdata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  {
282dc1788   Christoph Hellwig   get rid of cont_w...
33
  	int ret;
7c0efc627   Nick Piggin   hfsplus: convert ...
34
  	*pagep = NULL;
282dc1788   Christoph Hellwig   get rid of cont_w...
35
  	ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
7c0efc627   Nick Piggin   hfsplus: convert ...
36
  				hfsplus_get_block,
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
37
  				&HFSPLUS_I(mapping->host)->phys_size);
282dc1788   Christoph Hellwig   get rid of cont_w...
38
39
40
41
42
43
44
  	if (unlikely(ret)) {
  		loff_t isize = mapping->host->i_size;
  		if (pos + len > isize)
  			vmtruncate(mapping->host, isize);
  	}
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
49
50
  }
  
  static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block)
  {
  	return generic_block_bmap(mapping, block, hfsplus_get_block);
  }
27496a8c6   Al Viro   [PATCH] gfp_t: fs/*
51
  static int hfsplus_releasepage(struct page *page, gfp_t mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
56
57
58
59
60
61
  {
  	struct inode *inode = page->mapping->host;
  	struct super_block *sb = inode->i_sb;
  	struct hfs_btree *tree;
  	struct hfs_bnode *node;
  	u32 nidx;
  	int i, res = 1;
  
  	switch (inode->i_ino) {
  	case HFSPLUS_EXT_CNID:
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
62
  		tree = HFSPLUS_SB(sb)->ext_tree;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
  		break;
  	case HFSPLUS_CAT_CNID:
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
65
  		tree = HFSPLUS_SB(sb)->cat_tree;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
  		break;
  	case HFSPLUS_ATTR_CNID:
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
68
  		tree = HFSPLUS_SB(sb)->attr_tree;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
73
  		break;
  	default:
  		BUG();
  		return 0;
  	}
706322496   Eric Sesterhenn   Fix hfsplus oops ...
74
75
  	if (!tree)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
  	if (tree->node_size >= PAGE_CACHE_SIZE) {
2753cc281   Anton Salikhmetov   hfsplus: over 80 ...
77
78
  		nidx = page->index >>
  			(tree->node_size_shift - PAGE_CACHE_SHIFT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
82
83
84
85
86
87
88
89
90
  		spin_lock(&tree->hash_lock);
  		node = hfs_bnode_findhash(tree, nidx);
  		if (!node)
  			;
  		else if (atomic_read(&node->refcnt))
  			res = 0;
  		if (res && node) {
  			hfs_bnode_unhash(node);
  			hfs_bnode_free(node);
  		}
  		spin_unlock(&tree->hash_lock);
  	} else {
2753cc281   Anton Salikhmetov   hfsplus: over 80 ...
91
92
  		nidx = page->index <<
  			(PAGE_CACHE_SHIFT - tree->node_size_shift);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  		i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift);
  		spin_lock(&tree->hash_lock);
  		do {
  			node = hfs_bnode_findhash(tree, nidx++);
  			if (!node)
  				continue;
  			if (atomic_read(&node->refcnt)) {
  				res = 0;
  				break;
  			}
  			hfs_bnode_unhash(node);
  			hfs_bnode_free(node);
  		} while (--i && nidx < tree->node_count);
  		spin_unlock(&tree->hash_lock);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
  	return res ? try_to_free_buffers(page) : 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
  static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb,
  		const struct iovec *iov, loff_t offset, unsigned long nr_segs)
  {
  	struct file *file = iocb->ki_filp;
f44ea0310   Josef Sipek   [PATCH] struct pa...
114
  	struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
eafdc7d19   Christoph Hellwig   sort out blockdev...
115
  	ssize_t ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116

aacfc19c6   Christoph Hellwig   fs: simplify the ...
117
118
  	ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
  				 hfsplus_get_block);
eafdc7d19   Christoph Hellwig   sort out blockdev...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  
  	/*
  	 * In case of error extending write may have instantiated a few
  	 * blocks outside i_size. Trim these off again.
  	 */
  	if (unlikely((rw & WRITE) && ret < 0)) {
  		loff_t isize = i_size_read(inode);
  		loff_t end = offset + iov_length(iov, nr_segs);
  
  		if (end > isize)
  			vmtruncate(inode, isize);
  	}
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
135
136
137
138
139
  }
  
  static int hfsplus_writepages(struct address_space *mapping,
  			      struct writeback_control *wbc)
  {
  	return mpage_writepages(mapping, wbc, hfsplus_get_block);
  }
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
140
  const struct address_space_operations hfsplus_btree_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
  	.readpage	= hfsplus_readpage,
  	.writepage	= hfsplus_writepage,
7c0efc627   Nick Piggin   hfsplus: convert ...
143
144
  	.write_begin	= hfsplus_write_begin,
  	.write_end	= generic_write_end,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
  	.bmap		= hfsplus_bmap,
  	.releasepage	= hfsplus_releasepage,
  };
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
148
  const struct address_space_operations hfsplus_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
  	.readpage	= hfsplus_readpage,
  	.writepage	= hfsplus_writepage,
7c0efc627   Nick Piggin   hfsplus: convert ...
151
152
  	.write_begin	= hfsplus_write_begin,
  	.write_end	= generic_write_end,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
  	.bmap		= hfsplus_bmap,
  	.direct_IO	= hfsplus_direct_IO,
  	.writepages	= hfsplus_writepages,
  };
e16404ed0   Al Viro   constify dentry_o...
157
  const struct dentry_operations hfsplus_dentry_operations = {
d45bce8fa   Duane Griffin   HFS+: add custom ...
158
159
160
  	.d_hash       = hfsplus_hash_dentry,
  	.d_compare    = hfsplus_compare_dentry,
  };
2753cc281   Anton Salikhmetov   hfsplus: over 80 ...
161
162
  static struct dentry *hfsplus_file_lookup(struct inode *dir,
  		struct dentry *dentry, struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
166
  {
  	struct hfs_find_data fd;
  	struct super_block *sb = dir->i_sb;
  	struct inode *inode = NULL;
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
167
  	struct hfsplus_inode_info *hip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
170
171
  	int err;
  
  	if (HFSPLUS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc"))
  		goto out;
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
172
  	inode = HFSPLUS_I(dir)->rsrc_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
176
177
178
  	if (inode)
  		goto out;
  
  	inode = new_inode(sb);
  	if (!inode)
  		return ERR_PTR(-ENOMEM);
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
179
  	hip = HFSPLUS_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
  	inode->i_ino = dir->i_ino;
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
181
182
  	INIT_LIST_HEAD(&hip->open_dir_list);
  	mutex_init(&hip->extents_lock);
b33b7921d   Christoph Hellwig   hfsplus: split up...
183
184
185
  	hip->extent_state = 0;
  	hip->flags = 0;
  	set_bit(HFSPLUS_I_RSRC, &hip->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186

5bd9d99d1   Alexey Khoroshilov   hfsplus: add erro...
187
188
189
190
191
192
193
  	err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
  	if (!err) {
  		err = hfsplus_find_cat(sb, dir->i_ino, &fd);
  		if (!err)
  			err = hfsplus_cat_read_inode(inode, &fd);
  		hfs_find_exit(&fd);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
197
  	if (err) {
  		iput(inode);
  		return ERR_PTR(err);
  	}
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
198
199
  	hip->rsrc_inode = dir;
  	HFSPLUS_I(dir)->rsrc_inode = inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
  	igrab(dir);
58a818f53   Christoph Hellwig   hfsplus: remove t...
201
202
203
204
205
206
207
  
  	/*
  	 * __mark_inode_dirty expects inodes to be hashed.  Since we don't
  	 * want resource fork inodes in the regular inode space, we make them
  	 * appear hashed, but do not put on any lists.  hlist_del()
  	 * will work fine and require no locking.
  	 */
756acc2d6   Al Viro   list.h: new helpe...
208
  	hlist_add_fake(&inode->i_hash);
58a818f53   Christoph Hellwig   hfsplus: remove t...
209

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  	mark_inode_dirty(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
214
  out:
  	d_add(dentry, inode);
  	return NULL;
  }
2753cc281   Anton Salikhmetov   hfsplus: over 80 ...
215
216
  static void hfsplus_get_perms(struct inode *inode,
  		struct hfsplus_perm *perms, int dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  {
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
218
  	struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
221
222
223
224
  	u16 mode;
  
  	mode = be16_to_cpu(perms->mode);
  
  	inode->i_uid = be32_to_cpu(perms->owner);
  	if (!inode->i_uid && !mode)
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
225
  		inode->i_uid = sbi->uid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
  
  	inode->i_gid = be32_to_cpu(perms->group);
  	if (!inode->i_gid && !mode)
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
229
  		inode->i_gid = sbi->gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
  
  	if (dir) {
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
232
  		mode = mode ? (mode & S_IALLUGO) : (S_IRWXUGO & ~(sbi->umask));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
234
  		mode |= S_IFDIR;
  	} else if (!mode)
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
235
  		mode = S_IFREG | ((S_IRUGO|S_IWUGO) & ~(sbi->umask));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
  	inode->i_mode = mode;
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
237
  	HFSPLUS_I(inode)->userflags = perms->userflags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
240
241
242
243
244
245
246
  	if (perms->rootflags & HFSPLUS_FLG_IMMUTABLE)
  		inode->i_flags |= S_IMMUTABLE;
  	else
  		inode->i_flags &= ~S_IMMUTABLE;
  	if (perms->rootflags & HFSPLUS_FLG_APPEND)
  		inode->i_flags |= S_APPEND;
  	else
  		inode->i_flags &= ~S_APPEND;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
249
  static int hfsplus_file_open(struct inode *inode, struct file *file)
  {
  	if (HFSPLUS_IS_RSRC(inode))
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
250
  		inode = HFSPLUS_I(inode)->rsrc_inode;
6e7152944   Alan Cox   hfsplus: missing ...
251
252
  	if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS)
  		return -EOVERFLOW;
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
253
  	atomic_inc(&HFSPLUS_I(inode)->opencnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
255
256
257
258
259
260
261
  	return 0;
  }
  
  static int hfsplus_file_release(struct inode *inode, struct file *file)
  {
  	struct super_block *sb = inode->i_sb;
  
  	if (HFSPLUS_IS_RSRC(inode))
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
262
263
  		inode = HFSPLUS_I(inode)->rsrc_inode;
  	if (atomic_dec_and_test(&HFSPLUS_I(inode)->opencnt)) {
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
264
  		mutex_lock(&inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
  		hfsplus_file_truncate(inode);
  		if (inode->i_flags & S_DEAD) {
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
267
268
  			hfsplus_delete_cat(inode->i_ino,
  					   HFSPLUS_SB(sb)->hidden_dir, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
270
  			hfsplus_delete_inode(inode);
  		}
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
271
  		mutex_unlock(&inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
  	}
  	return 0;
  }
d39aae9ec   Christoph Hellwig   add missing setat...
275
276
277
278
279
280
281
282
  static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
  {
  	struct inode *inode = dentry->d_inode;
  	int error;
  
  	error = inode_change_ok(inode, attr);
  	if (error)
  		return error;
1025774ce   Christoph Hellwig   remove inode_setattr
283
284
285
  
  	if ((attr->ia_valid & ATTR_SIZE) &&
  	    attr->ia_size != i_size_read(inode)) {
562c72aa5   Christoph Hellwig   fs: move inode_di...
286
  		inode_dio_wait(inode);
1025774ce   Christoph Hellwig   remove inode_setattr
287
288
289
290
291
292
293
294
  		error = vmtruncate(inode, attr->ia_size);
  		if (error)
  			return error;
  	}
  
  	setattr_copy(inode, attr);
  	mark_inode_dirty(inode);
  	return 0;
d39aae9ec   Christoph Hellwig   add missing setat...
295
  }
02c24a821   Josef Bacik   fs: push i_mutex ...
296
297
  int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end,
  		       int datasync)
b5fc510c4   Al Viro   get rid of file_f...
298
  {
281469766   Christoph Hellwig   hfsplus: simplify...
299
  	struct inode *inode = file->f_mapping->host;
e34947056   Christoph Hellwig   hfsplus: optimize...
300
  	struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
281469766   Christoph Hellwig   hfsplus: simplify...
301
  	struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
e34947056   Christoph Hellwig   hfsplus: optimize...
302
  	int error = 0, error2;
b5fc510c4   Al Viro   get rid of file_f...
303

02c24a821   Josef Bacik   fs: push i_mutex ...
304
305
306
307
  	error = filemap_write_and_wait_range(inode->i_mapping, start, end);
  	if (error)
  		return error;
  	mutex_lock(&inode->i_mutex);
281469766   Christoph Hellwig   hfsplus: simplify...
308
309
310
311
312
313
314
315
  	/*
  	 * Sync inode metadata into the catalog and extent trees.
  	 */
  	sync_inode_metadata(inode, 1);
  
  	/*
  	 * And explicitly write out the btrees.
  	 */
e34947056   Christoph Hellwig   hfsplus: optimize...
316
317
318
319
  	if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags))
  		error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
  
  	if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags)) {
2753cc281   Anton Salikhmetov   hfsplus: over 80 ...
320
321
  		error2 =
  			filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
e34947056   Christoph Hellwig   hfsplus: optimize...
322
323
324
325
326
327
328
329
330
  		if (!error)
  			error = error2;
  	}
  
  	if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) {
  		error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
  		if (!error)
  			error = error2;
  	}
34a2d313c   Christoph Hellwig   hfsplus: flush di...
331
332
  	if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
  		blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
02c24a821   Josef Bacik   fs: push i_mutex ...
333
  	mutex_unlock(&inode->i_mutex);
281469766   Christoph Hellwig   hfsplus: simplify...
334
  	return error;
b5fc510c4   Al Viro   get rid of file_f...
335
  }
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
336
  static const struct inode_operations hfsplus_file_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
  	.lookup		= hfsplus_file_lookup,
  	.truncate	= hfsplus_file_truncate,
d39aae9ec   Christoph Hellwig   add missing setat...
339
  	.setattr	= hfsplus_setattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
341
342
343
  	.setxattr	= hfsplus_setxattr,
  	.getxattr	= hfsplus_getxattr,
  	.listxattr	= hfsplus_listxattr,
  };
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
344
  static const struct file_operations hfsplus_file_operations = {
20b7643d8   Anton Salikhmetov   hfsplus: spaces/i...
345
  	.llseek		= generic_file_llseek,
543ade1fc   Badari Pulavarty   [PATCH] Streamlin...
346
347
348
349
  	.read		= do_sync_read,
  	.aio_read	= generic_file_aio_read,
  	.write		= do_sync_write,
  	.aio_write	= generic_file_aio_write,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
  	.mmap		= generic_file_mmap,
5ffc4ef45   Jens Axboe   sendfile: remove ...
351
  	.splice_read	= generic_file_splice_read,
b5fc510c4   Al Viro   get rid of file_f...
352
  	.fsync		= hfsplus_file_fsync,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
  	.open		= hfsplus_file_open,
  	.release	= hfsplus_file_release,
7cc4bcc6f   Arnd Bergmann   hfsplus: Push dow...
355
  	.unlocked_ioctl = hfsplus_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  };
c47da7985   Al Viro   hfsplus: propagat...
357
  struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  {
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
359
  	struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
  	struct inode *inode = new_inode(sb);
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
361
  	struct hfsplus_inode_info *hip;
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
362

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
  	if (!inode)
  		return NULL;
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
365
  	inode->i_ino = sbi->next_cnid++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  	inode->i_mode = mode;
4ac8489a7   David Howells   CRED: Wrap task c...
367
368
  	inode->i_uid = current_fsuid();
  	inode->i_gid = current_fsgid();
bfe868486   Miklos Szeredi   filesystems: add ...
369
  	set_nlink(inode, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
371
372
373
374
375
  
  	hip = HFSPLUS_I(inode);
  	INIT_LIST_HEAD(&hip->open_dir_list);
  	mutex_init(&hip->extents_lock);
  	atomic_set(&hip->opencnt, 0);
b33b7921d   Christoph Hellwig   hfsplus: split up...
376
  	hip->extent_state = 0;
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
377
378
379
380
381
382
383
384
385
386
  	hip->flags = 0;
  	memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
  	memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
  	hip->alloc_blocks = 0;
  	hip->first_blocks = 0;
  	hip->cached_start = 0;
  	hip->cached_blocks = 0;
  	hip->phys_size = 0;
  	hip->fs_blocks = 0;
  	hip->rsrc_inode = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
  	if (S_ISDIR(inode->i_mode)) {
  		inode->i_size = 2;
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
389
  		sbi->folder_count++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
392
  		inode->i_op = &hfsplus_dir_inode_operations;
  		inode->i_fop = &hfsplus_dir_operations;
  	} else if (S_ISREG(inode->i_mode)) {
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
393
  		sbi->file_count++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
396
  		inode->i_op = &hfsplus_file_inode_operations;
  		inode->i_fop = &hfsplus_file_operations;
  		inode->i_mapping->a_ops = &hfsplus_aops;
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
397
  		hip->clump_blocks = sbi->data_clump_blocks;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  	} else if (S_ISLNK(inode->i_mode)) {
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
399
  		sbi->file_count++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
  		inode->i_op = &page_symlink_inode_operations;
  		inode->i_mapping->a_ops = &hfsplus_aops;
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
402
  		hip->clump_blocks = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
  	} else
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
404
  		sbi->file_count++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
407
408
409
410
411
412
413
414
415
416
  	insert_inode_hash(inode);
  	mark_inode_dirty(inode);
  	sb->s_dirt = 1;
  
  	return inode;
  }
  
  void hfsplus_delete_inode(struct inode *inode)
  {
  	struct super_block *sb = inode->i_sb;
  
  	if (S_ISDIR(inode->i_mode)) {
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
417
  		HFSPLUS_SB(sb)->folder_count--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
420
  		sb->s_dirt = 1;
  		return;
  	}
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
421
  	HFSPLUS_SB(sb)->file_count--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
  	if (S_ISREG(inode->i_mode)) {
  		if (!inode->i_nlink) {
  			inode->i_size = 0;
  			hfsplus_file_truncate(inode);
  		}
  	} else if (S_ISLNK(inode->i_mode)) {
  		inode->i_size = 0;
  		hfsplus_file_truncate(inode);
  	}
  	sb->s_dirt = 1;
  }
  
  void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
  {
  	struct super_block *sb = inode->i_sb;
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
437
  	struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
438
  	struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
  	u32 count;
  	int i;
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
441
  	memcpy(&hip->first_extents, &fork->extents, sizeof(hfsplus_extent_rec));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
  	for (count = 0, i = 0; i < 8; i++)
  		count += be32_to_cpu(fork->extents[i].block_count);
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
444
445
446
447
448
449
450
451
452
453
454
  	hip->first_blocks = count;
  	memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
  	hip->cached_start = 0;
  	hip->cached_blocks = 0;
  
  	hip->alloc_blocks = be32_to_cpu(fork->total_blocks);
  	hip->phys_size = inode->i_size = be64_to_cpu(fork->total_size);
  	hip->fs_blocks =
  		(inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
  	inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits);
  	hip->clump_blocks =
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
455
  		be32_to_cpu(fork->clump_size) >> sbi->alloc_blksz_shift;
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
456
457
  	if (!hip->clump_blocks) {
  		hip->clump_blocks = HFSPLUS_IS_RSRC(inode) ?
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
458
459
460
  			sbi->rsrc_clump_blocks :
  			sbi->data_clump_blocks;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
  }
2753cc281   Anton Salikhmetov   hfsplus: over 80 ...
462
463
  void hfsplus_inode_write_fork(struct inode *inode,
  		struct hfsplus_fork_raw *fork)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
  {
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
465
  	memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
467
  	       sizeof(hfsplus_extent_rec));
  	fork->total_size = cpu_to_be64(inode->i_size);
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
468
  	fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode)->alloc_blocks);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
471
472
473
474
475
476
477
  }
  
  int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
  {
  	hfsplus_cat_entry entry;
  	int res = 0;
  	u16 type;
  
  	type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset);
f6089ff87   Christoph Hellwig   hfsplus: fix link...
478
  	HFSPLUS_I(inode)->linkid = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
481
482
483
484
485
486
  	if (type == HFSPLUS_FOLDER) {
  		struct hfsplus_cat_folder *folder = &entry.folder;
  
  		if (fd->entrylength < sizeof(struct hfsplus_cat_folder))
  			/* panic? */;
  		hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
  					sizeof(struct hfsplus_cat_folder));
  		hfsplus_get_perms(inode, &folder->permissions, 1);
bfe868486   Miklos Szeredi   filesystems: add ...
487
  		set_nlink(inode, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
489
490
  		inode->i_size = 2 + be32_to_cpu(folder->valence);
  		inode->i_atime = hfsp_mt2ut(folder->access_date);
  		inode->i_mtime = hfsp_mt2ut(folder->content_mod_date);
9a4cad95c   Roman Zippel   [PATCH] hfs: set ...
491
  		inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date);
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
492
493
  		HFSPLUS_I(inode)->create_date = folder->create_date;
  		HFSPLUS_I(inode)->fs_blocks = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
496
497
498
499
500
501
502
  		inode->i_op = &hfsplus_dir_inode_operations;
  		inode->i_fop = &hfsplus_dir_operations;
  	} else if (type == HFSPLUS_FILE) {
  		struct hfsplus_cat_file *file = &entry.file;
  
  		if (fd->entrylength < sizeof(struct hfsplus_cat_file))
  			/* panic? */;
  		hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
  					sizeof(struct hfsplus_cat_file));
b33b7921d   Christoph Hellwig   hfsplus: split up...
503
504
  		hfsplus_inode_read_fork(inode, HFSPLUS_IS_RSRC(inode) ?
  					&file->rsrc_fork : &file->data_fork);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
  		hfsplus_get_perms(inode, &file->permissions, 0);
bfe868486   Miklos Szeredi   filesystems: add ...
506
  		set_nlink(inode, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
  		if (S_ISREG(inode->i_mode)) {
  			if (file->permissions.dev)
bfe868486   Miklos Szeredi   filesystems: add ...
509
510
  				set_nlink(inode,
  					  be32_to_cpu(file->permissions.dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
512
513
514
515
516
517
518
519
520
521
522
  			inode->i_op = &hfsplus_file_inode_operations;
  			inode->i_fop = &hfsplus_file_operations;
  			inode->i_mapping->a_ops = &hfsplus_aops;
  		} else if (S_ISLNK(inode->i_mode)) {
  			inode->i_op = &page_symlink_inode_operations;
  			inode->i_mapping->a_ops = &hfsplus_aops;
  		} else {
  			init_special_inode(inode, inode->i_mode,
  					   be32_to_cpu(file->permissions.dev));
  		}
  		inode->i_atime = hfsp_mt2ut(file->access_date);
  		inode->i_mtime = hfsp_mt2ut(file->content_mod_date);
9a4cad95c   Roman Zippel   [PATCH] hfs: set ...
523
  		inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date);
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
524
  		HFSPLUS_I(inode)->create_date = file->create_date;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
  	} else {
634725a92   Roman Zippel   [PATCH] hfs: clea...
526
527
  		printk(KERN_ERR "hfs: bad catalog entry used to create inode
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
529
530
531
532
533
534
535
536
537
538
539
  		res = -EIO;
  	}
  	return res;
  }
  
  int hfsplus_cat_write_inode(struct inode *inode)
  {
  	struct inode *main_inode = inode;
  	struct hfs_find_data fd;
  	hfsplus_cat_entry entry;
  
  	if (HFSPLUS_IS_RSRC(inode))
6af502de2   Christoph Hellwig   hfsplus: fix HFSP...
540
  		main_inode = HFSPLUS_I(inode)->rsrc_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
543
  
  	if (!main_inode->i_nlink)
  		return 0;
dd73a01a3   Christoph Hellwig   hfsplus: fix HFSP...
544
  	if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb)->cat_tree, &fd))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
  		/* panic? */
  		return -EIO;
  
  	if (hfsplus_find_cat(main_inode->i_sb, main_inode->i_ino, &fd))
  		/* panic? */
  		goto out;
  
  	if (S_ISDIR(main_inode->i_mode)) {
  		struct hfsplus_cat_folder *folder = &entry.folder;
  
  		if (fd.entrylength < sizeof(struct hfsplus_cat_folder))
  			/* panic? */;
  		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
  					sizeof(struct hfsplus_cat_folder));
  		/* simple node checks? */
90e616905   Christoph Hellwig   hfsplus: create c...
560
  		hfsplus_cat_set_perms(inode, &folder->permissions);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
  		folder->access_date = hfsp_ut2mt(inode->i_atime);
  		folder->content_mod_date = hfsp_ut2mt(inode->i_mtime);
  		folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
  		folder->valence = cpu_to_be32(inode->i_size - 2);
  		hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
  					 sizeof(struct hfsplus_cat_folder));
  	} else if (HFSPLUS_IS_RSRC(inode)) {
  		struct hfsplus_cat_file *file = &entry.file;
  		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
  			       sizeof(struct hfsplus_cat_file));
  		hfsplus_inode_write_fork(inode, &file->rsrc_fork);
  		hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
  				sizeof(struct hfsplus_cat_file));
  	} else {
  		struct hfsplus_cat_file *file = &entry.file;
  
  		if (fd.entrylength < sizeof(struct hfsplus_cat_file))
  			/* panic? */;
  		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
  					sizeof(struct hfsplus_cat_file));
  		hfsplus_inode_write_fork(inode, &file->data_fork);
90e616905   Christoph Hellwig   hfsplus: create c...
582
  		hfsplus_cat_set_perms(inode, &file->permissions);
2753cc281   Anton Salikhmetov   hfsplus: over 80 ...
583
584
585
  		if (HFSPLUS_FLG_IMMUTABLE &
  				(file->permissions.rootflags |
  					file->permissions.userflags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
587
588
589
590
591
592
593
594
  			file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
  		else
  			file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED);
  		file->access_date = hfsp_ut2mt(inode->i_atime);
  		file->content_mod_date = hfsp_ut2mt(inode->i_mtime);
  		file->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
  		hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
  					 sizeof(struct hfsplus_cat_file));
  	}
e34947056   Christoph Hellwig   hfsplus: optimize...
595
596
  
  	set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
599
600
  out:
  	hfs_find_exit(&fd);
  	return 0;
  }