xref: /openbmc/linux/fs/hfs/dir.c (revision 1cb8f3e2d8fe7533c26df9925a83bd3d185b312e)
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 user_namespace *mnt_userns, struct inode *dir,
193  		      struct dentry *dentry, umode_t mode, 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 user_namespace *mnt_userns, struct inode *dir,
223  		     struct dentry *dentry, umode_t mode)
224  {
225  	struct inode *inode;
226  	int res;
227  
228  	inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode);
229  	if (!inode)
230  		return -ENOMEM;
231  
232  	res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode);
233  	if (res) {
234  		clear_nlink(inode);
235  		hfs_delete_inode(inode);
236  		iput(inode);
237  		return res;
238  	}
239  	d_instantiate(dentry, inode);
240  	mark_inode_dirty(inode);
241  	return 0;
242  }
243  
244  /*
245   * hfs_remove()
246   *
247   * This serves as both unlink() and rmdir() in the inode_operations
248   * structure for regular HFS directories.  The purpose is to delete
249   * an existing child, given the inode for the parent directory and
250   * the name (and its length) of the existing directory.
251   *
252   * HFS does not have hardlinks, so both rmdir and unlink set the
253   * link count to 0.  The only difference is the emptiness check.
254   */
255  static int hfs_remove(struct inode *dir, struct dentry *dentry)
256  {
257  	struct inode *inode = d_inode(dentry);
258  	int res;
259  
260  	if (S_ISDIR(inode->i_mode) && inode->i_size != 2)
261  		return -ENOTEMPTY;
262  	res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
263  	if (res)
264  		return res;
265  	clear_nlink(inode);
266  	inode->i_ctime = current_time(inode);
267  	hfs_delete_inode(inode);
268  	mark_inode_dirty(inode);
269  	return 0;
270  }
271  
272  /*
273   * hfs_rename()
274   *
275   * This is the rename() entry in the inode_operations structure for
276   * regular HFS directories.  The purpose is to rename an existing
277   * file or directory, given the inode for the current directory and
278   * the name (and its length) of the existing file/directory and the
279   * inode for the new directory and the name (and its length) of the
280   * new file/directory.
281   * XXX: how do you handle must_be dir?
282   */
283  static int hfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
284  		      struct dentry *old_dentry, struct inode *new_dir,
285  		      struct dentry *new_dentry, unsigned int flags)
286  {
287  	int res;
288  
289  	if (flags & ~RENAME_NOREPLACE)
290  		return -EINVAL;
291  
292  	/* Unlink destination if it already exists */
293  	if (d_really_is_positive(new_dentry)) {
294  		res = hfs_remove(new_dir, new_dentry);
295  		if (res)
296  			return res;
297  	}
298  
299  	res = hfs_cat_move(d_inode(old_dentry)->i_ino,
300  			   old_dir, &old_dentry->d_name,
301  			   new_dir, &new_dentry->d_name);
302  	if (!res)
303  		hfs_cat_build_key(old_dir->i_sb,
304  				  (btree_key *)&HFS_I(d_inode(old_dentry))->cat_key,
305  				  new_dir->i_ino, &new_dentry->d_name);
306  	return res;
307  }
308  
309  const struct file_operations hfs_dir_operations = {
310  	.read		= generic_read_dir,
311  	.iterate_shared	= hfs_readdir,
312  	.llseek		= generic_file_llseek,
313  	.release	= hfs_dir_release,
314  };
315  
316  const struct inode_operations hfs_dir_inode_operations = {
317  	.create		= hfs_create,
318  	.lookup		= hfs_lookup,
319  	.unlink		= hfs_remove,
320  	.mkdir		= hfs_mkdir,
321  	.rmdir		= hfs_remove,
322  	.rename		= hfs_rename,
323  	.setattr	= hfs_inode_setattr,
324  };
325