summaryrefslogtreecommitdiffstats
path: root/fs/ncpfs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-04 07:40:19 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-04 07:40:19 +0000
commit33263fc5f9ac8e8cb2b22d06af3ce5ac1dd815e4 (patch)
tree2d1b86a40bef0958a68cf1a2eafbeb0667a70543 /fs/ncpfs
parent216f5f51aa02f8b113aa620ebc14a9631a217a00 (diff)
Merge with Linux 2.3.32.
Diffstat (limited to 'fs/ncpfs')
-rw-r--r--fs/ncpfs/Config.in6
-rw-r--r--fs/ncpfs/dir.c288
-rw-r--r--fs/ncpfs/file.c2
-rw-r--r--fs/ncpfs/inode.c17
-rw-r--r--fs/ncpfs/ioctl.c80
-rw-r--r--fs/ncpfs/mmap.c6
-rw-r--r--fs/ncpfs/ncplib_kernel.c222
-rw-r--r--fs/ncpfs/ncplib_kernel.h100
-rw-r--r--fs/ncpfs/symlink.c159
9 files changed, 480 insertions, 400 deletions
diff --git a/fs/ncpfs/Config.in b/fs/ncpfs/Config.in
index 5bbc29dc8..a9909cb49 100644
--- a/fs/ncpfs/Config.in
+++ b/fs/ncpfs/Config.in
@@ -6,10 +6,8 @@ bool ' Proprietary file locking' CONFIG_NCPFS_IOCTL_LOCKING
bool ' Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG
bool ' Use NFS namespace if available' CONFIG_NCPFS_NFS_NS
bool ' Use LONG (OS/2) namespace if available' CONFIG_NCPFS_OS2_NS
-if [ "$CONFIG_NCPFS_OS2_NS" = "y" ]; then
- bool ' Lowercase DOS filenames' CONFIG_NCPFS_SMALLDOS
-fi
+bool ' Lowercase DOS filenames' CONFIG_NCPFS_SMALLDOS
bool ' Allow mounting of volume subdirectories' CONFIG_NCPFS_MOUNT_SUBDIR
-# bool ' NDS interserver authentication support' CONFIG_NCPFS_NDS_DOMAINS
+bool ' NDS authentication support' CONFIG_NCPFS_NDS_DOMAINS
bool ' Use Native Language Support' CONFIG_NCPFS_NLS
bool ' Enable symbolic links and execute flags' CONFIG_NCPFS_EXTRAS
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 4ed7a9abe..31e414ebb 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -4,7 +4,7 @@
* 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 1998, 1999 Wolfram Pienkoss for NLS
* Modified 1999 Wolfram Pienkoss for directory caching
*
*/
@@ -81,10 +81,8 @@ struct inode_operations ncp_dir_inode_operations =
NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
- NULL, /* smap */
NULL, /* revalidate */
};
@@ -112,25 +110,23 @@ struct dentry_operations ncp_dentry_operations =
/*
- * XXX: It would be better to use the tolower from linux/ctype.h,
- * but _ctype is needed and it is not exported.
- */
-#define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c))
-
-/*
* Note: leave the hash unchanged if the directory
* is case-sensitive.
*/
static int
ncp_hash_dentry(struct dentry *dentry, struct qstr *this)
{
+ struct nls_table *t;
unsigned long hash;
int i;
+ t = NCP_IO_TABLE(dentry);
+
if (!ncp_case_sensitive(dentry->d_inode)) {
hash = init_name_hash();
for (i=0; i<this->len ; i++)
- hash = partial_name_hash(tolower(this->name[i]),hash);
+ hash = partial_name_hash(ncp_tolower(t, this->name[i]),
+ hash);
this->hash = end_name_hash(hash);
}
return 0;
@@ -139,18 +135,13 @@ ncp_hash_dentry(struct dentry *dentry, struct qstr *this)
static int
ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
{
- int i;
-
- if (a->len != b->len) return 1;
+ if (a->len != b->len)
+ return 1;
if (ncp_case_sensitive(dentry->d_inode))
- return strncmp(a->name, b->name, a->len);
-
- for (i=0; i<a->len; i++)
- if (tolower(a->name[i]) != tolower(b->name[i]))
- return 1;
+ return strncmp(a->name, b->name, a->len);
- return 0;
+ return ncp_strnicmp(NCP_IO_TABLE(dentry), a->name, b->name, a->len);
}
/*
@@ -303,10 +294,9 @@ ncp_lookup_validate(struct dentry * dentry, int flags)
{
struct ncp_server *server;
struct inode *dir = dentry->d_parent->d_inode;
- int res, val = 0;
- int len = dentry->d_name.len;
struct ncp_entry_info finfo;
- __u8 __name[dentry->d_name.len + 1];
+ int res, val = 0, len = dentry->d_name.len + 1;
+ __u8 __name[len];
if (!dentry->d_inode || !dir)
goto finished;
@@ -326,79 +316,42 @@ ncp_lookup_validate(struct dentry * dentry, int flags)
if (val)
goto finished;
- PPRINTK("ncp_lookup_validate: %s/%s not valid, age=%ld\n",
+ DDPRINTK("ncp_lookup_validate: %s/%s not valid, age=%ld, server lookup\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
NCP_GET_AGE(dentry));
- memcpy(__name, dentry->d_name.name, len);
- __name[len] = '\0';
-
- PPRINTK("ncp_lookup_validate: %s, len %d\n", __name, len);
- PPRINTK("ncp_lookup_validate: server lookup for %s/%s\n",
- dentry->d_parent->d_name.name, __name);
-
if (ncp_is_server_root(dir)) {
- io2vol(server, __name, 1);
- res = ncp_lookup_volume(server, __name, &(finfo.i));
+ res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
+ len-1, 1);
+ if (!res)
+ res = ncp_lookup_volume(server, __name, &(finfo.i));
} else {
- io2vol(server, __name, !ncp_preserve_case(dir));
- res = ncp_obtain_info(server, dir, __name, &(finfo.i));
+ res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
+ len-1, !ncp_preserve_case(dir));
+ if (!res)
+ res = ncp_obtain_info(server, dir, __name, &(finfo.i));
}
- PPRINTK("ncp_lookup_validate: looked for %s/%s, res=%d\n",
+ DDPRINTK("ncp_lookup_validate: looked for %s/%s, res=%d\n",
dentry->d_parent->d_name.name, __name, res);
/*
* If we didn't find it, or if it has a different dirEntNum to
* what we remember, it's not valid any more.
*/
if (!res) {
- if (finfo.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum)
+ if (finfo.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum) {
+ ncp_new_dentry(dentry);
val=1;
- else
- PPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n");
+ } else
+ DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n");
- vol2io(server, finfo.i.entryName,
- !ncp_preserve_entry_case(dir, finfo.i.NSCreator));
ncp_update_inode2(dentry->d_inode, &finfo);
- if (val)
- ncp_new_dentry(dentry);
}
finished:
- PPRINTK("ncp_lookup_validate: result=%d\n", val);
+ DDPRINTK("ncp_lookup_validate: result=%d\n", val);
return val;
}
-static struct page *
-ncp_get_cache_page(struct inode *inode, unsigned long offset, int used)
-{
- struct address_space *i_data = &inode->i_data;
- struct page *new_page, *page, **hash;
-
- hash = page_hash(i_data, offset);
-
- page = __find_lock_page(i_data, offset, hash);
- if (used || page)
- return page;
-
- new_page = page_cache_alloc();
- if (!new_page)
- return NULL;
-
- for (;;) {
- page = new_page;
- if (!add_to_page_cache_unique(page, i_data, offset, hash))
- break;
- page_cache_release(page);
- page = __find_lock_page(i_data, offset, hash);
- if (page) {
- page_cache_free(new_page);
- break;
- }
- }
-
- return page;
-}
-
/* most parts from nfsd_d_validate() */
static int
ncp_d_validate(struct dentry *dentry)
@@ -458,11 +411,12 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
goto out;
next = next->next;
}
- dent = NULL;
+ return NULL;
+
out:
- if (dent)
- if (dent->d_inode)
- return dget(dent);
+ if (dent->d_inode)
+ return dget(dent);
+
return NULL;
}
@@ -472,8 +426,7 @@ static time_t ncp_obtain_mtime(struct dentry *dentry)
struct ncp_server *server = NCP_SERVER(inode);
struct nw_info_struct i;
- if (!ncp_conn_valid(server) ||
- ncp_is_server_root(inode))
+ if (!ncp_conn_valid(server) || ncp_is_server_root(inode))
return 0;
if (ncp_obtain_info(server, inode, NULL, &i))
@@ -518,11 +471,11 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
filp->f_pos = 2;
}
- page = ncp_get_cache_page(inode, 0, 0);
+ page = grab_cache_page(&inode->i_data, 0);
if (!page)
goto read_really;
- ctl.cache = cache = (union ncp_dir_cache *) page_address(page);
+ ctl.cache = cache = (union ncp_dir_cache *) kmap(page);
ctl.head = cache->head;
if (!Page_Uptodate(page) || !ctl.head.eof)
@@ -547,13 +500,12 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
for (;;) {
if (ctl.ofs != 0) {
- ctl.page = ncp_get_cache_page(inode, ctl.ofs, 1);
+ ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
if (!ctl.page)
goto invalid_cache;
+ ctl.cache = (union ncp_dir_cache *) kmap(ctl.page);
if (!Page_Uptodate(ctl.page))
goto invalid_cache;
- ctl.cache = (union ncp_dir_cache *)
- page_address(ctl.page);
}
while (ctl.idx < NCP_DIRCACHE_SIZE) {
struct dentry *dent;
@@ -575,6 +527,7 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
goto finished;
}
if (ctl.page) {
+ kunmap(ctl.page);
SetPageUptodate(ctl.page);
UnlockPage(ctl.page);
page_cache_release(ctl.page);
@@ -585,6 +538,7 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
invalid_cache:
if (ctl.page) {
+ kunmap(ctl.page);
UnlockPage(ctl.page);
page_cache_release(ctl.page);
ctl.page = NULL;
@@ -615,11 +569,13 @@ read_really:
finished:
if (page) {
cache->head = ctl.head;
+ kunmap(page);
SetPageUptodate(page);
UnlockPage(page);
page_cache_release(page);
}
if (ctl.page) {
+ kunmap(ctl.page);
SetPageUptodate(ctl.page);
UnlockPage(ctl.page);
page_cache_release(ctl.page);
@@ -634,17 +590,19 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
{
struct dentry *newdent, *dentry = filp->f_dentry;
struct inode *newino, *inode = dentry->d_inode;
- struct ncp_server *server = NCP_SERVER(inode);
struct ncp_cache_control ctl = *ctrl;
struct qstr qname;
- ino_t ino = 0;
int valid = 0;
+ ino_t ino = 0;
+ __u8 __name[256];
- vol2io(server, entry->i.entryName,
- !ncp_preserve_entry_case(inode, entry->i.NSCreator));
+ qname.len = 256;
+ if (ncp_vol2io(NCP_SERVER(inode), __name, &qname.len,
+ entry->i.entryName, entry->i.nameLen,
+ !ncp_preserve_entry_case(inode, entry->i.NSCreator)))
+ return 1; /* I'm not sure */
- qname.name = entry->i.entryName;
- qname.len = entry->i.nameLen;
+ qname.name = __name;
qname.hash = full_name_hash(qname.name, qname.len);
if (dentry->d_op && dentry->d_op->d_hash)
@@ -680,6 +638,7 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
if (ctl.idx >= NCP_DIRCACHE_SIZE) {
if (ctl.page) {
+ kunmap(ctl.page);
SetPageUptodate(ctl.page);
UnlockPage(ctl.page);
page_cache_release(ctl.page);
@@ -687,10 +646,9 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
ctl.cache = NULL;
ctl.idx -= NCP_DIRCACHE_SIZE;
ctl.ofs += 1;
- ctl.page = ncp_get_cache_page(inode, ctl.ofs, 0);
+ ctl.page = grab_cache_page(&inode->i_data, ctl.ofs);
if (ctl.page)
- ctl.cache = (union ncp_dir_cache *)
- page_address(ctl.page);
+ ctl.cache = (union ncp_dir_cache *) kmap(ctl.page);
}
if (ctl.cache) {
ctl.cache->dentry[ctl.idx] = newdent;
@@ -705,8 +663,8 @@ end_advance:
ino = find_inode_number(dentry, &qname);
if (!ino)
ino = iunique(inode->i_sb, 2);
- ctl.filled = filldir(dirent, entry->i.entryName,
- entry->i.nameLen, filp->f_pos, ino);
+ ctl.filled = filldir(dirent, qname.name, qname.len,
+ filp->f_pos, ino);
if (!ctl.filled)
filp->f_pos += 1;
}
@@ -751,8 +709,9 @@ ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir,
}
}
-static void ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
- struct ncp_cache_control *ctl)
+static void
+ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
+ struct ncp_cache_control *ctl)
{
struct dentry *dentry = filp->f_dentry;
struct inode *dir = dentry->d_inode;
@@ -788,19 +747,21 @@ int ncp_conn_logged_in(struct super_block *sb)
{
struct ncp_server* server = NCP_SBP(sb);
struct nw_info_struct i;
- int result;
+ int result, len = strlen(server->m.mounted_vol) + 1;
+ __u8 __name[len];
if (ncp_single_volume(server)) {
struct dentry* dent;
result = -ENOENT;
- io2vol(server, server->m.mounted_vol, 1);
- if (ncp_lookup_volume(server, server->m.mounted_vol, &i)) {
+ if (ncp_io2vol(server, __name, &len, server->m.mounted_vol,
+ len-1, 1))
+ goto out;
+ if (ncp_lookup_volume(server, __name, &i)) {
PPRINTK("ncp_conn_logged_in: %s not found\n",
server->m.mounted_vol);
goto out;
}
- vol2io(server, i.entryName, 1);
dent = sb->s_root;
if (dent) {
struct inode* ino = dent->d_inode;
@@ -823,29 +784,29 @@ out:
static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry)
{
- struct ncp_server *server;
+ struct ncp_server *server = NCP_SERVER(dir);
struct inode *inode = NULL;
- int error, res, len = dentry->d_name.len;
struct ncp_entry_info finfo;
- __u8 __name[dentry->d_name.len + 1];
-
- server = NCP_SERVER(dir);
+ int error, res, len = dentry->d_name.len + 1;
+ __u8 __name[len];
error = -EIO;
if (!ncp_conn_valid(server))
goto finished;
- memcpy(__name, dentry->d_name.name, len);
- __name[len] = '\0';
- PPRINTK("ncp_lookup: %s, len %d\n", __name, len);
PPRINTK("ncp_lookup: server lookup for %s/%s\n",
- dentry->d_parent->d_name.name, __name);
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+
if (ncp_is_server_root(dir)) {
- io2vol(server, __name, 1);
- res = ncp_lookup_volume(server, __name, &(finfo.i));
+ res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
+ len-1, 1);
+ if (!res)
+ res = ncp_lookup_volume(server, __name, &(finfo.i));
} else {
- io2vol(server, __name, !ncp_preserve_case(dir));
- res = ncp_obtain_info(server, dir, __name, &(finfo.i));
+ res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
+ len-1, !ncp_preserve_case(dir));
+ if (!res)
+ res = ncp_obtain_info(server, dir, __name, &(finfo.i));
}
PPRINTK("ncp_lookup: looked for %s/%s, res=%d\n",
dentry->d_parent->d_name.name, __name, res);
@@ -855,9 +816,6 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry)
if (res)
goto add_entry;
- vol2io(server, finfo.i.entryName,
- !ncp_preserve_entry_case(dir, finfo.i.NSCreator));
-
/*
* Create an inode for the entry.
*/
@@ -867,10 +825,10 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry)
inode = ncp_iget(dir->i_sb, &finfo);
if (inode) {
+ ncp_new_dentry(dentry);
add_entry:
dentry->d_op = &ncp_dentry_operations;
d_add(dentry, inode);
- ncp_new_dentry(dentry);
error = 0;
}
@@ -907,10 +865,10 @@ out_close:
int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
int attributes)
{
- int error, result;
- struct ncp_entry_info finfo;
struct ncp_server *server = NCP_SERVER(dir);
- __u8 _name[dentry->d_name.len + 1];
+ struct ncp_entry_info finfo;
+ int error, result, len = dentry->d_name.len + 1;
+ __u8 __name[len];
PPRINTK("ncp_create_new: creating %s/%s, mode=%x\n",
dentry->d_parent->d_name.name, dentry->d_name.name, mode);
@@ -919,16 +877,15 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
goto out;
ncp_age_dentry(server, dentry);
-
- memcpy(_name, dentry->d_name.name, dentry->d_name.len);
- _name[dentry->d_name.len] = '\0';
-
- io2vol(server, _name, !ncp_preserve_case(dir));
+ error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
+ len-1, !ncp_preserve_case(dir));
+ if (error)
+ goto out;
error = -EACCES;
- result = ncp_open_create_file_or_subdir(server, dir, _name,
- OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
- attributes, AR_READ | AR_WRITE, &finfo);
+ result = ncp_open_create_file_or_subdir(server, dir, __name,
+ OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
+ attributes, AR_READ | AR_WRITE, &finfo);
if (!result) {
finfo.access = O_RDWR;
error = ncp_instantiate(dir, dentry, &finfo);
@@ -949,10 +906,10 @@ static int ncp_create(struct inode *dir, struct dentry *dentry, int mode)
static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
- int error;
struct ncp_entry_info finfo;
struct ncp_server *server = NCP_SERVER(dir);
- __u8 _name[dentry->d_name.len + 1];
+ int error, len = dentry->d_name.len + 1;
+ __u8 __name[len];
DPRINTK("ncp_mkdir: making %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
@@ -961,13 +918,13 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
goto out;
ncp_age_dentry(server, dentry);
-
- memcpy(_name, dentry->d_name.name, dentry->d_name.len);
- _name[dentry->d_name.len] = '\0';
- io2vol(server, _name, !ncp_preserve_case(dir));
+ error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
+ len-1, !ncp_preserve_case(dir));
+ if (error)
+ goto out;
error = -EACCES;
- if (ncp_open_create_file_or_subdir(server, dir, _name,
+ if (ncp_open_create_file_or_subdir(server, dir, __name,
OC_MODE_CREATE, aDIR, 0xffff,
&finfo) == 0)
{
@@ -979,9 +936,9 @@ out:
static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
{
- int error, result;
struct ncp_server *server = NCP_SERVER(dir);
- __u8 _name[dentry->d_name.len + 1];
+ int error, result, len = dentry->d_name.len + 1;
+ __u8 __name[len];
DPRINTK("ncp_rmdir: removing %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
@@ -994,11 +951,12 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
if (!list_empty(&dentry->d_hash))
goto out;
- memcpy(_name, dentry->d_name.name, dentry->d_name.len);
- _name[dentry->d_name.len] = '\0';
-
- io2vol(server, _name, !ncp_preserve_case(dir));
- result = ncp_del_file_or_subdir(server, dir, _name);
+ error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
+ len-1, !ncp_preserve_case(dir));
+ if (error)
+ goto out;
+
+ result = ncp_del_file_or_subdir(server, dir, __name);
switch (result) {
case 0x00:
error = 0;
@@ -1091,38 +1049,42 @@ out:
static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
- int old_len = old_dentry->d_name.len;
- int new_len = new_dentry->d_name.len;
+ struct ncp_server *server = NCP_SERVER(old_dir);
int error;
- char _old_name[old_dentry->d_name.len + 1];
- char _new_name[new_dentry->d_name.len + 1];
+ int old_len = old_dentry->d_name.len + 1;
+ int new_len = new_dentry->d_name.len + 1;
+ __u8 __old_name[old_len], __new_name[new_len];
DPRINTK("ncp_rename: %s/%s to %s/%s\n",
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
error = -EIO;
- if (!ncp_conn_valid(NCP_SERVER(old_dir)))
+ if (!ncp_conn_valid(server))
goto out;
- ncp_age_dentry(NCP_SERVER(old_dir), old_dentry);
- ncp_age_dentry(NCP_SERVER(new_dir), new_dentry);
+ ncp_age_dentry(server, old_dentry);
+ ncp_age_dentry(server, new_dentry);
- memcpy(_old_name, old_dentry->d_name.name, old_len);
- _old_name[old_len] = '\0';
- io2vol(NCP_SERVER(old_dir), _old_name, !ncp_preserve_case(old_dir));
+ error = ncp_io2vol(server, __old_name, &old_len,
+ old_dentry->d_name.name, old_len-1,
+ !ncp_preserve_case(old_dir));
+ if (error)
+ goto out;
- memcpy(_new_name, new_dentry->d_name.name, new_len);
- _new_name[new_len] = '\0';
- io2vol(NCP_SERVER(new_dir), _new_name, !ncp_preserve_case(new_dir));
+ error = ncp_io2vol(server, __new_name, &new_len,
+ new_dentry->d_name.name, new_len-1,
+ !ncp_preserve_case(new_dir));
+ if (error)
+ goto out;
- error = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
- old_dir, _old_name,
- new_dir, _new_name);
+ error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
+ new_dir, __new_name);
#ifdef CONFIG_NCPFS_STRONG
- if ((error == 0x90 || error == -EACCES) && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) { /* RO */
- error = ncp_force_rename(old_dir, old_dentry, _old_name,
- new_dir, new_dentry, _new_name);
+ if ((error == 0x90 || error == -EACCES) &&
+ server->m.flags & NCP_MOUNT_STRONG) { /* RO */
+ error = ncp_force_rename(old_dir, old_dentry, __old_name,
+ new_dir, new_dentry, __new_name);
}
#endif
switch (error) {
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index 4a907a9b1..98fd9f23e 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -294,9 +294,7 @@ struct inode_operations ncp_file_inode_operations =
NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
- NULL, /* smap */
NULL /* revalidate */
};
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index ec2c1a4e4..26bd474d2 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -124,16 +124,15 @@ void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
}
inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
- inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwinfo->i.modifyTime),
- le16_to_cpu(nwinfo->i.modifyDate));
- inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(nwinfo->i.creationTime),
- le16_to_cpu(nwinfo->i.creationDate));
- inode->i_atime = ncp_date_dos2unix(0,
- le16_to_cpu(nwinfo->i.lastAccessDate));
+ inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwi->modifyTime),
+ le16_to_cpu(nwi->modifyDate));
+ inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(nwi->creationTime),
+ le16_to_cpu(nwi->creationDate));
+ inode->i_atime = ncp_date_dos2unix(0, le16_to_cpu(nwi->lastAccessDate));
- NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
- NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
- NCP_FINFO(inode)->volNumber = nwinfo->i.volNumber;
+ NCP_FINFO(inode)->DosDirNum = nwi->DosDirNum;
+ NCP_FINFO(inode)->dirEntNum = nwi->dirEntNum;
+ NCP_FINFO(inode)->volNumber = nwi->volNumber;
}
/*
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 05def9d6c..36063db81 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 1995, 1996 by Volker Lendecke
* Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
- * Modified 1998 Wolfram Pienkoss for NLS
+ * Modified 1998, 1999 Wolfram Pienkoss for NLS
*
*/
@@ -364,8 +364,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
#ifdef CONFIG_NCPFS_NDS_DOMAINS
case NCP_IOC_GETOBJECTNAME:
- if ( (permission(inode, MAY_READ) != 0)
- && (current->uid != server->m.mounted_uid)) {
+ if (current->uid != server->m.mounted_uid) {
return -EACCES;
}
{
@@ -396,8 +395,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
return 0;
}
case NCP_IOC_SETOBJECTNAME:
- if ( (permission(inode, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid)) {
+ if (current->uid != server->m.mounted_uid) {
return -EACCES;
}
{
@@ -441,8 +439,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
return 0;
}
case NCP_IOC_GETPRIVATEDATA:
- if ( (permission(inode, MAY_READ) != 0)
- && (current->uid != server->m.mounted_uid)) {
+ if (current->uid != server->m.mounted_uid) {
return -EACCES;
}
{
@@ -471,8 +468,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
return 0;
}
case NCP_IOC_SETPRIVATEDATA:
- if ( (permission(inode, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid)) {
+ if (current->uid != server->m.mounted_uid) {
return -EACCES;
}
{
@@ -531,7 +527,8 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
codepage = NULL;
user.codepage[NCP_IOCSNAME_LEN] = 0;
- if (!user.codepage[0])
+ if (!user.codepage[0] ||
+ !strcmp(user.codepage, "default"))
codepage = load_nls_default();
else {
codepage = load_nls(user.codepage);
@@ -542,13 +539,21 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
iocharset = NULL;
user.iocharset[NCP_IOCSNAME_LEN] = 0;
- if (user.iocharset[0] == 0)
+ if (!user.iocharset[0] ||
+ !strcmp(user.iocharset, "default")) {
iocharset = load_nls_default();
- else {
- iocharset = load_nls(user.iocharset);
- if (!iocharset) {
- unload_nls(codepage);
- return -EBADRQC;
+ NCP_CLR_FLAG(server, NCP_FLAG_UTF8);
+ } else {
+ if (!strcmp(user.iocharset, "utf8")) {
+ iocharset = load_nls_default();
+ NCP_SET_FLAG(server, NCP_FLAG_UTF8);
+ } else {
+ iocharset = load_nls(user.iocharset);
+ if (!iocharset) {
+ unload_nls(codepage);
+ return -EBADRQC;
+ }
+ NCP_CLR_FLAG(server, NCP_FLAG_UTF8);
}
}
@@ -568,35 +573,28 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
case NCP_IOC_GETCHARSETS: /* not tested */
{
struct ncp_nls_ioctl user;
+ int len;
memset(&user, 0, sizeof(user));
- if (server->nls_vol)
- if (server->nls_vol->charset) {
- strncpy(user.codepage,
- server->nls_vol->charset,
- NCP_IOCSNAME_LEN);
- user.codepage[NCP_IOCSNAME_LEN] = 0;
- if (!strcmp(user.codepage, "default"))
- /* unfortunately, we cannot set
- 'default' charset... maybe
- we should change load_nls()?
- It is easy, do not initialize
- 'tables' in fs/nls/nls_base.c
- with NULL, but with
- 'default_table'... */
- memset(user.codepage, 0,
- sizeof(user.codepage));
- }
+ if (server->nls_vol && server->nls_vol->charset) {
+ len = strlen(server->nls_vol->charset);
+ if (len > NCP_IOCSNAME_LEN)
+ len = NCP_IOCSNAME_LEN;
+ strncpy(user.codepage,
+ server->nls_vol->charset, len);
+ user.codepage[len] = 0;
+ }
- if (server->nls_io)
- if (server->nls_io->charset) {
+ if (NCP_IS_FLAG(server, NCP_FLAG_UTF8))
+ strcpy(user.iocharset, "utf8");
+ else
+ if (server->nls_io && server->nls_io->charset) {
+ len = strlen(server->nls_io->charset);
+ if (len > NCP_IOCSNAME_LEN)
+ len = NCP_IOCSNAME_LEN;
strncpy(user.iocharset,
- server->nls_io->charset,
- NCP_IOCSNAME_LEN);
- user.iocharset[NCP_IOCSNAME_LEN] = 0;
- if (!strcmp(user.iocharset, "default"))
- memset(user.iocharset, 0,
- sizeof(user.iocharset));
+ server->nls_io->charset, len);
+ user.iocharset[len] = 0;
}
if (copy_to_user((struct ncp_nls_ioctl*)arg, &user,
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index 036e92e93..806c05d6e 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -43,10 +43,11 @@ static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area,
int bufsize;
int pos;
- page = alloc_page(GFP_KERNEL);
+ page = alloc_page(GFP_HIGHMEM); /* ncpfs has nothing against GFP_HIGHMEM
+ as long as recvmsg and memset works on it */
if (!page)
return page;
- pg_addr = page_address(page);
+ pg_addr = kmap(page);
address &= PAGE_MASK;
pos = address - area->vm_start + (area->vm_pgoff << PAGE_SHIFT);
@@ -87,6 +88,7 @@ static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area,
if (already_read < PAGE_SIZE)
memset((char*)(pg_addr + already_read), 0,
PAGE_SIZE - already_read);
+ kunmap(page);
return page;
}
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
index 5dbd0c55a..7220e4852 100644
--- a/fs/ncpfs/ncplib_kernel.c
+++ b/fs/ncpfs/ncplib_kernel.c
@@ -4,6 +4,7 @@
* 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 1999 Wolfram Pienkoss for NLS
*
*/
@@ -886,4 +887,225 @@ ncp_ClearPhysicalRecord(struct ncp_server *server, const char *file_id,
}
#endif /* CONFIG_NCPFS_IOCTL_LOCKING */
+#ifdef CONFIG_NCPFS_NLS
+/* This are the NLS conversion routines with inspirations and code parts
+ * from the vfat file system and hints from Petr Vandrovec.
+ */
+
+inline unsigned char
+ncp__tolower(struct nls_table *t, unsigned char c)
+{
+ unsigned char nc = t->charset2lower[c];
+
+ return nc ? nc : c;
+}
+
+inline unsigned char
+ncp__toupper(struct nls_table *t, unsigned char c)
+{
+ unsigned char nc = t->charset2upper[c];
+
+ return nc ? nc : c;
+}
+
+int
+ncp__io2vol(struct ncp_server *server, unsigned char *vname, unsigned int *vlen,
+ const unsigned char *iname, unsigned int ilen, int cc)
+{
+ struct nls_table *in = server->nls_io;
+ struct nls_table *out = server->nls_vol;
+ struct nls_unicode uc;
+ unsigned char nc, *up;
+ int i, k, maxlen = *vlen - 1;
+ __u16 ec;
+
+ *vlen = 0;
+
+ for (i = 0; i < ilen;) {
+ if (*vlen == maxlen)
+ return -ENAMETOOLONG;
+
+ if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) {
+ k = utf8_mbtowc(&ec, iname, ilen - i);
+ if (k == -1)
+ return -EINVAL;
+ uc.uni1 = ec & 0xFF;
+ uc.uni2 = ec >> 8;
+ iname += k;
+ i += k;
+ } else {
+ if (*iname == NCP_ESC) {
+ if (i > ilen - 5)
+ return -EINVAL;
+
+ ec = 0;
+ for (k = 1; k < 5; k++) {
+ nc = iname[k];
+ ec <<= 4;
+ if (nc >= '0' && nc <= '9') {
+ ec |= nc - '0';
+ continue;
+ }
+ if (nc >= 'a' && nc <= 'f') {
+ ec |= nc - ('a' - 10);
+ continue;
+ }
+ if (nc >= 'A' && nc <= 'F') {
+ ec |= nc - ('A' - 10);
+ continue;
+ }
+ return -EINVAL;
+ }
+ uc.uni1 = ec & 0xFF;
+ uc.uni2 = ec >> 8;
+ iname += 5;
+ i += 5;
+ } else {
+ uc = in->charset2uni[*iname];
+ iname++;
+ i++;
+ }
+ }
+
+ up = out->page_uni2charset[uc.uni2];
+ if (!up)
+ return -EINVAL;
+
+ nc = up[uc.uni1];
+ if (!nc)
+ return -EINVAL;
+
+ *vname = cc ? ncp_toupper(out, nc) : nc;
+ vname++;
+ *vlen += 1;
+ }
+
+ *vname = 0;
+ return 0;
+}
+
+int
+ncp__vol2io(struct ncp_server *server, unsigned char *iname, unsigned int *ilen,
+ const unsigned char *vname, unsigned int vlen, int cc)
+{
+ struct nls_table *in = server->nls_vol;
+ struct nls_table *out = server->nls_io;
+ struct nls_unicode uc;
+ unsigned char nc, *up;
+ int i, k, maxlen = *ilen - 1;
+ __u16 ec;
+
+ *ilen = 0;
+
+ for (i = 0; i < vlen; i++) {
+ if (*ilen == maxlen)
+ return -ENAMETOOLONG;
+
+ uc = in->charset2uni[cc ? ncp_tolower(in, *vname) : *vname];
+
+ if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) {
+ k = utf8_wctomb(iname, (uc.uni2 << 8) + uc.uni1,
+ maxlen - *ilen);
+ if (k == -1)
+ return -ENAMETOOLONG;
+ iname += k;
+ *ilen += k;
+ } else {
+ up = out->page_uni2charset[uc.uni2];
+ if (up)
+ nc = up[uc.uni1];
+ else
+ nc = 0;
+
+ if (nc) {
+ *iname = nc;
+ iname++;
+ *ilen += 1;
+ } else {
+ if (*ilen > maxlen - 5)
+ return -ENAMETOOLONG;
+ ec = (uc.uni2 << 8) + uc.uni1;
+ *iname = NCP_ESC;
+ for (k = 4; k > 0; k--) {
+ nc = ec & 0xF;
+ iname[k] = nc > 9 ? nc + ('a' - 10)
+ : nc + '0';
+ ec >>= 4;
+ }
+ iname += 5;
+ *ilen += 5;
+ }
+ }
+ vname++;
+ }
+
+ *iname = 0;
+ return 0;
+}
+#else
+
+int
+ncp__io2vol(unsigned char *vname, unsigned int *vlen,
+ const unsigned char *iname, unsigned int ilen, int cc)
+{
+ int i;
+
+ if (*vlen <= ilen)
+ return -ENAMETOOLONG;
+
+ if (cc)
+ for (i = 0; i < ilen; i++) {
+ *vname = toupper(*iname);
+ vname++;
+ iname++;
+ }
+ else {
+ memmove(vname, iname, ilen);
+ vname += ilen;
+ }
+
+ *vlen = ilen;
+ *vname = 0;
+ return 0;
+}
+
+int
+ncp__vol2io(unsigned char *iname, unsigned int *ilen,
+ const unsigned char *vname, unsigned int vlen, int cc)
+{
+ int i;
+
+ if (*ilen <= vlen)
+ return -ENAMETOOLONG;
+
+ if (cc)
+ for (i = 0; i < vlen; i++) {
+ *iname = tolower(*vname);
+ iname++;
+ vname++;
+ }
+ else {
+ memmove(iname, vname, vlen);
+ iname += vlen;
+ }
+
+ *ilen = vlen;
+ *iname = 0;
+ return 0;
+}
+
+#endif
+
+inline int
+ncp_strnicmp(struct nls_table *t, const unsigned char *s1,
+ const unsigned char *s2, int n)
+{
+ int i;
+
+ for (i=0; i<n; i++)
+ if (ncp_tolower(t, s1[i]) != ncp_tolower(t, s2[i]))
+ return 1;
+
+ return 0;
+}
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h
index 92309db26..8b33a5c2e 100644
--- a/fs/ncpfs/ncplib_kernel.h
+++ b/fs/ncpfs/ncplib_kernel.h
@@ -4,7 +4,7 @@
* 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 1998, 1999 Wolfram Pienkoss for NLS
* Modified 1999 Wolfram Pienkoss for directory caching
*
*/
@@ -29,7 +29,9 @@
#ifdef CONFIG_NCPFS_NLS
#include <linux/nls.h>
-#endif
+#else
+#include <linux/ctype.h>
+#endif /* CONFIG_NCPFS_NLS */
#include <linux/ncp_fs.h>
@@ -97,82 +99,40 @@ ncp_mount_subdir(struct ncp_server *, struct nw_info_struct *,
#endif /* CONFIG_NCPFS_MOUNT_SUBDIR */
#ifdef CONFIG_NCPFS_NLS
-/* This are the NLS conversion routines with inspirations and code parts
- * from the vfat file system and hints from Petr Vandrovec.
- */
-/*
- * It should be replaced by charset specifc conversion. Gordon Chaffee
- * has prepared some things, but I don't know, what he thinks about it.
- * The conversion tables for the io charsets should be generatable by
- * Unicode table, shouldn't it? I have written so generation code for it.
- * The tables for the vendor specific codepages...? Hmm. The Samba sources
- * contains also any hints.
- */
+inline unsigned char ncp__tolower(struct nls_table *, unsigned char);
+inline unsigned char ncp__toupper(struct nls_table *, unsigned char);
+int ncp__io2vol(struct ncp_server *, unsigned char *, unsigned int *,
+ const unsigned char *, unsigned int, int);
+int ncp__vol2io(struct ncp_server *, unsigned char *, unsigned int *,
+ const unsigned char *, unsigned int, int);
-#define toupperif(c, u) ((((u) != 0) && ((c) >= 'a') && ((c) <= 'z')) \
- ? (c)-('a'-'A') : (c))
-#define tolowerif(c, u) ((((u) != 0) && ((c) >= 'A') && ((c) <= 'Z')) \
- ? (c)-('A'-'a') : (c))
-
-static inline void
-io2vol(struct ncp_server *server, char *name, int case_trans)
-{
- unsigned char nc;
- unsigned char *np;
- unsigned char *up;
- struct nls_unicode uc;
- struct nls_table *nls_in;
- struct nls_table *nls_out;
-
- nls_in = server->nls_io;
- nls_out = server->nls_vol;
- np = name;
-
- while (*np)
- {
- nc = 0;
- uc = nls_in->charset2uni[toupperif(*np, case_trans)];
- up = nls_out->page_uni2charset[uc.uni2];
- if (up != NULL) nc = up[uc.uni1];
- if (nc != 0) *np = nc;
- np++;
- }
-}
-
-static inline void
-vol2io(struct ncp_server *server, char *name, int case_trans)
-{
- unsigned char nc;
- unsigned char *np;
- unsigned char *up;
- struct nls_unicode uc;
- struct nls_table *nls_in;
- struct nls_table *nls_out;
-
- nls_in = server->nls_vol;
- nls_out = server->nls_io;
- np = name;
-
- while (*np)
- {
- nc = 0;
- uc = nls_in->charset2uni[*np];
- up = nls_out->page_uni2charset[uc.uni2];
- if (up != NULL) nc = up[uc.uni1];
- if (nc == 0) nc = *np;
- *np = tolowerif(nc, case_trans);
- np++;
- }
-}
+#define NCP_ESC ':'
+#define NCP_IO_TABLE(dentry) (NCP_SERVER((dentry)->d_inode)->nls_io)
+#define ncp_tolower(t, c) ncp__tolower(t, c)
+#define ncp_toupper(t, c) ncp__toupper(t, c)
+#define ncp_io2vol(S,m,i,n,k,U) ncp__io2vol(S,m,i,n,k,U)
+#define ncp_vol2io(S,m,i,n,k,U) ncp__vol2io(S,m,i,n,k,U)
#else
-#define io2vol(S,N,U) if (U) str_upper(N)
-#define vol2io(S,N,U) if (U) str_lower(N)
+int ncp__io2vol(unsigned char *, unsigned int *,
+ const unsigned char *, unsigned int, int);
+int ncp__vol2io(unsigned char *, unsigned int *,
+ const unsigned char *, unsigned int, int);
+
+#define NCP_IO_TABLE(dentry) NULL
+#define ncp_tolower(t, c) tolower(c)
+#define ncp_toupper(t, c) toupper(c)
+#define ncp_io2vol(S,m,i,n,k,U) ncp__io2vol(m,i,n,k,U)
+#define ncp_vol2io(S,m,i,n,k,U) ncp__vol2io(m,i,n,k,U)
#endif /* CONFIG_NCPFS_NLS */
+inline int
+ncp_strnicmp(struct nls_table *,
+ const unsigned char *, const unsigned char *, int);
+
#define NCP_GET_AGE(dentry) (jiffies - (dentry)->d_time)
#define NCP_MAX_AGE(server) ((server)->dentry_ttl)
#define NCP_TEST_AGE(server,dentry) (NCP_GET_AGE(dentry) < NCP_MAX_AGE(server))
diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c
index 81151959a..5e5bf2fbd 100644
--- a/fs/ncpfs/symlink.c
+++ b/fs/ncpfs/symlink.c
@@ -38,139 +38,76 @@
#define NCP_SYMLINK_MAGIC0 le32_to_cpu(0x6c6d7973) /* "symlnk->" */
#define NCP_SYMLINK_MAGIC1 le32_to_cpu(0x3e2d6b6e)
-static int ncp_readlink(struct dentry *, char *, int);
-static struct dentry *ncp_follow_link(struct dentry *, struct dentry *, unsigned int);
int ncp_create_new(struct inode *dir, struct dentry *dentry,
int mode,int attributes);
-/*
- * symlinks can't do much...
- */
-struct inode_operations ncp_symlink_inode_operations={
- NULL, /* no file-operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- ncp_readlink, /* readlink */
- ncp_follow_link, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-/* ----- follow a symbolic link ------------------------------------------ */
+/* ----- read a symbolic link ------------------------------------------ */
-static struct dentry *ncp_follow_link(struct dentry *dentry,
- struct dentry *base,
- unsigned int follow)
+static int ncp_symlink_readpage(struct dentry *dentry, struct page *page)
{
struct inode *inode=dentry->d_inode;
- int error, length, cnt;
+ int error, length, len, cnt;
char *link;
+ char *buf = (char*)kmap(page);
-#ifdef DEBUG
- PRINTK("ncp_follow_link(dentry=%p,base=%p,follow=%u)\n",dentry,base,follow);
-#endif
-
- if(!S_ISLNK(inode->i_mode)) {
- dput(base);
- return ERR_PTR(-EINVAL);
- }
+ error = -EIO;
+ if (ncp_make_open(inode,O_RDONLY))
+ goto fail;
- if(ncp_make_open(inode,O_RDONLY)) {
- dput(base);
- return ERR_PTR(-EIO);
- }
-
- for (cnt = 0; (link=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE+1, GFP_NFS))==NULL; cnt++) {
- if (cnt > 10) {
- dput(base);
- return ERR_PTR(-EAGAIN); /* -ENOMEM? */
- }
+ error = -ENOMEM;
+ for (cnt = 0; (link=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_NFS))==NULL; cnt++) {
+ if (cnt > 10)
+ goto fail;
schedule();
}
error=ncp_read_kernel(NCP_SERVER(inode),NCP_FINFO(inode)->file_handle,
0,NCP_MAX_SYMLINK_SIZE,link,&length);
- if (error!=0 || length<NCP_MIN_SYMLINK_SIZE ||
- ((__u32 *)link)[0]!=NCP_SYMLINK_MAGIC0 || ((__u32 *)link)[1]!=NCP_SYMLINK_MAGIC1) {
- dput(base);
+ if (error) {
kfree(link);
- return ERR_PTR(-EIO);
+ goto fail;
}
-
- link[length]=0;
-
- vol2io(NCP_SERVER(inode), link+8, 0);
-
- /* UPDATE_ATIME(inode); */
- base=lookup_dentry(link+8, base, follow);
- kfree(link);
-
- return base;
-}
-
-/* ----- read symbolic link ---------------------------------------------- */
-
-static int ncp_readlink(struct dentry * dentry, char * buffer, int buflen)
-{
- struct inode *inode=dentry->d_inode;
- char *link;
- int length,error;
-
-#ifdef DEBUG
- PRINTK("ncp_readlink(dentry=%p,buffer=%p,buflen=%d)\n",dentry,buffer,buflen);
-#endif
-
- if(!S_ISLNK(inode->i_mode))
- return -EINVAL;
-
- if(ncp_make_open(inode,O_RDONLY))
- return -EIO;
-
- if((link=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE+1,GFP_NFS))==NULL)
- return -ENOMEM;
-
- error = ncp_read_kernel(NCP_SERVER(inode),NCP_FINFO(inode)->file_handle,
- 0,NCP_MAX_SYMLINK_SIZE,link,&length);
-
- if (error!=0 || length < NCP_MIN_SYMLINK_SIZE || buflen < (length-8) ||
- ((__u32 *)link)[0]!=NCP_SYMLINK_MAGIC0 ||((__u32 *)link)[1]!=NCP_SYMLINK_MAGIC1) {
- error = -EIO;
- goto out;
+ if (length<NCP_MIN_SYMLINK_SIZE ||
+ ((__u32 *)link)[0]!=NCP_SYMLINK_MAGIC0 ||
+ ((__u32 *)link)[1]!=NCP_SYMLINK_MAGIC1) {
+ error = -EIO;
+ kfree(link);
+ goto fail;
}
- link[length] = 0;
-
- vol2io(NCP_SERVER(inode), link+8, 0);
-
- error = length - 8;
- if(copy_to_user(buffer, link+8, error))
- error = -EFAULT;
-
-out:;
+ len = NCP_MAX_SYMLINK_SIZE;
+ error = ncp_vol2io(NCP_SERVER(inode), buf, &len, link+8, length-8, 0);
kfree(link);
+ if (error)
+ goto fail;
+ SetPageUptodate(page);
+ kunmap(page);
+ UnlockPage(page);
+ return 0;
+
+fail:
+ SetPageError(page);
+ kunmap(page);
+ UnlockPage(page);
return error;
}
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations ncp_symlink_inode_operations={
+ readlink: page_readlink,
+ follow_link: page_follow_link,
+ readpage: ncp_symlink_readpage,
+};
+
/* ----- create a new symbolic link -------------------------------------- */
int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
- int i,length;
struct inode *inode;
char *link;
+ int length, err, i;
#ifdef DEBUG
PRINTK("ncp_symlink(dir=%p,dentry=%p,symname=%s)\n",dir,dentry,symname);
@@ -179,7 +116,7 @@ int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
if (!(NCP_SERVER(dir)->m.flags & NCP_MOUNT_SYMLINKS))
return -EPERM; /* EPERM is returned by VFS if symlink procedure does not exist */
- if ((length=strlen(symname))>NCP_MAX_SYMLINK_SIZE)
+ if ((length=strlen(symname))>NCP_MAX_SYMLINK_SIZE-8)
return -EINVAL;
if ((link=(char *)kmalloc(length+9,GFP_NFS))==NULL)
@@ -194,12 +131,16 @@ int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
((__u32 *)link)[0]=NCP_SYMLINK_MAGIC0;
((__u32 *)link)[1]=NCP_SYMLINK_MAGIC1;
- memcpy(link+8, symname, length+1); /* including last zero for io2vol */
/* map to/from server charset, do not touch upper/lower case as
symlink can point out of ncp filesystem */
- io2vol(NCP_SERVER(inode), link+8, 0);
-
+ length += 1;
+ err = ncp_io2vol(NCP_SERVER(inode),link+8,&length,symname,length-1,0);
+ if (err) {
+ kfree(link);
+ return err;
+ }
+
if(ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
0, length+8, link, &i) || i!=length+8) {
kfree(link);