/*
* inode.c
*
* Copyright (C) 1995, 1996 by Volker Lendecke
* Modified for big endian by J.F. Chadima and David S. Miller
* Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
* Modified 1998 Wolfram Pienkoss for NLS
* Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
#include <linux/time.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/file.h>
#include <linux/fcntl.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <linux/vfs.h>
#include <linux/ncp_fs.h>
#include <net/sock.h>
#include "ncplib_kernel.h"
#include "getopt.h"
static void ncp_delete_inode(struct inode *);
static void ncp_put_super(struct super_block *);
static int ncp_statfs(struct super_block *, struct kstatfs *);
static kmem_cache_t * ncp_inode_cachep;
static struct inode *ncp_alloc_inode(struct super_block *sb)
{
struct ncp_inode_info *ei;
ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, SLAB_KERNEL);
if (!ei)
return NULL;
return &ei->vfs_inode;
}
static void ncp_destroy_inode(struct inode *inode)
{
kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
}
static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
{
struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
SLAB_CTOR_CONSTRUCTOR) {
init_MUTEX(&ei->open_sem);
inode_init_once(&ei->vfs_inode);
}
}
static int init_inodecache(void)
{
ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
sizeof(struct ncp_inode_info),
0, SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
if (ncp_inode_cachep == NULL)
return -ENOMEM;
return 0;
}
static void destroy_inodecache(void)
{
if (kmem_cache_destroy(ncp_inode_cachep))
printk(KERN_INFO "ncp_inode_cache: not all structures were freed\n");
}
static int ncp_remount(struct super_block *sb, int *flags, char* data)
{
*flags |= MS_NODIRATIME;
return 0;
}
static struct super_operations ncp_sops =
{
.alloc_inode = ncp_alloc_inode,
.destroy_inode = ncp_destroy_inode,
.drop_inode = generic_delete_inode,
.delete_inode = ncp_delete_inode,
.put_super = ncp_put_super,
.statfs = ncp_statfs,
.remount_fs = ncp_remount,
};
extern struct dentry_operations ncp_root_dentry_operations;
#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
extern struct address_space_operations ncp_symlink_aops;
extern int ncp_symlink(struct inode*, struct dentry*, const char*);
#endif
/*
* Fill in the ncpfs-specific information in the inode.
*/
static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
{
NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
NCP_FINFO(inode)->volNumber = nwinfo->volume;
}
void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
{
ncp_update_dirent(inode, nwinfo);
NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
NCP_FINFO(inode)->access = nwinfo->access;
memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
sizeof(nwinfo->file_handle));
DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
NCP_FINFO(inode)->dirEntNum);
}
static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
{
/* NFS namespace mode overrides others if it's set. */
DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
nwi->entryName, nwi->nfs.mode);
if (nwi->nfs.mode) {
/* XXX Security? */
inode->i_mode = nwi->nfs.mode;
}
inode->i_blocks = (inode->