linux/fs/minix/namei.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *  linux/fs/minix/namei.c
   4 *
   5 *  Copyright (C) 1991, 1992  Linus Torvalds
   6 */
   7
   8#include "minix.h"
   9
  10static int add_nondir(struct dentry *dentry, struct inode *inode)
  11{
  12        int err = minix_add_link(dentry, inode);
  13        if (!err) {
  14                d_instantiate(dentry, inode);
  15                return 0;
  16        }
  17        inode_dec_link_count(inode);
  18        iput(inode);
  19        return err;
  20}
  21
  22static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags)
  23{
  24        struct inode * inode = NULL;
  25        ino_t ino;
  26
  27        if (dentry->d_name.len > minix_sb(dir->i_sb)->s_namelen)
  28                return ERR_PTR(-ENAMETOOLONG);
  29
  30        ino = minix_inode_by_name(dentry);
  31        if (ino)
  32                inode = minix_iget(dir->i_sb, ino);
  33        return d_splice_alias(inode, dentry);
  34}
  35
  36static int minix_mknod(struct user_namespace *mnt_userns, struct inode *dir,
  37                       struct dentry *dentry, umode_t mode, dev_t rdev)
  38{
  39        int error;
  40        struct inode *inode;
  41
  42        if (!old_valid_dev(rdev))
  43                return -EINVAL;
  44
  45        inode = minix_new_inode(dir, mode, &error);
  46
  47        if (inode) {
  48                minix_set_inode(inode, rdev);
  49                mark_inode_dirty(inode);
  50                error = add_nondir(dentry, inode);
  51        }
  52        return error;
  53}
  54
  55static int minix_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
  56                         struct dentry *dentry, umode_t mode)
  57{
  58        int error;
  59        struct inode *inode = minix_new_inode(dir, mode, &error);
  60        if (inode) {
  61                minix_set_inode(inode, 0);
  62                mark_inode_dirty(inode);
  63                d_tmpfile(dentry, inode);
  64        }
  65        return error;
  66}
  67
  68static int minix_create(struct user_namespace *mnt_userns, struct inode *dir,
  69                        struct dentry *dentry, umode_t mode, bool excl)
  70{
  71        return minix_mknod(mnt_userns, dir, dentry, mode, 0);
  72}
  73
  74static int minix_symlink(struct user_namespace *mnt_userns, struct inode *dir,
  75                         struct dentry *dentry, const char *symname)
  76{
  77        int err = -ENAMETOOLONG;
  78        int i = strlen(symname)+1;
  79        struct inode * inode;
  80
  81        if (i > dir->i_sb->s_blocksize)
  82                goto out;
  83
  84        inode = minix_new_inode(dir, S_IFLNK | 0777, &err);
  85        if (!inode)
  86                goto out;
  87
  88        minix_set_inode(inode, 0);
  89        err = page_symlink(inode, symname, i);
  90        if (err)
  91                goto out_fail;
  92
  93        err = add_nondir(dentry, inode);
  94out:
  95        return err;
  96
  97out_fail:
  98        inode_dec_link_count(inode);
  99        iput(inode);
 100        goto out;
 101}
 102
 103static int minix_link(struct dentry * old_dentry, struct inode * dir,
 104        struct dentry *dentry)
 105{
 106        struct inode *inode = d_inode(old_dentry);
 107
 108        inode->i_ctime = current_time(inode);
 109        inode_inc_link_count(inode);
 110        ihold(inode);
 111        return add_nondir(dentry, inode);
 112}
 113
 114static int minix_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
 115                       struct dentry *dentry, umode_t mode)
 116{
 117        struct inode * inode;
 118        int err;
 119
 120        inode_inc_link_count(dir);
 121
 122        inode = minix_new_inode(dir, S_IFDIR | mode, &err);
 123        if (!inode)
 124                goto out_dir;
 125
 126        minix_set_inode(inode, 0);
 127
 128        inode_inc_link_count(inode);
 129
 130        err = minix_make_empty(inode, dir);
 131        if (err)
 132                goto out_fail;
 133
 134        err = minix_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 minix_unlink(struct inode * dir, struct dentry *dentry)
 152{
 153        int err = -ENOENT;
 154        struct inode * inode = d_inode(dentry);
 155        struct page * page;
 156        struct minix_dir_entry * de;
 157
 158        de = minix_find_entry(dentry, &page);
 159        if (!de)
 160                goto end_unlink;
 161
 162        err = minix_delete_entry(de, page);
 163        if (err)
 164                goto end_unlink;
 165
 166        inode->i_ctime = dir->i_ctime;
 167        inode_dec_link_count(inode);
 168end_unlink:
 169        return err;
 170}
 171
 172static int minix_rmdir(struct inode * dir, struct dentry *dentry)
 173{
 174        struct inode * inode = d_inode(dentry);
 175        int err = -ENOTEMPTY;
 176
 177        if (minix_empty_dir(inode)) {
 178                err = minix_unlink(dir, dentry);
 179                if (!err) {
 180                        inode_dec_link_count(dir);
 181                        inode_dec_link_count(inode);
 182                }
 183        }
 184        return err;
 185}
 186
 187static int minix_rename(struct user_namespace *mnt_userns,
 188                        struct inode *old_dir, struct dentry *old_dentry,
 189                        struct inode *new_dir, struct dentry *new_dentry,
 190                        unsigned int flags)
 191{
 192        struct inode * old_inode = d_inode(old_dentry);
 193        struct inode * new_inode = d_inode(new_dentry);
 194        struct page * dir_page = NULL;
 195        struct minix_dir_entry * dir_de = NULL;
 196        struct page * old_page;
 197        struct minix_dir_entry * old_de;
 198        int err = -ENOENT;
 199
 200        if (flags & ~RENAME_NOREPLACE)
 201                return -EINVAL;
 202
 203        old_de = minix_find_entry(old_dentry, &old_page);
 204        if (!old_de)
 205                goto out;
 206
 207        if (S_ISDIR(old_inode->i_mode)) {
 208                err = -EIO;
 209                dir_de = minix_dotdot(old_inode, &dir_page);
 210                if (!dir_de)
 211                        goto out_old;
 212        }
 213
 214        if (new_inode) {
 215                struct page * new_page;
 216                struct minix_dir_entry * new_de;
 217
 218                err = -ENOTEMPTY;
 219                if (dir_de && !minix_empty_dir(new_inode))
 220                        goto out_dir;
 221
 222                err = -ENOENT;
 223                new_de = minix_find_entry(new_dentry, &new_page);
 224                if (!new_de)
 225                        goto out_dir;
 226                minix_set_link(new_de, new_page, old_inode);
 227                new_inode->i_ctime = current_time(new_inode);
 228                if (dir_de)
 229                        drop_nlink(new_inode);
 230                inode_dec_link_count(new_inode);
 231        } else {
 232                err = minix_add_link(new_dentry, old_inode);
 233                if (err)
 234                        goto out_dir;
 235                if (dir_de)
 236                        inode_inc_link_count(new_dir);
 237        }
 238
 239        minix_delete_entry(old_de, old_page);
 240        mark_inode_dirty(old_inode);
 241
 242        if (dir_de) {
 243                minix_set_link(dir_de, dir_page, new_dir);
 244                inode_dec_link_count(old_dir);
 245        }
 246        return 0;
 247
 248out_dir:
 249        if (dir_de) {
 250                kunmap(dir_page);
 251                put_page(dir_page);
 252        }
 253out_old:
 254        kunmap(old_page);
 255        put_page(old_page);
 256out:
 257        return err;
 258}
 259
 260/*
 261 * directories can handle most operations...
 262 */
 263const struct inode_operations minix_dir_inode_operations = {
 264        .create         = minix_create,
 265        .lookup         = minix_lookup,
 266        .link           = minix_link,
 267        .unlink         = minix_unlink,
 268        .symlink        = minix_symlink,
 269        .mkdir          = minix_mkdir,
 270        .rmdir          = minix_rmdir,
 271        .mknod          = minix_mknod,
 272        .rename         = minix_rename,
 273        .getattr        = minix_getattr,
 274        .tmpfile        = minix_tmpfile,
 275};
 276