diff --git a/.downloads/ncpfs-0.7.tgz b/.downloads/ncpfs-0.7.tgz new file mode 100644 index 0000000..f638562 Binary files /dev/null and b/.downloads/ncpfs-0.7.tgz differ diff --git a/Makefile b/Makefile index 1e34194..f567a11 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux ncp-filesystem routines. # -KERNEL = 1.3 +KERNEL = 1.2 INCLUDES = -I/usr/src/linux/include -Ikernel BINDIR = ./bin @@ -31,7 +31,7 @@ clean: realclean: clean - rm -fr bin/* ncpfs.tgz util/mnt + rm -fr bin/* ncpfs.tgz make -C util realclean modules: ncpfs.o diff --git a/README b/README index 4b218d3..9d9feec 100644 --- a/README +++ b/README @@ -1,6 +1,16 @@ -This is version 0.6 of ncpfs, a free NetWare client for Linux. You -need at least kernel 1.3.44 for this version. It does NOT work with -any lower one, especially not with version 1.2.x. +This is version 0.7 of ncpfs, a free NetWare client filesystem for +Linux. This one currently works with Kernel 1.2.13. I do not know +whether it works with any other kernel of the 1.2.x series, I only +used it with 1.2.13. + +Due to problems in the 1.3.x IPX kernel code, ncpfs-0.7 does NOT work +with any 1.3.x kernel up to 1.3.44, although there is a kernel-1.3 +subdirectory. It compiles fine and seems to work, but any connection +will block after a very short time. Please be patient. I'm sure this +will be solved. If you follow the kernel development closely, you +might want to try ncpfs with a kernel later than 1.3.44, but I can not +promise anything. To try it with 1.3, simply change the variable +KERNEL in the Makefile from 1.2 to 1.3 and continue as usual. To install ncpfs, just type 'make'. After that, you find the neccessary kernel module and the mounting tools in ./bin. Type 'insmod diff --git a/kernel-1.2/linux/ncp.h b/kernel-1.2/linux/ncp.h new file mode 100644 index 0000000..83ffefd --- /dev/null +++ b/kernel-1.2/linux/ncp.h @@ -0,0 +1,282 @@ +/* + * ncp_fs.h + * + * Copyright (C) 1995 by Volker Lendecke + * + */ + +#ifndef _LINUX_NCP_H +#define _LINUX_NCP_H + +#include + +#define NCP_PTYPE (0x11) +#define NCP_PORT (0x0451) + +#define NCP_ALLOC_SLOT_REQUEST (0x1111) +#define NCP_REQUEST (0x2222) +#define NCP_DEALLOC_SLOT_REQUEST (0x5555) + +struct ncp_request_header { + __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 __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) +#define NCP_BINDERY_UGROUP (0x0002) +#define NCP_BINDERY_PQUEUE (0x0003) +#define NCP_BINDERY_FSERVER (0x0004) +#define NCP_BINDERY_NAME_LEN (48) +struct ncp_bindery_object { + __u32 object_id; + __u16 object_type; + __u8 object_name[NCP_BINDERY_NAME_LEN]; +}; + +struct nw_property { + __u8 value[128]; + __u8 more_flag; + __u8 property_flag; +}; + + +#define NCP_VOLNAME_LEN (16) +#define NCP_NUMBER_OF_VOLUMES (64) +struct ncp_volume_info { + __u32 total_blocks; + __u32 free_blocks; + __u32 purgeable_blocks; + __u32 not_yet_purgeable_blocks; + __u32 total_dir_entries; + __u32 available_dir_entries; + __u8 sectors_per_block; + char volume_name[NCP_VOLNAME_LEN+1]; +}; + +struct ncp_filesearch_info { + __u8 volume_number; + __u16 directory_id; + __u16 sequence_no; + __u8 access_rights; +}; + +#define NCP_MAX_FILENAME 14 + +/* these define the attribute byte as seen by NCP */ +#define aRONLY (1L<<0) +#define aHIDDEN (1L<<1) +#define aSYSTEM (1L<<2) +#define aEXECUTE (1L<<3) +#define aDIR (1L<<4) +#define aARCH (1L<<5) + +#define AR_READ (0x01) +#define AR_WRITE (0x02) +#define AR_EXCLUSIVE (0x20) + +#define NCP_FILE_ID_LEN 6 +struct ncp_file_info { + __u8 file_id[NCP_FILE_ID_LEN]; + char file_name[NCP_MAX_FILENAME+1]; + __u8 file_attributes; + __u8 file_mode; + __u32 file_length; + __u16 creation_date; + __u16 access_date; + __u16 update_date; + __u16 update_time; +}; + + +/* Defines for ReturnInformationMask */ +#define RIM_NAME (0x0001L) +#define RIM_SPACE_ALLOCATED (0x0002L) +#define RIM_ATTRIBUTES (0x0004L) +#define RIM_DATA_SIZE (0x0008L) +#define RIM_TOTAL_SIZE (0x0010L) +#define RIM_EXT_ATTR_INFO (0x0020L) +#define RIM_ARCHIVE (0x0040L) +#define RIM_MODIFY (0x0080L) +#define RIM_CREATION (0x0100L) +#define RIM_OWNING_NAMESPACE (0x0200L) +#define RIM_DIRECTORY (0x0400L) +#define RIM_RIGHTS (0x0800L) +#define RIM_ALL (0x0FFFL) +#define RIM_COMPRESSED_INFO (0x80000000L) + +/* open/create modes */ +#define OC_MODE_OPEN 0x01 +#define OC_MODE_TRUNCATE 0x02 +#define OC_MODE_REPLACE 0x02 +#define OC_MODE_CREATE 0x08 + +/* open/create results */ +#define OC_ACTION_NONE 0x00 +#define OC_ACTION_OPEN 0x01 +#define OC_ACTION_CREATE 0x02 +#define OC_ACTION_TRUNCATE 0x04 +#define OC_ACTION_REPLACE 0x04 + +/* access rights attributes */ +#ifndef AR_READ_ONLY +#define AR_READ_ONLY 0x0001 +#define AR_WRITE_ONLY 0x0002 +#define AR_DENY_READ 0x0004 +#define AR_DENY_WRITE 0x0008 +#define AR_COMPATIBILITY 0x0010 +#define AR_WRITE_THROUGH 0x0040 +#define AR_OPEN_COMPRESSED 0x0100 +#endif + +struct nw_info_struct +{ + __u32 spaceAlloc __attribute__ ((packed)); + __u32 attributes __attribute__ ((packed)); + __u16 flags __attribute__ ((packed)); + __u32 dataStreamSize __attribute__ ((packed)); + __u32 totalStreamSize __attribute__ ((packed)); + __u16 numberOfStreams __attribute__ ((packed)); + __u16 creationTime __attribute__ ((packed)); + __u16 creationDate __attribute__ ((packed)); + __u32 creatorID __attribute__ ((packed)); + __u16 modifyTime __attribute__ ((packed)); + __u16 modifyDate __attribute__ ((packed)); + __u32 modifierID __attribute__ ((packed)); + __u16 lastAccessDate __attribute__ ((packed)); + __u16 archiveTime __attribute__ ((packed)); + __u16 archiveDate __attribute__ ((packed)); + __u32 archiverID __attribute__ ((packed)); + __u16 inheritedRightsMask __attribute__ ((packed)); + __u32 dirEntNum __attribute__ ((packed)); + __u32 DosDirNum __attribute__ ((packed)); + __u32 volNumber __attribute__ ((packed)); + __u32 EADataSize __attribute__ ((packed)); + __u32 EAKeyCount __attribute__ ((packed)); + __u32 EAKeySize __attribute__ ((packed)); + __u32 NSCreator __attribute__ ((packed)); + __u8 nameLen __attribute__ ((packed)); + __u8 entryName[256] __attribute__ ((packed)); +}; + +/* modify mask - use with MODIFY_DOS_INFO structure */ +#define DM_ATTRIBUTES (0x0002L) +#define DM_CREATE_DATE (0x0004L) +#define DM_CREATE_TIME (0x0008L) +#define DM_CREATOR_ID (0x0010L) +#define DM_ARCHIVE_DATE (0x0020L) +#define DM_ARCHIVE_TIME (0x0040L) +#define DM_ARCHIVER_ID (0x0080L) +#define DM_MODIFY_DATE (0x0100L) +#define DM_MODIFY_TIME (0x0200L) +#define DM_MODIFIER_ID (0x0400L) +#define DM_LAST_ACCESS_DATE (0x0800L) +#define DM_INHERITED_RIGHTS_MASK (0x1000L) +#define DM_MAXIMUM_SPACE (0x2000L) + +struct nw_modify_dos_info +{ + __u32 attributes __attribute__ ((packed)); + __u16 creationDate __attribute__ ((packed)); + __u16 creationTime __attribute__ ((packed)); + __u32 creatorID __attribute__ ((packed)); + __u16 modifyDate __attribute__ ((packed)); + __u16 modifyTime __attribute__ ((packed)); + __u32 modifierID __attribute__ ((packed)); + __u16 archiveDate __attribute__ ((packed)); + __u16 archiveTime __attribute__ ((packed)); + __u32 archiverID __attribute__ ((packed)); + __u16 lastAccessDate __attribute__ ((packed)); + __u16 inheritanceGrantMask __attribute__ ((packed)); + __u16 inheritanceRevokeMask __attribute__ ((packed)); + __u32 maximumSpace __attribute__ ((packed)); +}; + +struct nw_file_info { + struct nw_info_struct i; + int opened; + int access; + __u32 server_file_handle __attribute__ ((packed)); + __u8 open_create_action __attribute__ ((packed)); + __u8 file_handle[6] __attribute__ ((packed)); +}; + +struct nw_search_sequence { + __u8 volNumber __attribute__ ((packed)); + __u32 dirBase __attribute__ ((packed)); + __u32 sequence __attribute__ ((packed)); +}; + +struct nw_queue_job_entry { + __u16 InUse __attribute__ ((packed)); + __u32 prev __attribute__ ((packed)); + __u32 next __attribute__ ((packed)); + __u32 ClientStation __attribute__ ((packed)); + __u32 ClientTask __attribute__ ((packed)); + __u32 ClientObjectID __attribute__ ((packed)); + __u32 TargetServerID __attribute__ ((packed)); + __u8 TargetExecTime[6] __attribute__ ((packed)); + __u8 JobEntryTime[6] __attribute__ ((packed)); + __u32 JobNumber __attribute__ ((packed)); + __u16 JobType __attribute__ ((packed)); + __u16 JobPosition __attribute__ ((packed)); + __u16 JobControlFlags __attribute__ ((packed)); + __u8 FileNameLen __attribute__ ((packed)); + char JobFileName[13] __attribute__ ((packed)); + __u32 JobFileHandle __attribute__ ((packed)); + __u32 ServerStation __attribute__ ((packed)); + __u32 ServerTaskNumber __attribute__ ((packed)); + __u32 ServerObjectID __attribute__ ((packed)); + char JobTextDescription[50] __attribute__ ((packed)); + char ClientRecordArea[152] __attribute__ ((packed)); +}; + +struct queue_job { + struct nw_queue_job_entry j; + __u8 file_handle[6]; +}; + +#define QJE_OPER_HOLD 0x80 +#define QJE_USER_HOLD 0x40 +#define QJE_ENTRYOPEN 0x20 +#define QJE_SERV_RESTART 0x10 +#define QJE_SERV_AUTO 0x08 + +/* ClientRecordArea for print jobs */ + +struct print_job_record { + __u8 Version __attribute__ ((packed)); + __u16 TabSize __attribute__ ((packed)); + __u16 Copies __attribute__ ((packed)); + __u8 CtrlFlags __attribute__ ((packed)); + __u16 Lines __attribute__ ((packed)); + __u16 Rows __attribute__ ((packed)); + char FormName[16] __attribute__ ((packed)); + __u8 Reserved[6] __attribute__ ((packed)); + char Banner[13] __attribute__ ((packed)); + char FnameBanner[13] __attribute__ ((packed)); + char FnameHeader[14] __attribute__ ((packed)); + char Path[80] __attribute__ ((packed)); +}; + + +#endif /* _LINUX_NCP_H */ diff --git a/kernel-1.2/linux/ncp_fs.h b/kernel-1.2/linux/ncp_fs.h new file mode 100644 index 0000000..8373185 --- /dev/null +++ b/kernel-1.2/linux/ncp_fs.h @@ -0,0 +1,149 @@ +/* + * ncp_fs.h + * + * Copyright (C) 1995 by Volker Lendecke + * + */ + +#ifndef _LINUX_NCP_FS_H +#define _LINUX_NCP_FS_H + +#include +#include +#include + +#include +#include +#include + +/* + * ioctl commands + */ + +struct ncp_ioctl_request { + unsigned int function; + unsigned int size; + char *data; +}; + +#define NCP_IOC_NCPREQUEST _IOR('n', 1, unsigned char *) +#define NCP_IOC_GETMOUNTUID _IOR('u', 1, uid_t) + +/* + * The packet size to allocate. One page should be enough. + */ +#define NCP_PACKET_SIZE 4070 + +#define NCP_MAXPATHLEN 255 +#define NCP_MAXNAMELEN 14 + +#ifdef __KERNEL__ + +/* The readdir cache size controls how many directory entries are + * cached. + */ +#define NCP_READDIR_CACHE_SIZE 64 + + +#define NCP_MAX_RPC_TIMEOUT (60) /* 6 seconds */ + +/* Guess, what 0x564c is :-) */ +#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_SERVER(inode) NCP_SBP((inode)->i_sb) +#define NCP_FINFO(inode) (&(NCP_INOP(inode)->finfo)) +#define NCP_ISTRUCT(inode) (&(NCP_FINFO(inode)->i)) + +static inline int min(int a, int b) { + return a + +extern int ncp_malloced; +extern int ncp_current_malloced; + +static inline void * +ncp_kmalloc(unsigned int size, int priority) +{ + ncp_malloced += 1; + ncp_current_malloced += 1; + return kmalloc(size, priority); +} + +static inline void +ncp_kfree_s(void *obj, int size) +{ + ncp_current_malloced -= 1; + kfree_s(obj, size); +} + +#else /* DEBUG_NCP_MALLOC */ + +#define ncp_kmalloc(s,p) kmalloc(s,p) +#define ncp_kfree_s(o,s) kfree_s(o,s) + +#endif /* DEBUG_NCP_MALLOC */ + +#if DEBUG_NCP > 0 +#define DPRINTK(format, args...) printk(format , ## args) +#else +#define DPRINTK(format, args...) +#endif + +#if DEBUG_NCP > 1 +#define DDPRINTK(format, args...) printk(format , ## args) +#else +#define DDPRINTK(format, args...) +#endif + + +/* linux/fs/ncpfs/file.c */ +extern struct inode_operations ncp_file_inode_operations; +int ncp_make_open(struct inode *i, int right); + +/* linux/fs/ncpfs/dir.c */ +extern struct inode_operations ncp_dir_inode_operations; +void ncp_free_inode_info(struct ncp_inode_info *i); +void ncp_free_all_inodes(struct ncp_server *server); +void ncp_init_root(struct ncp_server *server); +int ncp_stat_root(struct ncp_server *server); +void ncp_init_dir_cache(void); +void ncp_invalid_dir_cache(unsigned long ino); +void ncp_invalidate_all_inodes(struct ncp_server *server); +void ncp_free_dir_cache(void); +int ncp_date_dos2unix(__u16 time, __u16 date); +void ncp_date_unix2dos(int unix_date, __u16 *time, __u16 *date); + + +/* linux/fs/ncpfs/ioctl.c */ +int ncp_ioctl (struct inode * inode, struct file * filp, + unsigned int cmd, unsigned long arg); + +/* linux/fs/ncpfs/inode.c */ +struct super_block *ncp_read_super(struct super_block *sb, + void *raw_data, int silent); +void ncp_invalidate_connection(struct ncp_server *server); +int ncp_conn_is_valid(struct ncp_server *server); + +/* linux/fs/ncpfs/sock.c */ +int ncp_request(struct ncp_server *server, int function); +int ncp_connect(struct ncp_server *server); +int ncp_disconnect(struct ncp_server *server); +int ncp_catch_watchdog(struct ncp_server *server); +int ncp_dont_catch_watchdog(struct ncp_server *server); +void ncp_lock_server(struct ncp_server *server); +void ncp_unlock_server(struct ncp_server *server); + +/* linux/fs/ncpfs/mmap.c */ +int ncp_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma); + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_NCP_FS_H */ diff --git a/kernel-1.2/linux/ncp_fs_i.h b/kernel-1.2/linux/ncp_fs_i.h new file mode 100644 index 0000000..066c7b0 --- /dev/null +++ b/kernel-1.2/linux/ncp_fs_i.h @@ -0,0 +1,35 @@ +/* + * ncp_fs_i.h + * + * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke + * + */ + +#ifndef _LINUX_NCP_FS_I +#define _LINUX_NCP_FS_I + +#include + +#ifdef __KERNEL__ + +enum ncp_inode_state { + INODE_VALID = 19, /* Inode currently in use */ + INODE_LOOKED_UP, /* directly before iget */ + INODE_CACHED, /* in a path to an inode which is in use */ + INODE_INVALID +}; + +/* + * ncp fs inode data (in memory only) + */ +struct ncp_inode_info { + enum ncp_inode_state state; + int nused; /* for directories: + number of references in memory */ + struct ncp_inode_info *dir; + struct ncp_inode_info *next, *prev; + struct nw_file_info finfo; +}; + +#endif +#endif diff --git a/kernel-1.2/linux/ncp_fs_sb.h b/kernel-1.2/linux/ncp_fs_sb.h new file mode 100644 index 0000000..fc5e955 --- /dev/null +++ b/kernel-1.2/linux/ncp_fs_sb.h @@ -0,0 +1,61 @@ +/* + * ncp_fs_sb.h + * + * Copyright (C) 1995 by Volker Lendecke + * + */ + +#ifndef _NCP_FS_SB +#define _NCP_FS_SB + +#include +#include + +#ifdef __KERNEL__ + +#define NCP_DEFAULT_BUFSIZE 1024 + +struct ncp_server { + + struct ncp_mount_data m; /* Nearly all of the mount data is of + interest for us later, so we store + it completely. */ + + struct file *ncp_filp; /* File pointer to ncp socket */ + + struct file *wdog_filp; /* File pointer to wdog socket */ + void *data_ready; /* The wdog socket gets a new + data_ready callback. We store the + old one for checking purposes and + to reset it on unmounting. */ + + u8 sequence; + u8 task; + u16 connection; /* Remote connection number */ + + u8 completion; /* Status message from server */ + u8 conn_status; /* Bit 4 = 1 ==> Server going down, no + requests allowed anymore */ + + int buffer_size; /* Negotiated bufsize */ + + int reply_size; /* Size of last reply */ + + int packet_size; + unsigned char *packet; /* Here we prepare requests and + receive replies */ + + int lock; /* To prevent mismatch in protocols. */ + struct wait_queue *wait; + + int current_size; /* for packet preparation */ + int has_subfunction; + int ncp_reply_size; + + struct ncp_inode_info root; + char root_path; /* '\0' */ +}; + +#endif /* __KERNEL__ */ + +#endif diff --git a/kernel-1.2/linux/ncp_mount.h b/kernel-1.2/linux/ncp_mount.h new file mode 100644 index 0000000..83007be --- /dev/null +++ b/kernel-1.2/linux/ncp_mount.h @@ -0,0 +1,49 @@ +/* + * ncp_mount.h + * + * Copyright (C) 1995 by Volker Lendecke + * + */ + +#ifndef _LINUX_NCP_MOUNT_H +#define _LINUX_NCP_MOUNT_H + +#include +#include +#include +#include + +#define NCP_MOUNT_VERSION 1 + +#define NCP_USERNAME_LEN (NCP_BINDERY_NAME_LEN) +#define NCP_PASSWORD_LEN 20 + +/* Values for flags */ +#define NCP_MOUNT_SOFT 0x0001 +#define NCP_MOUNT_INTR 0x0002 + +struct ncp_mount_data { + int version; + unsigned int ncp_fd; /* The socket to the ncp port */ + unsigned int wdog_fd; /* Watchdog packets come here */ + unsigned int message_fd; /* Not used yet, maybe for messages */ + uid_t mounted_uid; /* Who may umount() this filesystem? */ + + struct sockaddr_ipx serv_addr; + unsigned char server_name[49]; + + unsigned char username[NCP_USERNAME_LEN+1]; + unsigned char password[NCP_PASSWORD_LEN+1]; + + unsigned int time_out; /* How long should I wait after + sending a NCP request? */ + unsigned int retry_count; /* And how often should I retry? */ + unsigned int flags; + + uid_t uid; + gid_t gid; + mode_t file_mode; + mode_t dir_mode; +}; + +#endif diff --git a/kernel-1.2/src/Makefile b/kernel-1.2/src/Makefile new file mode 100644 index 0000000..7477eb1 --- /dev/null +++ b/kernel-1.2/src/Makefile @@ -0,0 +1,67 @@ +# +# Makefile for the linux ncp-filesystem routines. +# + +INCLUDES = -I/usr/src/linux/include -I.. + +CFLAGS = -Wall -Wstrict-prototypes -O2 -DMODULE -fomit-frame-pointer \ + $(INCLUDES) \ +# -DDEBUG_NCP=1 -DDEBUG_NCP_MALLOC +# -DDEBUG_NCP_MALLOC + +CC = gcc -D__KERNEL__ -I. +AS = as +ARCH = i386 + +.c.s: + $(CC) $(CFLAGS) -S $< +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< + +OBJS= dir.o inode.o file.o sock.o ioctl.o ncplib.o + +all: ncpfs.o + +ncpfs.o: $(OBJS) + $(LD) -r -o ncpfs.o $(OBJS) + +ncplib.o: ncplib.c ncplib.h + $(CC) $(CFLAGS) -finline-functions -c $< + +dep: + $(CPP) -M $(INCLUDES) *.c > .depend + +clean: + rm -f *.o *~ + +realclean: clean + rm -f ncpmount ncptest .depend $(DISTFILE) *.out + +modules: ncpfs.o + +SRCPATH=$(shell pwd) +SRCDIR=$(shell basename $(SRCPATH)) +DISTFILE=$(SRCDIR).tgz +BACKUPFILE=ncpfs01.tgz +HOME=/home/me + +backup: + (rm -f $(DISTFILE); cd ..; tar cvf - $(SRCDIR) | gzip -1 \ + > $(HOME)/tarz/backup/$(BACKUPFILE)) + (cd $(HOME)/tarz/backup; ls -l $(BACKUPFILE); mcopy $(BACKUPFILE) a:) + +dist: realclean + rm -fr mnt + (cd ..; \ + tar cvf - $(SRCDIR) | \ + gzip -9 > $(DISTFILE); \ + mv $(DISTFILE) $(SRCDIR)) + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/kernel-1.2/src/dir.c b/kernel-1.2/src/dir.c new file mode 100644 index 0000000..79e0cc2 --- /dev/null +++ b/kernel-1.2/src/dir.c @@ -0,0 +1,965 @@ +/* + * dir.c + * + * Copyright (C) 1995 by Volker Lendecke + * + */ + +#include +#ifdef MODULE +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ncplib.h" + +struct ncp_dirent { + struct nw_info_struct i; + struct nw_search_sequence s; /* given back for i */ + unsigned long f_pos; +}; + +static int +ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count); + +static int +ncp_readdir(struct inode *inode, struct file *filp, + struct dirent *dirent, int count); + +static int +ncp_read_volume_list(struct ncp_server *server, int start_with, + int cache_size); + +static int +ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos, + int cache_size, struct ncp_dirent *entry); + +static struct inode * +ncp_iget(struct inode *dir, struct nw_file_info *finfo); + +static struct ncp_inode_info * +ncp_find_inode(struct inode *dir, const char *name); + +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 inline void +str_upper(char *name) +{ + while (*name) { + if (*name >= 'a' && *name <= 'z') + *name -= ('a' - 'A'); + name++; + } +} + +static inline void +str_lower(char *name) +{ + while (*name) { + if (*name >= 'A' && *name <= 'Z') + *name += ('a' - 'A'); + name ++; + } +} + +static struct file_operations ncp_dir_operations = { + NULL, /* lseek - default */ + ncp_dir_read, /* read - bad */ + NULL, /* write - bad */ + ncp_readdir, /* readdir */ + NULL, /* select - default */ + ncp_ioctl, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* fsync */ +}; + +struct inode_operations ncp_dir_inode_operations = { + &ncp_dir_operations, /* default directory file ops */ + ncp_create, /* create */ + ncp_lookup, /* lookup */ + NULL, /* link */ + ncp_unlink, /* unlink */ + NULL, /* symlink */ + ncp_mkdir, /* mkdir */ + ncp_rmdir, /* rmdir */ + NULL, /* mknod */ + ncp_rename, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL /* smap */ +}; + + +static int +ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count) +{ + return -EISDIR; +} + +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) +#define ROUND_UP(x) (((x)+3) & ~3) + +/* In ncpfs, we have unique inodes across all mounted filesystems, for + all inodes that are in memory. That's why it's enough to index the + directory cache by the inode number. */ + +static unsigned long c_ino = 0; +static int c_size; +static int c_seen_eof; +static int c_last_returned_index; +static struct ncp_dirent* c_entry = NULL; + +static int +ncp_readdir(struct inode *inode, struct file *filp, + struct dirent *dirent, int count) +{ + int result, i = 0; + int index = 0; + struct ncp_dirent *entry = NULL; + struct ncp_server *server = NCP_SERVER(inode); + struct ncp_inode_info *dir = (struct ncp_inode_info *)(inode->i_ino); + + int filldir(struct dirent *dirent, + const char *name, int len, + int f_pos, ino_t ino) + { + memcpy_tofs(dirent->d_name, name, len); + put_fs_byte(0, &(dirent->d_name[len])); + put_fs_long(ino, &dirent->d_ino); + put_fs_word(len, &dirent->d_reclen); + put_fs_word(f_pos, &dirent->d_off); + return 1; + } + + + DDPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos); + DDPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n", + inode->i_ino, c_ino); + + if (!inode || !S_ISDIR(inode->i_mode)) { + printk("ncp_readdir: inode is NULL or not a directory\n"); + return -EBADF; + } + + if (c_entry == NULL) + { + i = sizeof (struct ncp_dirent) * NCP_READDIR_CACHE_SIZE; + c_entry = (struct ncp_dirent *) ncp_kmalloc(i, GFP_KERNEL); + if (c_entry == NULL) { + printk("ncp_readdir: no MEMORY for cache\n"); + return -ENOMEM; + } + } + + if (filp->f_pos == 0) { + ncp_invalid_dir_cache(inode->i_ino); + if (filldir(dirent,".",1, filp->f_pos, (int)dir) < 0) { + return 0; + } + filp->f_pos += 1; + return ROUND_UP(NAME_OFFSET(dirent)+i+1); + } + + if (filp->f_pos == 1) { + if (filldir(dirent,"..",2, filp->f_pos, (int)(dir->dir)) < 0) { + return 0; + } + filp->f_pos += 1; + return ROUND_UP(NAME_OFFSET(dirent)+i+1); + } + + + + if (inode->i_ino == c_ino) { + for (i = 0; i < c_size; i++) { + if (filp->f_pos == c_entry[i].f_pos) { + entry = &c_entry[i]; + c_last_returned_index = i; + index = i; + break; + } + } + if ((entry == NULL) && c_seen_eof) + return 0; + } + + if (entry == NULL) { + DPRINTK("ncp_readdir: Not found in cache.\n"); + + if (inode->i_ino == (int)&(server->root)) { + + result = ncp_read_volume_list(server, filp->f_pos, + NCP_READDIR_CACHE_SIZE); + DPRINTK("ncp_read_volume_list returned %d\n", result); + + } else { + + result = ncp_do_readdir(server, inode, filp->f_pos, + NCP_READDIR_CACHE_SIZE, + c_entry); + DPRINTK("ncp_readdir returned %d\n", result); + } + + + if (result < 0) { + c_ino = 0; + return result; + } + + if (result > 0) { + c_seen_eof = (result < NCP_READDIR_CACHE_SIZE); + c_ino = inode->i_ino; + c_size = result; + entry = c_entry; + c_last_returned_index = 0; + index = 0; + + for (i = 0; i < c_size; i++) { + str_lower(c_entry[i].i.entryName); + } + } + } + + if (entry == NULL) { + /* Nothing found, even from a ncp call */ + return 0; + } + + if (index < c_size) { + + /* We found it. For getwd(), we have to return the + correct inode in d_ino if the inode is currently in + use. Otherwise the inode number does not + matter. (You can argue a lot about this..) */ + + struct ncp_inode_info *ino_info; + ino_info = ncp_find_inode(inode, entry->i.entryName); + + + /* Some programs seem to be confused about a zero + inode number, so we set it to one. Thanks to + Gordon Chaffee for this one. */ + if (ino_info == NULL) { + ino_info = (struct ncp_inode_info *) 1; + } + + DDPRINTK("ncp_readdir: entry->path= %s\n", entry->i.entryName); + DDPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos); + + if (filldir(dirent, entry->i.entryName, entry->i.nameLen, + entry->f_pos, (ino_t)ino_info) < 0) { + return 0; + } + + filp->f_pos += 1; + index += 1; + entry += 1; + return ROUND_UP(NAME_OFFSET(dirent)+i+1); + } + return 0; +} + +static int +ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size) +{ + struct ncp_dirent *entry = c_entry; + + int total_count = 2; + int i; + +#if 1 + if (fpos < 2) { + printk("OOPS, we expect fpos >= 2"); + fpos = 2; + } +#endif + + for (i=0; i 0) { + if (total_count < fpos) { + DPRINTK("ncp_read_volumes: skipped vol: %s\n", + info.volume_name); + } else if (total_count >= fpos + cache_size) { + return (total_count - fpos); + } else { + DPRINTK("ncp_read_volumes: found vol: %s\n", + info.volume_name); + + if (ncp_do_lookup(server, NULL, + info.volume_name, + &(entry->i)) != 0) { + printk("ncpfs: could not lookup vol " + "%s\n", info.volume_name); + continue; + } + + entry->f_pos = total_count; + entry += 1; + } + total_count += 1; + } + } + + return (total_count - fpos); +} + +static int +ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos, + int cache_size, struct ncp_dirent *entry) +{ + static struct nw_search_sequence seq; + static struct inode *last_dir; + static int total_count; + +#if 1 + if (fpos < 2) { + printk("OOPS, we expect fpos >= 2"); + fpos = 2; + } +#endif + DPRINTK("ncp_do_readdir: fpos = %d\n", fpos); + + if (fpos == 2) { + last_dir = NULL; + total_count = 2; + } + + if ((fpos != total_count) || (dir != last_dir)) { + + total_count = 2; + last_dir = dir; + + DPRINTK("ncp_do_readdir: re-used seq for %s\n", + NCP_ISTRUCT(dir)->entryName); + + if (ncp_initialize_search(server, NCP_ISTRUCT(dir), &seq)!=0) { + DPRINTK("ncp_init_search failed\n"); + return total_count - fpos; + } + } + + while (total_count < fpos + cache_size) { + + if (ncp_search_for_file_or_subdir(server, &seq, + &(entry->i)) != 0) { + return total_count - fpos; + } + + if (total_count < fpos) { + DPRINTK("ncp_do_readdir: skipped file: %s\n", + entry->i.entryName); + } else { + DDPRINTK("ncp_do_r: file: %s, f_pos=%d,total_count=%d", + entry->i.entryName, fpos, total_count); + entry->s = seq; + entry->f_pos = total_count; + entry += 1; + } + total_count += 1; + } + + return (total_count - fpos); +} + +void +ncp_init_dir_cache(void) +{ + c_ino = 0; + c_entry = NULL; +} + +void +ncp_invalid_dir_cache(unsigned long ino) +{ + if (ino == c_ino) { + c_ino = 0; + c_seen_eof = 0; + } +} + +void +ncp_free_dir_cache(void) +{ + DPRINTK("ncp_free_dir_cache: enter\n"); + + if (c_entry == NULL) + return; + + ncp_kfree_s(c_entry, + sizeof(struct ncp_dirent) * NCP_READDIR_CACHE_SIZE); + c_entry = NULL; + + DPRINTK("ncp_free_dir_cache: exit\n"); +} + + +static struct inode * +ncp_iget(struct inode *dir, struct nw_file_info *finfo) +{ + struct inode *inode; + struct ncp_inode_info *new_inode_info; + struct ncp_inode_info *root; + + if (!dir) { + printk("ncp_iget: dir is NULL\n"); + return NULL; + } + + if (!finfo) { + printk("ncp_iget: finfo is NULL\n"); + return NULL; + } + + new_inode_info = ncp_kmalloc(sizeof(struct ncp_inode_info), + GFP_KERNEL); + + if (new_inode_info == NULL) { + printk("ncp_iget: could not alloc mem for %s\n", + finfo->i.entryName); + return NULL; + } + + new_inode_info->state = INODE_LOOKED_UP; + new_inode_info->nused = 0; + new_inode_info->dir = NCP_INOP(dir); + new_inode_info->finfo = *finfo; + + NCP_INOP(dir)->nused += 1; + + /* We have to link the new inode_info into the doubly linked + list of inode_infos to make a complete linear search + possible. */ + + root = &(NCP_SERVER(dir)->root); + + new_inode_info->prev = root; + new_inode_info->next = root->next; + root->next->prev = new_inode_info; + root->next = new_inode_info; + + if (!(inode = iget(dir->i_sb, (int)new_inode_info))) { + printk("ncp_iget: iget failed!"); + return NULL; + } + + return inode; +} + +void +ncp_free_inode_info(struct ncp_inode_info *i) +{ + if (i == NULL) { + printk("ncp_free_inode: i == NULL\n"); + return; + } + + i->state = INODE_CACHED; + while ((i->nused == 0) && (i->state == INODE_CACHED)) { + struct ncp_inode_info *dir = i->dir; + + i->next->prev = i->prev; + i->prev->next = i->next; + + DDPRINTK("ncp_free_inode_info: freeing %s\n", + i->finfo.i.entryName); + + ncp_kfree_s(i, sizeof(struct ncp_inode_info)); + + if (dir == i) return; + + (dir->nused)--; + i = dir; + } +} + +void +ncp_init_root(struct ncp_server *server) +{ + struct ncp_inode_info *root = &(server->root); + struct nw_info_struct *i = &(root->finfo.i); + unsigned short dummy; + + DPRINTK("ncp_init_root: server %s\n", server->m.server_name); + DPRINTK("ncp_init_root: i = %x\n", (int)i); + + root->finfo.opened = 0; + i->attributes = aDIR; + i->dataStreamSize = 1024; + ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate)); + ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate)); + ncp_date_unix2dos(0, &dummy, &(i->lastAccessDate)); + i->nameLen = 0; + i->entryName[0] = '\0'; + + root->state = INODE_LOOKED_UP; + root->nused = 1; + root->dir = root; + root->next = root->prev = root; + return; +} + +void +ncp_free_all_inodes(struct ncp_server *server) +{ + /* Here nothing should be to do. I do not know whether it's + better to leave some memory allocated or be stuck in an + endless loop */ +#if 1 + struct ncp_inode_info *root = &(server->root); + + if (root->next != root) { + printk("ncp_free_all_inodes: INODES LEFT!!!\n"); + } + + while (root->next != root) { + printk("ncp_free_all_inodes: freeing inode\n"); + ncp_free_inode_info(root->next); + /* In case we have an endless loop.. */ + schedule(); + } +#endif + + return; +} + +/* We will search the inode that belongs to this name, currently by a + complete linear search through the inodes belonging to this + filesystem. This has to be fixed. */ +static struct ncp_inode_info * +ncp_find_inode(struct inode *dir, const char *name) +{ + struct ncp_server *server = NCP_SERVER(dir); + struct nw_info_struct *dir_info = NCP_ISTRUCT(dir); + struct ncp_inode_info *result = &(server->root); + + if (name == NULL) { + return NULL; + } + + do { + if ( (result->finfo.i.DosDirNum == dir_info->DosDirNum) + && (strcmp(result->finfo.i.entryName, name) == 0)) + return result; + result = result->next; + + } while (result != &(server->root)); + + return NULL; +} + +static int +ncp_lookup(struct inode *dir, const char *__name, int len, + struct inode **result) +{ + struct nw_file_info finfo; + struct ncp_server *server; + struct ncp_inode_info *result_info; + int found_in_cache; + + *result = NULL; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("ncp_lookup: inode is NULL or not a directory.\n"); + iput(dir); + return -ENOENT; + } + + DDPRINTK("ncp_lookup: %s, len %d\n", __name, len); + + server = NCP_SERVER(dir); + + /* Fast cheat for . */ + if (len == 0 || (len == 1 && __name[0] == '.')) { + *result = dir; + return 0; + } + + /* ..and for .. */ + if (len == 2 && __name[0] == '.' && __name[1] == '.') { + *result = iget(dir->i_sb, (int)(NCP_INOP(dir)->dir)); + iput(dir); + if (*result == 0) + return -EACCES; + else + return 0; + } + + result_info = ncp_find_inode(dir, __name); + + if (result_info != 0) { + + if (result_info->state == INODE_CACHED) + result_info->state = INODE_LOOKED_UP; + + /* Here we convert the inode_info address into an + inode number */ + + *result = iget(dir->i_sb, (int)result_info); + iput(dir); + + if (*result == NULL) { + return -EACCES; + } + + return 0; + } + + /* If the file is in the dir cache, we do not have to ask the + server. */ + + found_in_cache = 0; + + if (dir->i_ino == c_ino) { + int first = c_last_returned_index; + int i; + + i = first; + do { + DDPRINTK("ncp_lookup: trying index: %d, name: %s\n", + i, c_entry[i].i.entryName); + if (strcmp(c_entry[i].i.entryName, __name) == 0) { + DPRINTK("ncp_lookup: found in cache!\n"); + finfo.i = c_entry[i].i; + found_in_cache = 1; + break; + } + i = (i + 1) % c_size; + } while (i != first); + } + + if (found_in_cache == 0) { + + char this_name[len+1]; + + memcpy(this_name, __name, len); + this_name[len] = 0; + str_upper(this_name); + + DDPRINTK("ncp_lookup: do_lookup on %s/%s\n", + NCP_ISTRUCT(dir)->entryName, this_name); + + if (ncp_do_lookup(server, + dir->i_ino == (int)&(NCP_SERVER(dir)->root) + ? NULL : NCP_ISTRUCT(dir), + this_name, + &(finfo.i)) != 0) { + iput(dir); + return -ENOENT; + } + } + + finfo.opened = 0; + str_lower(finfo.i.entryName); + + if (!(*result = ncp_iget(dir, &finfo))) { + iput(dir); + return -EACCES; + } + + iput(dir); + return 0; +} + +static int +ncp_create(struct inode *dir, const char *name, int len, int mode, + struct inode **result) +{ + struct nw_file_info finfo; + __u8 _name[len+1]; + + *result = NULL; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("ncp_create: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + + strncpy(_name, name, len); + _name[len] = '\0'; + str_upper(_name); + + if (ncp_open_create_file_or_subdir(NCP_SERVER(dir), + NCP_ISTRUCT(dir), _name, + OC_MODE_CREATE|OC_MODE_OPEN, + 0, AR_READ|AR_WRITE, + &finfo) != 0) { + iput(dir); + return -EACCES; + } + + ncp_invalid_dir_cache(dir->i_ino); + + str_lower(finfo.i.entryName); + finfo.access = O_RDWR; + + if (!(*result = ncp_iget(dir, &finfo)) < 0) { + ncp_close_file(NCP_SERVER(dir), finfo.file_handle); + iput(dir); + return -EINVAL; + } + + iput(dir); + return 0; +} + +static int +ncp_mkdir(struct inode *dir, const char *name, int len, int mode) +{ + int error; + struct nw_file_info new_dir; + __u8 _name[len+1]; + + strncpy(_name, name, len); + _name[len] = '\0'; + str_upper(_name); + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("ncp_mkdir: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + + if (ncp_open_create_file_or_subdir(NCP_SERVER(dir), + NCP_ISTRUCT(dir), _name, + OC_MODE_CREATE, aDIR, 0xffff, + &new_dir) != 0) { + error = -EACCES; + } else { + error = 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; + __u8 _name[len+1]; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("ncp_rmdir: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + if (ncp_find_inode(dir, name) != NULL) { + error = -EBUSY; + } + else + { + + strncpy(_name, name, len); + _name[len] = '\0'; + str_upper(_name); + + if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir), + NCP_ISTRUCT(dir), + _name)) == 0) { + ncp_invalid_dir_cache(dir->i_ino); + } + else + { + error = -EINVAL; + } + } + iput(dir); + return error; +} + +static int +ncp_unlink(struct inode *dir, const char *name, int len) +{ + int error; + __u8 _name[len+1]; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("ncp_unlink: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + if (ncp_find_inode(dir, name) != NULL) { + error = -EBUSY; + } + else + { + + strncpy(_name, name, len); + _name[len] = '\0'; + str_upper(_name); + + if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir), + NCP_ISTRUCT(dir), + _name)) == 0) { + ncp_invalid_dir_cache(dir->i_ino); + } + else + { + error = -EINVAL; + } + } + 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_name[old_len+1]; + char _new_name[new_len+1]; + + 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; + } + + if ( (ncp_find_inode(old_dir, old_name) != NULL) + || (ncp_find_inode(new_dir, new_name) != NULL)) { + res = -EBUSY; + goto finished; + } + + strncpy(_old_name, old_name, old_len); + _old_name[old_len] = '\0'; + str_upper(_old_name); + + strncpy(_new_name, new_name, new_len); + _new_name[old_len] = '\0'; + str_upper(_new_name); + + res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir), + NCP_ISTRUCT(old_dir), _old_name, + NCP_ISTRUCT(new_dir), _new_name); + + if (res == 0) { + ncp_invalid_dir_cache(old_dir->i_ino); + ncp_invalid_dir_cache(new_dir->i_ino); + } + else + { + res = -EACCES; + } + + 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. */ + +static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 }; + /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */ + + +extern struct timezone sys_tz; + +static int +utc2local(int time) +{ + return time - sys_tz.tz_minuteswest*60; +} + +static int +local2utc(int time) +{ + return time + sys_tz.tz_minuteswest*60; +} + +/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ + +int +ncp_date_dos2unix(unsigned short time,unsigned short date) +{ + int month,year,secs; + + month = ((date >> 5) & 15)-1; + year = date >> 9; + secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* + ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && + month < 2 ? 1 : 0)+3653); + /* days since 1.1.70 plus 80's leap day */ + return local2utc(secs); +} + + +/* Convert linear UNIX date to a MS-DOS time/date pair. */ +void +ncp_date_unix2dos(int unix_date,unsigned short *time, unsigned short *date) +{ + int day,year,nl_day,month; + + unix_date = utc2local(unix_date); + *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+ + (((unix_date/3600) % 24) << 11); + day = unix_date/86400-3652; + year = day/365; + if ((year+3)/4+365*year > day) year--; + day -= (year+3)/4+365*year; + if (day == 59 && !(year & 3)) { + nl_day = day; + month = 2; + } + else { + nl_day = (year & 3) || day <= 59 ? day : day-1; + for (month = 0; month < 12; month++) + if (day_n[month] > nl_day) break; + } + *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9); +} diff --git a/kernel-1.2/src/file.c b/kernel-1.2/src/file.c new file mode 100644 index 0000000..0ad8185 --- /dev/null +++ b/kernel-1.2/src/file.c @@ -0,0 +1,258 @@ +/* + * file.c + * + * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke + * + */ + +/* #include */ + +#include +#ifdef MODULE +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "ncplib.h" +#include + +static int +ncp_fsync(struct inode *inode, struct file *file) +{ + return 0; +} + +int +ncp_make_open(struct inode *i, int right) +{ + struct nw_file_info *finfo; + + if (i == NULL) { + printk("ncp_make_open: got NULL inode\n"); + return -EINVAL; + } + + finfo = NCP_FINFO(i); + + DPRINTK("ncp_make_open: dirent->opened = %d\n", finfo->opened); + + if (finfo->opened == 0) { + + /* tries max. rights */ + if (ncp_open_create_file_or_subdir(NCP_SERVER(i), + NULL, NULL, + OC_MODE_OPEN, 0, + AR_READ | AR_WRITE, + finfo) == 0) { + finfo->access = O_RDWR; + } + else if (ncp_open_create_file_or_subdir(NCP_SERVER(i), + NULL, NULL, + OC_MODE_OPEN, 0, + AR_READ, + finfo) == 0) { + finfo->access = O_RDONLY; + } else { + return -EACCES; + } + } + + if ( ((right == O_RDONLY) && ( (finfo->access == O_RDONLY) + || (finfo->access == O_RDWR))) + || ((right == O_WRONLY) && ( (finfo->access == O_WRONLY) + || (finfo->access == O_RDWR))) + || ((right == O_RDWR) && (finfo->access == O_RDWR))) + return 0; + + return -EACCES; +} + +static int +ncp_file_read(struct inode *inode, struct file *file, char *buf, int count) +{ + int bufsize, to_read, already_read; + off_t pos; + int errno; + + DPRINTK("ncp_file_read: enter %s\n", NCP_ISTRUCT(inode)->entryName); + + if (!inode) { + DPRINTK("ncp_file_read: inode = NULL\n"); + return -EINVAL; + } + + if (!S_ISREG(inode->i_mode)) { + DPRINTK("ncp_file_read: read from non-file, mode %07o\n", + inode->i_mode); + return -EINVAL; + } + + pos = file->f_pos; + + if (pos + count > inode->i_size) + count = inode->i_size - pos; + + 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; + + /* First read in as much as possible for each bufsize. */ + while (already_read < count) { + + int read_this_time; + + if ((pos % bufsize) != 0) { + to_read = bufsize - (pos % bufsize); + } else { + to_read = bufsize; + } + + to_read = min(to_read, count - already_read); + + if (ncp_read(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, + pos, to_read, buf, &read_this_time) != 0) { + return -EIO; /* This is not exact, i know.. */ + } + + pos += read_this_time; + buf += read_this_time; + already_read += read_this_time; + + if (read_this_time < to_read) { + break; + } + } + + file->f_pos = pos; + + if (!IS_RDONLY(inode)) inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + + DPRINTK("ncp_file_read: exit %s\n", NCP_ISTRUCT(inode)->entryName); + + return already_read; +} + +static int +ncp_file_write(struct inode *inode, struct file *file, 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_ISTRUCT(inode)->entryName); + + 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_handle, + 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_ISTRUCT(inode)->entryName); + + return already_written; +} + +static struct file_operations ncp_file_operations = { + NULL, /* lseek - default */ + ncp_file_read, /* read */ + ncp_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + ncp_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* open */ + NULL, /* release */ + ncp_fsync, /* fsync */ +}; + +struct inode_operations ncp_file_inode_operations = { + &ncp_file_operations, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL /* truncate */ +}; diff --git a/kernel-1.2/src/inode.c b/kernel-1.2/src/inode.c new file mode 100644 index 0000000..44258ec --- /dev/null +++ b/kernel-1.2/src/inode.c @@ -0,0 +1,490 @@ +/* + * inode.c + * + * Copyright (C) 1995 by Volker Lendecke + * + */ + +#include +#ifdef MODULE +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ncplib.h" + +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 *stat); +static int ncp_notify_change(struct inode *inode, struct iattr *attr); + +static struct super_operations ncp_sops = { + ncp_read_inode, /* read inode */ + ncp_notify_change, /* notify change */ + NULL, /* write inode */ + ncp_put_inode, /* put inode */ + ncp_put_super, /* put superblock */ + NULL, /* write superblock */ + ncp_statfs, /* stat filesystem */ + NULL + }; + +/* ncp_read_inode: Called from iget, it only traverses the allocated + ncp_inode_info's and initializes the inode from the data found + there. It does not allocate or deallocate anything. */ + +static void +ncp_read_inode(struct inode *inode) +{ + /* Our task should be extremely simple here. We only have to + look up the infomation somebody else (ncp_iget) put into + the inode tree. The address of this information is the + inode->i_ino. Just to make sure everything went well, we + check it's there. */ + + struct ncp_inode_info *inode_info + = (struct ncp_inode_info *)(inode->i_ino); + +#if 1 + struct ncp_inode_info *root = &(NCP_SERVER(inode)->root); + struct ncp_inode_info *check_info = root; + + do { + if (inode_info == check_info) { + if (check_info->state == INODE_LOOKED_UP) { + DDPRINTK("ncp_read_inode: found it!\n"); + goto good; + } + else { + printk("ncp_read_inode: " + "state != INODE_LOOKED_UP\n"); + goto good; + } + } + check_info = check_info->next; + } while (check_info != root); + + /* Ok, now we're in trouble. The inode info is not there. What + should we do now??? */ + printk("ncp_read_inode: inode info not found\n"); + return; + + good: + DDPRINTK("ncp_read_inode: read entry %s\n", + inode_info->finfo.i.entryName); +#endif + inode_info->state = INODE_VALID; + + NCP_INOP(inode) = inode_info; + + if (NCP_ISTRUCT(inode)->attributes & aDIR) { + inode->i_mode = NCP_SERVER(inode)->m.dir_mode; + /* for directories in dataStreamSize seems to be some + Object ID ??? */ + inode->i_size = 0; + } + else + { + inode->i_mode = NCP_SERVER(inode)->m.file_mode; + inode->i_size = NCP_ISTRUCT(inode)->dataStreamSize; + } + + DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode); + + inode->i_nlink = 1; + inode->i_uid = NCP_SERVER(inode)->m.uid; + inode->i_gid = NCP_SERVER(inode)->m.gid; + inode->i_blksize = 1024; + inode->i_rdev = 0; + if ((inode->i_blksize != 0) && (inode->i_size != 0)) + inode->i_blocks = + (inode->i_size - 1) / inode->i_blksize + 1; + else + inode->i_blocks = 0; + + inode->i_mtime = ncp_date_dos2unix(NCP_ISTRUCT(inode)->modifyTime, + NCP_ISTRUCT(inode)->modifyDate); + inode->i_ctime = ncp_date_dos2unix(NCP_ISTRUCT(inode)->creationTime, + NCP_ISTRUCT(inode)->creationDate); + inode->i_atime = ncp_date_dos2unix(0, + NCP_ISTRUCT(inode)->lastAccessDate); + + if (S_ISREG(inode->i_mode)) + inode->i_op = &ncp_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) + inode->i_op = &ncp_dir_inode_operations; + else + inode->i_op = NULL; + +} + +static void +ncp_put_inode(struct inode *inode) +{ + struct nw_file_info *finfo = NCP_FINFO(inode); + + if (finfo->opened != 0) { + + if (ncp_close_file(NCP_SERVER(inode), finfo->file_handle)!=0) { + /* We can't do anything but complain. */ + printk("ncp_put_inode: could not close\n"); + } + } + + ncp_free_inode_info(NCP_INOP(inode)); + + if (S_ISDIR(inode->i_mode)) { + DDPRINTK("ncp_put_inode: put directory %ld\n", + inode->i_ino); + ncp_invalid_dir_cache(inode->i_ino); + } + + clear_inode(inode); +} + +struct super_block * +ncp_read_super(struct super_block *sb, void *raw_data, int silent) +{ + struct ncp_mount_data *data = (struct ncp_mount_data *) raw_data; + struct ncp_server *server; + struct file *ncp_filp; + struct file *wdog_filp; + dev_t dev = sb->s_dev; + int error; + + if (!data) { + printk("ncp_read_super: missing data argument\n"); + sb->s_dev = 0; + return NULL; + } + + if (data->version != NCP_MOUNT_VERSION) { + printk("ncp warning: mount version %s than kernel\n", + (data->version < NCP_MOUNT_VERSION) ? + "older" : "newer"); + } + + + if ( (data->ncp_fd >= NR_OPEN) + || ((ncp_filp = current->files->fd[data->ncp_fd]) == NULL) + || (!S_ISSOCK(ncp_filp->f_inode->i_mode))) { + printk("ncp_read_super: invalid ncp socket\n"); + sb->s_dev = 0; + return NULL; + } + + if ( (data->wdog_fd >= NR_OPEN) + || ((wdog_filp = current->files->fd[data->wdog_fd]) == NULL) + || (!S_ISSOCK(wdog_filp->f_inode->i_mode))) { + printk("ncp_read_super: invalid wdog socket\n"); + sb->s_dev = 0; + return NULL; + } + + /* We must malloc our own super-block info */ + server = (struct ncp_server *)ncp_kmalloc(sizeof(struct ncp_server), + GFP_KERNEL); + + if (server == NULL) { + printk("ncp_read_super: could not alloc ncp_server\n"); + return NULL; + } + + ncp_filp->f_count += 1; + wdog_filp->f_count += 1; + + lock_super(sb); + + NCP_SBP(sb) = server; + + sb->s_blocksize = 1024; /* Eh... Is this correct? */ + sb->s_blocksize_bits = 10; + sb->s_magic = NCP_SUPER_MAGIC; + sb->s_dev = dev; + sb->s_op = &ncp_sops; + + server->ncp_filp = ncp_filp; + server->wdog_filp = wdog_filp; + server->lock = 0; + server->wait = NULL; + server->packet = NULL; + server->buffer_size = 0; + + server->m = *data; + server->m.file_mode = (server->m.file_mode & + (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG; + server->m.dir_mode = (server->m.dir_mode & + (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR; + + server->packet_size = NCP_PACKET_SIZE; + server->packet = ncp_kmalloc(NCP_PACKET_SIZE, GFP_KERNEL); + + if (server->packet == NULL) { + printk("ncpfs: could not alloc packet\n"); + error = -ENOMEM; + unlock_super(sb); + goto fail; + } + + ncp_init_root(server); + + /* + * Make the connection to the server + */ + + if (ncp_catch_watchdog(server) != 0) { + printk("ncp_read_super: Could not catch watchdog\n"); + error = -EINVAL; + unlock_super(sb); + goto fail; + } + + ncp_lock_server(server); + error = ncp_connect(server); + ncp_unlock_server(server); + unlock_super(sb); + + if (error < 0) { + sb->s_dev = 0; + printk("ncp_read_super: Failed connection, bailing out " + "(error = %d).\n", -error); + ncp_kfree_s(server->packet, server->packet_size); + ncp_dont_catch_watchdog(server); + goto fail; + } + + DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int)NCP_SBP(sb)); + + if (!(sb->s_mounted = iget(sb, (int)&(server->root)))) { + sb->s_dev = 0; + printk("ncp_read_super: get root inode failed\n"); + goto disconnect; + } + + if (ncp_negotiate_buffersize(server, NCP_DEFAULT_BUFSIZE, + &(server->buffer_size)) != 0) { + sb->s_dev = 0; + printk("ncp_read_super: could not get bufsize\n"); + goto disconnect; + } + + DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size); + +/* if (ncp_login_user(server, server->m.username, + server->m.password) != 0) { + sb->s_dev = 0; + printk("ncp_read_super: login failed\n"); + goto disconnect; + } +*/ + + MOD_INC_USE_COUNT; + return sb; + + disconnect: + ncp_lock_server(server); + ncp_disconnect(server); + ncp_unlock_server(server); + ncp_kfree_s(server->packet, server->packet_size); + ncp_dont_catch_watchdog(server); + fail: + ncp_filp->f_count -= 1; + wdog_filp->f_count -= 1; + ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server)); + return NULL; +} + +static void +ncp_put_super(struct super_block *sb) +{ + struct ncp_server *server = NCP_SBP(sb); + + lock_super(sb); + + ncp_lock_server(server); + ncp_disconnect(server); + ncp_unlock_server(server); + + close_fp(server->ncp_filp); + + ncp_dont_catch_watchdog(server); + close_fp(server->wdog_filp); + + ncp_free_all_inodes(server); + + ncp_kfree_s(server->packet, server->packet_size); + + sb->s_dev = 0; + ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server)); + NCP_SBP(sb) = NULL; + + unlock_super(sb); + + MOD_DEC_USE_COUNT; +} + +static void +ncp_statfs(struct super_block *sb, struct statfs *stat) +{ + 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(stat, &tmp, sizeof(tmp)); +} + +static int +ncp_notify_change(struct inode *inode, struct iattr *attr) +{ + int result = 0; + int info_mask; + struct nw_modify_dos_info info; + + if ((result = inode_change_ok(inode, attr)) < 0) + return result; + + 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; + + info_mask = 0; + memset(&info, 0, sizeof(info)); + + if ((attr->ia_valid & ATTR_CTIME) != 0) { + info_mask |= (DM_CREATE_TIME|DM_CREATE_DATE); + ncp_date_unix2dos(attr->ia_ctime, + &(info.creationTime), &(info.creationDate)); + } + + if ((attr->ia_valid & ATTR_MTIME) != 0) { + info_mask |= (DM_MODIFY_TIME|DM_MODIFY_DATE); + ncp_date_unix2dos(attr->ia_mtime, + &(info.modifyTime), &(info.modifyDate)); + } + + if ((attr->ia_valid & ATTR_ATIME) != 0) { + __u16 dummy; + info_mask |= (DM_LAST_ACCESS_DATE); + ncp_date_unix2dos(attr->ia_ctime, + &(dummy), &(info.lastAccessDate)); + } + + if (info_mask != 0) { + if ((result = + ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode), + NCP_ISTRUCT(inode), + info_mask, + &info)) != 0) { + result = -EACCES; + } + } + + if ((attr->ia_valid & ATTR_SIZE) != 0) { + + int written; + + DPRINTK("ncpfs: trying to change size of %s to %ld\n", + NCP_ISTRUCT(inode)->entryName, attr->ia_size); + + if ((result = ncp_make_open(inode, O_RDWR)) < 0) { + return -EACCES; + } + + ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, + attr->ia_size, 0, "", &written); + + /* According to ndir, the changes only take effect after + closing the file */ + ncp_close_file(NCP_SERVER(inode), + NCP_FINFO(inode)->file_handle); + NCP_FINFO(inode)->opened = 0; + + result = 0; + } + + ncp_invalid_dir_cache((unsigned long)(NCP_INOP(inode)->dir)); + + return result; +} + +#ifdef DEBUG_NCP_MALLOC +int ncp_malloced; +int ncp_current_malloced; +#endif + +#ifdef MODULE + +char kernel_version[] = UTS_RELEASE; + +static struct file_system_type ncp_fs_type = { + ncp_read_super, "ncpfs", 0, NULL + }; + +int +init_module( void) +{ + DPRINTK("ncpfs: init_module called\n"); + +#ifdef DEBUG_NCP_MALLOC + ncp_malloced = 0; + ncp_current_malloced = 0; +#endif + + ncp_init_dir_cache(); + register_filesystem(&ncp_fs_type); + return 0; +} + +void +cleanup_module(void) +{ + DPRINTK("ncpfs: cleanup_module called\n"); + ncp_free_dir_cache(); + unregister_filesystem(&ncp_fs_type); +#ifdef DEBUG_NCP_MALLOC + printk("ncp_malloced: %d\n", ncp_malloced); + printk("ncp_current_malloced: %d\n", ncp_current_malloced); +#endif +} + +#endif diff --git a/kernel-1.2/src/ioctl.c b/kernel-1.2/src/ioctl.c new file mode 100644 index 0000000..d8b70bb --- /dev/null +++ b/kernel-1.2/src/ioctl.c @@ -0,0 +1,97 @@ +/* + * ioctl.c + * + * Copyright (C) 1995 by Volker Lendecke + * + */ + +#include +#ifdef MODULE +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +int +ncp_ioctl (struct inode * inode, struct file * filp, + unsigned int cmd, unsigned long arg) +{ + int result; + struct ncp_ioctl_request request; + struct ncp_server *server; + + switch(cmd) { + case NCP_IOC_NCPREQUEST: + + if (!suser()) { + return -EPERM; + } + + if ((result = verify_area(VERIFY_READ, (char *)arg, + sizeof(request))) != 0) { + return result; + } + + memcpy_fromfs(&request, (struct ncp_ioctl_request *)arg, + sizeof(request)); + + if ( (request.function > 255) + || (request.size > + NCP_PACKET_SIZE - sizeof(struct ncp_request_header))) { + return -EINVAL; + } + + if ((result = verify_area(VERIFY_WRITE, (char *)request.data, + NCP_PACKET_SIZE)) != 0) { + return result; + } + + server = NCP_SERVER(inode); + ncp_lock_server(server); + + /* FIXME: We hack around in the server's structures + here to be able to use ncp_request */ + + server->has_subfunction = 0; + server->current_size = + request.size + sizeof(struct ncp_request_header); + memcpy_fromfs(server->packet, request.data, + request.size+sizeof(struct ncp_request_header)); + + + ncp_request(server, request.function); + + DPRINTK("ncp_ioctl: copy %d bytes\n", + server->reply_size); + memcpy_tofs(request.data, server->packet, + server->reply_size); + + ncp_unlock_server(server); + + return server->reply_size; + + case NCP_IOC_GETMOUNTUID: + if ((result = verify_area(VERIFY_WRITE, (uid_t*) arg, + sizeof(uid_t))) != 0) { + return result; + } + put_fs_word(NCP_SERVER(inode)->m.mounted_uid, (uid_t*) arg); + return 0; + + default: + return -EINVAL; + } + + return -EINVAL; +} diff --git a/kernel-1.2/src/ncplib.c b/kernel-1.2/src/ncplib.c new file mode 100644 index 0000000..f751233 --- /dev/null +++ b/kernel-1.2/src/ncplib.c @@ -0,0 +1,590 @@ +#include +#ifdef MODULE +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + + + +#include "ncplib.h" + +typedef __u8 byte; +typedef __u16 word; +typedef __u32 dword; + +static void +assert_server_locked(struct ncp_server *server) +{ + if (server->lock == 0) { + DPRINTK("ncpfs: server not locked!\n"); + } +} + +static void +ncp_add_byte(struct ncp_server *server, byte x) +{ + assert_server_locked(server); + *(byte *)(&(server->packet[server->current_size])) = x; + server->current_size += 1; + return; +} + +static void +ncp_add_word(struct ncp_server *server, word x) +{ + assert_server_locked(server); + *(word *)(&(server->packet[server->current_size])) = x; + server->current_size += 2; + return; +} + +static void +ncp_add_dword(struct ncp_server *server, dword x) +{ + assert_server_locked(server); + *(dword *)(&(server->packet[server->current_size])) = x; + server->current_size += 4; + return; +} + +static void +ncp_add_mem(struct ncp_server *server, const void *source, int size) +{ + assert_server_locked(server); + memcpy(&(server->packet[server->current_size]), source, size); + server->current_size += size; + return; +} + +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; +} + +static void +ncp_add_pstring(struct ncp_server *server, const char *s) +{ + int len = strlen(s); + assert_server_locked(server); + if (len > 255) { + DPRINTK("ncpfs: string too long: %s\n", s); + len = 255; + } + ncp_add_byte(server, len); + ncp_add_mem(server, s, len); + return; +} + +static void +ncp_init_request(struct ncp_server *server) +{ + ncp_lock_server(server); + + server->current_size = sizeof(struct ncp_request_header); + server->has_subfunction = 0; +} + +static void +ncp_init_request_s(struct ncp_server *server, int subfunction) +{ + ncp_init_request(server); + ncp_add_word(server, 0); /* preliminary size */ + + ncp_add_byte(server, subfunction); + + server->has_subfunction = 1; +} + +static char * +ncp_reply_data(struct ncp_server *server, int offset) +{ + return &(server->packet[sizeof(struct ncp_reply_header) + offset]); +} + +static byte +ncp_reply_byte(struct ncp_server *server, int offset) +{ + return *(byte *)(ncp_reply_data(server, offset)); +} + +static word +ncp_reply_word(struct ncp_server *server, int offset) +{ + return *(word *)(ncp_reply_data(server, offset)); +} + +static dword +ncp_reply_dword(struct ncp_server *server, int offset) +{ + return *(dword *)(ncp_reply_data(server, offset)); +} + +int +ncp_negotiate_buffersize(struct ncp_server *server, + int size, int *target) { + + int result; + + ncp_init_request(server); + ncp_add_word(server, htons(size)); + + if ((result = ncp_request(server, 33)) != 0) { + ncp_unlock_server(server); + return result; + } + + *target =min(ntohs(ncp_reply_word(server, 0)), size); + + ncp_unlock_server(server); + return 0; +} + +int +ncp_get_volume_info_with_number(struct ncp_server *server, int n, + struct ncp_volume_info *target) +{ + int result; + int len; + + ncp_init_request_s(server, 44); + ncp_add_byte(server, n); + + if ((result = ncp_request(server, 22)) != 0) { + ncp_unlock_server(server); + return result; + } + + target->total_blocks = ncp_reply_dword(server, 0); + target->free_blocks = ncp_reply_dword(server, 4); + target->purgeable_blocks = ncp_reply_dword(server, 8); + target->not_yet_purgeable_blocks = ncp_reply_dword(server, 12); + target->total_dir_entries = ncp_reply_dword(server, 16); + target->available_dir_entries = ncp_reply_dword(server, 20); + target->sectors_per_block = ncp_reply_byte(server, 28); + + memset(&(target->volume_name), 0, sizeof(target->volume_name)); + + len = ncp_reply_byte(server, 29); + if (len > NCP_VOLNAME_LEN) { + DPRINTK("ncpfs: volume name too long: %d\n", len); + ncp_unlock_server(server); + return -EIO; + } + + memcpy(&(target->volume_name), ncp_reply_data(server, 30), len); + ncp_unlock_server(server); + return 0; +} + +int +ncp_get_volume_number(struct ncp_server *server, const char *name, int *target) +{ + int result; + + ncp_init_request_s(server, 5); + ncp_add_pstring(server, name); + + if ((result = ncp_request(server, 22)) != 0) { + ncp_unlock_server(server); + return result; + } + + *target = ncp_reply_byte(server, 0); + ncp_unlock_server(server); + return 0; +} + +int +ncp_close_file(struct ncp_server *server, const char *file_id) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, 0); + ncp_add_mem(server, file_id, 6); + + if ((result = ncp_request(server, 66)) != 0) { + ncp_unlock_server(server); + return result; + } + + ncp_unlock_server(server); + return 0; +} + +static void +ncp_add_handle_path(struct ncp_server *server, + __u8 vol_num, + __u32 dir_base, int have_dir_base, + char *path) +{ + ncp_add_byte(server, vol_num); + ncp_add_dword(server, dir_base); + if (have_dir_base != 0) { + ncp_add_byte(server, 1); /* dir_base */ + } else { + ncp_add_byte(server, 0xff); /* no handle */ + } + if (path != NULL) { + ncp_add_byte(server, 1); /* 1 component */ + ncp_add_pstring(server, path); + } + else + { + ncp_add_byte(server, 0); + } +} + +static void +ncp_extract_file_info(void *structure, struct nw_info_struct *target) +{ + __u8 *name_len; + const int info_struct_size = sizeof(struct nw_info_struct) - 257; + + memcpy(target, structure, info_struct_size); + name_len = structure + info_struct_size; + target->nameLen = *name_len; + strncpy(target->entryName, name_len+1, *name_len); + target->entryName[*name_len] = '\0'; + return; +} + + +int +ncp_do_lookup(struct ncp_server *server, + struct nw_info_struct *dir, + char *path, /* may only be one component */ + struct nw_info_struct *target) +{ + __u8 vol_num; + __u32 dir_base; + int result; + char *volname = NULL; + + if (target == NULL) { + return -EINVAL; + } + + if (dir == NULL) { + + DDPRINTK("ncp_do_lookup: looking up vol %s\n", path); + + /* Access a volume's root directory */ + ncp_init_request(server); + ncp_add_byte(server, 22); /* subfunction */ + ncp_add_byte(server, 0); /* dos name space */ + ncp_add_byte(server, 0); /* reserved */ + ncp_add_byte(server, 0); /* reserved */ + ncp_add_byte(server, 0); /* reserved */ + ncp_add_handle_path(server, 0, 0, 0, /* no handle */ + path); + + if ((result = ncp_request(server, 87)) != 0) { + ncp_unlock_server(server); + return result; + } + + dir_base = ncp_reply_dword(server, 4); + vol_num = ncp_reply_byte (server, 8); + ncp_unlock_server(server); + volname = path; + path = NULL; + } + else + { + vol_num = dir->volNumber; + dir_base = dir->DosDirNum; + } + + ncp_init_request(server); + ncp_add_byte(server, 6); /* subfunction */ + ncp_add_byte(server, 0); /* dos name space */ + ncp_add_byte(server, 0); /* dos name space as dest */ + ncp_add_word(server, 0xff); /* get all */ + ncp_add_dword(server, RIM_ALL); + ncp_add_handle_path(server, vol_num, dir_base, 1, + path); + + if ((result = ncp_request(server, 87)) != 0) { + ncp_unlock_server(server); + return result; + } + + ncp_extract_file_info(ncp_reply_data(server, 0), target); + + if (volname != NULL) { + target->nameLen = strlen(volname); + strcpy(target->entryName, volname); + } + + ncp_unlock_server(server); + return 0; +} + +int +ncp_modify_file_or_subdir_dos_info(struct ncp_server *server, + struct nw_info_struct *file, + __u32 info_mask, + struct nw_modify_dos_info *info) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, 7); /* subfunction */ + ncp_add_byte(server, 0); /* dos name space */ + ncp_add_byte(server, 0); /* reserved */ + ncp_add_word(server, 0x8006); /* search attribs: all */ + + ncp_add_dword(server, info_mask); + ncp_add_mem(server, info, sizeof(*info)); + ncp_add_handle_path(server, file->volNumber, + file->DosDirNum, 1, NULL); + + if ((result = ncp_request(server, 87)) != 0) { + ncp_unlock_server(server); + return result; + } + + ncp_unlock_server(server); + return 0; +} + +int +ncp_del_file_or_subdir(struct ncp_server *server, + struct nw_info_struct *dir, char *name) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, 8); /* subfunction */ + ncp_add_byte(server, 0); /* dos name space */ + ncp_add_byte(server, 0); /* reserved */ + ncp_add_word(server, 0x8006); /* search attribs: all */ + ncp_add_handle_path(server, dir->volNumber, + dir->DosDirNum, 1, name); + + if ((result = ncp_request(server, 87)) != 0) { + ncp_unlock_server(server); + return result; + } + + ncp_unlock_server(server); + return 0; +} + +static inline void +ConvertToNWfromDWORD ( __u32 sfd , __u8 ret[6] ) +{ + __u16 *dest = (__u16 *) ret; + memcpy(&(dest[1]), &sfd, 4); + dest[0] = dest[1] + 1; + return; +} + +/* If both dir and name are NULL, then in target there's already a + looked-up entry that wants to be opened. */ +int +ncp_open_create_file_or_subdir(struct ncp_server *server, + struct nw_info_struct *dir, char *name, + int open_create_mode, + __u32 create_attributes, + int desired_acc_rights, + struct nw_file_info *target) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, 1); /* subfunction */ + ncp_add_byte(server, 0); /* dos name space */ + ncp_add_byte(server, open_create_mode); + ncp_add_word(server, 0x8006); + ncp_add_dword(server, RIM_ALL); + ncp_add_dword(server, create_attributes); + /* The desired acc rights seem to be the inherited rights mask + for directories */ + ncp_add_word(server, desired_acc_rights); + + if (dir != NULL) { + ncp_add_handle_path(server, dir->volNumber, + dir->DosDirNum, 1, name); + } else { + ncp_add_handle_path(server, + target->i.volNumber, target->i.DosDirNum, + 1, NULL); + } + + if ((result = ncp_request(server, 87)) != 0) { + ncp_unlock_server(server); + return result; + } + + target->opened = 1; + target->server_file_handle = ncp_reply_dword(server, 0); + target->open_create_action = ncp_reply_byte(server, 4); + + if (dir != NULL) { + /* in target there's a new finfo to fill */ + ncp_extract_file_info(ncp_reply_data(server, 5), &(target->i)); + } + + ConvertToNWfromDWORD(target->server_file_handle, target->file_handle); + + ncp_unlock_server(server); + return 0; +} + + +int +ncp_initialize_search(struct ncp_server *server, + struct nw_info_struct *dir, + struct nw_search_sequence *target) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, 2); /* subfunction */ + ncp_add_byte(server, 0); /* dos name space */ + ncp_add_byte(server, 0); /* reserved */ + ncp_add_handle_path(server, dir->volNumber, dir->DosDirNum, 1, NULL); + + if ((result = ncp_request(server, 87)) != 0) { + ncp_unlock_server(server); + return result; + } + + memcpy(target, ncp_reply_data(server, 0), sizeof(*target)); + + ncp_unlock_server(server); + return 0; +} + +/* Search for everything */ +int +ncp_search_for_file_or_subdir(struct ncp_server *server, + struct nw_search_sequence *seq, + struct nw_info_struct *target) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, 3); /* subfunction */ + ncp_add_byte(server, 0); /* dos name space */ + ncp_add_byte(server, 0); /* data stream (???) */ + ncp_add_word(server, 0xffff); /* Search attribs */ + ncp_add_dword(server, RIM_ALL); /* return info mask */ + ncp_add_mem(server, seq, 9); + ncp_add_byte(server, 2); /* 2 byte pattern */ + ncp_add_byte(server, 0xff); /* following is a wildcard */ + ncp_add_byte(server, '*'); + + if ((result = ncp_request(server, 87)) != 0) { + ncp_unlock_server(server); + return result; + } + + memcpy(seq, ncp_reply_data(server, 0), sizeof(*seq)); + ncp_extract_file_info(ncp_reply_data(server, 10), target); + + ncp_unlock_server(server); + return 0; +} + +int +ncp_ren_or_mov_file_or_subdir(struct ncp_server *server, + struct nw_info_struct *old_dir, char *old_name, + struct nw_info_struct *new_dir, char *new_name) +{ + int result; + + if ( (old_dir == NULL) || (old_name == NULL) + || (new_dir == NULL) || (new_name == NULL)) + return -EINVAL; + + ncp_init_request(server); + ncp_add_byte(server, 4); /* subfunction */ + ncp_add_byte(server, 0); /* dos name space */ + ncp_add_byte(server, 1); /* rename flag */ + ncp_add_word(server, 0x8006); /* search attributes */ + + /* source Handle Path */ + ncp_add_byte(server, old_dir->volNumber); + ncp_add_dword(server, old_dir->DosDirNum); + ncp_add_byte(server, 1); + ncp_add_byte(server, 1); /* 1 source component */ + + /* dest Handle Path */ + ncp_add_byte(server, new_dir->volNumber); + ncp_add_dword(server, new_dir->DosDirNum); + ncp_add_byte(server, 1); + ncp_add_byte(server, 1); /* 1 destination component */ + + /* source path string */ + ncp_add_pstring(server, old_name); + /* dest path string */ + ncp_add_pstring(server, new_name); + + result = ncp_request(server, 87); + ncp_unlock_server(server); + return result; +} + + +/* We have to transfer to/from user space */ +int +ncp_read(struct ncp_server *server, const char *file_id, + __u32 offset, __u16 to_read, + char *target, int *bytes_read) +{ + 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_read)); + + if ((result = ncp_request(server, 72)) != 0) { + ncp_unlock_server(server); + return result; + } + + *bytes_read = ntohs(ncp_reply_word(server, 0)); + + memcpy_tofs(target, ncp_reply_data(server, 2), *bytes_read); + + ncp_unlock_server(server); + 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_unlock_server(server); + return result; + } + + *bytes_written = to_write; + + ncp_unlock_server(server); + return 0; +} + diff --git a/kernel-1.2/src/ncplib.h b/kernel-1.2/src/ncplib.h new file mode 100644 index 0000000..3278cdf --- /dev/null +++ b/kernel-1.2/src/ncplib.h @@ -0,0 +1,156 @@ +#ifndef _NCPLIB_H +#define _NCPLIB_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int +ncp_negotiate_buffersize(struct ncp_server *server, int size, + int *target); +int +ncp_get_encryption_key(struct ncp_server *server, + char *target); +int +ncp_get_bindery_object_id(struct ncp_server *server, + int object_type, char *object_name, + struct ncp_bindery_object *target); +int +ncp_login_encrypted(struct ncp_server *server, + struct ncp_bindery_object *object, + unsigned char *key, + unsigned char *passwd); +int +ncp_login_user(struct ncp_server *server, + unsigned char *username, + unsigned char *password); +int +ncp_get_volume_info_with_number(struct ncp_server *server, int n, + struct ncp_volume_info *target); + +int +ncp_get_volume_number(struct ncp_server *server, const char *name, + int *target); + +int +ncp_file_search_init(struct ncp_server *server, + int dir_handle, const char *path, + struct ncp_filesearch_info *target); + +int +ncp_file_search_continue(struct ncp_server *server, + struct ncp_filesearch_info *fsinfo, + int attributes, const char *path, + struct ncp_file_info *target); + +int +ncp_get_finfo(struct ncp_server *server, + int dir_handle, const char *path, const char *name, + struct ncp_file_info *target); + +int +ncp_open_file(struct ncp_server *server, + int dir_handle, const char *path, + int attr, int access, + struct ncp_file_info *target); +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 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); + +int +ncp_do_lookup(struct ncp_server *server, + struct nw_info_struct *dir, + char *path, /* may only be one component */ + struct nw_info_struct *target); + +int +ncp_modify_file_or_subdir_dos_info(struct ncp_server *server, + struct nw_info_struct *file, + __u32 info_mask, + struct nw_modify_dos_info *info); + +int +ncp_del_file_or_subdir(struct ncp_server *server, + struct nw_info_struct *dir, char *name); + +int +ncp_open_create_file_or_subdir(struct ncp_server *server, + struct nw_info_struct *dir, char *name, + int open_create_mode, + __u32 create_attributes, + int desired_acc_rights, + struct nw_file_info *target); + +int +ncp_initialize_search(struct ncp_server *server, + struct nw_info_struct *dir, + struct nw_search_sequence *target); + +int +ncp_search_for_file_or_subdir(struct ncp_server *server, + struct nw_search_sequence *seq, + struct nw_info_struct *target); + +int +ncp_ren_or_mov_file_or_subdir(struct ncp_server *server, + struct nw_info_struct *old_dir, char *old_name, + struct nw_info_struct *new_dir, char *new_name); + + +#endif /* _NCPLIB_H */ diff --git a/kernel-1.2/src/sock.c b/kernel-1.2/src/sock.c new file mode 100644 index 0000000..b5407c7 --- /dev/null +++ b/kernel-1.2/src/sock.c @@ -0,0 +1,543 @@ +/* + * linux/fs/ncp/sock.c + * + * Copyright (C) 1992, 1993 Rick Sladkey + * + * Modified 1995 by Volker Lendecke to be usable for ncp + * + */ + +#include +#ifdef MODULE +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "/usr/src/linux/net/inet/sock.h" + + +#define _S(nr) (1<<((nr)-1)) +static void +ncp_wdog_data_ready(struct sock *sk, int len) +{ + struct socket *sock = sk->socket; + + if (!sk->dead) + { + unsigned char packet_buf[2]; + struct sockaddr_ipx sender; + int addr_len = sizeof(struct sockaddr_ipx); + int result; + unsigned short fs; + + fs = get_fs(); + set_fs(get_ds()); + + result = sock->ops->recvfrom(sock, (void *)packet_buf, 2, 1, 0, + (struct sockaddr *)&sender, + &addr_len); + + if ( (result != 2) + || (packet_buf[1] != '?') + /* How to check connection number here? */ + ) + { + /* Error, throw away the complete packet */ + sock->ops->recvfrom(sock, (void *)packet_buf, 2, 1, 0, + (struct sockaddr *)&sender, + &addr_len); + + printk("ncpfs: got strange packet on watchdog " + "socket\n"); + + } else { + int result; + DPRINTK("ncpfs: got watchdog from:\n"); + DPRINTK("ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X," + " conn:%02X,type:%c\n", + htonl(sender.sipx_network), + sender.sipx_node[0], sender.sipx_node[1], + sender.sipx_node[2], sender.sipx_node[3], + sender.sipx_node[4], sender.sipx_node[5], + ntohs(sender.sipx_port), + packet_buf[0], packet_buf[1]); + + packet_buf[1] = 'Y'; + result = sock->ops->sendto(sock, (void *)packet_buf, + 2, 1, 0, + (struct sockaddr *)&sender, + sizeof(sender)); + DPRINTK("send result: %d\n", result); + } + set_fs(fs); + } +} + + +int +ncp_catch_watchdog(struct ncp_server *server) +{ + struct file *file; + struct inode *inode; + struct socket *sock; + struct sock *sk; + + if ( (server == NULL) + || ((file = server->wdog_filp) == NULL) + || ((inode = file->f_inode) == NULL) + || (!S_ISSOCK(inode->i_mode))) { + + printk("ncp_catch_watchdog: did not get valid server!\n"); + server->data_ready = NULL; + return -EINVAL; + } + + sock = &(inode->u.socket_i); + + if (sock->type != SOCK_DGRAM) { + printk("ncp_catch_watchdog: did not get SOCK_STREAM\n"); + server->data_ready = NULL; + return -EINVAL; + } + + sk = (struct sock *)(sock->data); + + if (sk == NULL) { + printk("ncp_catch_watchdog: sk == NULL"); + server->data_ready = NULL; + return -EINVAL; + } + + DDPRINTK("ncp_catch_watchdog.: sk->d_r = %x, server->d_r = %x\n", + (unsigned int)(sk->data_ready), + (unsigned int)(server->data_ready)); + + if (sk->data_ready == ncp_wdog_data_ready) { + printk("ncp_catch_watchdog: already done\n"); + return -EINVAL; + } + + server->data_ready = sk->data_ready; + sk->data_ready = ncp_wdog_data_ready; + return 0; +} + +int +ncp_dont_catch_watchdog(struct ncp_server *server) +{ + struct file *file; + struct inode *inode; + struct socket *sock; + struct sock *sk; + + if ( (server == NULL) + || ((file = server->wdog_filp) == NULL) + || ((inode = file->f_inode) == NULL) + || (!S_ISSOCK(inode->i_mode))) { + + printk("ncp_dont_catch_watchdog: " + "did not get valid server!\n"); + return -EINVAL; + } + + sock = &(inode->u.socket_i); + + if (sock->type != SOCK_DGRAM) { + printk("ncp_dont_catch_watchdog: did not get SOCK_STREAM\n"); + return -EINVAL; + } + + sk = (struct sock *)(sock->data); + + if (sk == NULL) { + printk("ncp_dont_catch_watchdog: sk == NULL"); + return -EINVAL; + } + + if (server->data_ready == NULL) { + printk("ncp_dont_catch_watchdog: " + "server->data_ready == NULL\n"); + return -EINVAL; + } + + if (sk->data_ready != ncp_wdog_data_ready) { + printk("ncp_dont_catch_watchdog: " + "sk->data_callback != ncp_data_callback\n"); + return -EINVAL; + } + + DDPRINTK("ncp_dont_catch_watchdog: sk->d_r = %x, server->d_r = %x\n", + (unsigned int)(sk->data_ready), + (unsigned int)(server->data_ready)); + + sk->data_ready = server->data_ready; + server->data_ready = NULL; + return 0; +} + + + +#define NCP_SLACK_SPACE 1024 + +#define _S(nr) (1<<((nr)-1)) + +static int +do_ncp_rpc_call(struct ncp_server *server, int size) +{ + struct file *file; + struct inode *inode; + struct socket *sock; + unsigned short fs; + int result; + char *start = server->packet; + select_table wait_table; + struct select_table_entry entry; + int (*select) (struct inode *, struct file *, int, select_table *); + int init_timeout, max_timeout; + int timeout; + int retrans; + int major_timeout_seen; + char *server_name; + int n; + int addrlen; + unsigned long old_mask; + + /* We have to check the result, so store the complete header */ + struct ncp_request_header request = + *((struct ncp_request_header *)(server->packet)); + + struct ncp_reply_header reply; + + + file = server->ncp_filp; + inode = file->f_inode; + select = file->f_op->select; + sock = &inode->u.socket_i; + if (!sock) { + printk("ncp_rpc_call: socki_lookup failed\n"); + return -EBADF; + } + init_timeout = server->m.time_out; + max_timeout = NCP_MAX_RPC_TIMEOUT*HZ/10; + retrans = server->m.retry_count; + major_timeout_seen = 0; + server_name = server->m.server_name; + old_mask = current->blocked; + current->blocked |= ~(_S(SIGKILL) +#if 0 + | _S(SIGSTOP) +#endif + | ((server->m.flags & NCP_MOUNT_INTR) + ? ((current->sigaction[SIGINT - 1].sa_handler == SIG_DFL + ? _S(SIGINT) : 0) + | (current->sigaction[SIGQUIT - 1].sa_handler == SIG_DFL + ? _S(SIGQUIT) : 0)) + : 0)); + fs = get_fs(); + set_fs(get_ds()); + for (n = 0, timeout = init_timeout; ; n++, timeout <<= 1) { + DDPRINTK("ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X\n", + htonl(server->m.serv_addr.sipx_network), + server->m.serv_addr.sipx_node[0], + server->m.serv_addr.sipx_node[1], + server->m.serv_addr.sipx_node[2], + server->m.serv_addr.sipx_node[3], + server->m.serv_addr.sipx_node[4], + server->m.serv_addr.sipx_node[5], + ntohs(server->m.serv_addr.sipx_port)); + DDPRINTK("ncpfs: req.typ: %04X, con: %d, " + "seq: %d", + request.type, + (request.conn_high << 8) + request.conn_low, + request.sequence); + DDPRINTK(" func: %d\n", + request.function); + + result = sock->ops->sendto(sock, (void *) start, size, 0, 0, + (struct sockaddr *) + &(server->m.serv_addr), + sizeof(server->m.serv_addr)); + if (result < 0) { + printk("ncp_rpc_call: send error = %d\n", result); + break; + } + re_select: + wait_table.nr = 0; + wait_table.entry = &entry; + current->state = TASK_INTERRUPTIBLE; + if ( !select(inode, file, SEL_IN, &wait_table) + && !select(inode, file, SEL_IN, NULL)) { + if (timeout > max_timeout) { + /* JEJB/JSP 2/7/94 + * This is useful to see if the system is + * hanging */ + printk("NCP max timeout reached on %s\n", + server_name); + timeout = max_timeout; + } + current->timeout = jiffies + timeout; + schedule(); + remove_wait_queue(entry.wait_address, &entry.wait); + current->state = TASK_RUNNING; + if (current->signal & ~current->blocked) { + current->timeout = 0; + result = -ERESTARTSYS; + break; + } + if (!current->timeout) { + if (n < retrans) + continue; + if (server->m.flags & NCP_MOUNT_SOFT) { + printk("NCP server %s not responding, " + "timed out\n", server_name); + result = -EIO; + break; + } + n = 0; + timeout = init_timeout; + init_timeout <<= 1; + if (!major_timeout_seen) { + printk("NCP server %s not responding, " + "still trying\n", server_name); + } + major_timeout_seen = 1; + continue; + } + else + current->timeout = 0; + } + else if (wait_table.nr) + remove_wait_queue(entry.wait_address, &entry.wait); + current->state = TASK_RUNNING; + addrlen = 0; + + /* Get the header from the next packet using a peek, so keep it + * on the recv queue. If it is wrong, it will be some reply + * we don't now need, so discard it */ + result = sock->ops->recvfrom(sock, (void *)&reply, + sizeof(reply), 1, MSG_PEEK, + NULL, &addrlen); + if (result < 0) { + if (result == -EAGAIN) { + DPRINTK("ncp_rpc_call: bad select ready\n"); + goto re_select; + } + if (result == -ECONNREFUSED) { + DPRINTK("ncp_rpc_call: server playing coy\n"); + goto re_select; + } + if (result != -ERESTARTSYS) { + printk("ncp_rpc_call: recv error = %d\n", + -result); + } + break; + } + if ( (result == sizeof(reply)) + && (reply.type == NCP_POSITIVE_ACK)) { + /* Throw away the packet */ + DPRINTK("ncp_rpc_call: got positive acknowledge\n"); + sock->ops->recvfrom(sock, (void *)&reply, + sizeof(reply), 1, 0, + NULL, &addrlen); + goto re_select; + } + + DDPRINTK("ncpfs: rep.typ: %04X, con: %d, tsk: %d," + "seq: %d\n", + reply.type, + (reply.conn_high << 8) + reply.conn_low, + reply.task, + reply.sequence); + + if ( (result >= sizeof(reply)) + && (reply.type == NCP_REPLY) + && ( (request.type == NCP_ALLOC_SLOT_REQUEST) + || ( (reply.sequence == request.sequence) + && (reply.conn_low == request.conn_low) +/* seem to get wrong task from NW311 && (reply.task == request.task)*/ + && (reply.conn_high == request.conn_high)))) { + if (major_timeout_seen) + printk("NCP server %s OK\n", server_name); + break; + } + /* JEJB/JSP 2/7/94 + * we have xid mismatch, so discard the packet and start + * again. What a hack! but I can't call recvfrom with + * a null buffer yet. */ + sock->ops->recvfrom(sock, (void *)&reply, sizeof(reply), 1, 0, + NULL, &addrlen); +#if 1 + printk("ncp_rpc_call: reply mismatch\n"); +#endif + goto re_select; + } + /* + * we have the correct reply, so read into the correct place and + * return it + */ + result = sock->ops->recvfrom(sock, (void *)start, server->packet_size, + 1, 0, NULL, &addrlen); + if (result < 0) { + printk("NCP: notice message: result=%d\n", result); + } else if (result < sizeof(struct ncp_reply_header)) { + printk("NCP: just caught a too small read memory size..., " + "email to NET channel\n"); + printk("NCP: result=%d,addrlen=%d\n", result, addrlen); + result = -EIO; + } + + current->blocked = old_mask; + set_fs(fs); + return result; +} + + +/* + * We need the server to be locked here, so check! + */ + +static int +ncp_do_request(struct ncp_server *server, int size) +{ + if (server->lock == 0) { + printk("ncpfs: Server not locked!\n"); + return -EIO; + } + + return do_ncp_rpc_call(server, size); +} + +/* ncp_do_request assures that at least a complete reply header is + * received. It assumes that server->current_size contains the ncp + * request size */ +int +ncp_request(struct ncp_server *server, int function) +{ + struct ncp_request_header *h + = (struct ncp_request_header *)(server->packet); + struct ncp_reply_header *reply + = (struct ncp_reply_header *)(server->packet); + + int request_size = server->current_size + - sizeof(struct ncp_request_header); + + int result; + + if (server->has_subfunction != 0) { + *(__u16 *)&(h->data[0]) = request_size - 2; + } + + h->type = NCP_REQUEST; + + server->sequence += 1; + h->sequence = server->sequence; + h->conn_low = (server->connection) & 0xff; + h->conn_high = ((server->connection) & 0xff00) >> 8; + h->task = (current->pid) & 0xff; + h->function = function; + + if ((result = ncp_do_request(server, request_size + sizeof(*h))) < 0) { + DPRINTK("ncp_request_error: %d\n", result); + return result; + } + + server->completion = reply->completion_code; + server->conn_status = reply->connection_state; + server->reply_size = result; + server->ncp_reply_size = result - sizeof(struct ncp_reply_header); + + result = reply->completion_code; + + if (result != 0) { + DPRINTK("ncp_completion_code: %d\n", result); + } + return result; +} + +int +ncp_connect(struct ncp_server *server) +{ + struct ncp_request_header *h + = (struct ncp_request_header *)(server->packet); + int result; + + h->type = NCP_ALLOC_SLOT_REQUEST; + + server->sequence = 0; + h->sequence = server->sequence; + h->conn_low = 0xff; + h->conn_high = 0xff; + h->task = (current->pid) & 0xff; + h->function = 0; + + if ((result = ncp_do_request(server, sizeof(*h))) < 0) { + return result; + } + + server->sequence = 0; + server->connection = h->conn_low + (h->conn_high * 256); + return 0; +} + +int +ncp_disconnect(struct ncp_server *server) +{ + struct ncp_request_header *h + = (struct ncp_request_header *)(server->packet); + + h->type = NCP_DEALLOC_SLOT_REQUEST; + + server->sequence += 1; + h->sequence = server->sequence; + h->conn_low = (server->connection) & 0xff; + h->conn_high = ((server->connection) & 0xff00) >> 8; + h->task = (current->pid) & 0xff; + h->function = 0; + + return ncp_do_request(server, sizeof(*h)); +} + +void +ncp_lock_server(struct ncp_server *server) +{ +#if 1 + /* For testing, only 1 process */ + if (server->lock != 0) { + DPRINTK("ncpfs: server locked!!!\n"); + } +#endif + while (server->lock) + sleep_on(&server->wait); + server->lock = 1; +} + +void +ncp_unlock_server(struct ncp_server *server) +{ + if (server->lock != 1) { + printk("ncp_unlock_server: was not locked!\n"); + } + + server->lock = 0; + wake_up(&server->wait); +} + diff --git a/kernel-1.3/linux/ncp.h b/kernel-1.3/linux/ncp.h index 83ffefd..6a9627d 100644 --- a/kernel-1.3/linux/ncp.h +++ b/kernel-1.3/linux/ncp.h @@ -8,6 +8,8 @@ #ifndef _LINUX_NCP_H #define _LINUX_NCP_H +#error "Please use kernel 1.2.13" + #include #define NCP_PTYPE (0x11) diff --git a/kernel-1.3/src/dir.c b/kernel-1.3/src/dir.c index 22408a5..d23fe3b 100644 --- a/kernel-1.3/src/dir.c +++ b/kernel-1.3/src/dir.c @@ -5,8 +5,6 @@ * */ -/* #include */ - #include #include #include @@ -30,6 +28,7 @@ ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count); static int ncp_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t filldir); + static int ncp_read_volume_list(struct ncp_server *server, int start_with, int cache_size); @@ -285,8 +284,8 @@ ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size) #if 1 if (fpos < 2) { printk("OOPS, we expect fpos >= 2"); + fpos = 2; } - fpos = 2; #endif for (i=0; i= 2"); + fpos = 2; } - fpos = 2; #endif + DPRINTK("ncp_do_readdir: fpos = %d\n", fpos); - if (ncp_initialize_search(server, NCP_ISTRUCT(dir), &seq) != 0) { - DPRINTK("ncp_init_search failed\n"); - return total_count - fpos; + if (fpos == 2) { + last_dir = NULL; + total_count = 2; + } + + if ((fpos != total_count) || (dir != last_dir)) { + + total_count = 2; + last_dir = dir; + + DPRINTK("ncp_do_readdir: re-used seq for %s\n", + NCP_ISTRUCT(dir)->entryName); + + if (ncp_initialize_search(server, NCP_ISTRUCT(dir), &seq)!=0) { + DPRINTK("ncp_init_search failed\n"); + return total_count - fpos; + } } while (total_count < fpos + cache_size) { @@ -355,8 +370,8 @@ ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos, DPRINTK("ncp_do_readdir: skipped file: %s\n", entry->i.entryName); } else { - DPRINTK("ncp_do_readdir: found file: %s\n", - entry->i.entryName); + DDPRINTK("ncp_do_r: file: %s, f_pos=%d,total_count=%d", + entry->i.entryName, fpos, total_count); entry->s = seq; entry->f_pos = total_count; entry += 1; diff --git a/kernel-1.3/src/file.c b/kernel-1.3/src/file.c index 40064e5..6d40afc 100644 --- a/kernel-1.3/src/file.c +++ b/kernel-1.3/src/file.c @@ -5,8 +5,6 @@ * */ -/* #include */ - #include #include diff --git a/kernel-1.3/src/ioctl.c b/kernel-1.3/src/ioctl.c index 36d8f36..6b0fcd8 100644 --- a/kernel-1.3/src/ioctl.c +++ b/kernel-1.3/src/ioctl.c @@ -4,7 +4,6 @@ * Copyright (C) 1995 by Volker Lendecke * */ -/* #include */ #include #include diff --git a/kernel-1.3/src/sock.c b/kernel-1.3/src/sock.c index 1c85702..01e3452 100644 --- a/kernel-1.3/src/sock.c +++ b/kernel-1.3/src/sock.c @@ -7,8 +7,6 @@ * */ -/* #include */ - #include #include #include @@ -80,7 +78,7 @@ ncp_wdog_data_ready(struct sock *sk, int len) { unsigned char packet_buf[2]; struct sockaddr_ipx sender; - int addr_len; + int addr_len = sizeof(struct sockaddr_ipx); int result; unsigned short fs; diff --git a/ncpfs-0.6.lsm b/ncpfs-0.7.lsm similarity index 73% rename from ncpfs-0.6.lsm rename to ncpfs-0.7.lsm index 71cadf8..089d470 100644 --- a/ncpfs-0.6.lsm +++ b/ncpfs-0.7.lsm @@ -1,14 +1,14 @@ Begin3 Title: ncpfs -Version: 0.6 -Entered-date: 25. November 1995 +Version: 0.7 +Entered-date: 26. 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 - ~59k ncpfs-0.6.tgz - ~ 1k ncpfs-0.6.lsm + ~80k ncpfs-0.7.tgz + ~ 1k ncpfs-0.7.lsm Copying-policy: GPL End diff --git a/util/Makefile b/util/Makefile index 9e4c9de..7fd9f60 100644 --- a/util/Makefile +++ b/util/Makefile @@ -6,7 +6,7 @@ INCLUDES = -I/usr/src/linux/include -I../kernel BINDIR = ../bin UTILS = ncpmount ncpumount ncptest ipx_configure -CFLAGS = -Wall $(INCLUDES) -g +CFLAGS = -Wall $(INCLUDES) -O2 CC = gcc all: $(UTILS) diff --git a/util/ipxutil.h b/util/ipxutil.h index c9c56ec..9b6e1e2 100644 --- a/util/ipxutil.h +++ b/util/ipxutil.h @@ -54,11 +54,15 @@ struct ipx_rip_packet { #define IPX_BROADCAST_NODE "\xff\xff\xff\xff\xff\xff" #define IPX_THIS_NODE "\0\0\0\0\0\0" +#ifndef IPX_NODE_LEN +#define IPX_NODE_LEN (6) +#endif typedef unsigned long IPXNet; typedef unsigned short IPXPort; typedef unsigned char IPXNode[IPX_NODE_LEN]; + void ipx_print_node(IPXNode node); void ipx_print_network(IPXNet net); void ipx_print_port(IPXPort port); diff --git a/util/ncplib_user.c b/util/ncplib_user.c index 234d970..4f08c16 100644 --- a/util/ncplib_user.c +++ b/util/ncplib_user.c @@ -6,7 +6,8 @@ typedef __u16 word; typedef __u32 dword; #include -#include +/* #include */ /* generates a warning here */ +extern pid_t wait(int *); #include #include #include @@ -175,7 +176,7 @@ ncp_user_request(struct ncp_server *server, int function) result = r->completion_code; - if (result != 0) { + if ((result != 0) && (server->silent == 0)) { ncp_printf("ncp_completion_code: %d\n", result); } return result; diff --git a/util/ncptest.c b/util/ncptest.c index c818658..33da516 100644 --- a/util/ncptest.c +++ b/util/ncptest.c @@ -629,7 +629,7 @@ main(int argc, char **argv) exit(1); } - test_touch(server); + getchar(); ncp_disconnect(server); diff --git a/util/start_ipx b/util/start_ipx index 08a3faf..f02f56b 100755 --- a/util/start_ipx +++ b/util/start_ipx @@ -4,5 +4,4 @@ # 00001b038b11 is the server's node number. # ipx_interface add -p eth0 EtherII 10 -ipx_route add 1992 10 00001b3bc0c9 ipx_route add 1234 10 00001b038b11