4  *  Copyright (C) 1999-2000 Russell King
 
   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.
 
  10  *  Common directory handling for ADFS
 
  12 #include <linux/errno.h>
 
  14 #include <linux/adfs_fs.h>
 
  15 #include <linux/time.h>
 
  16 #include <linux/stat.h>
 
  17 #include <linux/spinlock.h>
 
  18 #include <linux/smp_lock.h>
 
  19 #include <linux/buffer_head.h>          /* for file_fsync() */
 
  24  * For future.  This should probably be per-directory.
 
  26 static DEFINE_RWLOCK(adfs_dir_lock);
 
  29 adfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
  31         struct inode *inode = filp->f_path.dentry->d_inode;
 
  32         struct super_block *sb = inode->i_sb;
 
  33         struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
 
  34         struct object_info obj;
 
  40         if (filp->f_pos >> 32)
 
  43         ret = ops->read(sb, inode->i_ino, inode->i_size, &dir);
 
  47         switch ((unsigned long)filp->f_pos) {
 
  49                 if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
 
  54                 if (filldir(dirent, "..", 2, 1, dir.parent_id, DT_DIR) < 0)
 
  62         read_lock(&adfs_dir_lock);
 
  64         ret = ops->setpos(&dir, filp->f_pos - 2);
 
  67         while (ops->getnext(&dir, &obj) == 0) {
 
  68                 if (filldir(dirent, obj.name, obj.name_len,
 
  69                             filp->f_pos, obj.file_id, DT_UNKNOWN) < 0)
 
  75         read_unlock(&adfs_dir_lock);
 
  86 adfs_dir_update(struct super_block *sb, struct object_info *obj)
 
  89 #ifdef CONFIG_ADFS_FS_RW
 
  90         struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
 
  93         printk(KERN_INFO "adfs_dir_update: object %06X in dir %06X\n",
 
  94                  obj->file_id, obj->parent_id);
 
 101         ret = ops->read(sb, obj->parent_id, 0, &dir);
 
 105         write_lock(&adfs_dir_lock);
 
 106         ret = ops->update(&dir, obj);
 
 107         write_unlock(&adfs_dir_lock);
 
 116 adfs_match(struct qstr *name, struct object_info *obj)
 
 120         if (name->len != obj->name_len)
 
 123         for (i = 0; i < name->len; i++) {
 
 129                 if (c1 >= 'A' && c1 <= 'Z')
 
 131                 if (c2 >= 'A' && c2 <= 'Z')
 
 141 adfs_dir_lookup_byname(struct inode *inode, struct qstr *name, struct object_info *obj)
 
 143         struct super_block *sb = inode->i_sb;
 
 144         struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
 
 148         ret = ops->read(sb, inode->i_ino, inode->i_size, &dir);
 
 152         if (ADFS_I(inode)->parent_id != dir.parent_id) {
 
 153                 adfs_error(sb, "parent directory changed under me! (%lx but got %lx)\n",
 
 154                            ADFS_I(inode)->parent_id, dir.parent_id);
 
 159         obj->parent_id = inode->i_ino;
 
 162          * '.' is handled by reserved_lookup() in fs/namei.c
 
 164         if (name->len == 2 && name->name[0] == '.' && name->name[1] == '.') {
 
 166                  * Currently unable to fill in the rest of 'obj',
 
 167                  * but this is better than nothing.  We need to
 
 168                  * ascend one level to find it's parent.
 
 171                 obj->file_id  = obj->parent_id;
 
 175         read_lock(&adfs_dir_lock);
 
 177         ret = ops->setpos(&dir, 0);
 
 182         while (ops->getnext(&dir, obj) == 0) {
 
 183                 if (adfs_match(name, obj)) {
 
 190         read_unlock(&adfs_dir_lock);
 
 198 const struct file_operations adfs_dir_operations = {
 
 199         .read           = generic_read_dir,
 
 200         .llseek         = generic_file_llseek,
 
 201         .readdir        = adfs_readdir,
 
 206 adfs_hash(struct dentry *parent, struct qstr *qstr)
 
 208         const unsigned int name_len = ADFS_SB(parent->d_sb)->s_namelen;
 
 209         const unsigned char *name;
 
 213         if (qstr->len < name_len)
 
 217          * Truncate the name in place, avoids
 
 218          * having to define a compare function.
 
 220         qstr->len = i = name_len;
 
 222         hash = init_name_hash();
 
 227                 if (c >= 'A' && c <= 'Z')
 
 230                 hash = partial_name_hash(c, hash);
 
 232         qstr->hash = end_name_hash(hash);
 
 238  * Compare two names, taking note of the name length
 
 239  * requirements of the underlying filesystem.
 
 242 adfs_compare(struct dentry *parent, struct qstr *entry, struct qstr *name)
 
 246         if (entry->len != name->len)
 
 249         for (i = 0; i < name->len; i++) {
 
 255                 if (a >= 'A' && a <= 'Z')
 
 257                 if (b >= 'A' && b <= 'Z')
 
 266 struct dentry_operations adfs_dentry_operations = {
 
 268         .d_compare      = adfs_compare,
 
 271 static struct dentry *
 
 272 adfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 
 274         struct inode *inode = NULL;
 
 275         struct object_info obj;
 
 278         dentry->d_op = &adfs_dentry_operations; 
 
 280         error = adfs_dir_lookup_byname(dir, &dentry->d_name, &obj);
 
 284                  * This only returns NULL if get_empty_inode
 
 287                 inode = adfs_iget(dir->i_sb, &obj);
 
 292         d_add(dentry, inode);
 
 293         return ERR_PTR(error);
 
 297  * directories can handle most operations...
 
 299 const struct inode_operations adfs_dir_inode_operations = {
 
 300         .lookup         = adfs_lookup,
 
 301         .setattr        = adfs_notify_change,