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