xref: /openbmc/linux/fs/hfs/dir.c (revision 6a6d6681ac1add9655b7ab5dd0b46b54aeb1b44f)
1  /*
2   *  linux/fs/hfs/dir.c
3   *
4   * Copyright (C) 1995-1997  Paul H. Hargrove
5   * (C) 2003 Ardis Technologies <roman@ardistech.com>
6   * This file may be distributed under the terms of the GNU General Public License.
7   *
8   * This file contains directory-related functions independent of which
9   * scheme is being used to represent forks.
10   *
11   * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
12   */
13  
14  #include "hfs_fs.h"
15  #include "btree.h"
16  
17  /*
18   * hfs_lookup()
19   */
20  static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry,
21  				 unsigned int flags)
22  {
23  	hfs_cat_rec rec;
24  	struct hfs_find_data fd;
25  	struct inode *inode = NULL;
26  	int res;
27  
28  	res = hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd);
29  	if (res)
30  		return ERR_PTR(res);
31  	hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, &dentry->d_name);
32  	res = hfs_brec_read(&fd, &rec, sizeof(rec));
33  	if (res) {
34  		if (res != -ENOENT)
35  			inode = ERR_PTR(res);
36  	} else {
37  		inode = hfs_iget(dir->i_sb, &fd.search_key->cat, &rec);
38  		if (!inode)
39  			inode = ERR_PTR(-EACCES);
40  	}
41  	hfs_find_exit(&fd);
42  	return d_splice_alias(inode, dentry);
43  }
44  
45  /*
46   * hfs_readdir
47   */
48  static int hfs_readdir(struct file *file, struct dir_context *ctx)
49  {
50  	struct inode *inode = file_inode(file);
51  	struct super_block *sb = inode->i_sb;
52  	int len, err;
53  	char strbuf[HFS_MAX_NAMELEN];
54  	union hfs_cat_rec entry;
55  	struct hfs_find_data fd;
56  	struct hfs_readdir_data *rd;
57  	u16 type;
58  
59  	if (ctx->pos >= inode->i_size)
60  		return 0;
61  
62  	err = hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
63  	if (err)
64  		return err;
65  	hfs_cat_build_key(sb, fd.search_key, inode->i_ino, NULL);
66  	err = hfs_brec_find(&fd);
67  	if (err)
68  		goto out;
69  
70  	if (ctx->pos == 0) {
71  		/* This is completely artificial... */
72  		if (!dir_emit_dot(file, ctx))
73  			goto out;
74  		ctx->pos = 1;
75  	}
76  	if (ctx->pos == 1) {
77  		if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) {
78  			err = -EIO;
79  			goto out;
80  		}
81  
82  		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
83  		if (entry.type != HFS_CDR_THD) {
84  			pr_err("bad catalog folder thread\n");
85  			err = -EIO;
86  			goto out;
87  		}
88  		//if (fd.entrylength < HFS_MIN_THREAD_SZ) {
89  		//	pr_err("truncated catalog thread\n");
90  		//	err = -EIO;
91  		//	goto out;
92  		//}
93  		if (!dir_emit(ctx, "..", 2,
94  			    be32_to_cpu(entry.thread.ParID), DT_DIR))
95  			goto out;
96  		ctx->pos = 2;
97  	}
98  	if (ctx->pos >= inode->i_size)
99  		goto out;
100  	err = hfs_brec_goto(&fd, ctx->pos - 1);
101  	if (err)
102  		goto out;
103  
104  	for (;;) {
105  		if (be32_to_cpu(fd.key->cat.ParID) != inode->i_ino) {
106  			pr_err("walked past end of dir\n");
107  			err = -EIO;
108  			goto out;
109  		}
110  
111  		if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) {
112  			err = -EIO;
113  			goto out;
114  		}
115  
116  		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
117  		type = entry.type;
118  		len = hfs_mac2asc(sb, strbuf, &fd.key->cat.CName);
119  		if (type == HFS_CDR_DIR) {
120  			if (fd.entrylength < sizeof(struct hfs_cat_dir)) {
121  				pr_err("small dir entry\n");
122  				err = -EIO;
123  				goto out;
124  			}
125  			if (!dir_emit(ctx, strbuf, len,
126  				    be32_to_cpu(entry.dir.DirID), DT_DIR))
127  				break;
128  		} else if (type == HFS_CDR_FIL) {
129  			if (fd.entrylength < sizeof(struct hfs_cat_file)) {
130  				pr_err("small file entry\n");
131  				err = -EIO;
132  				goto out;
133  			}
134  			if (!dir_emit(ctx, strbuf, len,
135  				    be32_to_cpu(entry.file.FlNum), DT_REG))
136  				break;
137  		} else {
138  			pr_err("bad catalog entry type %d\n", type);
139  			err = -EIO;
140  			goto out;
141  		}
142  		ctx->pos++;
143  		if (ctx->pos >= inode->i_size)
144  			goto out;
145  		err = hfs_brec_goto(&fd, 1);
146  		if (err)
147  			goto out;
148  	}
149  	rd = file->private_data;
150  	if (!rd) {
151  		rd = kmalloc(sizeof(struct hfs_readdir_data), GFP_KERNEL);
152  		if (!rd) {
153  			err = -ENOMEM;
154  			goto out;
155  		}
156  		file->private_data = rd;
157  		rd->file = file;
158  		spin_lock(&HFS_I(inode)->open_dir_lock);
159  		list_add(&rd->list, &HFS_I(inode)->open_dir_list);
160  		spin_unlock(&HFS_I(inode)->open_dir_lock);
161  	}
162  	/*
163  	 * Can be done after the list insertion; exclusion with
164  	 * hfs_delete_cat() is provided by directory lock.
165  	 */
166  	memcpy(&rd->key, &fd.key->cat, sizeof(struct hfs_cat_key));
167  out:
168  	hfs_find_exit(&fd);
169  	return err;
170  }
171  
172  static int hfs_dir_release(struct inode *inode, struct file *file)
173  {
174  	struct hfs_readdir_data *rd = file->private_data;
175  	if (rd) {
176  		spin_lock(&HFS_I(inode)->open_dir_lock);
177  		list_del(&rd->list);
178  		spin_unlock(&HFS_I(inode)->open_dir_lock);
179  		kfree(rd);
180  	}
181  	return 0;
182  }
183  
184  /*
185   * hfs_create()
186   *
187   * This is the create() entry in the inode_operations structure for
188   * regular HFS directories.  The purpose is to create a new file in
189   * a directory and return a corresponding inode, given the inode for
190   * the directory and the name (and its length) of the new file.
191   */
192  static int hfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
193  		      bool excl)
194  {
195  	struct inode *inode;
196  	int res;
197  
198  	inode = hfs_new_inode(dir, &dentry->d_name, mode);
199  	if (!inode)
200  		return -ENOMEM;
201  
202  	res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode);
203  	if (res) {
204  		clear_nlink(inode);
205  		hfs_delete_inode(inode);
206  		iput(inode);
207  		return res;
208  	}
209  	d_instantiate(dentry, inode);
210  	mark_inode_dirty(inode);
211  	return 0;
212  }
213  
214  /*
215   * hfs_mkdir()
216   *
217   * This is the mkdir() entry in the inode_operations structure for
218   * regular HFS directories.  The purpose is to create a new directory
219   * in a directory, given the inode for the parent directory and the
220   * name (and its length) of the new directory.
221   */
222  static int hfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
223  {
224  	struct inode *inode;
225  	int res;
226  
227  	inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode);
228  	if (!inode)
229  		return -ENOMEM;
230  
231  	res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode);
232  	if (res) {
233  		clear_nlink(inode);
234  		hfs_delete_inode(inode);
235  		iput(inode);
236  		return res;
237  	}
238  	d_instantiate(dentry, inode);
239  	mark_inode_dirty(inode);
240  	return 0;
241  }
242  
243  /*
244   * hfs_remove()
245   *
246   * This serves as both unlink() and rmdir() in the inode_operations
247   * structure for regular HFS directories.  The purpose is to delete
248   * an existing child, given the inode for the parent directory and
249   * the name (and its length) of the existing directory.
250   *
251   * HFS does not have hardlinks, so both rmdir and unlink set the
252   * link count to 0.  The only difference is the emptiness check.
253   */
254  static int hfs_remove(struct inode *dir, struct dentry *dentry)
255  {
256  	struct inode *inode = d_inode(dentry);
257  	int res;
258  
259  	if (S_ISDIR(inode->i_mode) && inode->i_size != 2)
260  		return -ENOTEMPTY;
261  	res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
262  	if (res)
263  		return res;
264  	clear_nlink(inode);
265  	inode->i_ctime = current_time(inode);
266  	hfs_delete_inode(inode);
267  	mark_inode_dirty(inode);
268  	return 0;
269  }
270  
271  /*
272   * hfs_rename()
273   *
274   * This is the rename() entry in the inode_operations structure for
275   * regular HFS directories.  The purpose is to rename an existing
276   * file or directory, given the inode for the current directory and
277   * the name (and its length) of the existing file/directory and the
278   * inode for the new directory and the name (and its length) of the
279   * new file/directory.
280   * XXX: how do you handle must_be dir?
281   */
282  static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
283  		      struct inode *new_dir, struct dentry *new_dentry,
284  		      unsigned int flags)
285  {
286  	int res;
287  
288  	if (flags & ~RENAME_NOREPLACE)
289  		return -EINVAL;
290  
291  	/* Unlink destination if it already exists */
292  	if (d_really_is_positive(new_dentry)) {
293  		res = hfs_remove(new_dir, new_dentry);
294  		if (res)
295  			return res;
296  	}
297  
298  	res = hfs_cat_move(d_inode(old_dentry)->i_ino,
299  			   old_dir, &old_dentry->d_name,
300  			   new_dir, &new_dentry->d_name);
301  	if (!res)
302  		hfs_cat_build_key(old_dir->i_sb,
303  				  (btree_key *)&HFS_I(d_inode(old_dentry))->cat_key,
304  				  new_dir->i_ino, &new_dentry->d_name);
305  	return res;
306  }
307  
308  const struct file_operations hfs_dir_operations = {
309  	.read		= generic_read_dir,
310  	.iterate_shared	= hfs_readdir,
311  	.llseek		= generic_file_llseek,
312  	.release	= hfs_dir_release,
313  };
314  
315  const struct inode_operations hfs_dir_inode_operations = {
316  	.create		= hfs_create,
317  	.lookup		= hfs_lookup,
318  	.unlink		= hfs_remove,
319  	.mkdir		= hfs_mkdir,
320  	.rmdir		= hfs_remove,
321  	.rename		= hfs_rename,
322  	.setattr	= hfs_inode_setattr,
323  };
324