Blame view

fs/hfs/dir.c 8.03 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  /*
   *  linux/fs/hfs/dir.c
   *
   * Copyright (C) 1995-1997  Paul H. Hargrove
   * (C) 2003 Ardis Technologies <roman@ardistech.com>
   * This file may be distributed under the terms of the GNU General Public License.
   *
   * This file contains directory-related functions independent of which
   * scheme is being used to represent forks.
   *
   * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
   */
  
  #include "hfs_fs.h"
  #include "btree.h"
  
  /*
   * hfs_lookup()
   */
  static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry,
  				 struct nameidata *nd)
  {
  	hfs_cat_rec rec;
  	struct hfs_find_data fd;
  	struct inode *inode = NULL;
  	int res;
  
  	dentry->d_op = &hfs_dentry_operations;
  
  	hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd);
328b92278   Roman Zippel   [PATCH] hfs: NLS ...
31
  	hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, &dentry->d_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
  	res = hfs_brec_read(&fd, &rec, sizeof(rec));
  	if (res) {
  		hfs_find_exit(&fd);
  		if (res == -ENOENT) {
  			/* No such entry */
  			inode = NULL;
  			goto done;
  		}
  		return ERR_PTR(res);
  	}
  	inode = hfs_iget(dir->i_sb, &fd.search_key->cat, &rec);
  	hfs_find_exit(&fd);
  	if (!inode)
  		return ERR_PTR(-EACCES);
  done:
  	d_add(dentry, inode);
  	return NULL;
  }
  
  /*
   * hfs_readdir
   */
  static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
  {
c52889600   Josef Sipek   [PATCH] struct pa...
56
  	struct inode *inode = filp->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
  	struct super_block *sb = inode->i_sb;
  	int len, err;
328b92278   Roman Zippel   [PATCH] hfs: NLS ...
59
  	char strbuf[HFS_MAX_NAMELEN];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
63
64
65
66
67
68
  	union hfs_cat_rec entry;
  	struct hfs_find_data fd;
  	struct hfs_readdir_data *rd;
  	u16 type;
  
  	if (filp->f_pos >= inode->i_size)
  		return 0;
  
  	hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
328b92278   Roman Zippel   [PATCH] hfs: NLS ...
69
  	hfs_cat_build_key(sb, fd.search_key, inode->i_ino, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
73
74
75
76
77
78
79
80
81
82
83
  	err = hfs_brec_find(&fd);
  	if (err)
  		goto out;
  
  	switch ((u32)filp->f_pos) {
  	case 0:
  		/* This is completely artificial... */
  		if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR))
  			goto out;
  		filp->f_pos++;
  		/* fall through */
  	case 1:
  		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
  		if (entry.type != HFS_CDR_THD) {
7cf3cc303   Roman Zippel   [PATCH] hfs: clea...
84
85
  			printk(KERN_ERR "hfs: bad catalog folder thread
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
  			err = -EIO;
  			goto out;
  		}
  		//if (fd.entrylength < HFS_MIN_THREAD_SZ) {
7cf3cc303   Roman Zippel   [PATCH] hfs: clea...
90
91
  		//	printk(KERN_ERR "hfs: truncated catalog thread
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  		//	err = -EIO;
  		//	goto out;
  		//}
  		if (filldir(dirent, "..", 2, 1,
  			    be32_to_cpu(entry.thread.ParID), DT_DIR))
  			goto out;
  		filp->f_pos++;
  		/* fall through */
  	default:
  		if (filp->f_pos >= inode->i_size)
  			goto out;
  		err = hfs_brec_goto(&fd, filp->f_pos - 1);
  		if (err)
  			goto out;
  	}
  
  	for (;;) {
  		if (be32_to_cpu(fd.key->cat.ParID) != inode->i_ino) {
7cf3cc303   Roman Zippel   [PATCH] hfs: clea...
110
111
  			printk(KERN_ERR "hfs: walked past end of dir
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
114
115
116
  			err = -EIO;
  			goto out;
  		}
  		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
  		type = entry.type;
328b92278   Roman Zippel   [PATCH] hfs: NLS ...
117
  		len = hfs_mac2asc(sb, strbuf, &fd.key->cat.CName);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
  		if (type == HFS_CDR_DIR) {
  			if (fd.entrylength < sizeof(struct hfs_cat_dir)) {
7cf3cc303   Roman Zippel   [PATCH] hfs: clea...
120
121
  				printk(KERN_ERR "hfs: small dir entry
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
125
126
127
128
129
  				err = -EIO;
  				goto out;
  			}
  			if (filldir(dirent, strbuf, len, filp->f_pos,
  				    be32_to_cpu(entry.dir.DirID), DT_DIR))
  				break;
  		} else if (type == HFS_CDR_FIL) {
  			if (fd.entrylength < sizeof(struct hfs_cat_file)) {
7cf3cc303   Roman Zippel   [PATCH] hfs: clea...
130
131
  				printk(KERN_ERR "hfs: small file entry
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
135
136
137
138
  				err = -EIO;
  				goto out;
  			}
  			if (filldir(dirent, strbuf, len, filp->f_pos,
  				    be32_to_cpu(entry.file.FlNum), DT_REG))
  				break;
  		} else {
7cf3cc303   Roman Zippel   [PATCH] hfs: clea...
139
140
  			printk(KERN_ERR "hfs: bad catalog entry type %d
  ", type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
144
145
146
147
148
149
150
151
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
  			err = -EIO;
  			goto out;
  		}
  		filp->f_pos++;
  		if (filp->f_pos >= inode->i_size)
  			goto out;
  		err = hfs_brec_goto(&fd, 1);
  		if (err)
  			goto out;
  	}
  	rd = filp->private_data;
  	if (!rd) {
  		rd = kmalloc(sizeof(struct hfs_readdir_data), GFP_KERNEL);
  		if (!rd) {
  			err = -ENOMEM;
  			goto out;
  		}
  		filp->private_data = rd;
  		rd->file = filp;
  		list_add(&rd->list, &HFS_I(inode)->open_dir_list);
  	}
  	memcpy(&rd->key, &fd.key, sizeof(struct hfs_cat_key));
  out:
  	hfs_find_exit(&fd);
  	return err;
  }
  
  static int hfs_dir_release(struct inode *inode, struct file *file)
  {
  	struct hfs_readdir_data *rd = file->private_data;
  	if (rd) {
  		list_del(&rd->list);
  		kfree(rd);
  	}
  	return 0;
  }
  
  /*
   * hfs_create()
   *
   * This is the create() entry in the inode_operations structure for
   * regular HFS directories.  The purpose is to create a new file in
   * a directory and return a corresponding inode, given the inode for
   * the directory and the name (and its length) of the new file.
   */
  static int hfs_create(struct inode *dir, struct dentry *dentry, int mode,
  		      struct nameidata *nd)
  {
  	struct inode *inode;
  	int res;
  
  	inode = hfs_new_inode(dir, &dentry->d_name, mode);
  	if (!inode)
  		return -ENOSPC;
  
  	res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode);
  	if (res) {
  		inode->i_nlink = 0;
  		hfs_delete_inode(inode);
  		iput(inode);
  		return res;
  	}
  	d_instantiate(dentry, inode);
  	mark_inode_dirty(inode);
  	return 0;
  }
  
  /*
   * hfs_mkdir()
   *
   * This is the mkdir() entry in the inode_operations structure for
   * regular HFS directories.  The purpose is to create a new directory
   * in a directory, given the inode for the parent directory and the
   * name (and its length) of the new directory.
   */
  static int hfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
  {
  	struct inode *inode;
  	int res;
  
  	inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode);
  	if (!inode)
  		return -ENOSPC;
  
  	res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode);
  	if (res) {
  		inode->i_nlink = 0;
  		hfs_delete_inode(inode);
  		iput(inode);
  		return res;
  	}
  	d_instantiate(dentry, inode);
  	mark_inode_dirty(inode);
  	return 0;
  }
  
  /*
   * hfs_unlink()
   *
   * This is the unlink() entry in the inode_operations structure for
   * regular HFS directories.  The purpose is to delete an existing
   * file, given the inode for the parent directory and the name
   * (and its length) of the existing file.
   */
  static int hfs_unlink(struct inode *dir, struct dentry *dentry)
  {
  	struct inode *inode;
  	int res;
  
  	inode = dentry->d_inode;
  	res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
  	if (res)
  		return res;
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
254
  	drop_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
  	hfs_delete_inode(inode);
  	inode->i_ctime = CURRENT_TIME_SEC;
  	mark_inode_dirty(inode);
  
  	return res;
  }
  
  /*
   * hfs_rmdir()
   *
   * This is the rmdir() entry in the inode_operations structure for
   * regular HFS directories.  The purpose is to delete an existing
   * directory, given the inode for the parent directory and the name
   * (and its length) of the existing directory.
   */
  static int hfs_rmdir(struct inode *dir, struct dentry *dentry)
  {
  	struct inode *inode;
  	int res;
  
  	inode = dentry->d_inode;
  	if (inode->i_size != 2)
  		return -ENOTEMPTY;
  	res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
  	if (res)
  		return res;
ce71ec368   Dave Hansen   [PATCH] r/o bind ...
281
  	clear_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
  	inode->i_ctime = CURRENT_TIME_SEC;
  	hfs_delete_inode(inode);
  	mark_inode_dirty(inode);
  	return 0;
  }
  
  /*
   * hfs_rename()
   *
   * This is the rename() entry in the inode_operations structure for
   * regular HFS directories.  The purpose is to rename an existing
   * file or directory, given the inode for the current directory and
   * the name (and its length) of the existing file/directory and the
   * inode for the new directory and the name (and its length) of the
   * new file/directory.
   * XXX: how do you handle must_be dir?
   */
  static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
  		      struct inode *new_dir, struct dentry *new_dentry)
  {
  	int res;
  
  	/* Unlink destination if it already exists */
  	if (new_dentry->d_inode) {
  		res = hfs_unlink(new_dir, new_dentry);
  		if (res)
  			return res;
  	}
  
  	res = hfs_cat_move(old_dentry->d_inode->i_ino,
  			   old_dir, &old_dentry->d_name,
  			   new_dir, &new_dentry->d_name);
  	if (!res)
328b92278   Roman Zippel   [PATCH] hfs: NLS ...
315
316
  		hfs_cat_build_key(old_dir->i_sb,
  				  (btree_key *)&HFS_I(old_dentry->d_inode)->cat_key,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
318
319
  				  new_dir->i_ino, &new_dentry->d_name);
  	return res;
  }
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
320
  const struct file_operations hfs_dir_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
322
323
324
325
  	.read		= generic_read_dir,
  	.readdir	= hfs_readdir,
  	.llseek		= generic_file_llseek,
  	.release	= hfs_dir_release,
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
326
  const struct inode_operations hfs_dir_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
330
331
332
333
334
  	.create		= hfs_create,
  	.lookup		= hfs_lookup,
  	.unlink		= hfs_unlink,
  	.mkdir		= hfs_mkdir,
  	.rmdir		= hfs_rmdir,
  	.rename		= hfs_rename,
  	.setattr	= hfs_inode_setattr,
  };