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_create(struct inode *dir, struct dentry *dentry, umode_t mode,
  58                bool excl)
  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        inode->i_ctime = CURRENT_TIME_SEC;
  98        inode_inc_link_count(inode);
  99        ihold(inode);
 100        return add_nondir(dentry, inode);
 101}
 102
 103static int minix_mkdir(struct inode * dir, struct dentry *dentry, umode_t mode)
 104{
 105        struct inode * inode;
 106        int err;
 107
 108        inode_inc_link_count(dir);
 109
 110        inode = minix_new_inode(dir, S_IFDIR | mode, &err);
 111        if (!inode)
 112                goto out_dir;
 113
 114        minix_set_inode(inode, 0);
 115
 116        inode_inc_link_count(inode);
 117
 118        err = minix_make_empty(inode, dir);
 119        if (err)
 120                goto out_fail;
 121
 122        err = minix_add_link(dentry, inode);
 123        if (err)
 124                goto out_fail;
 125
 126        d_instantiate(dentry, inode);
 127out:
 128        return err;
 129
 130out_fail:
 131        inode_dec_link_count(inode);
 132        inode_dec_link_count(inode);
 133        iput(inode);
 134out_dir:
 135        inode_dec_link_count(dir);
 136        goto out;
 137}
 138
 139static int minix_unlink(struct inode * dir, struct dentry *dentry)
 140{
 141        int err = -ENOENT;
 142        struct inode * inode = dentry->d_inode;
 143        struct page * page;
 144        struct minix_dir_entry * de;
 145
 146        de = minix_find_entry(dentry, &page);
 147        if (!de)
 148                goto end_unlink;
 149
 150        err = minix_delete_entry(de, page);
 151        if (err)
 152                goto end_unlink;
 153
 154        inode->i_ctime = dir->i_ctime;
 155        inode_dec_link_count(inode);
 156end_unlink:
 157        return err;
 158}
 159
 160static int minix_rmdir(struct inode * dir, struct dentry *dentry)
 161{
 162        struct inode * inode = dentry->d_inode;
 163        int err = -ENOTEMPTY;
 164
 165        if (minix_empty_dir(inode)) {
 166                err = minix_unlink(dir, dentry);
 167                if (!err) {
 168                        inode_dec_link_count(dir);
 169                        inode_dec_link_count(inode);
 170                }
 171        }
 172        return err;
 173}
 174
 175static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
 176                           struct inode * new_dir, struct dentry *new_dentry)
 177{
 178        struct inode * old_inode = old_dentry->d_inode;
 179        struct inode * new_inode = new_dentry->d_inode;
 180        struct page * dir_page = NULL;
 181        struct minix_dir_entry * dir_de = NULL;
 182        struct page * old_page;
 183        struct minix_dir_entry * old_de;
 184        int err = -ENOENT;
 185
 186        old_de = minix_find_entry(old_dentry, &old_page);
 187        if (!old_de)
 188                goto out;
 189
 190        if (S_ISDIR(old_inode->i_mode)) {
 191                err = -EIO;
 192                dir_de = minix_dotdot(old_inode, &dir_page);
 193                if (!dir_de)
 194                        goto out_old;
 195        }
 196
 197        if (new_inode) {
 198                struct page * new_page;
 199                struct minix_dir_entry * new_de;
 200
 201                err = -ENOTEMPTY;
 202                if (dir_de && !minix_empty_dir(new_inode))
 203                        goto out_dir;
 204
 205                err = -ENOENT;
 206                new_de = minix_find_entry(new_dentry, &new_page);
 207                if (!new_de)
 208                        goto out_dir;
 209                minix_set_link(new_de, new_page, old_inode);
 210                new_inode->i_ctime = CURRENT_TIME_SEC;
 211                if (dir_de)
 212                        drop_nlink(new_inode);
 213                inode_dec_link_count(new_inode);
 214        } else {
 215                err = minix_add_link(new_dentry, old_inode);
 216                if (err)
 217                        goto out_dir;
 218                if (dir_de)
 219                        inode_inc_link_count(new_dir);
 220        }
 221
 222        minix_delete_entry(old_de, old_page);
 223        mark_inode_dirty(old_inode);
 224
 225        if (dir_de) {
 226                minix_set_link(dir_de, dir_page, new_dir);
 227                inode_dec_link_count(old_dir);
 228        }
 229        return 0;
 230
 231out_dir:
 232        if (dir_de) {
 233                kunmap(dir_page);
 234                page_cache_release(dir_page);
 235        }
 236out_old:
 237        kunmap(old_page);
 238        page_cache_release(old_page);
 239out:
 240        return err;
 241}
 242
 243/*
 244 * directories can handle most operations...
 245 */
 246const struct inode_operations minix_dir_inode_operations = {
 247        .create         = minix_create,
 248        .lookup         = minix_lookup,
 249        .link           = minix_link,
 250        .unlink         = minix_unlink,
 251        .symlink        = minix_symlink,
 252        .mkdir          = minix_mkdir,
 253        .rmdir          = minix_rmdir,
 254        .mknod          = minix_mknod,
 255        .rename         = minix_rename,
 256        .getattr        = minix_getattr,
 257};
 258
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.