Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aaa3c6e7cc | ||
|
|
f6e0a67e78 |
BIN
.downloads/ncpfs-0.2.tgz
Normal file
BIN
.downloads/ncpfs-0.2.tgz
Normal file
Binary file not shown.
BIN
.downloads/ncpfs-0.3.tgz
Normal file
BIN
.downloads/ncpfs-0.3.tgz
Normal file
Binary file not shown.
17
BUGS
Normal file
17
BUGS
Normal file
@@ -0,0 +1,17 @@
|
||||
Maybe you want to look at LIMITATIONS in README. Some might consider
|
||||
them to be bugs.
|
||||
|
||||
But there are really problems that might be fixed in the future.
|
||||
|
||||
Invalid directory timestamps:
|
||||
I did not yet find out how to get valid timestamps for directories
|
||||
from a NetWare server. So I simply return 0, which means 01.01.70. If
|
||||
anybody knows how to get these values, please mail
|
||||
lendecke@namu01.gwdg.de.
|
||||
|
||||
'df' returns 0:
|
||||
Free disk space is distributed among the volumes in NetWare. df is
|
||||
only able to report one number per mounted filesystem. As connections
|
||||
are quite expensive for NetWare (with lwared that might change ...), I
|
||||
rejected the alternative to mount only a single volume for a unix
|
||||
mount point. So I simply return 0.
|
||||
13
Changes
Normal file
13
Changes
Normal file
@@ -0,0 +1,13 @@
|
||||
ncpfs-0.2 -> ncpfs-0.3
|
||||
|
||||
- removed bug in get_pname_static
|
||||
- removed bug in 'ncpmount -n'
|
||||
- fake '.' and '..'
|
||||
- return 0 for df and directory timestamps. See file BUGS
|
||||
|
||||
ncpfs-0.1 -> ncpfs-0.2
|
||||
|
||||
- should be compileable with gcc other than 2.7.0
|
||||
- first attempt at read/write access
|
||||
- more complete ncpmount.c
|
||||
- included file ipx.tar
|
||||
15
Makefile
15
Makefile
@@ -22,26 +22,29 @@ ARCH = i386
|
||||
|
||||
OBJS= inode.o dir.o file.o sock.o ioctl.o ncplib.o nwcrypt.o
|
||||
|
||||
all: ncpfs.o ncpmount
|
||||
all: ncpfs.o ncpmount ncptest
|
||||
|
||||
ncpfs.o: $(OBJS)
|
||||
$(LD) -r -o ncpfs.o $(OBJS)
|
||||
|
||||
ncpmount: ncpmount.o
|
||||
ncpmount: ncpmount.o
|
||||
gcc -o ncpmount ncpmount.o
|
||||
|
||||
ncpmount.o: ncpmount.c
|
||||
gcc -c ncpmount.c -Wall -I. -g
|
||||
|
||||
ncptest: ncptest.o ncplib_user.o nwcrypt.o
|
||||
gcc -o ncptest ncptest.o ncplib_user.o nwcrypt.o
|
||||
|
||||
ncptest.o: ncptest.c
|
||||
gcc -c ncptest.c -Wall -I. -g
|
||||
|
||||
ncplib_user.o: ncplib.o
|
||||
gcc -c ncplib.c -Wall -I. -g -o ncplib_user.o
|
||||
|
||||
nwcrypt.o: nwcrypt.c
|
||||
gcc -c -O2 -Wall nwcrypt.c
|
||||
|
||||
ncpumount: ncpumount.o
|
||||
gcc -o ncpumount ncpumount.o
|
||||
|
||||
dep:
|
||||
$(CPP) -M $(INCLUDES) *.c > .depend
|
||||
|
||||
@@ -49,7 +52,7 @@ clean:
|
||||
rm -f *.o *~
|
||||
|
||||
realclean: clean
|
||||
rm -fr ncpmount ncpumount .depend $(DISTFILE) mnt
|
||||
rm -fr ncpmount ncptest .depend $(DISTFILE) mnt *.out
|
||||
|
||||
modules: ncpfs.o
|
||||
|
||||
|
||||
139
README
139
README
@@ -1,90 +1,79 @@
|
||||
This is version 0.1 of ncpfs, a free NetWare client for Linux. For me
|
||||
it works with 1.3.32 and 1.3.35.
|
||||
This is version 0.2 of ncpfs, a free NetWare client for Linux. For me
|
||||
it works with 1.3.32
|
||||
|
||||
I know that this piece of software is VERY incomplete, as it only
|
||||
gives you read-only access. I have to apologize for that. But I
|
||||
thought I should make it publically available, because I have tried to
|
||||
ask several people about the legal status of the code. I did not get
|
||||
very satisfying answers. So I publish ncpfs to open it for
|
||||
criticism. If nobody complains, I will go on working.
|
||||
I know that this piece of software is VERY incomplete, I have to
|
||||
apologize for that. But I thought I should make it publically
|
||||
available, because I have tried to ask several people about the legal
|
||||
status of the code. I did not get very satisfying answers. So I publish
|
||||
ncpfs to open it for criticism. If nobody complains, I will go on
|
||||
working.
|
||||
|
||||
To install ncpfs, just type 'make', 'insmod ncpfs.o' and
|
||||
'ncpmount server mount-point user password'. Please note that your IPX
|
||||
system has to be configured correctly. There has to be a route to the
|
||||
internal network of your server. I use tools from the dosemu-0.60.3
|
||||
distribution to do this. Once again I have to apologize for this
|
||||
cryptic description, but before I'm sure that I'm allowed to do all
|
||||
this I will not do more.
|
||||
To install ncpfs, just type 'make', 'insmod ncpfs.o' and then
|
||||
'ncpmount server mount-point'. Please note that your IPX system has to
|
||||
be configured correctly. There has to be a route to the internal
|
||||
network of your server. Please see the file start_ipx for an example.
|
||||
|
||||
I use tools written by Greg Page, Caldera. I hope I did not do too
|
||||
much harm to their business. For your convenience I included the file
|
||||
ipx.tar made available by Caldera.
|
||||
|
||||
My main source of information is a book written in german by Manfred
|
||||
Hill and Ralf Zessin, "Netzwerkprogrammierung in C", IWT Verlag GmbH,
|
||||
1995, ISBN 3-88322-491-X. It contains quite a lot of typographical and
|
||||
other errors, but I find it very valuable as an introduction to NCP
|
||||
programming. If you know about the concepts and possibilities of NCP,
|
||||
Ralph Brown's interrupt list becomes much more readable. It's much
|
||||
easier to find undocumented information if you know what to look for!
|
||||
|
||||
|
||||
I read that Novell is not very open when it comes to technical details
|
||||
of the Netware Core Protocol. This might be especially true for the
|
||||
encryption stuff. I took the necessary code from Dr. Dobb's Journal
|
||||
11/93, Undocumented Corner. I asked Jon Erickson <jon@ddj.com> about
|
||||
the legal status of this piece of code:
|
||||
MAILING LIST
|
||||
|
||||
There is a mailing list for discussing lwared and ncpfs. Here's the
|
||||
message I received after subscribing:
|
||||
|
||||
---
|
||||
Date: Thu, 12 Oct 1995 13:44:18 +0100
|
||||
From: Volker Lendecke <lendecke>
|
||||
To: jon@ddj.com
|
||||
Subject: legal status of your source code?
|
||||
Thank you for your subscription to the list "linware".
|
||||
|
||||
Topics for the list:
|
||||
- discussing LinWare server, its features, installation problems and bugs
|
||||
- using IPX protocol under Linux
|
||||
- IPX routing and router daemons under Linux
|
||||
|
||||
Hello!
|
||||
|
||||
I hope that you're the right one to write to, you are the first on your WWW
|
||||
server. If you are not, could you please forward this message to the right
|
||||
person? Thanks.
|
||||
|
||||
I'm currently exploring the possibility to write a free (in the GNU GPL
|
||||
sense) NCP filesystem, which would allow me to access a novell server
|
||||
transparently. For that I would like to use the encryption functions you
|
||||
published in DDJ 11/93, Undocumented Corner. I would make some cosmetic
|
||||
changes, such as other indentations, minor code changes and so on. But I do
|
||||
not know if that allows me to publish this code under GPL. One alternative
|
||||
would be to publish a diff against your listing, but that would probably
|
||||
contain much of your code as well, and it would be very inconvenient for
|
||||
the average user.
|
||||
|
||||
I think that you have some kind of standard procedure for such a
|
||||
case. Please tell me what I should do.
|
||||
|
||||
Many thanks in advance,
|
||||
|
||||
Volker
|
||||
|
||||
+=================================================================+
|
||||
! Volker Lendecke Internet: lendecke@namu01.gwdg.de !
|
||||
! D-37081 Goettingen, Germany !
|
||||
+=================================================================+
|
||||
|
||||
--
|
||||
|
||||
|
||||
I got the following answer:
|
||||
|
||||
---
|
||||
From: Jon Erickson <jon@ddj.com>
|
||||
X-Mailer: SCO System V Mail (version 3.2)
|
||||
To: lendecke@namu01.gwdg.de
|
||||
Subject: Re: legal status of your source code?
|
||||
Date: Thu, 12 Oct 95 5:42:56 PDT
|
||||
|
||||
Volker,
|
||||
Code from Dr. Dobb's Journal related articles is provided for
|
||||
anyone to use. Clearly, the author of the article should be
|
||||
given credit.
|
||||
Jon Erickson
|
||||
|
||||
Send your list postings to address: "linware@sh.cvut.cz"
|
||||
Send your list control commands to address: "listserv@sh.cvut.cz"
|
||||
---
|
||||
|
||||
With this answer in mind, I took the code and made it a bit more
|
||||
C-like. The original seemed to be translated by a mechanical pascal->c
|
||||
translator. Jon's answer encouraged me to publish nwcrypt.c under the
|
||||
GPL. If anybody who knows more about copyright and sees any problems
|
||||
with this, please tell me.
|
||||
You can subscribe to this list by sending a message with a line
|
||||
'add your_name@your_host linware' to listserv@sh.cvut.cz .
|
||||
|
||||
|
||||
NCPLIB
|
||||
|
||||
For the curious: the file ncplib.c is usable from user space as well.
|
||||
Look at the file ncptest.c for a possible use. I use ncptest to check
|
||||
my assumptions about the widely undocumented NetWare Core Protocol.
|
||||
Maybe this is the beginning of a free NetWare API for Linux! I would
|
||||
be happy to receive your comments on this.
|
||||
|
||||
|
||||
LIMITATIONS (compare these with smbfs :-)
|
||||
|
||||
The limitations ncpfs has are the natural limitations of the NCP
|
||||
protocol, which was designed with MS-DOS based PCs in mind. The first
|
||||
limitation is the lack of uid, gid and permission information per
|
||||
file. You have to assign those values once for a complete mounted
|
||||
directory.
|
||||
|
||||
The second limitation is just as annoying as the first: You cannot
|
||||
re-export a ncp-mounted directory by nfs. It is not possible because
|
||||
the NFS protocol defines access to files through unique file handles,
|
||||
which can be mapped to the device and inode numbers in unix NFS
|
||||
servers. NCP does not have unique numbers per file, you only have the
|
||||
path name. I implemented a caching scheme for inode numbers, which
|
||||
gives unique inode numbers for every open file in the system. This is
|
||||
just sufficient for local use of the files, because you can tell when
|
||||
an inode number can be discarded. With NFS the situation is
|
||||
different. You can never know when the client will access the file-id
|
||||
you offered, so you would have to cache the inode numbers
|
||||
indefinitely long. I think this should not be done in kernel mode, as
|
||||
it would require an unlimited amount of RAM.
|
||||
|
||||
352
dir.c
352
dir.c
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* dir.c
|
||||
*
|
||||
* Copyright (C) 1995 by Volker Lendecke
|
||||
@@ -60,6 +60,23 @@ static int
|
||||
ncp_lookup(struct inode *dir, const char *__name,
|
||||
int len, struct inode **result);
|
||||
|
||||
static int
|
||||
ncp_create(struct inode *dir, const char *name, int len, int mode,
|
||||
struct inode **result);
|
||||
|
||||
static int
|
||||
ncp_mkdir(struct inode *dir, const char *name, int len, int mode);
|
||||
|
||||
static int
|
||||
ncp_rmdir(struct inode *dir, const char *name, int len);
|
||||
|
||||
static int
|
||||
ncp_unlink(struct inode *dir, const char *name, int len);
|
||||
|
||||
static int
|
||||
ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
|
||||
struct inode *new_dir, const char *new_name, int new_len);
|
||||
|
||||
static int
|
||||
date_dos2unix(unsigned short time,unsigned short date);
|
||||
|
||||
@@ -103,15 +120,15 @@ static struct file_operations ncp_dir_operations = {
|
||||
|
||||
struct inode_operations ncp_dir_inode_operations = {
|
||||
&ncp_dir_operations, /* default directory file ops */
|
||||
NULL, /* create */
|
||||
ncp_create, /* create */
|
||||
ncp_lookup, /* lookup */
|
||||
NULL, /* link */
|
||||
NULL, /* unlink */
|
||||
ncp_unlink, /* unlink */
|
||||
NULL, /* symlink */
|
||||
NULL, /* mkdir */
|
||||
NULL, /* rmdir */
|
||||
ncp_mkdir, /* mkdir */
|
||||
ncp_rmdir, /* rmdir */
|
||||
NULL, /* mknod */
|
||||
NULL, /* rename */
|
||||
ncp_rename, /* rename */
|
||||
NULL, /* readlink */
|
||||
NULL, /* follow_link */
|
||||
NULL, /* bmap */
|
||||
@@ -286,13 +303,34 @@ ncp_readdir(struct inode *inode, struct file *filp,
|
||||
}
|
||||
|
||||
static int
|
||||
ncp_read_volume_list(struct ncp_server *server, int start_with, int cache_size)
|
||||
ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
|
||||
{
|
||||
struct ncp_dirent *entry = c_entry;
|
||||
|
||||
int total_count = 0;
|
||||
int i;
|
||||
|
||||
void fill_one(char *name)
|
||||
{
|
||||
if (total_count < fpos) {
|
||||
DPRINTK("ncp_do_readdir: skipped file: %s\n", name);
|
||||
} else if (total_count >= fpos + cache_size) {
|
||||
return;
|
||||
} else {
|
||||
DPRINTK("ncp_do_readdir: found file: %s\n", name);
|
||||
|
||||
entry->attr = aDIR;
|
||||
entry->mtime = 0;
|
||||
entry->ctime = 0;
|
||||
entry->atime = 0;
|
||||
entry->size = 1024;
|
||||
entry->f_pos = total_count;
|
||||
strcpy(entry->path, name);
|
||||
entry += 1;
|
||||
}
|
||||
total_count += 1;
|
||||
}
|
||||
|
||||
for (i=0; i<NCP_NUMBER_OF_VOLUMES; i++) {
|
||||
|
||||
struct ncp_volume_info info;
|
||||
@@ -302,29 +340,12 @@ ncp_read_volume_list(struct ncp_server *server, int start_with, int cache_size)
|
||||
}
|
||||
|
||||
if (strlen(info.volume_name) > 0) {
|
||||
|
||||
if (total_count < start_with) {
|
||||
DPRINTK("ncp_read_volumes: skipped vol: %s\n",
|
||||
info.volume_name);
|
||||
} else if (total_count >= start_with + cache_size) {
|
||||
return (total_count - start_with);
|
||||
} else {
|
||||
DPRINTK("ncp_read_volumes: found vol %s\n",
|
||||
info.volume_name);
|
||||
entry->attr = aDIR;
|
||||
entry->mtime = 0;
|
||||
entry->ctime = 0;
|
||||
entry->atime = 0;
|
||||
entry->size = 1024;
|
||||
entry->f_pos = total_count;
|
||||
strcpy(entry->path, info.volume_name);
|
||||
entry += 1;
|
||||
}
|
||||
|
||||
total_count += 1;
|
||||
fill_one(info.volume_name);
|
||||
}
|
||||
}
|
||||
return (total_count - start_with);
|
||||
fill_one(".");
|
||||
fill_one("..");
|
||||
return (total_count - fpos);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -336,6 +357,41 @@ ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
|
||||
|
||||
int total_count = 0;
|
||||
|
||||
void fill_one(int attr, char *name,
|
||||
int upd_time, int upd_date,
|
||||
int cr_date, int ac_date, int length)
|
||||
{
|
||||
if (total_count < fpos) {
|
||||
DPRINTK("ncp_do_readdir: skipped file: %s\n", name);
|
||||
} else if (total_count >= fpos + cache_size) {
|
||||
return;
|
||||
} else {
|
||||
DPRINTK("ncp_do_readdir: found file: %s\n", name);
|
||||
|
||||
entry->attr = attr;
|
||||
if ((attr & aDIR) == 0) {
|
||||
entry->mtime = date_dos2unix(upd_time,
|
||||
upd_date);
|
||||
entry->ctime = date_dos2unix(0, cr_date);
|
||||
entry->atime = date_dos2unix(0, ac_date);
|
||||
entry->size = length;
|
||||
} else {
|
||||
/* Sorry, I do not know how to get the
|
||||
* values for directories :-(. Mail
|
||||
* lendecke@namu01.gwdg.de if you
|
||||
* know more. */
|
||||
entry->mtime = 0;
|
||||
entry->ctime = 0;
|
||||
entry->atime = 0;
|
||||
entry->size = 1024;
|
||||
}
|
||||
entry->f_pos = total_count;
|
||||
strcpy(entry->path, name);
|
||||
entry += 1;
|
||||
}
|
||||
total_count += 1;
|
||||
}
|
||||
|
||||
void doit(int attr) {
|
||||
|
||||
if (ncp_file_search_init(server, 0, NCP_FINFO(dir)->path,
|
||||
@@ -346,36 +402,20 @@ ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
|
||||
|
||||
while (ncp_file_search_continue(server, &fsinfo, attr, "*",
|
||||
&finfo) == 0) {
|
||||
|
||||
fill_one(attr, finfo.file_name,
|
||||
finfo.update_time, finfo.update_date,
|
||||
finfo.creation_date, finfo.access_date,
|
||||
finfo.file_length);
|
||||
|
||||
if (total_count < fpos) {
|
||||
DPRINTK("ncp_do_readdir: skipped file: %s\n",
|
||||
finfo.file_name);
|
||||
} else if (total_count >= fpos + cache_size) {
|
||||
return;
|
||||
} else {
|
||||
DPRINTK("ncp_do_readdir: found file: %s\n",
|
||||
finfo.file_name);
|
||||
|
||||
entry->attr = attr;
|
||||
entry->mtime =
|
||||
date_dos2unix(finfo.update_time,
|
||||
finfo.update_date);
|
||||
entry->ctime =
|
||||
date_dos2unix(0, finfo.creation_date);
|
||||
entry->atime =
|
||||
date_dos2unix(0, finfo.access_date);
|
||||
;
|
||||
entry->size = (attr & aDIR) != 0 ?
|
||||
1024 : finfo.file_length;
|
||||
entry->f_pos = total_count;
|
||||
strcpy(entry->path, finfo.file_name);
|
||||
entry += 1;
|
||||
}
|
||||
total_count += 1;
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
fill_one(aDIR, ".", 0, 0, 0, 0, 0);
|
||||
fill_one(aDIR, "..", 0, 0, 0, 0, 0);
|
||||
|
||||
doit(0);
|
||||
doit(aDIR);
|
||||
|
||||
@@ -437,7 +477,7 @@ get_pname_static(struct inode *dir, const char *name, int len,
|
||||
}
|
||||
|
||||
#endif
|
||||
DPRINTK("get_pname_static: parentname = %s, len = %d\n",
|
||||
DDPRINTK("get_pname_static: parentname = %s, len = %d\n",
|
||||
parentname, parentlen);
|
||||
|
||||
if (len > NCP_MAXNAMELEN) {
|
||||
@@ -458,16 +498,16 @@ get_pname_static(struct inode *dir, const char *name, int len,
|
||||
char *pos = strrchr(parentname, '\\');
|
||||
|
||||
if ( (pos == NULL)
|
||||
&& (parentlen == 0)) {
|
||||
&& ( (parentname[parentlen-1] == ':')
|
||||
|| (parentlen == 0))) {
|
||||
|
||||
/* We're at the top */
|
||||
|
||||
path[0] = '\\';
|
||||
path[1] = '\0';
|
||||
*res_len = 2;
|
||||
path[0] = '\0';
|
||||
*res_len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (pos == NULL) {
|
||||
printk("ncp_make_name: Bad parent NCP-name: %s",
|
||||
@@ -481,7 +521,6 @@ get_pname_static(struct inode *dir, const char *name, int len,
|
||||
path[len] = '\0';
|
||||
}
|
||||
else if (parentlen == 0) {
|
||||
|
||||
memcpy(path, name, len);
|
||||
path[len] = ':';
|
||||
path[len+1] = '\0';
|
||||
@@ -501,7 +540,7 @@ get_pname_static(struct inode *dir, const char *name, int len,
|
||||
|
||||
*res_len = len;
|
||||
|
||||
DPRINTK("get_pname: path = %s, *pathlen = %d\n",
|
||||
DDPRINTK("get_pname: path = %s, *pathlen = %d\n",
|
||||
path, *res_len);
|
||||
return 0;
|
||||
}
|
||||
@@ -771,10 +810,10 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
|
||||
i, c_entry[i].path);
|
||||
if (strcmp(c_entry[i].path, __name) == 0) {
|
||||
DPRINTK("ncp_lookup: found in cache!\n");
|
||||
finfo = c_entry[i];
|
||||
finfo.path = NULL; /* It's not ours! */
|
||||
found_in_cache = 1;
|
||||
break;
|
||||
finfo = c_entry[i];
|
||||
finfo.path = NULL; /* It's not ours! */
|
||||
found_in_cache = 1;
|
||||
break;
|
||||
}
|
||||
i = (i + 1) % c_size;
|
||||
DDPRINTK("ncp_lookup: index %d, name %s failed\n",
|
||||
@@ -845,10 +884,191 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ncp_create(struct inode *dir, const char *name, int len, int mode,
|
||||
struct inode **result)
|
||||
{
|
||||
int error;
|
||||
char *path = NULL;
|
||||
struct ncp_dirent entry;
|
||||
struct ncp_file_info finfo;
|
||||
struct ncp_dirent *ino_finfo;
|
||||
|
||||
*result = NULL;
|
||||
|
||||
if (!dir || !S_ISDIR(dir->i_mode)) {
|
||||
printk("ncp_create: inode is NULL or not a directory\n");
|
||||
iput(dir);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* The following are taken directly from msdos-fs */
|
||||
/* Now we will have to build up an NCP filename. */
|
||||
if ((error = get_pname(dir, name, len, &path, &len)) < 0) {
|
||||
iput(dir);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (ncp_create_newfile(NCP_SERVER(dir), 0, path, 0, &finfo) != 0) {
|
||||
put_pname(path);
|
||||
iput(dir);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
entry.attr = finfo.file_attributes;
|
||||
entry.mtime = date_dos2unix(finfo.update_time,
|
||||
finfo.update_date);
|
||||
entry.ctime = date_dos2unix(0, finfo.creation_date);
|
||||
entry.atime = date_dos2unix(0, finfo.access_date);
|
||||
entry.size = 0;
|
||||
|
||||
ncp_invalid_dir_cache(dir->i_ino);
|
||||
|
||||
if (!(*result = ncp_iget(dir, path, &entry)) < 0) {
|
||||
ncp_close_file(NCP_SERVER(dir), finfo.file_id);
|
||||
put_pname(path);
|
||||
iput(dir);
|
||||
return error;
|
||||
}
|
||||
|
||||
ino_finfo = &(NCP_INOP(*result)->finfo);
|
||||
ino_finfo->opened = 1;
|
||||
ino_finfo->access = O_RDWR;
|
||||
memcpy(&(ino_finfo->file_id), finfo.file_id, NCP_FILE_ID_LEN);
|
||||
|
||||
iput(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
|
||||
{
|
||||
int error;
|
||||
char path[NCP_MAXPATHLEN];
|
||||
|
||||
if (!dir || !S_ISDIR(dir->i_mode)) {
|
||||
printk("ncp_mkdir: inode is NULL or not a directory\n");
|
||||
iput(dir);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Now we will have to build up an NCP filename. */
|
||||
if ((error = get_pname_static(dir, name, len, path, &len)) < 0) {
|
||||
iput(dir);
|
||||
return error;
|
||||
}
|
||||
|
||||
if ((error = ncp_create_directory(NCP_SERVER(dir), 0, path,
|
||||
0xff)) == 0) {
|
||||
ncp_invalid_dir_cache(dir->i_ino);
|
||||
}
|
||||
|
||||
iput(dir);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
ncp_rmdir(struct inode *dir, const char *name, int len)
|
||||
{
|
||||
int error;
|
||||
char path[NCP_MAXPATHLEN];
|
||||
|
||||
if (!dir || !S_ISDIR(dir->i_mode)) {
|
||||
printk("ncp_rmdir: inode is NULL or not a directory\n");
|
||||
iput(dir);
|
||||
return -ENOENT;
|
||||
}
|
||||
if ((error = get_pname_static(dir, name, len, path, &len)) < 0) {
|
||||
iput(dir);
|
||||
return error;
|
||||
}
|
||||
if (ncp_find_inode(NCP_SERVER(dir), path) != NULL) {
|
||||
error = -EBUSY;
|
||||
} else {
|
||||
if ((error = ncp_delete_directory(NCP_SERVER(dir),
|
||||
0, path)) == 0) {
|
||||
ncp_invalid_dir_cache(dir->i_ino);
|
||||
}
|
||||
}
|
||||
iput(dir);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
ncp_unlink(struct inode *dir, const char *name, int len)
|
||||
{
|
||||
int error;
|
||||
char path[NCP_MAXPATHLEN];
|
||||
|
||||
if (!dir || !S_ISDIR(dir->i_mode)) {
|
||||
printk("ncp_unlink: inode is NULL or not a directory\n");
|
||||
iput(dir);
|
||||
return -ENOENT;
|
||||
}
|
||||
if ((error = get_pname_static(dir, name, len, path, &len)) < 0) {
|
||||
iput(dir);
|
||||
return error;
|
||||
}
|
||||
if (ncp_find_inode(NCP_SERVER(dir), path) != NULL) {
|
||||
error = -EBUSY;
|
||||
} else {
|
||||
if ((error = ncp_erase_file(NCP_SERVER(dir), 0, path,
|
||||
0)) == 0)
|
||||
ncp_invalid_dir_cache(dir->i_ino);
|
||||
}
|
||||
|
||||
iput(dir);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
|
||||
struct inode *new_dir, const char *new_name, int new_len)
|
||||
{
|
||||
int res;
|
||||
char old_path[NCP_MAXPATHLEN], new_path[NCP_MAXPATHLEN];
|
||||
|
||||
if (!old_dir || !S_ISDIR(old_dir->i_mode)) {
|
||||
printk("ncp_rename: old inode is NULL or not a directory\n");
|
||||
res = -ENOENT;
|
||||
goto finished;
|
||||
}
|
||||
|
||||
if (!new_dir || !S_ISDIR(new_dir->i_mode)) {
|
||||
printk("ncp_rename: new inode is NULL or not a directory\n");
|
||||
res = -ENOENT;
|
||||
goto finished;
|
||||
}
|
||||
|
||||
res = get_pname_static(old_dir, old_name, old_len, old_path, &old_len);
|
||||
if (res < 0) {
|
||||
goto finished;
|
||||
}
|
||||
|
||||
res = get_pname_static(new_dir, new_name, new_len, new_path, &new_len);
|
||||
if (res < 0) {
|
||||
goto finished;
|
||||
}
|
||||
|
||||
if ( (ncp_find_inode(NCP_SERVER(old_dir), old_path) != NULL)
|
||||
|| (ncp_find_inode(NCP_SERVER(new_dir), new_path) != NULL)) {
|
||||
res = -EBUSY;
|
||||
goto finished;
|
||||
}
|
||||
|
||||
res = ncp_rename_file(NCP_SERVER(old_dir), 0, old_path, 0,0, new_path);
|
||||
|
||||
if (res == 0) {
|
||||
ncp_invalid_dir_cache(old_dir->i_ino);
|
||||
ncp_invalid_dir_cache(new_dir->i_ino);
|
||||
}
|
||||
|
||||
finished:
|
||||
iput(old_dir);
|
||||
iput(new_dir);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* The following routines are taken directly from msdos-fs */
|
||||
|
||||
/* Linear day numbers of the respective 1sts in non-leap years. */
|
||||
|
||||
|
||||
83
file.c
83
file.c
@@ -93,9 +93,6 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((errno = ncp_make_open(inode, O_RDONLY)) != 0)
|
||||
return errno;
|
||||
|
||||
pos = file->f_pos;
|
||||
|
||||
if (pos + count > inode->i_size)
|
||||
@@ -104,6 +101,9 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
|
||||
if (count <= 0)
|
||||
return 0;
|
||||
|
||||
if ((errno = ncp_make_open(inode, O_RDONLY)) != 0)
|
||||
return errno;
|
||||
|
||||
bufsize = NCP_SERVER(inode)->buffer_size;
|
||||
|
||||
already_read = 0;
|
||||
@@ -145,10 +145,85 @@ ncp_file_read(struct inode *inode, struct file *file, char *buf, int count)
|
||||
return already_read;
|
||||
}
|
||||
|
||||
static int
|
||||
ncp_file_write(struct inode *inode, struct file *file, const char *buf,
|
||||
int count)
|
||||
{
|
||||
int bufsize, to_write, already_written;
|
||||
off_t pos;
|
||||
int errno;
|
||||
|
||||
if (!inode) {
|
||||
DPRINTK("ncp_file_write: inode = NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!S_ISREG(inode->i_mode)) {
|
||||
DPRINTK("ncp_file_write: write to non-file, mode %07o\n",
|
||||
inode->i_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DPRINTK("ncp_file_write: enter %s\n", NCP_FINFO(inode)->path);
|
||||
|
||||
if (count <= 0)
|
||||
return 0;
|
||||
|
||||
if ((errno = ncp_make_open(inode, O_RDWR)) != 0)
|
||||
return errno;
|
||||
|
||||
pos = file->f_pos;
|
||||
|
||||
if (file->f_flags & O_APPEND)
|
||||
pos = inode->i_size;
|
||||
|
||||
bufsize = NCP_SERVER(inode)->buffer_size;
|
||||
|
||||
already_written = 0;
|
||||
|
||||
while (already_written < count) {
|
||||
|
||||
int written_this_time;
|
||||
|
||||
if ((pos % bufsize) != 0) {
|
||||
to_write = bufsize - (pos % bufsize);
|
||||
} else {
|
||||
to_write = bufsize;
|
||||
}
|
||||
|
||||
to_write = min(to_write, count - already_written);
|
||||
if (ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_id,
|
||||
pos, to_write, buf, &written_this_time) != 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
pos += written_this_time;
|
||||
buf += written_this_time;
|
||||
already_written += written_this_time;
|
||||
|
||||
if (written_this_time < to_write) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
|
||||
inode->i_dirt = 1;
|
||||
|
||||
file->f_pos = pos;
|
||||
|
||||
if (pos > inode->i_size) {
|
||||
inode->i_size = pos;
|
||||
}
|
||||
|
||||
DPRINTK("ncp_file_write: exit %s\n", NCP_FINFO(inode)->path);
|
||||
|
||||
return already_written;
|
||||
}
|
||||
|
||||
static struct file_operations ncp_file_operations = {
|
||||
NULL, /* lseek - default */
|
||||
ncp_file_read, /* read */
|
||||
NULL, /* write */
|
||||
ncp_file_write, /* write */
|
||||
NULL, /* readdir - bad */
|
||||
NULL, /* select - default */
|
||||
ncp_ioctl, /* ioctl */
|
||||
|
||||
79
inode.c
79
inode.c
@@ -34,15 +34,17 @@ extern int close_fp(struct file *filp);
|
||||
static void ncp_put_inode(struct inode *);
|
||||
static void ncp_read_inode(struct inode *);
|
||||
static void ncp_put_super(struct super_block *);
|
||||
static void ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
|
||||
static int ncp_notify_change(struct inode *inode, struct iattr *attr);
|
||||
|
||||
static struct super_operations ncp_sops = {
|
||||
ncp_read_inode, /* read inode */
|
||||
NULL, /* notify change */
|
||||
ncp_notify_change, /* notify change */
|
||||
NULL, /* write inode */
|
||||
ncp_put_inode, /* put inode */
|
||||
ncp_put_super, /* put superblock */
|
||||
NULL, /* write superblock */
|
||||
NULL, /* stat filesystem */
|
||||
ncp_statfs, /* stat filesystem */
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -328,6 +330,79 @@ ncp_put_super(struct super_block *sb)
|
||||
MOD_DEC_USE_COUNT;
|
||||
}
|
||||
|
||||
static void
|
||||
ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
|
||||
{
|
||||
struct statfs tmp;
|
||||
|
||||
/* We cannot say how much disk space is left on a mounted
|
||||
NetWare Server, because free space is distributed over
|
||||
volumes, and the current user might have disk quotas. So
|
||||
free space is not that simple to determine. Our decision
|
||||
here is to err conservatively. */
|
||||
|
||||
tmp.f_type = NCP_SUPER_MAGIC;
|
||||
tmp.f_bsize = 512;
|
||||
tmp.f_blocks = 0;
|
||||
tmp.f_bfree = 0;
|
||||
tmp.f_bavail = 0;
|
||||
tmp.f_files = -1;
|
||||
tmp.f_ffree = -1;
|
||||
tmp.f_namelen = 12;
|
||||
memcpy_tofs(buf, &tmp, bufsiz);
|
||||
}
|
||||
|
||||
/* DO MORE */
|
||||
static int
|
||||
ncp_notify_change(struct inode *inode, struct iattr *attr)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
if ((error = inode_change_ok(inode, attr)) < 0)
|
||||
return error;
|
||||
|
||||
if (((attr->ia_valid & ATTR_UID) &&
|
||||
(attr->ia_uid != NCP_SERVER(inode)->m.uid)))
|
||||
return -EPERM;
|
||||
|
||||
if (((attr->ia_valid & ATTR_GID) &&
|
||||
(attr->ia_uid != NCP_SERVER(inode)->m.gid)))
|
||||
return -EPERM;
|
||||
|
||||
if (((attr->ia_valid & ATTR_MODE) &&
|
||||
(attr->ia_mode &
|
||||
~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
|
||||
return -EPERM;
|
||||
|
||||
if ((attr->ia_valid & ATTR_SIZE) != 0) {
|
||||
|
||||
struct ncp_file_info finfo;
|
||||
struct ncp_dirent *dirent = NCP_FINFO(inode);
|
||||
|
||||
DPRINTK("ncpfs: trying to change size of %s to %ld\n",
|
||||
dirent->path, attr->ia_size);
|
||||
|
||||
if (attr->ia_size != 0) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (NCP_FINFO(inode)->opened != 0) {
|
||||
ncp_close_file(NCP_SERVER(inode), dirent->file_id);
|
||||
dirent->opened = 0;
|
||||
}
|
||||
|
||||
if (ncp_create_file(NCP_SERVER(inode), 0,
|
||||
dirent->path, 0, &finfo) == 0) {
|
||||
ncp_close_file(NCP_SERVER(inode), finfo.file_id);
|
||||
dirent->opened = 0;
|
||||
}
|
||||
error = 0;
|
||||
}
|
||||
|
||||
ncp_invalid_dir_cache((unsigned long)(NCP_INOP(inode)->dir));
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_NCP_MALLOC
|
||||
int ncp_malloced;
|
||||
|
||||
34
ncp.h
34
ncp.h
@@ -18,28 +18,28 @@
|
||||
#define NCP_DEALLOC_SLOT_REQUEST (0x5555)
|
||||
|
||||
struct ncp_request_header {
|
||||
__u16 type;
|
||||
__u8 sequence;
|
||||
__u8 conn_low;
|
||||
__u8 task;
|
||||
__u8 conn_high;
|
||||
__u8 function;
|
||||
__u8 data[0]; /* Depends upon request type */
|
||||
} __attribute__ ((packed));
|
||||
__u16 type __attribute__ ((packed));
|
||||
__u8 sequence __attribute__ ((packed));
|
||||
__u8 conn_low __attribute__ ((packed));
|
||||
__u8 task __attribute__ ((packed));
|
||||
__u8 conn_high __attribute__ ((packed));
|
||||
__u8 function __attribute__ ((packed));
|
||||
__u8 data[0] __attribute__ ((packed));
|
||||
};
|
||||
|
||||
#define NCP_REPLY (0x3333)
|
||||
#define NCP_POSITIVE_ACK (0x9999)
|
||||
|
||||
struct ncp_reply_header {
|
||||
__u16 type;
|
||||
__u8 sequence;
|
||||
__u8 conn_low;
|
||||
__u8 task;
|
||||
__u8 conn_high;
|
||||
__u8 completion_code;
|
||||
__u8 connection_state;
|
||||
__u8 data[0]; /* Depends upon request type */
|
||||
} __attribute__ ((packed));
|
||||
__u16 type __attribute__ ((packed));
|
||||
__u8 sequence __attribute__ ((packed));
|
||||
__u8 conn_low __attribute__ ((packed));
|
||||
__u8 task __attribute__ ((packed));
|
||||
__u8 conn_high __attribute__ ((packed));
|
||||
__u8 completion_code __attribute__ ((packed));
|
||||
__u8 connection_state __attribute__ ((packed));
|
||||
__u8 data[0] __attribute__ ((packed));
|
||||
};
|
||||
|
||||
|
||||
#define NCP_BINDERY_USER (0x0001)
|
||||
|
||||
7
ncp_fs.h
7
ncp_fs.h
@@ -50,10 +50,10 @@ struct ncp_ioctl_request {
|
||||
#define NCP_SUPER_MAGIC 0x564c
|
||||
|
||||
|
||||
#define NCP_SBP(sb) ((struct ncp_server *)(sb->u.generic_sbp))
|
||||
#define NCP_INOP(inode) ((struct ncp_inode_info *)(inode->u.generic_ip))
|
||||
#define NCP_SBP(sb) ((struct ncp_server *)((sb)->u.generic_sbp))
|
||||
#define NCP_INOP(inode) ((struct ncp_inode_info *)((inode)->u.generic_ip))
|
||||
|
||||
#define NCP_SERVER(inode) NCP_SBP(inode->i_sb)
|
||||
#define NCP_SERVER(inode) NCP_SBP((inode)->i_sb)
|
||||
#define NCP_FINFO(inode) (&(NCP_INOP(inode)->finfo))
|
||||
|
||||
static inline int min(int a, int b) {
|
||||
@@ -124,7 +124,6 @@ int ncp_ioctl (struct inode * inode, struct file * filp,
|
||||
/* linux/fs/ncpfs/inode.c */
|
||||
struct super_block *ncp_read_super(struct super_block *sb,
|
||||
void *raw_data, int silent);
|
||||
int ncp_notify_change(struct inode *inode, struct iattr *attr);
|
||||
void ncp_invalidate_connection(struct ncp_server *server);
|
||||
int ncp_conn_is_valid(struct ncp_server *server);
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
Begin3
|
||||
Title: ncpfs
|
||||
Version: 0.1
|
||||
Entered-date: 19. October 1995
|
||||
Version: 0.3
|
||||
Entered-date: 01. November 1995
|
||||
Description: With ncpfs you can mount volumes of your novell
|
||||
server under Linux.
|
||||
Keywords: filesystem kernel ncp novell
|
||||
Keywords: filesystem kernel ncp novell netware
|
||||
Author: lendecke@namu01.gwdg.de (Volker Lendecke)
|
||||
Maintained-by: lendecke@namu01.gwdg.de (Volker Lendecke)
|
||||
Primary-site: linux01.gwdg.de:/pub/smbfs
|
||||
~30k ncpfs-0.1.tgz
|
||||
~ 1k ncpfs-0.1.lsm
|
||||
Primary-site: linux01.gwdg.de:/pub/ncpfs
|
||||
~45k ncpfs-0.3.tgz
|
||||
~ 1k ncpfs-0.3.lsm
|
||||
Copying-policy: GPL
|
||||
End
|
||||
237
ncplib.c
237
ncplib.c
@@ -126,6 +126,19 @@ ncp_add_mem(struct ncp_server *server, const char *source, int size)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
static void
|
||||
ncp_add_mem_fromfs(struct ncp_server *server, const char *source, int size)
|
||||
{
|
||||
assert_server_locked(server);
|
||||
memcpy_fromfs(&(server->packet[server->current_size]), source, size);
|
||||
server->current_size += size;
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
ncp_add_pstring(struct ncp_server *server, const char *s)
|
||||
{
|
||||
@@ -536,6 +549,176 @@ ncp_close_file(struct ncp_server *server, const char *file_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ncp_do_create(struct ncp_server *server,
|
||||
int dir_handle, const char *path,
|
||||
int attr,
|
||||
struct ncp_file_info *target,
|
||||
int function)
|
||||
{
|
||||
int result;
|
||||
|
||||
ncp_init_request(server);
|
||||
ncp_add_byte(server, dir_handle);
|
||||
ncp_add_byte(server, attr);
|
||||
ncp_add_pstring(server, path);
|
||||
|
||||
if ((result = ncp_request(server, function)) != 0) {
|
||||
ncp_printf("ncp_request_error: %d\n", result);
|
||||
ncp_unlock_server(server);
|
||||
return result;
|
||||
}
|
||||
|
||||
memcpy(&(target->file_id), ncp_reply_data(server, 0),
|
||||
NCP_FILE_ID_LEN);
|
||||
|
||||
memset(&(target->file_name), 0, sizeof(target->file_name));
|
||||
memcpy(&(target->file_name), ncp_reply_data(server, 8),
|
||||
NCP_MAX_FILENAME);
|
||||
|
||||
target->file_attributes = ncp_reply_byte(server, 22);
|
||||
target->file_mode = ncp_reply_byte(server, 23);
|
||||
target->file_length = ntohl(ncp_reply_dword(server, 24));
|
||||
target->creation_date = ntohs(ncp_reply_word(server, 28));
|
||||
target->access_date = ntohs(ncp_reply_word(server, 30));
|
||||
target->update_date = ntohs(ncp_reply_word(server, 32));
|
||||
target->update_time = ntohs(ncp_reply_word(server, 34));
|
||||
|
||||
ncp_unlock_server(server);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ncp_create_newfile(struct ncp_server *server,
|
||||
int dir_handle, const char *path,
|
||||
int attr,
|
||||
struct ncp_file_info *target)
|
||||
{
|
||||
return ncp_do_create(server, dir_handle, path, attr, target, 77);
|
||||
}
|
||||
|
||||
int
|
||||
ncp_create_file(struct ncp_server *server,
|
||||
int dir_handle, const char *path,
|
||||
int attr,
|
||||
struct ncp_file_info *target)
|
||||
{
|
||||
return ncp_do_create(server, dir_handle, path, attr, target, 67);
|
||||
}
|
||||
|
||||
int
|
||||
ncp_erase_file(struct ncp_server *server,
|
||||
int dir_handle, const char *path,
|
||||
int attr)
|
||||
{
|
||||
int result;
|
||||
|
||||
ncp_init_request(server);
|
||||
ncp_add_byte(server, dir_handle);
|
||||
ncp_add_byte(server, attr);
|
||||
ncp_add_pstring(server, path);
|
||||
|
||||
if ((result = ncp_request(server, 68)) != 0) {
|
||||
ncp_printf("ncp_request_error: %d\n", result);
|
||||
ncp_unlock_server(server);
|
||||
return result;
|
||||
}
|
||||
|
||||
ncp_unlock_server(server);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ncp_rename_file(struct ncp_server *server,
|
||||
int old_handle, const char *old_path,
|
||||
int attr,
|
||||
int new_handle, const char *new_path)
|
||||
{
|
||||
int result;
|
||||
|
||||
ncp_init_request(server);
|
||||
ncp_add_byte(server, old_handle);
|
||||
ncp_add_byte(server, attr);
|
||||
ncp_add_pstring(server, old_path);
|
||||
ncp_add_byte(server, new_handle);
|
||||
ncp_add_pstring(server, new_path);
|
||||
|
||||
if ((result = ncp_request(server, 69)) != 0) {
|
||||
ncp_printf("ncp_request_error: %d\n", result);
|
||||
ncp_unlock_server(server);
|
||||
return result;
|
||||
}
|
||||
|
||||
ncp_unlock_server(server);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ncp_create_directory(struct ncp_server *server,
|
||||
int dir_handle, const char *path,
|
||||
int inherit_mask)
|
||||
{
|
||||
int result;
|
||||
|
||||
ncp_init_request_s(server, 10);
|
||||
ncp_add_byte(server, dir_handle);
|
||||
ncp_add_byte(server, inherit_mask);
|
||||
ncp_add_pstring(server, path);
|
||||
|
||||
if ((result = ncp_request(server, 22)) != 0) {
|
||||
ncp_printf("ncp_request_error: %d\n", result);
|
||||
ncp_unlock_server(server);
|
||||
return result;
|
||||
}
|
||||
|
||||
ncp_unlock_server(server);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ncp_delete_directory(struct ncp_server *server,
|
||||
int dir_handle, const char *path)
|
||||
{
|
||||
int result;
|
||||
|
||||
ncp_init_request_s(server, 11);
|
||||
ncp_add_byte(server, dir_handle);
|
||||
ncp_add_byte(server, 0); /* reserved */
|
||||
ncp_add_pstring(server, path);
|
||||
|
||||
if ((result = ncp_request(server, 22)) != 0) {
|
||||
ncp_printf("ncp_request_error: %d\n", result);
|
||||
ncp_unlock_server(server);
|
||||
return result;
|
||||
}
|
||||
|
||||
ncp_unlock_server(server);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ncp_rename_directory(struct ncp_server *server,
|
||||
int dir_handle,
|
||||
const char *old_path, const char *new_path)
|
||||
{
|
||||
int result;
|
||||
|
||||
ncp_init_request_s(server, 15);
|
||||
ncp_add_byte(server, dir_handle);
|
||||
ncp_add_pstring(server, old_path);
|
||||
ncp_add_pstring(server, new_path);
|
||||
|
||||
if ((result = ncp_request(server, 22)) != 0) {
|
||||
ncp_printf("ncp_request_error: %d\n", result);
|
||||
ncp_unlock_server(server);
|
||||
return result;
|
||||
}
|
||||
|
||||
ncp_unlock_server(server);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifndef __KERNEL__
|
||||
|
||||
int
|
||||
@@ -565,9 +748,35 @@ ncp_read(struct ncp_server *server, const char *file_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ncp_write(struct ncp_server *server, const char *file_id,
|
||||
__u32 offset, __u16 to_write,
|
||||
const char *source, int *bytes_written)
|
||||
{
|
||||
int result;
|
||||
|
||||
ncp_init_request(server);
|
||||
ncp_add_byte(server, 0);
|
||||
ncp_add_mem(server, file_id, 6);
|
||||
ncp_add_dword(server, htonl(offset));
|
||||
ncp_add_word(server, htons(to_write));
|
||||
ncp_add_mem(server, source, to_write);
|
||||
|
||||
if ((result = ncp_request(server, 73)) != 0) {
|
||||
ncp_printf("ncp_request_error: %d\n", result);
|
||||
ncp_unlock_server(server);
|
||||
return result;
|
||||
}
|
||||
|
||||
*bytes_written = to_write;
|
||||
|
||||
ncp_unlock_server(server);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* We have to read into user space */
|
||||
/* We have to transfer to/from user space */
|
||||
int
|
||||
ncp_read(struct ncp_server *server, const char *file_id,
|
||||
__u32 offset, __u16 to_read,
|
||||
@@ -595,4 +804,30 @@ ncp_read(struct ncp_server *server, const char *file_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ncp_write(struct ncp_server *server, const char *file_id,
|
||||
__u32 offset, __u16 to_write,
|
||||
const char *source, int *bytes_written)
|
||||
{
|
||||
int result;
|
||||
|
||||
ncp_init_request(server);
|
||||
ncp_add_byte(server, 0);
|
||||
ncp_add_mem(server, file_id, 6);
|
||||
ncp_add_dword(server, htonl(offset));
|
||||
ncp_add_word(server, htons(to_write));
|
||||
ncp_add_mem_fromfs(server, source, to_write);
|
||||
|
||||
if ((result = ncp_request(server, 73)) != 0) {
|
||||
ncp_printf("ncp_request_error: %d\n", result);
|
||||
ncp_unlock_server(server);
|
||||
return result;
|
||||
}
|
||||
|
||||
*bytes_written = to_write;
|
||||
|
||||
ncp_unlock_server(server);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
44
ncplib.h
44
ncplib.h
@@ -94,9 +94,51 @@ ncp_open_file(struct ncp_server *server,
|
||||
int
|
||||
ncp_close_file(struct ncp_server *server, const char *file_id);
|
||||
|
||||
int
|
||||
ncp_create_newfile(struct ncp_server *server,
|
||||
int dir_handle, const char *path,
|
||||
int attr,
|
||||
struct ncp_file_info *target);
|
||||
|
||||
int
|
||||
ncp_create_file(struct ncp_server *server,
|
||||
int dir_handle, const char *path,
|
||||
int attr,
|
||||
struct ncp_file_info *target);
|
||||
|
||||
int
|
||||
ncp_erase_file(struct ncp_server *server,
|
||||
int dir_handle, const char *path,
|
||||
int attr);
|
||||
|
||||
int
|
||||
ncp_rename_file(struct ncp_server *server,
|
||||
int old_handle, const char *old_path,
|
||||
int attr,
|
||||
int new_handle, const char *new_path);
|
||||
|
||||
int
|
||||
ncp_create_directory(struct ncp_server *server,
|
||||
int dir_handle, const char *path,
|
||||
int inherit_mask);
|
||||
|
||||
int
|
||||
ncp_delete_directory(struct ncp_server *server,
|
||||
int dir_handle, const char *path);
|
||||
|
||||
int
|
||||
ncp_rename_directory(struct ncp_server *server,
|
||||
int dir_handle,
|
||||
const char *old_path, const char *new_path);
|
||||
|
||||
int
|
||||
ncp_read(struct ncp_server *server, const char *file_id,
|
||||
__u32 start, __u16 to_read,
|
||||
__u32 offset, __u16 to_read,
|
||||
char *target, int *bytes_read);
|
||||
|
||||
int
|
||||
ncp_write(struct ncp_server *server, const char *file_id,
|
||||
__u32 offset, __u16 to_write,
|
||||
const char *source, int *bytes_written);
|
||||
|
||||
#endif /* _NCPLIB_H */
|
||||
|
||||
450
ncpmount.c
450
ncpmount.c
@@ -15,13 +15,11 @@
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
/* #include <sys/wait.h> */ /* generates a warning here */
|
||||
extern pid_t waitpid(pid_t, int *, int);
|
||||
#include <sys/errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
@@ -38,8 +36,54 @@ extern pid_t waitpid(pid_t, int *, int);
|
||||
#include "ipxutil.h"
|
||||
|
||||
static char *progname;
|
||||
static char *mount_point;
|
||||
static char *server_name;
|
||||
|
||||
|
||||
static void
|
||||
str_upper(char *name)
|
||||
{
|
||||
while (*name) {
|
||||
*name = toupper(*name);
|
||||
name = name + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
fullpath(const char *p)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
if (realpath(p, path) == NULL)
|
||||
return strdup(p);
|
||||
else
|
||||
return strdup(path);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
printf("usage: %s server mount-point [options]\n", progname);
|
||||
printf("Try `%s -h' for more information\n", progname);
|
||||
}
|
||||
|
||||
static void
|
||||
help(void)
|
||||
{
|
||||
printf("\n");
|
||||
printf("usage: %s server mount-point [options]\n", progname);
|
||||
printf("\n"
|
||||
"-U username Username sent to server\n"
|
||||
"-u uid uid the mounted files get\n"
|
||||
"-g gid gid the mounted files get\n"
|
||||
"-f mode permission the files get (octal notation)\n"
|
||||
"-d mode permission the dirs get (octal notation)\n"
|
||||
"-C Don't convert password to uppercase\n"
|
||||
"-P password Use this password\n"
|
||||
"-n Do not use any password\n"
|
||||
" If neither -P nor -n are given, you are\n"
|
||||
" asked for a password.\n"
|
||||
"-h print this help text\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
struct sap_query {
|
||||
unsigned short query_type; /* net order */
|
||||
@@ -47,15 +91,14 @@ struct sap_query {
|
||||
};
|
||||
|
||||
struct sap_server_ident {
|
||||
unsigned short server_type;
|
||||
char server_name[48];
|
||||
IPXNet server_network;
|
||||
IPXNode server_node;
|
||||
IPXPort server_port;
|
||||
unsigned short intermediate_network;
|
||||
} __attribute__ ((packed));
|
||||
unsigned short server_type __attribute__ ((packed));
|
||||
char server_name[48] __attribute__ ((packed));
|
||||
IPXNet server_network __attribute__ ((packed));
|
||||
IPXNode server_node __attribute__ ((packed));
|
||||
IPXPort server_port __attribute__ ((packed));
|
||||
unsigned short intermediate_network __attribute__ ((packed));
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
ipx_fprint_node(FILE* file,IPXNode node)
|
||||
{
|
||||
@@ -212,33 +255,217 @@ ipx_sap_find_server(char *name, int server_type, int timeout,
|
||||
return res;
|
||||
}
|
||||
|
||||
int ipx_sscanf_node(char *buf, unsigned char node[6])
|
||||
int
|
||||
ipx_sscanf_node(char *buf, unsigned char node[6])
|
||||
{
|
||||
int i;
|
||||
int n[6];
|
||||
int i;
|
||||
int n[6];
|
||||
|
||||
if ((i = sscanf(buf, "%2x%2x%2x%2x%2x%2x",
|
||||
&(n[0]), &(n[1]), &(n[2]),
|
||||
&(n[3]), &(n[4]), &(n[5]))) != 6) {
|
||||
return i;
|
||||
}
|
||||
if ((i = sscanf(buf, "%2x%2x%2x%2x%2x%2x",
|
||||
&(n[0]), &(n[1]), &(n[2]),
|
||||
&(n[3]), &(n[4]), &(n[5]))) != 6) {
|
||||
return i;
|
||||
}
|
||||
|
||||
for (i=0; i<6; i++) {
|
||||
node[i] = n[i];
|
||||
}
|
||||
return 6;
|
||||
for (i=0; i<6; i++) {
|
||||
node[i] = n[i];
|
||||
}
|
||||
return 6;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
static int
|
||||
parse_args(int argc, char *argv[], struct ncp_mount_data *data,
|
||||
int *got_password, int *upcase_password)
|
||||
{
|
||||
struct ncp_mount_data data;
|
||||
struct stat st;
|
||||
struct sockaddr_ipx addr;
|
||||
int ncp_sock, wdog_sock;
|
||||
int flags;
|
||||
int opt;
|
||||
struct passwd *pwd;
|
||||
struct group *grp;
|
||||
|
||||
progname = argv[0];
|
||||
*got_password = 0;
|
||||
*upcase_password = 1;
|
||||
|
||||
while ((opt = getopt (argc, argv, "Cp:s:c:U:u:g:f:d:m:P:n")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'C':
|
||||
*upcase_password = 0;
|
||||
break;
|
||||
case 'U':
|
||||
if (strlen(optarg) > 63) {
|
||||
fprintf(stderr, "Username too long: %s\n",
|
||||
optarg);
|
||||
return 1;
|
||||
}
|
||||
strcpy(data->username, optarg);
|
||||
break;
|
||||
case 'u':
|
||||
if (isdigit(optarg[0])) {
|
||||
data->uid = atoi(optarg);
|
||||
} else {
|
||||
pwd = getpwnam(optarg);
|
||||
if (pwd == NULL) {
|
||||
fprintf(stderr, "Unknown user: %s\n",
|
||||
optarg);
|
||||
return 1;
|
||||
}
|
||||
data->uid = pwd->pw_uid;
|
||||
}
|
||||
break;
|
||||
case 'g':
|
||||
if (isdigit(optarg[0])) {
|
||||
data->gid = atoi(optarg);
|
||||
} else {
|
||||
grp = getgrnam(optarg);
|
||||
if (grp == NULL) {
|
||||
fprintf(stderr, "Unknown group: %s\n",
|
||||
optarg);
|
||||
return 1;
|
||||
}
|
||||
data->gid = grp->gr_gid;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
data->file_mode = strtol(optarg, NULL, 8);
|
||||
break;
|
||||
case 'd':
|
||||
data->dir_mode = strtol(optarg, NULL, 8);
|
||||
break;
|
||||
case 'P':
|
||||
strcpy(data->password, optarg);
|
||||
*got_password = 1;
|
||||
break;
|
||||
case 'n':
|
||||
data->password[0] = '\0';
|
||||
*got_password = 1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* Returns 0 if the filesystem is in the kernel after this routine
|
||||
completes */
|
||||
static int
|
||||
load_ncpfs()
|
||||
{
|
||||
FILE *fver, *ffs;
|
||||
char s[1024];
|
||||
char modname[1024];
|
||||
char *p, *p1;
|
||||
pid_t pid;
|
||||
int status;
|
||||
|
||||
/* Check if ncpfs is in the kernel */
|
||||
ffs = fopen("/proc/filesystems", "r");
|
||||
if (ffs == NULL) {
|
||||
perror("Error: \"/proc/filesystems\" could not be read:");
|
||||
return -1;
|
||||
}
|
||||
p = NULL;
|
||||
while (! feof(ffs)) {
|
||||
p1 = fgets(s, sizeof(s), ffs);
|
||||
if (p1) {
|
||||
p = strstr(s, "ncpfs");
|
||||
if (p) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(ffs);
|
||||
if (p) {
|
||||
return 0;
|
||||
}
|
||||
fver = fopen("/proc/version", "r");
|
||||
if (fver == NULL) {
|
||||
perror("Error: \"/proc/version\" could not be read:");
|
||||
return -1;
|
||||
}
|
||||
fgets(s, 1024, fver);
|
||||
fclose(fver);
|
||||
p = strstr(s, "version ");
|
||||
if (p == NULL) {
|
||||
version_error:
|
||||
fprintf(stderr, "Error: Unable to determine the Linux version"
|
||||
"from \"/proc/version\n");
|
||||
return -1;
|
||||
}
|
||||
p = strchr(p, ' ') + 1;
|
||||
p1 = strchr(p, ' ');
|
||||
if (p1 == NULL) {
|
||||
goto version_error;
|
||||
}
|
||||
strcpy(modname, "/lib/modules/");
|
||||
strncat(modname, p, p1 - p);
|
||||
strcat(modname, "/ncpfs.o");
|
||||
|
||||
/* system() function without signal handling, from Stevens */
|
||||
|
||||
if ((pid = fork()) < 0) {
|
||||
return 1;
|
||||
} else if (pid == 0) {
|
||||
/* child */
|
||||
execl("/sbin/insmod", "insmod", modname, NULL);
|
||||
_exit(127); /* execl error */
|
||||
} else {
|
||||
/* parent */
|
||||
while (waitpid(pid, &status, 0) < 0) {
|
||||
if (errno != EINTR) {
|
||||
status = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Check whether user is allowed to mount on the specified mount point */
|
||||
static int
|
||||
mount_ok(struct stat *st)
|
||||
{
|
||||
if (!S_ISDIR(st->st_mode))
|
||||
{
|
||||
errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( (getuid() != 0)
|
||||
&& ( (getuid() != st->st_uid)
|
||||
|| ((st->st_mode & S_IRWXU) != S_IRWXU)))
|
||||
{
|
||||
errno = EPERM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct ncp_mount_data data;
|
||||
struct sockaddr_ipx addr;
|
||||
struct stat st;
|
||||
|
||||
int fd;
|
||||
int Got_Password;
|
||||
int Upcase_Password;
|
||||
int um;
|
||||
unsigned int flags;
|
||||
char hostname[MAXHOSTNAMELEN + 1];
|
||||
|
||||
char *server_name;
|
||||
char *mount_point;
|
||||
|
||||
struct mntent ment;
|
||||
FILE *mtab;
|
||||
|
||||
int ncp_sock, wdog_sock;
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
if (geteuid() != 0) {
|
||||
fprintf(stderr, "%s must be installed suid root\n", progname);
|
||||
@@ -247,22 +474,43 @@ main(int argc, char **argv)
|
||||
|
||||
memset(&data, 0, sizeof(struct ncp_mount_data));
|
||||
|
||||
if (argc != 5) {
|
||||
fprintf(stderr, "usage: %s server mount-point"
|
||||
" user password\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
memset(hostname, '\0', MAXHOSTNAMELEN+1);
|
||||
gethostname(hostname, MAXHOSTNAMELEN);
|
||||
|
||||
server_name = argv[1];
|
||||
mount_point = argv[2];
|
||||
|
||||
if (argc < 3) {
|
||||
if ( (argc == 2)
|
||||
&& (argv[1][0] == '-')
|
||||
&& (argv[1][1] == 'h')
|
||||
&& (argv[1][2] == '\0')) {
|
||||
|
||||
if (stat(mount_point, &st) == -1) {
|
||||
help();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
server_name = argv[1];
|
||||
mount_point = argv[2];
|
||||
|
||||
argv += 2;
|
||||
argc -= 2;
|
||||
|
||||
if (stat(mount_point, &st) == -1) {
|
||||
fprintf(stderr, "could not find mount point %s: %s\n",
|
||||
mount_point, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (mount_ok(&st) != 0) {
|
||||
fprintf(stderr, "cannot to mount on %s: %s\n",
|
||||
mount_point, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ncp_sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
|
||||
if (ncp_sock == -1) {
|
||||
fprintf(stderr, "could not open ncp socket: %s\n",
|
||||
@@ -297,10 +545,13 @@ main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("server: ");
|
||||
ipx_fprint_saddr(stdout, &addr);
|
||||
printf("\n");
|
||||
|
||||
/* Check if the ncpfs filesystem is in the kernel. If not, attempt
|
||||
* to load the ncpfs module */
|
||||
if (load_ncpfs() != 0) {
|
||||
fprintf(stderr, "Error: Unable to start ncpfs, exiting...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
data.version = NCP_MOUNT_VERSION;
|
||||
data.ncp_fd = ncp_sock;
|
||||
data.wdog_fd = wdog_sock;
|
||||
@@ -309,24 +560,111 @@ main(int argc, char **argv)
|
||||
strcpy(data.server_name, server_name);
|
||||
data.time_out = 20; /* 2 seconds */
|
||||
data.retry_count = 2;
|
||||
data.uid = 501; /* me */
|
||||
data.gid = 100; /* users */
|
||||
data.file_mode = data.dir_mode = S_IRWXU|S_IRWXG|S_IRWXO;
|
||||
strcpy(data.username, argv[3]);
|
||||
strcpy(data.password, argv[4]);
|
||||
|
||||
/* getuid() gives us the real uid, who may umount the fs */
|
||||
data.mounted_uid = getuid();
|
||||
|
||||
if (getenv("USER")) {
|
||||
strcpy(data.username, getenv("USER"));
|
||||
str_upper(data.username);
|
||||
}
|
||||
|
||||
if (data.username[0] == 0 && getenv("LOGNAME"))
|
||||
{
|
||||
strcpy(data.username,getenv("LOGNAME"));
|
||||
str_upper(data.username);
|
||||
}
|
||||
|
||||
data.uid = getuid();
|
||||
data.gid = getgid();
|
||||
um = umask(0);
|
||||
umask(um);
|
||||
data.file_mode = (S_IRWXU|S_IRWXG|S_IRWXO) & ~um;
|
||||
data.dir_mode = 0;
|
||||
|
||||
if (parse_args(argc, argv, &data, &Got_Password,
|
||||
&Upcase_Password) != 0) {
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data.dir_mode == 0) {
|
||||
data.dir_mode = data.file_mode;
|
||||
if ((data.dir_mode & S_IRUSR) != 0)
|
||||
data.dir_mode |= S_IXUSR;
|
||||
if ((data.dir_mode & S_IRGRP) != 0)
|
||||
data.dir_mode |= S_IXGRP;
|
||||
if ((data.dir_mode & S_IROTH) != 0)
|
||||
data.dir_mode |= S_IXOTH;
|
||||
}
|
||||
|
||||
if (Got_Password == 0) {
|
||||
strcpy(data.password, getpass("Password: "));
|
||||
}
|
||||
|
||||
if (Upcase_Password == 1) {
|
||||
str_upper(data.password);
|
||||
}
|
||||
|
||||
if (data.server_name[0] == '\0') {
|
||||
strcpy(data.server_name, server_name);
|
||||
str_upper(data.server_name);
|
||||
}
|
||||
|
||||
flags = MS_MGC_VAL;
|
||||
|
||||
if (mount(NULL, mount_point, "ncpfs", flags, (char *)&data) < 0) {
|
||||
if (mount(NULL, mount_point, "ncpfs",
|
||||
flags, (char *)&data) < 0) {
|
||||
perror("mount error");
|
||||
fprintf(stderr, "Maybe you should try your password in "
|
||||
"upper case\n");
|
||||
close(wdog_sock);
|
||||
close(ncp_sock);
|
||||
printf("Maybe you should try to type the username and\n"
|
||||
"password in UPPERCASE.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(ncp_sock);
|
||||
close(wdog_sock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
ment.mnt_fsname = server_name;
|
||||
ment.mnt_dir = fullpath(mount_point);
|
||||
ment.mnt_type = "ncpfs";
|
||||
ment.mnt_opts = "rw";
|
||||
ment.mnt_freq = 0;
|
||||
ment.mnt_passno= 0;
|
||||
|
||||
mount_point = ment.mnt_dir;
|
||||
|
||||
if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1)
|
||||
{
|
||||
fprintf(stderr, "Can't get "MOUNTED"~ lock file");
|
||||
return 1;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
if ((mtab = setmntent(MOUNTED, "a+")) == NULL)
|
||||
{
|
||||
fprintf(stderr, "Can't open " MOUNTED);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (addmntent(mtab, &ment) == 1)
|
||||
{
|
||||
fprintf(stderr, "Can't write mount entry");
|
||||
return 1;
|
||||
}
|
||||
if (fchmod(fileno(mtab), 0644) == -1)
|
||||
{
|
||||
fprintf(stderr, "Can't set perms on "MOUNTED);
|
||||
return 1;
|
||||
}
|
||||
endmntent(mtab);
|
||||
|
||||
if (unlink(MOUNTED"~") == -1)
|
||||
{
|
||||
fprintf(stderr, "Can't remove "MOUNTED"~");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
173
ncptest.c
Normal file
173
ncptest.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* ncpmount.c
|
||||
*
|
||||
* Copyright (C) 1995 by Volker Lendecke
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
/* #include <sys/wait.h> */ /* generates a warning here */
|
||||
extern pid_t waitpid(pid_t, int *, int);
|
||||
#include <sys/errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mount.h>
|
||||
#include <mntent.h>
|
||||
#include <linux/ipx.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/ncp.h>
|
||||
#include <linux/ncp_fs.h>
|
||||
#include <linux/ncp_mount.h>
|
||||
#include "ncplib.h"
|
||||
#include "ipxutil.h"
|
||||
|
||||
static char *progname;
|
||||
static char *mount_point;
|
||||
|
||||
void
|
||||
test_filesearch(struct ncp_server *server)
|
||||
{
|
||||
struct ncp_filesearch_info fsinfo;
|
||||
struct ncp_file_info finfo;
|
||||
|
||||
if (ncp_file_search_init(server, 0, "sys:\\public", &fsinfo) != 0) {
|
||||
printf("could not fs init\n");
|
||||
return;
|
||||
}
|
||||
|
||||
while (ncp_file_search_continue(server, &fsinfo,
|
||||
0,
|
||||
"*", &finfo) == 0) {
|
||||
printf("name: %s\n", finfo.file_name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
test_getfinfo(struct ncp_server *server)
|
||||
{
|
||||
struct ncp_file_info finfo;
|
||||
|
||||
ncp_get_finfo(server, 0, "sys:", "public", &finfo);
|
||||
ncp_get_finfo(server, 0, "sys:login", "login.exe", &finfo);
|
||||
}
|
||||
|
||||
void
|
||||
testopen(struct ncp_server *server)
|
||||
{
|
||||
struct ncp_file_info finfo;
|
||||
char buf[1025];
|
||||
int bytes_read;
|
||||
|
||||
ncp_open_file(server, 0, "sys:\\etc\\samples\\protocol", 0,
|
||||
AR_READ|AR_WRITE,
|
||||
&finfo);
|
||||
if (ncp_read(server, finfo.file_id, 0, 1024, buf, &bytes_read) == 0) {
|
||||
printf("bytes: %d\n", bytes_read);
|
||||
buf[bytes_read]=0;
|
||||
puts(buf);
|
||||
}
|
||||
|
||||
ncp_close_file(server, finfo.file_id);
|
||||
}
|
||||
|
||||
void
|
||||
testcreate(struct ncp_server *server)
|
||||
{
|
||||
|
||||
if (ncp_rename_file(server, 0, "sys:\\me\\blub.txt", 0,
|
||||
0, "sys:\\me\\blub1.txt") != 0) {
|
||||
printf("create war nix\n");
|
||||
}
|
||||
if (ncp_create_directory(server, 0, "sys:\\me\\blubdir", 0xff) != 0) {
|
||||
printf("mkdir war nix\n");
|
||||
}
|
||||
if (ncp_rename_directory(server, 0, "sys:\\me\\blubdir",
|
||||
"\\me\\blubneu") != 0) {
|
||||
printf("mvdir war nix\n");
|
||||
return;
|
||||
}
|
||||
if (ncp_delete_directory(server, 0, "sys:\\me\\blubneu") != 0) {
|
||||
printf("rmdir war nix\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct ncp_mount_data data;
|
||||
struct stat st;
|
||||
struct ncp_server serv;
|
||||
struct ncp_server *server = &serv;
|
||||
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
if (geteuid() != 0) {
|
||||
fprintf(stderr, "%s must be installed suid root\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(&data, 0, sizeof(struct ncp_mount_data));
|
||||
|
||||
if (argc == 2) {
|
||||
mount_point = argv[1];
|
||||
} else {
|
||||
fprintf(stderr, "usage: %s mount-point\n", progname);
|
||||
printf("defaulting to %s mnt\n", progname);
|
||||
mount_point = "mnt";
|
||||
}
|
||||
|
||||
|
||||
if (stat(mount_point, &st) == -1) {
|
||||
fprintf(stderr, "could not find mount point %s: %s\n",
|
||||
mount_point, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
server->mount_fid = open(mount_point, O_RDONLY, 0);
|
||||
|
||||
if (server->mount_fid == -1) {
|
||||
fprintf(stderr, "Could not open %s: %s\n",
|
||||
mount_point, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
for (i=0; i<5; i++) {
|
||||
struct ncp_volume_info info;
|
||||
ncp_get_volume_info_with_number(server, i, &info);
|
||||
printf("vol %d: %s\n", i, info.volume_name);
|
||||
}
|
||||
|
||||
test_filesearch(server);
|
||||
test_getfinfo(server);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
testcreate(server);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
75
nwcrypt.c
75
nwcrypt.c
@@ -1,9 +1,7 @@
|
||||
/*$*********************************************************
|
||||
$*
|
||||
$* This code has been taken from DDJ 11/93, from an
|
||||
$* article by Pawel Szczerbina. Please read the file
|
||||
$* README for my questions about the legal status of
|
||||
$* this code.
|
||||
$* article by Pawel Szczerbina.
|
||||
$*
|
||||
$* Password encryption routines follow.
|
||||
$* Converted to C from Barry Nance's Pascal
|
||||
@@ -15,6 +13,77 @@ $* October 1995.
|
||||
$*
|
||||
$**********************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
I read that Novell is not very open when it comes to technical details
|
||||
of the Netware Core Protocol. This might be especially true for the
|
||||
encryption stuff. I took the necessary code from Dr. Dobb's Journal
|
||||
11/93, Undocumented Corner. I asked Jon Erickson <jon@ddj.com> about
|
||||
the legal status of this piece of code:
|
||||
|
||||
|
||||
---
|
||||
Date: Thu, 12 Oct 1995 13:44:18 +0100
|
||||
From: Volker Lendecke <lendecke>
|
||||
To: jon@ddj.com
|
||||
Subject: legal status of your source code?
|
||||
|
||||
|
||||
Hello!
|
||||
|
||||
I hope that you're the right one to write to, you are the first on your WWW
|
||||
server. If you are not, could you please forward this message to the right
|
||||
person? Thanks.
|
||||
|
||||
I'm currently exploring the possibility to write a free (in the GNU GPL
|
||||
sense) NCP filesystem, which would allow me to access a novell server
|
||||
transparently. For that I would like to use the encryption functions you
|
||||
published in DDJ 11/93, Undocumented Corner. I would make some cosmetic
|
||||
changes, such as other indentations, minor code changes and so on. But I do
|
||||
not know if that allows me to publish this code under GPL. One alternative
|
||||
would be to publish a diff against your listing, but that would probably
|
||||
contain much of your code as well, and it would be very inconvenient for
|
||||
the average user.
|
||||
|
||||
I think that you have some kind of standard procedure for such a
|
||||
case. Please tell me what I should do.
|
||||
|
||||
Many thanks in advance,
|
||||
|
||||
Volker
|
||||
|
||||
+=================================================================+
|
||||
! Volker Lendecke Internet: lendecke@namu01.gwdg.de !
|
||||
! D-37081 Goettingen, Germany !
|
||||
+=================================================================+
|
||||
|
||||
--
|
||||
|
||||
|
||||
I got the following answer:
|
||||
|
||||
---
|
||||
From: Jon Erickson <jon@ddj.com>
|
||||
X-Mailer: SCO System V Mail (version 3.2)
|
||||
To: lendecke@namu01.gwdg.de
|
||||
Subject: Re: legal status of your source code?
|
||||
Date: Thu, 12 Oct 95 5:42:56 PDT
|
||||
|
||||
Volker,
|
||||
Code from Dr. Dobb's Journal related articles is provided for
|
||||
anyone to use. Clearly, the author of the article should be
|
||||
given credit.
|
||||
Jon Erickson
|
||||
|
||||
---
|
||||
|
||||
With this answer in mind, I took the code and made it a bit more
|
||||
C-like. The original seemed to be translated by a mechanical pascal->c
|
||||
translator. Jon's answer encouraged me to publish nwcrypt.c under the
|
||||
GPL. If anybody who knows more about copyright and sees any problems
|
||||
with this, please tell me.
|
||||
****************************************************************************/
|
||||
|
||||
/******************* Data types ***************************/
|
||||
typedef unsigned char buf32[32];
|
||||
typedef unsigned char buf16[16];
|
||||
|
||||
2
sock.c
2
sock.c
@@ -84,7 +84,7 @@ ncp_wdog_data_ready(struct sock *sk, int len)
|
||||
sendto(sock, (void *)packet_buf, 2, 1, 0,
|
||||
(struct sockaddr *)&sender,
|
||||
sizeof(sender));
|
||||
printk("send result: %d\n", result);
|
||||
DPRINTK("send result: %d\n", result);
|
||||
}
|
||||
set_fs(fs);
|
||||
}
|
||||
|
||||
7
start_ipx
Executable file
7
start_ipx
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# abcd is my ipx network number and 1234 my server's internal network number.
|
||||
# 00001b038b11 is the server's node number.
|
||||
#
|
||||
ipx_interface add -p eth0 EtherII abcd
|
||||
ipx_route add 1234 abcd 00001b038b11
|
||||
Reference in New Issue
Block a user