Compare commits

...

2 Commits
v0.2 ... v0.4

Author SHA1 Message Date
ncpfs archive import
8fa4442004 Import ncpfs 0.4 2026-04-28 20:39:57 +02:00
ncpfs archive import
aaa3c6e7cc Import ncpfs 0.3 2026-04-28 20:39:57 +02:00
11 changed files with 165 additions and 74 deletions

BIN
.downloads/ncpfs-0.3.tgz Normal file

Binary file not shown.

BIN
.downloads/ncpfs-0.4.tgz Normal file

Binary file not shown.

17
BUGS Normal file
View 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
View File

@@ -1,3 +1,16 @@
ncpfs-0.3 -> ncpfs-0.4
- removed bug causing kernel to crash on filenames too long
This was a typical C bug! Thanks to Uwe Bonnes,
bon@elektron.ikp.physik.th-darmstadt.de for his patience with this one.
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

View File

@@ -6,8 +6,8 @@ INCLUDES = -I/usr/src/linux/include
CFLAGS = -Wall -Wstrict-prototypes -O2 -DMODULE -fomit-frame-pointer \
$(INCLUDES) \
-DDEBUG_NCP_MALLOC
# -DDEBUG_NCP=1 -DDEBUG_NCP_MALLOC
# -DDEBUG_NCP=2 -DDEBUG_NCP_MALLOC
# -DDEBUG_NCP_MALLOC
CC = gcc -D__KERNEL__ -I.
AS = as
@@ -27,6 +27,9 @@ all: ncpfs.o ncpmount ncptest
ncpfs.o: $(OBJS)
$(LD) -r -o ncpfs.o $(OBJS)
ncplib.o: ncplib.c ncplib.h
$(CC) $(CFLAGS) -finline-functions -c $<
ncpmount: ncpmount.o
gcc -o ncpmount ncpmount.o
@@ -40,7 +43,7 @@ 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
gcc -c ncplib.c -O3 -Wall -I. -g -o ncplib_user.o
nwcrypt.o: nwcrypt.c
gcc -c -O2 -Wall nwcrypt.c
@@ -52,7 +55,7 @@ clean:
rm -f *.o *~
realclean: clean
rm -fr ncpmount ncptest .depend $(DISTFILE) mnt
rm -fr ncpmount ncptest .depend $(DISTFILE) mnt *.out
modules: ncpfs.o

22
README
View File

@@ -17,13 +17,22 @@ 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.
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.
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!
LIMITATIONS (compare these with smbfs :-))
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
@@ -44,4 +53,3 @@ 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.

138
dir.c
View File

@@ -303,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;
@@ -319,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
@@ -353,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,
@@ -363,35 +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);
@@ -453,8 +477,10 @@ get_pname_static(struct inode *dir, const char *name, int len,
}
#endif
DDPRINTK("get_pname_static: parentname = %s, len = %d\n",
DDPRINTK("get_pname_static: parentname = %s, parlen = %d\n",
parentname, parentlen);
DDPRINTK("get_pname_static: name = %s, len = %d\n",
name, len);
if (len > NCP_MAXNAMELEN) {
return -ENAMETOOLONG;
@@ -480,7 +506,7 @@ get_pname_static(struct inode *dir, const char *name, int len,
/* We're at the top */
path[0] = '\0';
*res_len = 1;
*res_len = 0;
return 0;
}
@@ -497,7 +523,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';
@@ -530,7 +555,7 @@ get_pname(struct inode *dir, const char *name, int len,
int result_len;
int res;
if ((res = get_pname_static(dir,name,len,result,&result_len) != 0)) {
if ((res = get_pname_static(dir,name,len,result,&result_len)) != 0) {
return res;
}
@@ -730,7 +755,7 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
return -ENOENT;
}
DPRINTK("ncp_lookup: %s\n", __name);
DDPRINTK("ncp_lookup: %s, len %d\n", __name, len);
server = NCP_SERVER(dir);
@@ -746,6 +771,9 @@ ncp_lookup(struct inode *dir, const char *__name, int len,
return error;
}
DDPRINTK("ncp_lookup: get_pname for %s returned %d\n",
__name, error);
result_info = ncp_find_inode(NCP_SERVER(dir), name);
if (result_info != 0) {
@@ -787,10 +815,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",

24
inode.c
View File

@@ -34,6 +34,7 @@ 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 = {
@@ -43,7 +44,7 @@ static struct super_operations ncp_sops = {
ncp_put_inode, /* put inode */
ncp_put_super, /* put superblock */
NULL, /* write superblock */
NULL, /* stat filesystem */
ncp_statfs, /* stat filesystem */
NULL
};
@@ -329,6 +330,27 @@ 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

View File

@@ -1,14 +1,14 @@
Begin3
Title: ncpfs
Version: 0.2
Entered-date: 19. October 1995
Version: 0.4
Entered-date: 02. November 1995
Description: With ncpfs you can mount volumes of your novell
server under Linux.
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/ncpfs
~44k ncpfs-0.2.tgz
~ 1k ncpfs-0.2.lsm
~45k ncpfs-0.4.tgz
~ 1k ncpfs-0.4.lsm
Copying-policy: GPL
End

View File

@@ -334,7 +334,7 @@ parse_args(int argc, char *argv[], struct ncp_mount_data *data,
*got_password = 1;
break;
case 'n':
data->password[0] = '0';
data->password[0] = '\0';
*got_password = 1;
break;
default:
@@ -629,7 +629,7 @@ main(int argc, char *argv[])
ment.mnt_fsname = server_name;
ment.mnt_dir = fullpath(mount_point);
ment.mnt_type = "ncpfs";
ment.mnt_opts = "";
ment.mnt_opts = "rw";
ment.mnt_freq = 0;
ment.mnt_passno= 0;

2
sock.c
View File

@@ -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);
}