root/fs/sysv/namei.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. add_nondir
  2. sysv_lookup
  3. sysv_mknod
  4. sysv_create
  5. sysv_symlink
  6. sysv_link
  7. sysv_mkdir
  8. sysv_unlink
  9. sysv_rmdir
  10. sysv_rename

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  *  linux/fs/sysv/namei.c
   4  *
   5  *  minix/namei.c
   6  *  Copyright (C) 1991, 1992  Linus Torvalds
   7  *
   8  *  coh/namei.c
   9  *  Copyright (C) 1993  Pascal Haible, Bruno Haible
  10  *
  11  *  sysv/namei.c
  12  *  Copyright (C) 1993  Bruno Haible
  13  *  Copyright (C) 1997, 1998  Krzysztof G. Baranowski
  14  */
  15 
  16 #include <linux/pagemap.h>
  17 #include "sysv.h"
  18 
  19 static int add_nondir(struct dentry *dentry, struct inode *inode)
  20 {
  21         int err = sysv_add_link(dentry, inode);
  22         if (!err) {
  23                 d_instantiate(dentry, inode);
  24                 return 0;
  25         }
  26         inode_dec_link_count(inode);
  27         iput(inode);
  28         return err;
  29 }
  30 
  31 static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, unsigned int flags)
  32 {
  33         struct inode * inode = NULL;
  34         ino_t ino;
  35 
  36         if (dentry->d_name.len > SYSV_NAMELEN)
  37                 return ERR_PTR(-ENAMETOOLONG);
  38         ino = sysv_inode_by_name(dentry);
  39         if (ino)
  40                 inode = sysv_iget(dir->i_sb, ino);
  41         return d_splice_alias(inode, dentry);
  42 }
  43 
  44 static int sysv_mknod(struct inode * dir, struct dentry * dentry, umode_t mode, dev_t rdev)
  45 {
  46         struct inode * inode;
  47         int err;
  48 
  49         if (!old_valid_dev(rdev))
  50                 return -EINVAL;
  51 
  52         inode = sysv_new_inode(dir, mode);
  53         err = PTR_ERR(inode);
  54 
  55         if (!IS_ERR(inode)) {
  56                 sysv_set_inode(inode, rdev);
  57                 mark_inode_dirty(inode);
  58                 err = add_nondir(dentry, inode);
  59         }
  60         return err;
  61 }
  62 
  63 static int sysv_create(struct inode * dir, struct dentry * dentry, umode_t mode, bool excl)
  64 {
  65         return sysv_mknod(dir, dentry, mode, 0);
  66 }
  67 
  68 static int sysv_symlink(struct inode * dir, struct dentry * dentry, 
  69         const char * symname)
  70 {
  71         int err = -ENAMETOOLONG;
  72         int l = strlen(symname)+1;
  73         struct inode * inode;
  74 
  75         if (l > dir->i_sb->s_blocksize)
  76                 goto out;
  77 
  78         inode = sysv_new_inode(dir, S_IFLNK|0777);
  79         err = PTR_ERR(inode);
  80         if (IS_ERR(inode))
  81                 goto out;
  82         
  83         sysv_set_inode(inode, 0);
  84         err = page_symlink(inode, symname, l);
  85         if (err)
  86                 goto out_fail;
  87 
  88         mark_inode_dirty(inode);
  89         err = add_nondir(dentry, inode);
  90 out:
  91         return err;
  92 
  93 out_fail:
  94         inode_dec_link_count(inode);
  95         iput(inode);
  96         goto out;
  97 }
  98 
  99 static int sysv_link(struct dentry * old_dentry, struct inode * dir, 
 100         struct dentry * dentry)
 101 {
 102         struct inode *inode = d_inode(old_dentry);
 103 
 104         inode->i_ctime = current_time(inode);
 105         inode_inc_link_count(inode);
 106         ihold(inode);
 107 
 108         return add_nondir(dentry, inode);
 109 }
 110 
 111 static int sysv_mkdir(struct inode * dir, struct dentry *dentry, umode_t mode)
 112 {
 113         struct inode * inode;
 114         int err;
 115 
 116         inode_inc_link_count(dir);
 117 
 118         inode = sysv_new_inode(dir, S_IFDIR|mode);
 119         err = PTR_ERR(inode);
 120         if (IS_ERR(inode))
 121                 goto out_dir;
 122 
 123         sysv_set_inode(inode, 0);
 124 
 125         inode_inc_link_count(inode);
 126 
 127         err = sysv_make_empty(inode, dir);
 128         if (err)
 129                 goto out_fail;
 130 
 131         err = sysv_add_link(dentry, inode);
 132         if (err)
 133                 goto out_fail;
 134 
 135         d_instantiate(dentry, inode);
 136 out:
 137         return err;
 138 
 139 out_fail:
 140         inode_dec_link_count(inode);
 141         inode_dec_link_count(inode);
 142         iput(inode);
 143 out_dir:
 144         inode_dec_link_count(dir);
 145         goto out;
 146 }
 147 
 148 static int sysv_unlink(struct inode * dir, struct dentry * dentry)
 149 {
 150         struct inode * inode = d_inode(dentry);
 151         struct page * page;
 152         struct sysv_dir_entry * de;
 153         int err = -ENOENT;
 154 
 155         de = sysv_find_entry(dentry, &page);
 156         if (!de)
 157                 goto out;
 158 
 159         err = sysv_delete_entry (de, page);
 160         if (err)
 161                 goto out;
 162 
 163         inode->i_ctime = dir->i_ctime;
 164         inode_dec_link_count(inode);
 165 out:
 166         return err;
 167 }
 168 
 169 static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
 170 {
 171         struct inode *inode = d_inode(dentry);
 172         int err = -ENOTEMPTY;
 173 
 174         if (sysv_empty_dir(inode)) {
 175                 err = sysv_unlink(dir, dentry);
 176                 if (!err) {
 177                         inode->i_size = 0;
 178                         inode_dec_link_count(inode);
 179                         inode_dec_link_count(dir);
 180                 }
 181         }
 182         return err;
 183 }
 184 
 185 /*
 186  * Anybody can rename anything with this: the permission checks are left to the
 187  * higher-level routines.
 188  */
 189 static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
 190                        struct inode * new_dir, struct dentry * new_dentry,
 191                        unsigned int flags)
 192 {
 193         struct inode * old_inode = d_inode(old_dentry);
 194         struct inode * new_inode = d_inode(new_dentry);
 195         struct page * dir_page = NULL;
 196         struct sysv_dir_entry * dir_de = NULL;
 197         struct page * old_page;
 198         struct sysv_dir_entry * old_de;
 199         int err = -ENOENT;
 200 
 201         if (flags & ~RENAME_NOREPLACE)
 202                 return -EINVAL;
 203 
 204         old_de = sysv_find_entry(old_dentry, &old_page);
 205         if (!old_de)
 206                 goto out;
 207 
 208         if (S_ISDIR(old_inode->i_mode)) {
 209                 err = -EIO;
 210                 dir_de = sysv_dotdot(old_inode, &dir_page);
 211                 if (!dir_de)
 212                         goto out_old;
 213         }
 214 
 215         if (new_inode) {
 216                 struct page * new_page;
 217                 struct sysv_dir_entry * new_de;
 218 
 219                 err = -ENOTEMPTY;
 220                 if (dir_de && !sysv_empty_dir(new_inode))
 221                         goto out_dir;
 222 
 223                 err = -ENOENT;
 224                 new_de = sysv_find_entry(new_dentry, &new_page);
 225                 if (!new_de)
 226                         goto out_dir;
 227                 sysv_set_link(new_de, new_page, old_inode);
 228                 new_inode->i_ctime = current_time(new_inode);
 229                 if (dir_de)
 230                         drop_nlink(new_inode);
 231                 inode_dec_link_count(new_inode);
 232         } else {
 233                 err = sysv_add_link(new_dentry, old_inode);
 234                 if (err)
 235                         goto out_dir;
 236                 if (dir_de)
 237                         inode_inc_link_count(new_dir);
 238         }
 239 
 240         sysv_delete_entry(old_de, old_page);
 241         mark_inode_dirty(old_inode);
 242 
 243         if (dir_de) {
 244                 sysv_set_link(dir_de, dir_page, new_dir);
 245                 inode_dec_link_count(old_dir);
 246         }
 247         return 0;
 248 
 249 out_dir:
 250         if (dir_de) {
 251                 kunmap(dir_page);
 252                 put_page(dir_page);
 253         }
 254 out_old:
 255         kunmap(old_page);
 256         put_page(old_page);
 257 out:
 258         return err;
 259 }
 260 
 261 /*
 262  * directories can handle most operations...
 263  */
 264 const struct inode_operations sysv_dir_inode_operations = {
 265         .create         = sysv_create,
 266         .lookup         = sysv_lookup,
 267         .link           = sysv_link,
 268         .unlink         = sysv_unlink,
 269         .symlink        = sysv_symlink,
 270         .mkdir          = sysv_mkdir,
 271         .rmdir          = sysv_rmdir,
 272         .mknod          = sysv_mknod,
 273         .rename         = sysv_rename,
 274         .getattr        = sysv_getattr,
 275 };

/* [<][>][^][v][top][bottom][index][help] */