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