/*
|
/*
|
* inode.c
|
* inode.c
|
*
|
*
|
* Copyright (C) 1995, 1996 by Volker Lendecke
|
* Copyright (C) 1995, 1996 by Volker Lendecke
|
*
|
*
|
*/
|
*/
|
|
|
#include <linux/module.h>
|
#include <linux/module.h>
|
#include <linux/config.h>
|
#include <linux/config.h>
|
|
|
#include <asm/system.h>
|
#include <asm/system.h>
|
#include <asm/segment.h>
|
#include <asm/segment.h>
|
|
|
#include <linux/sched.h>
|
#include <linux/sched.h>
|
#include <linux/ncp_fs.h>
|
#include <linux/ncp_fs.h>
|
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
#include <linux/mm.h>
|
#include <linux/mm.h>
|
#include <linux/string.h>
|
#include <linux/string.h>
|
#include <linux/stat.h>
|
#include <linux/stat.h>
|
#include <linux/errno.h>
|
#include <linux/errno.h>
|
#include <linux/locks.h>
|
#include <linux/locks.h>
|
#include <linux/fcntl.h>
|
#include <linux/fcntl.h>
|
#include <linux/malloc.h>
|
#include <linux/malloc.h>
|
#ifdef CONFIG_KERNELD
|
#ifdef CONFIG_KERNELD
|
#include <linux/kerneld.h>
|
#include <linux/kerneld.h>
|
#endif
|
#endif
|
#include "ncplib_kernel.h"
|
#include "ncplib_kernel.h"
|
|
|
extern int close_fp(struct file *filp);
|
extern int close_fp(struct file *filp);
|
|
|
static void ncp_put_inode(struct inode *);
|
static void ncp_put_inode(struct inode *);
|
static void ncp_read_inode(struct inode *);
|
static void ncp_read_inode(struct inode *);
|
static void ncp_put_super(struct super_block *);
|
static void ncp_put_super(struct super_block *);
|
static void ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
|
static void ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
|
|
|
static struct super_operations ncp_sops = {
|
static struct super_operations ncp_sops = {
|
ncp_read_inode, /* read inode */
|
ncp_read_inode, /* read inode */
|
ncp_notify_change, /* notify change */
|
ncp_notify_change, /* notify change */
|
NULL, /* write inode */
|
NULL, /* write inode */
|
ncp_put_inode, /* put inode */
|
ncp_put_inode, /* put inode */
|
ncp_put_super, /* put superblock */
|
ncp_put_super, /* put superblock */
|
NULL, /* write superblock */
|
NULL, /* write superblock */
|
ncp_statfs, /* stat filesystem */
|
ncp_statfs, /* stat filesystem */
|
NULL
|
NULL
|
};
|
};
|
|
|
/* ncp_read_inode: Called from iget, it only traverses the allocated
|
/* ncp_read_inode: Called from iget, it only traverses the allocated
|
ncp_inode_info's and initializes the inode from the data found
|
ncp_inode_info's and initializes the inode from the data found
|
there. It does not allocate or deallocate anything. */
|
there. It does not allocate or deallocate anything. */
|
|
|
static void
|
static void
|
ncp_read_inode(struct inode *inode)
|
ncp_read_inode(struct inode *inode)
|
{
|
{
|
/* Our task should be extremely simple here. We only have to
|
/* Our task should be extremely simple here. We only have to
|
look up the information somebody else (ncp_iget) put into
|
look up the information somebody else (ncp_iget) put into
|
the inode tree. The address of this information is the
|
the inode tree. The address of this information is the
|
inode->i_ino. Just to make sure everything went well, we
|
inode->i_ino. Just to make sure everything went well, we
|
check it's there. */
|
check it's there. */
|
|
|
struct ncp_inode_info *inode_info = ncp_find_inode(inode);
|
struct ncp_inode_info *inode_info = ncp_find_inode(inode);
|
|
|
if (inode_info == NULL)
|
if (inode_info == NULL)
|
{
|
{
|
/* Ok, now we're in trouble. The inode info is not there. What
|
/* Ok, now we're in trouble. The inode info is not there. What
|
should we do now??? */
|
should we do now??? */
|
printk("ncp_read_inode: inode info not found\n");
|
printk("ncp_read_inode: inode info not found\n");
|
return;
|
return;
|
}
|
}
|
|
|
inode_info->state = NCP_INODE_VALID;
|
inode_info->state = NCP_INODE_VALID;
|
|
|
NCP_INOP(inode) = inode_info;
|
NCP_INOP(inode) = inode_info;
|
inode_info->inode = inode;
|
inode_info->inode = inode;
|
|
|
if (NCP_ISTRUCT(inode)->attributes & aDIR)
|
if (NCP_ISTRUCT(inode)->attributes & aDIR)
|
{
|
{
|
inode->i_mode = NCP_SERVER(inode)->m.dir_mode;
|
inode->i_mode = NCP_SERVER(inode)->m.dir_mode;
|
/* for directories dataStreamSize seems to be some
|
/* for directories dataStreamSize seems to be some
|
Object ID ??? */
|
Object ID ??? */
|
inode->i_size = 512;
|
inode->i_size = 512;
|
}
|
}
|
else
|
else
|
{
|
{
|
inode->i_mode = NCP_SERVER(inode)->m.file_mode;
|
inode->i_mode = NCP_SERVER(inode)->m.file_mode;
|
#if 1
|
#if 1
|
if (NCP_ISTRUCT(inode)->attributes & /* 0x60001 incl. DiRi */ 1) inode->i_mode &= ~0222;
|
if (NCP_ISTRUCT(inode)->attributes & /* 0x60001 incl. DiRi */ 1) inode->i_mode &= ~0222;
|
#endif
|
#endif
|
inode->i_size = NCP_ISTRUCT(inode)->dataStreamSize;
|
inode->i_size = NCP_ISTRUCT(inode)->dataStreamSize;
|
}
|
}
|
|
|
DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
|
DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
|
|
|
inode->i_nlink = 1;
|
inode->i_nlink = 1;
|
inode->i_uid = NCP_SERVER(inode)->m.uid;
|
inode->i_uid = NCP_SERVER(inode)->m.uid;
|
inode->i_gid = NCP_SERVER(inode)->m.gid;
|
inode->i_gid = NCP_SERVER(inode)->m.gid;
|
inode->i_blksize = 512;
|
inode->i_blksize = 512;
|
inode->i_rdev = 0;
|
inode->i_rdev = 0;
|
|
|
if ((inode->i_blksize != 0) && (inode->i_size != 0))
|
if ((inode->i_blksize != 0) && (inode->i_size != 0))
|
{
|
{
|
inode->i_blocks =
|
inode->i_blocks =
|
(inode->i_size - 1) / inode->i_blksize + 1;
|
(inode->i_size - 1) / inode->i_blksize + 1;
|
}
|
}
|
else
|
else
|
{
|
{
|
inode->i_blocks = 0;
|
inode->i_blocks = 0;
|
}
|
}
|
|
|
inode->i_mtime = ncp_date_dos2unix(NCP_ISTRUCT(inode)->modifyTime,
|
inode->i_mtime = ncp_date_dos2unix(NCP_ISTRUCT(inode)->modifyTime,
|
NCP_ISTRUCT(inode)->modifyDate);
|
NCP_ISTRUCT(inode)->modifyDate);
|
inode->i_ctime = ncp_date_dos2unix(NCP_ISTRUCT(inode)->creationTime,
|
inode->i_ctime = ncp_date_dos2unix(NCP_ISTRUCT(inode)->creationTime,
|
NCP_ISTRUCT(inode)->creationDate);
|
NCP_ISTRUCT(inode)->creationDate);
|
inode->i_atime = ncp_date_dos2unix(0,
|
inode->i_atime = ncp_date_dos2unix(0,
|
NCP_ISTRUCT(inode)->lastAccessDate);
|
NCP_ISTRUCT(inode)->lastAccessDate);
|
|
|
if (S_ISREG(inode->i_mode))
|
if (S_ISREG(inode->i_mode))
|
{
|
{
|
inode->i_op = &ncp_file_inode_operations;
|
inode->i_op = &ncp_file_inode_operations;
|
}
|
}
|
else if (S_ISDIR(inode->i_mode))
|
else if (S_ISDIR(inode->i_mode))
|
{
|
{
|
inode->i_op = &ncp_dir_inode_operations;
|
inode->i_op = &ncp_dir_inode_operations;
|
}
|
}
|
else
|
else
|
{
|
{
|
inode->i_op = NULL;
|
inode->i_op = NULL;
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* Defer release of inode_info and file_info structures until the inode
|
* Defer release of inode_info and file_info structures until the inode
|
* has been cleared. This avoids a race condition allowing the inode to
|
* has been cleared. This avoids a race condition allowing the inode to
|
* be put back in use before being cleared. Also, temporarily increment
|
* be put back in use before being cleared. Also, temporarily increment
|
* i_count after clear_inode() so that the inode can't be reused.
|
* i_count after clear_inode() so that the inode can't be reused.
|
*/
|
*/
|
static void
|
static void
|
ncp_put_inode(struct inode *inode)
|
ncp_put_inode(struct inode *inode)
|
{
|
{
|
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
struct ncp_server *server = NCP_SERVER(inode);
|
struct ncp_server *server = NCP_SERVER(inode);
|
struct ncp_inode_info *iinfo = NCP_INOP(inode);
|
struct ncp_inode_info *iinfo = NCP_INOP(inode);
|
struct nw_file_info *finfo = NCP_FINFO(inode);
|
struct nw_file_info *finfo = NCP_FINFO(inode);
|
|
|
/*
|
/*
|
* This operation may block, so we lock before checking the count.
|
* This operation may block, so we lock before checking the count.
|
*/
|
*/
|
lock_super(sb);
|
lock_super(sb);
|
|
|
if (inode->i_count > 1)
|
if (inode->i_count > 1)
|
{
|
{
|
printk("ncp_put_inode: inode in use device %s, inode %ld, count=%ld\n",
|
printk("ncp_put_inode: inode in use device %s, inode %ld, count=%ld\n",
|
kdevname(inode->i_dev), inode->i_ino, inode->i_count);
|
kdevname(inode->i_dev), inode->i_ino, inode->i_count);
|
goto unlock;
|
goto unlock;
|
}
|
}
|
|
|
DDPRINTK("ncp_put_inode: put %s\n",
|
DDPRINTK("ncp_put_inode: put %s\n",
|
finfo->i.entryName);
|
finfo->i.entryName);
|
/*
|
/*
|
* This operation should never block.
|
* This operation should never block.
|
*/
|
*/
|
if (S_ISDIR(inode->i_mode))
|
if (S_ISDIR(inode->i_mode))
|
{
|
{
|
DDPRINTK("ncp_put_inode: put directory %ld\n",
|
DDPRINTK("ncp_put_inode: put directory %ld\n",
|
inode->i_ino);
|
inode->i_ino);
|
ncp_invalid_dir_cache(inode);
|
ncp_invalid_dir_cache(inode);
|
}
|
}
|
|
|
clear_inode(inode);
|
clear_inode(inode);
|
|
|
/*
|
/*
|
* After clearing the inode i_count will be 0 in 2.0.xx kernels.
|
* After clearing the inode i_count will be 0 in 2.0.xx kernels.
|
* To keep the inode from being reused as free if we block while
|
* To keep the inode from being reused as free if we block while
|
* closing the file, increment i_count temporarily.
|
* closing the file, increment i_count temporarily.
|
*/
|
*/
|
inode->i_count++;
|
inode->i_count++;
|
|
|
if (finfo->opened != 0)
|
if (finfo->opened != 0)
|
{
|
{
|
if (ncp_close_file(server, finfo->file_handle) != 0)
|
if (ncp_close_file(server, finfo->file_handle) != 0)
|
{
|
{
|
/* We can't do anything but complain. */
|
/* We can't do anything but complain. */
|
printk("ncp_put_inode: could not close %s\n",
|
printk("ncp_put_inode: could not close %s\n",
|
finfo->i.entryName);
|
finfo->i.entryName);
|
}
|
}
|
}
|
}
|
|
|
ncp_free_inode_info(iinfo);
|
ncp_free_inode_info(iinfo);
|
inode->i_count--;
|
inode->i_count--;
|
|
|
unlock:
|
unlock:
|
unlock_super(sb);
|
unlock_super(sb);
|
}
|
}
|
|
|
struct super_block *
|
struct super_block *
|
ncp_read_super(struct super_block *sb, void *raw_data, int silent)
|
ncp_read_super(struct super_block *sb, void *raw_data, int silent)
|
{
|
{
|
struct ncp_mount_data *data = (struct ncp_mount_data *) raw_data;
|
struct ncp_mount_data *data = (struct ncp_mount_data *) raw_data;
|
struct ncp_server *server;
|
struct ncp_server *server;
|
struct file *ncp_filp;
|
struct file *ncp_filp;
|
struct file *wdog_filp;
|
struct file *wdog_filp;
|
struct file *msg_filp;
|
struct file *msg_filp;
|
kdev_t dev = sb->s_dev;
|
kdev_t dev = sb->s_dev;
|
int error;
|
int error;
|
#ifdef CONFIG_NCPFS_PACKET_SIGNING
|
#ifdef CONFIG_NCPFS_PACKET_SIGNING
|
int options;
|
int options;
|
#endif
|
#endif
|
|
|
if (data == NULL)
|
if (data == NULL)
|
{
|
{
|
printk("ncp_read_super: missing data argument\n");
|
printk("ncp_read_super: missing data argument\n");
|
sb->s_dev = 0;
|
sb->s_dev = 0;
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
if (data->version != NCP_MOUNT_VERSION)
|
if (data->version != NCP_MOUNT_VERSION)
|
{
|
{
|
printk("ncp warning: mount version %s than kernel\n",
|
printk("ncp warning: mount version %s than kernel\n",
|
(data->version < NCP_MOUNT_VERSION) ?
|
(data->version < NCP_MOUNT_VERSION) ?
|
"older" : "newer");
|
"older" : "newer");
|
sb->s_dev = 0;
|
sb->s_dev = 0;
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
if ( (data->ncp_fd >= NR_OPEN)
|
if ( (data->ncp_fd >= NR_OPEN)
|
|| ((ncp_filp = current->files->fd[data->ncp_fd]) == NULL)
|
|| ((ncp_filp = current->files->fd[data->ncp_fd]) == NULL)
|
|| (!S_ISSOCK(ncp_filp->f_inode->i_mode)))
|
|| (!S_ISSOCK(ncp_filp->f_inode->i_mode)))
|
{
|
{
|
printk("ncp_read_super: invalid ncp socket\n");
|
printk("ncp_read_super: invalid ncp socket\n");
|
sb->s_dev = 0;
|
sb->s_dev = 0;
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
if ( (data->wdog_fd >= NR_OPEN)
|
if ( (data->wdog_fd >= NR_OPEN)
|
|| ((wdog_filp = current->files->fd[data->wdog_fd]) == NULL)
|
|| ((wdog_filp = current->files->fd[data->wdog_fd]) == NULL)
|
|| (!S_ISSOCK(wdog_filp->f_inode->i_mode)))
|
|| (!S_ISSOCK(wdog_filp->f_inode->i_mode)))
|
{
|
{
|
printk("ncp_read_super: invalid wdog socket\n");
|
printk("ncp_read_super: invalid wdog socket\n");
|
sb->s_dev = 0;
|
sb->s_dev = 0;
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
if ( (data->message_fd >= NR_OPEN)
|
if ( (data->message_fd >= NR_OPEN)
|
|| ((msg_filp = current->files->fd[data->message_fd]) == NULL)
|
|| ((msg_filp = current->files->fd[data->message_fd]) == NULL)
|
|| (!S_ISSOCK(msg_filp->f_inode->i_mode)))
|
|| (!S_ISSOCK(msg_filp->f_inode->i_mode)))
|
{
|
{
|
printk("ncp_read_super: invalid wdog socket\n");
|
printk("ncp_read_super: invalid wdog socket\n");
|
sb->s_dev = 0;
|
sb->s_dev = 0;
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
/* We must malloc our own super-block info */
|
/* We must malloc our own super-block info */
|
server = (struct ncp_server *)ncp_kmalloc(sizeof(struct ncp_server),
|
server = (struct ncp_server *)ncp_kmalloc(sizeof(struct ncp_server),
|
GFP_KERNEL);
|
GFP_KERNEL);
|
|
|
if (server == NULL)
|
if (server == NULL)
|
{
|
{
|
printk("ncp_read_super: could not alloc ncp_server\n");
|
printk("ncp_read_super: could not alloc ncp_server\n");
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
ncp_filp->f_count += 1;
|
ncp_filp->f_count += 1;
|
wdog_filp->f_count += 1;
|
wdog_filp->f_count += 1;
|
msg_filp->f_count += 1;
|
msg_filp->f_count += 1;
|
|
|
lock_super(sb);
|
lock_super(sb);
|
|
|
NCP_SBP(sb) = server;
|
NCP_SBP(sb) = server;
|
|
|
sb->s_blocksize = 1024; /* Eh... Is this correct? */
|
sb->s_blocksize = 1024; /* Eh... Is this correct? */
|
sb->s_blocksize_bits = 10;
|
sb->s_blocksize_bits = 10;
|
sb->s_magic = NCP_SUPER_MAGIC;
|
sb->s_magic = NCP_SUPER_MAGIC;
|
sb->s_dev = dev;
|
sb->s_dev = dev;
|
sb->s_op = &ncp_sops;
|
sb->s_op = &ncp_sops;
|
|
|
server->ncp_filp = ncp_filp;
|
server->ncp_filp = ncp_filp;
|
server->wdog_filp = wdog_filp;
|
server->wdog_filp = wdog_filp;
|
server->msg_filp = msg_filp;
|
server->msg_filp = msg_filp;
|
server->lock = 0;
|
server->lock = 0;
|
server->wait = NULL;
|
server->wait = NULL;
|
server->packet = NULL;
|
server->packet = NULL;
|
server->buffer_size = 0;
|
server->buffer_size = 0;
|
server->conn_status = 0;
|
server->conn_status = 0;
|
#ifdef CONFIG_NCPFS_PACKET_SIGNING
|
#ifdef CONFIG_NCPFS_PACKET_SIGNING
|
server->sign_wanted = 0;
|
server->sign_wanted = 0;
|
server->sign_active = 0;
|
server->sign_active = 0;
|
#endif
|
#endif
|
server->m = *data;
|
server->m = *data;
|
server->m.file_mode = (server->m.file_mode &
|
server->m.file_mode = (server->m.file_mode &
|
(S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG;
|
(S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG;
|
server->m.dir_mode = (server->m.dir_mode &
|
server->m.dir_mode = (server->m.dir_mode &
|
(S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR;
|
(S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR;
|
|
|
/* protect against invalid mount points */
|
/* protect against invalid mount points */
|
server->m.mount_point[sizeof(server->m.mount_point)-1] = '\0';
|
server->m.mount_point[sizeof(server->m.mount_point)-1] = '\0';
|
|
|
server->packet_size = NCP_PACKET_SIZE;
|
server->packet_size = NCP_PACKET_SIZE;
|
server->packet = ncp_kmalloc(NCP_PACKET_SIZE, GFP_KERNEL);
|
server->packet = ncp_kmalloc(NCP_PACKET_SIZE, GFP_KERNEL);
|
|
|
if (server->packet == NULL)
|
if (server->packet == NULL)
|
{
|
{
|
printk("ncpfs: could not alloc packet\n");
|
printk("ncpfs: could not alloc packet\n");
|
error = -ENOMEM;
|
error = -ENOMEM;
|
unlock_super(sb);
|
unlock_super(sb);
|
goto fail;
|
goto fail;
|
}
|
}
|
|
|
/*
|
/*
|
* Make the connection to the server
|
* Make the connection to the server
|
*/
|
*/
|
|
|
if (ncp_catch_watchdog(server) != 0)
|
if (ncp_catch_watchdog(server) != 0)
|
{
|
{
|
printk("ncp_read_super: Could not catch watchdog\n");
|
printk("ncp_read_super: Could not catch watchdog\n");
|
error = -EINVAL;
|
error = -EINVAL;
|
unlock_super(sb);
|
unlock_super(sb);
|
goto fail;
|
goto fail;
|
}
|
}
|
|
|
if (ncp_catch_message(server) != 0)
|
if (ncp_catch_message(server) != 0)
|
{
|
{
|
printk("ncp_read_super: Could not catch messages\n");
|
printk("ncp_read_super: Could not catch messages\n");
|
ncp_dont_catch_watchdog(server);
|
ncp_dont_catch_watchdog(server);
|
error = -EINVAL;
|
error = -EINVAL;
|
unlock_super(sb);
|
unlock_super(sb);
|
goto fail;
|
goto fail;
|
}
|
}
|
|
|
ncp_lock_server(server);
|
ncp_lock_server(server);
|
error = ncp_connect(server);
|
error = ncp_connect(server);
|
ncp_unlock_server(server);
|
ncp_unlock_server(server);
|
unlock_super(sb);
|
unlock_super(sb);
|
|
|
if (error < 0)
|
if (error < 0)
|
{
|
{
|
sb->s_dev = 0;
|
sb->s_dev = 0;
|
printk("ncp_read_super: Failed connection, bailing out "
|
printk("ncp_read_super: Failed connection, bailing out "
|
"(error = %d).\n", -error);
|
"(error = %d).\n", -error);
|
ncp_kfree_s(server->packet, server->packet_size);
|
ncp_kfree_s(server->packet, server->packet_size);
|
ncp_dont_catch_watchdog(server);
|
ncp_dont_catch_watchdog(server);
|
goto fail;
|
goto fail;
|
}
|
}
|
|
|
DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int)NCP_SBP(sb));
|
DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int)NCP_SBP(sb));
|
|
|
ncp_init_root(server);
|
ncp_init_root(server);
|
|
|
if (!(sb->s_mounted = iget(sb, ncp_info_ino(server, &(server->root)))))
|
if (!(sb->s_mounted = iget(sb, ncp_info_ino(server, &(server->root)))))
|
{
|
{
|
sb->s_dev = 0;
|
sb->s_dev = 0;
|
printk("ncp_read_super: get root inode failed\n");
|
printk("ncp_read_super: get root inode failed\n");
|
goto disconnect;
|
goto disconnect;
|
}
|
}
|
|
|
#ifdef CONFIG_NCPFS_PACKET_SIGNING
|
#ifdef CONFIG_NCPFS_PACKET_SIGNING
|
if (ncp_negotiate_size_and_options(server, NCP_DEFAULT_BUFSIZE,
|
if (ncp_negotiate_size_and_options(server, NCP_DEFAULT_BUFSIZE,
|
NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
|
NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
|
{
|
{
|
if (options != NCP_DEFAULT_OPTIONS)
|
if (options != NCP_DEFAULT_OPTIONS)
|
{
|
{
|
if (ncp_negotiate_size_and_options(server,
|
if (ncp_negotiate_size_and_options(server,
|
NCP_DEFAULT_BUFSIZE,
|
NCP_DEFAULT_BUFSIZE,
|
options & 2,
|
options & 2,
|
&(server->buffer_size), &options) != 0)
|
&(server->buffer_size), &options) != 0)
|
|
|
{
|
{
|
sb->s_dev = 0;
|
sb->s_dev = 0;
|
printk("ncp_read_super: "
|
printk("ncp_read_super: "
|
"could not set options\n");
|
"could not set options\n");
|
goto disconnect;
|
goto disconnect;
|
}
|
}
|
}
|
}
|
if (options & 2)
|
if (options & 2)
|
server->sign_wanted = 1;
|
server->sign_wanted = 1;
|
}
|
}
|
else
|
else
|
#endif /* CONFIG_NCPFS_PACKET_SIGNING */
|
#endif /* CONFIG_NCPFS_PACKET_SIGNING */
|
if (ncp_negotiate_buffersize(server, NCP_DEFAULT_BUFSIZE,
|
if (ncp_negotiate_buffersize(server, NCP_DEFAULT_BUFSIZE,
|
&(server->buffer_size)) != 0)
|
&(server->buffer_size)) != 0)
|
{
|
{
|
sb->s_dev = 0;
|
sb->s_dev = 0;
|
printk("ncp_read_super: could not get bufsize\n");
|
printk("ncp_read_super: could not get bufsize\n");
|
goto disconnect;
|
goto disconnect;
|
}
|
}
|
|
|
DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
|
DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
|
|
|
MOD_INC_USE_COUNT;
|
MOD_INC_USE_COUNT;
|
return sb;
|
return sb;
|
|
|
disconnect:
|
disconnect:
|
ncp_lock_server(server);
|
ncp_lock_server(server);
|
ncp_disconnect(server);
|
ncp_disconnect(server);
|
ncp_unlock_server(server);
|
ncp_unlock_server(server);
|
ncp_kfree_s(server->packet, server->packet_size);
|
ncp_kfree_s(server->packet, server->packet_size);
|
ncp_dont_catch_watchdog(server);
|
ncp_dont_catch_watchdog(server);
|
fail:
|
fail:
|
ncp_filp->f_count -= 1;
|
ncp_filp->f_count -= 1;
|
wdog_filp->f_count -= 1;
|
wdog_filp->f_count -= 1;
|
msg_filp->f_count -= 1;
|
msg_filp->f_count -= 1;
|
ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
|
ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
static void
|
static void
|
ncp_put_super(struct super_block *sb)
|
ncp_put_super(struct super_block *sb)
|
{
|
{
|
struct ncp_server *server = NCP_SBP(sb);
|
struct ncp_server *server = NCP_SBP(sb);
|
|
|
lock_super(sb);
|
lock_super(sb);
|
|
|
ncp_lock_server(server);
|
ncp_lock_server(server);
|
ncp_disconnect(server);
|
ncp_disconnect(server);
|
ncp_unlock_server(server);
|
ncp_unlock_server(server);
|
|
|
close_fp(server->ncp_filp);
|
close_fp(server->ncp_filp);
|
|
|
ncp_dont_catch_watchdog(server);
|
ncp_dont_catch_watchdog(server);
|
close_fp(server->wdog_filp);
|
close_fp(server->wdog_filp);
|
close_fp(server->msg_filp);
|
close_fp(server->msg_filp);
|
|
|
ncp_free_all_inodes(server);
|
ncp_free_all_inodes(server);
|
|
|
ncp_kfree_s(server->packet, server->packet_size);
|
ncp_kfree_s(server->packet, server->packet_size);
|
|
|
sb->s_dev = 0;
|
sb->s_dev = 0;
|
ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
|
ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
|
NCP_SBP(sb) = NULL;
|
NCP_SBP(sb) = NULL;
|
|
|
unlock_super(sb);
|
unlock_super(sb);
|
|
|
MOD_DEC_USE_COUNT;
|
MOD_DEC_USE_COUNT;
|
}
|
}
|
|
|
/* This routine is called from an interrupt in ncp_msg_data_ready. So
|
/* This routine is called from an interrupt in ncp_msg_data_ready. So
|
* we have to be careful NOT to sleep here! */
|
* we have to be careful NOT to sleep here! */
|
void
|
void
|
ncp_trigger_message(struct ncp_server *server)
|
ncp_trigger_message(struct ncp_server *server)
|
{
|
{
|
#ifdef CONFIG_KERNELD
|
#ifdef CONFIG_KERNELD
|
char command[ sizeof(server->m.mount_point)
|
char command[ sizeof(server->m.mount_point)
|
+ sizeof(NCP_MSG_COMMAND) + 2];
|
+ sizeof(NCP_MSG_COMMAND) + 2];
|
#endif
|
#endif
|
|
|
if (server == NULL)
|
if (server == NULL)
|
{
|
{
|
printk("ncp_trigger_message: invalid server!\n");
|
printk("ncp_trigger_message: invalid server!\n");
|
return;
|
return;
|
}
|
}
|
|
|
DPRINTK("ncp_trigger_message: on %s\n",
|
DPRINTK("ncp_trigger_message: on %s\n",
|
server->m.mount_point);
|
server->m.mount_point);
|
|
|
#ifdef CONFIG_KERNELD
|
#ifdef CONFIG_KERNELD
|
strcpy(command, NCP_MSG_COMMAND);
|
strcpy(command, NCP_MSG_COMMAND);
|
strcat(command, " ");
|
strcat(command, " ");
|
strcat(command, server->m.mount_point);
|
strcat(command, server->m.mount_point);
|
DPRINTK("ksystem: %s\n", command);
|
DPRINTK("ksystem: %s\n", command);
|
ksystem(command, KERNELD_NOWAIT);
|
ksystem(command, KERNELD_NOWAIT);
|
#endif
|
#endif
|
}
|
}
|
|
|
static void
|
static void
|
ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
|
ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
|
{
|
{
|
struct statfs tmp;
|
struct statfs tmp;
|
|
|
/* We cannot say how much disk space is left on a mounted
|
/* We cannot say how much disk space is left on a mounted
|
NetWare Server, because free space is distributed over
|
NetWare Server, because free space is distributed over
|
volumes, and the current user might have disk quotas. So
|
volumes, and the current user might have disk quotas. So
|
free space is not that simple to determine. Our decision
|
free space is not that simple to determine. Our decision
|
here is to err conservatively. */
|
here is to err conservatively. */
|
|
|
tmp.f_type = NCP_SUPER_MAGIC;
|
tmp.f_type = NCP_SUPER_MAGIC;
|
tmp.f_bsize = 512;
|
tmp.f_bsize = 512;
|
tmp.f_blocks = 0;
|
tmp.f_blocks = 0;
|
tmp.f_bfree = 0;
|
tmp.f_bfree = 0;
|
tmp.f_bavail = 0;
|
tmp.f_bavail = 0;
|
tmp.f_files = -1;
|
tmp.f_files = -1;
|
tmp.f_ffree = -1;
|
tmp.f_ffree = -1;
|
tmp.f_namelen = 12;
|
tmp.f_namelen = 12;
|
memcpy_tofs(buf, &tmp, bufsiz);
|
memcpy_tofs(buf, &tmp, bufsiz);
|
}
|
}
|
|
|
int
|
int
|
ncp_notify_change(struct inode *inode, struct iattr *attr)
|
ncp_notify_change(struct inode *inode, struct iattr *attr)
|
{
|
{
|
int result = 0;
|
int result = 0;
|
int info_mask;
|
int info_mask;
|
struct nw_modify_dos_info info;
|
struct nw_modify_dos_info info;
|
|
|
if (!ncp_conn_valid(NCP_SERVER(inode)))
|
if (!ncp_conn_valid(NCP_SERVER(inode)))
|
{
|
{
|
return -EIO;
|
return -EIO;
|
}
|
}
|
|
|
if ((result = inode_change_ok(inode, attr)) < 0)
|
if ((result = inode_change_ok(inode, attr)) < 0)
|
return result;
|
return result;
|
|
|
if (((attr->ia_valid & ATTR_UID) &&
|
if (((attr->ia_valid & ATTR_UID) &&
|
(attr->ia_uid != NCP_SERVER(inode)->m.uid)))
|
(attr->ia_uid != NCP_SERVER(inode)->m.uid)))
|
return -EPERM;
|
return -EPERM;
|
|
|
if (((attr->ia_valid & ATTR_GID) &&
|
if (((attr->ia_valid & ATTR_GID) &&
|
(attr->ia_uid != NCP_SERVER(inode)->m.gid)))
|
(attr->ia_uid != NCP_SERVER(inode)->m.gid)))
|
return -EPERM;
|
return -EPERM;
|
|
|
if (((attr->ia_valid & ATTR_MODE) &&
|
if (((attr->ia_valid & ATTR_MODE) &&
|
(attr->ia_mode &
|
(attr->ia_mode &
|
~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
|
~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
|
return -EPERM;
|
return -EPERM;
|
|
|
info_mask = 0;
|
info_mask = 0;
|
memset(&info, 0, sizeof(info));
|
memset(&info, 0, sizeof(info));
|
|
|
#if 1
|
#if 1
|
if ((attr->ia_valid & ATTR_MODE) != 0)
|
if ((attr->ia_valid & ATTR_MODE) != 0)
|
{
|
{
|
if (NCP_ISTRUCT(inode)->attributes & aDIR)
|
if (NCP_ISTRUCT(inode)->attributes & aDIR)
|
{
|
{
|
return -EPERM;
|
return -EPERM;
|
}
|
}
|
else
|
else
|
{
|
{
|
umode_t newmode;
|
umode_t newmode;
|
|
|
info_mask |= DM_ATTRIBUTES;
|
info_mask |= DM_ATTRIBUTES;
|
newmode=attr->ia_mode;
|
newmode=attr->ia_mode;
|
newmode &= NCP_SERVER(inode)->m.file_mode;
|
newmode &= NCP_SERVER(inode)->m.file_mode;
|
|
|
if (newmode & 0222) /* any write bit set */
|
if (newmode & 0222) /* any write bit set */
|
{
|
{
|
info.attributes &= ~0x60001;
|
info.attributes &= ~0x60001;
|
}
|
}
|
else
|
else
|
{
|
{
|
info.attributes |= 0x60001;
|
info.attributes |= 0x60001;
|
}
|
}
|
}
|
}
|
}
|
}
|
#endif
|
#endif
|
|
|
if ((attr->ia_valid & ATTR_CTIME) != 0)
|
if ((attr->ia_valid & ATTR_CTIME) != 0)
|
{
|
{
|
info_mask |= (DM_CREATE_TIME|DM_CREATE_DATE);
|
info_mask |= (DM_CREATE_TIME|DM_CREATE_DATE);
|
ncp_date_unix2dos(attr->ia_ctime,
|
ncp_date_unix2dos(attr->ia_ctime,
|
&(info.creationTime), &(info.creationDate));
|
&(info.creationTime), &(info.creationDate));
|
}
|
}
|
|
|
if ((attr->ia_valid & ATTR_MTIME) != 0)
|
if ((attr->ia_valid & ATTR_MTIME) != 0)
|
{
|
{
|
info_mask |= (DM_MODIFY_TIME|DM_MODIFY_DATE);
|
info_mask |= (DM_MODIFY_TIME|DM_MODIFY_DATE);
|
ncp_date_unix2dos(attr->ia_mtime,
|
ncp_date_unix2dos(attr->ia_mtime,
|
&(info.modifyTime), &(info.modifyDate));
|
&(info.modifyTime), &(info.modifyDate));
|
}
|
}
|
|
|
if ((attr->ia_valid & ATTR_ATIME) != 0)
|
if ((attr->ia_valid & ATTR_ATIME) != 0)
|
{
|
{
|
__u16 dummy;
|
__u16 dummy;
|
info_mask |= (DM_LAST_ACCESS_DATE);
|
info_mask |= (DM_LAST_ACCESS_DATE);
|
ncp_date_unix2dos(attr->ia_ctime,
|
ncp_date_unix2dos(attr->ia_ctime,
|
&(dummy), &(info.lastAccessDate));
|
&(dummy), &(info.lastAccessDate));
|
}
|
}
|
|
|
if (info_mask != 0)
|
if (info_mask != 0)
|
{
|
{
|
if ((result =
|
if ((result =
|
ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
|
ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
|
NCP_ISTRUCT(inode),
|
NCP_ISTRUCT(inode),
|
info_mask,
|
info_mask,
|
&info)) != 0)
|
&info)) != 0)
|
{
|
{
|
result = -EACCES;
|
result = -EACCES;
|
|
|
if (info_mask == (DM_CREATE_TIME|DM_CREATE_DATE))
|
if (info_mask == (DM_CREATE_TIME|DM_CREATE_DATE))
|
{
|
{
|
/* NetWare seems not to allow this. I
|
/* NetWare seems not to allow this. I
|
do not know why. So, just tell the
|
do not know why. So, just tell the
|
user everything went fine. This is
|
user everything went fine. This is
|
a terrible hack, but I do not know
|
a terrible hack, but I do not know
|
how to do this correctly. */
|
how to do this correctly. */
|
result = 0;
|
result = 0;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
if ((attr->ia_valid & ATTR_SIZE) != 0)
|
if ((attr->ia_valid & ATTR_SIZE) != 0)
|
{
|
{
|
int written;
|
int written;
|
|
|
DPRINTK("ncpfs: trying to change size of %s to %ld\n",
|
DPRINTK("ncpfs: trying to change size of %s to %ld\n",
|
NCP_ISTRUCT(inode)->entryName, attr->ia_size);
|
NCP_ISTRUCT(inode)->entryName, attr->ia_size);
|
|
|
if ((result = ncp_make_open(inode, O_RDWR)) < 0)
|
if ((result = ncp_make_open(inode, O_RDWR)) < 0)
|
{
|
{
|
return -EACCES;
|
return -EACCES;
|
}
|
}
|
|
|
ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
|
ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
|
attr->ia_size, 0, "", &written);
|
attr->ia_size, 0, "", &written);
|
|
|
/* According to ndir, the changes only take effect after
|
/* According to ndir, the changes only take effect after
|
closing the file */
|
closing the file */
|
ncp_close_file(NCP_SERVER(inode),
|
ncp_close_file(NCP_SERVER(inode),
|
NCP_FINFO(inode)->file_handle);
|
NCP_FINFO(inode)->file_handle);
|
NCP_FINFO(inode)->opened = 0;
|
NCP_FINFO(inode)->opened = 0;
|
|
|
result = 0;
|
result = 0;
|
}
|
}
|
|
|
ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode);
|
ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode);
|
|
|
return result;
|
return result;
|
}
|
}
|
|
|
#ifdef DEBUG_NCP_MALLOC
|
#ifdef DEBUG_NCP_MALLOC
|
int ncp_malloced;
|
int ncp_malloced;
|
int ncp_current_malloced;
|
int ncp_current_malloced;
|
#endif
|
#endif
|
|
|
static struct file_system_type ncp_fs_type = {
|
static struct file_system_type ncp_fs_type = {
|
ncp_read_super, "ncpfs", 0, NULL
|
ncp_read_super, "ncpfs", 0, NULL
|
};
|
};
|
|
|
int init_ncp_fs(void)
|
int init_ncp_fs(void)
|
{
|
{
|
return register_filesystem(&ncp_fs_type);
|
return register_filesystem(&ncp_fs_type);
|
}
|
}
|
|
|
#ifdef MODULE
|
#ifdef MODULE
|
int
|
int
|
init_module( void)
|
init_module( void)
|
{
|
{
|
int status;
|
int status;
|
|
|
DPRINTK("ncpfs: init_module called\n");
|
DPRINTK("ncpfs: init_module called\n");
|
|
|
#ifdef DEBUG_NCP_MALLOC
|
#ifdef DEBUG_NCP_MALLOC
|
ncp_malloced = 0;
|
ncp_malloced = 0;
|
ncp_current_malloced = 0;
|
ncp_current_malloced = 0;
|
#endif
|
#endif
|
ncp_init_dir_cache();
|
ncp_init_dir_cache();
|
|
|
if ((status = init_ncp_fs()) == 0)
|
if ((status = init_ncp_fs()) == 0)
|
register_symtab(0);
|
register_symtab(0);
|
return status;
|
return status;
|
}
|
}
|
|
|
void
|
void
|
cleanup_module(void)
|
cleanup_module(void)
|
{
|
{
|
DPRINTK("ncpfs: cleanup_module called\n");
|
DPRINTK("ncpfs: cleanup_module called\n");
|
ncp_free_dir_cache();
|
ncp_free_dir_cache();
|
unregister_filesystem(&ncp_fs_type);
|
unregister_filesystem(&ncp_fs_type);
|
#ifdef DEBUG_NCP_MALLOC
|
#ifdef DEBUG_NCP_MALLOC
|
printk("ncp_malloced: %d\n", ncp_malloced);
|
printk("ncp_malloced: %d\n", ncp_malloced);
|
printk("ncp_current_malloced: %d\n", ncp_current_malloced);
|
printk("ncp_current_malloced: %d\n", ncp_current_malloced);
|
#endif
|
#endif
|
}
|
}
|
|
|
#endif
|
#endif
|
|
|