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