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