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