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