/* dir.c: AFS filesystem directory handling
*
* Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/ctype.h>
#include <linux/sched.h>
#include "internal.h"
static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd);
static int afs_dir_open(struct inode *inode, struct file *file);
static int afs_readdir(struct file *file, void *dirent, filldir_t filldir);
static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd);
static int afs_d_delete(struct dentry *dentry);
static void afs_d_release(struct dentry *dentry);
static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,
loff_t fpos, u64 ino, unsigned dtype);
static int afs_create(struct inode *dir, struct dentry *dentry, int mode,
struct nameidata *nd);
static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
static int afs_rmdir(struct inode *dir, struct dentry *dentry);
static int afs_unlink(struct inode *dir, struct dentry *dentry);
static int afs_link(struct dentry *from, struct inode *dir,
struct dentry *dentry);
static int afs_symlink(struct inode *dir, struct dentry *dentry,
const char *content);
static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry);
const struct file_operations afs_dir_file_operations = {
.open = afs_dir_open,
.release = afs_release,
.readdir = afs_readdir,
.lock = afs_lock,
};
const struct inode_operations afs_dir_inode_operations = {
.create = afs_create,
.lookup = afs_lookup,
.link = afs_link,
.unlink = afs_unlink,
.symlink = afs_symlink,
.mkdir = afs_mkdir,
.rmdir = afs_rmdir,
.rename = afs_rename,
.permission = afs_permission,
.getattr = afs_getattr,
.setattr = afs_setattr,
};
static struct dentry_operations afs_fs_dentry_operations = {
.d_revalidate = afs_d_revalidate,
.d_delete = afs_d_delete,
.d_release = afs_d_release,
};
#define AFS_DIR_HASHTBL_SIZE 128
#define AFS_DIR_DIRENT_SIZE 32
#define AFS_DIRENT_PER_BLOCK 64
union afs_dirent {
struct {
uint8_t valid;
uint8_t unused[1];
__be16 hash_next;
__be32 vnode;
__be32 unique;
uint8_t name[16];
uint8_t overflow[4]; /* if any char of the name (inc
* NUL) reaches here, consume
* the next dirent too */
} u;
uint8_t extended_name[32];
};
/* AFS directory page header (one at the beginning of every 2048-byte chunk) */
struct afs_dir_pagehdr