Blame view

fs/exofs/namei.c 7.32 KB
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1
2
  /*
   * Copyright (C) 2005, 2006
27d2e1491   Boaz Harrosh   exofs: Remove IBM...
3
   * Avishay Traeger (avishay@gmail.com)
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
4
   * Copyright (C) 2008, 2009
aa281ac63   Boaz Harrosh   Boaz Harrosh - Fi...
5
   * Boaz Harrosh <ooo@electrozaur.com>
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
   *
   * Copyrights for code taken from ext2:
   *     Copyright (C) 1992, 1993, 1994, 1995
   *     Remy Card (card@masi.ibp.fr)
   *     Laboratoire MASI - Institut Blaise Pascal
   *     Universite Pierre et Marie Curie (Paris VI)
   *     from
   *     linux/fs/minix/inode.c
   *     Copyright (C) 1991, 1992  Linus Torvalds
   *
   * This file is part of exofs.
   *
   * exofs is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation.  Since it is based on ext2, and the only
   * valid version of GPL for the Linux kernel is version 2, the only valid
   * version of GPL for exofs is version 2.
   *
   * exofs is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with exofs; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   */
  
  #include "exofs.h"
  
  static inline int exofs_add_nondir(struct dentry *dentry, struct inode *inode)
  {
  	int err = exofs_add_link(dentry, inode);
  	if (!err) {
  		d_instantiate(dentry, inode);
  		return 0;
  	}
  	inode_dec_link_count(inode);
  	iput(inode);
  	return err;
  }
  
  static struct dentry *exofs_lookup(struct inode *dir, struct dentry *dentry,
00cd8dd3b   Al Viro   stop passing name...
49
  				   unsigned int flags)
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
50
51
52
53
54
55
56
57
  {
  	struct inode *inode;
  	ino_t ino;
  
  	if (dentry->d_name.len > EXOFS_NAME_LEN)
  		return ERR_PTR(-ENAMETOOLONG);
  
  	ino = exofs_inode_by_name(dir, dentry);
a9049376e   Al Viro   make d_splice_ali...
58
  	inode = ino ? exofs_iget(dir->i_sb, ino) : NULL;
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
59
60
  	return d_splice_alias(inode, dentry);
  }
4acdaf27e   Al Viro   switch ->create()...
61
  static int exofs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
ebfc3b49a   Al Viro   don't pass nameid...
62
  			 bool excl)
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
63
64
65
66
67
68
69
70
71
72
73
74
  {
  	struct inode *inode = exofs_new_inode(dir, mode);
  	int err = PTR_ERR(inode);
  	if (!IS_ERR(inode)) {
  		inode->i_op = &exofs_file_inode_operations;
  		inode->i_fop = &exofs_file_operations;
  		inode->i_mapping->a_ops = &exofs_aops;
  		mark_inode_dirty(inode);
  		err = exofs_add_nondir(dentry, inode);
  	}
  	return err;
  }
1a67aafb5   Al Viro   switch ->mknod() ...
75
  static int exofs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
76
77
78
79
  		       dev_t rdev)
  {
  	struct inode *inode;
  	int err;
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
80
81
82
83
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
  	inode = exofs_new_inode(dir, mode);
  	err = PTR_ERR(inode);
  	if (!IS_ERR(inode)) {
  		init_special_inode(inode, inode->i_mode, rdev);
  		mark_inode_dirty(inode);
  		err = exofs_add_nondir(dentry, inode);
  	}
  	return err;
  }
  
  static int exofs_symlink(struct inode *dir, struct dentry *dentry,
  			  const char *symname)
  {
  	struct super_block *sb = dir->i_sb;
  	int err = -ENAMETOOLONG;
  	unsigned l = strlen(symname)+1;
  	struct inode *inode;
  	struct exofs_i_info *oi;
  
  	if (l > sb->s_blocksize)
  		goto out;
  
  	inode = exofs_new_inode(dir, S_IFLNK | S_IRWXUGO);
  	err = PTR_ERR(inode);
  	if (IS_ERR(inode))
  		goto out;
  
  	oi = exofs_i(inode);
  	if (l > sizeof(oi->i_data)) {
  		/* slow symlink */
a5ef103da   Al Viro   exofs: switch to ...
110
  		inode->i_op = &page_symlink_inode_operations;
21fc61c73   Al Viro   don't put symlink...
111
  		inode_nohighmem(inode);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
112
113
114
115
116
117
118
119
  		inode->i_mapping->a_ops = &exofs_aops;
  		memset(oi->i_data, 0, sizeof(oi->i_data));
  
  		err = page_symlink(inode, symname, l);
  		if (err)
  			goto out_fail;
  	} else {
  		/* fast symlink */
a5ef103da   Al Viro   exofs: switch to ...
120
121
  		inode->i_op = &simple_symlink_inode_operations;
  		inode->i_link = (char *)oi->i_data;
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  		memcpy(oi->i_data, symname, l);
  		inode->i_size = l-1;
  	}
  	mark_inode_dirty(inode);
  
  	err = exofs_add_nondir(dentry, inode);
  out:
  	return err;
  
  out_fail:
  	inode_dec_link_count(inode);
  	iput(inode);
  	goto out;
  }
  
  static int exofs_link(struct dentry *old_dentry, struct inode *dir,
  		struct dentry *dentry)
  {
2b0143b5c   David Howells   VFS: normal files...
140
  	struct inode *inode = d_inode(old_dentry);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
141

078cd8279   Deepa Dinamani   fs: Replace CURRE...
142
  	inode->i_ctime = current_time(inode);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
143
  	inode_inc_link_count(inode);
7de9c6ee3   Al Viro   new helper: ihold()
144
  	ihold(inode);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
145
146
147
  
  	return exofs_add_nondir(dentry, inode);
  }
18bb1db3e   Al Viro   switch vfs_mkdir(...
148
  static int exofs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
149
150
  {
  	struct inode *inode;
8de527787   Al Viro   vfs: check i_nlin...
151
  	int err;
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
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
  
  	inode_inc_link_count(dir);
  
  	inode = exofs_new_inode(dir, S_IFDIR | mode);
  	err = PTR_ERR(inode);
  	if (IS_ERR(inode))
  		goto out_dir;
  
  	inode->i_op = &exofs_dir_inode_operations;
  	inode->i_fop = &exofs_dir_operations;
  	inode->i_mapping->a_ops = &exofs_aops;
  
  	inode_inc_link_count(inode);
  
  	err = exofs_make_empty(inode, dir);
  	if (err)
  		goto out_fail;
  
  	err = exofs_add_link(dentry, inode);
  	if (err)
  		goto out_fail;
  
  	d_instantiate(dentry, inode);
  out:
  	return err;
  
  out_fail:
  	inode_dec_link_count(inode);
  	inode_dec_link_count(inode);
  	iput(inode);
  out_dir:
  	inode_dec_link_count(dir);
  	goto out;
  }
  
  static int exofs_unlink(struct inode *dir, struct dentry *dentry)
  {
2b0143b5c   David Howells   VFS: normal files...
189
  	struct inode *inode = d_inode(dentry);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  	struct exofs_dir_entry *de;
  	struct page *page;
  	int err = -ENOENT;
  
  	de = exofs_find_entry(dir, dentry, &page);
  	if (!de)
  		goto out;
  
  	err = exofs_delete_entry(de, page);
  	if (err)
  		goto out;
  
  	inode->i_ctime = dir->i_ctime;
  	inode_dec_link_count(inode);
  	err = 0;
  out:
  	return err;
  }
  
  static int exofs_rmdir(struct inode *dir, struct dentry *dentry)
  {
2b0143b5c   David Howells   VFS: normal files...
211
  	struct inode *inode = d_inode(dentry);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
  	int err = -ENOTEMPTY;
  
  	if (exofs_empty_dir(inode)) {
  		err = exofs_unlink(dir, dentry);
  		if (!err) {
  			inode->i_size = 0;
  			inode_dec_link_count(inode);
  			inode_dec_link_count(dir);
  		}
  	}
  	return err;
  }
  
  static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
f03b8ad8d   Miklos Szeredi   fs: support RENAM...
226
227
  			struct inode *new_dir, struct dentry *new_dentry,
  			unsigned int flags)
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
228
  {
2b0143b5c   David Howells   VFS: normal files...
229
230
  	struct inode *old_inode = d_inode(old_dentry);
  	struct inode *new_inode = d_inode(new_dentry);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
231
232
233
234
235
  	struct page *dir_page = NULL;
  	struct exofs_dir_entry *dir_de = NULL;
  	struct page *old_page;
  	struct exofs_dir_entry *old_de;
  	int err = -ENOENT;
f03b8ad8d   Miklos Szeredi   fs: support RENAM...
236
237
  	if (flags & ~RENAME_NOREPLACE)
  		return -EINVAL;
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  	old_de = exofs_find_entry(old_dir, old_dentry, &old_page);
  	if (!old_de)
  		goto out;
  
  	if (S_ISDIR(old_inode->i_mode)) {
  		err = -EIO;
  		dir_de = exofs_dotdot(old_inode, &dir_page);
  		if (!dir_de)
  			goto out_old;
  	}
  
  	if (new_inode) {
  		struct page *new_page;
  		struct exofs_dir_entry *new_de;
  
  		err = -ENOTEMPTY;
  		if (dir_de && !exofs_empty_dir(new_inode))
  			goto out_dir;
  
  		err = -ENOENT;
  		new_de = exofs_find_entry(new_dir, new_dentry, &new_page);
  		if (!new_de)
  			goto out_dir;
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
261
  		err = exofs_set_link(new_dir, new_de, new_page, old_inode);
078cd8279   Deepa Dinamani   fs: Replace CURRE...
262
  		new_inode->i_ctime = current_time(new_inode);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
263
264
265
266
267
268
  		if (dir_de)
  			drop_nlink(new_inode);
  		inode_dec_link_count(new_inode);
  		if (err)
  			goto out_dir;
  	} else {
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
269
  		err = exofs_add_link(new_dentry, old_inode);
babfe5604   Al Viro   exofs: i_nlink ra...
270
  		if (err)
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
271
  			goto out_dir;
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
272
273
274
  		if (dir_de)
  			inode_inc_link_count(new_dir);
  	}
078cd8279   Deepa Dinamani   fs: Replace CURRE...
275
  	old_inode->i_ctime = current_time(old_inode);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
276
277
  
  	exofs_delete_entry(old_de, old_page);
babfe5604   Al Viro   exofs: i_nlink ra...
278
  	mark_inode_dirty(old_inode);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
279
280
281
282
283
284
285
286
287
288
289
290
291
  
  	if (dir_de) {
  		err = exofs_set_link(old_inode, dir_de, dir_page, new_dir);
  		inode_dec_link_count(old_dir);
  		if (err)
  			goto out_dir;
  	}
  	return 0;
  
  
  out_dir:
  	if (dir_de) {
  		kunmap(dir_page);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
292
  		put_page(dir_page);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
293
294
295
  	}
  out_old:
  	kunmap(old_page);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
296
  	put_page(old_page);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
297
298
299
300
301
302
303
304
305
306
307
308
309
  out:
  	return err;
  }
  
  const struct inode_operations exofs_dir_inode_operations = {
  	.create 	= exofs_create,
  	.lookup 	= exofs_lookup,
  	.link   	= exofs_link,
  	.unlink 	= exofs_unlink,
  	.symlink	= exofs_symlink,
  	.mkdir  	= exofs_mkdir,
  	.rmdir  	= exofs_rmdir,
  	.mknod  	= exofs_mknod,
2773bf00a   Miklos Szeredi   fs: rename "renam...
310
  	.rename		= exofs_rename,
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
311
312
313
314
315
316
  	.setattr	= exofs_setattr,
  };
  
  const struct inode_operations exofs_special_inode_operations = {
  	.setattr	= exofs_setattr,
  };