xref: /kernel/linux/linux-5.10/fs/ufs/namei.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/fs/ufs/namei.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Migration to usage of "page cache" on May 2006 by
68c2ecf20Sopenharmony_ci * Evgeniy Dushistov <dushistov@mail.ru> based on ext2 code base.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright (C) 1998
98c2ecf20Sopenharmony_ci * Daniel Pirkl <daniel.pirkl@email.cz>
108c2ecf20Sopenharmony_ci * Charles University, Faculty of Mathematics and Physics
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci *  from
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *  linux/fs/ext2/namei.c
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * Copyright (C) 1992, 1993, 1994, 1995
178c2ecf20Sopenharmony_ci * Remy Card (card@masi.ibp.fr)
188c2ecf20Sopenharmony_ci * Laboratoire MASI - Institut Blaise Pascal
198c2ecf20Sopenharmony_ci * Universite Pierre et Marie Curie (Paris VI)
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci *  from
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci *  linux/fs/minix/namei.c
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci *  Copyright (C) 1991, 1992  Linus Torvalds
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci *  Big-endian to little-endian byte-swapping/bitmaps by
288c2ecf20Sopenharmony_ci *        David S. Miller (davem@caip.rutgers.edu), 1995
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include <linux/time.h>
328c2ecf20Sopenharmony_ci#include <linux/fs.h>
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include "ufs_fs.h"
358c2ecf20Sopenharmony_ci#include "ufs.h"
368c2ecf20Sopenharmony_ci#include "util.h"
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	int err = ufs_add_link(dentry, inode);
418c2ecf20Sopenharmony_ci	if (!err) {
428c2ecf20Sopenharmony_ci		d_instantiate_new(dentry, inode);
438c2ecf20Sopenharmony_ci		return 0;
448c2ecf20Sopenharmony_ci	}
458c2ecf20Sopenharmony_ci	inode_dec_link_count(inode);
468c2ecf20Sopenharmony_ci	discard_new_inode(inode);
478c2ecf20Sopenharmony_ci	return err;
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	struct inode * inode = NULL;
538c2ecf20Sopenharmony_ci	ino_t ino;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (dentry->d_name.len > UFS_MAXNAMLEN)
568c2ecf20Sopenharmony_ci		return ERR_PTR(-ENAMETOOLONG);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	ino = ufs_inode_by_name(dir, &dentry->d_name);
598c2ecf20Sopenharmony_ci	if (ino)
608c2ecf20Sopenharmony_ci		inode = ufs_iget(dir->i_sb, ino);
618c2ecf20Sopenharmony_ci	return d_splice_alias(inode, dentry);
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci/*
658c2ecf20Sopenharmony_ci * By the time this is called, we already have created
668c2ecf20Sopenharmony_ci * the directory cache entry for the new file, but it
678c2ecf20Sopenharmony_ci * is so far negative - it has no inode.
688c2ecf20Sopenharmony_ci *
698c2ecf20Sopenharmony_ci * If the create succeeds, we fill in the inode information
708c2ecf20Sopenharmony_ci * with d_instantiate().
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_cistatic int ufs_create (struct inode * dir, struct dentry * dentry, umode_t mode,
738c2ecf20Sopenharmony_ci		bool excl)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	struct inode *inode;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	inode = ufs_new_inode(dir, mode);
788c2ecf20Sopenharmony_ci	if (IS_ERR(inode))
798c2ecf20Sopenharmony_ci		return PTR_ERR(inode);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	inode->i_op = &ufs_file_inode_operations;
828c2ecf20Sopenharmony_ci	inode->i_fop = &ufs_file_operations;
838c2ecf20Sopenharmony_ci	inode->i_mapping->a_ops = &ufs_aops;
848c2ecf20Sopenharmony_ci	mark_inode_dirty(inode);
858c2ecf20Sopenharmony_ci	return ufs_add_nondir(dentry, inode);
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic int ufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	struct inode *inode;
918c2ecf20Sopenharmony_ci	int err;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	if (!old_valid_dev(rdev))
948c2ecf20Sopenharmony_ci		return -EINVAL;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	inode = ufs_new_inode(dir, mode);
978c2ecf20Sopenharmony_ci	err = PTR_ERR(inode);
988c2ecf20Sopenharmony_ci	if (!IS_ERR(inode)) {
998c2ecf20Sopenharmony_ci		init_special_inode(inode, mode, rdev);
1008c2ecf20Sopenharmony_ci		ufs_set_inode_dev(inode->i_sb, UFS_I(inode), rdev);
1018c2ecf20Sopenharmony_ci		mark_inode_dirty(inode);
1028c2ecf20Sopenharmony_ci		err = ufs_add_nondir(dentry, inode);
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci	return err;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic int ufs_symlink (struct inode * dir, struct dentry * dentry,
1088c2ecf20Sopenharmony_ci	const char * symname)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct super_block * sb = dir->i_sb;
1118c2ecf20Sopenharmony_ci	int err;
1128c2ecf20Sopenharmony_ci	unsigned l = strlen(symname)+1;
1138c2ecf20Sopenharmony_ci	struct inode * inode;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (l > sb->s_blocksize)
1168c2ecf20Sopenharmony_ci		return -ENAMETOOLONG;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO);
1198c2ecf20Sopenharmony_ci	err = PTR_ERR(inode);
1208c2ecf20Sopenharmony_ci	if (IS_ERR(inode))
1218c2ecf20Sopenharmony_ci		return err;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) {
1248c2ecf20Sopenharmony_ci		/* slow symlink */
1258c2ecf20Sopenharmony_ci		inode->i_op = &page_symlink_inode_operations;
1268c2ecf20Sopenharmony_ci		inode_nohighmem(inode);
1278c2ecf20Sopenharmony_ci		inode->i_mapping->a_ops = &ufs_aops;
1288c2ecf20Sopenharmony_ci		err = page_symlink(inode, symname, l);
1298c2ecf20Sopenharmony_ci		if (err)
1308c2ecf20Sopenharmony_ci			goto out_fail;
1318c2ecf20Sopenharmony_ci	} else {
1328c2ecf20Sopenharmony_ci		/* fast symlink */
1338c2ecf20Sopenharmony_ci		inode->i_op = &simple_symlink_inode_operations;
1348c2ecf20Sopenharmony_ci		inode->i_link = (char *)UFS_I(inode)->i_u1.i_symlink;
1358c2ecf20Sopenharmony_ci		memcpy(inode->i_link, symname, l);
1368c2ecf20Sopenharmony_ci		inode->i_size = l-1;
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci	mark_inode_dirty(inode);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return ufs_add_nondir(dentry, inode);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ciout_fail:
1438c2ecf20Sopenharmony_ci	inode_dec_link_count(inode);
1448c2ecf20Sopenharmony_ci	discard_new_inode(inode);
1458c2ecf20Sopenharmony_ci	return err;
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic int ufs_link (struct dentry * old_dentry, struct inode * dir,
1498c2ecf20Sopenharmony_ci	struct dentry *dentry)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(old_dentry);
1528c2ecf20Sopenharmony_ci	int error;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	inode->i_ctime = current_time(inode);
1558c2ecf20Sopenharmony_ci	inode_inc_link_count(inode);
1568c2ecf20Sopenharmony_ci	ihold(inode);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	error = ufs_add_link(dentry, inode);
1598c2ecf20Sopenharmony_ci	if (error) {
1608c2ecf20Sopenharmony_ci		inode_dec_link_count(inode);
1618c2ecf20Sopenharmony_ci		iput(inode);
1628c2ecf20Sopenharmony_ci	} else
1638c2ecf20Sopenharmony_ci		d_instantiate(dentry, inode);
1648c2ecf20Sopenharmony_ci	return error;
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	struct inode * inode;
1708c2ecf20Sopenharmony_ci	int err;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	inode_inc_link_count(dir);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	inode = ufs_new_inode(dir, S_IFDIR|mode);
1758c2ecf20Sopenharmony_ci	err = PTR_ERR(inode);
1768c2ecf20Sopenharmony_ci	if (IS_ERR(inode))
1778c2ecf20Sopenharmony_ci		goto out_dir;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	inode->i_op = &ufs_dir_inode_operations;
1808c2ecf20Sopenharmony_ci	inode->i_fop = &ufs_dir_operations;
1818c2ecf20Sopenharmony_ci	inode->i_mapping->a_ops = &ufs_aops;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	inode_inc_link_count(inode);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	err = ufs_make_empty(inode, dir);
1868c2ecf20Sopenharmony_ci	if (err)
1878c2ecf20Sopenharmony_ci		goto out_fail;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	err = ufs_add_link(dentry, inode);
1908c2ecf20Sopenharmony_ci	if (err)
1918c2ecf20Sopenharmony_ci		goto out_fail;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	d_instantiate_new(dentry, inode);
1948c2ecf20Sopenharmony_ci	return 0;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ciout_fail:
1978c2ecf20Sopenharmony_ci	inode_dec_link_count(inode);
1988c2ecf20Sopenharmony_ci	inode_dec_link_count(inode);
1998c2ecf20Sopenharmony_ci	discard_new_inode(inode);
2008c2ecf20Sopenharmony_ciout_dir:
2018c2ecf20Sopenharmony_ci	inode_dec_link_count(dir);
2028c2ecf20Sopenharmony_ci	return err;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic int ufs_unlink(struct inode *dir, struct dentry *dentry)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	struct inode * inode = d_inode(dentry);
2088c2ecf20Sopenharmony_ci	struct ufs_dir_entry *de;
2098c2ecf20Sopenharmony_ci	struct page *page;
2108c2ecf20Sopenharmony_ci	int err = -ENOENT;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	de = ufs_find_entry(dir, &dentry->d_name, &page);
2138c2ecf20Sopenharmony_ci	if (!de)
2148c2ecf20Sopenharmony_ci		goto out;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	err = ufs_delete_entry(dir, de, page);
2178c2ecf20Sopenharmony_ci	if (err)
2188c2ecf20Sopenharmony_ci		goto out;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	inode->i_ctime = dir->i_ctime;
2218c2ecf20Sopenharmony_ci	inode_dec_link_count(inode);
2228c2ecf20Sopenharmony_ci	err = 0;
2238c2ecf20Sopenharmony_ciout:
2248c2ecf20Sopenharmony_ci	return err;
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic int ufs_rmdir (struct inode * dir, struct dentry *dentry)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	struct inode * inode = d_inode(dentry);
2308c2ecf20Sopenharmony_ci	int err= -ENOTEMPTY;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	if (ufs_empty_dir (inode)) {
2338c2ecf20Sopenharmony_ci		err = ufs_unlink(dir, dentry);
2348c2ecf20Sopenharmony_ci		if (!err) {
2358c2ecf20Sopenharmony_ci			inode->i_size = 0;
2368c2ecf20Sopenharmony_ci			inode_dec_link_count(inode);
2378c2ecf20Sopenharmony_ci			inode_dec_link_count(dir);
2388c2ecf20Sopenharmony_ci		}
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci	return err;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
2448c2ecf20Sopenharmony_ci		      struct inode *new_dir, struct dentry *new_dentry,
2458c2ecf20Sopenharmony_ci		      unsigned int flags)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	struct inode *old_inode = d_inode(old_dentry);
2488c2ecf20Sopenharmony_ci	struct inode *new_inode = d_inode(new_dentry);
2498c2ecf20Sopenharmony_ci	struct page *dir_page = NULL;
2508c2ecf20Sopenharmony_ci	struct ufs_dir_entry * dir_de = NULL;
2518c2ecf20Sopenharmony_ci	struct page *old_page;
2528c2ecf20Sopenharmony_ci	struct ufs_dir_entry *old_de;
2538c2ecf20Sopenharmony_ci	int err = -ENOENT;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	if (flags & ~RENAME_NOREPLACE)
2568c2ecf20Sopenharmony_ci		return -EINVAL;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	old_de = ufs_find_entry(old_dir, &old_dentry->d_name, &old_page);
2598c2ecf20Sopenharmony_ci	if (!old_de)
2608c2ecf20Sopenharmony_ci		goto out;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	if (S_ISDIR(old_inode->i_mode)) {
2638c2ecf20Sopenharmony_ci		err = -EIO;
2648c2ecf20Sopenharmony_ci		dir_de = ufs_dotdot(old_inode, &dir_page);
2658c2ecf20Sopenharmony_ci		if (!dir_de)
2668c2ecf20Sopenharmony_ci			goto out_old;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	if (new_inode) {
2708c2ecf20Sopenharmony_ci		struct page *new_page;
2718c2ecf20Sopenharmony_ci		struct ufs_dir_entry *new_de;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci		err = -ENOTEMPTY;
2748c2ecf20Sopenharmony_ci		if (dir_de && !ufs_empty_dir(new_inode))
2758c2ecf20Sopenharmony_ci			goto out_dir;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci		err = -ENOENT;
2788c2ecf20Sopenharmony_ci		new_de = ufs_find_entry(new_dir, &new_dentry->d_name, &new_page);
2798c2ecf20Sopenharmony_ci		if (!new_de)
2808c2ecf20Sopenharmony_ci			goto out_dir;
2818c2ecf20Sopenharmony_ci		ufs_set_link(new_dir, new_de, new_page, old_inode, 1);
2828c2ecf20Sopenharmony_ci		new_inode->i_ctime = current_time(new_inode);
2838c2ecf20Sopenharmony_ci		if (dir_de)
2848c2ecf20Sopenharmony_ci			drop_nlink(new_inode);
2858c2ecf20Sopenharmony_ci		inode_dec_link_count(new_inode);
2868c2ecf20Sopenharmony_ci	} else {
2878c2ecf20Sopenharmony_ci		err = ufs_add_link(new_dentry, old_inode);
2888c2ecf20Sopenharmony_ci		if (err)
2898c2ecf20Sopenharmony_ci			goto out_dir;
2908c2ecf20Sopenharmony_ci		if (dir_de)
2918c2ecf20Sopenharmony_ci			inode_inc_link_count(new_dir);
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	/*
2958c2ecf20Sopenharmony_ci	 * Like most other Unix systems, set the ctime for inodes on a
2968c2ecf20Sopenharmony_ci 	 * rename.
2978c2ecf20Sopenharmony_ci	 */
2988c2ecf20Sopenharmony_ci	old_inode->i_ctime = current_time(old_inode);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	ufs_delete_entry(old_dir, old_de, old_page);
3018c2ecf20Sopenharmony_ci	mark_inode_dirty(old_inode);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	if (dir_de) {
3048c2ecf20Sopenharmony_ci		if (old_dir != new_dir)
3058c2ecf20Sopenharmony_ci			ufs_set_link(old_inode, dir_de, dir_page, new_dir, 0);
3068c2ecf20Sopenharmony_ci		else {
3078c2ecf20Sopenharmony_ci			kunmap(dir_page);
3088c2ecf20Sopenharmony_ci			put_page(dir_page);
3098c2ecf20Sopenharmony_ci		}
3108c2ecf20Sopenharmony_ci		inode_dec_link_count(old_dir);
3118c2ecf20Sopenharmony_ci	}
3128c2ecf20Sopenharmony_ci	return 0;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ciout_dir:
3168c2ecf20Sopenharmony_ci	if (dir_de) {
3178c2ecf20Sopenharmony_ci		kunmap(dir_page);
3188c2ecf20Sopenharmony_ci		put_page(dir_page);
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ciout_old:
3218c2ecf20Sopenharmony_ci	kunmap(old_page);
3228c2ecf20Sopenharmony_ci	put_page(old_page);
3238c2ecf20Sopenharmony_ciout:
3248c2ecf20Sopenharmony_ci	return err;
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ciconst struct inode_operations ufs_dir_inode_operations = {
3288c2ecf20Sopenharmony_ci	.create		= ufs_create,
3298c2ecf20Sopenharmony_ci	.lookup		= ufs_lookup,
3308c2ecf20Sopenharmony_ci	.link		= ufs_link,
3318c2ecf20Sopenharmony_ci	.unlink		= ufs_unlink,
3328c2ecf20Sopenharmony_ci	.symlink	= ufs_symlink,
3338c2ecf20Sopenharmony_ci	.mkdir		= ufs_mkdir,
3348c2ecf20Sopenharmony_ci	.rmdir		= ufs_rmdir,
3358c2ecf20Sopenharmony_ci	.mknod		= ufs_mknod,
3368c2ecf20Sopenharmony_ci	.rename		= ufs_rename,
3378c2ecf20Sopenharmony_ci};
338