namei.c 7.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 * linux/fs/ufs/namei.c
 *
4 5 6
 * Migration to usage of "page cache" on May 2006 by
 * Evgeniy Dushistov <dushistov@mail.ru> based on ext2 code base.
 *
L
Linus Torvalds 已提交
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
 * Copyright (C) 1998
 * Daniel Pirkl <daniel.pirkl@email.cz>
 * Charles University, Faculty of Mathematics and Physics
 *
 *  from
 *
 *  linux/fs/ext2/namei.c
 *
 * 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/namei.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *
 *  Big-endian to little-endian byte-swapping/bitmaps by
 *        David S. Miller (davem@caip.rutgers.edu), 1995
 */

#include <linux/time.h>
#include <linux/fs.h>
#include <linux/ufs_fs.h>
#include <linux/smp_lock.h>
#include "swab.h"	/* will go away - see comment in mknod() */
#include "util.h"

static inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode)
{
	int err = ufs_add_link(dentry, inode);
	if (!err) {
		d_instantiate(dentry, inode);
		return 0;
	}
44
	inode_dec_link_count(inode);
L
Linus Torvalds 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
	iput(inode);
	return err;
}

static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
{
	struct inode * inode = NULL;
	ino_t ino;
	
	if (dentry->d_name.len > UFS_MAXNAMLEN)
		return ERR_PTR(-ENAMETOOLONG);

	lock_kernel();
	ino = ufs_inode_by_name(dir, dentry);
	if (ino) {
		inode = iget(dir->i_sb, ino);
		if (!inode) {
			unlock_kernel();
			return ERR_PTR(-EACCES);
		}
	}
	unlock_kernel();
	d_add(dentry, inode);
	return NULL;
}

/*
 * By the time this is called, we already have created
 * the directory cache entry for the new file, but it
 * is so far negative - it has no inode.
 *
 * If the create succeeds, we fill in the inode information
 * with d_instantiate(). 
 */
static int ufs_create (struct inode * dir, struct dentry * dentry, int mode,
		struct nameidata *nd)
{
E
Evgeniy Dushistov 已提交
82 83 84 85 86 87 88
	struct inode *inode;
	int err;

	UFSD("BEGIN\n");
	inode = ufs_new_inode(dir, mode);
	err = PTR_ERR(inode);

L
Linus Torvalds 已提交
89 90 91 92 93 94 95 96 97
	if (!IS_ERR(inode)) {
		inode->i_op = &ufs_file_inode_operations;
		inode->i_fop = &ufs_file_operations;
		inode->i_mapping->a_ops = &ufs_aops;
		mark_inode_dirty(inode);
		lock_kernel();
		err = ufs_add_nondir(dentry, inode);
		unlock_kernel();
	}
E
Evgeniy Dushistov 已提交
98
	UFSD("END: err=%d\n", err);
L
Linus Torvalds 已提交
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
	return err;
}

static int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t rdev)
{
	struct inode *inode;
	int err;

	if (!old_valid_dev(rdev))
		return -EINVAL;
	inode = ufs_new_inode(dir, mode);
	err = PTR_ERR(inode);
	if (!IS_ERR(inode)) {
		init_special_inode(inode, mode, rdev);
		/* NOTE: that'll go when we get wide dev_t */
		ufs_set_inode_dev(inode->i_sb, UFS_I(inode), rdev);
		mark_inode_dirty(inode);
		lock_kernel();
		err = ufs_add_nondir(dentry, inode);
		unlock_kernel();
	}
	return err;
}

static int ufs_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;

	if (l > sb->s_blocksize)
132
		goto out_notlocked;
L
Linus Torvalds 已提交
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157

	lock_kernel();
	inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO);
	err = PTR_ERR(inode);
	if (IS_ERR(inode))
		goto out;

	if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) {
		/* slow symlink */
		inode->i_op = &page_symlink_inode_operations;
		inode->i_mapping->a_ops = &ufs_aops;
		err = page_symlink(inode, symname, l);
		if (err)
			goto out_fail;
	} else {
		/* fast symlink */
		inode->i_op = &ufs_fast_symlink_inode_operations;
		memcpy((char*)&UFS_I(inode)->i_u1.i_data,symname,l);
		inode->i_size = l-1;
	}
	mark_inode_dirty(inode);

	err = ufs_add_nondir(dentry, inode);
out:
	unlock_kernel();
158
out_notlocked:
L
Linus Torvalds 已提交
159 160 161
	return err;

out_fail:
162
	inode_dec_link_count(inode);
L
Linus Torvalds 已提交
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
	iput(inode);
	goto out;
}

static int ufs_link (struct dentry * old_dentry, struct inode * dir,
	struct dentry *dentry)
{
	struct inode *inode = old_dentry->d_inode;
	int error;

	lock_kernel();
	if (inode->i_nlink >= UFS_LINK_MAX) {
		unlock_kernel();
		return -EMLINK;
	}

	inode->i_ctime = CURRENT_TIME_SEC;
180
	inode_inc_link_count(inode);
L
Linus Torvalds 已提交
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
	atomic_inc(&inode->i_count);

	error = ufs_add_nondir(dentry, inode);
	unlock_kernel();
	return error;
}

static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
	struct inode * inode;
	int err = -EMLINK;

	if (dir->i_nlink >= UFS_LINK_MAX)
		goto out;

	lock_kernel();
197
	inode_inc_link_count(dir);
L
Linus Torvalds 已提交
198 199 200 201 202 203 204 205

	inode = ufs_new_inode(dir, S_IFDIR|mode);
	err = PTR_ERR(inode);
	if (IS_ERR(inode))
		goto out_dir;

	inode->i_op = &ufs_dir_inode_operations;
	inode->i_fop = &ufs_dir_operations;
206
	inode->i_mapping->a_ops = &ufs_aops;
L
Linus Torvalds 已提交
207

208
	inode_inc_link_count(inode);
L
Linus Torvalds 已提交
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223

	err = ufs_make_empty(inode, dir);
	if (err)
		goto out_fail;

	err = ufs_add_link(dentry, inode);
	if (err)
		goto out_fail;
	unlock_kernel();

	d_instantiate(dentry, inode);
out:
	return err;

out_fail:
224 225
	inode_dec_link_count(inode);
	inode_dec_link_count(inode);
L
Linus Torvalds 已提交
226 227
	iput (inode);
out_dir:
228
	inode_dec_link_count(dir);
L
Linus Torvalds 已提交
229 230 231 232
	unlock_kernel();
	goto out;
}

233
static int ufs_unlink(struct inode *dir, struct dentry *dentry)
L
Linus Torvalds 已提交
234 235
{
	struct inode * inode = dentry->d_inode;
236 237
	struct ufs_dir_entry *de;
	struct page *page;
L
Linus Torvalds 已提交
238 239
	int err = -ENOENT;

240
	de = ufs_find_entry(dir, dentry, &page);
L
Linus Torvalds 已提交
241 242 243
	if (!de)
		goto out;

244
	err = ufs_delete_entry(dir, de, page);
L
Linus Torvalds 已提交
245 246 247 248
	if (err)
		goto out;

	inode->i_ctime = dir->i_ctime;
249
	inode_dec_link_count(inode);
L
Linus Torvalds 已提交
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
	err = 0;
out:
	return err;
}

static int ufs_rmdir (struct inode * dir, struct dentry *dentry)
{
	struct inode * inode = dentry->d_inode;
	int err= -ENOTEMPTY;

	lock_kernel();
	if (ufs_empty_dir (inode)) {
		err = ufs_unlink(dir, dentry);
		if (!err) {
			inode->i_size = 0;
265 266
			inode_dec_link_count(inode);
			inode_dec_link_count(dir);
L
Linus Torvalds 已提交
267 268 269 270 271 272
		}
	}
	unlock_kernel();
	return err;
}

273 274
static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
		      struct inode *new_dir, struct dentry *new_dentry)
L
Linus Torvalds 已提交
275 276 277
{
	struct inode *old_inode = old_dentry->d_inode;
	struct inode *new_inode = new_dentry->d_inode;
278 279 280
	struct page *dir_page = NULL;
	struct ufs_dir_entry * dir_de = NULL;
	struct page *old_page;
L
Linus Torvalds 已提交
281 282 283
	struct ufs_dir_entry *old_de;
	int err = -ENOENT;

284
	old_de = ufs_find_entry(old_dir, old_dentry, &old_page);
L
Linus Torvalds 已提交
285 286 287 288 289
	if (!old_de)
		goto out;

	if (S_ISDIR(old_inode->i_mode)) {
		err = -EIO;
290
		dir_de = ufs_dotdot(old_inode, &dir_page);
L
Linus Torvalds 已提交
291 292 293 294 295
		if (!dir_de)
			goto out_old;
	}

	if (new_inode) {
296
		struct page *new_page;
L
Linus Torvalds 已提交
297 298 299
		struct ufs_dir_entry *new_de;

		err = -ENOTEMPTY;
300
		if (dir_de && !ufs_empty_dir(new_inode))
L
Linus Torvalds 已提交
301
			goto out_dir;
302

L
Linus Torvalds 已提交
303
		err = -ENOENT;
304
		new_de = ufs_find_entry(new_dir, new_dentry, &new_page);
L
Linus Torvalds 已提交
305 306
		if (!new_de)
			goto out_dir;
307
		inode_inc_link_count(old_inode);
308
		ufs_set_link(new_dir, new_de, new_page, old_inode);
L
Linus Torvalds 已提交
309 310
		new_inode->i_ctime = CURRENT_TIME_SEC;
		if (dir_de)
311
			drop_nlink(new_inode);
312
		inode_dec_link_count(new_inode);
L
Linus Torvalds 已提交
313 314 315 316 317 318
	} else {
		if (dir_de) {
			err = -EMLINK;
			if (new_dir->i_nlink >= UFS_LINK_MAX)
				goto out_dir;
		}
319
		inode_inc_link_count(old_inode);
L
Linus Torvalds 已提交
320 321
		err = ufs_add_link(new_dentry, old_inode);
		if (err) {
322
			inode_dec_link_count(old_inode);
L
Linus Torvalds 已提交
323 324 325
			goto out_dir;
		}
		if (dir_de)
326
			inode_inc_link_count(new_dir);
L
Linus Torvalds 已提交
327 328
	}

329 330 331 332 333 334
	/*
	 * Like most other Unix systems, set the ctime for inodes on a
 	 * rename.
	 * inode_dec_link_count() will mark the inode dirty.
	 */
	old_inode->i_ctime = CURRENT_TIME_SEC;
L
Linus Torvalds 已提交
335

336
	ufs_delete_entry(old_dir, old_de, old_page);
337
	inode_dec_link_count(old_inode);
L
Linus Torvalds 已提交
338 339

	if (dir_de) {
340
		ufs_set_link(old_inode, dir_de, dir_page, new_dir);
341
		inode_dec_link_count(old_dir);
L
Linus Torvalds 已提交
342 343 344
	}
	return 0;

345

L
Linus Torvalds 已提交
346
out_dir:
347 348 349 350
	if (dir_de) {
		kunmap(dir_page);
		page_cache_release(dir_page);
	}
L
Linus Torvalds 已提交
351
out_old:
352 353
	kunmap(old_page);
	page_cache_release(old_page);
L
Linus Torvalds 已提交
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
out:
	return err;
}

struct inode_operations ufs_dir_inode_operations = {
	.create		= ufs_create,
	.lookup		= ufs_lookup,
	.link		= ufs_link,
	.unlink		= ufs_unlink,
	.symlink	= ufs_symlink,
	.mkdir		= ufs_mkdir,
	.rmdir		= ufs_rmdir,
	.mknod		= ufs_mknod,
	.rename		= ufs_rename,
};