/*
|
/*
|
* dir.c
|
* dir.c
|
*
|
*
|
* Copyright (C) 1995, 1996 by Volker Lendecke
|
* Copyright (C) 1995, 1996 by Volker Lendecke
|
*
|
*
|
*/
|
*/
|
|
|
#include <linux/config.h>
|
#include <linux/config.h>
|
|
|
#include <linux/sched.h>
|
#include <linux/sched.h>
|
#include <linux/errno.h>
|
#include <linux/errno.h>
|
#include <linux/stat.h>
|
#include <linux/stat.h>
|
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
#include <linux/malloc.h>
|
#include <linux/malloc.h>
|
#include <linux/mm.h>
|
#include <linux/mm.h>
|
#include <linux/ncp_fs.h>
|
#include <linux/ncp_fs.h>
|
#include <asm/segment.h>
|
#include <asm/segment.h>
|
#include <linux/errno.h>
|
#include <linux/errno.h>
|
#include <linux/locks.h>
|
#include <linux/locks.h>
|
#include "ncplib_kernel.h"
|
#include "ncplib_kernel.h"
|
|
|
struct ncp_dirent {
|
struct ncp_dirent {
|
struct nw_info_struct i;
|
struct nw_info_struct i;
|
struct nw_search_sequence s; /* given back for i */
|
struct nw_search_sequence s; /* given back for i */
|
unsigned long f_pos;
|
unsigned long f_pos;
|
};
|
};
|
|
|
static int
|
static int
|
ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count);
|
ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count);
|
|
|
static int
|
static int
|
ncp_readdir(struct inode *inode, struct file *filp,
|
ncp_readdir(struct inode *inode, struct file *filp,
|
void *dirent, filldir_t filldir);
|
void *dirent, filldir_t filldir);
|
|
|
static int
|
static int
|
ncp_read_volume_list(struct ncp_server *server, int start_with,
|
ncp_read_volume_list(struct ncp_server *server, int start_with,
|
int cache_size);
|
int cache_size);
|
|
|
static int
|
static int
|
ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
|
ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
|
int cache_size, struct ncp_dirent *entry);
|
int cache_size, struct ncp_dirent *entry);
|
|
|
static struct inode *
|
static struct inode *
|
ncp_iget(struct inode *dir, struct nw_file_info *finfo);
|
ncp_iget(struct inode *dir, struct nw_file_info *finfo);
|
|
|
static struct ncp_inode_info *
|
static struct ncp_inode_info *
|
ncp_find_dir_inode(struct inode *dir, const char *name);
|
ncp_find_dir_inode(struct inode *dir, const char *name);
|
|
|
static int
|
static int
|
ncp_lookup(struct inode *dir, const char *__name,
|
ncp_lookup(struct inode *dir, const char *__name,
|
int len, struct inode **result);
|
int len, struct inode **result);
|
|
|
static int
|
static int
|
ncp_create(struct inode *dir, const char *name, int len, int mode,
|
ncp_create(struct inode *dir, const char *name, int len, int mode,
|
struct inode **result);
|
struct inode **result);
|
|
|
static int
|
static int
|
ncp_mkdir(struct inode *dir, const char *name, int len, int mode);
|
ncp_mkdir(struct inode *dir, const char *name, int len, int mode);
|
|
|
static int
|
static int
|
ncp_rmdir(struct inode *dir, const char *name, int len);
|
ncp_rmdir(struct inode *dir, const char *name, int len);
|
|
|
static int
|
static int
|
ncp_unlink(struct inode *dir, const char *name, int len);
|
ncp_unlink(struct inode *dir, const char *name, int len);
|
|
|
static int
|
static int
|
ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
|
ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
|
struct inode *new_dir, const char *new_name, int new_len,
|
struct inode *new_dir, const char *new_name, int new_len,
|
int must_be_dir);
|
int must_be_dir);
|
|
|
static inline void
|
static inline void
|
str_upper(char *name)
|
str_upper(char *name)
|
{
|
{
|
while (*name)
|
while (*name)
|
{
|
{
|
if (*name >= 'a' && *name <= 'z')
|
if (*name >= 'a' && *name <= 'z')
|
{
|
{
|
*name -= ('a' - 'A');
|
*name -= ('a' - 'A');
|
}
|
}
|
name++;
|
name++;
|
}
|
}
|
}
|
}
|
|
|
static inline void
|
static inline void
|
str_lower(char *name)
|
str_lower(char *name)
|
{
|
{
|
while (*name)
|
while (*name)
|
{
|
{
|
if (*name >= 'A' && *name <= 'Z')
|
if (*name >= 'A' && *name <= 'Z')
|
{
|
{
|
*name += ('a' - 'A');
|
*name += ('a' - 'A');
|
}
|
}
|
name ++;
|
name ++;
|
}
|
}
|
}
|
}
|
|
|
static inline int
|
static inline int
|
ncp_namespace(struct inode *i)
|
ncp_namespace(struct inode *i)
|
{
|
{
|
struct ncp_server *server = NCP_SERVER(i);
|
struct ncp_server *server = NCP_SERVER(i);
|
struct nw_info_struct *info = NCP_ISTRUCT(i);
|
struct nw_info_struct *info = NCP_ISTRUCT(i);
|
return server->name_space[info->volNumber];
|
return server->name_space[info->volNumber];
|
}
|
}
|
|
|
static inline int
|
static inline int
|
ncp_preserve_case(struct inode *i)
|
ncp_preserve_case(struct inode *i)
|
{
|
{
|
return
|
return
|
#ifdef CONFIG_NCPFS_OS2_NS
|
#ifdef CONFIG_NCPFS_OS2_NS
|
(ncp_namespace(i) == NW_NS_OS2) ||
|
(ncp_namespace(i) == NW_NS_OS2) ||
|
#endif /* CONFIG_NCPFS_OS2_NS */
|
#endif /* CONFIG_NCPFS_OS2_NS */
|
#ifdef CONFIG_NCPFS_NFS_NS
|
#ifdef CONFIG_NCPFS_NFS_NS
|
(ncp_namespace(i) == NW_NS_NFS) ||
|
(ncp_namespace(i) == NW_NS_NFS) ||
|
#endif /* CONFIG_NCPFS_NFS_NS */
|
#endif /* CONFIG_NCPFS_NFS_NS */
|
0;
|
0;
|
}
|
}
|
|
|
static struct file_operations ncp_dir_operations = {
|
static struct file_operations ncp_dir_operations = {
|
NULL, /* lseek - default */
|
NULL, /* lseek - default */
|
ncp_dir_read, /* read - bad */
|
ncp_dir_read, /* read - bad */
|
NULL, /* write - bad */
|
NULL, /* write - bad */
|
ncp_readdir, /* readdir */
|
ncp_readdir, /* readdir */
|
NULL, /* select - default */
|
NULL, /* select - default */
|
ncp_ioctl, /* ioctl */
|
ncp_ioctl, /* ioctl */
|
NULL, /* mmap */
|
NULL, /* mmap */
|
NULL, /* no special open code */
|
NULL, /* no special open code */
|
NULL, /* no special release code */
|
NULL, /* no special release code */
|
NULL /* fsync */
|
NULL /* fsync */
|
};
|
};
|
|
|
struct inode_operations ncp_dir_inode_operations = {
|
struct inode_operations ncp_dir_inode_operations = {
|
&ncp_dir_operations, /* default directory file ops */
|
&ncp_dir_operations, /* default directory file ops */
|
ncp_create, /* create */
|
ncp_create, /* create */
|
ncp_lookup, /* lookup */
|
ncp_lookup, /* lookup */
|
NULL, /* link */
|
NULL, /* link */
|
ncp_unlink, /* unlink */
|
ncp_unlink, /* unlink */
|
NULL, /* symlink */
|
NULL, /* symlink */
|
ncp_mkdir, /* mkdir */
|
ncp_mkdir, /* mkdir */
|
ncp_rmdir, /* rmdir */
|
ncp_rmdir, /* rmdir */
|
NULL, /* mknod */
|
NULL, /* mknod */
|
ncp_rename, /* rename */
|
ncp_rename, /* rename */
|
NULL, /* readlink */
|
NULL, /* readlink */
|
NULL, /* follow_link */
|
NULL, /* follow_link */
|
NULL, /* bmap */
|
NULL, /* bmap */
|
NULL, /* truncate */
|
NULL, /* truncate */
|
NULL, /* permission */
|
NULL, /* permission */
|
NULL /* smap */
|
NULL /* smap */
|
};
|
};
|
|
|
|
|
/* Here we encapsulate the inode number handling that depends upon the
|
/* Here we encapsulate the inode number handling that depends upon the
|
* mount mode: When we mount a complete server, the memory address of
|
* mount mode: When we mount a complete server, the memory address of
|
* the ncp_inode_info is used as the inode number. When only a single
|
* the ncp_inode_info is used as the inode number. When only a single
|
* volume is mounted, then the dirEntNum is used as the inode
|
* volume is mounted, then the dirEntNum is used as the inode
|
* number. As this is unique for the complete volume, this should
|
* number. As this is unique for the complete volume, this should
|
* enable the NFS exportability of a ncpfs-mounted volume.
|
* enable the NFS exportability of a ncpfs-mounted volume.
|
*/
|
*/
|
|
|
static inline int
|
static inline int
|
ncp_single_volume(struct ncp_server *server)
|
ncp_single_volume(struct ncp_server *server)
|
{
|
{
|
return (server->m.mounted_vol[0] != '\0');
|
return (server->m.mounted_vol[0] != '\0');
|
}
|
}
|
|
|
inline ino_t
|
inline ino_t
|
ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info)
|
ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info)
|
{
|
{
|
return ncp_single_volume(server)
|
return ncp_single_volume(server)
|
? (info->finfo.i.dirEntNum == server->root.finfo.i.dirEntNum)?0:info->finfo.i.dirEntNum: (ino_t)info;
|
? (info->finfo.i.dirEntNum == server->root.finfo.i.dirEntNum)?0:info->finfo.i.dirEntNum: (ino_t)info;
|
}
|
}
|
|
|
static inline int
|
static inline int
|
ncp_is_server_root(struct inode *inode)
|
ncp_is_server_root(struct inode *inode)
|
{
|
{
|
struct ncp_server *s = NCP_SERVER(inode);
|
struct ncp_server *s = NCP_SERVER(inode);
|
|
|
return ( (!ncp_single_volume(s))
|
return ( (!ncp_single_volume(s))
|
&& (inode->i_ino == ncp_info_ino(s, &(s->root))));
|
&& (inode->i_ino == ncp_info_ino(s, &(s->root))));
|
}
|
}
|
|
|
struct ncp_inode_info *
|
struct ncp_inode_info *
|
ncp_find_inode(struct inode *inode)
|
ncp_find_inode(struct inode *inode)
|
{
|
{
|
struct ncp_server *server = NCP_SERVER(inode);
|
struct ncp_server *server = NCP_SERVER(inode);
|
struct ncp_inode_info *root = &(server->root);
|
struct ncp_inode_info *root = &(server->root);
|
struct ncp_inode_info *this = root;
|
struct ncp_inode_info *this = root;
|
|
|
ino_t ino = inode->i_ino;
|
ino_t ino = inode->i_ino;
|
|
|
do
|
do
|
{
|
{
|
if (ino == ncp_info_ino(server, this))
|
if (ino == ncp_info_ino(server, this))
|
{
|
{
|
return this;
|
return this;
|
}
|
}
|
this = this->next;
|
this = this->next;
|
}
|
}
|
while (this != root);
|
while (this != root);
|
|
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
static int
|
static int
|
ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
|
ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
|
{
|
{
|
return -EISDIR;
|
return -EISDIR;
|
}
|
}
|
|
|
static kdev_t c_dev = 0;
|
static kdev_t c_dev = 0;
|
static unsigned long c_ino = 0;
|
static unsigned long c_ino = 0;
|
static int c_size;
|
static int c_size;
|
static int c_seen_eof;
|
static int c_seen_eof;
|
static int c_last_returned_index;
|
static int c_last_returned_index;
|
static struct ncp_dirent* c_entry = NULL;
|
static struct ncp_dirent* c_entry = NULL;
|
static int c_lock = 0;
|
static int c_lock = 0;
|
static struct wait_queue *c_wait = NULL;
|
static struct wait_queue *c_wait = NULL;
|
|
|
static inline void
|
static inline void
|
ncp_lock_dircache(void)
|
ncp_lock_dircache(void)
|
{
|
{
|
while (c_lock)
|
while (c_lock)
|
sleep_on(&c_wait);
|
sleep_on(&c_wait);
|
c_lock = 1;
|
c_lock = 1;
|
}
|
}
|
|
|
static inline void
|
static inline void
|
ncp_unlock_dircache(void)
|
ncp_unlock_dircache(void)
|
{
|
{
|
c_lock = 0;
|
c_lock = 0;
|
wake_up(&c_wait);
|
wake_up(&c_wait);
|
}
|
}
|
|
|
static int
|
static int
|
ncp_readdir(struct inode *inode, struct file *filp,
|
ncp_readdir(struct inode *inode, struct file *filp,
|
void *dirent, filldir_t filldir)
|
void *dirent, filldir_t filldir)
|
{
|
{
|
int result = 0;
|
int result = 0;
|
int i = 0;
|
int i = 0;
|
int index = 0;
|
int index = 0;
|
struct ncp_dirent *entry = NULL;
|
struct ncp_dirent *entry = NULL;
|
struct ncp_server *server = NCP_SERVER(inode);
|
struct ncp_server *server = NCP_SERVER(inode);
|
struct ncp_inode_info *dir = NCP_INOP(inode);
|
struct ncp_inode_info *dir = NCP_INOP(inode);
|
|
|
DDPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos);
|
DDPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos);
|
DDPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
|
DDPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
|
inode->i_ino, c_ino);
|
inode->i_ino, c_ino);
|
|
|
if (!inode || !S_ISDIR(inode->i_mode))
|
if (!inode || !S_ISDIR(inode->i_mode))
|
{
|
{
|
printk("ncp_readdir: inode is NULL or not a directory\n");
|
printk("ncp_readdir: inode is NULL or not a directory\n");
|
return -EBADF;
|
return -EBADF;
|
}
|
}
|
|
|
if (!ncp_conn_valid(server))
|
if (!ncp_conn_valid(server))
|
{
|
{
|
return -EIO;
|
return -EIO;
|
}
|
}
|
|
|
ncp_lock_dircache();
|
ncp_lock_dircache();
|
|
|
if (c_entry == NULL)
|
if (c_entry == NULL)
|
{
|
{
|
i = sizeof (struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
|
i = sizeof (struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
|
c_entry = (struct ncp_dirent *) vmalloc(i);
|
c_entry = (struct ncp_dirent *) vmalloc(i);
|
if (c_entry == NULL)
|
if (c_entry == NULL)
|
{
|
{
|
printk("ncp_readdir: no MEMORY for cache\n");
|
printk("ncp_readdir: no MEMORY for cache\n");
|
result = -ENOMEM;
|
result = -ENOMEM;
|
goto finished;
|
goto finished;
|
}
|
}
|
}
|
}
|
|
|
if (filp->f_pos == 0)
|
if (filp->f_pos == 0)
|
{
|
{
|
ncp_invalid_dir_cache(inode);
|
ncp_invalid_dir_cache(inode);
|
if (filldir(dirent,".",1, filp->f_pos,
|
if (filldir(dirent,".",1, filp->f_pos,
|
ncp_info_ino(server, dir)) < 0)
|
ncp_info_ino(server, dir)) < 0)
|
{
|
{
|
goto finished;
|
goto finished;
|
}
|
}
|
filp->f_pos += 1;
|
filp->f_pos += 1;
|
}
|
}
|
|
|
if (filp->f_pos == 1)
|
if (filp->f_pos == 1)
|
{
|
{
|
if (filldir(dirent,"..",2, filp->f_pos,
|
if (filldir(dirent,"..",2, filp->f_pos,
|
ncp_info_ino(server, dir->dir)) < 0)
|
ncp_info_ino(server, dir->dir)) < 0)
|
{
|
{
|
goto finished;
|
goto finished;
|
}
|
}
|
filp->f_pos += 1;
|
filp->f_pos += 1;
|
}
|
}
|
|
|
if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino))
|
if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino))
|
{
|
{
|
for (i = 0; i < c_size; i++)
|
for (i = 0; i < c_size; i++)
|
{
|
{
|
if (filp->f_pos == c_entry[i].f_pos)
|
if (filp->f_pos == c_entry[i].f_pos)
|
{
|
{
|
entry = &c_entry[i];
|
entry = &c_entry[i];
|
c_last_returned_index = i;
|
c_last_returned_index = i;
|
index = i;
|
index = i;
|
break;
|
break;
|
}
|
}
|
}
|
}
|
if ((entry == NULL) && c_seen_eof)
|
if ((entry == NULL) && c_seen_eof)
|
{
|
{
|
goto finished;
|
goto finished;
|
}
|
}
|
}
|
}
|
|
|
if (entry == NULL)
|
if (entry == NULL)
|
{
|
{
|
int entries;
|
int entries;
|
DDPRINTK("ncp_readdir: Not found in cache.\n");
|
DDPRINTK("ncp_readdir: Not found in cache.\n");
|
|
|
if (ncp_is_server_root(inode))
|
if (ncp_is_server_root(inode))
|
{
|
{
|
entries = ncp_read_volume_list(server, filp->f_pos,
|
entries = ncp_read_volume_list(server, filp->f_pos,
|
NCP_READDIR_CACHE_SIZE);
|
NCP_READDIR_CACHE_SIZE);
|
DPRINTK("ncp_read_volume_list returned %d\n", entries);
|
DPRINTK("ncp_read_volume_list returned %d\n", entries);
|
|
|
}
|
}
|
else
|
else
|
{
|
{
|
entries = ncp_do_readdir(server, inode, filp->f_pos,
|
entries = ncp_do_readdir(server, inode, filp->f_pos,
|
NCP_READDIR_CACHE_SIZE,
|
NCP_READDIR_CACHE_SIZE,
|
c_entry);
|
c_entry);
|
DPRINTK("ncp_readdir returned %d\n", entries);
|
DPRINTK("ncp_readdir returned %d\n", entries);
|
}
|
}
|
|
|
if (entries < 0)
|
if (entries < 0)
|
{
|
{
|
c_dev = 0;
|
c_dev = 0;
|
c_ino = 0;
|
c_ino = 0;
|
result = entries;
|
result = entries;
|
goto finished;
|
goto finished;
|
}
|
}
|
|
|
if (entries > 0)
|
if (entries > 0)
|
{
|
{
|
c_seen_eof = (entries < NCP_READDIR_CACHE_SIZE);
|
c_seen_eof = (entries < NCP_READDIR_CACHE_SIZE);
|
c_dev = inode->i_dev;
|
c_dev = inode->i_dev;
|
c_ino = inode->i_ino;
|
c_ino = inode->i_ino;
|
c_size = entries;
|
c_size = entries;
|
entry = c_entry;
|
entry = c_entry;
|
c_last_returned_index = 0;
|
c_last_returned_index = 0;
|
index = 0;
|
index = 0;
|
|
|
if (!ncp_preserve_case(inode))
|
if (!ncp_preserve_case(inode))
|
{
|
{
|
for (i = 0; i < c_size; i++)
|
for (i = 0; i < c_size; i++)
|
{
|
{
|
str_lower(c_entry[i].i.entryName);
|
str_lower(c_entry[i].i.entryName);
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
if (entry == NULL)
|
if (entry == NULL)
|
{
|
{
|
/* Nothing found, even from a ncp call */
|
/* Nothing found, even from a ncp call */
|
goto finished;
|
goto finished;
|
}
|
}
|
|
|
while (index < c_size)
|
while (index < c_size)
|
{
|
{
|
ino_t ino;
|
ino_t ino;
|
|
|
if (ncp_single_volume(server))
|
if (ncp_single_volume(server))
|
{
|
{
|
ino = (ino_t)(entry->i.dirEntNum);
|
ino = (ino_t)(entry->i.dirEntNum);
|
}
|
}
|
else
|
else
|
{
|
{
|
/* For getwd() we have to return the correct
|
/* For getwd() we have to return the correct
|
* inode in d_ino if the inode is currently in
|
* inode in d_ino if the inode is currently in
|
* use. Otherwise the inode number does not
|
* use. Otherwise the inode number does not
|
* matter. (You can argue a lot about this..) */
|
* matter. (You can argue a lot about this..) */
|
struct ncp_inode_info *ino_info;
|
struct ncp_inode_info *ino_info;
|
ino_info = ncp_find_dir_inode(inode,
|
ino_info = ncp_find_dir_inode(inode,
|
entry->i.entryName);
|
entry->i.entryName);
|
|
|
/* Some programs seem to be confused about a
|
/* Some programs seem to be confused about a
|
* zero inode number, so we set it to one.
|
* zero inode number, so we set it to one.
|
* Thanks to Gordon Chaffee for this one. */
|
* Thanks to Gordon Chaffee for this one. */
|
if (ino_info == NULL)
|
if (ino_info == NULL)
|
{
|
{
|
ino_info = (struct ncp_inode_info *) 1;
|
ino_info = (struct ncp_inode_info *) 1;
|
}
|
}
|
ino = (ino_t)(ino_info);
|
ino = (ino_t)(ino_info);
|
}
|
}
|
|
|
DDPRINTK("ncp_readdir: entry->path= %s\n", entry->i.entryName);
|
DDPRINTK("ncp_readdir: entry->path= %s\n", entry->i.entryName);
|
DDPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
|
DDPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
|
|
|
if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
|
if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
|
entry->f_pos, ino) < 0)
|
entry->f_pos, ino) < 0)
|
{
|
{
|
break;
|
break;
|
}
|
}
|
|
|
if ( (inode->i_dev != c_dev)
|
if ( (inode->i_dev != c_dev)
|
|| (inode->i_ino != c_ino)
|
|| (inode->i_ino != c_ino)
|
|| (entry->f_pos != filp->f_pos))
|
|| (entry->f_pos != filp->f_pos))
|
{
|
{
|
/* Someone has destroyed the cache while we slept
|
/* Someone has destroyed the cache while we slept
|
in filldir */
|
in filldir */
|
break;
|
break;
|
}
|
}
|
filp->f_pos += 1;
|
filp->f_pos += 1;
|
index += 1;
|
index += 1;
|
entry += 1;
|
entry += 1;
|
}
|
}
|
finished:
|
finished:
|
ncp_unlock_dircache();
|
ncp_unlock_dircache();
|
return result;
|
return result;
|
}
|
}
|
|
|
static int
|
static int
|
ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
|
ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
|
{
|
{
|
struct ncp_dirent *entry = c_entry;
|
struct ncp_dirent *entry = c_entry;
|
|
|
int total_count = 2;
|
int total_count = 2;
|
int i;
|
int i;
|
|
|
#if 1
|
#if 1
|
if (fpos < 2)
|
if (fpos < 2)
|
{
|
{
|
printk("OOPS, we expect fpos >= 2");
|
printk("OOPS, we expect fpos >= 2");
|
fpos = 2;
|
fpos = 2;
|
}
|
}
|
#endif
|
#endif
|
|
|
for (i=0; i<NCP_NUMBER_OF_VOLUMES; i++)
|
for (i=0; i<NCP_NUMBER_OF_VOLUMES; i++)
|
{
|
{
|
struct ncp_volume_info info;
|
struct ncp_volume_info info;
|
|
|
if (ncp_get_volume_info_with_number(server, i, &info) != 0)
|
if (ncp_get_volume_info_with_number(server, i, &info) != 0)
|
{
|
{
|
return (total_count - fpos);
|
return (total_count - fpos);
|
}
|
}
|
|
|
if (strlen(info.volume_name) > 0)
|
if (strlen(info.volume_name) > 0)
|
{
|
{
|
if (total_count < fpos)
|
if (total_count < fpos)
|
{
|
{
|
DPRINTK("ncp_read_volumes: skipped vol: %s\n",
|
DPRINTK("ncp_read_volumes: skipped vol: %s\n",
|
info.volume_name);
|
info.volume_name);
|
}
|
}
|
else if (total_count >= fpos + cache_size)
|
else if (total_count >= fpos + cache_size)
|
{
|
{
|
return (total_count - fpos);
|
return (total_count - fpos);
|
}
|
}
|
else
|
else
|
{
|
{
|
DPRINTK("ncp_read_volumes: found vol: %s\n",
|
DPRINTK("ncp_read_volumes: found vol: %s\n",
|
info.volume_name);
|
info.volume_name);
|
|
|
if (ncp_lookup_volume(server,
|
if (ncp_lookup_volume(server,
|
info.volume_name,
|
info.volume_name,
|
&(entry->i)) != 0)
|
&(entry->i)) != 0)
|
{
|
{
|
DPRINTK("ncpfs: could not lookup vol "
|
DPRINTK("ncpfs: could not lookup vol "
|
"%s\n", info.volume_name);
|
"%s\n", info.volume_name);
|
continue;
|
continue;
|
}
|
}
|
|
|
entry->f_pos = total_count;
|
entry->f_pos = total_count;
|
entry += 1;
|
entry += 1;
|
}
|
}
|
total_count += 1;
|
total_count += 1;
|
}
|
}
|
}
|
}
|
return (total_count - fpos);
|
return (total_count - fpos);
|
}
|
}
|
|
|
static int
|
static int
|
ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
|
ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
|
int cache_size, struct ncp_dirent *entry)
|
int cache_size, struct ncp_dirent *entry)
|
{
|
{
|
static struct nw_search_sequence seq;
|
static struct nw_search_sequence seq;
|
static struct inode *last_dir;
|
static struct inode *last_dir;
|
static int total_count;
|
static int total_count;
|
|
|
#if 1
|
#if 1
|
if (fpos < 2)
|
if (fpos < 2)
|
{
|
{
|
printk("OOPS, we expect fpos >= 2");
|
printk("OOPS, we expect fpos >= 2");
|
fpos = 2;
|
fpos = 2;
|
}
|
}
|
#endif
|
#endif
|
DPRINTK("ncp_do_readdir: fpos = %d\n", fpos);
|
DPRINTK("ncp_do_readdir: fpos = %d\n", fpos);
|
|
|
if (fpos == 2)
|
if (fpos == 2)
|
{
|
{
|
last_dir = NULL;
|
last_dir = NULL;
|
total_count = 2;
|
total_count = 2;
|
}
|
}
|
|
|
if ((fpos != total_count) || (dir != last_dir))
|
if ((fpos != total_count) || (dir != last_dir))
|
{
|
{
|
total_count = 2;
|
total_count = 2;
|
last_dir = dir;
|
last_dir = dir;
|
|
|
DPRINTK("ncp_do_readdir: re-used seq for %s\n",
|
DPRINTK("ncp_do_readdir: re-used seq for %s\n",
|
NCP_ISTRUCT(dir)->entryName);
|
NCP_ISTRUCT(dir)->entryName);
|
|
|
if (ncp_initialize_search(server, NCP_ISTRUCT(dir), &seq)!=0)
|
if (ncp_initialize_search(server, NCP_ISTRUCT(dir), &seq)!=0)
|
{
|
{
|
DPRINTK("ncp_init_search failed\n");
|
DPRINTK("ncp_init_search failed\n");
|
return total_count - fpos;
|
return total_count - fpos;
|
}
|
}
|
}
|
}
|
|
|
while (total_count < fpos + cache_size)
|
while (total_count < fpos + cache_size)
|
{
|
{
|
if (ncp_search_for_file_or_subdir(server, &seq,
|
if (ncp_search_for_file_or_subdir(server, &seq,
|
&(entry->i)) != 0)
|
&(entry->i)) != 0)
|
{
|
{
|
return total_count - fpos;
|
return total_count - fpos;
|
}
|
}
|
|
|
if (total_count < fpos)
|
if (total_count < fpos)
|
{
|
{
|
DPRINTK("ncp_do_readdir: skipped file: %s\n",
|
DPRINTK("ncp_do_readdir: skipped file: %s\n",
|
entry->i.entryName);
|
entry->i.entryName);
|
}
|
}
|
else
|
else
|
{
|
{
|
DDPRINTK("ncp_do_r: file: %s, f_pos=%d,total_count=%d",
|
DDPRINTK("ncp_do_r: file: %s, f_pos=%d,total_count=%d",
|
entry->i.entryName, fpos, total_count);
|
entry->i.entryName, fpos, total_count);
|
entry->s = seq;
|
entry->s = seq;
|
entry->f_pos = total_count;
|
entry->f_pos = total_count;
|
entry += 1;
|
entry += 1;
|
}
|
}
|
total_count += 1;
|
total_count += 1;
|
}
|
}
|
return (total_count - fpos);
|
return (total_count - fpos);
|
}
|
}
|
|
|
void
|
void
|
ncp_init_dir_cache(void)
|
ncp_init_dir_cache(void)
|
{
|
{
|
c_dev = 0;
|
c_dev = 0;
|
c_ino = 0;
|
c_ino = 0;
|
c_entry = NULL;
|
c_entry = NULL;
|
}
|
}
|
|
|
void
|
void
|
ncp_invalid_dir_cache(struct inode *ino)
|
ncp_invalid_dir_cache(struct inode *ino)
|
{
|
{
|
if ((ino->i_dev == c_dev) && (ino->i_ino == c_ino))
|
if ((ino->i_dev == c_dev) && (ino->i_ino == c_ino))
|
{
|
{
|
c_dev = 0;
|
c_dev = 0;
|
c_ino = 0;
|
c_ino = 0;
|
c_seen_eof = 0;
|
c_seen_eof = 0;
|
}
|
}
|
}
|
}
|
|
|
void
|
void
|
ncp_free_dir_cache(void)
|
ncp_free_dir_cache(void)
|
{
|
{
|
DPRINTK("ncp_free_dir_cache: enter\n");
|
DPRINTK("ncp_free_dir_cache: enter\n");
|
|
|
if (c_entry == NULL)
|
if (c_entry == NULL)
|
{
|
{
|
return;
|
return;
|
}
|
}
|
|
|
vfree(c_entry);
|
vfree(c_entry);
|
c_entry = NULL;
|
c_entry = NULL;
|
|
|
DPRINTK("ncp_free_dir_cache: exit\n");
|
DPRINTK("ncp_free_dir_cache: exit\n");
|
}
|
}
|
|
|
|
|
static struct inode *
|
static struct inode *
|
ncp_iget(struct inode *dir, struct nw_file_info *finfo)
|
ncp_iget(struct inode *dir, struct nw_file_info *finfo)
|
{
|
{
|
struct inode *inode;
|
struct inode *inode;
|
struct ncp_inode_info *new_inode_info;
|
struct ncp_inode_info *new_inode_info;
|
struct ncp_inode_info *root;
|
struct ncp_inode_info *root;
|
|
|
if (dir == NULL)
|
if (dir == NULL)
|
{
|
{
|
printk("ncp_iget: dir is NULL\n");
|
printk("ncp_iget: dir is NULL\n");
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
if (finfo == NULL)
|
if (finfo == NULL)
|
{
|
{
|
printk("ncp_iget: finfo is NULL\n");
|
printk("ncp_iget: finfo is NULL\n");
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
new_inode_info = ncp_kmalloc(sizeof(struct ncp_inode_info),
|
new_inode_info = ncp_kmalloc(sizeof(struct ncp_inode_info),
|
GFP_KERNEL);
|
GFP_KERNEL);
|
|
|
if (new_inode_info == NULL)
|
if (new_inode_info == NULL)
|
{
|
{
|
printk("ncp_iget: could not alloc mem for %s\n",
|
printk("ncp_iget: could not alloc mem for %s\n",
|
finfo->i.entryName);
|
finfo->i.entryName);
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
new_inode_info->state = NCP_INODE_LOOKED_UP;
|
new_inode_info->state = NCP_INODE_LOOKED_UP;
|
new_inode_info->nused = 0;
|
new_inode_info->nused = 0;
|
new_inode_info->dir = NCP_INOP(dir);
|
new_inode_info->dir = NCP_INOP(dir);
|
new_inode_info->finfo = *finfo;
|
new_inode_info->finfo = *finfo;
|
|
|
NCP_INOP(dir)->nused += 1;
|
NCP_INOP(dir)->nused += 1;
|
|
|
/* We have to link the new inode_info into the doubly linked
|
/* We have to link the new inode_info into the doubly linked
|
list of inode_infos to make a complete linear search
|
list of inode_infos to make a complete linear search
|
possible. */
|
possible. */
|
|
|
root = &(NCP_SERVER(dir)->root);
|
root = &(NCP_SERVER(dir)->root);
|
|
|
new_inode_info->prev = root;
|
new_inode_info->prev = root;
|
new_inode_info->next = root->next;
|
new_inode_info->next = root->next;
|
root->next->prev = new_inode_info;
|
root->next->prev = new_inode_info;
|
root->next = new_inode_info;
|
root->next = new_inode_info;
|
|
|
if (!(inode = iget(dir->i_sb, ncp_info_ino(NCP_SERVER(dir),
|
if (!(inode = iget(dir->i_sb, ncp_info_ino(NCP_SERVER(dir),
|
new_inode_info))))
|
new_inode_info))))
|
{
|
{
|
printk("ncp_iget: iget failed!");
|
printk("ncp_iget: iget failed!");
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
return inode;
|
return inode;
|
}
|
}
|
|
|
void
|
void
|
ncp_free_inode_info(struct ncp_inode_info *i)
|
ncp_free_inode_info(struct ncp_inode_info *i)
|
{
|
{
|
if (i == NULL)
|
if (i == NULL)
|
{
|
{
|
printk("ncp_free_inode: i == NULL\n");
|
printk("ncp_free_inode: i == NULL\n");
|
return;
|
return;
|
}
|
}
|
|
|
i->state = NCP_INODE_CACHED;
|
i->state = NCP_INODE_CACHED;
|
while ((i->nused == 0) && (i->state == NCP_INODE_CACHED))
|
while ((i->nused == 0) && (i->state == NCP_INODE_CACHED))
|
{
|
{
|
struct ncp_inode_info *dir = i->dir;
|
struct ncp_inode_info *dir = i->dir;
|
|
|
i->next->prev = i->prev;
|
i->next->prev = i->prev;
|
i->prev->next = i->next;
|
i->prev->next = i->next;
|
|
|
DDPRINTK("ncp_free_inode_info: freeing %s\n",
|
DDPRINTK("ncp_free_inode_info: freeing %s\n",
|
i->finfo.i.entryName);
|
i->finfo.i.entryName);
|
|
|
ncp_kfree_s(i, sizeof(struct ncp_inode_info));
|
ncp_kfree_s(i, sizeof(struct ncp_inode_info));
|
|
|
if (dir == i) return;
|
if (dir == i) return;
|
|
|
(dir->nused)--;
|
(dir->nused)--;
|
i = dir;
|
i = dir;
|
}
|
}
|
}
|
}
|
|
|
void
|
void
|
ncp_init_root(struct ncp_server *server)
|
ncp_init_root(struct ncp_server *server)
|
{
|
{
|
struct ncp_inode_info *root = &(server->root);
|
struct ncp_inode_info *root = &(server->root);
|
struct nw_info_struct *i = &(root->finfo.i);
|
struct nw_info_struct *i = &(root->finfo.i);
|
unsigned short dummy;
|
unsigned short dummy;
|
|
|
DPRINTK("ncp_init_root: server %s\n", server->m.server_name);
|
DPRINTK("ncp_init_root: server %s\n", server->m.server_name);
|
DPRINTK("ncp_init_root: i = %x\n", (int)i);
|
DPRINTK("ncp_init_root: i = %x\n", (int)i);
|
|
|
root->finfo.opened = 0;
|
root->finfo.opened = 0;
|
i->attributes = aDIR;
|
i->attributes = aDIR;
|
i->dataStreamSize = 1024;
|
i->dataStreamSize = 1024;
|
i->dirEntNum = i->DosDirNum = 0;
|
i->dirEntNum = i->DosDirNum = 0;
|
i->volNumber = NCP_NUMBER_OF_VOLUMES+1; /* illegal volnum */
|
i->volNumber = NCP_NUMBER_OF_VOLUMES+1; /* illegal volnum */
|
ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
|
ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
|
ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate));
|
ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate));
|
ncp_date_unix2dos(0, &dummy, &(i->lastAccessDate));
|
ncp_date_unix2dos(0, &dummy, &(i->lastAccessDate));
|
i->nameLen = 0;
|
i->nameLen = 0;
|
i->entryName[0] = '\0';
|
i->entryName[0] = '\0';
|
|
|
root->state = NCP_INODE_LOOKED_UP;
|
root->state = NCP_INODE_LOOKED_UP;
|
root->nused = 1;
|
root->nused = 1;
|
root->dir = root;
|
root->dir = root;
|
root->next = root->prev = root;
|
root->next = root->prev = root;
|
return;
|
return;
|
}
|
}
|
|
|
int
|
int
|
ncp_conn_logged_in(struct ncp_server *server)
|
ncp_conn_logged_in(struct ncp_server *server)
|
{
|
{
|
if (server->m.mounted_vol[0] == '\0')
|
if (server->m.mounted_vol[0] == '\0')
|
{
|
{
|
return 0;
|
return 0;
|
}
|
}
|
|
|
str_upper(server->m.mounted_vol);
|
str_upper(server->m.mounted_vol);
|
if (ncp_lookup_volume(server, server->m.mounted_vol,
|
if (ncp_lookup_volume(server, server->m.mounted_vol,
|
&(server->root.finfo.i)) != 0)
|
&(server->root.finfo.i)) != 0)
|
{
|
{
|
return -ENOENT;
|
return -ENOENT;
|
}
|
}
|
str_lower(server->root.finfo.i.entryName);
|
str_lower(server->root.finfo.i.entryName);
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
void
|
void
|
ncp_free_all_inodes(struct ncp_server *server)
|
ncp_free_all_inodes(struct ncp_server *server)
|
{
|
{
|
/* Here nothing should be to do. I do not know whether it's
|
/* Here nothing should be to do. I do not know whether it's
|
better to leave some memory allocated or be stuck in an
|
better to leave some memory allocated or be stuck in an
|
endless loop */
|
endless loop */
|
#if 1
|
#if 1
|
struct ncp_inode_info *root = &(server->root);
|
struct ncp_inode_info *root = &(server->root);
|
|
|
if (root->next != root)
|
if (root->next != root)
|
{
|
{
|
printk("ncp_free_all_inodes: INODES LEFT!!!\n");
|
printk("ncp_free_all_inodes: INODES LEFT!!!\n");
|
}
|
}
|
|
|
while (root->next != root)
|
while (root->next != root)
|
{
|
{
|
printk("ncp_free_all_inodes: freeing inode\n");
|
printk("ncp_free_all_inodes: freeing inode\n");
|
ncp_free_inode_info(root->next);
|
ncp_free_inode_info(root->next);
|
/* In case we have an endless loop.. */
|
/* In case we have an endless loop.. */
|
schedule();
|
schedule();
|
}
|
}
|
#endif
|
#endif
|
|
|
return;
|
return;
|
}
|
}
|
|
|
/* We will search the inode that belongs to this name, currently by a
|
/* We will search the inode that belongs to this name, currently by a
|
complete linear search through the inodes belonging to this
|
complete linear search through the inodes belonging to this
|
filesystem. This has to be fixed. */
|
filesystem. This has to be fixed. */
|
static struct ncp_inode_info *
|
static struct ncp_inode_info *
|
ncp_find_dir_inode(struct inode *dir, const char *name)
|
ncp_find_dir_inode(struct inode *dir, const char *name)
|
{
|
{
|
struct ncp_server *server = NCP_SERVER(dir);
|
struct ncp_server *server = NCP_SERVER(dir);
|
struct nw_info_struct *dir_info = NCP_ISTRUCT(dir);
|
struct nw_info_struct *dir_info = NCP_ISTRUCT(dir);
|
struct ncp_inode_info *result = &(server->root);
|
struct ncp_inode_info *result = &(server->root);
|
|
|
if (name == NULL)
|
if (name == NULL)
|
{
|
{
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
do
|
do
|
{
|
{
|
if ( (result->dir->finfo.i.dirEntNum == dir_info->dirEntNum)
|
if ( (result->dir->finfo.i.dirEntNum == dir_info->dirEntNum)
|
&& (result->dir->finfo.i.volNumber == dir_info->volNumber)
|
&& (result->dir->finfo.i.volNumber == dir_info->volNumber)
|
&& (strcmp(result->finfo.i.entryName, name) == 0)
|
&& (strcmp(result->finfo.i.entryName, name) == 0)
|
/* The root dir is never looked up using this
|
/* The root dir is never looked up using this
|
* routine. Without the following test a root
|
* routine. Without the following test a root
|
* directory 'sys' in a volume named 'sys' could
|
* directory 'sys' in a volume named 'sys' could
|
* never be looked up, because
|
* never be looked up, because
|
* server->root->dir==server->root. */
|
* server->root->dir==server->root. */
|
&& (result != &(server->root)))
|
&& (result != &(server->root)))
|
{
|
{
|
return result;
|
return result;
|
}
|
}
|
result = result->next;
|
result = result->next;
|
|
|
}
|
}
|
while (result != &(server->root));
|
while (result != &(server->root));
|
|
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
static int
|
static int
|
ncp_lookup(struct inode *dir, const char *__name, int len,
|
ncp_lookup(struct inode *dir, const char *__name, int len,
|
struct inode **result)
|
struct inode **result)
|
{
|
{
|
struct nw_file_info finfo;
|
struct nw_file_info finfo;
|
struct ncp_server *server;
|
struct ncp_server *server;
|
struct ncp_inode_info *result_info;
|
struct ncp_inode_info *result_info;
|
int found_in_cache;
|
int found_in_cache;
|
int down_case = 0;
|
int down_case = 0;
|
char name[len+1];
|
char name[len+1];
|
|
|
*result = NULL;
|
*result = NULL;
|
|
|
if (!dir || !S_ISDIR(dir->i_mode))
|
if (!dir || !S_ISDIR(dir->i_mode))
|
{
|
{
|
printk("ncp_lookup: inode is NULL or not a directory.\n");
|
printk("ncp_lookup: inode is NULL or not a directory.\n");
|
iput(dir);
|
iput(dir);
|
return -ENOENT;
|
return -ENOENT;
|
}
|
}
|
|
|
server = NCP_SERVER(dir);
|
server = NCP_SERVER(dir);
|
|
|
if (!ncp_conn_valid(server))
|
if (!ncp_conn_valid(server))
|
{
|
{
|
iput(dir);
|
iput(dir);
|
return -EIO;
|
return -EIO;
|
}
|
}
|
|
|
DPRINTK("ncp_lookup: %s, len %d\n", __name, len);
|
DPRINTK("ncp_lookup: %s, len %d\n", __name, len);
|
|
|
/* Fast cheat for . */
|
/* Fast cheat for . */
|
if (len == 0 || (len == 1 && __name[0] == '.'))
|
if (len == 0 || (len == 1 && __name[0] == '.'))
|
{
|
{
|
*result = dir;
|
*result = dir;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* ..and for .. */
|
/* ..and for .. */
|
if (len == 2 && __name[0] == '.' && __name[1] == '.')
|
if (len == 2 && __name[0] == '.' && __name[1] == '.')
|
{
|
{
|
struct ncp_inode_info *parent = NCP_INOP(dir)->dir;
|
struct ncp_inode_info *parent = NCP_INOP(dir)->dir;
|
|
|
if (parent->state == NCP_INODE_CACHED)
|
if (parent->state == NCP_INODE_CACHED)
|
{
|
{
|
parent->state = NCP_INODE_LOOKED_UP;
|
parent->state = NCP_INODE_LOOKED_UP;
|
}
|
}
|
|
|
*result = iget(dir->i_sb, ncp_info_ino(server, parent));
|
*result = iget(dir->i_sb, ncp_info_ino(server, parent));
|
iput(dir);
|
iput(dir);
|
if (*result == 0)
|
if (*result == 0)
|
{
|
{
|
return -EACCES;
|
return -EACCES;
|
}
|
}
|
else
|
else
|
{
|
{
|
return 0;
|
return 0;
|
}
|
}
|
}
|
}
|
|
|
memcpy(name, __name, len);
|
memcpy(name, __name, len);
|
name[len] = 0;
|
name[len] = 0;
|
lock_super(dir->i_sb);
|
lock_super(dir->i_sb);
|
result_info = ncp_find_dir_inode(dir, name);
|
result_info = ncp_find_dir_inode(dir, name);
|
|
|
if (result_info != 0)
|
if (result_info != 0)
|
{
|
{
|
if (result_info->state == NCP_INODE_CACHED)
|
if (result_info->state == NCP_INODE_CACHED)
|
{
|
{
|
result_info->state = NCP_INODE_LOOKED_UP;
|
result_info->state = NCP_INODE_LOOKED_UP;
|
}
|
}
|
|
|
/* Here we convert the inode_info address into an
|
/* Here we convert the inode_info address into an
|
inode number */
|
inode number */
|
|
|
*result = iget(dir->i_sb, ncp_info_ino(server, result_info));
|
*result = iget(dir->i_sb, ncp_info_ino(server, result_info));
|
unlock_super(dir->i_sb);
|
unlock_super(dir->i_sb);
|
iput(dir);
|
iput(dir);
|
|
|
if (*result == NULL)
|
if (*result == NULL)
|
{
|
{
|
return -EACCES;
|
return -EACCES;
|
}
|
}
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* If the file is in the dir cache, we do not have to ask the
|
/* If the file is in the dir cache, we do not have to ask the
|
server. */
|
server. */
|
|
|
found_in_cache = 0;
|
found_in_cache = 0;
|
ncp_lock_dircache();
|
ncp_lock_dircache();
|
|
|
if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
|
if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
|
{
|
{
|
int first = c_last_returned_index;
|
int first = c_last_returned_index;
|
int i;
|
int i;
|
|
|
i = first;
|
i = first;
|
do
|
do
|
{
|
{
|
DDPRINTK("ncp_lookup: trying index: %d, name: %s\n",
|
DDPRINTK("ncp_lookup: trying index: %d, name: %s\n",
|
i, c_entry[i].i.entryName);
|
i, c_entry[i].i.entryName);
|
|
|
if (strcmp(c_entry[i].i.entryName, name) == 0)
|
if (strcmp(c_entry[i].i.entryName, name) == 0)
|
{
|
{
|
DPRINTK("ncp_lookup: found in cache!\n");
|
DPRINTK("ncp_lookup: found in cache!\n");
|
finfo.i = c_entry[i].i;
|
finfo.i = c_entry[i].i;
|
found_in_cache = 1;
|
found_in_cache = 1;
|
break;
|
break;
|
}
|
}
|
i = (i + 1) % c_size;
|
i = (i + 1) % c_size;
|
}
|
}
|
while (i != first);
|
while (i != first);
|
}
|
}
|
ncp_unlock_dircache();
|
ncp_unlock_dircache();
|
|
|
if (found_in_cache == 0)
|
if (found_in_cache == 0)
|
{
|
{
|
int res;
|
int res;
|
|
|
DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
|
DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
|
NCP_ISTRUCT(dir)->entryName, name);
|
NCP_ISTRUCT(dir)->entryName, name);
|
|
|
if (ncp_is_server_root(dir))
|
if (ncp_is_server_root(dir))
|
{
|
{
|
str_upper(name);
|
str_upper(name);
|
down_case = 1;
|
down_case = 1;
|
res = ncp_lookup_volume(server, name, &(finfo.i));
|
res = ncp_lookup_volume(server, name, &(finfo.i));
|
}
|
}
|
else
|
else
|
{
|
{
|
if (!ncp_preserve_case(dir))
|
if (!ncp_preserve_case(dir))
|
{
|
{
|
str_upper(name);
|
str_upper(name);
|
down_case = 1;
|
down_case = 1;
|
}
|
}
|
res = ncp_obtain_info(server,
|
res = ncp_obtain_info(server,
|
NCP_ISTRUCT(dir)->volNumber,
|
NCP_ISTRUCT(dir)->volNumber,
|
NCP_ISTRUCT(dir)->dirEntNum,
|
NCP_ISTRUCT(dir)->dirEntNum,
|
name, &(finfo.i));
|
name, &(finfo.i));
|
}
|
}
|
if (res != 0)
|
if (res != 0)
|
{
|
{
|
unlock_super(dir->i_sb);
|
unlock_super(dir->i_sb);
|
iput(dir);
|
iput(dir);
|
return -ENOENT;
|
return -ENOENT;
|
}
|
}
|
}
|
}
|
|
|
finfo.opened = 0;
|
finfo.opened = 0;
|
|
|
if (down_case != 0)
|
if (down_case != 0)
|
{
|
{
|
str_lower(finfo.i.entryName);
|
str_lower(finfo.i.entryName);
|
}
|
}
|
|
|
if (!(*result = ncp_iget(dir, &finfo)))
|
if (!(*result = ncp_iget(dir, &finfo)))
|
{
|
{
|
unlock_super(dir->i_sb);
|
unlock_super(dir->i_sb);
|
iput(dir);
|
iput(dir);
|
return -EACCES;
|
return -EACCES;
|
}
|
}
|
|
|
unlock_super(dir->i_sb);
|
unlock_super(dir->i_sb);
|
iput(dir);
|
iput(dir);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
static int
|
static int
|
ncp_create(struct inode *dir, const char *name, int len, int mode,
|
ncp_create(struct inode *dir, const char *name, int len, int mode,
|
struct inode **result)
|
struct inode **result)
|
{
|
{
|
struct nw_file_info finfo;
|
struct nw_file_info finfo;
|
__u8 _name[len+1];
|
__u8 _name[len+1];
|
int error;
|
int error;
|
|
|
*result = NULL;
|
*result = NULL;
|
|
|
if (!dir || !S_ISDIR(dir->i_mode))
|
if (!dir || !S_ISDIR(dir->i_mode))
|
{
|
{
|
printk("ncp_create: inode is NULL or not a directory\n");
|
printk("ncp_create: inode is NULL or not a directory\n");
|
iput(dir);
|
iput(dir);
|
return -ENOENT;
|
return -ENOENT;
|
}
|
}
|
if (!ncp_conn_valid(NCP_SERVER(dir)))
|
if (!ncp_conn_valid(NCP_SERVER(dir)))
|
{
|
{
|
iput(dir);
|
iput(dir);
|
return -EIO;
|
return -EIO;
|
}
|
}
|
|
|
strncpy(_name, name, len);
|
strncpy(_name, name, len);
|
_name[len] = '\0';
|
_name[len] = '\0';
|
|
|
if (!ncp_preserve_case(dir))
|
if (!ncp_preserve_case(dir))
|
{
|
{
|
str_upper(_name);
|
str_upper(_name);
|
}
|
}
|
|
|
lock_super(dir->i_sb);
|
lock_super(dir->i_sb);
|
if ((error = ncp_open_create_file_or_subdir(NCP_SERVER(dir),
|
if ((error = ncp_open_create_file_or_subdir(NCP_SERVER(dir),
|
NCP_ISTRUCT(dir), _name,
|
NCP_ISTRUCT(dir), _name,
|
OC_MODE_CREATE|OC_MODE_OPEN|
|
OC_MODE_CREATE|OC_MODE_OPEN|
|
OC_MODE_REPLACE,
|
OC_MODE_REPLACE,
|
0, AR_READ|AR_WRITE,
|
0, AR_READ|AR_WRITE,
|
&finfo)) != 0)
|
&finfo)) != 0)
|
{
|
{
|
unlock_super(dir->i_sb);
|
unlock_super(dir->i_sb);
|
iput(dir);
|
iput(dir);
|
if (error == 0x87) {
|
if (error == 0x87) {
|
return -ENAMETOOLONG;
|
return -ENAMETOOLONG;
|
}
|
}
|
return -EACCES;
|
return -EACCES;
|
}
|
}
|
|
|
ncp_invalid_dir_cache(dir);
|
ncp_invalid_dir_cache(dir);
|
|
|
if (!ncp_preserve_case(dir))
|
if (!ncp_preserve_case(dir))
|
{
|
{
|
str_lower(finfo.i.entryName);
|
str_lower(finfo.i.entryName);
|
}
|
}
|
|
|
finfo.access = O_RDWR;
|
finfo.access = O_RDWR;
|
|
|
if (!(*result = ncp_iget(dir, &finfo)) < 0)
|
if (!(*result = ncp_iget(dir, &finfo)) < 0)
|
{
|
{
|
ncp_close_file(NCP_SERVER(dir), finfo.file_handle);
|
ncp_close_file(NCP_SERVER(dir), finfo.file_handle);
|
unlock_super(dir->i_sb);
|
unlock_super(dir->i_sb);
|
iput(dir);
|
iput(dir);
|
return -EINVAL;
|
return -EINVAL;
|
}
|
}
|
|
|
unlock_super(dir->i_sb);
|
unlock_super(dir->i_sb);
|
iput(dir);
|
iput(dir);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
static int
|
static int
|
ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
|
ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
|
{
|
{
|
int error;
|
int error;
|
struct nw_file_info new_dir;
|
struct nw_file_info new_dir;
|
__u8 _name[len+1];
|
__u8 _name[len+1];
|
|
|
if ( (name[0] == '.')
|
if ( (name[0] == '.')
|
&& ( (len == 1)
|
&& ( (len == 1)
|
|| ( (len == 2)
|
|| ( (len == 2)
|
&& (name[1] == '.'))))
|
&& (name[1] == '.'))))
|
{
|
{
|
iput(dir);
|
iput(dir);
|
return -EEXIST;
|
return -EEXIST;
|
}
|
}
|
|
|
strncpy(_name, name, len);
|
strncpy(_name, name, len);
|
_name[len] = '\0';
|
_name[len] = '\0';
|
|
|
if (!ncp_preserve_case(dir))
|
if (!ncp_preserve_case(dir))
|
{
|
{
|
str_upper(_name);
|
str_upper(_name);
|
}
|
}
|
|
|
if (!dir || !S_ISDIR(dir->i_mode))
|
if (!dir || !S_ISDIR(dir->i_mode))
|
{
|
{
|
printk("ncp_mkdir: inode is NULL or not a directory\n");
|
printk("ncp_mkdir: inode is NULL or not a directory\n");
|
iput(dir);
|
iput(dir);
|
return -ENOENT;
|
return -ENOENT;
|
}
|
}
|
if (!ncp_conn_valid(NCP_SERVER(dir)))
|
if (!ncp_conn_valid(NCP_SERVER(dir)))
|
{
|
{
|
iput(dir);
|
iput(dir);
|
return -EIO;
|
return -EIO;
|
}
|
}
|
|
|
if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
|
if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
|
NCP_ISTRUCT(dir), _name,
|
NCP_ISTRUCT(dir), _name,
|
OC_MODE_CREATE, aDIR, 0xffff,
|
OC_MODE_CREATE, aDIR, 0xffff,
|
&new_dir) != 0)
|
&new_dir) != 0)
|
{
|
{
|
error = -EACCES;
|
error = -EACCES;
|
}
|
}
|
else
|
else
|
{
|
{
|
error = 0;
|
error = 0;
|
ncp_invalid_dir_cache(dir);
|
ncp_invalid_dir_cache(dir);
|
}
|
}
|
|
|
iput(dir);
|
iput(dir);
|
return error;
|
return error;
|
}
|
}
|
|
|
static int
|
static int
|
ncp_rmdir(struct inode *dir, const char *name, int len)
|
ncp_rmdir(struct inode *dir, const char *name, int len)
|
{
|
{
|
int error;
|
int error;
|
__u8 _name[len+1];
|
__u8 _name[len+1];
|
|
|
if (!dir || !S_ISDIR(dir->i_mode))
|
if (!dir || !S_ISDIR(dir->i_mode))
|
{
|
{
|
printk("ncp_rmdir: inode is NULL or not a directory\n");
|
printk("ncp_rmdir: inode is NULL or not a directory\n");
|
iput(dir);
|
iput(dir);
|
return -ENOENT;
|
return -ENOENT;
|
}
|
}
|
if (!ncp_conn_valid(NCP_SERVER(dir)))
|
if (!ncp_conn_valid(NCP_SERVER(dir)))
|
{
|
{
|
iput(dir);
|
iput(dir);
|
return -EIO;
|
return -EIO;
|
}
|
}
|
if (ncp_find_dir_inode(dir, name) != NULL)
|
if (ncp_find_dir_inode(dir, name) != NULL)
|
{
|
{
|
error = -EBUSY;
|
error = -EBUSY;
|
}
|
}
|
else
|
else
|
{
|
{
|
|
|
strncpy(_name, name, len);
|
strncpy(_name, name, len);
|
_name[len] = '\0';
|
_name[len] = '\0';
|
|
|
if (!ncp_preserve_case(dir))
|
if (!ncp_preserve_case(dir))
|
{
|
{
|
str_upper(_name);
|
str_upper(_name);
|
}
|
}
|
|
|
if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
|
if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
|
NCP_ISTRUCT(dir),
|
NCP_ISTRUCT(dir),
|
_name)) == 0)
|
_name)) == 0)
|
{
|
{
|
ncp_invalid_dir_cache(dir);
|
ncp_invalid_dir_cache(dir);
|
}
|
}
|
else
|
else
|
{
|
{
|
error = -EACCES;
|
error = -EACCES;
|
}
|
}
|
}
|
}
|
iput(dir);
|
iput(dir);
|
return error;
|
return error;
|
}
|
}
|
|
|
|
|
#ifdef CONFIG_NCPFS_STRONG
|
#ifdef CONFIG_NCPFS_STRONG
|
/* try to delete a readonly file (NW R bit set) */
|
/* try to delete a readonly file (NW R bit set) */
|
|
|
static int
|
static int
|
ncp_force_unlink(struct inode *dir,char *name,int len)
|
ncp_force_unlink(struct inode *dir,char *name,int len)
|
{
|
{
|
int res=0x9c,res2;
|
int res=0x9c,res2;
|
struct inode *_inode;
|
struct inode *_inode;
|
struct iattr ia;
|
struct iattr ia;
|
|
|
/* remove the Read-Only flag on the NW server */
|
/* remove the Read-Only flag on the NW server */
|
|
|
dir->i_count++;
|
dir->i_count++;
|
res2=ncp_lookup(dir,name,len,&_inode);
|
res2=ncp_lookup(dir,name,len,&_inode);
|
if (res2)
|
if (res2)
|
{
|
{
|
goto leave_me; /* abort operation */
|
goto leave_me; /* abort operation */
|
}
|
}
|
memset(&ia,0,sizeof(struct iattr));
|
memset(&ia,0,sizeof(struct iattr));
|
ia.ia_mode = _inode->i_mode;
|
ia.ia_mode = _inode->i_mode;
|
ia.ia_mode |= NCP_SERVER(dir)->m.file_mode & 0222; /* set write bits */
|
ia.ia_mode |= NCP_SERVER(dir)->m.file_mode & 0222; /* set write bits */
|
ia.ia_valid = ATTR_MODE;
|
ia.ia_valid = ATTR_MODE;
|
|
|
res2=ncp_notify_change(_inode,&ia);
|
res2=ncp_notify_change(_inode,&ia);
|
if (res2)
|
if (res2)
|
{
|
{
|
iput(_inode);
|
iput(_inode);
|
goto leave_me;
|
goto leave_me;
|
}
|
}
|
|
|
/* now try again the delete operation */
|
/* now try again the delete operation */
|
|
|
res2 = ncp_del_file_or_subdir(NCP_SERVER(dir),NCP_ISTRUCT(dir),name);
|
res2 = ncp_del_file_or_subdir(NCP_SERVER(dir),NCP_ISTRUCT(dir),name);
|
|
|
res=res2; /* save status to use as return value */
|
res=res2; /* save status to use as return value */
|
|
|
res=res2;
|
res=res2;
|
if (res2) /* delete failed, set R bit again */
|
if (res2) /* delete failed, set R bit again */
|
{
|
{
|
memset(&ia,0,sizeof(struct iattr));
|
memset(&ia,0,sizeof(struct iattr));
|
ia.ia_mode = _inode->i_mode;
|
ia.ia_mode = _inode->i_mode;
|
ia.ia_mode &= ~(NCP_SERVER(dir)->m.file_mode & 0222); /* clear write bits */
|
ia.ia_mode &= ~(NCP_SERVER(dir)->m.file_mode & 0222); /* clear write bits */
|
ia.ia_valid = ATTR_MODE;
|
ia.ia_valid = ATTR_MODE;
|
|
|
res2=ncp_notify_change(_inode,&ia);
|
res2=ncp_notify_change(_inode,&ia);
|
if (res2)
|
if (res2)
|
{
|
{
|
iput(_inode);
|
iput(_inode);
|
goto leave_me;
|
goto leave_me;
|
}
|
}
|
}
|
}
|
iput(_inode);
|
iput(_inode);
|
|
|
leave_me:
|
leave_me:
|
return(res);
|
return(res);
|
}
|
}
|
#endif /* CONFIG_NCPFS_STRONG */
|
#endif /* CONFIG_NCPFS_STRONG */
|
|
|
static int
|
static int
|
ncp_unlink(struct inode *dir, const char *name, int len)
|
ncp_unlink(struct inode *dir, const char *name, int len)
|
{
|
{
|
int error;
|
int error;
|
__u8 _name[len+1];
|
__u8 _name[len+1];
|
|
|
if (!dir || !S_ISDIR(dir->i_mode))
|
if (!dir || !S_ISDIR(dir->i_mode))
|
{
|
{
|
printk("ncp_unlink: inode is NULL or not a directory\n");
|
printk("ncp_unlink: inode is NULL or not a directory\n");
|
iput(dir);
|
iput(dir);
|
return -ENOENT;
|
return -ENOENT;
|
}
|
}
|
if (!ncp_conn_valid(NCP_SERVER(dir)))
|
if (!ncp_conn_valid(NCP_SERVER(dir)))
|
{
|
{
|
iput(dir);
|
iput(dir);
|
return -EIO;
|
return -EIO;
|
}
|
}
|
if (ncp_find_dir_inode(dir, name) != NULL)
|
if (ncp_find_dir_inode(dir, name) != NULL)
|
{
|
{
|
error = -EBUSY;
|
error = -EBUSY;
|
}
|
}
|
else
|
else
|
{
|
{
|
strncpy(_name, name, len);
|
strncpy(_name, name, len);
|
_name[len] = '\0';
|
_name[len] = '\0';
|
|
|
if (!ncp_preserve_case(dir))
|
if (!ncp_preserve_case(dir))
|
{
|
{
|
str_upper(_name);
|
str_upper(_name);
|
}
|
}
|
|
|
error = ncp_del_file_or_subdir(NCP_SERVER(dir),
|
error = ncp_del_file_or_subdir(NCP_SERVER(dir),
|
NCP_ISTRUCT(dir),
|
NCP_ISTRUCT(dir),
|
_name);
|
_name);
|
#ifdef CONFIG_NCPFS_STRONG
|
#ifdef CONFIG_NCPFS_STRONG
|
if (error == 0x9c && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG) /* readonly */
|
if (error == 0x9c && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG) /* readonly */
|
{
|
{
|
error = ncp_force_unlink(dir,_name,len); /* special treatment */
|
error = ncp_force_unlink(dir,_name,len); /* special treatment */
|
}
|
}
|
#endif /* CONFIG_NCPFS_STRONG */
|
#endif /* CONFIG_NCPFS_STRONG */
|
|
|
if (error == 0) {
|
if (error == 0) {
|
ncp_invalid_dir_cache(dir);
|
ncp_invalid_dir_cache(dir);
|
} else if (error == 0xFF) {
|
} else if (error == 0xFF) {
|
error = -ENOENT;
|
error = -ENOENT;
|
} else {
|
} else {
|
error = -EACCES;
|
error = -EACCES;
|
}
|
}
|
}
|
}
|
iput(dir);
|
iput(dir);
|
return error;
|
return error;
|
}
|
}
|
|
|
#ifdef CONFIG_NCPFS_STRONG
|
#ifdef CONFIG_NCPFS_STRONG
|
static int
|
static int
|
ncp_force_rename(struct inode *old_dir, const char *old_name, char *_old_name, int old_len,
|
ncp_force_rename(struct inode *old_dir, const char *old_name, char *_old_name, int old_len,
|
struct inode *new_dir, const char *new_name, char *_new_name, int new_len)
|
struct inode *new_dir, const char *new_name, char *_new_name, int new_len)
|
{
|
{
|
int res=0x90,res2;
|
int res=0x90,res2;
|
char _rename_old[old_len+1];
|
char _rename_old[old_len+1];
|
char _rename_new[new_len+1];
|
char _rename_new[new_len+1];
|
struct inode *_inode,*x_dir;
|
struct inode *_inode,*x_dir;
|
struct iattr ia;
|
struct iattr ia;
|
|
|
strncpy(_rename_old,old_name,old_len);
|
strncpy(_rename_old,old_name,old_len);
|
_rename_old[old_len] = 0;
|
_rename_old[old_len] = 0;
|
strncpy(_rename_new,new_name,new_len);
|
strncpy(_rename_new,new_name,new_len);
|
_rename_new[new_len] = 0;
|
_rename_new[new_len] = 0;
|
|
|
/* remove the Read-Only flag on the NW server */
|
/* remove the Read-Only flag on the NW server */
|
|
|
old_dir->i_count++;
|
old_dir->i_count++;
|
res2=ncp_lookup(old_dir,_rename_old,old_len,&_inode);
|
res2=ncp_lookup(old_dir,_rename_old,old_len,&_inode);
|
if (res2)
|
if (res2)
|
{
|
{
|
goto leave_me;
|
goto leave_me;
|
}
|
}
|
memset(&ia,0,sizeof(struct iattr));
|
memset(&ia,0,sizeof(struct iattr));
|
ia.ia_mode = _inode->i_mode;
|
ia.ia_mode = _inode->i_mode;
|
ia.ia_mode |= NCP_SERVER(old_dir)->m.file_mode & 0222; /* set write bits */
|
ia.ia_mode |= NCP_SERVER(old_dir)->m.file_mode & 0222; /* set write bits */
|
ia.ia_valid = ATTR_MODE;
|
ia.ia_valid = ATTR_MODE;
|
|
|
res2=ncp_notify_change(_inode,&ia);
|
res2=ncp_notify_change(_inode,&ia);
|
if (res2)
|
if (res2)
|
{
|
{
|
iput(_inode);
|
iput(_inode);
|
goto leave_me;
|
goto leave_me;
|
}
|
}
|
|
|
/* now try again the rename operation */
|
/* now try again the rename operation */
|
res2 = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
|
res2 = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
|
NCP_ISTRUCT(old_dir), _old_name,
|
NCP_ISTRUCT(old_dir), _old_name,
|
NCP_ISTRUCT(new_dir), _new_name);
|
NCP_ISTRUCT(new_dir), _new_name);
|
|
|
res=res2;
|
res=res2;
|
if (!res2) /* rename succeeded, get a new inode for the new file */
|
if (!res2) /* rename succeeded, get a new inode for the new file */
|
{
|
{
|
x_dir=new_dir;
|
x_dir=new_dir;
|
new_dir->i_count++;
|
new_dir->i_count++;
|
iput(_inode);
|
iput(_inode);
|
res2=ncp_lookup(new_dir,_rename_new,new_len,&_inode);
|
res2=ncp_lookup(new_dir,_rename_new,new_len,&_inode);
|
if (res2)
|
if (res2)
|
{
|
{
|
goto leave_me;
|
goto leave_me;
|
}
|
}
|
}
|
}
|
else
|
else
|
{
|
{
|
x_dir=old_dir;
|
x_dir=old_dir;
|
}
|
}
|
|
|
memset(&ia,0,sizeof(struct iattr));
|
memset(&ia,0,sizeof(struct iattr));
|
ia.ia_mode = _inode->i_mode;
|
ia.ia_mode = _inode->i_mode;
|
ia.ia_mode &= ~(NCP_SERVER(x_dir)->m.file_mode & 0222); /* clear write bits */
|
ia.ia_mode &= ~(NCP_SERVER(x_dir)->m.file_mode & 0222); /* clear write bits */
|
ia.ia_valid = ATTR_MODE;
|
ia.ia_valid = ATTR_MODE;
|
|
|
res2=ncp_notify_change(_inode,&ia);
|
res2=ncp_notify_change(_inode,&ia);
|
iput(_inode);
|
iput(_inode);
|
if (res2)
|
if (res2)
|
{
|
{
|
printk(KERN_INFO "ncpfs: ncp_notify_change (2) failed: %08x\n",res2);
|
printk(KERN_INFO "ncpfs: ncp_notify_change (2) failed: %08x\n",res2);
|
goto leave_me;
|
goto leave_me;
|
}
|
}
|
|
|
leave_me:
|
leave_me:
|
return(res);
|
return(res);
|
}
|
}
|
#endif /* CONFIG_NCPFS_STRONG */
|
#endif /* CONFIG_NCPFS_STRONG */
|
|
|
|
|
static int
|
static int
|
ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
|
ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
|
struct inode *new_dir, const char *new_name, int new_len,
|
struct inode *new_dir, const char *new_name, int new_len,
|
int must_be_dir)
|
int must_be_dir)
|
{
|
{
|
int res;
|
int res;
|
char _old_name[old_len+1];
|
char _old_name[old_len+1];
|
char _new_name[new_len+1];
|
char _new_name[new_len+1];
|
|
|
if (!old_dir || !S_ISDIR(old_dir->i_mode))
|
if (!old_dir || !S_ISDIR(old_dir->i_mode))
|
{
|
{
|
printk("ncp_rename: old inode is NULL or not a directory\n");
|
printk("ncp_rename: old inode is NULL or not a directory\n");
|
res = -ENOENT;
|
res = -ENOENT;
|
goto finished;
|
goto finished;
|
}
|
}
|
|
|
if (!ncp_conn_valid(NCP_SERVER(old_dir)))
|
if (!ncp_conn_valid(NCP_SERVER(old_dir)))
|
{
|
{
|
res = -EIO;
|
res = -EIO;
|
goto finished;
|
goto finished;
|
}
|
}
|
|
|
if (!new_dir || !S_ISDIR(new_dir->i_mode))
|
if (!new_dir || !S_ISDIR(new_dir->i_mode))
|
{
|
{
|
printk("ncp_rename: new inode is NULL or not a directory\n");
|
printk("ncp_rename: new inode is NULL or not a directory\n");
|
res = -ENOENT;
|
res = -ENOENT;
|
goto finished;
|
goto finished;
|
}
|
}
|
|
|
if ( (ncp_find_dir_inode(old_dir, old_name) != NULL)
|
if ( (ncp_find_dir_inode(old_dir, old_name) != NULL)
|
|| (ncp_find_dir_inode(new_dir, new_name) != NULL))
|
|| (ncp_find_dir_inode(new_dir, new_name) != NULL))
|
{
|
{
|
res = -EBUSY;
|
res = -EBUSY;
|
goto finished;
|
goto finished;
|
}
|
}
|
|
|
strncpy(_old_name, old_name, old_len);
|
strncpy(_old_name, old_name, old_len);
|
_old_name[old_len] = '\0';
|
_old_name[old_len] = '\0';
|
|
|
if (!ncp_preserve_case(old_dir))
|
if (!ncp_preserve_case(old_dir))
|
{
|
{
|
str_upper(_old_name);
|
str_upper(_old_name);
|
}
|
}
|
|
|
strncpy(_new_name, new_name, new_len);
|
strncpy(_new_name, new_name, new_len);
|
_new_name[new_len] = '\0';
|
_new_name[new_len] = '\0';
|
|
|
if (!ncp_preserve_case(new_dir))
|
if (!ncp_preserve_case(new_dir))
|
{
|
{
|
str_upper(_new_name);
|
str_upper(_new_name);
|
}
|
}
|
|
|
res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
|
res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
|
NCP_ISTRUCT(old_dir), _old_name,
|
NCP_ISTRUCT(old_dir), _old_name,
|
NCP_ISTRUCT(new_dir), _new_name);
|
NCP_ISTRUCT(new_dir), _new_name);
|
|
|
#ifdef CONFIG_NCPFS_STRONG
|
#ifdef CONFIG_NCPFS_STRONG
|
if (res == 0x90 && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) /* file is readonly */
|
if (res == 0x90 && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) /* file is readonly */
|
{
|
{
|
res=ncp_force_rename(old_dir,old_name,_old_name,old_len,new_dir,new_name,_new_name,new_len);
|
res=ncp_force_rename(old_dir,old_name,_old_name,old_len,new_dir,new_name,_new_name,new_len);
|
}
|
}
|
#endif /* CONFIG_NCPFS_STRONG */
|
#endif /* CONFIG_NCPFS_STRONG */
|
|
|
if (res == 0)
|
if (res == 0)
|
{
|
{
|
ncp_invalid_dir_cache(old_dir);
|
ncp_invalid_dir_cache(old_dir);
|
ncp_invalid_dir_cache(new_dir);
|
ncp_invalid_dir_cache(new_dir);
|
}
|
}
|
else
|
else
|
{
|
{
|
if (res == 0x9E)
|
if (res == 0x9E)
|
res = -ENAMETOOLONG;
|
res = -ENAMETOOLONG;
|
else if (res == 0xFF)
|
else if (res == 0xFF)
|
res = -ENOENT;
|
res = -ENOENT;
|
else
|
else
|
res = -EACCES;
|
res = -EACCES;
|
}
|
}
|
|
|
finished:
|
finished:
|
iput(old_dir);
|
iput(old_dir);
|
iput(new_dir);
|
iput(new_dir);
|
return res;
|
return res;
|
}
|
}
|
|
|
/* The following routines are taken directly from msdos-fs */
|
/* The following routines are taken directly from msdos-fs */
|
|
|
/* Linear day numbers of the respective 1sts in non-leap years. */
|
/* Linear day numbers of the respective 1sts in non-leap years. */
|
|
|
static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
|
static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
|
/* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
|
/* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
|
|
|
|
|
extern struct timezone sys_tz;
|
extern struct timezone sys_tz;
|
|
|
static int
|
static int
|
utc2local(int time)
|
utc2local(int time)
|
{
|
{
|
return time - sys_tz.tz_minuteswest*60 + sys_tz.tz_dsttime*3600;
|
return time - sys_tz.tz_minuteswest*60 + sys_tz.tz_dsttime*3600;
|
}
|
}
|
|
|
static int
|
static int
|
local2utc(int time)
|
local2utc(int time)
|
{
|
{
|
return time + sys_tz.tz_minuteswest*60 - sys_tz.tz_dsttime*3600;
|
return time + sys_tz.tz_minuteswest*60 - sys_tz.tz_dsttime*3600;
|
}
|
}
|
|
|
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
|
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
|
|
|
int
|
int
|
ncp_date_dos2unix(unsigned short time,unsigned short date)
|
ncp_date_dos2unix(unsigned short time,unsigned short date)
|
{
|
{
|
int month,year,secs;
|
int month,year,secs;
|
|
|
month = ((date >> 5) & 15)-1;
|
month = ((date >> 5) & 15)-1;
|
year = date >> 9;
|
year = date >> 9;
|
secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
|
secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
|
((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
|
((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
|
month < 2 ? 1 : 0)+3653);
|
month < 2 ? 1 : 0)+3653);
|
/* days since 1.1.70 plus 80's leap day */
|
/* days since 1.1.70 plus 80's leap day */
|
return local2utc(secs);
|
return local2utc(secs);
|
}
|
}
|
|
|
|
|
/* Convert linear UNIX date to a MS-DOS time/date pair. */
|
/* Convert linear UNIX date to a MS-DOS time/date pair. */
|
void
|
void
|
ncp_date_unix2dos(int unix_date,unsigned short *time, unsigned short *date)
|
ncp_date_unix2dos(int unix_date,unsigned short *time, unsigned short *date)
|
{
|
{
|
int day,year,nl_day,month;
|
int day,year,nl_day,month;
|
|
|
unix_date = utc2local(unix_date);
|
unix_date = utc2local(unix_date);
|
*time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
|
*time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
|
(((unix_date/3600) % 24) << 11);
|
(((unix_date/3600) % 24) << 11);
|
day = unix_date/86400-3652;
|
day = unix_date/86400-3652;
|
year = day/365;
|
year = day/365;
|
if ((year+3)/4+365*year > day) year--;
|
if ((year+3)/4+365*year > day) year--;
|
day -= (year+3)/4+365*year;
|
day -= (year+3)/4+365*year;
|
if (day == 59 && !(year & 3)) {
|
if (day == 59 && !(year & 3)) {
|
nl_day = day;
|
nl_day = day;
|
month = 2;
|
month = 2;
|
}
|
}
|
else {
|
else {
|
nl_day = (year & 3) || day <= 59 ? day : day-1;
|
nl_day = (year & 3) || day <= 59 ? day : day-1;
|
for (month = 0; month < 12; month++)
|
for (month = 0; month < 12; month++)
|
if (day_n[month] > nl_day) break;
|
if (day_n[month] > nl_day) break;
|
}
|
}
|
*date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
|
*date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
|
}
|
}
|
|
|