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 inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev)
  37{
  38        int error;
  39        struct inode *inode;
  40
  41        if (!old_valid_dev(rdev))
  42                return -EINVAL;
  43
  44        inode = minix_new_inode(dir, mode, &error);
  45
  46        if (inode) {
  47                minix_set_inode(inode, rdev);
  48                mark_inode_dirty(inode);
  49                error = add_nondir(dentry, inode);
  50        }
  51        return error;
  52}
  53
  54static int minix_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
  55{
  56        int error;
  57        struct inode *inode = minix_new_inode(dir, mode, &error);
  58        if (inode) {
  59                minix_set_inode(inode, 0);
  60                mark_inode_dirty(inode);
  61                d_tmpfile(dentry, inode);
  62        }
  63        return error;
  64}
  65
  66static int minix_create(struct inode *dir, struct dentry *dentry, umode_t mode,
  67                bool excl)
  68{
  69        return minix_mknod(dir, dentry, mode, 0);
  70}
  71
  72static int minix_symlink(struct inode * dir, struct dentry *dentry,
  73          const char * symname)
  74{
  75        int err = -ENAMETOOLONG;
  76        int i = strlen(symname)+1;
  77        struct inode * inode;
  78
  79        if (i > dir->i_sb->s_blocksize)
  80                goto out;
  81
  82        inode = minix_new_inode(dir, S_IFLNK | 0777, &err);
  83        if (!inode)
  84                goto out;
  85
  86        minix_set_inode(inode, 0);
  87        err = page_symlink(inode, symname, i);
  88        if (err)
  89                goto out_fail;
  90
  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 minix_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        return add_nondir(dentry, inode);
 110}
 111
 112static int minix_mkdir(struct inode * dir, struct dentry *dentry, umode_t mode)
 113{
 114        struct inode * inode;
 115        int err;
 116
 117        inode_inc_link_count(dir);
 118
 119        inode = minix_new_inode(dir, S_IFDIR | mode, &err);
 120        if (!inode)
 121                goto out_dir;
 122
 123        minix_set_inode(inode, 0);
 124
 125        inode_inc_link_count(inode);
 126
 127        err = minix_make_empty(inode, dir);
 128        if (err)
 129                goto out_fail;
 130
 131        err = minix_add_link(dentry, inode);
 132        if (err)
 133                goto out_fail;
 134
 135        d_instantiate(dentry, inode);
 136out:
 137        return err;
 138
 139out_fail:
 140        inode_dec_link_count(inode);
 141        inode_dec_link_count(inode);
 142        iput(inode);
 143out_dir:
 144        inode_dec_link_count(dir);
 145        goto out;
 146}
 147
 148static int minix_unlink(struct inode * dir, struct dentry *dentry)
 149{
 150        int err = -ENOENT;
 151        struct inode * inode = d_inode(dentry);
 152        struct page * page;
 153        struct minix_dir_entry * de;
 154
 155        de = minix_find_entry(dentry, &page);
 156        if (!de)
 157                goto end_unlink;
 158
 159        err = minix_delete_entry(de, page);
 160        if (err)
 161                goto end_unlink;
 162
 163        inode->i_ctime = dir->i_ctime;
 164        inode_dec_link_count(inode);
 165end_unlink:
 166        return err;
 167}
 168
 169static int minix_rmdir(struct inode * dir, struct dentry *dentry)
 170{
 171        struct inode * inode = d_inode(dentry);
 172        int err = -ENOTEMPTY;
 173
 174        if (minix_empty_dir(inode)) {
 175                err = minix_unlink(dir, dentry);
 176                if (!err) {
 177                        inode_dec_link_count(dir);
 178                        inode_dec_link_count(inode);
 179                }
 180        }
 181        return err;
 182}
 183
 184static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
 185                        struct inode * new_dir, struct dentry *new_dentry,
 186                        unsigned int flags)
 187{
 188        struct inode * old_inode = d_inode(old_dentry);
 189        struct inode * new_inode = d_inode(new_dentry);
 190        struct page * dir_page = NULL;
 191        struct minix_dir_entry * dir_de = NULL;
 192        struct page * old_page;
 193        struct minix_dir_entry * old_de;
 194        int err = -ENOENT;
 195
 196        if (flags & ~RENAME_NOREPLACE)
 197                return -EINVAL;
 198
 199        old_de = minix_find_entry(old_dentry, &old_page);
 200        if (!old_de)
 201                goto out;
 202
 203        if (S_ISDIR(old_inode->i_mode)) {
 204                err = -EIO;
 205                dir_de = minix_dotdot(old_inode, &dir_page);
 206                if (!dir_de)
 207                        goto out_old;
 208        }
 209
 210        if (new_inode) {
 211                struct page * new_page;
 212                struct minix_dir_entry * new_de;
 213
 214                err = -ENOTEMPTY;
 215                if (dir_de && !minix_empty_dir(new_inode))
 216                        goto out_dir;
 217
 218                err = -ENOENT;
 219                new_de = minix_find_entry(new_dentry, &new_page);
 220                if (!new_de)
 221                        goto out_dir;
 222                minix_set_link(new_de, new_page, old_inode);
 223                new_inode->i_ctime = current_time(new_inode);
 224                if (dir_de)
 225                        drop_nlink(new_inode);
 226                inode_dec_link_count(new_inode);
 227        } else {
 228                err = minix_add_link(new_dentry, old_inode);
 229                if (err)
 230                        goto out_dir;
 231                if (dir_de)
 232                        inode_inc_link_count(new_dir);
 233        }
 234
 235        minix_delete_entry(old_de, old_page);
 236        mark_inode_dirty(old_inode);
 237
 238        if (dir_de) {
 239                minix_set_link(dir_de, dir_page, new_dir);
 240                inode_dec_link_count(old_dir);
 241        }
 242        return 0;
 243
 244out_dir:
 245        if (dir_de) {
 246                kunmap(dir_page);
 247                put_page(dir_page);
 248        }
 249out_old:
 250        kunmap(old_page);
 251        put_page(old_page);
 252out:
 253        return err;
 254}
 255
 256/*
 257 * directories can handle most operations...
 258 */
 259const struct inode_operations minix_dir_inode_operations = {
 260        .create         = minix_create,
 261        .lookup         = minix_lookup,
 262        .link           = minix_link,
 263        .unlink         = minix_unlink,
 264        .symlink        = minix_symlink,
 265        .mkdir          = minix_mkdir,
 266        .rmdir          = minix_rmdir,
 267        .mknod          = minix_mknod,
 268        .rename         = minix_rename,
 269        .getattr        = minix_getattr,
 270        .tmpfile        = minix_tmpfile,
 271};
 272