The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/adfs/dir.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *  linux/fs/adfs/dir.c
    3  *
    4  *  Copyright (C) 1999-2000 Russell King
    5  *
    6  * This program is free software; you can redistribute it and/or modify
    7  * it under the terms of the GNU General Public License version 2 as
    8  * published by the Free Software Foundation.
    9  *
   10  *  Common directory handling for ADFS
   11  */
   12 #include <linux/config.h>
   13 #include <linux/version.h>
   14 #include <linux/errno.h>
   15 #include <linux/fs.h>
   16 #include <linux/adfs_fs.h>
   17 #include <linux/sched.h>
   18 #include <linux/stat.h>
   19 #include <linux/spinlock.h>
   20 
   21 #include "adfs.h"
   22 
   23 /*
   24  * For future.  This should probably be per-directory.
   25  */
   26 static rwlock_t adfs_dir_lock;
   27 
   28 static int
   29 adfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
   30 {
   31         struct inode *inode = filp->f_dentry->d_inode;
   32         struct super_block *sb = inode->i_sb;
   33         struct adfs_dir_ops *ops = sb->u.adfs_sb.s_dir;
   34         struct object_info obj;
   35         struct adfs_dir dir;
   36         int ret = 0;
   37 
   38         if (filp->f_pos >> 32)
   39                 goto out;
   40 
   41         ret = ops->read(sb, inode->i_ino, inode->i_size, &dir);
   42         if (ret)
   43                 goto out;
   44 
   45         switch ((unsigned long)filp->f_pos) {
   46         case 0:
   47                 if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
   48                         goto free_out;
   49                 filp->f_pos += 1;
   50 
   51         case 1:
   52                 if (filldir(dirent, "..", 2, 1, dir.parent_id, DT_DIR) < 0)
   53                         goto free_out;
   54                 filp->f_pos += 1;
   55 
   56         default:
   57                 break;
   58         }
   59 
   60         read_lock(&adfs_dir_lock);
   61 
   62         ret = ops->setpos(&dir, filp->f_pos - 2);
   63         if (ret)
   64                 goto unlock_out;
   65         while (ops->getnext(&dir, &obj) == 0) {
   66                 if (filldir(dirent, obj.name, obj.name_len,
   67                             filp->f_pos, obj.file_id, DT_UNKNOWN) < 0)
   68                         goto unlock_out;
   69                 filp->f_pos += 1;
   70         }
   71 
   72 unlock_out:
   73         read_unlock(&adfs_dir_lock);
   74 
   75 free_out:
   76         ops->free(&dir);
   77 
   78 out:
   79         return ret;
   80 }
   81 
   82 int
   83 adfs_dir_update(struct super_block *sb, struct object_info *obj)
   84 {
   85         int ret = -EINVAL;
   86 #ifdef CONFIG_ADFS_FS_RW
   87         struct adfs_dir_ops *ops = sb->u.adfs_sb.s_dir;
   88         struct adfs_dir dir;
   89 
   90         printk(KERN_INFO "adfs_dir_update: object %06X in dir %06X\n",
   91                  obj->file_id, obj->parent_id);
   92 
   93         if (!ops->update) {
   94                 ret = -EINVAL;
   95                 goto out;
   96         }
   97 
   98         ret = ops->read(sb, obj->parent_id, 0, &dir);
   99         if (ret)
  100                 goto out;
  101 
  102         write_lock(&adfs_dir_lock);
  103         ret = ops->update(&dir, obj);
  104         write_unlock(&adfs_dir_lock);
  105 
  106         ops->free(&dir);
  107 out:
  108 #endif
  109         return ret;
  110 }
  111 
  112 static int
  113 adfs_match(struct qstr *name, struct object_info *obj)
  114 {
  115         int i;
  116 
  117         if (name->len != obj->name_len)
  118                 return 0;
  119 
  120         for (i = 0; i < name->len; i++) {
  121                 char c1, c2;
  122 
  123                 c1 = name->name[i];
  124                 c2 = obj->name[i];
  125 
  126                 if (c1 >= 'A' && c1 <= 'Z')
  127                         c1 += 'a' - 'A';
  128                 if (c2 >= 'A' && c2 <= 'Z')
  129                         c2 += 'a' - 'A';
  130 
  131                 if (c1 != c2)
  132                         return 0;
  133         }
  134         return 1;
  135 }
  136 
  137 static int
  138 adfs_dir_lookup_byname(struct inode *inode, struct qstr *name, struct object_info *obj)
  139 {
  140         struct super_block *sb = inode->i_sb;
  141         struct adfs_dir_ops *ops = sb->u.adfs_sb.s_dir;
  142         struct adfs_dir dir;
  143         int ret;
  144 
  145         ret = ops->read(sb, inode->i_ino, inode->i_size, &dir);
  146         if (ret)
  147                 goto out;
  148 
  149         if (inode->u.adfs_i.parent_id != dir.parent_id) {
  150                 adfs_error(sb, "parent directory changed under me! (%lx but got %lx)\n",
  151                            inode->u.adfs_i.parent_id, dir.parent_id);
  152                 ret = -EIO;
  153                 goto free_out;
  154         }
  155 
  156         obj->parent_id = inode->i_ino;
  157 
  158         /*
  159          * '.' is handled by reserved_lookup() in fs/namei.c
  160          */
  161         if (name->len == 2 && name->name[0] == '.' && name->name[1] == '.') {
  162                 /*
  163                  * Currently unable to fill in the rest of 'obj',
  164                  * but this is better than nothing.  We need to
  165                  * ascend one level to find it's parent.
  166                  */
  167                 obj->name_len = 0;
  168                 obj->file_id  = obj->parent_id;
  169                 goto free_out;
  170         }
  171 
  172         read_lock(&adfs_dir_lock);
  173 
  174         ret = ops->setpos(&dir, 0);
  175         if (ret)
  176                 goto unlock_out;
  177 
  178         ret = -ENOENT;
  179         while (ops->getnext(&dir, obj) == 0) {
  180                 if (adfs_match(name, obj)) {
  181                         ret = 0;
  182                         break;
  183                 }
  184         }
  185 
  186 unlock_out:
  187         read_unlock(&adfs_dir_lock);
  188 
  189 free_out:
  190         ops->free(&dir);
  191 out:
  192         return ret;
  193 }
  194 
  195 struct file_operations adfs_dir_operations = {
  196         read:           generic_read_dir,
  197         readdir:        adfs_readdir,
  198         fsync:          file_fsync,
  199 };
  200 
  201 static int
  202 adfs_hash(struct dentry *parent, struct qstr *qstr)
  203 {
  204         const unsigned int name_len = parent->d_sb->u.adfs_sb.s_namelen;
  205         const unsigned char *name;
  206         unsigned long hash;
  207         int i;
  208 
  209         if (qstr->len < name_len)
  210                 return 0;
  211 
  212         /*
  213          * Truncate the name in place, avoids
  214          * having to define a compare function.
  215          */
  216         qstr->len = i = name_len;
  217         name = qstr->name;
  218         hash = init_name_hash();
  219         while (i--) {
  220                 char c;
  221 
  222                 c = *name++;
  223                 if (c >= 'A' && c <= 'Z')
  224                         c += 'a' - 'A';
  225 
  226                 hash = partial_name_hash(c, hash);
  227         }
  228         qstr->hash = end_name_hash(hash);
  229 
  230         return 0;
  231 }
  232 
  233 /*
  234  * Compare two names, taking note of the name length
  235  * requirements of the underlying filesystem.
  236  */
  237 static int
  238 adfs_compare(struct dentry *parent, struct qstr *entry, struct qstr *name)
  239 {
  240         int i;
  241 
  242         if (entry->len != name->len)
  243                 return 1;
  244 
  245         for (i = 0; i < name->len; i++) {
  246                 char a, b;
  247 
  248                 a = entry->name[i];
  249                 b = name->name[i];
  250 
  251                 if (a >= 'A' && a <= 'Z')
  252                         a += 'a' - 'A';
  253                 if (b >= 'A' && b <= 'Z')
  254                         b += 'a' - 'A';
  255 
  256                 if (a != b)
  257                         return 1;
  258         }
  259         return 0;
  260 }
  261 
  262 struct dentry_operations adfs_dentry_operations = {
  263         d_hash:         adfs_hash,
  264         d_compare:      adfs_compare,
  265 };
  266 
  267 struct dentry *adfs_lookup(struct inode *dir, struct dentry *dentry)
  268 {
  269         struct inode *inode = NULL;
  270         struct object_info obj;
  271         int error;
  272 
  273         dentry->d_op = &adfs_dentry_operations; 
  274         error = adfs_dir_lookup_byname(dir, &dentry->d_name, &obj);
  275         if (error == 0) {
  276                 error = -EACCES;
  277                 /*
  278                  * This only returns NULL if get_empty_inode
  279                  * fails.
  280                  */
  281                 inode = adfs_iget(dir->i_sb, &obj);
  282                 if (inode)
  283                         error = 0;
  284         }
  285         d_add(dentry, inode);
  286         return ERR_PTR(error);
  287 }
  288 
  289 /*
  290  * directories can handle most operations...
  291  */
  292 struct inode_operations adfs_dir_inode_operations = {
  293         lookup:         adfs_lookup,
  294         setattr:        adfs_notify_change,
  295 };

Cache object: 058b9f0ebf16279027872d92d5f5b248


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.