From 9297af3ffd8a1c98f35fb7a273386576e061ff16 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Mar 2008 10:40:48 -0700 Subject: novfs: Add the Novell filesystem client kernel module Patch-mainline: not yet, being worked on. This adds the Novell filesystem client kernel module. Things to do before it can be submitted: - coding style cleanups - remove typedefs - function name lowercase - 80 chars wide - sparse cleanups - __user markings - endian markings - remove functions that are never called and structures never used - yeah, there are a lot of them... - remove wrapper functions - private kmalloc/free? - resolve FIXME markings that have been added to the code - wrong types passed to functions!!! - userspace interface revisit - uses /proc/novfs, not nice. - might need userspace tools rework - use of semaphore as mutex - abuse of semaphore in lieu of completions. Update May 13 2009 jeffm: - Merged patches back into master novfs patch Cc: Lonnie Iverson Signed-off-by: Greg Kroah-Hartman --- fs/Kconfig | 1 fs/Makefile | 1 fs/novfs/Kconfig | 8 fs/novfs/Makefile | 19 fs/novfs/commands.h | 955 ++++++++++ fs/novfs/daemon.c | 2085 +++++++++++++++++++++++ fs/novfs/file.c | 1921 +++++++++++++++++++++ fs/novfs/inode.c | 4638 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/novfs/nwcapi.c | 2202 ++++++++++++++++++++++++ fs/novfs/nwcapi.h | 1416 +++++++++++++++ fs/novfs/nwerror.h | 658 +++++++ fs/novfs/proc.c | 149 + fs/novfs/profile.c | 704 +++++++ fs/novfs/scope.c | 659 +++++++ fs/novfs/vfs.h | 454 +++++ 15 files changed, 15870 insertions(+) --- a/fs/Kconfig +++ b/fs/Kconfig @@ -241,6 +241,7 @@ source "fs/ncpfs/Kconfig" source "fs/coda/Kconfig" source "fs/afs/Kconfig" source "fs/9p/Kconfig" +source "fs/novfs/Kconfig" endif # NETWORK_FILESYSTEMS --- a/fs/Makefile +++ b/fs/Makefile @@ -125,4 +125,5 @@ obj-$(CONFIG_OCFS2_FS) += ocfs2/ obj-$(CONFIG_BTRFS_FS) += btrfs/ obj-$(CONFIG_GFS2_FS) += gfs2/ obj-$(CONFIG_EXOFS_FS) += exofs/ +obj-$(CONFIG_NOVFS) += novfs/ obj-$(CONFIG_CEPH_FS) += ceph/ --- /dev/null +++ b/fs/novfs/Kconfig @@ -0,0 +1,8 @@ +config NOVFS + tristate "Novell Netware Filesystem support (novfs) (EXPERIMENTAL)" + depends on INET && EXPERIMENTAL + help + If you say Y here, you will get an experimental Novell Netware + filesystem driver. + + If unsure, say N. --- /dev/null +++ b/fs/novfs/Makefile @@ -0,0 +1,19 @@ +# +# Makefile for the Novell NetWare Client for Linux filesystem. +# + +NOVFS_VFS_MAJOR = 2 +NOVFS_VFS_MINOR = 0 +NOVFS_VFS_SUB = 0 +NOVFS_VFS_RELEASE = 440 + +EXTRA_CFLAGS += -DNOVFS_VFS_MAJOR=$(NOVFS_VFS_MAJOR) +EXTRA_CFLAGS += -DNOVFS_VFS_MINOR=$(NOVFS_VFS_MINOR) +EXTRA_CFLAGS += -DNOVFS_VFS_SUB=$(NOVFS_VFS_SUB) +EXTRA_CFLAGS += -DNOVFS_VFS_PATCH=$(NOVFS_VFS_PATCH) +EXTRA_CFLAGS += -DNOVFS_VFS_RELEASE=$(NOVFS_VFS_RELEASE) + +obj-$(CONFIG_NOVFS) += novfs.o + +novfs-objs := inode.o proc.o profile.o daemon.o file.o scope.o nwcapi.o + --- /dev/null +++ b/fs/novfs/commands.h @@ -0,0 +1,955 @@ +/* + * NetWare Redirector for Linux + * Author: James Turner/Richard Williams + * + * This file contains all defined commands. + * + * Copyright (C) 2005 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ + +#ifndef __NOVFS_COMMANDS_H +#define __NOVFS_COMMANDS_H + +#define VFS_COMMAND_GET_CONNECTED_SERVER_LIST 0 +#define VFS_COMMAND_GET_SERVER_VOLUME_LIST 1 +#define VFS_COMMAND_VERIFY_FILE 2 +#define VFS_COMMAND_OPEN_CONNECTION_BY_ADDR 3 +#define VFS_COMMAND_LOGIN_IDENTITY 4 +#define VFS_COMMAND_ENUMERATE_DIRECTORY 5 +#define VFS_COMMAND_OPEN_FILE 6 +#define VFS_COMMAND_CREATE_FILE 7 +#define VFS_COMMAND_CLOSE_FILE 8 +#define VFS_COMMAND_READ_FILE 9 +#define VFS_COMMAND_WRITE_FILE 10 +#define VFS_COMMAND_DELETE_FILE 11 +#define VFS_COMMAND_CREATE_DIRECOTRY 12 +#define VFS_COMMAND_START_ENUMERATE 13 +#define VFS_COMMAND_END_ENUMERATE 14 +#define VFS_COMMAND_LOGIN_USER 15 +#define VFS_COMMAND_LOGOUT_USER 16 +#define VFS_COMMAND_CREATE_CONTEXT 17 +#define VFS_COMMAND_DESTROY_CONTEXT 18 +#define VFS_COMMAND_SET_FILE_INFO 19 +#define VFS_COMMAND_TRUNCATE_FILE 20 +#define VFS_COMMAND_OPEN_CONNECTION_BY_NAME 21 +#define VFS_COMMAND_XPLAT_CALL 22 +#define VFS_COMMAND_RENAME_FILE 23 +#define VFS_COMMAND_ENUMERATE_DIRECTORY_EX 24 +#define VFS_COMMAND_GETPWUD 25 +#define VFS_COMMAND_ENUM_XCONN 26 +#define VFS_COMMAND_READ_STREAM 27 +#define VFS_COMMAND_WRITE_STREAM 28 +#define VFS_COMMAND_CLOSE_STREAM 29 +#define VFS_COMMAND_GET_VERSION 30 +#define VFS_COMMAND_SET_MOUNT_PATH 31 +#define VFS_COMMAND_GET_USER_SPACE 32 +#define VFS_COMMAND_DBG 33 +#define VFS_COMMAND_GET_CACHE_FLAG 34 +#define VFS_COMMAND_GET_EXTENDED_ATTRIBUTE 35 +#define VFS_COMMAND_LIST_EXTENDED_ATTRIBUTES 36 +#define VFS_COMMAND_SET_EXTENDED_ATTRIBUTE 37 +#define VFS_COMMAND_SET_FILE_LOCK 38 + +#define NWD_ACCESS_QUERY 0x00000001 +#define NWD_ACCESS_READ 0x00000002 +#define NWD_ACCESS_WRITE 0x00000004 +#define NWD_ACCESS_EXECUTE 0x00000008 +#define NWD_ACCESS_VALID 0x0000000F + +/* + Share Mode + + A value of zero in a shared mode field specifies the caller + desires exclusive access to the object. +*/ + +#define NWD_SHARE_READ 0x00000001 +#define NWD_SHARE_WRITE 0x00000002 +#define NWD_SHARE_DELETE 0x00000004 +#define NWD_SHARE_VALID 0x00000007 + +/* + Creates a new file. The create API will fail if the specified + file already exists. +*/ +#define NWD_DISP_CREATE_NEW 0x00000001 + +/* + Creates a new file. If the specified file already exists, + the create API will overwrite the old file and clear the + existing attributes. +*/ +#define NWD_DISP_CREATE_ALWAYS 0x00000002 + +/* + Opens the file. The API will fail if the file does not exist. +*/ +#define NWD_DISP_OPEN_EXISTING 0x00000003 + +/* + Opens the file. If the file does not exist, the API will + create the file. +*/ +#define NWD_DISP_OPEN_ALWAYS 0x00000004 + +/* + Opens the file. When the file is opened the API will truncate + the stream to zero bytes. The API will fail if the file + does not exist. +*/ +#define NWD_DISP_TRUNCATE_EXISTING 0x00000005 +#define NWD_DISP_MAXIMUM 0x00000005 + +/* + Open/Create returned information values + + The bottom two bytes of NWD_ACTION are returned + as a value. All values are mutually exclusive. +*/ + +#define NWD_ACTION_OPENED 0x00000001 +#define NWD_ACTION_CREATED 0x00000002 + +#define MAX_IO_SIZE (1024 * 32) + +#define MAX_XATTR_NAME_LEN 255 +#define MAX_PATH_LENGTH 255 +#define ENOATTR ENODATA +/*===[ Type definitions ]=================================================*/ + +/*===[ Function prototypes ]==============================================*/ + +#pragma pack(push, 1) + +/*struct _ncl_string +{ + unsigned int type; + unsigned char *buffer; + unsigned int len; + +} NclString, *PNclString; +*/ +struct ncl_string { + unsigned int type; + unsigned char *buffer; + u32 len; +}; + +struct nwd_string { + unsigned int type; + unsigned int len; + unsigned int boffset; +}; + +struct novfs_command_request_header { + unsigned int CommandType; + unsigned long SequenceNumber; + struct novfs_schandle SessionId; + +}; + +struct novfs_command_reply_header { + unsigned long Sequence_Number; + unsigned int ErrorCode; + +}; + + +struct novfs_delete_file_request { + struct novfs_command_request_header Command; + unsigned int isDirectory; + unsigned int pathlength; + unsigned char path[1]; +}; + +struct novfs_delete_file_reply { + struct novfs_command_reply_header Reply; +}; + +struct novfs_get_connected_server_list { + struct novfs_command_request_header Command; +}; + +struct novfs_get_connected_server_list_reply { + struct novfs_command_reply_header Reply; + unsigned char List[1]; +}; + +struct novfs_get_connected_server_list_request_ex { + struct novfs_command_request_header Command; +}; + +struct novfs_get_connected_server_list_reply_ex { + + struct novfs_command_reply_header Reply; + unsigned int bufferLen; + unsigned char List[1]; + +}; + +struct novfs_get_server_volume_list { + struct novfs_command_request_header Command; + unsigned int Length; + unsigned char Name[1]; +}; + +struct novfs_get_server_volume_list_reply { + struct novfs_command_reply_header Reply; + unsigned char List[1]; +}; + +struct novfs_verify_file_request { + struct novfs_command_request_header Command; + unsigned int pathLen; + unsigned char path[1]; + +}; + +struct novfs_verify_file_reply { + struct novfs_command_reply_header Reply; + unsigned int lastAccessTime; + unsigned int modifyTime; + unsigned int createTime; + unsigned long long fileSize; + unsigned int fileMode; + +}; + +struct novfs_begin_enumerate_directory_request { + struct novfs_command_request_header Command; + unsigned int pathLen; + unsigned char path[1]; + +}; + +struct novfs_begin_enumerate_directory_reply { + struct novfs_command_reply_header Reply; + void *enumerateHandle; + +}; + +struct novfs_end_enumerate_directory_request { + struct novfs_command_request_header Command; + void *enumerateHandle; + +}; + +struct novfs_end_enumerate_directory_reply { + struct novfs_command_reply_header Reply; + +}; + +struct novfs_enumerate_directory_request { + struct novfs_command_request_header Command; + void *enumerateHandle; + unsigned int pathLen; + unsigned char path[1]; + +}; + +struct novfs_enumerate_directory_reply { + struct novfs_command_reply_header Reply; + void *enumerateHandle; + unsigned int lastAccessTime; + unsigned int modifyTime; + unsigned int createTime; + unsigned long long size; + unsigned int mode; + unsigned int nameLen; + unsigned char name[1]; + +}; + +struct novfs_enumerate_directory_ex_request { + struct novfs_command_request_header Command; + void *enumerateHandle; + unsigned int pathLen; + unsigned char path[1]; + +}; + +struct novfs_enumerate_directory_ex_data { + unsigned int length; + unsigned int lastAccessTime; + unsigned int modifyTime; + unsigned int createTime; + unsigned long long size; + unsigned int mode; + unsigned int nameLen; + unsigned char name[1]; + +}; + +struct novfs_enumerate_directory_ex_reply { + struct novfs_command_reply_header Reply; + void *enumerateHandle; + unsigned int enumCount; + +}; + +struct novfs_open_file_request { + struct novfs_command_request_header Command; + unsigned int access; /* File Access */ + unsigned int mode; /* Sharing Mode */ + unsigned int disp; /* Create Disposition */ + unsigned int pathLen; + unsigned char path[1]; + +}; + +struct novfs_open_file_reply { + struct novfs_command_reply_header Reply; + void *handle; + unsigned int lastAccessTime; + unsigned int modifyTime; + unsigned int createTime; + unsigned int attributes; + loff_t size; + +}; + +struct novfs_create_file_request { + + struct novfs_command_request_header Command; + unsigned int pathlength; + unsigned char path[1]; + +}; + +struct novfs_create_file_reply { + struct novfs_command_reply_header Reply; + +}; + +struct novfs_close_file_request { + struct novfs_command_request_header Command; + void *handle; + +}; + +struct novfs_close_file_reply { + struct novfs_command_reply_header Reply; + +}; + +struct novfs_read_file_request { + struct novfs_command_request_header Command; + void *handle; + loff_t offset; + size_t len; + +}; + +struct novfs_read_file_reply { + struct novfs_command_reply_header Reply; + unsigned long long bytesRead; + unsigned char data[1]; + +}; + +struct novfs_write_file_request { + struct novfs_command_request_header Command; + void *handle; + loff_t offset; + size_t len; + unsigned char data[1]; + +}; + +struct novfs_write_file_reply { + struct novfs_command_reply_header Reply; + unsigned long long bytesWritten; +}; + +struct novfs_read_stream_request { + struct novfs_command_request_header Command; + void *connection; + unsigned char handle[6]; + loff_t offset; + size_t len; +}; + +struct novfs_read_stream_reply { + struct novfs_command_reply_header Reply; + size_t bytesRead; + unsigned char data[1]; +}; + +struct novfs_write_stream_request { + struct novfs_command_request_header Command; + void *connection; + unsigned char handle[6]; + loff_t offset; + size_t len; + unsigned char data[1]; +}; + +struct novfs_write_stream_reply { + struct novfs_command_reply_header Reply; + size_t bytesWritten; +}; + +struct novfs_close_stream_request { + struct novfs_command_request_header Command; + void *connection; + unsigned char handle[6]; +}; + +struct novfs_close_stream_reply { + struct novfs_command_reply_header Reply; + +}; + +struct novfs_login_user_request { + struct novfs_command_request_header Command; + unsigned int srvNameType; + unsigned int serverLength; + unsigned int serverOffset; + unsigned int usrNameType; + unsigned int userNameLength; + unsigned int userNameOffset; + unsigned int pwdNameType; + unsigned int passwordLength; + unsigned int passwordOffset; + +}; + +struct novfs_login_user_reply { + struct novfs_command_reply_header Reply; + unsigned int connectionHandle; + void *loginIdentity; + +}; + +struct novfs_logout_request { + struct novfs_command_request_header Command; + unsigned int length; + unsigned char Name[1]; + +}; + +struct novfs_logout_reply { + struct novfs_command_reply_header Reply; + +}; + +struct novfs_create_context_request { + struct novfs_command_request_header Command; + +}; + +struct novfs_create_context_reply { + struct novfs_command_reply_header Reply; + struct novfs_schandle SessionId; + +}; + +struct novfs_destroy_context_request { + struct novfs_command_request_header Command; + +}; + +struct novfs_destroy_context_reply { + struct novfs_command_reply_header Reply; + +}; + +/* + * Attribute flags. These should be or-ed together to figure out what + * has been changed! + */ +#ifndef ATTR_MODE +#define ATTR_MODE 1 +#define ATTR_UID 2 +#define ATTR_GID 4 +#define ATTR_SIZE 8 +#define ATTR_ATIME 16 +#define ATTR_MTIME 32 +#define ATTR_CTIME 64 +#define ATTR_ATIME_SET 128 +#define ATTR_MTIME_SET 256 +#define ATTR_FORCE 512 /* Not a change, but a change it */ +#define ATTR_ATTR_FLAG 1024 +#endif + +struct novfs_lnx_file_info { + unsigned int ia_valid; + unsigned int ia_mode; + uid_t ia_uid; + gid_t ia_gid; + loff_t ia_size; + time_t ia_atime; + time_t ia_mtime; + time_t ia_ctime; + unsigned int ia_attr_flags; +}; + +struct novfs_set_file_info_request { + struct novfs_command_request_header Command; + struct novfs_lnx_file_info fileInfo; + unsigned int pathlength; + char path[1]; +}; + +struct novfs_set_file_info_reply { + struct novfs_command_reply_header Reply; + +}; + +struct novfs_truncate_file_request { + struct novfs_command_request_header Command; + unsigned int pathLen; + char path[1]; + +}; + +struct novfs_truncate_file_reply { + struct novfs_command_reply_header Reply; + +}; + +struct novfs_getpwuid_request { + struct novfs_command_request_header Command; + unsigned int uid; +}; + +struct novfs_getpwuid_reply { + struct novfs_command_reply_header Reply; + unsigned char UserName[1]; +}; + +struct novfs_get_version_request { + struct novfs_command_request_header Command; +}; + +struct novfs_get_version_reply { + struct novfs_command_reply_header Reply; + unsigned char Version[1]; +}; + +struct novfs_set_mount_path { + struct novfs_command_request_header Command; + unsigned int PathLength; + unsigned char Path[1]; +}; + +struct novfs_set_mount_path_reply { + struct novfs_command_reply_header Reply; +}; + +struct novfs_get_user_space { + struct novfs_command_request_header Command; +}; + +struct novfs_get_user_space_reply { + struct novfs_command_reply_header Reply; + uint64_t TotalSpace; + uint64_t FreeSpace; + uint64_t TotalEnties; + uint64_t FreeEnties; +}; + +struct novfs_xplat_call_request { + struct novfs_command_request_header Command; + unsigned int NwcCommand; + unsigned long dataLen; + unsigned char data[1]; + +}; + +struct novfs_xplat_call_reply { + struct novfs_command_reply_header Reply; + unsigned long dataLen; + unsigned char data[1]; + +}; + +/* XPlat NWC structures used by the daemon */ + +struct nwd_open_conn_by_name { + void *ConnHandle; + unsigned int nameLen; + unsigned int oName; /* Ofset to the Name */ + unsigned int serviceLen; + unsigned int oServiceType; /* Offset to service Type; */ + unsigned int uConnFlags; + unsigned int uTranType; + void *newConnHandle; + +}; + +struct nwd_tran_addr { + unsigned int uTransportType; + unsigned int uAddressLength; + unsigned int oAddress; + +}; + +struct nwd_open_conn_by_addr { + void *ConnHandle; + unsigned int oServiceType; + unsigned int uConnFlags; + struct nwd_tran_addr TranAddr; + +}; + +struct nwd_close_conn { + void *ConnHandle; + +}; + +struct nwd_ncp_req { + void *ConnHandle; + unsigned int replyLen; + unsigned int requestLen; + unsigned int function; +/* unsigned int subFunction; */ +/* unsigned int verb; */ + unsigned int flags; + unsigned char data[1]; + +}; + +struct nwd_ncp_rep { + unsigned int replyLen; + unsigned char data[1]; + +}; + +struct nwc_auth_wid { + void *ConnHandle; + u32 AuthenticationId; + +}; + +struct nwc_unauthenticate { + void *ConnHandle; + unsigned int AuthenticationId; + +}; + +struct nwc_lisc_id { + void *ConnHandle; + +}; + +struct nwc_unlic_conn { + void *ConnHandle; + +}; + +struct nwd_get_id_info { + u32 AuthenticationId; + unsigned int AuthType; + unsigned int NameType; + unsigned short int ObjectType; + unsigned int IdentityFlags; + unsigned int domainLen; + unsigned int pDomainNameOffset; + unsigned int objectLen; + unsigned int pObjectNameOffset; + +}; + +struct nwc_lo_id { + u32 AuthenticationId; + +}; + +struct novfs_rename_file_request { + struct novfs_command_request_header Command; + int directoryFlag; + unsigned int newnameLen; + unsigned char newname[256]; + unsigned int oldnameLen; + unsigned char oldname[256]; +}; + +struct novfs_rename_file_reply { + struct novfs_command_reply_header Reply; + +}; + +struct nwd_server_version { + unsigned int uMajorVersion; + unsigned short int uMinorVersion; + unsigned short int uRevision; +}; + + +#define MAX_ADDRESS_LENGTH 32 + +struct tagNwdTranAddrEx { + unsigned int uTransportType; + unsigned int uAddressLength; + unsigned char Buffer[MAX_ADDRESS_LENGTH]; + +}; + +struct __NWD_CONN_INFO { + unsigned int uInfoVersion; + unsigned int uAuthenticationState; + unsigned int uBroadcastState; + u32 uConnectionReference; + unsigned int pTreeNameOffset; +/* unsigned int pWorkGroupIdOffset; Not used */ + unsigned int uSecurityState; + unsigned int uConnectionNumber; + unsigned int uUserId; + unsigned int pServerNameOffset; + unsigned int uNdsState; + unsigned int uMaxPacketSize; + unsigned int uLicenseState; + unsigned int uPublicState; + unsigned int bcastState; + unsigned int pServiceTypeOffset; + unsigned int uDistance; + u32 uAuthId; + unsigned int uDisconnected; + struct nwd_server_version ServerVersion; + struct nwd_tran_addr TranAddress; +}; + +struct nwd_conn_info { + void *ConnHandle; + unsigned int uInfoLevel; + unsigned int uInfoLength; +}; + +struct nwd_open_conn_by_ref { + void *uConnReference; + unsigned int uConnFlags; + void *ConnHandle; + +}; + +struct nwd_get_reqversion { + unsigned int uMajorVersion; + unsigned int uMinorVersion; + unsigned int uRevision; + +}; + +struct nwd_scan_conn_info { + unsigned int uScanIndex; + unsigned int uScanInfoLevel; + unsigned int uScanInfoLen; + unsigned int uScanConnInfoOffset; + unsigned int uScanFlags; + unsigned int uReturnInfoLevel; + unsigned int uReturnInfoLength; + unsigned int uConnectionReference; + unsigned int uReturnConnInfoOffset; + +}; + +struct nwd_get_pref_ds_tree { + unsigned int uTreeLength; + unsigned int DsTreeNameOffset; + +}; + +struct nwd_set_pref_ds_tree { + unsigned int uTreeLength; + unsigned int DsTreeNameOffset; + +}; + +struct nwd_set_def_name_ctx { + unsigned int uTreeLength; + unsigned int TreeOffset; + unsigned int uNameLength; + unsigned int NameContextOffset; + +}; + +struct nwd_get_def_name_ctx { + unsigned int uTreeLength; + unsigned int TreeOffset; + unsigned int uNameLength; + unsigned int NameContextOffset; + +}; + +struct nwd_get_tree_monitored_conn_ref { + struct nwd_string TreeName; + void *uConnReference; + +}; + +struct nwd_enum_ids { + unsigned int Iterator; + unsigned int domainNameLen; + unsigned int domainNameOffset; + unsigned int AuthType; + unsigned int objectNameLen; + unsigned int objectNameOffset; + unsigned int NameType; + unsigned short int ObjectType; + unsigned int IdentityFlags; + u32 AuthenticationId; + +}; + +struct nwd_change_key { + unsigned int domainNameOffset; + unsigned int domainNameLen; + unsigned int AuthType; + unsigned int objectNameOffset; + unsigned int objectNameLen; + unsigned int NameType; + unsigned short int ObjectType; + unsigned int verifyPasswordOffset; + unsigned int verifyPasswordLen; + unsigned int newPasswordOffset; + unsigned int newPasswordLen; + +}; + +struct nwd_set_primary_conn { + void *ConnHandle; + +}; + +struct nwd_get_bcast_notification { + unsigned int uMessageFlags; + void *uConnReference; + unsigned int messageLen; + char message[1]; + +}; + +struct nwd_set_conn_info { + void *ConnHandle; + unsigned int uInfoLevel; + unsigned int uInfoLength; + unsigned int offsetConnInfo; + +}; + +struct novfs_debug_request { + struct novfs_command_request_header Command; + int cmdlen; + char dbgcmd[1]; + +}; + +struct novfs_debug_reply { + struct novfs_command_reply_header Reply; + +}; + +struct nwd_set_key { + void *ConnHandle; + unsigned int AuthenticationId; + unsigned int objectNameLen; + unsigned int objectNameOffset; + unsigned short int ObjectType; + unsigned int newPasswordLen; + unsigned int newPasswordOffset; + +}; + +struct nwd_verify_key { + unsigned int AuthType; + unsigned int NameType; + unsigned short int ObjectType; + unsigned int domainNameLen; + unsigned int domainNameOffset; + unsigned int objectNameLen; + unsigned int objectNameOffset; + unsigned int verifyPasswordLen; + unsigned int verifyPasswordOffset; + +}; + +struct novfs_get_cache_flag { + struct novfs_command_request_header Command; + int pathLen; + unsigned char path[0]; + +}; + +struct novfs_get_cache_flag_reply { + struct novfs_command_reply_header Reply; + int CacheFlag; + +}; + +struct novfs_xa_list_reply { + struct novfs_command_reply_header Reply; + unsigned char *pData; + +}; + +struct novfs_xa_get_request { + struct novfs_command_request_header Command; + unsigned int pathLen; + unsigned int nameLen; + unsigned char data[1]; //hold path, attribute name + +}; + +struct novfs_xa_get_reply { + struct novfs_command_reply_header Reply; + unsigned char *pData; + +}; + +struct novfs_xa_set_request { + struct novfs_command_request_header Command; + unsigned int TtlWriteDataSize; + unsigned int WritePosition; + int flags; + unsigned int pathLen; + unsigned int nameLen; + unsigned int valueLen; + unsigned char data[1]; //hold path, attribute name, value data + +}; + +struct novfs_xa_set_reply { + struct novfs_command_reply_header Reply; + unsigned char *pData; + +}; + +struct novfs_set_file_lock_request { + struct novfs_command_request_header Command; + void *handle; + unsigned char fl_type; + loff_t fl_start; + loff_t fl_len; + +}; + +struct novfs_set_file_lock_reply { + struct novfs_command_reply_header Reply; + +}; + + +struct novfs_scope_list{ + struct list_head ScopeList; + struct novfs_schandle ScopeId; + struct novfs_schandle SessionId; + pid_t ScopePid; + struct task_struct *ScopeTask; + unsigned int ScopeHash; + uid_t ScopeUid; + uint64_t ScopeUSize; + uint64_t ScopeUFree; + uint64_t ScopeUTEnties; + uint64_t ScopeUAEnties; + int ScopeUserNameLength; + unsigned char ScopeUserName[32]; +}; + +#pragma pack(pop) + +#endif /* __NOVFS_COMMANDS_H */ --- /dev/null +++ b/fs/novfs/daemon.c @@ -0,0 +1,2085 @@ +/* + * Novell NCP Redirector for Linux + * Author: James Turner + * + * This file contains all the functions necessary for sending commands to our + * daemon module. + * + * Copyright (C) 2005 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vfs.h" +#include "nwcapi.h" +#include "commands.h" +#include "nwerror.h" + +#define QUEUE_SENDING 0 +#define QUEUE_WAITING 1 +#define QUEUE_TIMEOUT 2 +#define QUEUE_ACKED 3 +#define QUEUE_DONE 4 + +#define TIMEOUT_VALUE 10 + +#define DH_TYPE_UNDEFINED 0 +#define DH_TYPE_STREAM 1 +#define DH_TYPE_CONNECTION 2 + +struct daemon_queue { + struct list_head list; /* Must be first entry */ + spinlock_t lock; /* Used to control access to list */ + struct semaphore semaphore; /* Used to signal when data is available */ +}; + +struct daemon_cmd { + struct list_head list; /* Must be first entry */ + atomic_t reference; + unsigned int status; + unsigned int flags; + struct semaphore semaphore; + unsigned long sequence; + struct timer_list timer; + void *request; + unsigned long reqlen; + void *data; + int datalen; + void *reply; + unsigned long replen; +}; + +struct daemon_handle { + struct list_head list; + rwlock_t lock; + struct novfs_schandle session; +}; + +struct daemon_resource { + struct list_head list; + int type; + void *connection; + unsigned char handle[6]; + mode_t mode; + loff_t size; +}; + +struct drive_map { + struct list_head list; /* Must be first item */ + struct novfs_schandle session; + unsigned long hash; + int namelen; + char name[1]; +}; + +static void Queue_get(struct daemon_cmd * Que); +static void Queue_put(struct daemon_cmd * Que); +static void RemoveDriveMaps(void); +static int NwdConvertLocalHandle(struct novfs_xplat *pdata, struct daemon_handle * DHandle); +static int NwdConvertNetwareHandle(struct novfs_xplat *pdata, struct daemon_handle * DHandle); +static int set_map_drive(struct novfs_xplat *pdata, struct novfs_schandle Session); +static int unmap_drive(struct novfs_xplat *pdata, struct novfs_schandle Session); +static int NwdGetMountPath(struct novfs_xplat *pdata); +static long local_unlink(const char *pathname); + + +/*===[ Global variables ]=================================================*/ +static struct daemon_queue Daemon_Queue; + +static DECLARE_WAIT_QUEUE_HEAD(Read_waitqueue); + +static atomic_t Sequence = ATOMIC_INIT(-1); +static atomic_t Daemon_Open_Count = ATOMIC_INIT(0); + +static unsigned long Daemon_Command_Timeout = TIMEOUT_VALUE; + +static DECLARE_MUTEX(DriveMapLock); +static LIST_HEAD(DriveMapList); + +int novfs_max_iosize = PAGE_SIZE; + +void novfs_daemon_queue_init() +{ + INIT_LIST_HEAD(&Daemon_Queue.list); + spin_lock_init(&Daemon_Queue.lock); + init_MUTEX_LOCKED(&Daemon_Queue.semaphore); +} + +void novfs_daemon_queue_exit(void) +{ + /* Does nothing for now but we maybe should clear the queue. */ +} + +/*++======================================================================*/ +static void novfs_daemon_timer(unsigned long data) +{ + struct daemon_cmd *que = (struct daemon_cmd *) data; + + if (QUEUE_ACKED != que->status) { + que->status = QUEUE_TIMEOUT; + } + up(&que->semaphore); +} + +/*++======================================================================*/ +int Queue_Daemon_Command(void *request, + unsigned long reqlen, + void *data, + int dlen, + void **reply, unsigned long * replen, int interruptible) +{ + struct daemon_cmd *que; + int retCode = 0; + uint64_t ts1, ts2; + + ts1 = get_nanosecond_time(); + + DbgPrint("0x%p %d", request, reqlen); + + if (atomic_read(&Daemon_Open_Count)) { + + que = kmalloc(sizeof(*que), GFP_KERNEL); + + DbgPrint("que=0x%p", que); + if (que) { + atomic_set(&que->reference, 0); + que->status = QUEUE_SENDING; + que->flags = 0; + + init_MUTEX_LOCKED(&que->semaphore); + + que->sequence = atomic_inc_return(&Sequence); + + ((struct novfs_command_request_header *) request)->SequenceNumber = + que->sequence; + + /* + * Setup and start que timer + */ + init_timer(&que->timer); + que->timer.expires = jiffies + (HZ * Daemon_Command_Timeout); + que->timer.data = (unsigned long) que; + que->timer.function = novfs_daemon_timer; + add_timer(&que->timer); + + /* + * Setup request + */ + que->request = request; + que->reqlen = reqlen; + que->data = data; + que->datalen = dlen; + que->reply = NULL; + que->replen = 0; + + /* + * Added entry to queue. + */ + /* + * Check to see if interruptible and set flags. + */ + if (interruptible) { + que->flags |= INTERRUPTIBLE; + } + + Queue_get(que); + + spin_lock(&Daemon_Queue.lock); + list_add_tail(&que->list, &Daemon_Queue.list); + spin_unlock(&Daemon_Queue.lock); + + /* + * Signal that there is data to be read + */ + up(&Daemon_Queue.semaphore); + + /* + * Give a change to the other processes. + */ + yield(); + + /* + * Block waiting for reply or timeout + */ + down(&que->semaphore); + + if (QUEUE_ACKED == que->status) { + que->status = QUEUE_WAITING; + mod_timer(&que->timer, + jiffies + + (HZ * 2 * Daemon_Command_Timeout)); + if (interruptible) { + retCode = + down_interruptible(&que->semaphore); + } else { + down(&que->semaphore); + } + } + + /* + * Delete timer + */ + del_timer(&que->timer); + + /* + * Check for timeout + */ + if ((QUEUE_TIMEOUT == que->status) + && (NULL == que->reply)) { + DbgPrint("Timeout"); + retCode = -ETIME; + } + *reply = que->reply; + *replen = que->replen; + + /* + * Remove item from queue + */ + Queue_put(que); + + } else { /* Error case with no memory */ + + retCode = -ENOMEM; + *reply = NULL; + *replen = 0; + } + } else { + retCode = -EIO; + *reply = NULL; + *replen = 0; + + } + ts2 = get_nanosecond_time(); + ts2 = ts2 - ts1; + + DbgPrint("%llu retCode=%d", ts2, retCode); + return (retCode); +} + +static void Queue_get(struct daemon_cmd * Que) +{ + DbgPrint("que=0x%p %d", Que, atomic_read(&Que->reference)); + atomic_inc(&Que->reference); +} + +static void Queue_put(struct daemon_cmd * Que) +{ + + DbgPrint("que=0x%p %d", Que, atomic_read(&Que->reference)); + spin_lock(&Daemon_Queue.lock); + + if (atomic_dec_and_test(&Que->reference)) { + /* + * Remove item from queue + */ + list_del(&Que->list); + spin_unlock(&Daemon_Queue.lock); + + /* + * Free item memory + */ + kfree(Que); + } else { + spin_unlock(&Daemon_Queue.lock); + } +} + +struct daemon_cmd *get_next_queue(int Set_Queue_Waiting) +{ + struct daemon_cmd *que; + + DbgPrint("que=0x%p", Daemon_Queue.list.next); + + spin_lock(&Daemon_Queue.lock); + que = (struct daemon_cmd *) Daemon_Queue.list.next; + + while (que && (que != (struct daemon_cmd *) & Daemon_Queue.list.next) + && (que->status != QUEUE_SENDING)) { + que = (struct daemon_cmd *) que->list.next; + } + + if ((NULL == que) || (que == (struct daemon_cmd *) & Daemon_Queue.list) + || (que->status != QUEUE_SENDING)) { + que = NULL; + } else if (Set_Queue_Waiting) { + que->status = QUEUE_WAITING; + } + + if (que) { + atomic_inc(&que->reference); + } + + spin_unlock(&Daemon_Queue.lock); + + DbgPrint("return=0x%p", que); + return (que); +} + +static struct daemon_cmd *find_queue(unsigned long sequence) +{ + struct daemon_cmd *que; + + DbgPrint("0x%x", sequence); + + spin_lock(&Daemon_Queue.lock); + que = (struct daemon_cmd *) Daemon_Queue.list.next; + + while (que && (que != (struct daemon_cmd *) & Daemon_Queue.list.next) + && (que->sequence != sequence)) { + que = (struct daemon_cmd *) que->list.next; + } + + if ((NULL == que) + || (que == (struct daemon_cmd *) & Daemon_Queue.list.next) + || (que->sequence != sequence)) { + que = NULL; + } + + if (que) { + atomic_inc(&que->reference); + } + + spin_unlock(&Daemon_Queue.lock); + + DbgPrint("return 0x%p", que); + return (que); +} + +int novfs_daemon_open_control(struct inode *Inode, struct file *File) +{ + DbgPrint("pid=%d Count=%d", current->pid, + atomic_read(&Daemon_Open_Count)); + atomic_inc(&Daemon_Open_Count); + + return (0); +} + +int novfs_daemon_close_control(struct inode *Inode, struct file *File) +{ + struct daemon_cmd *que; + + DbgPrint("pid=%d Count=%d", current->pid, + atomic_read(&Daemon_Open_Count)); + + if (atomic_dec_and_test(&Daemon_Open_Count)) { + /* + * Signal any pending que itmes. + */ + + spin_lock(&Daemon_Queue.lock); + que = (struct daemon_cmd *) Daemon_Queue.list.next; + + while (que + && (que != (struct daemon_cmd *) & Daemon_Queue.list.next) + && (que->status != QUEUE_DONE)) { + que->status = QUEUE_TIMEOUT; + up(&que->semaphore); + + que = (struct daemon_cmd *) que->list.next; + } + spin_unlock(&Daemon_Queue.lock); + + RemoveDriveMaps(); + + novfs_scope_cleanup(); + } + + return (0); +} + +ssize_t novfs_daemon_cmd_send(struct file * file, char *buf, size_t len, loff_t * off) +{ + struct daemon_cmd *que; + size_t retValue = 0; + int Finished = 0; + struct novfs_data_list *dlist; + int i, dcnt, bcnt, ccnt, error; + char *vadr; + unsigned long cpylen; + + DbgPrint("%u %lld", len, *off); + if (len > novfs_max_iosize) { + novfs_max_iosize = len; + } + + while (!Finished) { + que = get_next_queue(1); + DbgPrint("0x%p", que); + if (que) { + retValue = que->reqlen; + if (retValue > len) { + retValue = len; + } + if (retValue > 0x80) + novfs_dump(0x80, que->request); + else + novfs_dump(retValue, que->request); + + cpylen = copy_to_user(buf, que->request, retValue); + if (que->datalen && (retValue < len)) { + buf += retValue; + dlist = que->data; + dcnt = que->datalen; + for (i = 0; i < dcnt; i++, dlist++) { + if (DLREAD == dlist->rwflag) { + bcnt = dlist->len; + DbgPrint("page=0x%p " + "offset=0x%p len=%d", + i, dlist->page, + dlist->offset, dlist->len); + if ((bcnt + retValue) <= len) { + void *km_adr = NULL; + + if (dlist->page) { + km_adr = + kmap(dlist-> + page); + vadr = km_adr; + vadr += + (unsigned long) + dlist-> + offset; + } else { + vadr = + dlist-> + offset; + } + + ccnt = + copy_to_user(buf, + vadr, + bcnt); + + DbgPrint("Copy %d from 0x%p to 0x%p.", + bcnt, vadr, buf); + if (bcnt > 0x80) + novfs_dump(0x80, + vadr); + else + novfs_dump(bcnt, + vadr); + + if (km_adr) { + kunmap(dlist-> + page); + } + + retValue += bcnt; + buf += bcnt; + } else { + break; + } + } + } + } + Queue_put(que); + break; + } + + if (O_NONBLOCK & file->f_flags) { + retValue = -EAGAIN; + break; + } else { + if ((error = + down_interruptible(&Daemon_Queue.semaphore))) { + DbgPrint("after down_interruptible error...%d", + error); + retValue = -EINTR; + break; + } + DbgPrint("after down_interruptible"); + } + } + + *off = *off; + + DbgPrint("return 0x%x", retValue); + + return (retValue); +} + +ssize_t novfs_daemon_recv_reply(struct file *file, const char *buf, size_t nbytes, loff_t * ppos) +{ + struct daemon_cmd *que; + size_t retValue = 0; + void *reply; + unsigned long sequence, cpylen; + + struct novfs_data_list *dlist; + char *vadr; + int i; + + DbgPrint("buf=0x%p nbytes=%d ppos=%llx", buf, + nbytes, *ppos); + + /* + * Get sequence number from reply buffer + */ + + cpylen = copy_from_user(&sequence, buf, sizeof(sequence)); + + /* + * Find item based on sequence number + */ + que = find_queue(sequence); + + DbgPrint("0x%x 0x%p %d", sequence, que, nbytes); + if (que) { + do { + retValue = nbytes; + /* + * Ack packet from novfsd. Remove timer and + * return + */ + if (nbytes == sizeof(sequence)) { + que->status = QUEUE_ACKED; + break; + } + + if (NULL != (dlist = que->data)) { + int thiscopy, left = nbytes; + retValue = 0; + + DbgPrint("dlist=0x%p count=%d", + dlist, que->datalen); + for (i = 0; + (i < que->datalen) && (retValue < nbytes); + i++, dlist++) { + __DbgPrint("\n" + " dlist[%d].page: 0x%p\n" + " dlist[%d].offset: 0x%p\n" + " dlist[%d].len: 0x%x\n" + " dlist[%d].rwflag: 0x%x\n", + i, dlist->page, i, + dlist->offset, i, dlist->len, + i, dlist->rwflag); + + if (DLWRITE == dlist->rwflag) { + void *km_adr = NULL; + + if (dlist->page) { + km_adr = + kmap(dlist->page); + vadr = km_adr; + vadr += + (unsigned long) dlist-> + offset; + } else { + vadr = dlist->offset; + } + + thiscopy = dlist->len; + if (thiscopy > left) { + thiscopy = left; + dlist->len = left; + } + cpylen = + copy_from_user(vadr, buf, + thiscopy); + + if (thiscopy > 0x80) + novfs_dump(0x80, vadr); + else + novfs_dump(thiscopy, vadr); + + if (km_adr) { + kunmap(dlist->page); + } + + left -= thiscopy; + retValue += thiscopy; + buf += thiscopy; + } + } + que->replen = retValue; + } else { + reply = kmalloc(nbytes, GFP_KERNEL); + DbgPrint("reply=0x%p", reply); + if (reply) { + retValue = nbytes; + que->reply = reply; + que->replen = nbytes; + + retValue -= + copy_from_user(reply, buf, + retValue); + if (retValue > 0x80) + novfs_dump(0x80, reply); + else + novfs_dump(retValue, reply); + + } else { + retValue = -ENOMEM; + } + } + + /* + * Set status that packet is done. + */ + que->status = QUEUE_DONE; + + } while (0); + up(&que->semaphore); + Queue_put(que); + } + + DbgPrint("return 0x%x", retValue); + + return (retValue); +} + +int novfs_do_login(struct ncl_string *Server, struct ncl_string *Username, +struct ncl_string *Password, void **lgnId, struct novfs_schandle *Session) +{ + struct novfs_login_user_request *cmd; + struct novfs_login_user_reply *reply; + unsigned long replylen = 0; + int retCode, cmdlen, datalen; + unsigned char *data; + + datalen = Server->len + Username->len + Password->len; + cmdlen = sizeof(*cmd) + datalen; + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + data = (unsigned char *) cmd + sizeof(*cmd); + cmd->Command.CommandType = VFS_COMMAND_LOGIN_USER; + cmd->Command.SequenceNumber = 0; + memcpy(&cmd->Command.SessionId, Session, sizeof(*Session)); + + cmd->srvNameType = Server->type; + cmd->serverLength = Server->len; + cmd->serverOffset = (unsigned long) (data - (unsigned char *) cmd); + memcpy(data, Server->buffer, Server->len); + data += Server->len; + + cmd->usrNameType = Username->type; + cmd->userNameLength = Username->len; + cmd->userNameOffset = (unsigned long) (data - (unsigned char *) cmd); + memcpy(data, Username->buffer, Username->len); + data += Username->len; + + cmd->pwdNameType = Password->type; + cmd->passwordLength = Password->len; + cmd->passwordOffset = (unsigned long) (data - (unsigned char *) cmd); + memcpy(data, Password->buffer, Password->len); + data += Password->len; + + retCode = Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { + if (reply->Reply.ErrorCode) { + retCode = reply->Reply.ErrorCode; + } else { + retCode = 0; + if (lgnId) { + *lgnId = reply->loginIdentity; + } + } + kfree(reply); + } + memset(cmd, 0, cmdlen); + kfree(cmd); + return (retCode); + +} + +int novfs_daemon_logout(struct qstr *Server, struct novfs_schandle *Session) +{ + struct novfs_logout_request *cmd; + struct novfs_logout_reply *reply; + unsigned long replylen = 0; + int retCode, cmdlen; + + cmdlen = offsetof(struct novfs_logout_request, Name) + Server->len; + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_LOGOUT_USER; + cmd->Command.SequenceNumber = 0; + memcpy(&cmd->Command.SessionId, Session, sizeof(*Session)); + cmd->length = Server->len; + memcpy(cmd->Name, Server->name, Server->len); + + retCode = + Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, &replylen, INTERRUPTIBLE); + if (reply) { + if (reply->Reply.ErrorCode) { + retCode = -EIO; + } + kfree(reply); + } + kfree(cmd); + return (retCode); + +} + +int novfs_daemon_getpwuid(uid_t uid, int unamelen, char *uname) +{ + struct novfs_getpwuid_request cmd; + struct novfs_getpwuid_reply *reply; + unsigned long replylen = 0; + int retCode; + + cmd.Command.CommandType = VFS_COMMAND_GETPWUD; + cmd.Command.SequenceNumber = 0; + SC_INITIALIZE(cmd.Command.SessionId); + cmd.uid = uid; + + retCode = + Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { + if (reply->Reply.ErrorCode) { + retCode = -EIO; + } else { + retCode = 0; + memset(uname, 0, unamelen); + replylen = + replylen - offsetof(struct + novfs_getpwuid_reply, UserName); + if (replylen) { + if (replylen > unamelen) { + retCode = -EINVAL; + replylen = unamelen - 1; + } + memcpy(uname, reply->UserName, replylen); + } + } + kfree(reply); + } + return (retCode); + +} + +int novfs_daemon_getversion(char *Buf, int length) +{ + struct novfs_get_version_request cmd; + struct novfs_get_version_reply *reply; + unsigned long replylen = 0; + int retVal = 0; + + cmd.Command.CommandType = VFS_COMMAND_GET_VERSION; + cmd.Command.SequenceNumber = 0; + SC_INITIALIZE(cmd.Command.SessionId); + + Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { + if (reply->Reply.ErrorCode) { + retVal = -EIO; + } else { + retVal = + replylen - offsetof(struct + novfs_get_version_reply, Version); + if (retVal < length) { + memcpy(Buf, reply->Version, retVal); + Buf[retVal] = '\0'; + } + } + kfree(reply); + } + return (retVal); + +} + +static int daemon_login(struct novfs_login *Login, struct novfs_schandle *Session) +{ + int retCode = -ENOMEM; + struct novfs_login lLogin; + struct ncl_string server; + struct ncl_string username; + struct ncl_string password; + + if (!copy_from_user(&lLogin, Login, sizeof(lLogin))) { + server.buffer = kmalloc(lLogin.Server.length, GFP_KERNEL); + if (server.buffer) { + server.len = lLogin.Server.length; + server.type = NWC_STRING_TYPE_ASCII; + if (!copy_from_user((void *)server.buffer, lLogin.Server.data, server.len)) { + username.buffer = kmalloc(lLogin.UserName.length, GFP_KERNEL); + if (username.buffer) { + username.len = lLogin.UserName.length; + username.type = NWC_STRING_TYPE_ASCII; + if (!copy_from_user((void *)username.buffer, lLogin.UserName.data, username.len)) { + password.buffer = kmalloc(lLogin.Password.length, GFP_KERNEL); + if (password.buffer) + { + password.len = lLogin.Password.length; + password.type = NWC_STRING_TYPE_ASCII; + if (!copy_from_user((void *)password.buffer, lLogin.Password.data, password.len)) { + retCode = novfs_do_login (&server, &username, &password, NULL, Session); + if (!retCode) { + char *username; + username = novfs_scope_get_username(); + if (username) { + novfs_add_to_root(username); + } + } + } + kfree(password.buffer); + } + } + kfree(username.buffer); + } + } + kfree(server.buffer); + } + } + + return (retCode); +} + +static int daemon_logout(struct novfs_logout *Logout, struct novfs_schandle *Session) +{ + struct novfs_logout lLogout; + struct qstr server; + int retCode = 0; + + if (copy_from_user(&lLogout, Logout, sizeof(lLogout))) + return -EFAULT; + server.name = kmalloc(lLogout.Server.length, GFP_KERNEL); + if (!server.name) + return -ENOMEM; + server.len = lLogout.Server.length; + if (copy_from_user((void *)server.name, lLogout.Server.data, server.len)) + goto exit; + retCode = novfs_daemon_logout(&server, Session); +exit: + kfree(server.name); + return (retCode); +} + +int novfs_daemon_create_sessionId(struct novfs_schandle * SessionId) +{ + struct novfs_create_context_request cmd; + struct novfs_create_context_reply *reply; + unsigned long replylen = 0; + int retCode = 0; + + DbgPrint("%d", current->pid); + + cmd.Command.CommandType = VFS_COMMAND_CREATE_CONTEXT; + cmd.Command.SequenceNumber = 0; + SC_INITIALIZE(cmd.Command.SessionId); + + retCode = + Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { + if (!reply->Reply.ErrorCode + && replylen > sizeof(struct novfs_command_reply_header)) { + *SessionId = reply->SessionId; + retCode = 0; + } else { + SessionId->hTypeId = 0; + SessionId->hId = 0; + retCode = -EIO; + } + kfree(reply); + } + DbgPrint("SessionId=0x%llx", *SessionId); + return (retCode); +} + +int novfs_daemon_destroy_sessionId(struct novfs_schandle SessionId) +{ + struct novfs_destroy_context_request cmd; + struct novfs_destroy_context_reply *reply; + unsigned long replylen = 0; + int retCode = 0; + + DbgPrint("0x%p:%p", SessionId.hTypeId, + SessionId.hId); + + cmd.Command.CommandType = VFS_COMMAND_DESTROY_CONTEXT; + cmd.Command.SequenceNumber = 0; + cmd.Command.SessionId = SessionId; + + retCode = + Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { + if (!reply->Reply.ErrorCode) { + struct drive_map *dm; + struct list_head *list; + + retCode = 0; + + /* + * When destroying the session check to see if there are any + * mapped drives. If there are then remove them. + */ + down(&DriveMapLock); + list_for_each(list, &DriveMapList) { + dm = list_entry(list, struct drive_map, list); + if (SC_EQUAL(SessionId, dm->session)) { + local_unlink(dm->name); + list = list->prev; + list_del(&dm->list); + kfree(dm); + } + + } + up(&DriveMapLock); + + } else { + retCode = -EIO; + } + kfree(reply); + } + return (retCode); +} + +int novfs_daemon_get_userspace(struct novfs_schandle SessionId, uint64_t * TotalSize, + uint64_t * Free, uint64_t * TotalEnties, + uint64_t * FreeEnties) +{ + struct novfs_get_user_space cmd; + struct novfs_get_user_space_reply *reply; + unsigned long replylen = 0; + int retCode = 0; + + DbgPrint("0x%p:%p", SessionId.hTypeId, + SessionId.hId); + + cmd.Command.CommandType = VFS_COMMAND_GET_USER_SPACE; + cmd.Command.SequenceNumber = 0; + cmd.Command.SessionId = SessionId; + + retCode = + Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { + if (!reply->Reply.ErrorCode) { + + __DbgPrint("TotalSpace: %llu\n", reply->TotalSpace); + __DbgPrint("FreeSpace: %llu\n", reply->FreeSpace); + __DbgPrint("TotalEnties: %llu\n", reply->TotalEnties); + __DbgPrint("FreeEnties: %llu\n", reply->FreeEnties); + + if (TotalSize) + *TotalSize = reply->TotalSpace; + if (Free) + *Free = reply->FreeSpace; + if (TotalEnties) + *TotalEnties = reply->TotalEnties; + if (FreeEnties) + *FreeEnties = reply->FreeEnties; + retCode = 0; + } else { + retCode = -EIO; + } + kfree(reply); + } + return (retCode); +} + +int novfs_daemon_set_mnt_point(char *Path) +{ + struct novfs_set_mount_path *cmd; + struct novfs_set_mount_path_reply *reply; + unsigned long replylen, cmdlen; + int retCode = -ENOMEM; + + DbgPrint("%s", Path); + + replylen = strlen(Path); + + cmdlen = sizeof(struct novfs_set_mount_path) + replylen; + + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + cmd->Command.CommandType = VFS_COMMAND_SET_MOUNT_PATH; + cmd->Command.SequenceNumber = 0; + SC_INITIALIZE(cmd->Command.SessionId); + cmd->PathLength = replylen; + + strcpy(cmd->Path, Path); + + replylen = 0; + + retCode = + Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { + if (!reply->Reply.ErrorCode) { + retCode = 0; + } else { + retCode = -EIO; + } + kfree(reply); + } + kfree(cmd); + return retCode; +} + +int novfs_daemon_debug_cmd_send(char *Command) +{ + struct novfs_debug_request cmd; + struct novfs_debug_reply *reply; + struct novfs_debug_reply lreply; + unsigned long replylen, cmdlen; + struct novfs_data_list dlist[2]; + + int retCode = -ENOMEM; + + DbgPrint("%s", Command); + + dlist[0].page = NULL; + dlist[0].offset = (char *)Command; + dlist[0].len = strlen(Command); + dlist[0].rwflag = DLREAD; + + dlist[1].page = NULL; + dlist[1].offset = (char *)&lreply; + dlist[1].len = sizeof(lreply); + dlist[1].rwflag = DLWRITE; + + cmdlen = offsetof(struct novfs_debug_request, dbgcmd); + + cmd.Command.CommandType = VFS_COMMAND_DBG; + cmd.Command.SequenceNumber = 0; + SC_INITIALIZE(cmd.Command.SessionId); + cmd.cmdlen = strlen(Command); + + replylen = 0; + + retCode = + Queue_Daemon_Command(&cmd, cmdlen, dlist, 2, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { + kfree(reply); + } + if (0 == retCode) { + retCode = lreply.Reply.ErrorCode; + } + + return (retCode); +} + +int novfs_daemon_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int retCode = -ENOSYS; + unsigned long cpylen; + struct novfs_schandle session_id; + session_id = novfs_scope_get_sessionId(NULL); + + switch (cmd) { + case IOC_LOGIN: + retCode = daemon_login((struct novfs_login *) arg, &session_id); + break; + + case IOC_LOGOUT: + retCode = daemon_logout((struct novfs_logout *)arg, &session_id); + break; + case IOC_DEBUGPRINT: + { + struct Ioctl_Debug { + int length; + char *data; + } io; + char *buf; + io.length = 0; + cpylen = copy_from_user(&io, (char *)arg, sizeof(io)); + if (io.length) { + buf = kmalloc(io.length + 1, GFP_KERNEL); + if (buf) { + buf[0] = 0; + cpylen = + copy_from_user(buf, io.data, + io.length); + buf[io.length] = '\0'; + DbgPrint("%s", buf); + kfree(buf); + retCode = 0; + } + } + break; + } + + case IOC_XPLAT: + { + struct novfs_xplat data; + + cpylen = + copy_from_user(&data, (void *)arg, sizeof(data)); + retCode = ((data.xfunction & 0x0000FFFF) | 0xCC000000); + + switch (data.xfunction) { + case NWC_GET_MOUNT_PATH: + DbgPrint("Call NwdGetMountPath"); + retCode = NwdGetMountPath(&data); + break; + } + + DbgPrint("[NOVFS XPLAT] status Code = %X\n", retCode); + break; + } + + } + return (retCode); +} + +static int daemon_added_resource(struct daemon_handle * DHandle, int Type, void *CHandle, + unsigned char * FHandle, unsigned long Mode, u_long Size) +{ + struct daemon_resource *resource; + + if (FHandle) + DbgPrint("DHandle=0x%p Type=%d CHandle=0x%p FHandle=0x%x " + "Mode=0x%x Size=%d", DHandle, Type, CHandle, + *(u32 *) & FHandle[2], Mode, Size); + else + DbgPrint("DHandle=0x%p Type=%d CHandle=0x%p\n", + DHandle, Type, CHandle); + + resource = kmalloc(sizeof(struct daemon_resource), GFP_KERNEL); + if (!resource) + return -ENOMEM; + + resource->type = Type; + resource->connection = CHandle; + if (FHandle) + memcpy(resource->handle, FHandle, + sizeof(resource->handle)); + else + memset(resource->handle, 0, sizeof(resource->handle)); + resource->mode = Mode; + resource->size = Size; + write_lock(&DHandle->lock); + list_add(&resource->list, &DHandle->list); + write_unlock(&DHandle->lock); + DbgPrint("Adding resource=0x%p", resource); + return 0; +} + +static int daemon_remove_resource(struct daemon_handle * DHandle, int Type, void *CHandle, + unsigned long FHandle) +{ + struct daemon_resource *resource; + struct list_head *l; + int retVal = -ENOMEM; + + DbgPrint("DHandle=0x%p Type=%d CHandle=0x%p FHandle=0x%x", + DHandle, Type, CHandle, FHandle); + + write_lock(&DHandle->lock); + + list_for_each(l, &DHandle->list) { + resource = list_entry(l, struct daemon_resource, list); + + if ((Type == resource->type) && + (resource->connection == CHandle)) { + DbgPrint("Found resource=0x%p", resource); + l = l->prev; + list_del(&resource->list); + kfree(resource); + break; + } + } + + write_unlock(&DHandle->lock); + + return (retVal); +} + +int novfs_daemon_lib_open(struct inode *inode, struct file *file) +{ + struct daemon_handle *dh; + + DbgPrint("inode=0x%p file=0x%p", inode, file); + dh = kmalloc(sizeof(struct daemon_handle), GFP_KERNEL); + if (!dh) + return -ENOMEM; + file->private_data = dh; + INIT_LIST_HEAD(&dh->list); + rwlock_init(&dh->lock); + dh->session = novfs_scope_get_sessionId(NULL); + return 0; +} + +int novfs_daemon_lib_close(struct inode *inode, struct file *file) +{ + struct daemon_handle *dh; + struct daemon_resource *resource; + struct list_head *l; + + char commanddata[sizeof(struct novfs_xplat_call_request) + sizeof(struct nwd_close_conn)]; + struct novfs_xplat_call_request *cmd; + struct xplat_call_reply *reply; + struct nwd_close_conn *nwdClose; + unsigned long cmdlen, replylen; + + DbgPrint("inode=0x%p file=0x%p", inode, file); + if (file->private_data) { + dh = (struct daemon_handle *) file->private_data; + + list_for_each(l, &dh->list) { + resource = list_entry(l, struct daemon_resource, list); + + if (DH_TYPE_STREAM == resource->type) { + novfs_close_stream(resource->connection, + resource->handle, + dh->session); + } else if (DH_TYPE_CONNECTION == resource->type) { + cmd = (struct novfs_xplat_call_request *) commanddata; + cmdlen = + offsetof(struct novfs_xplat_call_request, + data) + sizeof(struct nwd_close_conn); + cmd->Command.CommandType = + VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = dh->session; + cmd->NwcCommand = NWC_CLOSE_CONN; + + cmd->dataLen = sizeof(struct nwd_close_conn); + nwdClose = (struct nwd_close_conn *) cmd->data; + nwdClose->ConnHandle = + (void *) resource->connection; + + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, + 0, (void **)&reply, + &replylen, 0); + if (reply) + kfree(reply); + } + l = l->prev; + list_del(&resource->list); + kfree(resource); + } + kfree(dh); + file->private_data = NULL; + } + + return (0); +} + +ssize_t novfs_daemon_lib_read(struct file * file, char *buf, size_t len, + loff_t * off) +{ + struct daemon_handle *dh; + struct daemon_resource *resource; + + size_t thisread, totalread = 0; + loff_t offset = *off; + + DbgPrint("file=0x%p len=%d off=%lld", file, len, *off); + + if (file->private_data) { + dh = file->private_data; + read_lock(&dh->lock); + if (&dh->list != dh->list.next) { + resource = + list_entry(dh->list.next, struct daemon_resource, list); + + if (DH_TYPE_STREAM == resource->type) { + while (len > 0 && (offset < resource->size)) { + thisread = len; + if (novfs_read_stream + (resource->connection, + resource->handle, buf, &thisread, + &offset, 1, dh->session) + || !thisread) { + break; + } + len -= thisread; + buf += thisread; + offset += thisread; + totalread += thisread; + } + } + } + read_unlock(&dh->lock); + } + *off = offset; + DbgPrint("return = 0x%x", totalread); + return (totalread); +} + +ssize_t novfs_daemon_lib_write(struct file * file, const char *buf, size_t len, + loff_t * off) +{ + struct daemon_handle *dh; + struct daemon_resource *resource; + + size_t thiswrite, totalwrite = -EINVAL; + loff_t offset = *off; + int status; + + DbgPrint("file=0x%p len=%d off=%lld", file, len, *off); + + if (file->private_data) { + dh = file->private_data; + write_lock(&dh->lock); + if (&dh->list != dh->list.next) { + resource = + list_entry(dh->list.next, struct daemon_resource, list); + + if ((DH_TYPE_STREAM == resource->type) && (len >= 0)) { + totalwrite = 0; + do { + thiswrite = len; + status = + novfs_write_stream(resource-> + connection, + resource->handle, + (void *)buf, + &thiswrite, + &offset, + dh->session); + if (status || !thiswrite) { + /* + * If len is zero then the file will have just been + * truncated to offset. Update size. + */ + if (!status && !len) { + resource->size = offset; + } + totalwrite = status; + break; + } + len -= thiswrite; + buf += thiswrite; + offset += thiswrite; + totalwrite += thiswrite; + if (offset > resource->size) { + resource->size = offset; + } + } while (len > 0); + } + } + write_unlock(&dh->lock); + } + *off = offset; + DbgPrint("return = 0x%x", totalwrite); + + return (totalwrite); +} + +loff_t novfs_daemon_lib_llseek(struct file * file, loff_t offset, int origin) +{ + struct daemon_handle *dh; + struct daemon_resource *resource; + + loff_t retVal = -EINVAL; + + DbgPrint("file=0x%p offset=%lld origin=%d", file, offset, origin); + + if (file->private_data) { + dh = file->private_data; + read_lock(&dh->lock); + if (&dh->list != dh->list.next) { + resource = + list_entry(dh->list.next, struct daemon_resource, list); + + if (DH_TYPE_STREAM == resource->type) { + switch (origin) { + case 2: + offset += resource->size; + break; + case 1: + offset += file->f_pos; + } + if (offset >= 0) { + if (offset != file->f_pos) { + file->f_pos = offset; + file->f_version = 0; + } + retVal = offset; + } + } + } + read_unlock(&dh->lock); + } + + DbgPrint("ret %lld", retVal); + + return retVal; +} + +#define DbgIocCall(str) __DbgPrint("[VFS XPLAT] Call " str "\n") + +int novfs_daemon_lib_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int retCode = -ENOSYS; + struct daemon_handle *dh; + void *handle = NULL; + unsigned long cpylen; + + dh = file->private_data; + + DbgPrint("file=0x%p 0x%x 0x%p dh=0x%p", file, cmd, arg, dh); + + if (dh) { + + switch (cmd) { + case IOC_LOGIN: + retCode = daemon_login((struct novfs_login *)arg, &dh->session); + break; + + case IOC_LOGOUT: + retCode = daemon_logout((struct novfs_logout *)arg, &dh->session); + break; + + case IOC_DEBUGPRINT: + { + struct Ioctl_Debug { + int length; + char *data; + } io; + char *buf; + io.length = 0; + cpylen = + copy_from_user(&io, (void *)arg, + sizeof(io)); + if (io.length) { + buf = + kmalloc(io.length + 1, + GFP_KERNEL); + if (buf) { + buf[0] = 0; + cpylen = + copy_from_user(buf, io.data, + io.length); + buf[io.length] = '\0'; + __DbgPrint("%s", buf); + kfree(buf); + retCode = 0; + } + } + break; + } + + case IOC_XPLAT: + { + struct novfs_xplat data; + + cpylen = + copy_from_user(&data, (void *)arg, + sizeof(data)); + retCode = + ((data. + xfunction & 0x0000FFFF) | 0xCC000000); + + switch (data.xfunction) { + case NWC_OPEN_CONN_BY_NAME: + DbgIocCall("NwOpenConnByName"); + retCode = + novfs_open_conn_by_name(&data, + &handle, dh->session); + if (!retCode) + daemon_added_resource(dh, + DH_TYPE_CONNECTION,handle, 0, 0, 0); + break; + + case NWC_OPEN_CONN_BY_ADDRESS: + DbgIocCall("NwOpenConnByAddress"); + retCode = + novfs_open_conn_by_addr(&data, &handle, + dh->session); + if (!retCode) + daemon_added_resource(dh, + DH_TYPE_CONNECTION, + handle, 0, + 0, 0); + break; + + case NWC_OPEN_CONN_BY_REFERENCE: + + DbgIocCall("NwOpenConnByReference"); + retCode = + novfs_open_conn_by_ref(&data, &handle, + dh->session); + if (!retCode) + daemon_added_resource(dh, + DH_TYPE_CONNECTION, + handle, 0, + 0, 0); + break; + + case NWC_SYS_CLOSE_CONN: + DbgIocCall("NwSysCloseConn"); + retCode = + novfs_sys_conn_close(&data, (unsigned long *)&handle, dh->session); + daemon_remove_resource(dh, DH_TYPE_CONNECTION, handle, 0); + break; + + case NWC_CLOSE_CONN: + DbgIocCall("NwCloseConn"); + retCode = + novfs_conn_close(&data, &handle, + dh->session); + daemon_remove_resource(dh, + DH_TYPE_CONNECTION, + handle, 0); + break; + + case NWC_LOGIN_IDENTITY: + DbgIocCall("" + "NwLoginIdentity"); + retCode = + novfs_login_id(&data, dh->session); + break; + + case NWC_RAW_NCP_REQUEST: + DbgIocCall("[VFS XPLAT] Send Raw " + "NCP Request"); + retCode = novfs_raw_send(&data, dh->session); + break; + + case NWC_AUTHENTICATE_CONN_WITH_ID: + DbgIocCall("[VFS XPLAT] Authenticate " + "Conn With ID"); + retCode = + novfs_auth_conn(&data, + dh->session); + break; + + case NWC_UNAUTHENTICATE_CONN: + DbgIocCall("[VFS XPLAT] UnAuthenticate " + "Conn With ID"); + retCode = + novfs_unauthenticate(&data, + dh->session); + break; + + case NWC_LICENSE_CONN: + DbgIocCall("Call NwLicenseConn"); + retCode = + novfs_license_conn(&data, dh->session); + break; + + case NWC_LOGOUT_IDENTITY: + DbgIocCall("NwLogoutIdentity"); + retCode = + novfs_logout_id(&data, + dh->session); + break; + + case NWC_UNLICENSE_CONN: + DbgIocCall("NwUnlicense"); + retCode = + novfs_unlicense_conn(&data, dh->session); + break; + + case NWC_GET_CONN_INFO: + DbgIocCall("NwGetConnInfo"); + retCode = + novfs_get_conn_info(&data, dh->session); + break; + + case NWC_SET_CONN_INFO: + DbgIocCall("NwGetConnInfo"); + retCode = + novfs_set_conn_info(&data, dh->session); + break; + + case NWC_SCAN_CONN_INFO: + DbgIocCall("NwScanConnInfo"); + retCode = + novfs_scan_conn_info(&data, dh->session); + break; + + case NWC_GET_IDENTITY_INFO: + DbgIocCall("NwGetIdentityInfo"); + retCode = + novfs_get_id_info(&data, + dh->session); + break; + + case NWC_GET_REQUESTER_VERSION: + DbgIocCall("NwGetDaemonVersion"); + retCode = + novfs_get_daemon_ver(&data, + dh->session); + break; + + case NWC_GET_PREFERRED_DS_TREE: + DbgIocCall("NwcGetPreferredDsTree"); + retCode = + novfs_get_preferred_DS_tree(&data, + dh->session); + break; + + case NWC_SET_PREFERRED_DS_TREE: + DbgIocCall("NwcSetPreferredDsTree"); + retCode = + novfs_set_preferred_DS_tree(&data, + dh->session); + break; + + case NWC_GET_DEFAULT_NAME_CONTEXT: + DbgIocCall("NwcGetDefaultNameContext"); + retCode = + novfs_get_default_ctx(&data, + dh->session); + break; + + case NWC_SET_DEFAULT_NAME_CONTEXT: + DbgIocCall("NwcSetDefaultNameContext"); + retCode = + novfs_set_default_ctx(&data, + dh->session); + break; + + case NWC_QUERY_FEATURE: + DbgIocCall("NwQueryFeature"); + retCode = + novfs_query_feature(&data, dh->session); + break; + + case NWC_GET_TREE_MONITORED_CONN_REF: + DbgIocCall("NwcGetTreeMonitoredConn"); + retCode = + novfs_get_tree_monitored_conn(&data, + dh-> + session); + break; + + case NWC_ENUMERATE_IDENTITIES: + DbgIocCall("NwcEnumerateIdentities"); + retCode = + novfs_enum_ids(&data, + dh->session); + break; + + case NWC_CHANGE_KEY: + DbgIocCall("NwcChangeAuthKey"); + retCode = + novfs_change_auth_key(&data, + dh->session); + break; + + case NWC_CONVERT_LOCAL_HANDLE: + DbgIocCall("NwdConvertLocalHandle"); + retCode = + NwdConvertLocalHandle(&data, dh); + break; + + case NWC_CONVERT_NETWARE_HANDLE: + DbgIocCall("NwdConvertNetwareHandle"); + retCode = + NwdConvertNetwareHandle(&data, dh); + break; + + case NWC_SET_PRIMARY_CONN: + DbgIocCall("NwcSetPrimaryConn"); + retCode = + novfs_set_pri_conn(&data, + dh->session); + break; + + case NWC_GET_PRIMARY_CONN: + DbgIocCall("NwcGetPrimaryConn"); + retCode = + novfs_get_pri_conn(&data, + dh->session); + break; + + case NWC_MAP_DRIVE: + DbgIocCall("NwcMapDrive"); + retCode = + set_map_drive(&data, dh->session); + break; + + case NWC_UNMAP_DRIVE: + DbgIocCall("NwcUnMapDrive"); + retCode = + unmap_drive(&data, dh->session); + break; + + case NWC_ENUMERATE_DRIVES: + DbgIocCall("NwcEnumerateDrives"); + retCode = + novfs_enum_drives(&data, + dh->session); + break; + + case NWC_GET_MOUNT_PATH: + DbgIocCall("NwdGetMountPath"); + retCode = NwdGetMountPath(&data); + break; + + case NWC_GET_BROADCAST_MESSAGE: + DbgIocCall("NwdGetBroadcastMessage"); + retCode = + novfs_get_bcast_msg(&data, + dh->session); + break; + + case NWC_SET_KEY: + DbgIocCall("NwdSetKey"); + retCode = + novfs_set_key_value(&data, dh->session); + break; + + case NWC_VERIFY_KEY: + DbgIocCall("NwdVerifyKey"); + retCode = + novfs_verify_key_value(&data, + dh->session); + break; + + case NWC_RAW_NCP_REQUEST_ALL: + case NWC_NDS_RESOLVE_NAME_TO_ID: + case NWC_FRAGMENT_REQUEST: + case NWC_GET_CONFIGURED_NSPS: + default: + break; + + } + + DbgPrint("[NOVFS XPLAT] status Code = %X\n", + retCode); + break; + } + } + } + + return (retCode); +} + +unsigned int novfs_daemon_poll(struct file *file, + struct poll_table_struct *poll_table) +{ + struct daemon_cmd *que; + unsigned int mask = POLLOUT | POLLWRNORM; + + que = get_next_queue(0); + if (que) + mask |= (POLLIN | POLLRDNORM); + return mask; +} + +static int NwdConvertNetwareHandle(struct novfs_xplat *pdata, struct daemon_handle * DHandle) +{ + int retVal; + struct nwc_convert_netware_handle nh; + unsigned long cpylen; + + DbgPrint("DHandle=0x%p", DHandle); + + cpylen = + copy_from_user(&nh, pdata->reqData, + sizeof(struct nwc_convert_netware_handle)); + + retVal = + daemon_added_resource(DHandle, DH_TYPE_STREAM, + Uint32toHandle(nh.ConnHandle), + nh.NetWareHandle, nh.uAccessMode, + nh.uFileSize); + + return (retVal); +} + +static int NwdConvertLocalHandle(struct novfs_xplat *pdata, struct daemon_handle * DHandle) +{ + int retVal = NWE_REQUESTER_FAILURE; + struct daemon_resource *resource; + struct nwc_convert_local_handle lh; + struct list_head *l; + unsigned long cpylen; + + DbgPrint("DHandle=0x%p", DHandle); + + read_lock(&DHandle->lock); + + list_for_each(l, &DHandle->list) { + resource = list_entry(l, struct daemon_resource, list); + + if (DH_TYPE_STREAM == resource->type) { + lh.uConnReference = + HandletoUint32(resource->connection); + +//sgled memcpy(lh.NwWareHandle, resource->handle, sizeof(resource->handle)); + memcpy(lh.NetWareHandle, resource->handle, sizeof(resource->handle)); //sgled + if (pdata->repLen >= sizeof(struct nwc_convert_local_handle)) { + cpylen = + copy_to_user(pdata->repData, &lh, + sizeof(struct nwc_convert_local_handle)); + retVal = 0; + } else { + retVal = NWE_BUFFER_OVERFLOW; + } + break; + } + } + + read_unlock(&DHandle->lock); + + return (retVal); +} + +static int NwdGetMountPath(struct novfs_xplat *pdata) +{ + int retVal = NWE_REQUESTER_FAILURE; + int len; + unsigned long cpylen; + struct nwc_get_mount_path mp; + + cpylen = copy_from_user(&mp, pdata->reqData, pdata->reqLen); + + if (novfs_current_mnt) { + + len = strlen(novfs_current_mnt) + 1; + if ((len > mp.MountPathLen) && mp.pMountPath) { + retVal = NWE_BUFFER_OVERFLOW; + } else { + if (mp.pMountPath) { + cpylen = + copy_to_user(mp.pMountPath, + novfs_current_mnt, len); + } + retVal = 0; + } + + mp.MountPathLen = len; + + if (pdata->repData && (pdata->repLen >= sizeof(mp))) { + cpylen = copy_to_user(pdata->repData, &mp, sizeof(mp)); + } + } + + return (retVal); +} + +static int set_map_drive(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + int retVal; + unsigned long cpylen; + struct nwc_map_drive_ex symInfo; + char *path; + struct drive_map *drivemap, *dm; + struct list_head *list; + + retVal = novfs_set_map_drive(pdata, Session); + if (retVal) + return retVal; + if (copy_from_user(&symInfo, pdata->reqData, sizeof(symInfo))) + return -EFAULT; + drivemap = + kmalloc(sizeof(struct drive_map) + symInfo.linkOffsetLength, + GFP_KERNEL); + if (!drivemap) + return -ENOMEM; + + path = (char *)pdata->reqData; + path += symInfo.linkOffset; + cpylen = + copy_from_user(drivemap->name, path, + symInfo.linkOffsetLength); + + drivemap->session = Session; + drivemap->hash = + full_name_hash(drivemap->name, + symInfo.linkOffsetLength - 1); + drivemap->namelen = symInfo.linkOffsetLength - 1; + DbgPrint("hash=0x%lx path=%s", drivemap->hash, drivemap->name); + + dm = (struct drive_map *) & DriveMapList.next; + + down(&DriveMapLock); + + list_for_each(list, &DriveMapList) { + dm = list_entry(list, struct drive_map, list); + __DbgPrint("%s: dm=0x%p\n" + " hash: 0x%lx\n" + " namelen: %d\n" + " name: %s\n", __func__, + dm, dm->hash, dm->namelen, dm->name); + + if (drivemap->hash == dm->hash) { + if (0 == + strcmp(dm->name, drivemap->name)) { + dm = NULL; + break; + } + } else if (drivemap->hash < dm->hash) { + break; + } + } + + if (dm) { + if ((dm == (struct drive_map *) & DriveMapList) || + (dm->hash < drivemap->hash)) { + list_add(&drivemap->list, &dm->list); + } else { + list_add_tail(&drivemap->list, + &dm->list); + } + } + else + kfree(drivemap); + up(&DriveMapLock); + return (retVal); +} + +static int unmap_drive(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + int retVal = NWE_REQUESTER_FAILURE; + struct nwc_unmap_drive_ex symInfo; + char *path; + struct drive_map *dm; + struct list_head *list; + unsigned long hash; + + + retVal = novfs_unmap_drive(pdata, Session); + if (retVal) + return retVal; + if (copy_from_user(&symInfo, pdata->reqData, sizeof(symInfo))) + return -EFAULT; + + path = kmalloc(symInfo.linkLen, GFP_KERNEL); + if (!path) + return -ENOMEM; + if (copy_from_user(path,((struct nwc_unmap_drive_ex *) pdata->reqData)->linkData, symInfo.linkLen)) { + kfree(path); + return -EFAULT; + } + + hash = full_name_hash(path, symInfo.linkLen - 1); + DbgPrint("hash=0x%x path=%s", hash, path); + + dm = NULL; + + down(&DriveMapLock); + + list_for_each(list, &DriveMapList) { + dm = list_entry(list, struct drive_map, list); + __DbgPrint("%s: dm=0x%p %s\n" + " hash: 0x%x\n" + " namelen: %d\n", __func__, + dm, dm->name, dm->hash, dm->namelen); + + if (hash == dm->hash) { + if (0 == strcmp(dm->name, path)) { + break; + } + } else if (hash < dm->hash) { + dm = NULL; + break; + } + } + + if (dm) { + __DbgPrint("%s: Remove dm=0x%p %s\n" + " hash: 0x%x\n" + " namelen: %d\n", __func__, + dm, dm->name, dm->hash, dm->namelen); + list_del(&dm->list); + kfree(dm); + } + + up(&DriveMapLock); + return (retVal); +} + +static void RemoveDriveMaps(void) +{ + struct drive_map *dm; + struct list_head *list; + + down(&DriveMapLock); + list_for_each(list, &DriveMapList) { + dm = list_entry(list, struct drive_map, list); + + __DbgPrint("%s: dm=0x%p\n" + " hash: 0x%x\n" + " namelen: %d\n" + " name: %s\n", __func__, + dm, dm->hash, dm->namelen, dm->name); + local_unlink(dm->name); + list = list->prev; + list_del(&dm->list); + kfree(dm); + } + up(&DriveMapLock); +} + +/* As picked from do_unlinkat() */ + +static long local_unlink(const char *pathname) +{ + int error; + struct dentry *dentry; + char *name, *c; + struct nameidata nd; + struct inode *inode = NULL; + + error = path_lookup(pathname, LOOKUP_PARENT, &nd); + DbgPrint("path_lookup %s error: %d\n", pathname, error); + if (error) + return error; + + error = -EISDIR; + if (nd.last_type != LAST_NORM) + goto exit1; + mutex_lock(&nd.path.dentry->d_inode->i_mutex); + /* Get the filename of pathname */ + name=c=(char *)pathname; + while (*c!='\0') { + if (*c=='/') + name=++c; + c++; + } + dentry = lookup_one_len(name, nd.path.dentry, strlen(name)); + error = PTR_ERR(dentry); + DbgPrint("dentry %p", dentry); + if (!(dentry->d_inode->i_mode & S_IFLNK)) { + DbgPrint("%s not a link", name); + error=-ENOENT; + goto exit1; + } + + if (!IS_ERR(dentry)) { + /* Why not before? Because we want correct error value */ + if (nd.last.name[nd.last.len]) + goto slashes; + inode = dentry->d_inode; + if (inode) + atomic_inc(&inode->i_count); + error = mnt_want_write(nd.path.mnt); + DbgPrint("inode %p mnt_want_write error %d", inode, error); + if (error) + goto exit2; + error = vfs_unlink(nd.path.dentry->d_inode, dentry); + mnt_drop_write(nd.path.mnt); + exit2: + dput(dentry); + } + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + if (inode) + iput(inode); /* truncate the inode here */ +exit1: + path_put(&nd.path); + DbgPrint("returning error %d", error); + return error; + +slashes: + error = !dentry->d_inode ? -ENOENT : + S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR; + goto exit2; +} + --- /dev/null +++ b/fs/novfs/file.c @@ -0,0 +1,1921 @@ +/* + * Novell NCP Redirector for Linux + * Author: James Turner + * + * This file contains functions for accessing files through the daemon. + * + * Copyright (C) 2005 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vfs.h" +#include "commands.h" +#include "nwerror.h" + +static ssize_t novfs_tree_read(struct file * file, char *buf, size_t len, loff_t * off); +extern struct dentry_operations novfs_dentry_operations; + +static struct file_operations novfs_tree_operations = { + read:novfs_tree_read, +}; + +/* + * StripTrailingDots was added because some apps will + * try and create a file name with a trailing dot. NetWare + * doesn't like this and will return an error. + */ +static int StripTrailingDots = 1; + +int novfs_get_alltrees(struct dentry *parent) +{ + unsigned char *p; + struct novfs_command_reply_header * reply = NULL; + unsigned long replylen = 0; + struct novfs_command_request_header cmd; + int retCode; + struct dentry *entry; + struct qstr name; + struct inode *inode; + + cmd.CommandType = 0; + cmd.SequenceNumber = 0; +//sg ??? cmd.SessionId = 0x1234; + SC_INITIALIZE(cmd.SessionId); + + DbgPrint(""); + + retCode = Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, &replylen, INTERRUPTIBLE); + DbgPrint("reply=0x%p replylen=%d", reply, replylen); + if (reply) { + novfs_dump(replylen, reply); + if (!reply->ErrorCode + && (replylen > sizeof(struct novfs_command_reply_header))) { + p = (char *)reply + 8; + while (*p) { + DbgPrint("%s", p); + name.len = strlen(p); + name.name = p; + name.hash = full_name_hash(name.name, name.len); + entry = d_lookup(parent, &name); + if (NULL == entry) { + DbgPrint("adding %s", p); + entry = d_alloc(parent, &name); + if (entry) { + entry->d_op = &novfs_dentry_operations; + inode = novfs_get_inode(parent->d_sb, S_IFREG | 0400, 0, 0, 0, &name); + if (inode) { + inode->i_fop = &novfs_tree_operations; + d_add(entry, inode); + } + } + } + p += (name.len + 1); + } + } + kfree(reply); + } + return (retCode); +} + +static ssize_t novfs_tree_read(struct file * file, char *buf, size_t len, loff_t * off) +{ + if (file->f_pos != 0) { + return (0); + } + if (copy_to_user(buf, "Tree\n", 5)) { + return (0); + } + return (5); +} + +int novfs_get_servers(unsigned char ** ServerList, struct novfs_schandle SessionId) +{ + struct novfs_get_connected_server_list req; + struct novfs_get_connected_server_list_reply *reply = NULL; + unsigned long replylen = 0; + int retCode = 0; + + *ServerList = NULL; + + req.Command.CommandType = VFS_COMMAND_GET_CONNECTED_SERVER_LIST; + req.Command.SessionId = SessionId; + + retCode = + Queue_Daemon_Command(&req, sizeof(req), NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { + DbgPrint("reply"); + replylen -= sizeof(struct novfs_command_reply_header); + if (!reply->Reply.ErrorCode && replylen) { + memcpy(reply, reply->List, replylen); + *ServerList = (unsigned char *) reply; + retCode = 0; + } else { + kfree(reply); + retCode = -ENOENT; + } + } + return (retCode); +} + +int novfs_get_vols(struct qstr *Server, unsigned char ** VolumeList, + struct novfs_schandle SessionId) +{ + struct novfs_get_server_volume_list *req; + struct novfs_get_server_volume_list_reply *reply = NULL; + unsigned long replylen = 0, reqlen; + int retCode; + + *VolumeList = NULL; + reqlen = sizeof(struct novfs_get_server_volume_list) + Server->len; + req = kmalloc(reqlen, GFP_KERNEL); + if (!req) + return -ENOMEM; + req->Command.CommandType = VFS_COMMAND_GET_SERVER_VOLUME_LIST; + req->Length = Server->len; + memcpy(req->Name, Server->name, Server->len); + req->Command.SessionId = SessionId; + + retCode = + Queue_Daemon_Command(req, reqlen, NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { + DbgPrint("reply"); + novfs_dump(replylen, reply); + replylen -= sizeof(struct novfs_command_reply_header); + + if (!reply->Reply.ErrorCode && replylen) { + memcpy(reply, reply->List, replylen); + *VolumeList = (unsigned char *) reply; + retCode = 0; + } else { + kfree(reply); + retCode = -ENOENT; + } + } + kfree(req); + return (retCode); +} + +int novfs_get_file_info(unsigned char * Path, struct novfs_entry_info * Info, struct novfs_schandle SessionId) +{ + struct novfs_verify_file_reply *reply = NULL; + unsigned long replylen = 0; + struct novfs_verify_file_request * cmd; + int cmdlen; + int retCode = -ENOENT; + int pathlen; + + DbgPrint("Path = %s", Path); + + Info->mode = S_IFDIR | 0700; + Info->uid = current_uid(); + Info->gid = current_gid(); + Info->size = 0; + Info->atime = Info->mtime = Info->ctime = CURRENT_TIME; + + if (Path && *Path) { + pathlen = strlen(Path); + if (StripTrailingDots) { + if ('.' == Path[pathlen - 1]) + pathlen--; + } + cmdlen = offsetof(struct novfs_verify_file_request,path) + pathlen; + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_VERIFY_FILE; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = SessionId; + cmd->pathLen = pathlen; + memcpy(cmd->path, Path, cmd->pathLen); + + retCode = + Queue_Daemon_Command(cmd, cmdlen, NULL, 0, + (void *)&reply, &replylen, + INTERRUPTIBLE); + + if (reply) { + + if (reply->Reply.ErrorCode) { + retCode = -ENOENT; + } else { + Info->type = 3; + Info->mode = S_IRWXU; + + if (reply-> + fileMode & NW_ATTRIBUTE_DIRECTORY) { + Info->mode |= S_IFDIR; + } else { + Info->mode |= S_IFREG; + } + + if (reply-> + fileMode & NW_ATTRIBUTE_READ_ONLY) { + Info->mode &= ~(S_IWUSR); + } + + Info->uid = current_euid(); + Info->gid = current_egid(); + Info->size = reply->fileSize; + Info->atime.tv_sec = + reply->lastAccessTime; + Info->atime.tv_nsec = 0; + Info->mtime.tv_sec = reply->modifyTime; + Info->mtime.tv_nsec = 0; + Info->ctime.tv_sec = reply->createTime; + Info->ctime.tv_nsec = 0; + DbgPrint("replylen=%d sizeof(VERIFY_FILE_REPLY)=%d", + replylen, + sizeof(struct novfs_verify_file_reply)); + if (replylen > + sizeof(struct novfs_verify_file_reply)) { + unsigned int *lp = + &reply->fileMode; + lp++; + DbgPrint("extra data 0x%x", + *lp); + Info->mtime.tv_nsec = *lp; + } + retCode = 0; + } + + kfree(reply); + } + kfree(cmd); + } + } + + DbgPrint("return 0x%x", retCode); + return (retCode); +} + +int novfs_getx_file_info(char *Path, const char *Name, char *buffer, + ssize_t buffer_size, ssize_t * dataLen, + struct novfs_schandle SessionId) +{ + struct novfs_xa_get_reply *reply = NULL; + unsigned long replylen = 0; + struct novfs_xa_get_request *cmd; + int cmdlen; + int retCode = -ENOENT; + + int namelen = strlen(Name); + int pathlen = strlen(Path); + + DbgPrint("xattr: Path = %s, pathlen = %i, Name = %s, namelen = %i", + Path, pathlen, Name, namelen); + + if (namelen > MAX_XATTR_NAME_LEN) { + return ENOATTR; + } + + cmdlen = offsetof(struct novfs_xa_get_request, data) + pathlen + 1 + namelen + 1; // two '\0' + cmd = (struct novfs_xa_get_request *) kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_GET_EXTENDED_ATTRIBUTE; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = SessionId; + + cmd->pathLen = pathlen; + memcpy(cmd->data, Path, cmd->pathLen + 1); //+ '\0' + + cmd->nameLen = namelen; + memcpy(cmd->data + cmd->pathLen + 1, Name, cmd->nameLen + 1); + + DbgPrint("xattr: PXA_GET_REQUEST BEGIN"); + DbgPrint("xattr: Queue_Daemon_Command %d", + cmd->Command.CommandType); + DbgPrint("xattr: Command.SessionId = %d", + cmd->Command.SessionId); + DbgPrint("xattr: pathLen = %d", cmd->pathLen); + DbgPrint("xattr: Path = %s", cmd->data); + DbgPrint("xattr: nameLen = %d", cmd->nameLen); + DbgPrint("xattr: name = %s", (cmd->data + cmd->pathLen + 1)); + DbgPrint("xattr: PXA_GET_REQUEST END"); + + retCode = + Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + + if (reply) { + + if (reply->Reply.ErrorCode) { + DbgPrint("xattr: reply->Reply.ErrorCode=%d, %X", + reply->Reply.ErrorCode, + reply->Reply.ErrorCode); + DbgPrint("xattr: replylen=%d", replylen); + + //0xC9 = EA not found (C9), 0xD1 = EA access denied + if ((reply->Reply.ErrorCode == 0xC9) + || (reply->Reply.ErrorCode == 0xD1)) { + retCode = -ENOATTR; + } else { + retCode = -ENOENT; + } + } else { + + *dataLen = + replylen - sizeof(struct novfs_command_reply_header); + DbgPrint("xattr: replylen=%u, dataLen=%u", + replylen, *dataLen); + + if (buffer_size >= *dataLen) { + DbgPrint("xattr: copying to buffer from &reply->pData"); + memcpy(buffer, &reply->pData, *dataLen); + + retCode = 0; + } else { + DbgPrint("xattr: (!!!) buffer is smaller then reply"); + retCode = -ERANGE; + } + DbgPrint("xattr: /dumping buffer"); + novfs_dump(*dataLen, buffer); + DbgPrint("xattr: \\after dumping buffer"); + } + + kfree(reply); + } else { + DbgPrint("xattr: reply = NULL"); + } + kfree(cmd); + + } + + return retCode; +} + +int novfs_setx_file_info(char *Path, const char *Name, const void *Value, + unsigned long valueLen, unsigned long *bytesWritten, + int flags, struct novfs_schandle SessionId) +{ + struct novfs_xa_set_reply *reply = NULL; + unsigned long replylen = 0; + struct novfs_xa_set_request *cmd; + int cmdlen; + int retCode = -ENOENT; + + int namelen = strlen(Name); + int pathlen = strlen(Path); + + DbgPrint("xattr: Path = %s, pathlen = %i, Name = %s, namelen = %i, " + "value len = %u", Path, pathlen, Name, namelen, valueLen); + + if (namelen > MAX_XATTR_NAME_LEN) { + return ENOATTR; + } + + cmdlen = offsetof(struct novfs_xa_set_request, data) + pathlen + 1 + namelen + 1 + valueLen; + cmd = (struct novfs_xa_set_request *) kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_SET_EXTENDED_ATTRIBUTE; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = SessionId; + + cmd->flags = flags; + cmd->pathLen = pathlen; + memcpy(cmd->data, Path, cmd->pathLen); + + cmd->nameLen = namelen; + memcpy(cmd->data + cmd->pathLen + 1, Name, cmd->nameLen + 1); + + cmd->valueLen = valueLen; + memcpy(cmd->data + cmd->pathLen + 1 + cmd->nameLen + 1, Value, + valueLen); + + DbgPrint("xattr: PXA_SET_REQUEST BEGIN"); + DbgPrint("attr: Queue_Daemon_Command %d", + cmd->Command.CommandType); + DbgPrint("xattr: Command.SessionId = %d", + cmd->Command.SessionId); + DbgPrint("xattr: pathLen = %d", cmd->pathLen); + DbgPrint("xattr: Path = %s", cmd->data); + DbgPrint("xattr: nameLen = %d", cmd->nameLen); + DbgPrint("xattr: name = %s", (cmd->data + cmd->pathLen + 1)); + novfs_dump(valueLen < 16 ? valueLen : 16, (char *)Value); + + DbgPrint("xattr: PXA_SET_REQUEST END"); + + retCode = + Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + + if (reply) { + + if (reply->Reply.ErrorCode) { + DbgPrint("xattr: reply->Reply.ErrorCode=%d, %X", + reply->Reply.ErrorCode, + reply->Reply.ErrorCode); + DbgPrint("xattr: replylen=%d", replylen); + + retCode = -reply->Reply.ErrorCode; //-ENOENT; + } else { + + DbgPrint("xattr: replylen=%u, real len = %u", + replylen, + replylen - sizeof(struct novfs_command_reply_header)); + memcpy(bytesWritten, &reply->pData, + replylen - sizeof(struct novfs_command_reply_header)); + + retCode = 0; + } + + kfree(reply); + } else { + DbgPrint("xattr: reply = NULL"); + } + kfree(cmd); + + } + + return retCode; +} + +int novfs_listx_file_info(char *Path, char *buffer, ssize_t buffer_size, + ssize_t * dataLen, struct novfs_schandle SessionId) +{ + struct novfs_xa_list_reply *reply = NULL; + unsigned long replylen = 0; + struct novfs_verify_file_request *cmd; + int cmdlen; + int retCode = -ENOENT; + + int pathlen = strlen(Path); + DbgPrint("xattr: Path = %s, pathlen = %i", Path, pathlen); + + *dataLen = 0; + cmdlen = offsetof(struct novfs_verify_file_request, path) + pathlen; + cmd = (struct novfs_verify_file_request *) kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_LIST_EXTENDED_ATTRIBUTES; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = SessionId; + cmd->pathLen = pathlen; + memcpy(cmd->path, Path, cmd->pathLen + 1); //+ '\0' + DbgPrint("xattr: PVERIFY_FILE_REQUEST BEGIN"); + DbgPrint("xattr: Queue_Daemon_Command %d", + cmd->Command.CommandType); + DbgPrint("xattr: Command.SessionId = %d", + cmd->Command.SessionId); + DbgPrint("xattr: pathLen = %d", cmd->pathLen); + DbgPrint("xattr: Path = %s", cmd->path); + DbgPrint("xattr: PVERIFY_FILE_REQUEST END"); + + retCode = Queue_Daemon_Command(cmd, cmdlen, NULL, 0, + (void *)&reply, &replylen, + INTERRUPTIBLE); + + if (reply) { + + if (reply->Reply.ErrorCode) { + DbgPrint("xattr: reply->Reply.ErrorCode=%d, %X", + reply->Reply.ErrorCode, + reply->Reply.ErrorCode); + DbgPrint("xattr: replylen=%d", replylen); + + retCode = -ENOENT; + } else { + *dataLen = + replylen - sizeof(struct novfs_command_reply_header); + DbgPrint("xattr: replylen=%u, dataLen=%u", + replylen, *dataLen); + + if (buffer_size >= *dataLen) { + DbgPrint("xattr: copying to buffer " + "from &reply->pData"); + memcpy(buffer, &reply->pData, *dataLen); + } else { + DbgPrint("xattr: (!!!) buffer is " + "smaller then reply\n"); + retCode = -ERANGE; + } + DbgPrint("xattr: /dumping buffer"); + novfs_dump(*dataLen, buffer); + DbgPrint("xattr: \\after dumping buffer"); + + retCode = 0; + } + + kfree(reply); + } else { + DbgPrint("xattr: reply = NULL"); + } + kfree(cmd); + + } + + return retCode; +} + +static int begin_directory_enumerate(unsigned char * Path, int PathLen, void ** EnumHandle, + struct novfs_schandle SessionId) +{ + struct novfs_begin_enumerate_directory_request *cmd; + struct novfs_begin_enumerate_directory_reply *reply = NULL; + unsigned long replylen = 0; + int retCode, cmdlen; + + *EnumHandle = 0; + + cmdlen = offsetof(struct + novfs_begin_enumerate_directory_request, path) + PathLen; + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_START_ENUMERATE; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = SessionId; + + cmd->pathLen = PathLen; + memcpy(cmd->path, Path, PathLen); + + retCode = + Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); +/* + * retCode = Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, &replylen, 0); + */ + if (reply) { + if (reply->Reply.ErrorCode) { + retCode = -EIO; + } else { + *EnumHandle = reply->enumerateHandle; + retCode = 0; + } + kfree(reply); + } + kfree(cmd); + } else { + retCode = -ENOMEM; + } + return (retCode); +} + +int novfs_end_directory_enumerate(void *EnumHandle, struct novfs_schandle SessionId) +{ + struct novfs_end_enumerate_directory_request cmd; + struct novfs_end_enumerate_directory_reply *reply = NULL; + unsigned long replylen = 0; + int retCode; + + cmd.Command.CommandType = VFS_COMMAND_END_ENUMERATE; + cmd.Command.SequenceNumber = 0; + cmd.Command.SessionId = SessionId; + + cmd.enumerateHandle = EnumHandle; + + retCode = + Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, + &replylen, 0); + if (reply) { + retCode = 0; + if (reply->Reply.ErrorCode) { + retCode = -EIO; + } + kfree(reply); + } + + return (retCode); +} + +static int directory_enumerate_ex(void ** EnumHandle, struct novfs_schandle SessionId, int *Count, + struct novfs_entry_info **PInfo, int Interrupt) +{ + struct novfs_enumerate_directory_ex_request cmd; + struct novfs_enumerate_directory_ex_reply *reply = NULL; + unsigned long replylen = 0; + int retCode = 0; + struct novfs_entry_info * info; + struct novfs_enumerate_directory_ex_data *data; + int isize; + + if (PInfo) + *PInfo = NULL; + *Count = 0; + + cmd.Command.CommandType = VFS_COMMAND_ENUMERATE_DIRECTORY_EX; + cmd.Command.SequenceNumber = 0; + cmd.Command.SessionId = SessionId; + + cmd.enumerateHandle = *EnumHandle; + cmd.pathLen = 0; + cmd.path[0] = '\0'; + + retCode = + Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, + &replylen, Interrupt); + + if (reply) { + retCode = 0; + /* + * The VFS_COMMAND_ENUMERATE_DIRECTORY call can return an + * error but there could still be valid data. + */ + + if (!reply->Reply.ErrorCode || + ((replylen > sizeof(struct novfs_command_reply_header)) && + (reply->enumCount > 0))) { + DbgPrint("isize=%d", replylen); + data = + (struct novfs_enumerate_directory_ex_data *) ((char *)reply + + sizeof + (struct novfs_enumerate_directory_ex_reply)); + isize = + replylen - sizeof(struct novfs_enumerate_directory_ex_reply *) - + reply->enumCount * + offsetof(struct + novfs_enumerate_directory_ex_data, name); + isize += + (reply->enumCount * + offsetof(struct novfs_entry_info, name)); + + if (PInfo) { + *PInfo = info = kmalloc(isize, GFP_KERNEL); + if (*PInfo) { + DbgPrint("data=0x%p info=0x%p", + data, info); + *Count = reply->enumCount; + do { + DbgPrint("data=0x%p length=%d", + data); + + info->type = 3; + info->mode = S_IRWXU; + + if (data-> + mode & + NW_ATTRIBUTE_DIRECTORY) { + info->mode |= S_IFDIR; + info->mode |= S_IXUSR; + } else { + info->mode |= S_IFREG; + } + + if (data-> + mode & + NW_ATTRIBUTE_READ_ONLY) { + info->mode &= + ~(S_IWUSR); + } + + if (data-> + mode & NW_ATTRIBUTE_EXECUTE) + { + info->mode |= S_IXUSR; + } + + info->uid = current_euid(); + info->gid = current_egid(); + info->size = data->size; + info->atime.tv_sec = + data->lastAccessTime; + info->atime.tv_nsec = 0; + info->mtime.tv_sec = + data->modifyTime; + info->mtime.tv_nsec = 0; + info->ctime.tv_sec = + data->createTime; + info->ctime.tv_nsec = 0; + info->namelength = + data->nameLen; + memcpy(info->name, data->name, + data->nameLen); + data = + (struct novfs_enumerate_directory_ex_data *) + & data->name[data->nameLen]; + replylen = + (int)((char *)&info-> + name[info-> + namelength] - + (char *)info); + DbgPrint("info=0x%p", info); + novfs_dump(replylen, info); + + info = + (struct novfs_entry_info *) & info-> + name[info->namelength]; + + } while (--reply->enumCount); + } + } + + if (reply->Reply.ErrorCode) { + retCode = -1; /* Eof of data */ + } + *EnumHandle = reply->enumerateHandle; + } else { + retCode = -ENODATA; + } + kfree(reply); + } + + return (retCode); +} + +int novfs_get_dir_listex(unsigned char * Path, void ** EnumHandle, int *Count, + struct novfs_entry_info **Info, + struct novfs_schandle SessionId) +{ + int retCode = -ENOENT; + + if (Count) + *Count = 0; + if (Info) + *Info = NULL; + + if ((void *) - 1 == *EnumHandle) { + return (-ENODATA); + } + + if (0 == *EnumHandle) { + retCode = + begin_directory_enumerate(Path, strlen(Path), EnumHandle, + SessionId); + } + + if (*EnumHandle) { + retCode = + directory_enumerate_ex(EnumHandle, SessionId, Count, Info, + INTERRUPTIBLE); + if (retCode) { + novfs_end_directory_enumerate(*EnumHandle, SessionId); + retCode = 0; + *EnumHandle = Uint32toHandle(-1); + } + } + return (retCode); +} + +int novfs_open_file(unsigned char * Path, int Flags, struct novfs_entry_info * Info, + void ** Handle, + struct novfs_schandle SessionId) +{ + struct novfs_open_file_request *cmd; + struct novfs_open_file_reply *reply; + unsigned long replylen = 0; + int retCode, cmdlen, pathlen; + + pathlen = strlen(Path); + + if (StripTrailingDots) { + if ('.' == Path[pathlen - 1]) + pathlen--; + } + + *Handle = 0; + + cmdlen = offsetof(struct novfs_open_file_request, path) + pathlen; + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_OPEN_FILE; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = SessionId; + + cmd->access = 0; + + if (!(Flags & O_WRONLY) || (Flags & O_RDWR)) { + cmd->access |= NWD_ACCESS_READ; + } + + if ((Flags & O_WRONLY) || (Flags & O_RDWR)) { + cmd->access |= NWD_ACCESS_WRITE; + } + + switch (Flags & (O_CREAT | O_EXCL | O_TRUNC)) { + case O_CREAT: + cmd->disp = NWD_DISP_OPEN_ALWAYS; + break; + + case O_CREAT | O_EXCL: + cmd->disp = NWD_DISP_CREATE_NEW; + break; + + case O_TRUNC: + cmd->disp = NWD_DISP_CREATE_ALWAYS; + break; + + case O_CREAT | O_TRUNC: + cmd->disp = NWD_DISP_CREATE_ALWAYS; + break; + + case O_CREAT | O_EXCL | O_TRUNC: + cmd->disp = NWD_DISP_CREATE_NEW; + break; + + default: + cmd->disp = NWD_DISP_OPEN_EXISTING; + break; + } + + cmd->mode = NWD_SHARE_READ | NWD_SHARE_WRITE | NWD_SHARE_DELETE; + + cmd->pathLen = pathlen; + memcpy(cmd->path, Path, pathlen); + + retCode = + Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + + if (reply) { + if (reply->Reply.ErrorCode) { + if (NWE_OBJECT_EXISTS == reply->Reply.ErrorCode) { + retCode = -EEXIST; + } else if (NWE_ACCESS_DENIED == + reply->Reply.ErrorCode) { + retCode = -EACCES; + } else if (NWE_FILE_IN_USE == + reply->Reply.ErrorCode) { + retCode = -EBUSY; + } else { + retCode = -ENOENT; + } + } else { + *Handle = reply->handle; + retCode = 0; + } + kfree(reply); + } + kfree(cmd); + } else { + retCode = -ENOMEM; + } + return (retCode); +} + +int novfs_create(unsigned char * Path, int DirectoryFlag, struct novfs_schandle SessionId) +{ + struct novfs_create_file_request *cmd; + struct novfs_create_file_reply *reply; + unsigned long replylen = 0; + int retCode, cmdlen, pathlen; + + pathlen = strlen(Path); + + if (StripTrailingDots) { + if ('.' == Path[pathlen - 1]) + pathlen--; + } + + cmdlen = offsetof(struct novfs_create_file_request, path) + pathlen; + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + cmd->Command.CommandType = VFS_COMMAND_CREATE_FILE; + if (DirectoryFlag) { + cmd->Command.CommandType = VFS_COMMAND_CREATE_DIRECOTRY; + } + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = SessionId; + + cmd->pathlength = pathlen; + memcpy(cmd->path, Path, pathlen); + + retCode = + Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + + if (reply) { + retCode = 0; + if (reply->Reply.ErrorCode) { + retCode = -EIO; + if (reply->Reply.ErrorCode == NWE_ACCESS_DENIED) + retCode = -EACCES; + + } + kfree(reply); + } + kfree(cmd); + return (retCode); +} + +int novfs_close_file(void *Handle, struct novfs_schandle SessionId) +{ + struct novfs_close_file_request cmd; + struct novfs_close_file_reply *reply; + unsigned long replylen = 0; + int retCode; + + cmd.Command.CommandType = VFS_COMMAND_CLOSE_FILE; + cmd.Command.SequenceNumber = 0; + cmd.Command.SessionId = SessionId; + + cmd.handle = Handle; + + retCode = + Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, + &replylen, 0); + if (reply) { + retCode = 0; + if (reply->Reply.ErrorCode) { + retCode = -EIO; + } + kfree(reply); + } + return (retCode); +} + +int novfs_read_file(void *Handle, unsigned char * Buffer, size_t * Bytes, + loff_t * Offset, struct novfs_schandle SessionId) +{ + struct novfs_read_file_request cmd; + struct novfs_read_file_reply * reply = NULL; + unsigned long replylen = 0; + int retCode = 0; + size_t len; + + len = *Bytes; + *Bytes = 0; + + if (offsetof(struct novfs_read_file_reply, data) + len + > novfs_max_iosize) { + len = novfs_max_iosize - offsetof(struct + novfs_read_file_reply, data); + len = (len / PAGE_SIZE) * PAGE_SIZE; + } + + cmd.Command.CommandType = VFS_COMMAND_READ_FILE; + cmd.Command.SequenceNumber = 0; + cmd.Command.SessionId = SessionId; + + cmd.handle = Handle; + cmd.len = len; + cmd.offset = *Offset; + + retCode = + Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + + DbgPrint("Queue_Daemon_Command 0x%x replylen=%d", retCode, replylen); + + if (!retCode) { + if (reply->Reply.ErrorCode) { + if (NWE_FILE_IO_LOCKED == reply->Reply.ErrorCode) { + retCode = -EBUSY; + } else { + retCode = -EIO; + } + } else { + replylen -= offsetof(struct + novfs_read_file_reply, data); + + if (replylen > 0) { + replylen -= + copy_to_user(Buffer, reply->data, replylen); + *Bytes = replylen; + } + } + } + + if (reply) { + kfree(reply); + } + + DbgPrint("*Bytes=0x%x retCode=0x%x", *Bytes, retCode); + + return (retCode); +} + +int novfs_read_pages(void *Handle, struct novfs_data_list *DList, + int DList_Cnt, size_t * Bytes, loff_t * Offset, + struct novfs_schandle SessionId) +{ + struct novfs_read_file_request cmd; + struct novfs_read_file_reply * reply = NULL; + struct novfs_read_file_reply lreply; + unsigned long replylen = 0; + int retCode = 0; + size_t len; + + len = *Bytes; + *Bytes = 0; + + DbgPrint("Handle=0x%p Dlst=0x%p Dlcnt=%d Bytes=%d Offset=%lld " + "SessionId=0x%p:%p", Handle, DList, DList_Cnt, len, *Offset, + SessionId.hTypeId, SessionId.hId); + + cmd.Command.CommandType = VFS_COMMAND_READ_FILE; + cmd.Command.SequenceNumber = 0; + cmd.Command.SessionId = SessionId; + + cmd.handle = Handle; + cmd.len = len; + cmd.offset = *Offset; + + /* + * Dlst first entry is reserved for reply header. + */ + DList[0].page = NULL; + DList[0].offset = &lreply; + DList[0].len = offsetof(struct novfs_read_file_reply, data); + DList[0].rwflag = DLWRITE; + + retCode = + Queue_Daemon_Command(&cmd, sizeof(cmd), DList, DList_Cnt, + (void *)&reply, &replylen, INTERRUPTIBLE); + + DbgPrint("Queue_Daemon_Command 0x%x", retCode); + + if (!retCode) { + if (reply) { + memcpy(&lreply, reply, sizeof(lreply)); + } + + if (lreply.Reply.ErrorCode) { + if (NWE_FILE_IO_LOCKED == lreply.Reply.ErrorCode) { + retCode = -EBUSY; + } else { + retCode = -EIO; + } + } + *Bytes = replylen - offsetof(struct + novfs_read_file_reply, data); + } + + if (reply) { + kfree(reply); + } + + DbgPrint("retCode=0x%x", retCode); + + return (retCode); +} + +int novfs_write_file(void *Handle, unsigned char * Buffer, size_t * Bytes, + loff_t * Offset, struct novfs_schandle SessionId) +{ + struct novfs_write_file_request cmd; + struct novfs_write_file_reply *reply = NULL; + unsigned long replylen = 0; + int retCode = 0, cmdlen; + size_t len; + + unsigned long boff; + struct page **pages; + struct novfs_data_list *dlist; + int res = 0, npage, i; + struct novfs_write_file_reply lreply; + + len = *Bytes; + cmdlen = offsetof(struct novfs_write_file_request, data); + + *Bytes = 0; + + memset(&lreply, 0, sizeof(lreply)); + + DbgPrint("cmdlen=%ld len=%ld", cmdlen, len); + + if ((cmdlen + len) > novfs_max_iosize) { + len = novfs_max_iosize - cmdlen; + len = (len / PAGE_SIZE) * PAGE_SIZE; + } + cmd.Command.CommandType = VFS_COMMAND_WRITE_FILE; + cmd.Command.SequenceNumber = 0; + cmd.Command.SessionId = SessionId; + cmd.handle = Handle; + cmd.len = len; + cmd.offset = *Offset; + + DbgPrint("cmdlen=%ld len=%ld", cmdlen, len); + + npage = + (((unsigned long)Buffer & ~PAGE_MASK) + len + + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + + dlist = kmalloc(sizeof(struct novfs_data_list) * (npage + 1), GFP_KERNEL); + if (NULL == dlist) { + return (-ENOMEM); + } + + pages = kmalloc(sizeof(struct page *) * npage, GFP_KERNEL); + + if (NULL == pages) { + kfree(dlist); + return (-ENOMEM); + } + + down_read(¤t->mm->mmap_sem); + + res = get_user_pages(current, current->mm, (unsigned long)Buffer, npage, 0, /* read type */ + 0, /* don't force */ + pages, NULL); + + up_read(¤t->mm->mmap_sem); + + DbgPrint("res=%d", res); + + if (res > 0) { + boff = (unsigned long)Buffer & ~PAGE_MASK; + + flush_dcache_page(pages[0]); + dlist[0].page = pages[0]; + dlist[0].offset = (char *)boff; + dlist[0].len = PAGE_SIZE - boff; + dlist[0].rwflag = DLREAD; + + if (dlist[0].len > len) { + dlist[0].len = len; + } + + DbgPrint("page=0x%p offset=0x%p len=%d", + dlist[0].page, dlist[0].offset, dlist[0].len); + + boff = dlist[0].len; + + DbgPrint("len=%d boff=%d", len, boff); + + for (i = 1; (i < res) && (boff < len); i++) { + flush_dcache_page(pages[i]); + + dlist[i].page = pages[i]; + dlist[i].offset = NULL; + dlist[i].len = len - boff; + if (dlist[i].len > PAGE_SIZE) { + dlist[i].len = PAGE_SIZE; + } + dlist[i].rwflag = DLREAD; + + boff += dlist[i].len; + DbgPrint("%d: page=0x%p offset=0x%p len=%d", i, + dlist[i].page, dlist[i].offset, dlist[i].len); + } + + dlist[i].page = NULL; + dlist[i].offset = &lreply; + dlist[i].len = sizeof(lreply); + dlist[i].rwflag = DLWRITE; + res++; + + DbgPrint("Buffer=0x%p boff=0x%x len=%d", Buffer, boff, len); + + retCode = + Queue_Daemon_Command(&cmd, cmdlen, dlist, res, + (void *)&reply, &replylen, + INTERRUPTIBLE); + + } else { + char *kdata; + + res = 0; + + kdata = kmalloc(len, GFP_KERNEL); + if (kdata) { + len -= copy_from_user(kdata, Buffer, len); + dlist[0].page = NULL; + dlist[0].offset = kdata; + dlist[0].len = len; + dlist[0].rwflag = DLREAD; + + dlist[1].page = NULL; + dlist[1].offset = &lreply; + dlist[1].len = sizeof(lreply); + dlist[1].rwflag = DLWRITE; + + retCode = + Queue_Daemon_Command(&cmd, cmdlen, dlist, 2, + (void *)&reply, &replylen, + INTERRUPTIBLE); + + kfree(kdata); + } + } + + DbgPrint("retCode=0x%x reply=0x%p", retCode, reply); + + if (!retCode) { + switch (lreply.Reply.ErrorCode) { + case 0: + *Bytes = (size_t) lreply.bytesWritten; + retCode = 0; + break; + + case NWE_INSUFFICIENT_SPACE: + retCode = -ENOSPC; + break; + + case NWE_ACCESS_DENIED: + retCode = -EACCES; + break; + + default: + retCode = -EIO; + break; + } + } + + if (res) { + for (i = 0; i < res; i++) { + if (dlist[i].page) { + page_cache_release(dlist[i].page); + } + } + } + + kfree(pages); + kfree(dlist); + + DbgPrint("*Bytes=0x%x retCode=0x%x", *Bytes, + retCode); + + return (retCode); +} + +/* + * Arguments: HANDLE Handle - novfsd file handle + * struct page *Page - Page to be written out + * struct novfs_schandle SessionId - novfsd session handle + * + * Returns: 0 - Success + * -ENOSPC - Out of space on server + * -EACCES - Access denied + * -EIO - Any other error + * + * Abstract: Write page to file. + */ +int novfs_write_page(void *Handle, struct page *Page, struct novfs_schandle SessionId) +{ + struct novfs_write_file_request cmd; + struct novfs_write_file_reply lreply; + struct novfs_write_file_reply *reply = NULL; + unsigned long replylen = 0; + int retCode = 0, cmdlen; + struct novfs_data_list dlst[2]; + + DbgPrint("Handle=0x%p Page=0x%p Index=%lu SessionId=0x%llx", + Handle, Page, Page->index, SessionId); + + dlst[0].page = NULL; + dlst[0].offset = &lreply; + dlst[0].len = sizeof(lreply); + dlst[0].rwflag = DLWRITE; + + dlst[1].page = Page; + dlst[1].offset = 0; + dlst[1].len = PAGE_CACHE_SIZE; + dlst[1].rwflag = DLREAD; + + cmdlen = offsetof(struct novfs_write_file_request, data); + + cmd.Command.CommandType = VFS_COMMAND_WRITE_FILE; + cmd.Command.SequenceNumber = 0; + cmd.Command.SessionId = SessionId; + + cmd.handle = Handle; + cmd.len = PAGE_CACHE_SIZE; + cmd.offset = (loff_t) Page->index << PAGE_CACHE_SHIFT;; + + retCode = + Queue_Daemon_Command(&cmd, cmdlen, &dlst, 2, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (!retCode) { + if (reply) { + memcpy(&lreply, reply, sizeof(lreply)); + } + switch (lreply.Reply.ErrorCode) { + case 0: + retCode = 0; + break; + + case NWE_INSUFFICIENT_SPACE: + retCode = -ENOSPC; + break; + + case NWE_ACCESS_DENIED: + retCode = -EACCES; + break; + + default: + retCode = -EIO; + break; + } + } + + if (reply) { + kfree(reply); + } + + DbgPrint("retCode=0x%x", retCode); + + return (retCode); +} + +int novfs_write_pages(void *Handle, struct novfs_data_list *DList, int DList_Cnt, + size_t Bytes, loff_t Offset, struct novfs_schandle SessionId) +{ + struct novfs_write_file_request cmd; + struct novfs_write_file_reply lreply; + struct novfs_write_file_reply *reply = NULL; + unsigned long replylen = 0; + int retCode = 0, cmdlen; + size_t len; + + DbgPrint("Handle=0x%p Dlst=0x%p Dlcnt=%d Bytes=%d Offset=%lld " + "SessionId=0x%llx\n", Handle, DList, DList_Cnt, Bytes, + Offset, SessionId); + + DList[0].page = NULL; + DList[0].offset = &lreply; + DList[0].len = sizeof(lreply); + DList[0].rwflag = DLWRITE; + + len = Bytes; + cmdlen = offsetof(struct novfs_write_file_request, data); + + if (len) { + cmd.Command.CommandType = VFS_COMMAND_WRITE_FILE; + cmd.Command.SequenceNumber = 0; + cmd.Command.SessionId = SessionId; + + cmd.handle = Handle; + cmd.len = len; + cmd.offset = Offset; + + retCode = + Queue_Daemon_Command(&cmd, cmdlen, DList, DList_Cnt, + (void *)&reply, &replylen, + INTERRUPTIBLE); + if (!retCode) { + if (reply) { + memcpy(&lreply, reply, sizeof(lreply)); + } + switch (lreply.Reply.ErrorCode) { + case 0: + retCode = 0; + break; + + case NWE_INSUFFICIENT_SPACE: + retCode = -ENOSPC; + break; + + case NWE_ACCESS_DENIED: + retCode = -EACCES; + break; + + default: + retCode = -EIO; + break; + } + } + if (reply) { + kfree(reply); + } + } + DbgPrint("retCode=0x%x", retCode); + + return (retCode); +} + +int novfs_read_stream(void *ConnHandle, unsigned char * Handle, u_char * Buffer, + size_t * Bytes, loff_t * Offset, int User, + struct novfs_schandle SessionId) +{ + struct novfs_read_stream_request cmd; + struct novfs_read_stream_reply *reply = NULL; + unsigned long replylen = 0; + int retCode = 0; + size_t len; + + len = *Bytes; + *Bytes = 0; + + if (offsetof(struct novfs_read_file_reply, data) + len + > novfs_max_iosize) { + len = novfs_max_iosize - offsetof(struct + novfs_read_file_reply, data); + len = (len / PAGE_SIZE) * PAGE_SIZE; + } + + cmd.Command.CommandType = VFS_COMMAND_READ_STREAM; + cmd.Command.SequenceNumber = 0; + cmd.Command.SessionId = SessionId; + + cmd.connection = ConnHandle; + memcpy(cmd.handle, Handle, sizeof(cmd.handle)); + cmd.len = len; + cmd.offset = *Offset; + + retCode = + Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + + DbgPrint("Queue_Daemon_Command 0x%x replylen=%d", retCode, replylen); + + if (reply) { + retCode = 0; + if (reply->Reply.ErrorCode) { + retCode = -EIO; + } else { + replylen -= offsetof(struct + novfs_read_stream_reply, data); + if (replylen > 0) { + if (User) { + replylen -= + copy_to_user(Buffer, reply->data, + replylen); + } else { + memcpy(Buffer, reply->data, replylen); + } + + *Bytes = replylen; + } + } + kfree(reply); + } + + DbgPrint("*Bytes=0x%x retCode=0x%x", *Bytes, retCode); + + return (retCode); +} + +int novfs_write_stream(void *ConnHandle, unsigned char * Handle, u_char * Buffer, + size_t * Bytes, loff_t * Offset, struct novfs_schandle SessionId) +{ + struct novfs_write_stream_request * cmd; + struct novfs_write_stream_reply * reply = NULL; + unsigned long replylen = 0; + int retCode = 0, cmdlen; + size_t len; + + len = *Bytes; + cmdlen = len + offsetof(struct novfs_write_stream_request, data); + *Bytes = 0; + + if (cmdlen > novfs_max_iosize) { + cmdlen = novfs_max_iosize; + len = cmdlen - offsetof(struct + novfs_write_stream_request, data); + } + + DbgPrint("cmdlen=%d len=%d", cmdlen, len); + + cmd = kmalloc(cmdlen, GFP_KERNEL); + + if (cmd) { + if (Buffer && len) { + len -= copy_from_user(cmd->data, Buffer, len); + } + + DbgPrint("len=%d", len); + + cmd->Command.CommandType = VFS_COMMAND_WRITE_STREAM; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = SessionId; + + cmd->connection = ConnHandle; + memcpy(cmd->handle, Handle, sizeof(cmd->handle)); + cmd->len = len; + cmd->offset = *Offset; + + retCode = + Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { + switch (reply->Reply.ErrorCode) { + case 0: + retCode = 0; + break; + + case NWE_INSUFFICIENT_SPACE: + retCode = -ENOSPC; + break; + + case NWE_ACCESS_DENIED: + retCode = -EACCES; + break; + + default: + retCode = -EIO; + break; + } + DbgPrint("reply->bytesWritten=0x%lx", + reply->bytesWritten); + *Bytes = reply->bytesWritten; + kfree(reply); + } + kfree(cmd); + } + DbgPrint("*Bytes=0x%x retCode=0x%x", *Bytes, retCode); + + return (retCode); +} + +int novfs_close_stream(void *ConnHandle, unsigned char * Handle, struct novfs_schandle SessionId) +{ + struct novfs_close_stream_request cmd; + struct novfs_close_stream_reply *reply; + unsigned long replylen = 0; + int retCode; + + cmd.Command.CommandType = VFS_COMMAND_CLOSE_STREAM; + cmd.Command.SequenceNumber = 0; + cmd.Command.SessionId = SessionId; + + cmd.connection = ConnHandle; + memcpy(cmd.handle, Handle, sizeof(cmd.handle)); + + retCode = + Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, + &replylen, 0); + if (reply) { + retCode = 0; + if (reply->Reply.ErrorCode) { + retCode = -EIO; + } + kfree(reply); + } + return (retCode); +} + +int novfs_delete(unsigned char * Path, int DirectoryFlag, struct novfs_schandle SessionId) +{ + struct novfs_delete_file_request *cmd; + struct novfs_delete_file_reply *reply; + unsigned long replylen = 0; + int retCode, cmdlen, pathlen; + + pathlen = strlen(Path); + + if (StripTrailingDots) { + if ('.' == Path[pathlen - 1]) + pathlen--; + } + + cmdlen = offsetof(struct novfs_delete_file_request, path) + pathlen; + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_DELETE_FILE; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = SessionId; + + cmd->isDirectory = DirectoryFlag; + cmd->pathlength = pathlen; + memcpy(cmd->path, Path, pathlen); + + retCode = + Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { + retCode = 0; + if (reply->Reply.ErrorCode) { + if ((reply->Reply.ErrorCode & 0xFFFF) == 0x0006) { /* Access Denied Error */ + retCode = -EACCES; + } else { + retCode = -EIO; + } + } + kfree(reply); + } + kfree(cmd); + } else { + retCode = -ENOMEM; + } + return (retCode); +} + +int novfs_trunc(unsigned char * Path, int PathLen, + struct novfs_schandle SessionId) +{ + struct novfs_truncate_file_request *cmd; + struct novfs_truncate_file_reply *reply = NULL; + unsigned long replylen = 0; + int retCode, cmdlen; + + if (StripTrailingDots) { + if ('.' == Path[PathLen - 1]) + PathLen--; + } + cmdlen = offsetof(struct novfs_truncate_file_request, path) + + PathLen; + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_TRUNCATE_FILE; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = SessionId; + + cmd->pathLen = PathLen; + memcpy(cmd->path, Path, PathLen); + + retCode = + Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { + if (reply->Reply.ErrorCode) { + retCode = -EIO; + } + kfree(reply); + } + kfree(cmd); + } else { + retCode = -ENOMEM; + } + return (retCode); +} + +int novfs_trunc_ex(void *Handle, loff_t Offset, + struct novfs_schandle SessionId) +{ + struct novfs_write_file_request cmd; + struct novfs_write_file_reply *reply = NULL; + unsigned long replylen = 0; + int retCode = 0, cmdlen; + + DbgPrint("Handle=0x%p Offset=%lld", Handle, Offset); + + cmdlen = offsetof(struct novfs_write_file_request, data); + + cmd.Command.CommandType = VFS_COMMAND_WRITE_FILE; + cmd.Command.SequenceNumber = 0; + cmd.Command.SessionId = SessionId; + cmd.handle = Handle; + cmd.len = 0; + cmd.offset = Offset; + + retCode = + Queue_Daemon_Command(&cmd, cmdlen, NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + + DbgPrint("retCode=0x%x reply=0x%p", retCode, reply); + + if (!retCode) { + switch (reply->Reply.ErrorCode) { + case 0: + retCode = 0; + break; + + case NWE_INSUFFICIENT_SPACE: + retCode = -ENOSPC; + break; + + case NWE_ACCESS_DENIED: + retCode = -EACCES; + break; + + case NWE_FILE_IO_LOCKED: + retCode = -EBUSY; + break; + + default: + retCode = -EIO; + break; + } + } + + if (reply) { + kfree(reply); + } + + DbgPrint("retCode=%d", retCode); + + return (retCode); +} + +int novfs_rename_file(int DirectoryFlag, unsigned char * OldName, int OldLen, + unsigned char * NewName, int NewLen, + struct novfs_schandle SessionId) +{ + struct novfs_rename_file_request cmd; + struct novfs_rename_file_reply *reply; + unsigned long replylen = 0; + int retCode; + + __DbgPrint("%s:\n" + " DirectoryFlag: %d\n" + " OldName: %.*s\n" + " NewName: %.*s\n" + " SessionId: 0x%llx\n", __func__, + DirectoryFlag, OldLen, OldName, NewLen, NewName, SessionId); + + cmd.Command.CommandType = VFS_COMMAND_RENAME_FILE; + cmd.Command.SequenceNumber = 0; + cmd.Command.SessionId = SessionId; + + cmd.directoryFlag = DirectoryFlag; + + if (StripTrailingDots) { + if ('.' == OldName[OldLen - 1]) + OldLen--; + if ('.' == NewName[NewLen - 1]) + NewLen--; + } + + cmd.newnameLen = NewLen; + memcpy(cmd.newname, NewName, NewLen); + + cmd.oldnameLen = OldLen; + memcpy(cmd.oldname, OldName, OldLen); + + retCode = + Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { + retCode = 0; + if (reply->Reply.ErrorCode) { + retCode = -ENOENT; + } + kfree(reply); + } + return (retCode); +} + +int novfs_set_attr(unsigned char * Path, struct iattr *Attr, + struct novfs_schandle SessionId) +{ + struct novfs_set_file_info_request *cmd; + struct novfs_set_file_info_reply *reply; + unsigned long replylen = 0; + int retCode, cmdlen, pathlen; + + pathlen = strlen(Path); + + if (StripTrailingDots) { + if ('.' == Path[pathlen - 1]) + pathlen--; + } + + cmdlen = offsetof(struct novfs_set_file_info_request,path) + pathlen; + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_SET_FILE_INFO; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = SessionId; + cmd->fileInfo.ia_valid = Attr->ia_valid; + cmd->fileInfo.ia_mode = Attr->ia_mode; + cmd->fileInfo.ia_uid = Attr->ia_uid; + cmd->fileInfo.ia_gid = Attr->ia_uid; + cmd->fileInfo.ia_size = Attr->ia_size; + cmd->fileInfo.ia_atime = Attr->ia_atime.tv_sec; + cmd->fileInfo.ia_mtime = Attr->ia_mtime.tv_sec;; + cmd->fileInfo.ia_ctime = Attr->ia_ctime.tv_sec;; +/* + cmd->fileInfo.ia_attr_flags = Attr->ia_attr_flags; +*/ + cmd->fileInfo.ia_attr_flags = 0; + + cmd->pathlength = pathlen; + memcpy(cmd->path, Path, pathlen); + + retCode = + Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { + switch (reply->Reply.ErrorCode) { + case 0: + retCode = 0; + break; + + case NWE_PARAM_INVALID: + retCode = -EINVAL; + break; + + case NWE_FILE_IO_LOCKED: + retCode = -EBUSY; + break; + + default: + retCode = -EIO; + break; + } + kfree(reply); + } + kfree(cmd); + } else { + retCode = -ENOMEM; + } + return (retCode); +} + +int novfs_get_file_cache_flag(unsigned char * Path, + struct novfs_schandle SessionId) +{ + struct novfs_get_cache_flag *cmd; + struct novfs_get_cache_flag_reply *reply = NULL; + unsigned long replylen = 0; + int cmdlen; + int retCode = 0; + int pathlen; + + DbgPrint("Path = %s", Path); + + if (Path && *Path) { + pathlen = strlen(Path); + if (StripTrailingDots) { + if ('.' == Path[pathlen - 1]) + pathlen--; + } + cmdlen = offsetof(struct novfs_get_cache_flag, path) + + pathlen; + cmd = (struct novfs_get_cache_flag *) + kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_GET_CACHE_FLAG; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = SessionId; + cmd->pathLen = pathlen; + memcpy(cmd->path, Path, cmd->pathLen); + + Queue_Daemon_Command(cmd, cmdlen, NULL, 0, + (void *)&reply, &replylen, + INTERRUPTIBLE); + + if (reply) { + + if (!reply->Reply.ErrorCode) { + retCode = reply->CacheFlag; + } + + kfree(reply); + } + kfree(cmd); + } + } + + DbgPrint("return %d", retCode); + return (retCode); +} + +/* + * Arguments: + * SessionId, file handle, type of lock (read/write or unlock), + * start of lock area, length of lock area + * + * Notes: lock type - fcntl + */ +int novfs_set_file_lock(struct novfs_schandle SessionId, void *Handle, + unsigned char fl_type, loff_t fl_start, loff_t fl_len) +{ + struct novfs_set_file_lock_request *cmd; + struct novfs_set_file_lock_reply *reply = NULL; + unsigned long replylen = 0; + int retCode; + + retCode = -1; + + DbgPrint("SessionId: 0x%llx\n", SessionId); + + cmd = + (struct novfs_set_file_lock_request *) kmalloc(sizeof(struct novfs_set_file_lock_request), GFP_KERNEL); + + if (cmd) { + DbgPrint("2"); + + cmd->Command.CommandType = VFS_COMMAND_SET_FILE_LOCK; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = SessionId; + + cmd->handle = Handle; + if (F_RDLCK == fl_type) { + fl_type = 1; // LockRegionExclusive + } else if (F_WRLCK == fl_type) { + fl_type = 0; // LockRegionShared + } + + cmd->fl_type = fl_type; + cmd->fl_start = fl_start; + cmd->fl_len = fl_len; + + DbgPrint("3"); + + DbgPrint("BEGIN dump arguments"); + DbgPrint("Queue_Daemon_Command %d", + cmd->Command.CommandType); + DbgPrint("cmd->handle = 0x%p", cmd->handle); + DbgPrint("cmd->fl_type = %u", cmd->fl_type); + DbgPrint("cmd->fl_start = 0x%X", cmd->fl_start); + DbgPrint("cmd->fl_len = 0x%X", cmd->fl_len); + DbgPrint("sizeof(SET_FILE_LOCK_REQUEST) = %u", + sizeof(struct novfs_set_file_lock_request)); + DbgPrint("END dump arguments"); + + retCode = + Queue_Daemon_Command(cmd, sizeof(struct novfs_set_file_lock_request), + NULL, 0, (void *)&reply, &replylen, + INTERRUPTIBLE); + DbgPrint("4"); + + if (reply) { + DbgPrint("5, ErrorCode = %X", reply->Reply.ErrorCode); + + if (reply->Reply.ErrorCode) { + retCode = reply->Reply.ErrorCode; + } + kfree(reply); + } + kfree(cmd); + } + + DbgPrint("6"); + + return (retCode); +} --- /dev/null +++ b/fs/novfs/inode.c @@ -0,0 +1,4638 @@ +/* + * Novell NCP Redirector for Linux + * Author: James Turner + * + * This file contains functions used to control access to the Linux file + * system. + * + * Copyright (C) 2005 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*===[ Include files specific to this module ]============================*/ +#include "vfs.h" + + +struct inode_data { + void *Scope; + unsigned long Flags; + struct list_head IList; + struct inode *Inode; + unsigned long cntDC; + struct list_head DirCache; + struct semaphore DirCacheLock; + void * FileHandle; + int CacheFlag; + char Name[1]; /* Needs to be last entry */ +}; + +#define FILE_UPDATE_TIMEOUT 2 + +/*===[ Function prototypes ]=============================================*/ + +static unsigned long novfs_internal_hash(struct qstr *name); +static int novfs_d_add(struct dentry *p, struct dentry *d, struct inode *i, int add); + +static int novfs_get_sb(struct file_system_type *Fstype, int Flags, + const char *Dev_name, void *Data, struct vfsmount *Mnt); + +static void novfs_kill_sb(struct super_block *SB); + + +/* + * Declared dentry_operations + */ +int novfs_d_revalidate(struct dentry *, struct nameidata *); +int novfs_d_hash(struct dentry *, struct qstr *); +int novfs_d_compare(struct dentry *, struct qstr *, struct qstr *); +int novfs_d_delete(struct dentry *dentry); +void novfs_d_release(struct dentry *dentry); +void novfs_d_iput(struct dentry *dentry, struct inode *inode); + +/* + * Declared directory operations + */ +int novfs_dir_open(struct inode *inode, struct file *file); +int novfs_dir_release(struct inode *inode, struct file *file); +loff_t novfs_dir_lseek(struct file *file, loff_t offset, int origin); +ssize_t novfs_dir_read(struct file *file, char *buf, size_t len, loff_t * off); +void addtodentry(struct dentry *Parent, unsigned char *List, int Level); +int novfs_filldir(void *data, const char *name, int namelen, loff_t off, + ino_t ino, unsigned ftype); +int novfs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir); +int novfs_dir_fsync(struct file *file, struct dentry *dentry, int datasync); + +/* + * Declared address space operations + */ +int novfs_a_writepage(struct page *page, struct writeback_control *wbc); +int novfs_a_writepages(struct address_space *mapping, + struct writeback_control *wbc); +int novfs_a_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata); +int novfs_a_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *pagep, void *fsdata); +int novfs_a_readpage(struct file *file, struct page *page); +int novfs_a_readpages(struct file *file, struct address_space *mapping, + struct list_head *page_lst, unsigned nr_pages); +ssize_t novfs_a_direct_IO(int rw, struct kiocb *kiocb, const struct iovec *iov, + loff_t offset, unsigned long nr_segs); + +/* + * Declared file_operations + */ +ssize_t novfs_f_read(struct file *, char *, size_t, loff_t *); +ssize_t novfs_f_write(struct file *, const char *, size_t, loff_t *); +int novfs_f_readdir(struct file *, void *, filldir_t); +int novfs_f_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +int novfs_f_mmap(struct file *file, struct vm_area_struct *vma); +int novfs_f_open(struct inode *, struct file *); +int novfs_f_flush(struct file *, fl_owner_t); +int novfs_f_release(struct inode *, struct file *); +int novfs_f_fsync(struct file *, struct dentry *, int datasync); +int novfs_f_lock(struct file *, int, struct file_lock *); + +/* + * Declared inode_operations + */ +int novfs_i_create(struct inode *, struct dentry *, int, struct nameidata *); +struct dentry *novfs_i_lookup(struct inode *, struct dentry *, + struct nameidata *); +int novfs_i_mkdir(struct inode *, struct dentry *, int); +int novfs_i_unlink(struct inode *dir, struct dentry *dentry); +int novfs_i_rmdir(struct inode *, struct dentry *); +int novfs_i_mknod(struct inode *, struct dentry *, int, dev_t); +int novfs_i_rename(struct inode *, struct dentry *, struct inode *, + struct dentry *); +int novfs_i_setattr(struct dentry *, struct iattr *); +int novfs_i_getattr(struct vfsmount *mnt, struct dentry *, struct kstat *); +int novfs_i_revalidate(struct dentry *dentry); + +/* + * Extended attributes operations + */ + +ssize_t novfs_i_getxattr(struct dentry *dentry, const char *name, void *buffer, + size_t size); +int novfs_i_setxattr(struct dentry *dentry, const char *name, const void *value, + size_t value_size, int flags); +ssize_t novfs_i_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size); + +void update_inode(struct inode *Inode, struct novfs_entry_info *Info); + +/* + * Declared super_operations + */ +void novfs_read_inode(struct inode *inode); +void novfs_write_inode(struct inode *inode); +int novfs_notify_change(struct dentry *dentry, struct iattr *attr); +void novfs_clear_inode(struct inode *inode); +int novfs_show_options(struct seq_file *s, struct vfsmount *m); + +int novfs_statfs(struct dentry *de, struct kstatfs *buf); + +/* + * Declared control interface functions + */ +ssize_t +novfs_control_Read(struct file *file, char *buf, size_t nbytes, loff_t * ppos); + +ssize_t +novfs_control_write(struct file *file, const char *buf, size_t nbytes, + loff_t * ppos); + +int novfs_control_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); + +int __init init_novfs(void); +void __exit exit_novfs(void); + +int novfs_lock_inode_cache(struct inode *i); +void novfs_unlock_inode_cache(struct inode *i); +int novfs_enumerate_inode_cache(struct inode *i, struct list_head **iteration, + ino_t * ino, struct novfs_entry_info *info); +int novfs_get_entry(struct inode *i, struct qstr *name, ino_t * ino, + struct novfs_entry_info *info); +int novfs_get_entry_by_pos(struct inode *i, loff_t pos, ino_t * ino, + struct novfs_entry_info *info); +int novfs_get_entry_time(struct inode *i, struct qstr *name, ino_t * ino, + struct novfs_entry_info *info, u64 * EntryTime); +int novfs_get_remove_entry(struct inode *i, ino_t * ino, struct novfs_entry_info *info); +void novfs_invalidate_inode_cache(struct inode *i); +struct novfs_dir_cache *novfs_lookup_inode_cache(struct inode *i, struct qstr *name, + ino_t ino); +int novfs_lookup_validate(struct inode *i, struct qstr *name, ino_t ino); +int novfs_add_inode_entry(struct inode *i, struct qstr *name, ino_t ino, + struct novfs_entry_info *info); +int novfs_update_entry(struct inode *i, struct qstr *name, ino_t ino, + struct novfs_entry_info *info); +void novfs_remove_inode_entry(struct inode *i, struct qstr *name, ino_t ino); +void novfs_free_invalid_entries(struct inode *i); +void novfs_free_inode_cache(struct inode *i); + +/*===[ Global variables ]=================================================*/ +struct dentry_operations novfs_dentry_operations = { + .d_revalidate = novfs_d_revalidate, + .d_hash = novfs_d_hash, + .d_compare = novfs_d_compare, + //.d_delete = novfs_d_delete, + .d_release = novfs_d_release, + .d_iput = novfs_d_iput, +}; + +struct file_operations novfs_dir_operations = { + .owner = THIS_MODULE, + .open = novfs_dir_open, + .release = novfs_dir_release, + .llseek = novfs_dir_lseek, + .read = novfs_dir_read, + .readdir = novfs_dir_readdir, + .fsync = novfs_dir_fsync, +}; + +static struct file_operations novfs_file_operations = { + .owner = THIS_MODULE, + .read = novfs_f_read, + .write = novfs_f_write, + .readdir = novfs_f_readdir, + .ioctl = novfs_f_ioctl, + .mmap = novfs_f_mmap, + .open = novfs_f_open, + .flush = novfs_f_flush, + .release = novfs_f_release, + .fsync = novfs_f_fsync, + .llseek = generic_file_llseek, + .lock = novfs_f_lock, +}; + +static struct address_space_operations novfs_nocache_aops = { + .readpage = novfs_a_readpage, +}; + +struct backing_dev_info novfs_backing_dev_info = { + .ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE, + .state = 0, + .capabilities = BDI_CAP_NO_WRITEBACK | BDI_CAP_MAP_COPY, + .unplug_io_fn = default_unplug_io_fn, +}; + +static struct address_space_operations novfs_aops = { + .readpage = novfs_a_readpage, + .readpages = novfs_a_readpages, + .writepage = novfs_a_writepage, + .writepages = novfs_a_writepages, + .write_begin = novfs_a_write_begin, + .write_end = novfs_a_write_end, + .set_page_dirty = __set_page_dirty_nobuffers, + .direct_IO = novfs_a_direct_IO, +}; + +static struct inode_operations novfs_inode_operations = { + .create = novfs_i_create, + .lookup = novfs_i_lookup, + .unlink = novfs_i_unlink, + .mkdir = novfs_i_mkdir, + .rmdir = novfs_i_rmdir, + .mknod = novfs_i_mknod, + .rename = novfs_i_rename, + .setattr = novfs_i_setattr, + .getattr = novfs_i_getattr, + .getxattr = novfs_i_getxattr, + .setxattr = novfs_i_setxattr, + .listxattr = novfs_i_listxattr, +}; + +static struct inode_operations novfs_file_inode_operations = { + .setattr = novfs_i_setattr, + .getattr = novfs_i_getattr, + .getxattr = novfs_i_getxattr, + .setxattr = novfs_i_setxattr, + .listxattr = novfs_i_listxattr, +}; + +static struct super_operations novfs_ops = { + .statfs = novfs_statfs, + .clear_inode = novfs_clear_inode, + .drop_inode = generic_delete_inode, + .show_options = novfs_show_options, + +}; + +/* Not currently used +static struct file_operations novfs_Control_operations = { + .read = novfs_Control_read, + .write = novfs_Control_write, + .ioctl = novfs_Control_ioctl, +}; +*/ + +static atomic_t novfs_Inode_Number = ATOMIC_INIT(0); + + +struct dentry *novfs_root = NULL; +char *novfs_current_mnt = NULL; + +DECLARE_MUTEX(InodeList_lock); + +LIST_HEAD(InodeList); + +DECLARE_MUTEX(TimeDir_Lock); +uint64_t lastTime; +char lastDir[PATH_MAX]; + +uint64_t inHAXTime; +int inHAX; + +unsigned long InodeCount = 0, DCCount = 0; +unsigned long novfs_update_timeout = FILE_UPDATE_TIMEOUT; +int novfs_page_cache = 0; + +struct file_private { + int listedall; + void *enumHandle; +}; + +static void PRINT_DENTRY(const char *s, struct dentry *d) +{ + __DbgPrint("%s: 0x%p\n", s, d); + __DbgPrint(" d_count: 0x%x\n", d->d_count); + __DbgPrint(" d_lock: 0x%x\n", d->d_lock); + __DbgPrint(" d_inode: 0x%x\n", d->d_inode); + __DbgPrint(" d_lru: 0x%p\n" + " next: 0x%p\n" + " prev: 0x%p\n", &d->d_lru, d->d_lru.next, + d->d_lru.prev); + __DbgPrint(" d_child: 0x%p\n" " next: 0x%p\n" + " prev: 0x%p\n", &d->d_u.d_child, + d->d_u.d_child.next, d->d_u.d_child.prev); + __DbgPrint(" d_subdirs: 0x%p\n" " next: 0x%p\n" + " prev: 0x%p\n", &d->d_subdirs, d->d_subdirs.next, + d->d_subdirs.prev); + __DbgPrint(" d_alias: 0x%p\n" " next: 0x%p\n" + " prev: 0x%p\n", &d->d_alias, d->d_alias.next, + d->d_alias.prev); + __DbgPrint(" d_time: 0x%x\n", d->d_time); + __DbgPrint(" d_op: 0x%p\n", d->d_op); + __DbgPrint(" d_sb: 0x%p\n", d->d_sb); + __DbgPrint(" d_flags: 0x%x\n", d->d_flags); + __DbgPrint(" d_mounted: 0x%x\n", d->d_mounted); + __DbgPrint(" d_fsdata: 0x%p\n", d->d_fsdata); +/* DbgPrint(" d_cookie: 0x%x\n", d->d_cookie); */ + __DbgPrint(" d_parent: 0x%p\n", d->d_parent); + __DbgPrint(" d_name: 0x%p %.*s\n", &d->d_name, d->d_name.len, + d->d_name.name); + __DbgPrint(" name: 0x%p\n" " len: %d\n" + " hash: 0x%x\n", d->d_name.name, d->d_name.len, + d->d_name.hash); + __DbgPrint(" d_hash: 0x%x\n" " next: 0x%x\n" + " pprev: 0x%x\n", d->d_hash, d->d_hash.next, + d->d_hash.pprev); +} + +/*++======================================================================*/ +int novfs_remove_from_root(char *RemoveName) +{ + struct qstr name; + struct dentry *dentry; + struct inode *dir; + + DbgPrint("%s", RemoveName); + name.len = strlen(RemoveName); + name.name = RemoveName; + novfs_d_hash(novfs_root, &name); + + dentry = d_lookup(novfs_root, &name); + if (dentry) { + if (dentry->d_inode && dentry->d_inode->i_private) { + struct inode_data *n_inode = + dentry->d_inode->i_private; + n_inode->Scope = NULL; + } + dput(dentry); + } + + dir = novfs_root->d_inode; + + novfs_lock_inode_cache(dir); + novfs_remove_inode_entry(dir, &name, 0); + novfs_unlock_inode_cache(dir); + + return (0); +} + +/*++======================================================================*/ +int novfs_add_to_root(char *AddName) +{ + struct qstr name; + struct inode *dir; + struct novfs_entry_info info; + ino_t ino; + + DbgPrint("%s", AddName); + name.len = strlen(AddName); + name.name = AddName; + novfs_d_hash(novfs_root, &name); + + dir = novfs_root->d_inode; + + novfs_lock_inode_cache(dir); + + ino = 0; + + if (!novfs_lookup_inode_cache(dir, &name, 0)) { + info.mode = S_IFDIR | 0700; + info.size = 0; + info.atime = info.ctime = info.mtime = CURRENT_TIME; + + ino = (ino_t)atomic_inc_return(&novfs_Inode_Number); + novfs_add_inode_entry(dir, &name, ino, &info); + } + + novfs_unlock_inode_cache(dir); + + return (0); +} + +/*++======================================================================*/ +int novfs_Add_to_Root2(char *AddName) +{ + struct dentry *entry; + struct qstr name; + struct inode *inode; + void *scope; + + DbgPrint("%s", AddName); + name.len = strlen(AddName); + name.name = AddName; + + novfs_d_hash(novfs_root, &name); + + entry = d_lookup(novfs_root, &name); + DbgPrint("novfs_d_lookup 0x%p", entry); + if (NULL == entry) { + scope = novfs_scope_lookup(); + + entry = d_alloc(novfs_root, &name); + DbgPrint("d_alloc 0x%p", entry); + if (entry) { + entry->d_op = &novfs_dentry_operations; + entry->d_time = jiffies + (novfs_update_timeout * HZ); + /* + * done in novfs_d_add now... entry->d_fsdata = (void *)novfs_internal_hash( &name ); + */ + inode = + novfs_get_inode(novfs_root->d_sb, S_IFDIR | 0700, 0, novfs_scope_get_uid(scope), 0, &name); + DbgPrint("Inode=0x%p", inode); + if (inode) { + inode->i_atime = + inode->i_ctime = + inode->i_mtime = CURRENT_TIME; + if (!novfs_d_add(novfs_root, entry, inode, 1)) { + if (inode->i_private) { + struct inode_data *n_inode = inode->i_private; + n_inode->Flags = USER_INODE; + } + PRINT_DENTRY("After novfs_d_add", + entry); + } else { + dput(entry); + iput(inode); + } + } + } + } else { + dput(entry); + PRINT_DENTRY("novfs_Add_to_Root: After dput Dentry", entry); + } + return (0); +} + +char *novfs_dget_path(struct dentry *Dentry, char *Buf, unsigned int Buflen) +{ + char *retval = &Buf[Buflen]; + struct dentry *p = Dentry; + + *(--retval) = '\0'; + Buflen--; + + if (!IS_ROOT(p) && !IS_ROOT(p->d_parent)) { + while (Buflen && !IS_ROOT(p) && !IS_ROOT(p->d_parent)) { + if (Buflen > p->d_name.len) { + retval -= p->d_name.len; + Buflen -= p->d_name.len; + memcpy(retval, p->d_name.name, p->d_name.len); + *(--retval) = '\\'; + Buflen--; + p = p->d_parent; + } else { + retval = NULL; + break; + } + } + } else { + *(--retval) = '\\'; + } + + if (retval) + DbgPrint("%s", retval); + return (retval); +} + +int verify_dentry(struct dentry *dentry, int Flags) +{ + int retVal = -ENOENT; + struct inode *dir; + struct novfs_entry_info *info = NULL; + struct inode_data *id; + struct novfs_schandle session; + char *path, *list = NULL, *cp; + ino_t ino = 0; + struct qstr name; + int iLock = 0; + struct dentry *parent = NULL; + u64 ctime; + struct inode *inode; + + if (IS_ROOT(dentry)) { + DbgPrint("Root entry"); + return (0); + } + + if (dentry && dentry->d_parent && + (dir = dentry->d_parent->d_inode) && (id = dir->i_private)) { + parent = dget_parent(dentry); + + info = kmalloc(sizeof(struct novfs_entry_info) + PATH_LENGTH_BUFFER, GFP_KERNEL); + + if (info) { + if (novfs_lock_inode_cache(dir)) { + name.len = dentry->d_name.len; + name.name = dentry->d_name.name; + name.hash = novfs_internal_hash(&name); + if (!novfs_get_entry_time(dir, &name, &ino, info, &ctime)) { + inode = dentry->d_inode; + if (inode && inode->i_private && + ((inode->i_size != info->size) || + (inode->i_mtime.tv_sec != + info->mtime.tv_sec) + || (inode->i_mtime.tv_nsec != + info->mtime.tv_nsec))) { + /* + * Values don't match so update. + */ + struct inode_data *n_inode = inode->i_private; + n_inode->Flags |= UPDATE_INODE; + } + + ctime = get_jiffies_64() - ctime; + if (Flags || ctime < (u64) (novfs_update_timeout * HZ)) { + retVal = 0; + novfs_unlock_inode_cache(dir); + dput(parent); + kfree(info); + return (0); + } + } + novfs_unlock_inode_cache(dir); + } + + if (IS_ROOT(dentry->d_parent)) { + session = novfs_scope_get_sessionId( + novfs_get_scope_from_name(&dentry->d_name)); + } else + session = novfs_scope_get_sessionId(id->Scope); + + if (!SC_PRESENT(session)) { + id->Scope = novfs_get_scope(dentry); + session = novfs_scope_get_sessionId(id->Scope); + } + + ino = 0; + retVal = 0; + + if (IS_ROOT(dentry->d_parent)) { + DbgPrint("parent is Root directory"); + list = novfs_get_scopeusers(); + + iLock = novfs_lock_inode_cache(dir); + novfs_invalidate_inode_cache(dir); + + if (list) { + cp = list; + while (*cp) { + name.name = cp; + name.len = strlen(cp); + name.hash = novfs_internal_hash(&name); + cp += (name.len + 1); + ino = 0; + if (novfs_get_entry(dir, &name, &ino, info)) { + info->mode = S_IFDIR | 0700; + info->size = 0; + info->atime = info->ctime = info->mtime = CURRENT_TIME; + ino = (ino_t)atomic_inc_return(&novfs_Inode_Number); + novfs_add_inode_entry(dir, &name, ino, info); + } + } + } + novfs_free_invalid_entries(dir); + } else { + + path = + novfs_dget_path(dentry, info->name, + PATH_LENGTH_BUFFER); + if (path) { + if (dentry->d_name.len <= + NW_MAX_PATH_LENGTH) { + name.hash = + novfs_internal_hash + (&dentry->d_name); + name.len = dentry->d_name.len; + name.name = dentry->d_name.name; + + retVal = + novfs_get_file_info(path, + info, + session); + if (0 == retVal) { + dentry->d_time = + jiffies + + (novfs_update_timeout + * HZ); + iLock = + novfs_lock_inode_cache + (dir); + if (novfs_update_entry + (dir, &name, 0, + info)) { + if (dentry-> + d_inode) { + ino = dentry->d_inode->i_ino; + } else { + ino = (ino_t)atomic_inc_return(&novfs_Inode_Number); + } + novfs_add_inode_entry + (dir, &name, + ino, info); + } + if (dentry->d_inode) { + update_inode + (dentry-> + d_inode, + info); + id->Flags &= + ~UPDATE_INODE; + + dentry-> + d_inode-> + i_flags &= + ~S_DEAD; + if (dentry-> + d_inode-> + i_private) { + ((struct inode_data *) dentry->d_inode->i_private)->Scope = id->Scope; + } + } + } else if (-EINTR != retVal) { + retVal = 0; + iLock = novfs_lock_inode_cache(dir); + novfs_remove_inode_entry(dir, &name, 0); + if (dentry->d_inode + && !(dentry->d_inode->i_flags & S_DEAD)) { + dentry->d_inode->i_flags |= S_DEAD; + dentry->d_inode-> i_size = 0; + dentry->d_inode->i_atime.tv_sec = + dentry->d_inode->i_atime.tv_nsec = + dentry->d_inode->i_ctime.tv_sec = + dentry->d_inode->i_ctime.tv_nsec = + dentry->d_inode->i_mtime.tv_sec = + dentry->d_inode->i_mtime.tv_nsec = 0; + dentry->d_inode->i_blocks = 0; + d_delete(dentry); /* Remove from cache */ + } + } + } else { + retVal = -ENAMETOOLONG; + } + } + } + } else { + retVal = -ENOMEM; + } + if (iLock) { + novfs_unlock_inode_cache(dir); + } + dput(parent); + } + + if (list) + kfree(list); + if (info) + kfree(info); + + DbgPrint("return=0x%x", retVal); + + return (retVal); +} + + +static int novfs_d_add(struct dentry *Parent, struct dentry *d, struct inode *i, int a) +{ + void *scope; + struct inode_data *id = NULL; + + char *path, *buf; + + buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + path = novfs_dget_path(d, buf, PATH_LENGTH_BUFFER); + if (path) { + DbgPrint("inode=0x%p ino=%d path %s", i, + i->i_ino, path); + } + kfree(buf); + } + + if (Parent && Parent->d_inode && Parent->d_inode->i_private) { + id = (struct inode_data *) Parent->d_inode->i_private; + } + + if (id && id->Scope) { + scope = id->Scope; + } else { + scope = novfs_get_scope(d); + } + + ((struct inode_data *) i->i_private)->Scope = scope; + + d->d_time = jiffies + (novfs_update_timeout * HZ); + if (a) { + d_add(d, i); + } else { + d_instantiate(d, i); + } + + return (0); +} + +int novfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) +{ + int retCode = 0; + struct inode *dir; + struct inode_data *id; + struct qstr name; + + __DbgPrint("%s: 0x%p %.*s\n" + " d_count: %d\n" + " d_inode: 0x%p\n", __func__, + dentry, dentry->d_name.len, dentry->d_name.name, + dentry->d_count, dentry->d_inode); + + if (IS_ROOT(dentry)) { + retCode = 1; + } else { + if (dentry->d_inode && + dentry->d_parent && + (dir = dentry->d_parent->d_inode) && + (id = dir->i_private)) { + /* + * Check timer to see if in valid time limit + */ + if (jiffies > dentry->d_time) { + /* + * Revalidate entry + */ + name.len = dentry->d_name.len; + name.name = dentry->d_name.name; + name.hash = + novfs_internal_hash(&dentry->d_name); + dentry->d_time = 0; + + if (0 == verify_dentry(dentry, 0)) { + if (novfs_lock_inode_cache(dir)) { + if (novfs_lookup_inode_cache + (dir, &name, 0)) { + dentry->d_time = + jiffies + + (novfs_update_timeout + * HZ); + retCode = 1; + } + novfs_unlock_inode_cache(dir); + } + } + } else { + retCode = 1; + } + } + } + + if ((0 == retCode) && dentry->d_inode) { + /* + * Entry has become invalid + */ +/* dput(dentry); +*/ + } + + DbgPrint("return 0x%x %.*s", retCode, + dentry->d_name.len, dentry->d_name.name); + + return (retCode); +} + +static unsigned long novfs_internal_hash(struct qstr *name) +{ + unsigned long hash = 0; + unsigned int len = name->len; + unsigned char *c = (unsigned char *)name->name; + + while (len--) { + /* + * Lower case values for the hash. + */ + hash = partial_name_hash(tolower(*c++), hash); + } + + return (hash); +} + +int novfs_d_hash(struct dentry *dentry, struct qstr *name) +{ + DbgPrint("%.*s", name->len, name->name); + + name->hash = novfs_internal_hash(name); + + return (0); +} + +int novfs_d_strcmp(struct qstr *s1, struct qstr *s2) +{ + int retCode = 1; + unsigned char *str1, *str2; + unsigned int len; + + DbgPrint("s1=%.*s s2=%.*s", s1->len, s1->name, + s2->len, s2->name); + + if (s1->len && (s1->len == s2->len) && (s1->hash == s2->hash)) { + len = s1->len; + str1 = (unsigned char *)s1->name; + str2 = (unsigned char *)s2->name; + for (retCode = 0; len--; str1++, str2++) { + if (*str1 != *str2) { + if (tolower(*str1) != tolower(*str2)) { + retCode = 1; + break; + } + } + } + } + + DbgPrint("retCode=0x%x", retCode); + return (retCode); +} + +int novfs_d_compare(struct dentry *parent, struct qstr *s1, struct qstr *s2) +{ + int retCode; + + retCode = novfs_d_strcmp(s1, s2); + + DbgPrint("retCode=0x%x", retCode); + return (retCode); +} + +int novfs_d_delete(struct dentry *dentry) +{ + int retVal = 0; + + DbgPrint("0x%p %.*s; d_count: %d; d_inode: 0x%p", + dentry, dentry->d_name.len, dentry->d_name.name, + dentry->d_count, dentry->d_inode); + + if (dentry->d_inode && (dentry->d_inode->i_flags & S_DEAD)) { + retVal = 1; + } + + dentry->d_time = 0; + + return (retVal); +} + +void novfs_d_release(struct dentry *dentry) +{ + DbgPrint("0x%p %.*s", dentry, dentry->d_name.len, + dentry->d_name.name); +} + +void novfs_d_iput(struct dentry *dentry, struct inode *inode) +{ + DbgPrint("Inode=0x%p Ino=%d Dentry=0x%p i_state=%d Name=%.*s", + inode, inode->i_ino, dentry, inode->i_state, dentry->d_name.len, + dentry->d_name.name); + + iput(inode); + +} + +int novfs_dir_open(struct inode *dir, struct file *file) +{ + char *path, *buf; + struct file_private *file_private = NULL; + + DbgPrint("Inode 0x%p %d Name %.*s", dir, dir->i_ino, + file->f_dentry->d_name.len, file->f_dentry->d_name.name); + + buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + path = novfs_dget_path(file->f_dentry, buf, PATH_LENGTH_BUFFER); + if (path) { + DbgPrint("path %s", path); + } + kfree(buf); + } + + file_private = kmalloc(sizeof(struct file_private), GFP_KERNEL); + file_private->listedall = 0; + file_private->enumHandle = NULL; + + file->private_data = file_private; + + return (0); +} + +int novfs_dir_release(struct inode *dir, struct file *file) +{ + struct file_private *file_private = file->private_data; + struct inode *inode = file->f_dentry->d_inode; + struct novfs_schandle sessionId; + + DbgPrint("Inode 0x%p %d Name %.*s", dir, dir->i_ino, + file->f_dentry->d_name.len, file->f_dentry->d_name.name); + + if (file_private) { + if (file_private->enumHandle && (file_private->enumHandle != ((void *)-1))) { + sessionId = novfs_scope_get_sessionId(((struct inode_data *)inode->i_private)->Scope); + if (SC_PRESENT(sessionId) == 0) { + ((struct inode_data *)inode->i_private)->Scope = novfs_get_scope(file->f_dentry); + sessionId = novfs_scope_get_sessionId(((struct inode_data *)inode->i_private)->Scope); + } + novfs_end_directory_enumerate(file_private->enumHandle, sessionId); + } + kfree(file_private); + file->private_data = NULL; + } + + return (0); +} + +loff_t novfs_dir_lseek(struct file * file, loff_t offset, int origin) +{ + struct file_private *file_private = NULL; + + DbgPrint("offset %lld %d Name %.*s", offset, origin, + file->f_dentry->d_name.len, file->f_dentry->d_name.name); + //printk("<1> seekdir file = %.*s offset = %i\n", file->f_dentry->d_name.len, file->f_dentry->d_name.name, (int)offset); + + if (0 != offset) { + return -ESPIPE; + } + + file->f_pos = 0; + + file_private = (struct file_private *) file->private_data; + file_private->listedall = 0; + if (file_private->enumHandle && (file_private->enumHandle != ((void *)-1))) { + struct novfs_schandle sessionId; + struct inode *inode = file->f_dentry->d_inode; + sessionId = novfs_scope_get_sessionId(((struct inode_data *)inode->i_private)->Scope); + if (SC_PRESENT(sessionId) == 0) { + ((struct inode_data *)inode->i_private)->Scope = novfs_get_scope(file->f_dentry); + sessionId = novfs_scope_get_sessionId(((struct inode_data *)inode->i_private)->Scope); + } + novfs_end_directory_enumerate(file_private->enumHandle, sessionId); + } + file_private->enumHandle = NULL; + + return 0; + //return(default_llseek(file, offset, origin)); +} + +ssize_t novfs_dir_read(struct file * file, char *buf, size_t len, loff_t * off) +{ +/* + int rlen = 0; + + DbgPrint("dentry path %.*s buf=0x%p len=%d off=%lld", file->f_dentry->d_name.len, file->f_dentry->d_name.name, buf, len, *off); + + if (0 == *off) + { + rlen = 8; + rlen -= copy_to_user(buf, "Testing\n", 8); + *off += rlen; + } + return(rlen); +*/ + DbgPrint("%lld %d Name %.*s", *off, len, + file->f_dentry->d_name.len, file->f_dentry->d_name.name); + return (generic_read_dir(file, buf, len, off)); +} + +static void novfs_Dump_Info(struct novfs_entry_info *info) +{ + char atime_buf[32], mtime_buf[32], ctime_buf[32]; + char namebuf[512]; + int len = 0; + + if (info == NULL) { + DbgPrint("Dump_Info info == NULL"); + return; + } + + if (info->namelength >= 512) { + len = 511; + } else { + len = info->namelength; + } + + memcpy(namebuf, info->name, len); + namebuf[len] = '\0'; + + ctime_r(&info->atime.tv_sec, atime_buf); + ctime_r(&info->mtime.tv_sec, mtime_buf); + ctime_r(&info->ctime.tv_sec, ctime_buf); + DbgPrint("type = %i", info->type); + DbgPrint("mode = %x", info->mode); + DbgPrint("uid = %d", info->uid); + DbgPrint("gid = %d", info->gid); + DbgPrint("size = %i", info->size); + DbgPrint("atime = %s", atime_buf); + DbgPrint("mtime = %s", mtime_buf); + DbgPrint("ctime = %s", ctime_buf); + DbgPrint("namelength = %i", info->namelength); + DbgPrint("name = %s", namebuf); +} + +void processList(struct file *file, void *dirent, filldir_t filldir, char *list, + int type, struct novfs_schandle SessionId) +{ + unsigned char *path, *buf = NULL, *cp; + struct qstr name; + struct novfs_entry_info *pinfo = NULL; + + buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + path = buf; + if (buf) { + path = novfs_dget_path(file->f_dentry, buf, PATH_LENGTH_BUFFER); + if (path) { + strcpy(buf, path); + } + path = buf + strlen(buf); + *path++ = '\\'; + } + + if (list) { + cp = list; + while (*cp) { + name.name = cp; + DbgPrint("name.name = %s", name.name); + name.len = strlen(cp); + name.hash = novfs_internal_hash(&name); + cp += (name.len + 1); + + pinfo = + kmalloc(sizeof(struct novfs_entry_info) + + PATH_LENGTH_BUFFER, GFP_KERNEL); + pinfo->mode = S_IFDIR | 0700; + pinfo->size = 0; + pinfo->atime = pinfo->ctime = pinfo->mtime = + CURRENT_TIME; + strcpy(pinfo->name, name.name); + pinfo->namelength = name.len; + + novfs_Dump_Info(pinfo); + + filldir(dirent, pinfo->name, pinfo->namelength, + file->f_pos, file->f_pos, pinfo->mode >> 12); + file->f_pos += 1; + + kfree(pinfo); + } + } + + if (buf) { + kfree(buf); + } +} + +int processEntries(struct file *file, void *dirent, filldir_t filldir, + void ** enumHandle, struct novfs_schandle sessionId) +{ + unsigned char *path = NULL, *buf = NULL; + int count = 0, status = 0; + struct novfs_entry_info *pinfo = NULL; + struct novfs_entry_info *pInfoMem = NULL; + + buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (!buf) { + return -ENOMEM; + } + + path = novfs_dget_path(file->f_dentry, buf, PATH_LENGTH_BUFFER); + if (!path) { + kfree(buf); + return -ENOMEM; + } + //NWSearchfiles + count = 0; + status = + novfs_get_dir_listex(path, enumHandle, &count, &pinfo, + sessionId); + pInfoMem = pinfo; + + if ((count == -1) || (count == 0) || (status != 0)) { + kfree(pInfoMem); + kfree(buf); + return -1; + } + // parse resultset + while (pinfo && count--) { + filldir(dirent, pinfo->name, pinfo->namelength, file->f_pos, + file->f_pos, pinfo->mode >> 12); + file->f_pos += 1; + + pinfo = (struct novfs_entry_info *) (pinfo->name + pinfo->namelength); + } + + kfree(pInfoMem); + kfree(buf); + return 0; +} + +int novfs_dir_readdir(struct file *file, void *dirent, filldir_t filldir) +{ + unsigned char *list = NULL; + int status = 0; //-ENOMEM; + struct inode *inode = file->f_dentry->d_inode; + struct novfs_schandle sessionId; + uid_t uid; + int type = 0; + struct file_private *file_private = NULL; + int lComm; + + file_private = (struct file_private *) file->private_data; + DbgPrint("Name %.*s", file->f_dentry->d_name.len, + file->f_dentry->d_name.name); + + //printk("<1> file = %.*s\n", file->f_dentry->d_name.len, file->f_dentry->d_name.name); + +// Use this hack by default +#ifndef SKIP_CROSSOVER_HACK + // Hack for crossover - begin + down(&TimeDir_Lock); + if ((file->f_dentry->d_name.len == 7) && + ((0 == strncmp(file->f_dentry->d_name.name, " !xover", 7)) || + (0 == strncmp(file->f_dentry->d_name.name, "z!xover", 7)))) { + //printk("<1> xoverhack: we are in xoverHack\n"); + + inHAX = 1; + inHAXTime = get_nanosecond_time(); + //up( &TimeDir_Lock ); + //return 0; + file_private->listedall = 1; + } else { + if (inHAX) { + if (get_nanosecond_time() - inHAXTime > + 100 * 1000 * 1000) { + //printk("<1> xoverhack: it was long, long, long ago...\n"); + inHAX = 0; + } else { + //printk("<1> xoverhack: word gotcha in xoverHack...\n"); + inHAXTime = get_nanosecond_time(); + //up( &TimeDir_Lock ); + //return 0; + file_private->listedall = 1; + } + } + } + + up(&TimeDir_Lock); + // Hack for crossover - end +#endif + + if (file->f_pos == 0) { + if (filldir(dirent, ".", 1, file->f_pos, inode->i_ino, DT_DIR) < + 0) + return 1; + file->f_pos++; + return 1; + } + + if (file->f_pos == 1) { + if (filldir + (dirent, "..", 2, file->f_pos, + file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) + return 1; + file->f_pos++; + return 1; + } + + if (file_private->listedall != 0) { + return 0; + } + + inode = file->f_dentry->d_inode; + if (inode && inode->i_private) { + sessionId = + novfs_scope_get_sessionId(((struct inode_data *) inode->i_private)-> + Scope); + if (0 == SC_PRESENT(sessionId)) { + ((struct inode_data *) inode->i_private)->Scope = + novfs_get_scope(file->f_dentry); + sessionId = + novfs_scope_get_sessionId(((struct inode_data *) inode-> + i_private)->Scope); + } + uid = novfs_scope_get_uid(((struct inode_data *) inode->i_private)->Scope); + } else { + SC_INITIALIZE(sessionId); + uid = current_euid(); + } + + if (IS_ROOT(file->f_dentry) || // Root + IS_ROOT(file->f_dentry->d_parent) || // User + IS_ROOT(file->f_dentry->d_parent->d_parent)) // Server + { + if (IS_ROOT(file->f_dentry)) { + DbgPrint("Root directory"); + list = novfs_get_scopeusers(); + type = USER_LIST; + } else if (IS_ROOT(file->f_dentry->d_parent)) { + DbgPrint("Parent is Root directory"); + novfs_get_servers(&list, sessionId); + type = SERVER_LIST; + } else { + DbgPrint("Parent-Parent is Root directory"); + novfs_get_vols(&file->f_dentry->d_name, + &list, sessionId); + type = VOLUME_LIST; + } + + processList(file, dirent, filldir, list, type, sessionId); + file_private->listedall = 1; + } else { + status = + processEntries(file, dirent, filldir, + &file_private->enumHandle, sessionId); + + if (status != 0) { + file_private->listedall = 1; +#ifndef SKIP_CROSSOVER_HACK + // Hack for crossover part 2 - begin + lComm = strlen(current->comm); + if ((lComm > 4) + && (0 == + strcmp(current->comm + lComm - 4, ".EXE"))) { + if (filldir + (dirent, " !xover", 7, file->f_pos, + inode->i_ino, DT_DIR) < 0) + return 1; + if (filldir + (dirent, "z!xover", 7, file->f_pos, + inode->i_ino, DT_DIR) < 0) + return 1; + file->f_pos += 2; + } + // Hack for crossover part2 - end +#endif + } + } + + file->private_data = file_private; + return 1; +} + +int novfs_dir_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + DbgPrint("Name %.*s", file->f_dentry->d_name.len, + file->f_dentry->d_name.name); + return (simple_sync_file(file, dentry, datasync)); +} + +ssize_t novfs_f_read(struct file * file, char *buf, size_t len, loff_t * off) +{ + size_t thisread, totalread = 0; + loff_t offset = *off; + struct inode *inode; + struct novfs_schandle session; + struct inode_data *id; + + if (file->f_dentry && + (inode = file->f_dentry->d_inode) && + (id = (struct inode_data *) inode->i_private)) { + + DbgPrint("(0x%p 0x%p %d %lld %.*s)", + file->private_data, + buf, len, offset, + file->f_dentry->d_name.len, + file->f_dentry->d_name.name); + + if (novfs_page_cache && !(file->f_flags & O_DIRECT) && id->CacheFlag) { + totalread = do_sync_read(file, buf, len, off); + } else { + session = novfs_scope_get_sessionId(id->Scope); + if (0 == SC_PRESENT(session)) { + id->Scope = + novfs_get_scope(file->f_dentry); + session = novfs_scope_get_sessionId(id->Scope); + } + + while (len > 0 && (offset < i_size_read(inode))) { + int retval; + thisread = len; + retval = + novfs_read_file(file->private_data, buf, + &thisread, &offset, + session); + if (retval || !thisread) { + if (retval) { + totalread = retval; + } + break; + } + DbgPrint("thisread = 0x%x", thisread); + len -= thisread; + buf += thisread; + offset += thisread; + totalread += thisread; + } + *off = offset; + } + } + DbgPrint("return = %d", totalread); + + return (totalread); +} + +ssize_t novfs_f_write(struct file * file, const char *buf, size_t len, + loff_t * off) +{ + ssize_t thiswrite, totalwrite = 0; + loff_t offset = *off; + struct novfs_schandle session; + struct inode *inode; + int status; + struct inode_data *id; + + if (file->f_dentry && + (inode = file->f_dentry->d_inode) && + (id = file->f_dentry->d_inode->i_private)) { + DbgPrint("(0x%p 0x%p 0x%p %d %lld %.*s)", + file->private_data, inode, id->FileHandle, len, offset, + file->f_dentry->d_name.len, + file->f_dentry->d_name.name); + + if (novfs_page_cache && + !(file->f_flags & O_DIRECT) && + id->CacheFlag && !(file->f_flags & O_WRONLY)) { + totalwrite = do_sync_write(file, buf, len, off); + } else { + if (file->f_flags & O_APPEND) { + offset = i_size_read(inode); + DbgPrint("appending to end %lld %.*s", + offset, file->f_dentry->d_name.len, + file->f_dentry->d_name.name); + } + + session = novfs_scope_get_sessionId(id->Scope); + if (0 == SC_PRESENT(session)) { + id->Scope = + novfs_get_scope(file->f_dentry); + session = novfs_scope_get_sessionId(id->Scope); + } + + while (len > 0) { + thiswrite = len; + if ((status = + novfs_write_file(file->private_data, + (unsigned char *)buf, + &thiswrite, &offset, + session)) || !thiswrite) { + totalwrite = status; + break; + } + DbgPrint("thiswrite = 0x%x", + thiswrite); + len -= thiswrite; + buf += thiswrite; + offset += thiswrite; + totalwrite += thiswrite; + if (offset > i_size_read(inode)) { + i_size_write(inode, offset); + inode->i_blocks = + (offset + inode->i_sb->s_blocksize - + 1) >> inode->i_blkbits; + } + inode->i_mtime = inode->i_atime = CURRENT_TIME; + id->Flags |= UPDATE_INODE; + + } + *off = offset; + } + } + DbgPrint("return = 0x%x", totalwrite); + + return (totalwrite); +} + +int novfs_f_readdir(struct file *file, void *data, filldir_t fill) +{ + return -EISDIR; +} + +int novfs_f_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + DbgPrint("file=0x%p cmd=0x%x arg=0x%p", file, cmd, arg); + + return -ENOSYS; +} + +int novfs_f_mmap(struct file *file, struct vm_area_struct *vma) +{ + int retCode = -EINVAL; + + DbgPrint("file=0x%p %.*s", file, file->f_dentry->d_name.len, + file->f_dentry->d_name.name); + + retCode = generic_file_mmap(file, vma); + + DbgPrint("retCode=0x%x", retCode); + return (retCode); +} + +int novfs_f_open(struct inode *inode, struct file *file) +{ + struct novfs_entry_info *info = NULL; + int retCode = -ENOENT; + struct novfs_schandle session; + char *path; + struct dentry *parent; + ino_t ino; + struct inode_data *id; + int errInfo; + + DbgPrint("inode=0x%p file=0x%p dentry=0x%p dentry->d_inode=0x%p %.*s", + inode, file, file->f_dentry, file->f_dentry->d_inode, + file->f_dentry->d_name.len, file->f_dentry->d_name.name); + if (file->f_dentry) { + DbgPrint("%.*s f_flags=0%o f_mode=0%o i_mode=0%o", + file->f_dentry->d_name.len, + file->f_dentry->d_name.name, + file->f_flags, file->f_mode, inode->i_mode); + } + + if (inode && inode->i_private) { + id = (struct inode_data *) file->f_dentry->d_inode->i_private; + session = novfs_scope_get_sessionId(id->Scope); + if (0 == SC_PRESENT(session)) { + id->Scope = novfs_get_scope(file->f_dentry); + session = novfs_scope_get_sessionId(id->Scope); + } + + info = kmalloc(sizeof(struct novfs_entry_info) + + PATH_LENGTH_BUFFER, GFP_KERNEL); + if (info) { + path = + novfs_dget_path(file->f_dentry, info->name, + PATH_LENGTH_BUFFER); + if (path) { + if (file->f_flags & O_TRUNC) { + errInfo = + novfs_get_file_info(path, info, + session); + + if (errInfo || info->size == 0) { + // clear O_TRUNC flag, bug #275366 + file->f_flags = + file->f_flags & (~O_TRUNC); + } + } + + DbgPrint("%s", path); + retCode = novfs_open_file(path, + file-> + f_flags & ~O_EXCL, + info, + &file->private_data, + session); + + DbgPrint("0x%x 0x%p", retCode, + file->private_data); + if (!retCode) { + /* + *update_inode(inode, &info); + */ + //id->FileHandle = file->private_data; + id->CacheFlag = + novfs_get_file_cache_flag(path, + session); + + if (!novfs_get_file_info + (path, info, session)) { + update_inode(inode, info); + } + + parent = dget_parent(file->f_dentry); + + if (parent && parent->d_inode) { + struct inode *dir = + parent->d_inode; + novfs_lock_inode_cache(dir); + ino = 0; + if (novfs_get_entry + (dir, + &file->f_dentry->d_name, + &ino, info)) { + ((struct inode_data *) inode-> + i_private)->Flags |= + UPDATE_INODE; + } + + novfs_unlock_inode_cache(dir); + } + dput(parent); + } + } + kfree(info); + } + } + DbgPrint("retCode=0x%x", retCode); + return (retCode); +} + +int novfs_flush_mapping(void *Handle, struct address_space *mapping, + struct novfs_schandle Session) +{ + struct pagevec pagevec; + unsigned nrpages; + pgoff_t index = 0; + int done, rc = 0; + + pagevec_init(&pagevec, 0); + + do { + done = 1; + nrpages = pagevec_lookup_tag(&pagevec, + mapping, + &index, + PAGECACHE_TAG_DIRTY, PAGEVEC_SIZE); + + if (nrpages) { + struct page *page; + int i; + + DbgPrint("%u", nrpages); + + done = 0; + for (i = 0; !rc && (i < nrpages); i++) { + page = pagevec.pages[i]; + + DbgPrint("page 0x%p %lu", page, page->index); + + lock_page(page); + page_cache_get(page); + if (page->mapping == mapping) { + if (clear_page_dirty_for_io(page)) { + rc = novfs_write_page(Handle, + page, + Session); + if (!rc) { + //ClearPageDirty(page); + radix_tree_tag_clear + (&mapping-> + page_tree, + page_index(page), + PAGECACHE_TAG_DIRTY); + } + } + } + + page_cache_release(page); + unlock_page(page); + } + pagevec_release(&pagevec); + } + } while (!rc && !done); + + DbgPrint("return %d", rc); + + return (rc); +} + +int novfs_f_flush(struct file *file, fl_owner_t ownid) +{ + + int rc = 0; +#ifdef FLUSH + struct inode *inode; + struct novfs_schandle session; + struct inode_data *id; + + DbgPrint("Called from 0x%p", __builtin_return_address(0)); + if (file->f_dentry && (inode = file->f_dentry->d_inode) + && (id = file->f_dentry->d_inode->i_private)) { + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + inode = file->f_dentry->d_inode; + DbgPrint("%.*s f_flags=0%o f_mode=0%o i_mode=0%o", + file->f_dentry->d_name.len, + file->f_dentry->d_name.name, file->f_flags, + file->f_mode, inode->i_mode); + + session = novfs_scope_get_sessionId(id->Scope); + if (0 == SC_PRESENT(session)) { + id->Scope = + novfs_get_scope(file->f_dentry); + session = novfs_scope_get_sessionId(id->Scope); + } + + if (inode && + inode->i_mapping && inode->i_mapping->nrpages) { + + DbgPrint("%.*s pages=%lu", + file->f_dentry->d_name.len, + file->f_dentry->d_name.name, + inode->i_mapping->nrpages); + + if (file->f_dentry && + file->f_dentry->d_inode && + file->f_dentry->d_inode->i_mapping && + file->f_dentry->d_inode->i_mapping->a_ops && + file->f_dentry->d_inode->i_mapping->a_ops-> + writepage) { + rc = filemap_fdatawrite(file->f_dentry-> + d_inode-> + i_mapping); + } else { + rc = novfs_flush_mapping(file-> + private_data, + file-> + f_dentry-> + d_inode-> + i_mapping, + session); + } + } + } + } +#endif + return (rc); +} + +int novfs_f_release(struct inode *inode, struct file *file) +{ + int retCode = -EACCES; + struct novfs_schandle session; + struct inode_data *id; + + DbgPrint("path=%.*s handle=%p", + file->f_dentry->d_name.len, + file->f_dentry->d_name.name, file->private_data); + + if (inode && (id = inode->i_private)) { + session = novfs_scope_get_sessionId(id->Scope); + if (0 == SC_PRESENT(session)) { + id->Scope = novfs_get_scope(file->f_dentry); + session = novfs_scope_get_sessionId(id->Scope); + } + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + DbgPrint("%.*s f_flags=0%o f_mode=0%o i_mode=0%o", + file->f_dentry->d_name.len, + file->f_dentry->d_name.name, file->f_flags, + file->f_mode, inode->i_mode); + + if (inode->i_mapping && inode->i_mapping->nrpages) { + + DbgPrint("%.*s pages=%lu", + file->f_dentry->d_name.len, + file->f_dentry->d_name.name, + inode->i_mapping->nrpages); + + if (inode->i_mapping->a_ops && + inode->i_mapping->a_ops->writepage) { + filemap_fdatawrite(file->f_dentry-> + d_inode->i_mapping); + } else { + novfs_flush_mapping(file->private_data, + file->f_dentry-> + d_inode->i_mapping, + session); + } + } + } + + if (file->f_dentry && file->f_dentry->d_inode) { + invalidate_remote_inode(file->f_dentry->d_inode); + } + + retCode = novfs_close_file(file->private_data, session); + //id->FileHandle = 0; + } + return (retCode); +} + +int novfs_f_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + return 0; +} + +int novfs_f_llseek(struct file *file, loff_t offset, int origin) +{ + DbgPrint("File=0x%p Name=%.*s offset=%lld origin=%d", + file, file->f_dentry->d_name.len, file->f_dentry->d_name.name, + offset, origin); + return (generic_file_llseek(file, offset, origin)); +} + +/*++======================================================================*/ +int novfs_f_lock(struct file *file, int cmd, struct file_lock *lock) +/* + * Arguments: + * "file" - pointer to file structure - contains file handle in "file->private_data" + * + * "cmd" could be F_SETLK, F_SETLKW, F_GETLK + * F_SETLK/F_SETLKW are for setting/unsetting file lock + * F_GETLK is for getting infomation about region - is it locked, or not + * + * "lock" structure - contains "start" and "end" of locking region + * + * Returns: + * 0 on success + * -ENOSYS on F_GETLK cmd. It's not implemented. + * -EINVAL if (lock->fl_start > lock->fl_end) + * -EAGAIN on all other errors + * Abstract: + * + * Notes: + * "lock->fl_start" and "lock->fl_end" are of type "long long", + * but xtier functions in novfsd "NCFsdLockFile" and "NCFsdUnlockFile" + * receive arguments in u64 type. + * + * + *========================================================================*/ +{ + int err_code; + + struct inode *inode; + struct novfs_schandle session; + struct inode_data *id; + loff_t len; + + DbgPrint("(0x%p): begin in novfs_f_lock 0x%p", + __builtin_return_address(0), file->private_data); + DbgPrint("cmd = %d, F_GETLK = %d, F_SETLK = %d, F_SETLKW = %d", + cmd, F_GETLK, F_SETLK, F_SETLKW); + DbgPrint("lock->fl_start = 0x%llX, lock->fl_end = 0x%llX", + lock->fl_start, lock->fl_end); + + err_code = -1; + if (lock->fl_start <= lock->fl_end) { + /* Get len from "start" and "end" */ + len = lock->fl_end - lock->fl_start + 1; + if ((0 == lock->fl_start) && (OFFSET_MAX == lock->fl_end)) { + len = 0; + } + + if (file->f_dentry && + (inode = file->f_dentry->d_inode) && + (id = (struct inode_data *) inode->i_private)) { + DbgPrint("(0x%p 0x%p %.*s)", + file->private_data, inode, + file->f_dentry->d_name.len, + file->f_dentry->d_name.name); + + session = novfs_scope_get_sessionId(id->Scope); + if (0 == SC_PRESENT(session)) { + id->Scope = + novfs_get_scope(file->f_dentry); + session = novfs_scope_get_sessionId(id->Scope); + } + + /* fl_type = F_RDLCK, F_WRLCK, F_UNLCK */ + switch (cmd) { + case F_SETLK: +#ifdef F_GETLK64 + case F_SETLK64: +#endif + + err_code = + novfs_set_file_lock(session, + file->private_data, + lock->fl_type, + lock->fl_start, len); + break; + + case F_SETLKW: +#ifdef F_GETLK64 + case F_SETLKW64: +#endif + err_code = + novfs_set_file_lock(session, + file->private_data, + lock->fl_type, + lock->fl_start, len); + break; + + case F_GETLK: +#ifdef F_GETLK64 + case F_GETLK64: +#endif + err_code = -ENOSYS; + /* + * Not implemented. We doesn't have appropriate xtier function. + * */ + break; + + default: + printk + ("<1> novfs in novfs_f_lock, not implemented cmd = %d\n", + cmd); + DbgPrint("novfs in novfs_f_lock, not implemented cmd = %d", + cmd); + break; + } + } + + DbgPrint("lock->fl_type = %u, err_code 0x%X", + lock->fl_type, err_code); + + if ((err_code != 0) && (err_code != -1) + && (err_code != -ENOSYS)) { + err_code = -EAGAIN; + } + } else { + err_code = -EINVAL; + } + + return (err_code); +} + +/*++======================================================================*/ +static void novfs_copy_cache_pages(struct address_space *mapping, + struct list_head *pages, int bytes_read, + char *data, struct pagevec *plru_pvec) +{ + struct page *page; + char *target; + + while (bytes_read > 0) { + if (list_empty(pages)) + break; + + page = list_entry(pages->prev, struct page, lru); + list_del(&page->lru); + + if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) { + page_cache_release(page); + data += PAGE_CACHE_SIZE; + bytes_read -= PAGE_CACHE_SIZE; + continue; + } + + target = kmap_atomic(page, KM_USER0); + + if (PAGE_CACHE_SIZE > bytes_read) { + memcpy(target, data, bytes_read); + /* zero the tail end of this partial page */ + memset(target + bytes_read, 0, + PAGE_CACHE_SIZE - bytes_read); + bytes_read = 0; + } else { + memcpy(target, data, PAGE_CACHE_SIZE); + bytes_read -= PAGE_CACHE_SIZE; + } + kunmap_atomic(target, KM_USER0); + + flush_dcache_page(page); + SetPageUptodate(page); + unlock_page(page); + if (!pagevec_add(plru_pvec, page)) + __pagevec_lru_add_file(plru_pvec); + data += PAGE_CACHE_SIZE; + } + return; +} + +int novfs_a_writepage(struct page *page, struct writeback_control *wbc) +{ + int retCode = -EFAULT; + struct inode *inode = page->mapping->host; + struct inode_data *id = inode->i_private; + loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT); + struct novfs_schandle session; + struct novfs_data_list dlst[2]; + size_t len = PAGE_CACHE_SIZE; + + session = novfs_scope_get_sessionId(((struct inode_data *) inode->i_private)->Scope); + + page_cache_get(page); + + pos = ((loff_t) page->index << PAGE_CACHE_SHIFT); + + /* + * Leave first dlst entry for reply header. + */ + dlst[1].page = page; + dlst[1].offset = NULL; + dlst[1].len = len; + dlst[1].rwflag = DLREAD; + + /* + * Check size so we don't write pass end of file. + */ + if ((pos + (loff_t) len) > i_size_read(inode)) { + len = (size_t) (i_size_read(inode) - pos); + } + + retCode = novfs_write_pages(id->FileHandle, dlst, 2, len, pos, session); + if (!retCode) { + SetPageUptodate(page); + } + + unlock_page(page); + page_cache_release(page); + + return (retCode); +} + +int novfs_a_writepages(struct address_space *mapping, + struct writeback_control *wbc) +{ + int retCode = 0; + struct inode *inode = mapping->host; + struct novfs_schandle session; + void *fh = NULL; + struct inode_data *id = NULL; + + int max_page_lookup = novfs_max_iosize / PAGE_CACHE_SIZE; + + struct novfs_data_list *dlist, *dlptr; + struct page **pages; + + int dlist_idx, i = 0; + pgoff_t index, next_index = 0; + loff_t pos = 0; + size_t tsize; + + SC_INITIALIZE(session); + DbgPrint("inode=0x%p mapping=0x%p wbc=0x%p nr_to_write=%d", + inode, mapping, wbc, wbc->nr_to_write); + + if (inode) { + DbgPrint("Inode=0x%p Ino=%d Id=0x%p", inode, inode->i_ino, + inode->i_private); + + if (NULL != (id = inode->i_private)) { + session = + novfs_scope_get_sessionId(((struct inode_data *) inode-> + i_private)->Scope); + fh = ((struct inode_data *) inode->i_private)->FileHandle; + } + } + + dlist = kmalloc(sizeof(struct novfs_data_list) * max_page_lookup, GFP_KERNEL); + pages = + kmalloc(sizeof(struct page *) * max_page_lookup, GFP_KERNEL); + + if (id) + DbgPrint("inode=0x%p fh=0x%p dlist=0x%p pages=0x%p %s", + inode, fh, dlist, pages, id->Name); + else + DbgPrint("inode=0x%p fh=0x%p dlist=0x%p pages=0x%p", + inode, fh, dlist, pages); + + if (dlist && pages) { + struct backing_dev_info *bdi = mapping->backing_dev_info; + int done = 0; + int nr_pages = 0; + int scanned = 0; + + if (wbc->nonblocking && bdi_write_congested(bdi)) { + wbc->encountered_congestion = 1; + return 0; + } + + if (wbc->sync_mode == WB_SYNC_NONE) { + index = mapping->writeback_index; /* Start from prev offset */ + } else { + index = 0; /* whole-file sweep */ + scanned = 1; + } + + next_index = index; + + while (!done && (wbc->nr_to_write > 0)) { + dlist_idx = 0; + dlptr = &dlist[1]; + + DbgPrint("nr_pages=%d", nr_pages); + if (!nr_pages) { + memset(pages, 0, + sizeof(struct page *) * max_page_lookup); + + spin_lock_irq(&mapping->tree_lock); + + /* + * Need to ask for one less then max_page_lookup or we + * will overflow the request buffer. This also frees + * the first entry for the reply buffer. + */ + nr_pages = + radix_tree_gang_lookup_tag(&mapping-> + page_tree, + (void **)pages, + index, + max_page_lookup - + 1, + PAGECACHE_TAG_DIRTY); + + DbgPrint("2; nr_pages=%d\n", nr_pages); + /* + * Check to see if there are dirty pages and there is a valid + * file handle. + */ + if (nr_pages && !fh) { + set_bit(AS_EIO, &mapping->flags); + done = 1; + DbgPrint("set_bit AS_EIO"); + break; + } + + for (i = 0; i < nr_pages; i++) { + page_cache_get(pages[i]); + } + + spin_unlock_irq(&mapping->tree_lock); + + if (nr_pages) { + index = pages[nr_pages - 1]->index + 1; + pos = + (loff_t) pages[0]-> + index << PAGE_CACHE_SHIFT; + } + + if (!nr_pages) { + if (scanned) { + index = 0; + scanned = 0; + continue; + } + done = 1; + } else { + next_index = pages[0]->index; + i = 0; + } + } else { + if (pages[i]) { + pos = + (loff_t) pages[i]-> + index << PAGE_CACHE_SHIFT; + } + } + + for (; i < nr_pages; i++) { + struct page *page = pages[i]; + + /* + * At this point we hold neither mapping->tree_lock nor + * lock on the page itself: the page may be truncated or + * invalidated (changing page->mapping to NULL), or even + * swizzled back from swapper_space to tmpfs file + * mapping + */ + + DbgPrint + ("novfs_a_writepages: pos=0x%llx index=%d page->index=%d next_index=%d\n", + pos, index, page->index, next_index); + + if (page->index != next_index) { + next_index = page->index; + break; + } + next_index = page->index + 1; + + lock_page(page); + + if (wbc->sync_mode != WB_SYNC_NONE) + wait_on_page_writeback(page); + + if (page->mapping != mapping + || PageWriteback(page) + || !clear_page_dirty_for_io(page)) { + unlock_page(page); + continue; + } + + dlptr[dlist_idx].page = page; + dlptr[dlist_idx].offset = NULL; + dlptr[dlist_idx].len = PAGE_CACHE_SIZE; + dlptr[dlist_idx].rwflag = DLREAD; + dlist_idx++; + DbgPrint("Add page=0x%p index=0x%lx", + page, page->index); + } + + DbgPrint("dlist_idx=%d", dlist_idx); + if (dlist_idx) { + tsize = dlist_idx * PAGE_CACHE_SIZE; + /* + * Check size so we don't write pass end of file. + */ + if ((pos + tsize) > i_size_read(inode)) { + tsize = + (size_t) (i_size_read(inode) - pos); + } + + retCode = + novfs_write_pages(fh, dlist, dlist_idx + 1, + tsize, pos, session); + switch (retCode) { + case 0: + wbc->nr_to_write -= dlist_idx; + break; + + case -ENOSPC: + set_bit(AS_ENOSPC, &mapping->flags); + done = 1; + break; + + default: + set_bit(AS_EIO, &mapping->flags); + done = 1; + break; + } + + do { + unlock_page((struct page *) + dlptr[dlist_idx - 1].page); + page_cache_release((struct page *) + dlptr[dlist_idx - + 1].page); + DbgPrint("release page=0x%p index=0x%lx", + dlptr[dlist_idx - 1].page, + ((struct page *) + dlptr[dlist_idx - + 1].page)->index); + if (!retCode) { + wbc->nr_to_write--; + } + } while (--dlist_idx); + } + + if (i >= nr_pages) { + nr_pages = 0; + } + } + + mapping->writeback_index = index; + + } else { + DbgPrint("set_bit AS_EIO"); + set_bit(AS_EIO, &mapping->flags); + } + if (dlist) + kfree(dlist); + if (pages) + kfree(pages); + + DbgPrint("retCode=%d", retCode); + return (0); + +} + +int novfs_a_readpage(struct file *file, struct page *page) +{ + int retCode = 0; + void *pbuf; + struct inode *inode = NULL; + struct dentry *dentry = NULL; + loff_t offset; + size_t len; + struct novfs_schandle session; + + SC_INITIALIZE(session); + DbgPrint("File=0x%p Name=%.*s Page=0x%p", file, + file->f_dentry->d_name.len, file->f_dentry->d_name.name, page); + + dentry = file->f_dentry; + + if (dentry) { + DbgPrint("Dentry=0x%p Name=%.*s", dentry, dentry->d_name.len, + dentry->d_name.name); + if (dentry->d_inode) { + inode = dentry->d_inode; + } + } + + if (inode) { + DbgPrint("Inode=0x%p Ino=%d", inode, inode->i_ino); + + if (inode->i_private) { + session = + novfs_scope_get_sessionId(((struct inode_data *) inode-> + i_private)->Scope); + if (0 == SC_PRESENT(session)) { + ((struct inode_data *) inode->i_private)->Scope = + novfs_get_scope(file->f_dentry); + session = + novfs_scope_get_sessionId(((struct inode_data *) inode-> + i_private)->Scope); + } + } + } + + if (!PageUptodate(page)) { + struct novfs_data_list dlst[2]; + + offset = page->index << PAGE_CACHE_SHIFT; + len = PAGE_CACHE_SIZE; + + /* + * Save the first entry for the reply header. + */ + dlst[1].page = page; + dlst[1].offset = NULL; + dlst[1].len = PAGE_CACHE_SIZE; + dlst[1].rwflag = DLWRITE; + + DbgPrint("calling= novfs_Read_Pages %lld", + offset); + retCode = + novfs_read_pages(file->private_data, dlst, 2, &len, &offset, + session); + if (len && (len < PAGE_CACHE_SIZE)) { + pbuf = kmap_atomic(page, KM_USER0); + memset(&((char *)pbuf)[len], 0, PAGE_CACHE_SIZE - len); + kunmap_atomic(pbuf, KM_USER0); + } + + flush_dcache_page(page); + SetPageUptodate(page); + } + unlock_page(page); + + DbgPrint("retCode=%d", retCode); + return (retCode); + +} + +int novfs_a_readpages(struct file *file, struct address_space *mapping, + struct list_head *page_lst, unsigned nr_pages) +{ + int retCode = 0; + struct inode *inode = NULL; + struct dentry *dentry = NULL; + struct novfs_schandle session; + loff_t offset; + size_t len; + + unsigned page_idx; + struct pagevec lru_pvec; + pgoff_t next_index; + + char *rbuf, done = 0; + SC_INITIALIZE(session); + + DbgPrint("File=0x%p Name=%.*s Pages=%d", file, + file->f_dentry->d_name.len, file->f_dentry->d_name.name, + nr_pages); + + dentry = file->f_dentry; + + if (dentry) { + DbgPrint("Dentry=0x%p Name=%.*s", dentry, dentry->d_name.len, + dentry->d_name.name); + if (dentry->d_inode) { + inode = dentry->d_inode; + } + } + + if (inode) { + DbgPrint("Inode=0x%p Ino=%d", inode, inode->i_ino); + + if (inode->i_private) { + session = + novfs_scope_get_sessionId(((struct inode_data *) inode-> + i_private)->Scope); + if (0 == SC_PRESENT(session)) { + ((struct inode_data *) inode->i_private)->Scope = + novfs_get_scope(file->f_dentry); + session = + novfs_scope_get_sessionId(((struct inode_data *) inode-> + i_private)->Scope); + } + } + } + + rbuf = kmalloc(novfs_max_iosize, GFP_KERNEL); + if (rbuf) { + pagevec_init(&lru_pvec, 0); + for (page_idx = 0; page_idx < nr_pages && !done;) { + struct page *page, *tpage; + + if (list_empty(page_lst)) + break; + + page = list_entry(page_lst->prev, struct page, lru); + + next_index = page->index; + offset = (loff_t) page->index << PAGE_CACHE_SHIFT; + len = 0; + + /* + * Count number of contiguous pages. + */ + list_for_each_entry_reverse(tpage, page_lst, lru) { + if ((next_index != tpage->index) || + (len >= novfs_max_iosize - PAGE_SIZE)) { + break; + } + len += PAGE_SIZE; + next_index++; + } + + if (len && !done) { + struct novfs_data_list dllst[2]; + + dllst[1].page = NULL; + dllst[1].offset = rbuf; + dllst[1].len = len; + dllst[1].rwflag = DLWRITE; + + DbgPrint("calling novfs_Read_Pages %lld", + offset); + if (!novfs_read_pages + (file->private_data, dllst, 2, &len, + &offset, session)) { + novfs_copy_cache_pages(mapping, + page_lst, len, + rbuf, &lru_pvec); + page_idx += len >> PAGE_CACHE_SHIFT; + if ((int)(len & PAGE_CACHE_MASK) != len) { + page_idx++; + } + if (len == 0) { + done = 1; + } + } else { + done = 1; + } + } + } + + /* + * Free any remaining pages. + */ + while (!list_empty(page_lst)) { + struct page *page = + list_entry(page_lst->prev, struct page, lru); + + list_del(&page->lru); + page_cache_release(page); + } + + pagevec_lru_add_file(&lru_pvec); + kfree(rbuf); + } else { + retCode = -ENOMEM; + } + + DbgPrint("retCode=%d", retCode); + return (retCode); + +} + +int novfs_a_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ + int retVal = 0; + loff_t offset = pos; + struct novfs_schandle session; + struct novfs_data_list dllst[2]; + struct inode *inode = file->f_dentry->d_inode; + struct page *page; + pgoff_t index; + unsigned from, to; + SC_INITIALIZE(session); + + index = pos >> PAGE_CACHE_SHIFT; + from = pos & (PAGE_CACHE_SIZE - 1); + to = from + len; + + page = grab_cache_page_write_begin(mapping, index, flags); + if (!page) + return -ENOMEM; + + *pagep = page; + + DbgPrint("File=0x%p Page=0x%p offset=0x%llx From=%u To=%u " + "filesize=%lld\n", file, page, offset, from, to, + i_size_read(file->f_dentry->d_inode)); + if (!PageUptodate(page)) { + /* + * Check to see if whole page + */ + if ((to == PAGE_CACHE_SIZE) && (from == 0)) { + SetPageUptodate(page); + } + + /* + * Check to see if we can read page. + */ + else if ((file->f_flags & O_ACCMODE) != O_WRONLY) { + /* + * Get session. + */ + if (file->f_dentry && file->f_dentry->d_inode) { + if (file->f_dentry->d_inode->i_private) { + session = + novfs_scope_get_sessionId(((struct inode_data *) + inode-> + i_private)-> + Scope); + if (0 == SC_PRESENT(session)) { + ((struct inode_data *) inode-> + i_private)->Scope = + novfs_get_scope(file->f_dentry); + session = + novfs_scope_get_sessionId(((struct inode_data *) inode->i_private)->Scope); + } + } + } + + page_cache_get(page); + + len = i_size_read(inode) - offset; + if (len > PAGE_CACHE_SIZE) { + len = PAGE_CACHE_SIZE; + } + + if (len) { + /* + * Read page from server. + */ + + dllst[1].page = page; + dllst[1].offset = 0; + dllst[1].len = len; + dllst[1].rwflag = DLWRITE; + + DbgPrint("calling novfs_Read_Pages %lld", + offset); + novfs_read_pages(file->private_data, dllst, 2, + &len, &offset, session); + + /* + * Zero unnsed page. + */ + } + + if (len < PAGE_CACHE_SIZE) { + char *adr = kmap_atomic(page, KM_USER0); + memset(adr + len, 0, PAGE_CACHE_SIZE - len); + kunmap_atomic(adr, KM_USER0); + } + } else { + /* + * Zero section of memory that not going to be used. + */ + char *adr = kmap_atomic(page, KM_USER0); + memset(adr, 0, from); + memset(adr + to, 0, PAGE_CACHE_SIZE - to); + kunmap_atomic(adr, KM_USER0); + + DbgPrint("memset 0x%p", adr); + } + flush_dcache_page(page); + SetPageUptodate(page); + } +// DbgPrint("return %d", retVal); + return (retVal); +} + +int novfs_a_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) +{ + int retCode = 0; + struct inode *inode = page->mapping->host; + loff_t offset = pos; + struct novfs_schandle session; + struct inode_data *id; + struct novfs_data_list dlst[1]; + pgoff_t index; + unsigned from, to; + SC_INITIALIZE(session); + + index = pos >> PAGE_CACHE_SHIFT; + from = pos & (PAGE_CACHE_SIZE - 1); + to = from + len; + + + DbgPrint("File=0x%p Page=0x%p offset=0x%x To=%u filesize=%lld", + file, page, offset, to, i_size_read(file->f_dentry->d_inode)); + if (file->f_dentry->d_inode + && (id = file->f_dentry->d_inode->i_private)) { + session = novfs_scope_get_sessionId(id->Scope); + if (0 == SC_PRESENT(session)) { + id->Scope = novfs_get_scope(file->f_dentry); + session = novfs_scope_get_sessionId(id->Scope); + } + + /* + * Setup file handle + */ + id->FileHandle = file->private_data; + + if (pos > inode->i_size) { + i_size_write(inode, pos); + } + + if (!PageUptodate(page)) { + pos = + ((loff_t) page->index << PAGE_CACHE_SHIFT) + offset; + + if (to < offset) { + return (retCode); + } + dlst[0].page = page; + dlst[0].offset = (void *)(unsigned long) offset; + dlst[0].len = len; + dlst[0].rwflag = DLREAD; + + retCode = + novfs_write_pages(id->FileHandle, dlst, 1, len, pos, + session); + + } else { + set_page_dirty(page); + } + } + + return (retCode); +} + +/*++======================================================================*/ +ssize_t novfs_a_direct_IO(int rw, struct kiocb * kiocb, + const struct iovec * iov, + loff_t offset, unsigned long nr_segs) +/* + * + * Notes: This is a dummy function so that we can allow a file + * to get the direct IO flag set. novfs_f_read and + * novfs_f_write will do the work. Maybe not the best + * way to do but it was the easiest to implement. + * + *========================================================================*/ +{ + return (-EIO); +} + +/*++======================================================================*/ +int novfs_i_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) +{ + char *path, *buf; + struct novfs_entry_info info; + void *handle; + struct novfs_schandle session; + int retCode = -EACCES; + + DbgPrint("mode=0%o flags=0%o %.*s", mode, + nd->NDOPENFLAGS, dentry->d_name.len, dentry->d_name.name); + + if (IS_ROOT(dentry) || /* Root */ + IS_ROOT(dentry->d_parent) || /* User */ + IS_ROOT(dentry->d_parent->d_parent) || /* Server */ + IS_ROOT(dentry->d_parent->d_parent->d_parent)) { /* Volume */ + return (-EACCES); + } + + if (mode | S_IFREG) { + if (dir->i_private) { + session = + novfs_scope_get_sessionId(((struct inode_data *) dir->i_private)-> + Scope); + if (0 == SC_PRESENT(session)) { + ((struct inode_data *) dir->i_private)->Scope = + novfs_get_scope(dentry); + session = + novfs_scope_get_sessionId(((struct inode_data *) dir-> + i_private)->Scope); + } + + buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + path = + novfs_dget_path(dentry, buf, + PATH_LENGTH_BUFFER); + if (path) { + retCode = + novfs_open_file(path, + nd-> + NDOPENFLAGS | + O_RDWR, &info, + &handle, session); + if (!retCode && handle) { + novfs_close_file(handle, + session); + if (!novfs_i_mknod + (dir, dentry, + mode | S_IFREG, 0)) { + if (dentry->d_inode) { + ((struct inode_data *) + dentry-> + d_inode-> + i_private)-> + Flags |= UPDATE_INODE; + } + } + } + } + kfree(buf); + } + } + } + return (retCode); +} + +void update_inode(struct inode *Inode, struct novfs_entry_info *Info) +{ + static char dbuf[128]; + + DbgPrint("Inode=0x%p I_ino=%d", Inode, Inode->i_ino); + + DbgPrint("atime=%s", ctime_r(&Info->atime.tv_sec, dbuf)); + DbgPrint("ctime=%s", ctime_r(&Info->ctime.tv_sec, dbuf)); + DbgPrint("mtime=%s %d", ctime_r(&Info->mtime.tv_sec, dbuf), + Info->mtime.tv_nsec); + DbgPrint("size=%lld", Info->size); + DbgPrint("mode=0%o", Info->mode); + + if (Inode && + ((Inode->i_size != Info->size) || + (Inode->i_mtime.tv_sec != Info->mtime.tv_sec) || + (Inode->i_mtime.tv_nsec != Info->mtime.tv_nsec))) { + DbgPrint ("calling invalidate_remote_inode sz %d %d", + Inode->i_size, Info->size); + DbgPrint ("calling invalidate_remote_inode sec %d %d", + Inode->i_mtime.tv_sec, Info->mtime.tv_sec); + DbgPrint ("calling invalidate_remote_inode ns %d %d", + Inode->i_mtime.tv_nsec, Info->mtime.tv_nsec); + + if (Inode && Inode->i_mapping) { + invalidate_remote_inode(Inode); + } + } + + Inode->i_mode = Info->mode; + Inode->i_size = Info->size; + Inode->i_atime = Info->atime; + Inode->i_ctime = Info->ctime; + Inode->i_mtime = Info->mtime; + + if (Inode->i_size && Inode->i_sb->s_blocksize) { + Inode->i_blocks = + (unsigned long) (Info->size >> (loff_t) Inode->i_blkbits); + Inode->i_bytes = Info->size & (Inode->i_sb->s_blocksize - 1); + + DbgPrint("i_sb->s_blocksize=%d", Inode->i_sb->s_blocksize); + DbgPrint("i_blkbits=%d", Inode->i_blkbits); + DbgPrint("i_blocks=%d", Inode->i_blocks); + DbgPrint("i_bytes=%d", Inode->i_bytes); + } +} + +struct dentry *novfs_i_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +{ + struct dentry *retVal = ERR_PTR(-ENOENT); + struct dentry *parent; + struct novfs_entry_info *info = NULL; + struct inode_data *id; + struct inode *inode = NULL; + uid_t uid = current_euid(); + ino_t ino = 0; + struct qstr name; + char *buf; + + buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + char *path; + path = novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); + if (path) { + DbgPrint("dir 0x%p %d hash %d inode 0x%0p %s", + dir, dir->i_ino, dentry->d_name.hash, + dentry->d_inode, path); + } + kfree(buf); + } else { + DbgPrint("dir 0x%p %d name %.*s hash %d inode 0x%0p", + dir, dir->i_ino, dentry->d_name.len, dentry->d_name.name, + dentry->d_name.hash, dentry->d_inode); + } + + if ((dentry->d_name.len == 7) + && (0 == strncmp(dentry->d_name.name, " !xover", 7))) { + dentry->d_op = &novfs_dentry_operations; + igrab(dir); + d_add(dentry, dir); + return NULL; + } + if ((dentry->d_name.len == 7) + && (0 == strncmp(dentry->d_name.name, "z!xover", 7))) { + dentry->d_op = &novfs_dentry_operations; + igrab(dir); + d_add(dentry, dir); + return NULL; + } + + if (dir && (id = dir->i_private)) { + retVal = 0; + if (IS_ROOT(dentry)) { + DbgPrint("Root entry=0x%p", novfs_root); + inode = novfs_root->d_inode; + return (0); + } else { + info = + kmalloc(sizeof(struct novfs_entry_info) + + PATH_LENGTH_BUFFER, GFP_KERNEL); + if (info) { + if (NULL == + (retVal = + ERR_PTR(verify_dentry(dentry, 1)))) { + name.name = dentry->d_name.name; + name.len = dentry->d_name.len; + name.hash = novfs_internal_hash(&name); + + if (novfs_lock_inode_cache(dir)) { + if (!novfs_get_entry + (dir, &name, &ino, info)) { + inode = + ilookup(dentry-> + d_sb, ino); + if (inode) { + update_inode + (inode, + info); + } + } + novfs_unlock_inode_cache(dir); + } + + if (!inode && ino) { + uid = novfs_scope_get_uid(id->Scope); + if (novfs_lock_inode_cache(dir)) { + inode = novfs_get_inode (dentry->d_sb, info->mode, 0, uid, ino, &name); + if (inode) { + if (!novfs_get_entry(dir, &dentry->d_name, &ino, info)) { + update_inode + (inode, + info); + } + } + novfs_unlock_inode_cache + (dir); + } + } + } + } + } + } + + if (!retVal) { + dentry->d_op = &novfs_dentry_operations; + if (inode) { + parent = dget_parent(dentry); + novfs_d_add(dentry->d_parent, dentry, inode, 1); + dput(parent); + } else { + d_add(dentry, inode); + } + } + + if (info) + kfree(info); + + DbgPrint("inode=0x%p dentry->d_inode=0x%p return=0x%p", + dir, dentry->d_inode, retVal); + + return (retVal); +} + +int novfs_i_unlink(struct inode *dir, struct dentry *dentry) +{ + int retCode = -ENOENT; + struct inode *inode; + struct novfs_schandle session; + char *path, *buf; + uint64_t t64; + + DbgPrint("dir=0x%p dir->i_ino=%d %.*s", dir, + dir->i_ino, dentry->d_name.len, dentry->d_name.name); + DbgPrint("IS_ROOT(dentry)=%d", IS_ROOT(dentry)); + DbgPrint("IS_ROOT(dentry->d_parent)=%d", + IS_ROOT(dentry->d_parent)); + DbgPrint("IS_ROOT(dentry->d_parent->d_parent)=%d", + IS_ROOT(dentry->d_parent->d_parent)); + DbgPrint("IS_ROOT(dentry->d_parent->d_parent->d_parent)=%d", + IS_ROOT(dentry->d_parent->d_parent->d_parent)); + + if (IS_ROOT(dentry) || /* Root */ + IS_ROOT(dentry->d_parent) || /* User */ + (!IS_ROOT(dentry->d_parent->d_parent) && /* Server */ + IS_ROOT(dentry->d_parent->d_parent->d_parent))) { /* Volume */ + return (-EACCES); + } + + inode = dentry->d_inode; + if (inode) { + DbgPrint("dir=0x%p dir->i_ino=%d inode=0x%p ino=%d", + dir, dir->i_ino, inode, inode->i_ino); + if (inode->i_private) { + session = + novfs_scope_get_sessionId(((struct inode_data *) inode-> + i_private)->Scope); + if (0 == SC_PRESENT(session)) { + ((struct inode_data *) inode->i_private)->Scope = + novfs_get_scope(dentry); + session = + novfs_scope_get_sessionId(((struct inode_data *) inode-> + i_private)->Scope); + } + + buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + path = + novfs_dget_path(dentry, buf, + PATH_LENGTH_BUFFER); + if (path) { + DbgPrint("path %s mode 0%o", + path, inode->i_mode); + if (IS_ROOT(dentry->d_parent->d_parent)) { + retCode = novfs_daemon_logout(&dentry->d_name, &session); + } else { + retCode = + novfs_delete(path, + S_ISDIR(inode->i_mode), session); + if (retCode) { + struct iattr ia; + memset(&ia, 0, sizeof(ia)); + ia.ia_valid = ATTR_MODE; + ia.ia_mode = S_IRWXU; + novfs_set_attr(path, &ia, session); + retCode = novfs_delete(path, S_ISDIR(inode->i_mode), session); + } + } + if (!retCode || IS_DEADDIR(inode)) { + novfs_remove_inode_entry(dir, + &dentry-> + d_name, + 0); + dentry->d_time = 0; + t64 = 0; + novfs_scope_set_userspace(&t64, &t64, + &t64, &t64); + retCode = 0; + } + } + kfree(buf); + } + } + } + + DbgPrint("retCode 0x%x", retCode); + return (retCode); +} + +int novfs_i_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + char *path, *buf; + struct novfs_schandle session; + int retCode = 0; + struct inode *inode; + struct novfs_entry_info info; + uid_t uid; + + DbgPrint("dir=0x%p ino=%d dentry=0x%p %.*s mode=0%lo", + dir, dir->i_ino, dentry, dentry->d_name.len, + dentry->d_name.name, mode); + + if (IS_ROOT(dentry) || /* Root */ + IS_ROOT(dentry->d_parent) || /* User */ + IS_ROOT(dentry->d_parent->d_parent) || /* Server */ + IS_ROOT(dentry->d_parent->d_parent->d_parent)) { /* Volume */ + return (-EACCES); + } + + mode |= S_IFDIR; + mode &= (S_IFMT | S_IRWXU); + if (dir->i_private) { + session = + novfs_scope_get_sessionId(((struct inode_data *) dir->i_private)->Scope); + if (0 == SC_PRESENT(session)) { + ((struct inode_data *) dir->i_private)->Scope = + novfs_get_scope(dentry); + session = + novfs_scope_get_sessionId(((struct inode_data *) dir->i_private)-> + Scope); + } + + uid = novfs_scope_get_uid(((struct inode_data *) dir->i_private)->Scope); + buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + path = novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); + if (path) { + DbgPrint("path %s", path); + retCode = + novfs_create(path, S_ISDIR(mode), session); + if (!retCode) { + retCode = + novfs_get_file_info(path, &info, + session); + if (!retCode) { + retCode = + novfs_i_mknod(dir, dentry, + mode, 0); + inode = dentry->d_inode; + if (inode) { + update_inode(inode, + &info); + ((struct inode_data *) inode-> + i_private)->Flags &= + ~UPDATE_INODE; + + dentry->d_time = + jiffies + + (novfs_update_timeout + * HZ); + + novfs_lock_inode_cache + (dir); + if (novfs_update_entry + (dir, + &dentry->d_name, 0, + &info)) { + novfs_add_inode_entry + (dir, + &dentry-> + d_name, + inode-> + i_ino, + &info); + } + novfs_unlock_inode_cache + (dir); + } + + } + } + } + kfree(buf); + } + } + + return (retCode); +} + +int novfs_i_rmdir(struct inode *inode, struct dentry *dentry) +{ + return (novfs_i_unlink(inode, dentry)); +} + +int novfs_i_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +{ + struct inode *inode = NULL; + int retCode = -EACCES; + uid_t uid; + struct dentry *parent; + + if (IS_ROOT(dentry) || /* Root */ + IS_ROOT(dentry->d_parent) || /* User */ + IS_ROOT(dentry->d_parent->d_parent) || /* Server */ + IS_ROOT(dentry->d_parent->d_parent->d_parent)) { /* Volume */ + return (-EACCES); + } + + if (((struct inode_data *) dir->i_private)) { + uid = novfs_scope_get_uid(((struct inode_data *) dir->i_private)->Scope); + if (mode & (S_IFREG | S_IFDIR)) { + inode = + novfs_get_inode(dir->i_sb, mode, dev, uid, 0, &dentry->d_name); + } + } + if (inode) { + struct novfs_entry_info info; + + dentry->d_op = &novfs_dentry_operations; + parent = dget_parent(dentry); + novfs_d_add(parent, dentry, inode, 0); + memset(&info, 0, sizeof(info)); + info.mode = inode->i_mode; + novfs_lock_inode_cache(dir); + novfs_add_inode_entry(dir, &dentry->d_name, inode->i_ino, + &info); + novfs_unlock_inode_cache(dir); + + dput(parent); + + retCode = 0; + } + DbgPrint("return 0x%x", retCode); + return retCode; +} + +int novfs_i_rename(struct inode *odir, struct dentry *od, struct inode *ndir, + struct dentry *nd) +{ + int retCode = -ENOTEMPTY; + char *newpath, *newbuf, *newcon; + char *oldpath, *oldbuf, *oldcon; + struct qstr newname, oldname; + struct novfs_entry_info *info = NULL; + int oldlen, newlen; + struct novfs_schandle session; + ino_t ino; + + if (IS_ROOT(od) || /* Root */ + IS_ROOT(od->d_parent) || /* User */ + IS_ROOT(od->d_parent->d_parent) || /* Server */ + IS_ROOT(od->d_parent->d_parent->d_parent)) { /* Volume */ + return (-EACCES); + } + + DbgPrint("odir=0x%p ino=%d ndir=0x%p ino=%d", odir, + odir->i_ino, ndir, ndir->i_ino); + + oldbuf = kmalloc(PATH_LENGTH_BUFFER * 2, GFP_KERNEL); + newbuf = oldbuf + PATH_LENGTH_BUFFER; + if (oldbuf && newbuf) { + oldpath = novfs_dget_path(od, oldbuf, PATH_LENGTH_BUFFER); + newpath = novfs_dget_path(nd, newbuf, PATH_LENGTH_BUFFER); + if (oldpath && newpath) { + oldlen = PATH_LENGTH_BUFFER - (int)(oldpath - oldbuf); + newlen = PATH_LENGTH_BUFFER - (int)(newpath - newbuf); + + DbgPrint("od=0x%p od->inode=0x%p od->inode->i_ino=%d %s", + od, od->d_inode, od->d_inode->i_ino, oldpath); + if (nd->d_inode) { + DbgPrint("nd=0x%p nd->inode=0x%p nd->inode->i_ino=%d %s", + nd, nd->d_inode, nd->d_inode->i_ino, + newpath); + } else { + DbgPrint("nd=0x%p nd->inode=0x%p %s", + nd, nd->d_inode, newpath); + } + + /* + * Check to see if two different servers or different volumes + */ + newcon = strchr(newpath + 1, '\\'); + oldcon = strchr(oldpath + 1, '\\'); + DbgPrint("newcon=0x%p newpath=0x%p", newcon, newpath); + DbgPrint("oldcon=0x%p oldpath=0x%p", oldcon, oldpath); + retCode = -EXDEV; + if (newcon && oldcon + && ((int)(newcon - newpath) == + (int)(oldcon - oldpath))) { + newcon = strchr(newcon + 1, '\\'); + oldcon = strchr(oldcon + 1, '\\'); + DbgPrint("2; newcon=0x%p newpath=0x%p", + newcon, newpath); + DbgPrint("2; oldcon=0x%p oldpath=0x%p", + oldcon, oldpath); + if (newcon && oldcon && + ((int)(newcon - newpath) == (int)(oldcon - oldpath))) { + newname.name = newpath; + newname.len = (int)(newcon - newpath); + newname.hash = 0; + + oldname.name = oldpath; + oldname.len = (int)(oldcon - oldpath); + oldname.hash = 0; + if (!novfs_d_strcmp(&newname, &oldname)) { + + if (od->d_inode + && od->d_inode->i_private) { + + if (nd->d_inode + && nd->d_inode-> + i_private) { + session = + novfs_scope_get_sessionId + (((struct inode_data *) ndir->i_private)->Scope); + if (0 == + SC_PRESENT + (session)) { + ((struct inode_data *) ndir->i_private)->Scope = novfs_get_scope(nd); + session + = + novfs_scope_get_sessionId + (((struct inode_data *) ndir->i_private)->Scope); + } + + retCode = + novfs_delete(newpath, S_ISDIR(nd->d_inode->i_mode), session); + if (retCode) { + struct iattr ia; + memset(&ia, 0, sizeof(ia)); + ia.ia_valid = ATTR_MODE; + ia.ia_mode = S_IRWXU; + novfs_set_attr(newpath, &ia, session); + retCode = novfs_delete(newpath, S_ISDIR(nd->d_inode->i_mode), session); + } + + } + + session = novfs_scope_get_sessionId(((struct inode_data *) ndir->i_private)->Scope); + if (0 == SC_PRESENT(session)) { + ((struct inode_data *)ndir->i_private)->Scope = novfs_get_scope(nd); + session = novfs_scope_get_sessionId(((struct inode_data *) ndir->i_private)->Scope); + } + retCode = novfs_rename_file(S_ISDIR(od->d_inode->i_mode), oldpath, oldlen - 1, newpath, newlen - 1, session); + + if (!retCode) { + info = (struct novfs_entry_info *) oldbuf; + od->d_time = 0; + novfs_remove_inode_entry(odir, &od->d_name, 0); + novfs_remove_inode_entry(ndir, &nd->d_name, 0); + novfs_get_file_info(newpath, info, session); + nd->d_time = jiffies + (novfs_update_timeout * HZ); + + if (od->d_inode && od->d_inode->i_ino) { + ino = od->d_inode-> i_ino; + } else { + ino = (ino_t)atomic_inc_return(&novfs_Inode_Number); + } + novfs_add_inode_entry(ndir, &nd->d_name, ino, info); + } + } + } + } + } + } + } + + if (oldbuf) + kfree(oldbuf); + + DbgPrint("return %d", retCode); + return (retCode); +} + + +int novfs_i_setattr(struct dentry *dentry, struct iattr *attr) +{ + char *path, *buf; + struct inode *inode = dentry->d_inode; + char atime_buf[32]; + char mtime_buf[32]; + char ctime_buf[32]; + unsigned int ia_valid = attr->ia_valid; + struct novfs_schandle session; + int retVal = 0; + struct iattr mattr; + + if (IS_ROOT(dentry) || /* Root */ + IS_ROOT(dentry->d_parent) || /* User */ + IS_ROOT(dentry->d_parent->d_parent) || /* Server */ + IS_ROOT(dentry->d_parent->d_parent->d_parent)) { /* Volume */ + return (-EACCES); + } + + if (inode && inode->i_private) { + session = + novfs_scope_get_sessionId(((struct inode_data *) inode->i_private)-> + Scope); + if (0 == SC_PRESENT(session)) { + ((struct inode_data *) inode->i_private)->Scope = + novfs_get_scope(dentry); + session = + novfs_scope_get_sessionId(((struct inode_data *) inode-> + i_private)->Scope); + } + + buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + path = novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); + if (path) { + strcpy(atime_buf, "Unspecified"); + strcpy(mtime_buf, "Unspecified"); + strcpy(ctime_buf, "Unspecified"); + if (attr->ia_valid & ATTR_ATIME) { + ctime_r(&attr->ia_atime.tv_sec, + atime_buf); + } + if (attr->ia_valid & ATTR_MTIME) { + ctime_r(&attr->ia_mtime.tv_sec, + mtime_buf); + } + if (attr->ia_valid & ATTR_CTIME) { + ctime_r(&attr->ia_ctime.tv_sec, + ctime_buf); + } + /* Removed for Bug 132374. jlt */ + __DbgPrint("%s: %s\n" + " ia_valid: 0x%x\n" + " ia_mode: 0%o\n" + " ia_uid: %d\n" + " ia_gid: %d\n" + " ia_size: %lld\n" + " ia_atime: %s\n" + " ia_mtime: %s\n" + " ia_ctime: %s\n", __func__, + path, + attr->ia_valid, + attr->ia_mode, + attr->ia_uid, + attr->ia_gid, + attr->ia_size, + atime_buf, mtime_buf, ctime_buf); + + if ((attr->ia_valid & ATTR_FILE) + && (attr->ia_valid & ATTR_SIZE)) { + memcpy(&mattr, attr, sizeof(mattr)); + mattr.ia_valid &= + ~(ATTR_FILE | ATTR_SIZE); + attr = &mattr; + ia_valid = attr->ia_valid; +#if 0 // thanks to vfs changes in our tree... + retVal = + novfs_trunc_ex(attr-> + ia_file-> + private_data, + attr-> + ia_size, + session); + if (!retVal) { + inode->i_size = attr->ia_size; + ((struct inode_data *) inode-> + i_private)->Flags |= + UPDATE_INODE; + } +#endif + } + + if (ia_valid + && !(retVal = + novfs_set_attr(path, attr, session))) { + ((struct inode_data *) inode->i_private)-> + Flags |= UPDATE_INODE; + + if (ia_valid & ATTR_ATIME) + inode->i_atime = attr->ia_atime; + if (ia_valid & ATTR_MTIME) + inode->i_mtime = attr->ia_mtime; + if (ia_valid & ATTR_CTIME) + inode->i_ctime = attr->ia_ctime; + if (ia_valid & ATTR_MODE) { + inode->i_mode = + attr-> + ia_mode & (S_IFMT | + S_IRWXU); + } + } + } + } + kfree(buf); + } + DbgPrint("return 0x%x", retVal); + + return (retVal); +} + +int novfs_i_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *kstat) +{ + int retCode = 0; + char atime_buf[32]; + char mtime_buf[32]; + char ctime_buf[32]; + struct inode *inode = dentry->d_inode; + + struct novfs_entry_info info; + char *path, *buf; + struct novfs_schandle session; + struct inode_data *id; + + if (!IS_ROOT(dentry) && !IS_ROOT(dentry->d_parent)) { + SC_INITIALIZE(session); + id = dentry->d_inode->i_private; + + if (id && (id->Flags & UPDATE_INODE)) { + session = novfs_scope_get_sessionId(id->Scope); + + if (0 == SC_PRESENT(session)) { + id->Scope = novfs_get_scope(dentry); + session = novfs_scope_get_sessionId(id->Scope); + } + + buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + path = + novfs_dget_path(dentry, buf, + PATH_LENGTH_BUFFER); + if (path) { + retCode = + novfs_get_file_info(path, &info, + session); + if (!retCode) { + update_inode(inode, &info); + id->Flags &= ~UPDATE_INODE; + } + } + kfree(buf); + } + } + } + + kstat->ino = inode->i_ino; + kstat->dev = inode->i_sb->s_dev; + kstat->mode = inode->i_mode; + kstat->nlink = inode->i_nlink; + kstat->uid = inode->i_uid; + kstat->gid = inode->i_gid; + kstat->rdev = inode->i_rdev; + kstat->size = i_size_read(inode); + kstat->atime = inode->i_atime; + kstat->mtime = inode->i_mtime; + kstat->ctime = inode->i_ctime; + kstat->blksize = inode->i_sb->s_blocksize; + kstat->blocks = inode->i_blocks; + if (inode->i_bytes) { + kstat->blocks++; + } + ctime_r(&kstat->atime.tv_sec, atime_buf); + ctime_r(&kstat->mtime.tv_sec, mtime_buf); + ctime_r(&kstat->ctime.tv_sec, ctime_buf); + + __DbgPrint("%s: 0x%x 0x%p <%.*s>\n" + " ino: %d\n" + " dev: 0x%x\n" + " mode: 0%o\n" + " nlink: 0x%x\n" + " uid: 0x%x\n" + " gid: 0x%x\n" + " rdev: 0x%x\n" + " size: 0x%llx\n" + " atime: %s\n" + " mtime: %s\n" + " ctime: %s\n" + " blksize: 0x%x\n" + " blocks: 0x%x\n", __func__, + retCode, dentry, dentry->d_name.len, dentry->d_name.name, + kstat->ino, + kstat->dev, + kstat->mode, + kstat->nlink, + kstat->uid, + kstat->gid, + kstat->rdev, + kstat->size, + atime_buf, + mtime_buf, ctime_buf, kstat->blksize, kstat->blocks); + return (retCode); +} + +ssize_t novfs_i_getxattr(struct dentry *dentry, const char *name, void *buffer, + size_t buffer_size) +{ + struct inode *inode = dentry->d_inode; + struct novfs_schandle sessionId; + char *path, *buf, *bufRead; + ssize_t dataLen; + + int retxcode = 0; + + SC_INITIALIZE(sessionId); + + DbgPrint("Ian"); /*%.*s\n", dentry->d_name.len, dentry->d_name.name); */ + DbgPrint("dentry->d_name.len %u, dentry->d_name.name %s", + dentry->d_name.len, dentry->d_name.name); + DbgPrint("name %s", name); + DbgPrint("size %u", buffer_size); + + if (inode && inode->i_private) { + sessionId = + novfs_scope_get_sessionId(((struct inode_data *) inode->i_private)-> + Scope); + DbgPrint("SessionId = %u", sessionId); + //if (0 == sessionId) + if (0 == SC_PRESENT(sessionId)) { + ((struct inode_data *) inode->i_private)->Scope = + novfs_get_scope(dentry); + sessionId = + novfs_scope_get_sessionId(((struct inode_data *) inode-> + i_private)->Scope); + DbgPrint("SessionId = %u", sessionId); + } + } + + dataLen = 0; + buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + path = novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); + if (path) { + bufRead = kmalloc(XA_BUFFER, GFP_KERNEL); + if (bufRead) { + retxcode = + novfs_getx_file_info(path, name, bufRead, + XA_BUFFER, &dataLen, + sessionId); + DbgPrint("after novfs_GetX_File_Info retxcode = %d", + retxcode); + if (!retxcode) { + novfs_dump(64, bufRead); + if (buffer_size != 0) { + if (buffer_size >= dataLen) { + memcpy(buffer, bufRead, + dataLen); + } else { + DbgPrint("(!!!) not enough buffer_size. buffer_size = %d, dataLen = %d", + buffer_size, + dataLen); + retxcode = -ERANGE; + } + } + + if (bufRead) { + kfree(bufRead); + } + } + } + } + kfree(buf); + } + + if (retxcode) { + dataLen = retxcode; + } else { + if ((buffer_size > 0) && (buffer_size < dataLen)) { + dataLen = -ERANGE; + } + } + + return (dataLen); +} + +int novfs_i_setxattr(struct dentry *dentry, const char *name, const void *value, + size_t value_size, int flags) +{ + + struct inode *inode = dentry->d_inode; + struct novfs_schandle sessionId; + char *path, *buf; + unsigned long bytesWritten = 0; + int retError = 0; + int retxcode = 0; + + SC_INITIALIZE(sessionId); + + DbgPrint("Ian"); /*%.*s\n", dentry->d_name.len, dentry->d_name.name); */ + DbgPrint("dentry->d_name.len %u, dentry->d_name.name %s", + dentry->d_name.len, dentry->d_name.name); + DbgPrint("name %s", name); + DbgPrint("value_size %u", value_size); + DbgPrint("flags %d", flags); + + if (inode && inode->i_private) { + sessionId = + novfs_scope_get_sessionId(((struct inode_data *) inode->i_private)-> + Scope); + DbgPrint("SessionId = %u", sessionId); + //if (0 == sessionId) + if (0 == SC_PRESENT(sessionId)) { + ((struct inode_data *) inode->i_private)->Scope = + novfs_get_scope(dentry); + sessionId = + novfs_scope_get_sessionId(((struct inode_data *) inode-> + i_private)->Scope); + DbgPrint("SessionId = %u", sessionId); + } + } + + buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + path = novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); + if (path) { + retxcode = + novfs_setx_file_info(path, name, value, value_size, + &bytesWritten, flags, + sessionId); + if (!retxcode) { + DbgPrint("bytesWritten = %u", bytesWritten); + } + } + kfree(buf); + } + + if (retxcode) { + retError = retxcode; + } + + if (bytesWritten < value_size) { + retError = retxcode; + } + return (retError); +} + +ssize_t novfs_i_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) +{ + struct inode *inode = dentry->d_inode; + struct novfs_schandle sessionId; + char *path, *buf, *bufList; + ssize_t dataLen; + int retxcode = 0; + + SC_INITIALIZE(sessionId); + + DbgPrint("Ian"); //%.*s\n", dentry->d_name.len, dentry->d_name.name); + DbgPrint("dentry->d_name.len %u, dentry->d_name.name %s", + dentry->d_name.len, dentry->d_name.name); + DbgPrint("size %u", buffer_size); + + if (inode && inode->i_private) { + sessionId = + novfs_scope_get_sessionId(((struct inode_data *) inode->i_private)-> + Scope); + DbgPrint("SessionId = %u", sessionId); + //if (0 == sessionId) + if (0 == SC_PRESENT(sessionId)) { + ((struct inode_data *) inode->i_private)->Scope = + novfs_get_scope(dentry); + sessionId = + novfs_scope_get_sessionId(((struct inode_data *) inode-> + i_private)->Scope); + DbgPrint("SessionId = %u", sessionId); + } + } + + dataLen = 0; + buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + path = novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); + if (path) { + bufList = kmalloc(XA_BUFFER, GFP_KERNEL); + if (bufList) { + retxcode = + novfs_listx_file_info(path, bufList, + XA_BUFFER, &dataLen, + sessionId); + + novfs_dump(64, bufList); + if (buffer_size != 0) { + if (buffer_size >= dataLen) { + memcpy(buffer, bufList, + dataLen); + } else { + DbgPrint("(!!!) not enough buffer_size. buffer_size = %d, dataLen = %d", + buffer_size, dataLen); + retxcode = -1; + } + } + + if (bufList) { + kfree(bufList); + } + } + + } + kfree(buf); + } + + if (retxcode) { + dataLen = -1; + } else { + + if ((buffer_size > 0) && (buffer_size < dataLen)) { + dataLen = -ERANGE; + } + } + return (dataLen); +} + +int novfs_i_revalidate(struct dentry *dentry) +{ + + DbgPrint("name %.*s", dentry->d_name.len, dentry->d_name.name); + + return (0); +} + +void novfs_read_inode(struct inode *inode) +{ + DbgPrint("0x%p %d", inode, inode->i_ino); +} + +void novfs_write_inode(struct inode *inode) +{ + DbgPrint("Inode=0x%p Ino=%d", inode, inode->i_ino); +} + +int novfs_notify_change(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + + DbgPrint("Dentry=0x%p Name=%.*s Inode=0x%p Ino=%d ia_valid=0x%x", + dentry, dentry->d_name.len, dentry->d_name.name, inode, + inode->i_ino, attr->ia_valid); + return (0); +} + +void novfs_clear_inode(struct inode *inode) +{ + InodeCount--; + + if (inode->i_private) { + struct inode_data *id = inode->i_private; + + DbgPrint("inode=0x%p ino=%d Scope=0x%p Name=%s", + inode, inode->i_ino, id->Scope, id->Name); + + novfs_free_inode_cache(inode); + + down(&InodeList_lock); + list_del(&id->IList); + up(&InodeList_lock); + + kfree(inode->i_private); + inode->i_private = NULL; + + remove_inode_hash(inode); + + } else { + DbgPrint("inode=0x%p ino=%d", inode, inode->i_ino); + } +} + +/* Called when /proc/mounts is read */ +int novfs_show_options(struct seq_file *s, struct vfsmount *m) +{ + char *buf, *path, *tmp; + + buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + struct path my_path; + my_path.mnt = m; + my_path.dentry = m->mnt_root; + path = d_path(&my_path, buf, PATH_LENGTH_BUFFER); + if (path) { + if (!novfs_current_mnt + || (novfs_current_mnt + && strcmp(novfs_current_mnt, path))) { + DbgPrint("%.*s %.*s %s", + m->mnt_root->d_name.len, + m->mnt_root->d_name.name, + m->mnt_mountpoint->d_name.len, + m->mnt_mountpoint->d_name.name, path); + tmp = kmalloc(PATH_LENGTH_BUFFER - + (int)(path - buf), + GFP_KERNEL); + if (tmp) { + strcpy(tmp, path); + path = novfs_current_mnt; + novfs_current_mnt = tmp; + novfs_daemon_set_mnt_point(novfs_current_mnt); + + if (path) { + kfree(path); + } + } + } + } + kfree(buf); + } + return (0); +} + +/* Called when statfs(2) system called. */ +int novfs_statfs(struct dentry *de, struct kstatfs *buf) +{ + uint64_t td, fd, te, fe; + struct super_block *sb = de->d_sb; + + DbgPrint(""); + + td = fd = te = fe = 0; + + novfs_scope_get_userspace(&td, &fd, &te, &fe); + + DbgPrint("td=%llu", td); + DbgPrint("fd=%llu", fd); + DbgPrint("te=%llu", te); + DbgPrint("fe=%llu", fd); + /* fix for Nautilus */ + if (sb->s_blocksize == 0) + sb->s_blocksize = 4096; + + buf->f_type = sb->s_magic; + buf->f_bsize = sb->s_blocksize; + buf->f_namelen = NW_MAX_PATH_LENGTH; + buf->f_blocks = + (sector_t) (td + + (uint64_t) (sb->s_blocksize - + 1)) >> (uint64_t) sb->s_blocksize_bits; + buf->f_bfree = (sector_t) fd >> (uint64_t) sb->s_blocksize_bits; + buf->f_bavail = (sector_t) buf->f_bfree; + buf->f_files = (sector_t) te; + buf->f_ffree = (sector_t) fe; + buf->f_frsize = sb->s_blocksize; + if (te > 0xffffffff) + buf->f_files = 0xffffffff; + + if (fe > 0xffffffff) + buf->f_ffree = 0xffffffff; + + DbgPrint("f_type: 0x%x", buf->f_type); + DbgPrint("f_bsize: %u", buf->f_bsize); + DbgPrint("f_namelen: %d", buf->f_namelen); + DbgPrint("f_blocks: %llu", buf->f_blocks); + DbgPrint("f_bfree: %llu", buf->f_bfree); + DbgPrint("f_bavail: %llu", buf->f_bavail); + DbgPrint("f_files: %llu", buf->f_files); + DbgPrint("f_ffree: %llu", buf->f_ffree); + DbgPrint("f_frsize: %u", buf->f_frsize); + + return 0; +} + +struct inode *novfs_get_inode(struct super_block *sb, int mode, int dev, + uid_t Uid, ino_t ino, struct qstr *name) +{ + struct inode *inode = new_inode(sb); + + if (inode) { + InodeCount++; + inode->i_mode = mode; + inode->i_uid = Uid; + inode->i_gid = 0; + inode->i_blkbits = sb->s_blocksize_bits; + inode->i_blocks = 0; + inode->i_rdev = 0; + inode->i_ino = (ino) ? ino : (ino_t)atomic_inc_return(&novfs_Inode_Number); + if (novfs_page_cache) { + inode->i_mapping->a_ops = &novfs_aops; + } else { + inode->i_mapping->a_ops = &novfs_nocache_aops; + } + inode->i_mapping->backing_dev_info = &novfs_backing_dev_info; + inode->i_atime.tv_sec = 0; + inode->i_atime.tv_nsec = 0; + inode->i_mtime = inode->i_ctime = inode->i_atime; + + DbgPrint("Inode=0x%p I_ino=%d len=%d", + inode, inode->i_ino, name->len); + + if (NULL != + (inode->i_private = + kmalloc(sizeof(struct inode_data) + name->len, + GFP_KERNEL))) { + struct inode_data *id; + id = inode->i_private; + + DbgPrint("i_private 0x%p", id); + + id->Scope = NULL; + id->Flags = 0; + id->Inode = inode; + + id->cntDC = 1; + + INIT_LIST_HEAD(&id->DirCache); + init_MUTEX(&id->DirCacheLock); + + id->FileHandle = 0; + id->CacheFlag = 0; + + down(&InodeList_lock); + + list_add_tail(&id->IList, &InodeList); + up(&InodeList_lock); + + id->Name[0] = '\0'; + + memcpy(id->Name, name->name, name->len); + id->Name[name->len] = '\0'; + + DbgPrint("name %s", id->Name); + } + + insert_inode_hash(inode); + + switch (mode & S_IFMT) { + + case S_IFREG: + inode->i_op = &novfs_file_inode_operations; + inode->i_fop = &novfs_file_operations; + break; + + case S_IFDIR: + inode->i_op = &novfs_inode_operations; + inode->i_fop = &novfs_dir_operations; + inode->i_blkbits = 0; + break; + + default: + init_special_inode(inode, mode, dev); + break; + } + + DbgPrint("size=%lld", inode->i_size); + DbgPrint("mode=0%o", inode->i_mode); + DbgPrint("i_sb->s_blocksize=%d", inode->i_sb->s_blocksize); + DbgPrint("i_blkbits=%d", inode->i_blkbits); + DbgPrint("i_blocks=%d", inode->i_blocks); + DbgPrint("i_bytes=%d", inode->i_bytes); + } + + DbgPrint("0x%p %d", inode, inode->i_ino); + return (inode); +} + +int novfs_fill_super(struct super_block *SB, void *Data, int Silent) +{ + struct inode *inode; + struct dentry *server, *tree; + struct qstr name; + struct novfs_entry_info info; + + SB->s_blocksize = PAGE_CACHE_SIZE; + SB->s_blocksize_bits = PAGE_CACHE_SHIFT; + SB->s_maxbytes = 0xFFFFFFFFFFFFFFFFULL; /* Max file size */ + SB->s_op = &novfs_ops; + SB->s_flags |= (MS_NODIRATIME | MS_NODEV | MS_POSIXACL); + SB->s_magic = NOVFS_MAGIC; + + name.len = 1; + name.name = "/"; + + inode = novfs_get_inode(SB, S_IFDIR | 0777, 0, 0, 0, &name); + if (!inode) { + return (-ENOMEM); + } + + novfs_root = d_alloc_root(inode); + + if (!novfs_root) { + iput(inode); + return (-ENOMEM); + } + novfs_root->d_time = jiffies + (novfs_update_timeout * HZ); + + inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; + + SB->s_root = novfs_root; + + DbgPrint("root 0x%p", novfs_root); + + if (novfs_root) { + novfs_root->d_op = &novfs_dentry_operations; + + name.name = SERVER_DIRECTORY_NAME; + name.len = strlen(SERVER_DIRECTORY_NAME); + name.hash = novfs_internal_hash(&name); + + inode = novfs_get_inode(SB, S_IFDIR | 0777, 0, 0, 0, &name); + if (inode) { + info.mode = inode->i_mode; + info.namelength = 0; + inode->i_size = info.size = 0; + inode->i_uid = info.uid = 0; + inode->i_gid = info.gid = 0; + inode->i_atime = info.atime = + inode->i_ctime = info.ctime = + inode->i_mtime = info.mtime = CURRENT_TIME; + + server = d_alloc(novfs_root, &name); + if (server) { + server->d_op = &novfs_dentry_operations; + server->d_time = 0xffffffff; + d_add(server, inode); + DbgPrint("d_add %s 0x%p", + SERVER_DIRECTORY_NAME, server); + novfs_add_inode_entry(novfs_root->d_inode, + &name, inode->i_ino, + &info); + } + } + + name.name = TREE_DIRECTORY_NAME; + name.len = strlen(TREE_DIRECTORY_NAME); + name.hash = novfs_internal_hash(&name); + + inode = novfs_get_inode(SB, S_IFDIR | 0777, 0, 0, 0, &name); + if (inode) { + info.mode = inode->i_mode; + info.namelength = 0; + inode->i_size = info.size = 0; + inode->i_uid = info.uid = 0; + inode->i_gid = info.gid = 0; + inode->i_atime = info.atime = + inode->i_ctime = info.ctime = + inode->i_mtime = info.mtime = CURRENT_TIME; + tree = d_alloc(novfs_root, &name); + if (tree) { + tree->d_op = &novfs_dentry_operations; + tree->d_time = 0xffffffff; + + d_add(tree, inode); + DbgPrint("d_add %s 0x%p", + TREE_DIRECTORY_NAME, tree); + novfs_add_inode_entry(novfs_root->d_inode, + &name, inode->i_ino, + &info); + } + } + } + + return (0); +} + +static int novfs_get_sb(struct file_system_type *Fstype, int Flags, + const char *Dev_name, void *Data, struct vfsmount *Mnt) +{ + DbgPrint("Fstype=0x%x Dev_name=%s", Fstype, Dev_name); + return get_sb_nodev(Fstype, Flags, Data, novfs_fill_super, Mnt); +} + +static void novfs_kill_sb(struct super_block *super) +{ + shrink_dcache_sb(super); + kill_litter_super(super); +} + +ssize_t novfs_Control_read(struct file *file, char *buf, size_t nbytes, + loff_t * ppos) +{ + ssize_t retval = 0; + + DbgPrint("kernel_locked 0x%x", kernel_locked()); + + return retval; +} + +ssize_t novfs_Control_write(struct file * file, const char *buf, size_t nbytes, + loff_t * ppos) +{ + ssize_t retval = 0; + + DbgPrint("kernel_locked 0x%x", kernel_locked()); + if (buf && nbytes) { + } + + return (retval); +} + +int novfs_Control_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int retval = 0; + + DbgPrint("kernel_locked 0x%x", kernel_locked()); + + return (retval); +} + +static struct file_system_type novfs_fs_type = { + .name = "novfs", + .get_sb = novfs_get_sb, + .kill_sb = novfs_kill_sb, + .owner = THIS_MODULE, +}; + +int __init init_novfs(void) +{ + int retCode; + + lastDir[0] = 0; + lastTime = get_nanosecond_time(); + + inHAX = 0; + inHAXTime = get_nanosecond_time(); + + retCode = novfs_proc_init(); + + novfs_profile_init(); + + if (!retCode) { + DbgPrint("%s %s %s", __DATE__, __TIME__, NOVFS_VERSION_STRING); + novfs_daemon_queue_init(); + novfs_scope_init(); + retCode = register_filesystem(&novfs_fs_type); + if (retCode) { + novfs_proc_exit(); + novfs_daemon_queue_exit(); + novfs_scope_exit(); + } + } + return (retCode); +} + +void __exit exit_novfs(void) +{ + novfs_scope_exit(); + novfs_daemon_queue_exit(); + novfs_profile_exit(); + novfs_proc_exit(); + unregister_filesystem(&novfs_fs_type); + + if (novfs_current_mnt) { + kfree(novfs_current_mnt); + novfs_current_mnt = NULL; + } +} + +int novfs_lock_inode_cache(struct inode *i) +{ + struct inode_data *id; + int retVal = 0; + + DbgPrint("0x%p", i); + if (i && (id = i->i_private) && id->DirCache.next) { + down(&id->DirCacheLock); + retVal = 1; + } + DbgPrint("return %d", retVal); + return (retVal); +} + +void novfs_unlock_inode_cache(struct inode *i) +{ + struct inode_data *id; + + if (i && (id = i->i_private) && id->DirCache.next) { + up(&id->DirCacheLock); + } +} + +int novfs_enumerate_inode_cache(struct inode *i, struct list_head **iteration, + ino_t * ino, struct novfs_entry_info *info) +/* + * Arguments: struct inode *i - pointer to directory inode + * + * Returns: 0 - item found + * -1 - done + * + * Abstract: Unlocks inode cache. + * + * Notes: DirCacheLock should be held before calling this routine. + *========================================================================*/ +{ + struct inode_data *id; + struct novfs_dir_cache *dc; + struct list_head *l = NULL; + int retVal = -1; + + if (i && (id = i->i_private) && id->DirCache.next) { + if ((NULL == iteration) || (NULL == *iteration)) { + l = id->DirCache.next; + } else { + l = *iteration; + } + + if (l == &id->DirCache) { + l = NULL; + } else { + dc = list_entry(l, struct novfs_dir_cache, list); + + *ino = dc->ino; + info->type = 0; + info->mode = dc->mode; + info->size = dc->size; + info->atime = dc->atime; + info->mtime = dc->mtime; + info->ctime = dc->ctime; + info->namelength = dc->nameLen; + memcpy(info->name, dc->name, dc->nameLen); + info->name[dc->nameLen] = '\0'; + retVal = 0; + + l = l->next; + } + } + *iteration = l; + return (retVal); +} + +/* DirCacheLock should be held before calling this routine. */ +int novfs_get_entry(struct inode *i, struct qstr *name, ino_t * ino, + struct novfs_entry_info *info) +{ + struct inode_data *id; + struct novfs_dir_cache *dc; + int retVal = -1; + char *n = ""; + int nl = 6; + + if (i && (id = i->i_private) && id->DirCache.next) { + if (name && name->len) { + n = (char *)name->name; + nl = name->len; + } + + dc = novfs_lookup_inode_cache(i, name, *ino); + if (dc) { + dc->flags |= ENTRY_VALID; + retVal = 0; + *ino = dc->ino; + info->type = 0; + info->mode = dc->mode; + info->size = dc->size; + info->atime = dc->atime; + info->mtime = dc->mtime; + info->ctime = dc->ctime; + info->namelength = dc->nameLen; + memcpy(info->name, dc->name, dc->nameLen); + info->name[dc->nameLen] = '\0'; + retVal = 0; + } + + DbgPrint("inode: 0x%p; name: %.*s; ino: %d\n", i, nl, n, *ino); + } + DbgPrint("return %d", retVal); + return (retVal); +} + + /*DirCacheLock should be held before calling this routine. */ +int novfs_get_entry_by_pos(struct inode *i, loff_t pos, ino_t * ino, + struct novfs_entry_info *info) +{ + int retVal = -1; + loff_t count = 0; + loff_t i_pos = pos - 2; + struct list_head *inter = NULL; + while (!novfs_enumerate_inode_cache(i, &inter, ino, info)) { + DbgPrint("info->name = %s", info->name); + if (count == i_pos) { + retVal = 0; + break; + } else + count++; + } + + return retVal; +} + +/* DirCacheLock should be held before calling this routine. */ +int novfs_get_entry_time(struct inode *i, struct qstr *name, ino_t * ino, + struct novfs_entry_info *info, u64 * EntryTime) +{ + struct inode_data *id; + struct novfs_dir_cache *dc; + int retVal = -1; + char *n = ""; + int nl = 6; + + if (i && (id = i->i_private) && id->DirCache.next) { + if (name && name->len) { + n = (char *)name->name; + nl = name->len; + } + DbgPrint("inode: 0x%p; name: %.*s; ino: %d", i, nl, n, *ino); + + dc = novfs_lookup_inode_cache(i, name, *ino); + if (dc) { + retVal = 0; + *ino = dc->ino; + info->type = 0; + info->mode = dc->mode; + info->size = dc->size; + info->atime = dc->atime; + info->mtime = dc->mtime; + info->ctime = dc->ctime; + info->namelength = dc->nameLen; + memcpy(info->name, dc->name, dc->nameLen); + info->name[dc->nameLen] = '\0'; + if (EntryTime) { + *EntryTime = dc->jiffies; + } + retVal = 0; + } + } + DbgPrint("return %d", retVal); + return (retVal); +} + +/* + * Abstract: This routine will return the first entry on the list + * and then remove it. + * + * Notes: DirCacheLock should be held before calling this routine. + * + */ +int novfs_get_remove_entry(struct inode *i, ino_t * ino, struct novfs_entry_info *info) +{ + struct inode_data *id; + struct novfs_dir_cache *dc; + struct list_head *l = NULL; + int retVal = -1; + + if (i && (id = i->i_private) && id->DirCache.next) { + l = id->DirCache.next; + + if (l != &id->DirCache) { + dc = list_entry(l, struct novfs_dir_cache, list); + + *ino = dc->ino; + info->type = 0; + info->mode = dc->mode; + info->size = dc->size; + info->atime = dc->atime; + info->mtime = dc->mtime; + info->ctime = dc->ctime; + info->namelength = dc->nameLen; + memcpy(info->name, dc->name, dc->nameLen); + info->name[dc->nameLen] = '\0'; + retVal = 0; + + list_del(&dc->list); + kfree(dc); + DCCount--; + + id->cntDC--; + } + } + return (retVal); +} + +/* + * Abstract: Marks all entries in the directory cache as invalid. + * + * Notes: DirCacheLock should be held before calling this routine. + * + *========================================================================*/ +void novfs_invalidate_inode_cache(struct inode *i) +{ + struct inode_data *id; + struct novfs_dir_cache *dc; + struct list_head *l; + + if (i && (id = i->i_private) && id->DirCache.next) { + list_for_each(l, &id->DirCache) { + dc = list_entry(l, struct novfs_dir_cache, list); + dc->flags &= ~ENTRY_VALID; + } + } +} + +/*++======================================================================*/ +struct novfs_dir_cache *novfs_lookup_inode_cache(struct inode *i, struct qstr *name, + ino_t ino) +/* + * Returns: struct novfs_dir_cache entry if match + * NULL - if there is no match. + * + * Abstract: Checks a inode directory to see if there are any enties + * matching name or ino. If name is specified then ino is + * not used. ino is use if name is not specified. + * + * Notes: DirCacheLock should be held before calling this routine. + * + *========================================================================*/ +{ + struct inode_data *id; + struct novfs_dir_cache *dc, *retVal = NULL; + struct list_head *l; + char *n = ""; + int nl = 6; + int hash = 0; + + if (i && (id = i->i_private) && id->DirCache.next) { + if (name && name->name) { + nl = name->len; + n = (char *)name->name; + hash = name->hash; + } + DbgPrint("inode: 0x%p; name: %.*s; hash: 0x%x;\n" + " len: %d; ino: %d", i, nl, n, hash, nl, ino); + + list_for_each(l, &id->DirCache) { + dc = list_entry(l, struct novfs_dir_cache, list); + if (name) { + +/* DbgPrint("novfs_lookup_inode_cache: 0x%p\n" \ + " ino: %d\n" \ + " hash: 0x%x\n" \ + " len: %d\n" \ + " name: %.*s\n", + dc, dc->ino, dc->hash, dc->nameLen, dc->nameLen, dc->name); +*/ + if ((name->hash == dc->hash) && + (name->len == dc->nameLen) && + (0 == + memcmp(name->name, dc->name, name->len))) { + retVal = dc; + break; + } + } else { + if (ino == dc->ino) { + retVal = dc; + break; + } + } + } + } + + DbgPrint("return 0x%p", retVal); + return (retVal); +} + +/* + * Checks a inode directory to see if there are any enties matching name + * or ino. If entry is found the valid bit is set. + * + * DirCacheLock should be held before calling this routine. + */ +int novfs_lookup_validate(struct inode *i, struct qstr *name, ino_t ino) +{ + struct inode_data *id; + struct novfs_dir_cache *dc; + int retVal = -1; + char *n = ""; + int nl = 6; + + if (i && (id = i->i_private) && id->DirCache.next) { + if (name && name->len) { + n = (char *)name->name; + nl = name->len; + } + DbgPrint("inode: 0x%p; name: %.*s; ino: %d", i, nl, n, ino); + + dc = novfs_lookup_inode_cache(i, name, ino); + if (dc) { + dc->flags |= ENTRY_VALID; + retVal = 0; + } + } + return (retVal); +} + +/* + * Added entry to directory cache. + * + * DirCacheLock should be held before calling this routine. + */ +int novfs_add_inode_entry(struct inode *i, + struct qstr *name, ino_t ino, struct novfs_entry_info *info) +{ + struct inode_data *id; + struct novfs_dir_cache *new; + int retVal = -ENOMEM; + struct novfs_dir_cache *todel; + struct list_head *todeltmp; + + //SClark + DbgPrint("i: %p", i); + if ((id = i->i_private)) { + DbgPrint("i->i_private: %p", id); + if (id->DirCache.next) + DbgPrint("id->DirCache.next: %p", id->DirCache.next); + } + //SClark + + if (i && (id = i->i_private) && id->DirCache.next) { + new = kmalloc(sizeof(struct novfs_dir_cache) + name->len, GFP_KERNEL); + if (new) { + id->cntDC++; + + DCCount++; + DbgPrint("inode: 0x%p; id: 0x%p; DC: 0x%p; new: 0x%p; " + "name: %.*s; ino: %d; size: %lld; mode: 0x%x", + i, id, &id->DirCache, new, name->len, + name->name, ino, info->size, info->mode); + + retVal = 0; + new->flags = ENTRY_VALID; + new->jiffies = get_jiffies_64(); + new->size = info->size; + new->mode = info->mode; + new->atime = info->atime; + new->mtime = info->mtime; + new->ctime = info->ctime; + new->ino = ino; + new->hash = name->hash; + new->nameLen = name->len; + memcpy(new->name, name->name, name->len); + new->name[new->nameLen] = '\0'; + list_add(&new->list, &id->DirCache); + + if (id->cntDC > 20) { + todeltmp = id->DirCache.prev; + todel = list_entry(todeltmp, struct novfs_dir_cache, list); + + list_del(&todel->list); + + kfree(todel); + + DCCount--; + id->cntDC--; + } + + } + } + return (retVal); +} + +/* + * DirCacheLock should be held before calling this routine. + */ +int novfs_update_entry(struct inode *i, struct qstr *name, ino_t ino, + struct novfs_entry_info *info) +{ + struct inode_data *id; + struct novfs_dir_cache *dc; + int retVal = -1; + char *n = ""; + int nl = 6; + char atime_buf[32]; + char mtime_buf[32]; + char ctime_buf[32]; + + if (i && (id = i->i_private) && id->DirCache.next) { + + if (name && name->len) { + n = (char *)name->name; + nl = name->len; + } + ctime_r(&info->atime.tv_sec, atime_buf); + ctime_r(&info->mtime.tv_sec, mtime_buf); + ctime_r(&info->ctime.tv_sec, ctime_buf); + DbgPrint("inode: 0x%p; name: %.*s; ino: %d; size: %lld; " + "atime: %s; mtime: %s; ctime: %s", + i, nl, n, ino, info->size, atime_buf, mtime_buf, + ctime_buf); + + dc = novfs_lookup_inode_cache(i, name, ino); + if (dc) { + retVal = 0; + dc->flags = ENTRY_VALID; + dc->jiffies = get_jiffies_64(); + dc->size = info->size; + dc->mode = info->mode; + dc->atime = info->atime; + dc->mtime = info->mtime; + dc->ctime = info->ctime; + + ctime_r(&dc->atime.tv_sec, atime_buf); + ctime_r(&dc->mtime.tv_sec, mtime_buf); + ctime_r(&dc->ctime.tv_sec, ctime_buf); + DbgPrint("entry: 0x%p; flags: 0x%x; jiffies: %lld; " + "ino: %d; size: %lld; mode: 0%o; atime: %s; " + "mtime: %s %d; ctime: %s; hash: 0x%x; " + " nameLen: %d; name: %s", + dc, dc->flags, dc->jiffies, dc->ino, dc->size, + dc->mode, atime_buf, mtime_buf, + dc->mtime.tv_nsec, ctime_buf, dc->hash, + dc->nameLen, dc->name); + } + } + DbgPrint("return %d", retVal); + return (retVal); +} + +/* + * Removes entry from directory cache. You can specify a name + * or an inode number. + * + * DirCacheLock should be held before calling this routine. + */ +void novfs_remove_inode_entry(struct inode *i, struct qstr *name, ino_t ino) +{ + struct inode_data *id; + struct novfs_dir_cache *dc; + char *n = ""; + int nl = 6; + + if (i && (id = i->i_private) && id->DirCache.next) { + dc = novfs_lookup_inode_cache(i, name, ino); + if (dc) { + if (name && name->name) { + nl = name->len; + n = (char *)name->name; + } + DbgPrint("inode: 0x%p; id: 0x%p; DC: 0x%p; " + "name: %.*s; ino: %d entry: 0x%p " + "[name: %.*s; ino: %d; next: 0x%p; " + "prev: 0x%p]", + i, id, &id->DirCache, nl, n, ino, dc, + dc->nameLen, dc->name, dc->ino, dc->list.next, + dc->list.prev); + list_del(&dc->list); + kfree(dc); + DCCount--; + + id->cntDC--; + } + } +} + +/* + * Frees all invalid entries in the directory cache. + * + * DirCacheLock should be held before calling this routine. + */ +void novfs_free_invalid_entries(struct inode *i) +{ + struct inode_data *id; + struct novfs_dir_cache *dc; + struct list_head *l; + + if (i && (id = i->i_private) && id->DirCache.next) { + list_for_each(l, &id->DirCache) { + dc = list_entry(l, struct novfs_dir_cache, list); + if (0 == (dc->flags & ENTRY_VALID)) { + DbgPrint("inode: 0x%p; id: 0x%p; entry: 0x%p; " + "name: %.*s; ino: %d", + i, id, dc, dc->nameLen, dc->name, + dc->ino); + l = l->prev; + list_del(&dc->list); + kfree(dc); + DCCount--; + + id->cntDC--; + } + } + } +} + +/* + * Frees all entries in the inode cache. + * + * DirCacheLock should be held before calling this routine. + */ +void novfs_free_inode_cache(struct inode *i) +{ + struct inode_data *id; + struct novfs_dir_cache *dc; + struct list_head *l; + + if (i && (id = i->i_private) && id->DirCache.next) { + list_for_each(l, &id->DirCache) { + dc = list_entry(l, struct novfs_dir_cache, list); + l = l->prev; + list_del(&dc->list); + kfree(dc); + DCCount--; + + id->cntDC--; + } + } +} + +void novfs_dump_inode(void *pf) +{ + struct inode *inode; + void (*pfunc) (char *Fmt, ...) = pf; + struct inode_data *id; + struct novfs_dir_cache *dc; + struct list_head *il, *l; + char atime_buf[32]; + char mtime_buf[32]; + char ctime_buf[32]; + unsigned long icnt = 0, dccnt = 0; + + down(&InodeList_lock); + list_for_each(il, &InodeList) { + id = list_entry(il, struct inode_data, IList); + inode = id->Inode; + if (inode) { + icnt++; + + pfunc("Inode=0x%p I_ino=%d\n", inode, inode->i_ino); + + pfunc(" atime=%s\n", + ctime_r(&inode->i_atime.tv_sec, atime_buf)); + pfunc(" ctime=%s\n", + ctime_r(&inode->i_mtime.tv_sec, atime_buf)); + pfunc(" mtime=%s\n", + ctime_r(&inode->i_ctime.tv_sec, atime_buf)); + pfunc(" size=%lld\n", inode->i_size); + pfunc(" mode=0%o\n", inode->i_mode); + pfunc(" count=0%o\n", atomic_read(&inode->i_count)); + } + + pfunc(" nofs_inode_data: 0x%p Name=%s Scope=0x%p\n", id, id->Name, + id->Scope); + + if (id->DirCache.next) { + list_for_each(l, &id->DirCache) { + dccnt++; + dc = list_entry(l, struct novfs_dir_cache, + list); + ctime_r(&dc->atime.tv_sec, atime_buf); + ctime_r(&dc->mtime.tv_sec, mtime_buf); + ctime_r(&dc->ctime.tv_sec, ctime_buf); + + pfunc(" Cache Entry: 0x%p\n" + " flags: 0x%x\n" + " jiffies: %llu\n" + " ino: %u\n" + " size: %llu\n" + " mode: 0%o\n" + " atime: %s\n" + " mtime: %s\n" + " ctime: %s\n" + " hash: 0x%x\n" + " len: %d\n" + " name: %s\n", + dc, dc->flags, dc->jiffies, + dc->ino, dc->size, dc->mode, + atime_buf, mtime_buf, ctime_buf, + dc->hash, dc->nameLen, dc->name); + } + } + } + up(&InodeList_lock); + + pfunc("Inodes: %d(%d) DirCache: %d(%d)\n", InodeCount, icnt, DCCount, + dccnt); + +} + +module_init(init_novfs); +module_exit(exit_novfs); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Novell Inc."); +MODULE_DESCRIPTION("Novell NetWare Client for Linux"); +MODULE_VERSION(NOVFS_VERSION_STRING); --- /dev/null +++ b/fs/novfs/nwcapi.c @@ -0,0 +1,2202 @@ +/* + * Novell NCP Redirector for Linux + * Author: James Turner/Richard Williams + * + * This file contains functions used to interface to the library interface of + * the daemon. + * + * Copyright (C) 2005 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nwcapi.h" +#include "nwerror.h" +#include "vfs.h" +#include "commands.h" + +#ifndef strlen_user +#define strlen_user(str) strnlen_user(str, ~0UL >> 1) +#endif + +static void GetUserData(struct nwc_scan_conn_info * connInfo, struct novfs_xplat_call_request *cmd, struct novfs_xplat_call_reply *reply); +static void GetConnData(struct nwc_get_conn_info * connInfo, struct novfs_xplat_call_request *cmd, struct novfs_xplat_call_reply *reply); + +/*++======================================================================*/ +int novfs_open_conn_by_name(struct novfs_xplat *pdata, void ** Handle, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwd_open_conn_by_name *openConn, *connReply; + struct nwc_open_conn_by_name ocbn; + int retCode = 0; + unsigned long cmdlen, datalen, replylen, cpylen; + char *data; + + cpylen = copy_from_user(&ocbn, pdata->reqData, sizeof(ocbn)); + datalen = sizeof(*openConn) + strlen_user(ocbn.pName->pString) + strlen_user(ocbn.pServiceType); + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); + + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_OPEN_CONN_BY_NAME; + + cmd->dataLen = datalen; + openConn = (struct nwd_open_conn_by_name *) cmd->data; + + openConn->nameLen = strlen_user(ocbn.pName->pString); + openConn->serviceLen = strlen_user(ocbn.pServiceType); + openConn->uConnFlags = ocbn.uConnFlags; + openConn->ConnHandle = Uint32toHandle(ocbn.ConnHandle); + data = (char *)openConn; + data += sizeof(*openConn); + openConn->oName = sizeof(*openConn); + + openConn->oServiceType = openConn->oName + openConn->nameLen; + cpylen = + copy_from_user(data, ocbn.pName->pString, + openConn->nameLen); + data += openConn->nameLen; + cpylen = + copy_from_user(data, ocbn.pServiceType, + openConn->serviceLen); + + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + /* + * we got reply data from the daemon + */ + connReply = (struct nwd_open_conn_by_name *) reply->data; + retCode = reply->Reply.ErrorCode; + if (!retCode) { + /* + * we got valid data. + */ + connReply = (struct nwd_open_conn_by_name *) reply->data; + ocbn.RetConnHandle = HandletoUint32(connReply->newConnHandle); + *Handle = connReply->newConnHandle; + + cpylen = copy_to_user(pdata->reqData, &ocbn, sizeof(ocbn)); + DbgPrint("New Conn Handle = %X", connReply->newConnHandle); + } + kfree(reply); + } + + kfree(cmd); + return ((int)retCode); + +} + +int novfs_open_conn_by_addr(struct novfs_xplat *pdata, void ** Handle, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwd_open_conn_by_addr *openConn, *connReply; + struct nwc_open_conn_by_addr ocba; + struct nwc_tran_addr tranAddr; + int retCode = 0; + unsigned long cmdlen, datalen, replylen, cpylen; + char addr[MAX_ADDRESS_LENGTH]; + + cpylen = copy_from_user(&ocba, pdata->reqData, sizeof(ocba)); + datalen = sizeof(*openConn); + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); + + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_OPEN_CONN_BY_ADDRESS; + cmd->dataLen = datalen; + openConn = (struct nwd_open_conn_by_addr *) cmd->data; + + cpylen = + copy_from_user(&tranAddr, ocba.pTranAddr, sizeof(tranAddr)); + + DbgPrint("tranAddr"); + novfs_dump(sizeof(tranAddr), &tranAddr); + + openConn->TranAddr.uTransportType = tranAddr.uTransportType; + openConn->TranAddr.uAddressLength = tranAddr.uAddressLength; + memset(addr, 0xcc, sizeof(addr) - 1); + + cpylen = + copy_from_user(addr, tranAddr.puAddress, + tranAddr.uAddressLength); + + DbgPrint("addr"); + novfs_dump(sizeof(addr), addr); + + openConn->TranAddr.oAddress = *(unsigned int *) (&addr[2]); + + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + /* + * we got reply data from the daemon + */ + connReply = (struct nwd_open_conn_by_addr *) reply->data; + retCode = reply->Reply.ErrorCode; + if (!retCode) { + /* + * we got valid data. + */ + connReply = (struct nwd_open_conn_by_addr *) reply->data; + ocba.ConnHandle = + HandletoUint32(connReply->ConnHandle); + *Handle = connReply->ConnHandle; + cpylen = + copy_to_user(pdata->reqData, &ocba, + sizeof(ocba)); + DbgPrint("New Conn Handle = %X", connReply->ConnHandle); + } + kfree(reply); + } + + kfree(cmd); + + return (retCode); + +} + +int novfs_open_conn_by_ref(struct novfs_xplat *pdata, void ** Handle, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwd_open_conn_by_ref *openConn; + struct nwc_open_conn_by_ref ocbr; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + + cpylen = copy_from_user(&ocbr, pdata->reqData, sizeof(ocbr)); + datalen = sizeof(*openConn); + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_OPEN_CONN_BY_REFERENCE; + cmd->dataLen = datalen; + openConn = (struct nwd_open_conn_by_ref *) cmd->data; + + openConn->uConnReference = + (void *) (unsigned long) ocbr.uConnReference; + openConn->uConnFlags = ocbr.uConnFlags; + + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + /* + * we got reply data from the daemon + */ + openConn = (struct nwd_open_conn_by_ref *) reply->data; + retCode = reply->Reply.ErrorCode; + if (!retCode) { + /* + * we got valid data. + */ + ocbr.ConnHandle = + HandletoUint32(openConn->ConnHandle); + *Handle = openConn->ConnHandle; + + cpylen = + copy_to_user(pdata->reqData, &ocbr, + sizeof(ocbr)); + DbgPrint("New Conn Handle = %X", openConn->ConnHandle); + } + kfree(reply); + } + + kfree(cmd); + return (retCode); + +} + +int novfs_raw_send(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct nwc_request xRequest; + struct nwc_frag *frag, *cFrag, *reqFrag; + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen, totalLen; + unsigned int x; + struct nwd_ncp_req *ncpData; + struct nwd_ncp_rep *ncpReply; + unsigned char *reqData; + unsigned long actualReplyLength = 0; + + DbgPrint("[XPLAT] Process Raw NCP Send"); + cpylen = copy_from_user(&xRequest, pdata->reqData, sizeof(xRequest)); + + /* + * Figure out the length of the request + */ + frag = + kmalloc(xRequest.uNumReplyFrags * sizeof(struct nwc_frag), GFP_KERNEL); + + DbgPrint("[XPLAT RawNCP] - Reply Frag Count 0x%X", + xRequest.uNumReplyFrags); + + if (!frag) + return (retCode); + + cpylen = + copy_from_user(frag, xRequest.pReplyFrags, + xRequest.uNumReplyFrags * sizeof(struct nwc_frag)); + totalLen = 0; + + cFrag = frag; + for (x = 0; x < xRequest.uNumReplyFrags; x++) { + DbgPrint("[XPLAT - RawNCP] - Frag Len = %d", cFrag->uLength); + totalLen += cFrag->uLength; + cFrag++; + } + + DbgPrint("[XPLAT - RawNCP] - totalLen = %d", totalLen); + datalen = 0; + reqFrag = + kmalloc(xRequest.uNumRequestFrags * sizeof(struct nwc_frag), + GFP_KERNEL); + if (!reqFrag) { + kfree(frag); + return (retCode); + } + + cpylen = + copy_from_user(reqFrag, xRequest.pRequestFrags, + xRequest.uNumRequestFrags * sizeof(struct nwc_frag)); + cFrag = reqFrag; + for (x = 0; x < xRequest.uNumRequestFrags; x++) { + datalen += cFrag->uLength; + cFrag++; + } + + /* + * Allocate the cmd Request + */ + cmdlen = datalen + sizeof(*cmd) + sizeof(*ncpData); + DbgPrint("[XPLAT RawNCP] - Frag Count 0x%X", + xRequest.uNumRequestFrags); + DbgPrint("[XPLAT RawNCP] - Total Command Data Len = %x", cmdlen); + + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_RAW_NCP_REQUEST; + + /* + * build the NCP Request + */ + cmd->dataLen = cmdlen - sizeof(*cmd); + ncpData = (struct nwd_ncp_req *) cmd->data; + ncpData->replyLen = totalLen; + ncpData->requestLen = datalen; + ncpData->ConnHandle = (void *) (unsigned long) xRequest.ConnHandle; + ncpData->function = xRequest.uFunction; + + reqData = ncpData->data; + cFrag = reqFrag; + + for (x = 0; x < xRequest.uNumRequestFrags; x++) { + cpylen = + copy_from_user(reqData, cFrag->pData, + cFrag->uLength); + reqData += cFrag->uLength; + cFrag++; + } + + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + DbgPrint("RawNCP - reply = %x", reply); + DbgPrint("RawNCP - retCode = %x", retCode); + + if (reply) { + /* + * we got reply data from the daemon + */ + ncpReply = (struct nwd_ncp_rep *) reply->data; + retCode = reply->Reply.ErrorCode; + + DbgPrint("RawNCP - Reply Frag Count 0x%X", + xRequest.uNumReplyFrags); + + /* + * We need to copy the reply frags to the packet. + */ + reqData = ncpReply->data; + cFrag = frag; + + totalLen = ncpReply->replyLen; + for (x = 0; x < xRequest.uNumReplyFrags; x++) { + + DbgPrint("RawNCP - Copy Frag %d: 0x%X", x, + cFrag->uLength); + + datalen = + min((unsigned long) cFrag->uLength, totalLen); + + cpylen = + copy_to_user(cFrag->pData, reqData, + datalen); + totalLen -= datalen; + reqData += datalen; + actualReplyLength += datalen; + + cFrag++; + } + + kfree(reply); + } else { + retCode = -EIO; + } + + kfree(cmd); + xRequest.uActualReplyLength = actualReplyLength; + cpylen = copy_to_user(pdata->reqData, &xRequest, sizeof(xRequest)); + + kfree(reqFrag); + kfree(frag); + + return (retCode); +} + +int novfs_conn_close(struct novfs_xplat *pdata, void ** Handle, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_close_conn cc; + struct nwd_close_conn *nwdClose; + int retCode = 0; + unsigned long cmdlen, datalen, replylen, cpylen; + + cpylen = copy_from_user(&cc, pdata->reqData, sizeof(cc)); + + datalen = sizeof(*nwdClose); + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_CLOSE_CONN; + + nwdClose = (struct nwd_close_conn *) cmd->data; + cmd->dataLen = sizeof(*nwdClose); + *Handle = nwdClose->ConnHandle = Uint32toHandle(cc.ConnHandle); + + /* + * send the request + */ + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, 0); + if (reply) { + retCode = reply->Reply.ErrorCode; + kfree(reply); + } + kfree(cmd); + return (retCode); + +} + +int novfs_sys_conn_close(struct novfs_xplat *pdata, unsigned long *Handle, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_close_conn cc; + struct nwd_close_conn *nwdClose; + unsigned int retCode = 0; + unsigned long cmdlen, datalen, replylen, cpylen; + + cpylen = copy_from_user(&cc, pdata->reqData, sizeof(cc)); + + datalen = sizeof(*nwdClose); + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_SYS_CLOSE_CONN; + + nwdClose = (struct nwd_close_conn *) cmd->data; + cmd->dataLen = sizeof(*nwdClose); + nwdClose->ConnHandle = (void *) (unsigned long) cc.ConnHandle; + *Handle = (unsigned long) cc.ConnHandle; + + /* + * send the request + */ + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, (void **)&reply, &replylen, 0); + if (reply) { + retCode = reply->Reply.ErrorCode; + kfree(reply); + } + kfree(cmd); + return (retCode); + +} + +int novfs_login_id(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct nwc_login_id lgn, *plgn; + int retCode = -ENOMEM; + struct ncl_string server; + struct ncl_string username; + struct ncl_string password; + unsigned long cpylen; + struct nwc_string nwcStr; + + cpylen = copy_from_user(&lgn, pdata->reqData, sizeof(lgn)); + + DbgPrint(""); + novfs_dump(sizeof(lgn), &lgn); + + cpylen = copy_from_user(&nwcStr, lgn.pDomainName, sizeof(nwcStr)); + DbgPrint("DomainName\n"); + novfs_dump(sizeof(nwcStr), &nwcStr); + + if ((server.buffer = kmalloc(nwcStr.DataLen, GFP_KERNEL))) { + server.type = nwcStr.DataType; + server.len = nwcStr.DataLen; + if (!copy_from_user((void *)server.buffer, nwcStr.pBuffer, server.len)) { + DbgPrint("Server"); + novfs_dump(server.len, server.buffer); + + cpylen = copy_from_user(&nwcStr, lgn.pObjectName, sizeof(nwcStr)); + DbgPrint("ObjectName"); + novfs_dump(sizeof(nwcStr), &nwcStr); + + if ((username.buffer = kmalloc(nwcStr.DataLen, GFP_KERNEL))) { + username.type = nwcStr.DataType; + username.len = nwcStr.DataLen; + if (!copy_from_user((void *)username.buffer, nwcStr.pBuffer, username.len)) { + DbgPrint("User"); + novfs_dump(username.len, username.buffer); + + cpylen = copy_from_user(&nwcStr, lgn.pPassword, sizeof(nwcStr)); + DbgPrint("Password"); + novfs_dump(sizeof(nwcStr), &nwcStr); + + if ((password.buffer = kmalloc(nwcStr.DataLen, GFP_KERNEL))) { + password.type = nwcStr.DataType; + password.len = nwcStr.DataLen; + if (!copy_from_user((void *)password.buffer, nwcStr.pBuffer, password.len)) { + retCode = novfs_do_login(&server, &username, &password, (void **)&lgn.AuthenticationId, &Session); + if (retCode) { + lgn.AuthenticationId = 0; + } + + plgn = (struct nwc_login_id *)pdata->reqData; + cpylen = copy_to_user(&plgn->AuthenticationId, &lgn.AuthenticationId, sizeof(plgn->AuthenticationId)); + } + memset(password.buffer, 0, password.len); + kfree(password.buffer); + } + } + memset(username.buffer, 0, username.len); + kfree(username.buffer); + } + } + kfree(server.buffer); + } + return (retCode); +} + +int novfs_auth_conn(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct nwc_auth_with_id pauth; + struct nwc_auth_wid *pDauth; + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + + datalen = sizeof(*pDauth); + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_AUTHENTICATE_CONN_WITH_ID; + + cpylen = copy_from_user(&pauth, pdata->reqData, sizeof(pauth)); + + pDauth = (struct nwc_auth_wid *) cmd->data; + cmd->dataLen = datalen; + pDauth->AuthenticationId = pauth.AuthenticationId; + pDauth->ConnHandle = (void *) (unsigned long) pauth.ConnHandle; + + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + retCode = reply->Reply.ErrorCode; + kfree(reply); + } + return (retCode); +} + +int novfs_license_conn(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_license_conn lisc; + struct nwc_lisc_id * pDLisc; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + + datalen = sizeof(*pDLisc); + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_LICENSE_CONN; + + cpylen = copy_from_user(&lisc, pdata->reqData, sizeof(lisc)); + + pDLisc = (struct nwc_lisc_id *) cmd->data; + cmd->dataLen = datalen; + pDLisc->ConnHandle = (void *) (unsigned long) lisc.ConnHandle; + + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + retCode = reply->Reply.ErrorCode; + kfree(reply); + } + kfree(cmd); + return (retCode); +} + +int novfs_logout_id(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_lo_id logout, *pDLogout; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + + datalen = sizeof(*pDLogout); + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); + + if (!cmd) + return -ENOMEM; + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_LOGOUT_IDENTITY; + + cpylen = + copy_from_user(&logout, pdata->reqData, sizeof(logout)); + + pDLogout = (struct nwc_lo_id *) cmd->data; + cmd->dataLen = datalen; + pDLogout->AuthenticationId = logout.AuthenticationId; + + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + retCode = reply->Reply.ErrorCode; + kfree(reply); + } + kfree(cmd); + return (retCode); +} + +int novfs_unlicense_conn(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_unlic_conn *pUconn, ulc; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + + cpylen = copy_from_user(&ulc, pdata->reqData, sizeof(ulc)); + datalen = sizeof(*pUconn); + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_UNLICENSE_CONN; + cmd->dataLen = datalen; + pUconn = (struct nwc_unlic_conn *) cmd->data; + + pUconn->ConnHandle = (void *) (unsigned long) ulc.ConnHandle; + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + /* + * we got reply data from the daemon + */ + retCode = reply->Reply.ErrorCode; + kfree(reply); + } + return (retCode); + +} + +int novfs_unauthenticate(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_unauthenticate auth, *pDAuth; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + + datalen = sizeof(*pDAuth); + cmdlen = datalen + sizeof(*cmd); + cmd = (struct novfs_xplat_call_request *)kmalloc(cmdlen, GFP_KERNEL); + + if (!cmd) + return -ENOMEM; + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_UNAUTHENTICATE_CONN; + + cpylen = copy_from_user(&auth, pdata->reqData, sizeof(auth)); + + pDAuth = (struct nwc_unauthenticate *) cmd->data; + cmd->dataLen = datalen; + pDAuth->AuthenticationId = auth.AuthenticationId; + pDAuth->ConnHandle = (void *) (unsigned long) auth.ConnHandle; + + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + retCode = reply->Reply.ErrorCode; + kfree(reply); + } + kfree(cmd); + return (retCode); + +} + +int novfs_get_conn_info(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_get_conn_info connInfo; + struct nwd_conn_info *pDConnInfo; + int retCode = -ENOMEM; + unsigned long cmdlen, replylen, cpylen; + + cmdlen = sizeof(*cmd) + sizeof(*pDConnInfo); + cmd = kmalloc(cmdlen, GFP_KERNEL); + cpylen = + copy_from_user(&connInfo, pdata->reqData, sizeof(struct nwc_get_conn_info)); + + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_GET_CONN_INFO; + + pDConnInfo = (struct nwd_conn_info *) cmd->data; + + pDConnInfo->ConnHandle = (void *) (unsigned long) connInfo.ConnHandle; + pDConnInfo->uInfoLevel = connInfo.uInfoLevel; + pDConnInfo->uInfoLength = connInfo.uInfoLength; + cmd->dataLen = sizeof(*pDConnInfo); + + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + retCode = reply->Reply.ErrorCode; + if (!retCode) { + GetConnData(&connInfo, cmd, reply); + } + + kfree(reply); + } + kfree(cmd); + return (retCode); + +} + +int novfs_set_conn_info(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_set_conn_info connInfo; + struct nwd_set_conn_info *pDConnInfo; + int retCode = -ENOMEM; + unsigned long cmdlen, replylen, cpylen; + + cmdlen = sizeof(*cmd) + sizeof(*pDConnInfo); + cmd = kmalloc(cmdlen, GFP_KERNEL); + cpylen = + copy_from_user(&connInfo, pdata->reqData, sizeof(struct nwc_set_conn_info)); + + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_SET_CONN_INFO; + + pDConnInfo = (struct nwd_set_conn_info *) cmd->data; + + pDConnInfo->ConnHandle = (void *) (unsigned long) connInfo.ConnHandle; + pDConnInfo->uInfoLevel = connInfo.uInfoLevel; + pDConnInfo->uInfoLength = connInfo.uInfoLength; + cmd->dataLen = sizeof(*pDConnInfo); + + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + retCode = reply->Reply.ErrorCode; + kfree(reply); + } + kfree(cmd); + return (retCode); + +} + +int novfs_get_id_info(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_get_id_info qidInfo, *gId; + struct nwd_get_id_info *idInfo; + struct nwc_string xferStr; + char *str; + int retCode = -ENOMEM; + unsigned long cmdlen, replylen, cpylen; + + cmdlen = sizeof(*cmd) + sizeof(*idInfo); + cmd = kmalloc(cmdlen, GFP_KERNEL); + cpylen = copy_from_user(&qidInfo, pdata->reqData, sizeof(qidInfo)); + + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_GET_IDENTITY_INFO; + + idInfo = (struct nwd_get_id_info *) cmd->data; + + idInfo->AuthenticationId = qidInfo.AuthenticationId; + cmd->dataLen = sizeof(*idInfo); + + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + retCode = reply->Reply.ErrorCode; + + if (!reply->Reply.ErrorCode) { + /* + * Save the return info to the user structure. + */ + gId = pdata->reqData; + idInfo = (struct nwd_get_id_info *) reply->data; + cpylen = + copy_to_user(&gId->AuthenticationId, + &idInfo->AuthenticationId, + sizeof(idInfo-> + AuthenticationId)); + cpylen = + copy_to_user(&gId->AuthType, + &idInfo->AuthType, + sizeof(idInfo->AuthType)); + cpylen = + copy_to_user(&gId->IdentityFlags, + &idInfo->IdentityFlags, + sizeof(idInfo->IdentityFlags)); + cpylen = + copy_to_user(&gId->NameType, + &idInfo->NameType, + sizeof(idInfo->NameType)); + cpylen = + copy_to_user(&gId->ObjectType, + &idInfo->ObjectType, + sizeof(idInfo->ObjectType)); + + cpylen = + copy_from_user(&xferStr, gId->pDomainName, + sizeof(struct nwc_string)); + str = + (char *)((char *)reply->data + + idInfo->pDomainNameOffset); + cpylen = + copy_to_user(xferStr.pBuffer, str, + idInfo->domainLen); + xferStr.DataType = NWC_STRING_TYPE_ASCII; + xferStr.DataLen = idInfo->domainLen; + cpylen = + copy_to_user(gId->pDomainName, &xferStr, + sizeof(struct nwc_string)); + + cpylen = + copy_from_user(&xferStr, gId->pObjectName, + sizeof(struct nwc_string)); + str = + (char *)((char *)reply->data + + idInfo->pObjectNameOffset); + cpylen = + copy_to_user(xferStr.pBuffer, str, + idInfo->objectLen); + xferStr.DataLen = idInfo->objectLen - 1; + xferStr.DataType = NWC_STRING_TYPE_ASCII; + cpylen = + copy_to_user(gId->pObjectName, &xferStr, + sizeof(struct nwc_string)); + } + + kfree(reply); + } + kfree(cmd); + return (retCode); +} + +int novfs_scan_conn_info(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_scan_conn_info connInfo, *rInfo; + struct nwd_scan_conn_info *pDConnInfo; + int retCode = -ENOMEM; + unsigned long cmdlen, replylen, cpylen; + unsigned char *localData; + + cpylen = + copy_from_user(&connInfo, pdata->reqData, sizeof(struct nwc_scan_conn_info)); + + cmdlen = sizeof(*cmd) + sizeof(*pDConnInfo) + connInfo.uScanInfoLen; + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_SCAN_CONN_INFO; + + pDConnInfo = (struct nwd_scan_conn_info *) cmd->data; + + DbgPrint("Input Data"); + __DbgPrint(" connInfo.uScanIndex = 0x%X\n", connInfo.uScanIndex); + __DbgPrint(" connInfo.uConnectionReference = 0x%X\n", + connInfo.uConnectionReference); + __DbgPrint(" connInfo.uScanInfoLevel = 0x%X\n", + connInfo.uScanInfoLevel); + __DbgPrint(" connInfo.uScanInfoLen = 0x%X\n", + connInfo.uScanInfoLen); + __DbgPrint(" connInfo.uReturnInfoLength = 0x%X\n", + connInfo.uReturnInfoLength); + __DbgPrint(" connInfo.uReturnInfoLevel = 0x%X\n", + connInfo.uReturnInfoLevel); + __DbgPrint(" connInfo.uScanFlags = 0x%X\n", connInfo.uScanFlags); + + pDConnInfo->uScanIndex = connInfo.uScanIndex; + pDConnInfo->uConnectionReference = + connInfo.uConnectionReference; + pDConnInfo->uScanInfoLevel = connInfo.uScanInfoLevel; + pDConnInfo->uScanInfoLen = connInfo.uScanInfoLen; + pDConnInfo->uReturnInfoLength = connInfo.uReturnInfoLength; + pDConnInfo->uReturnInfoLevel = connInfo.uReturnInfoLevel; + pDConnInfo->uScanFlags = connInfo.uScanFlags; + + if (pDConnInfo->uScanInfoLen) { + localData = (unsigned char *) pDConnInfo; + pDConnInfo->uScanConnInfoOffset = sizeof(*pDConnInfo); + localData += pDConnInfo->uScanConnInfoOffset; + cpylen = + copy_from_user(localData, connInfo.pScanConnInfo, + connInfo.uScanInfoLen); + } else { + pDConnInfo->uScanConnInfoOffset = 0; + } + + cmd->dataLen = sizeof(*pDConnInfo); + + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + DbgPrint("Reply recieved"); + __DbgPrint(" NextIndex = %x\n", connInfo.uScanIndex); + __DbgPrint(" ErrorCode = %x\n", reply->Reply.ErrorCode); + __DbgPrint(" data = %p\n", reply->data); + + pDConnInfo = (struct nwd_scan_conn_info *) reply->data; + retCode = (unsigned long) reply->Reply.ErrorCode; + if (!retCode) { + GetUserData(&connInfo, cmd, reply); + rInfo = (struct nwc_scan_conn_info *) pdata->repData; + cpylen = + copy_to_user(pdata->repData, + &pDConnInfo->uScanIndex, + sizeof(pDConnInfo-> + uScanIndex)); + cpylen = + copy_to_user(&rInfo->uConnectionReference, + &pDConnInfo-> + uConnectionReference, + sizeof(pDConnInfo-> + uConnectionReference)); + } else { + unsigned long x; + + x = 0; + rInfo = (struct nwc_scan_conn_info *) pdata->reqData; + cpylen = + copy_to_user(&rInfo->uConnectionReference, + &x, + sizeof(rInfo-> + uConnectionReference)); + } + + kfree(reply); + } else { + retCode = -EIO; + } + kfree(cmd); + return (retCode); +} + +/* + * Copies the user data out of the scan conn info call. + */ +static void GetUserData(struct nwc_scan_conn_info * connInfo, struct novfs_xplat_call_request *cmd, struct novfs_xplat_call_reply *reply) +{ + unsigned long uLevel; + struct nwd_scan_conn_info *pDConnInfo; + + unsigned char *srcData = NULL; + unsigned long dataLen = 0, cpylen; + + pDConnInfo = (struct nwd_scan_conn_info *) reply->data; + uLevel = pDConnInfo->uReturnInfoLevel; + DbgPrint("uLevel = %d, reply = 0x%p, reply->data = 0x%X", + uLevel, reply, reply->data); + + switch (uLevel) { + case NWC_CONN_INFO_RETURN_ALL: + case NWC_CONN_INFO_NDS_STATE: + case NWC_CONN_INFO_MAX_PACKET_SIZE: + case NWC_CONN_INFO_LICENSE_STATE: + case NWC_CONN_INFO_PUBLIC_STATE: + case NWC_CONN_INFO_SERVICE_TYPE: + case NWC_CONN_INFO_DISTANCE: + case NWC_CONN_INFO_SERVER_VERSION: + case NWC_CONN_INFO_AUTH_ID: + case NWC_CONN_INFO_SUSPENDED: + case NWC_CONN_INFO_WORKGROUP_ID: + case NWC_CONN_INFO_SECURITY_STATE: + case NWC_CONN_INFO_CONN_NUMBER: + case NWC_CONN_INFO_USER_ID: + case NWC_CONN_INFO_BCAST_STATE: + case NWC_CONN_INFO_CONN_REF: + case NWC_CONN_INFO_AUTH_STATE: + case NWC_CONN_INFO_TREE_NAME: + case NWC_CONN_INFO_SERVER_NAME: + case NWC_CONN_INFO_VERSION: + srcData = (unsigned char *) pDConnInfo; + srcData += pDConnInfo->uReturnConnInfoOffset; + dataLen = pDConnInfo->uReturnInfoLength; + break; + + case NWC_CONN_INFO_TRAN_ADDR: + { + unsigned char *dstData = connInfo->pReturnConnInfo; + struct nwc_tran_addr tranAddr; + + srcData = (unsigned char *) reply->data; + dataLen = reply->dataLen; + + DbgPrint("NWC_CONN_INFO_TRAN_ADDR 0x%p -> 0x%p :: 0x%X", + srcData, connInfo->pReturnConnInfo, dataLen); + + cpylen = + copy_from_user(&tranAddr, dstData, + sizeof(tranAddr)); + + srcData += + ((struct nwd_scan_conn_info *) srcData)-> + uReturnConnInfoOffset; + + tranAddr.uTransportType = + ((struct nwd_tran_addr *) srcData)->uTransportType; + tranAddr.uAddressLength = + ((struct tagNwdTranAddrEx *) srcData)->uAddressLength; + + cpylen = + copy_to_user(dstData, &tranAddr, sizeof(tranAddr)); + cpylen = + copy_to_user(tranAddr.puAddress, + ((struct tagNwdTranAddrEx *) srcData)->Buffer, + ((struct tagNwdTranAddrEx *) srcData)-> + uAddressLength); + dataLen = 0; + break; + } + case NWC_CONN_INFO_RETURN_NONE: + case NWC_CONN_INFO_TREE_NAME_UNICODE: + case NWC_CONN_INFO_SERVER_NAME_UNICODE: + case NWC_CONN_INFO_LOCAL_TRAN_ADDR: + case NWC_CONN_INFO_ALTERNATE_ADDR: + case NWC_CONN_INFO_SERVER_GUID: + default: + break; + } + + if (srcData && dataLen) { + DbgPrint("Copy Data 0x%p -> 0x%p :: 0x%X", + srcData, connInfo->pReturnConnInfo, dataLen); + cpylen = + copy_to_user(connInfo->pReturnConnInfo, srcData, dataLen); + } + + return; +} + +/* + * Copies the user data out of the scan conn info call. + */ +static void GetConnData(struct nwc_get_conn_info * connInfo, struct novfs_xplat_call_request *cmd, struct novfs_xplat_call_reply *reply) +{ + unsigned long uLevel; + struct nwd_conn_info * pDConnInfo; + + unsigned char *srcData = NULL; + unsigned long dataLen = 0, cpylen; + + pDConnInfo = (struct nwd_conn_info *) cmd->data; + uLevel = pDConnInfo->uInfoLevel; + + switch (uLevel) { + case NWC_CONN_INFO_RETURN_ALL: + srcData = (unsigned char *) reply->data; + dataLen = reply->dataLen; + break; + + case NWC_CONN_INFO_RETURN_NONE: + dataLen = 0; + break; + + case NWC_CONN_INFO_TRAN_ADDR: + { + unsigned char *dstData = connInfo->pConnInfo; + struct nwc_tran_addr tranAddr; + + srcData = (unsigned char *) reply->data; + + cpylen = + copy_from_user(&tranAddr, dstData, + sizeof(tranAddr)); + tranAddr.uTransportType = + ((struct tagNwdTranAddrEx *) srcData)->uTransportType; + tranAddr.uAddressLength = + ((struct tagNwdTranAddrEx *) srcData)->uAddressLength; + + cpylen = + copy_to_user(dstData, &tranAddr, sizeof(tranAddr)); + cpylen = + copy_to_user(tranAddr.puAddress, + ((struct tagNwdTranAddrEx *) srcData)->Buffer, + ((struct tagNwdTranAddrEx *) srcData)-> + uAddressLength); + dataLen = 0; + break; + } + case NWC_CONN_INFO_NDS_STATE: + case NWC_CONN_INFO_MAX_PACKET_SIZE: + case NWC_CONN_INFO_LICENSE_STATE: + case NWC_CONN_INFO_PUBLIC_STATE: + case NWC_CONN_INFO_SERVICE_TYPE: + case NWC_CONN_INFO_DISTANCE: + case NWC_CONN_INFO_SERVER_VERSION: + case NWC_CONN_INFO_AUTH_ID: + case NWC_CONN_INFO_SUSPENDED: + case NWC_CONN_INFO_WORKGROUP_ID: + case NWC_CONN_INFO_SECURITY_STATE: + case NWC_CONN_INFO_CONN_NUMBER: + case NWC_CONN_INFO_USER_ID: + case NWC_CONN_INFO_BCAST_STATE: + case NWC_CONN_INFO_CONN_REF: + case NWC_CONN_INFO_AUTH_STATE: + case NWC_CONN_INFO_VERSION: + case NWC_CONN_INFO_SERVER_NAME: + case NWC_CONN_INFO_TREE_NAME: + srcData = (unsigned char *) reply->data; + dataLen = reply->dataLen; + break; + + case NWC_CONN_INFO_TREE_NAME_UNICODE: + case NWC_CONN_INFO_SERVER_NAME_UNICODE: + break; + + case NWC_CONN_INFO_LOCAL_TRAN_ADDR: + break; + + case NWC_CONN_INFO_ALTERNATE_ADDR: + break; + + case NWC_CONN_INFO_SERVER_GUID: + break; + + default: + break; + } + + if (srcData && dataLen) { + cpylen = + copy_to_user(connInfo->pConnInfo, srcData, + connInfo->uInfoLength); + } + + return; +} + +int novfs_get_daemon_ver(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwd_get_reqversion *pDVersion; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + + datalen = sizeof(*pDVersion); + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_GET_REQUESTER_VERSION; + cmdlen = sizeof(*cmd); + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + retCode = reply->Reply.ErrorCode; + pDVersion = (struct nwd_get_reqversion *) reply->data; + cpylen = + copy_to_user(pDVersion, pdata->reqData, + sizeof(*pDVersion)); + kfree(reply); + } + kfree(cmd); + return (retCode); + +} + +int novfs_get_preferred_DS_tree(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwd_get_pref_ds_tree *pDGetTree; + struct nwc_get_pref_ds_tree xplatCall, *p; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + unsigned char *dPtr; + + cpylen = + copy_from_user(&xplatCall, pdata->reqData, + sizeof(struct nwc_get_pref_ds_tree)); + datalen = sizeof(*pDGetTree) + xplatCall.uTreeLength; + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); + + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_GET_PREFERRED_DS_TREE; + cmdlen = sizeof(*cmd); + + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + retCode = reply->Reply.ErrorCode; + if (!retCode) { + pDGetTree = + (struct nwd_get_pref_ds_tree *) reply->data; + dPtr = + reply->data + pDGetTree->DsTreeNameOffset; + p = (struct nwc_get_pref_ds_tree *) pdata->reqData; + + DbgPrint("Reply recieved"); + __DbgPrint(" TreeLen = %x\n", + pDGetTree->uTreeLength); + __DbgPrint(" TreeName = %s\n", dPtr); + + cpylen = + copy_to_user(p, &pDGetTree->uTreeLength, 4); + cpylen = + copy_to_user(xplatCall.pDsTreeName, dPtr, + pDGetTree->uTreeLength); + } + kfree(reply); + } + kfree(cmd); + return (retCode); + +} + +int novfs_set_preferred_DS_tree(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwd_set_pref_ds_tree *pDSetTree; + struct nwc_set_pref_ds_tree xplatCall; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + unsigned char *dPtr; + + cpylen = + copy_from_user(&xplatCall, pdata->reqData, + sizeof(struct nwc_set_pref_ds_tree)); + datalen = sizeof(*pDSetTree) + xplatCall.uTreeLength; + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); + + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_SET_PREFERRED_DS_TREE; + + pDSetTree = (struct nwd_set_pref_ds_tree *) cmd->data; + pDSetTree->DsTreeNameOffset = sizeof(*pDSetTree); + pDSetTree->uTreeLength = xplatCall.uTreeLength; + + dPtr = cmd->data + sizeof(*pDSetTree); + cpylen = + copy_from_user(dPtr, xplatCall.pDsTreeName, + xplatCall.uTreeLength); + + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + retCode = reply->Reply.ErrorCode; + kfree(reply); + } + kfree(cmd); + return (retCode); + +} + +int novfs_set_default_ctx(struct novfs_xplat *pdata, + struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_set_def_name_ctx xplatCall; + struct nwd_set_def_name_ctx * pDSet; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + unsigned char *dPtr; + + cpylen = + copy_from_user(&xplatCall, pdata->reqData, + sizeof(struct nwc_set_def_name_ctx)); + datalen = + sizeof(*pDSet) + xplatCall.uTreeLength + xplatCall.uNameLength; + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); + + if (!cmd) + return -ENOMEM; + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_SET_DEFAULT_NAME_CONTEXT; + cmd->dataLen = + sizeof(struct nwd_set_def_name_ctx) + + xplatCall.uTreeLength + xplatCall.uNameLength; + + pDSet = (struct nwd_set_def_name_ctx *) cmd->data; + dPtr = cmd->data; + + pDSet->TreeOffset = sizeof(struct nwd_set_def_name_ctx); + pDSet->uTreeLength = xplatCall.uTreeLength; + pDSet->NameContextOffset = + pDSet->TreeOffset + xplatCall.uTreeLength; + pDSet->uNameLength = xplatCall.uNameLength; + + //sgled cpylen = copy_from_user(dPtr+pDSet->TreeOffset, xplatCall.pTreeName, xplatCall.uTreeLength); + cpylen = copy_from_user(dPtr + pDSet->TreeOffset, xplatCall.pDsTreeName, xplatCall.uTreeLength); //sgled + cpylen = + copy_from_user(dPtr + pDSet->NameContextOffset, + xplatCall.pNameContext, + xplatCall.uNameLength); + + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + retCode = reply->Reply.ErrorCode; + kfree(reply); + } + kfree(cmd); + return (retCode); + +} + +int novfs_get_default_ctx(struct novfs_xplat *pdata, + struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_get_def_name_ctx xplatCall; + struct nwd_get_def_name_ctx * pGet; + char *dPtr; + int retCode = -ENOMEM; + unsigned long cmdlen, replylen, cpylen; + + cpylen = + copy_from_user(&xplatCall, pdata->reqData, + sizeof(struct nwc_get_def_name_ctx)); + cmdlen = + sizeof(*cmd) + sizeof(struct nwd_get_def_name_ctx ) + + xplatCall.uTreeLength; + cmd = kmalloc(cmdlen, GFP_KERNEL); + + if (!cmd) + return -ENOMEM; + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_GET_DEFAULT_NAME_CONTEXT; + cmd->dataLen = + sizeof(struct nwd_get_def_name_ctx) + xplatCall.uTreeLength; + + pGet = (struct nwd_get_def_name_ctx *) cmd->data; + dPtr = cmd->data; + + pGet->TreeOffset = sizeof(struct nwd_get_def_name_ctx ); + pGet->uTreeLength = xplatCall.uTreeLength; + + //sgled cpylen = copy_from_user( dPtr + pGet->TreeOffset, xplatCall.pTreeName, xplatCall.uTreeLength); + cpylen = copy_from_user(dPtr + pGet->TreeOffset, xplatCall.pDsTreeName, xplatCall.uTreeLength); //sgled + dPtr[pGet->TreeOffset + pGet->uTreeLength] = 0; + + retCode = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + retCode = reply->Reply.ErrorCode; + if (!retCode) { + pGet = (struct nwd_get_def_name_ctx *) reply->data; + + DbgPrint("retCode=0x%x uNameLength1=%d uNameLength2=%d", + retCode, pGet->uNameLength, + xplatCall.uNameLength); + if (xplatCall.uNameLength < pGet->uNameLength) { + pGet->uNameLength = + xplatCall.uNameLength; + retCode = NWE_BUFFER_OVERFLOW; + } + dPtr = (char *)pGet + pGet->NameContextOffset; + cpylen = + copy_to_user(xplatCall.pNameContext, dPtr, + pGet->uNameLength); + } + + kfree(reply); + } + kfree(cmd); + return (retCode); + +} + +int novfs_query_feature(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct nwc_query_feature xpCall; + int status = 0; + unsigned long cpylen; + + cpylen = + copy_from_user(&xpCall, pdata->reqData, sizeof(struct nwc_query_feature)); + switch (xpCall.Feature) { + case NWC_FEAT_NDS: + case NWC_FEAT_NDS_MTREE: + case NWC_FEAT_PRN_CAPTURE: + case NWC_FEAT_NDS_RESOLVE: + + status = NWE_REQUESTER_FAILURE; + + } + return (status); +} + +int novfs_get_tree_monitored_conn(struct novfs_xplat *pdata, + struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_get_tree_monitored_conn_ref xplatCall, *p; + struct nwd_get_tree_monitored_conn_ref *pDConnRef; + char *dPtr; + unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; + + cpylen = + copy_from_user(&xplatCall, pdata->reqData, + sizeof(struct nwc_get_tree_monitored_conn_ref)); + datalen = sizeof(*pDConnRef) + xplatCall.pTreeName->DataLen; + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); + + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_GET_TREE_MONITORED_CONN_REF; + + pDConnRef = (struct nwd_get_tree_monitored_conn_ref *) cmd->data; + pDConnRef->TreeName.boffset = sizeof(*pDConnRef); + pDConnRef->TreeName.len = xplatCall.pTreeName->DataLen; + pDConnRef->TreeName.type = xplatCall.pTreeName->DataType; + + dPtr = cmd->data + sizeof(*pDConnRef); + cpylen = + copy_from_user(dPtr, xplatCall.pTreeName->pBuffer, + pDConnRef->TreeName.len); + status = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + pDConnRef = (struct nwd_get_tree_monitored_conn_ref *) reply->data; + dPtr = reply->data + pDConnRef->TreeName.boffset; + p = (struct nwc_get_tree_monitored_conn_ref *) pdata->reqData; + cpylen = + copy_to_user(&p->uConnReference, + &pDConnRef->uConnReference, 4); + + status = reply->Reply.ErrorCode; + kfree(reply); + } + kfree(cmd); + return (status); +} + +int novfs_enum_ids(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_enum_ids xplatCall, *eId; + struct nwd_enum_ids *pEnum; + struct nwc_string xferStr; + char *str; + unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; + + cpylen = + copy_from_user(&xplatCall, pdata->reqData, + sizeof(struct nwc_enum_ids)); + datalen = sizeof(*pEnum); + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); + + if (!cmd) + return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_ENUMERATE_IDENTITIES; + + DbgPrint("Send Request"); + __DbgPrint(" iterator = %x\n", xplatCall.Iterator); + __DbgPrint(" cmdlen = %d\n", cmdlen); + + pEnum = (struct nwd_enum_ids *) cmd->data; + pEnum->Iterator = xplatCall.Iterator; + status = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + status = reply->Reply.ErrorCode; + + eId = pdata->repData; + pEnum = (struct nwd_enum_ids *) reply->data; + cpylen = + copy_to_user(&eId->Iterator, &pEnum->Iterator, + sizeof(pEnum->Iterator)); + DbgPrint("[XPLAT NWCAPI] Found AuthId 0x%X", + pEnum->AuthenticationId); + cpylen = + copy_to_user(&eId->AuthenticationId, + &pEnum->AuthenticationId, + sizeof(pEnum->AuthenticationId)); + cpylen = + copy_to_user(&eId->AuthType, &pEnum->AuthType, + sizeof(pEnum->AuthType)); + cpylen = + copy_to_user(&eId->IdentityFlags, + &pEnum->IdentityFlags, + sizeof(pEnum->IdentityFlags)); + cpylen = + copy_to_user(&eId->NameType, &pEnum->NameType, + sizeof(pEnum->NameType)); + cpylen = + copy_to_user(&eId->ObjectType, &pEnum->ObjectType, + sizeof(pEnum->ObjectType)); + + if (!status) { + cpylen = + copy_from_user(&xferStr, eId->pDomainName, + sizeof(struct nwc_string)); + str = + (char *)((char *)reply->data + + pEnum->domainNameOffset); + DbgPrint("[XPLAT NWCAPI] Found Domain %s", + str); + cpylen = + copy_to_user(xferStr.pBuffer, str, + pEnum->domainNameLen); + xferStr.DataType = NWC_STRING_TYPE_ASCII; + xferStr.DataLen = pEnum->domainNameLen - 1; + cpylen = + copy_to_user(eId->pDomainName, &xferStr, + sizeof(struct nwc_string)); + + cpylen = + copy_from_user(&xferStr, eId->pObjectName, + sizeof(struct nwc_string)); + str = + (char *)((char *)reply->data + + pEnum->objectNameOffset); + DbgPrint("[XPLAT NWCAPI] Found User %s", str); + cpylen = + copy_to_user(xferStr.pBuffer, str, + pEnum->objectNameLen); + xferStr.DataType = NWC_STRING_TYPE_ASCII; + xferStr.DataLen = pEnum->objectNameLen - 1; + cpylen = + copy_to_user(eId->pObjectName, &xferStr, + sizeof(struct nwc_string)); + } + + kfree(reply); + + } + kfree(cmd); + return (status); +} + +int novfs_change_auth_key(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_change_key xplatCall; + struct nwd_change_key *pNewKey; + struct nwc_string xferStr; + char *str; + unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; + + cpylen = + copy_from_user(&xplatCall, pdata->reqData, sizeof(struct nwc_change_key)); + + datalen = + sizeof(struct nwd_change_key) + xplatCall.pDomainName->DataLen + + xplatCall.pObjectName->DataLen + xplatCall.pNewPassword->DataLen + + xplatCall.pVerifyPassword->DataLen; + + cmdlen = sizeof(*cmd) + datalen; + cmd = kmalloc(cmdlen, GFP_KERNEL); + + if (!cmd) + return -ENOMEM; + + pNewKey = (struct nwd_change_key *) cmd->data; + cmd->dataLen = datalen; + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_CHANGE_KEY; + + pNewKey->NameType = xplatCall.NameType; + pNewKey->ObjectType = xplatCall.ObjectType; + pNewKey->AuthType = xplatCall.AuthType; + str = (char *)pNewKey; + + /* + * Get the tree name + */ + str += sizeof(*pNewKey); + cpylen = + copy_from_user(&xferStr, xplatCall.pDomainName, + sizeof(struct nwc_string)); + pNewKey->domainNameOffset = sizeof(*pNewKey); + cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); + pNewKey->domainNameLen = xferStr.DataLen; + + /* + * Get the User Name + */ + str += pNewKey->domainNameLen; + cpylen = + copy_from_user(&xferStr, xplatCall.pObjectName, + sizeof(struct nwc_string)); + pNewKey->objectNameOffset = + pNewKey->domainNameOffset + pNewKey->domainNameLen; + cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); + pNewKey->objectNameLen = xferStr.DataLen; + + /* + * Get the New Password + */ + str += pNewKey->objectNameLen; + cpylen = + copy_from_user(&xferStr, xplatCall.pNewPassword, + sizeof(struct nwc_string)); + pNewKey->newPasswordOffset = + pNewKey->objectNameOffset + pNewKey->objectNameLen; + cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); + pNewKey->newPasswordLen = xferStr.DataLen; + + /* + * Get the Verify Password + */ + str += pNewKey->newPasswordLen; + cpylen = + copy_from_user(&xferStr, xplatCall.pVerifyPassword, + sizeof(struct nwc_string)); + pNewKey->verifyPasswordOffset = + pNewKey->newPasswordOffset + pNewKey->newPasswordLen; + cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); + pNewKey->verifyPasswordLen = xferStr.DataLen; + + status = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + status = reply->Reply.ErrorCode; + kfree(reply); + } + memset(cmd, 0, cmdlen); + + kfree(cmd); + return (status); +} + +int novfs_set_pri_conn(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_set_primary_conn xplatCall; + struct nwd_set_primary_conn *pConn; + unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; + + cpylen = + copy_from_user(&xplatCall, pdata->reqData, + sizeof(struct nwc_set_primary_conn)); + + datalen = sizeof(struct nwd_set_primary_conn); + cmdlen = sizeof(*cmd) + datalen; + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + pConn = (struct nwd_set_primary_conn *) cmd->data; + cmd->dataLen = datalen; + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_SET_PRIMARY_CONN; + pConn->ConnHandle = (void *) (unsigned long) xplatCall.ConnHandle; + status = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + + if (reply) { + status = reply->Reply.ErrorCode; + kfree(reply); + } + kfree(cmd); + return (status); +} + +int novfs_get_pri_conn(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request cmd; + struct novfs_xplat_call_reply *reply; + unsigned long status = -ENOMEM, cmdlen, replylen, cpylen; + + cmdlen = (unsigned long) (&((struct novfs_xplat_call_request *) 0)->data); + + cmd.dataLen = 0; + cmd.Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd.Command.SequenceNumber = 0; + cmd.Command.SessionId = Session; + cmd.NwcCommand = NWC_GET_PRIMARY_CONN; + + status = + Queue_Daemon_Command((void *)&cmd, cmdlen, NULL, 0, (void **)&reply, + &replylen, INTERRUPTIBLE); + + if (reply) { + status = reply->Reply.ErrorCode; + if (!status) { + cpylen = + copy_to_user(pdata->repData, reply->data, + sizeof(unsigned long)); + } + + kfree(reply); + } + + return (status); +} + +int novfs_set_map_drive(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + unsigned long status = 0, datalen, cmdlen, replylen; + struct nwc_map_drive_ex symInfo; + + DbgPrint(""); + cmdlen = sizeof(*cmd); + if (copy_from_user(&symInfo, pdata->reqData, sizeof(symInfo))) + return -EFAULT; + datalen = sizeof(symInfo) + symInfo.dirPathOffsetLength + + symInfo.linkOffsetLength; + + __DbgPrint(" cmdlen = %d\n", cmdlen); + __DbgPrint(" dataLen = %d\n", datalen); + __DbgPrint(" symInfo.dirPathOffsetLength = %d\n", + symInfo.dirPathOffsetLength); + __DbgPrint(" symInfo.linkOffsetLength = %d\n", symInfo.linkOffsetLength); + __DbgPrint(" pdata->datalen = %d\n", pdata->reqLen); + + novfs_dump(sizeof(symInfo), &symInfo); + + cmdlen += datalen; + + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->dataLen = datalen; + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_MAP_DRIVE; + + if (copy_from_user(cmd->data, pdata->reqData, datalen)) { + kfree(cmd); + return -EFAULT; + } + status = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + + if (reply) { + status = reply->Reply.ErrorCode; + kfree(reply); + } + kfree(cmd); + return (status); + +} + +int novfs_unmap_drive(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + unsigned long status = 0, datalen, cmdlen, replylen, cpylen; + struct nwc_unmap_drive_ex symInfo; + + DbgPrint(""); + + cpylen = copy_from_user(&symInfo, pdata->reqData, sizeof(symInfo)); + cmdlen = sizeof(*cmd); + datalen = sizeof(symInfo) + symInfo.linkLen; + + cmdlen += datalen; + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->dataLen = datalen; + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_UNMAP_DRIVE; + + cpylen = copy_from_user(cmd->data, pdata->reqData, datalen); + status = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + + if (reply) { + status = reply->Reply.ErrorCode; + kfree(reply); + } + kfree(cmd); + return (status); +} + +int novfs_enum_drives(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + unsigned long status = 0, cmdlen, replylen, cpylen; + unsigned long offset; + char *cp; + + DbgPrint(""); + + cmdlen = sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->dataLen = 0; + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_ENUMERATE_DRIVES; + status = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + + if (reply) { + status = reply->Reply.ErrorCode; + DbgPrint("Status Code = 0x%X", status); + if (!status) { + offset = + sizeof(((struct nwc_get_mapped_drives *) pdata-> + repData)->MapBuffLen); + cp = reply->data; + replylen = + ((struct nwc_get_mapped_drives *) pdata->repData)-> + MapBuffLen; + cpylen = + copy_to_user(pdata->repData, cp, offset); + cp += offset; + cpylen = + copy_to_user(((struct nwc_get_mapped_drives *) pdata-> + repData)->MapBuffer, cp, + min(replylen - offset, + reply->dataLen - offset)); + } + + kfree(reply); + } + kfree(cmd); + return (status); +} + +int novfs_get_bcast_msg(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + unsigned long cmdlen, replylen; + int status = 0x8866, cpylen; + struct nwc_get_bcast_notification msg; + struct nwd_get_bcast_notification *dmsg; + + cmdlen = sizeof(*cmd) + sizeof(*dmsg); + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cpylen = copy_from_user(&msg, pdata->reqData, sizeof(msg)); + cmd->dataLen = sizeof(*dmsg); + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + + cmd->NwcCommand = NWC_GET_BROADCAST_MESSAGE; + dmsg = (struct nwd_get_bcast_notification *) cmd->data; + dmsg->uConnReference = (void *) (unsigned long) msg.uConnReference; + + status = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + + if (reply) { + status = reply->Reply.ErrorCode; + + if (!status) { + char *cp = pdata->repData; + + dmsg = + (struct nwd_get_bcast_notification *) reply->data; + if (pdata->repLen < dmsg->messageLen) { + dmsg->messageLen = pdata->repLen; + } + msg.messageLen = dmsg->messageLen; + cpylen = + offsetof(struct + nwc_get_bcast_notification, + message); + cp += cpylen; + cpylen = + copy_to_user(pdata->repData, &msg, cpylen); + cpylen = + copy_to_user(cp, dmsg->message, + msg.messageLen); + } else { + msg.messageLen = 0; + msg.message[0] = 0; + cpylen = offsetof(struct + nwc_get_bcast_notification, + message); + cpylen = + copy_to_user(pdata->repData, &msg, + sizeof(msg)); + } + + kfree(reply); + } + kfree(cmd); + return (status); +} + +int novfs_set_key_value(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_set_key xplatCall; + struct nwd_set_key *pNewKey; + struct nwc_string cstrObjectName, cstrPassword; + char *str; + unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; + + cpylen = copy_from_user(&xplatCall, pdata->reqData, sizeof(struct nwc_set_key)); + cpylen = + copy_from_user(&cstrObjectName, xplatCall.pObjectName, + sizeof(struct nwc_string)); + cpylen = + copy_from_user(&cstrPassword, xplatCall.pNewPassword, + sizeof(struct nwc_string)); + + datalen = + sizeof(struct nwd_set_key ) + cstrObjectName.DataLen + cstrPassword.DataLen; + + cmdlen = sizeof(*cmd) + datalen; + cmd = kmalloc(cmdlen, GFP_KERNEL); + + if (!cmd) + return -ENOMEM; + + pNewKey = (struct nwd_set_key *) cmd->data; + cmd->dataLen = datalen; + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_SET_KEY; + + pNewKey->ObjectType = xplatCall.ObjectType; + pNewKey->AuthenticationId = xplatCall.AuthenticationId; + pNewKey->ConnHandle = (void *) (unsigned long) xplatCall.ConnHandle; + str = (char *)pNewKey; + + /* + * Get the User Name + */ + str += sizeof(struct nwd_set_key ); + cpylen = + copy_from_user(str, cstrObjectName.pBuffer, + cstrObjectName.DataLen); + + str += pNewKey->objectNameLen = cstrObjectName.DataLen; + pNewKey->objectNameOffset = sizeof(struct nwd_set_key ); + + /* + * Get the Verify Password + */ + cpylen = + copy_from_user(str, cstrPassword.pBuffer, + cstrPassword.DataLen); + + pNewKey->newPasswordLen = cstrPassword.DataLen; + pNewKey->newPasswordOffset = + pNewKey->objectNameOffset + pNewKey->objectNameLen; + + status = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + status = reply->Reply.ErrorCode; + kfree(reply); + } + kfree(cmd); + return (status); +} + +int novfs_verify_key_value(struct novfs_xplat *pdata, struct novfs_schandle Session) +{ + struct novfs_xplat_call_request *cmd; + struct novfs_xplat_call_reply *reply; + struct nwc_verify_key xplatCall; + struct nwd_verify_key *pNewKey; + struct nwc_string xferStr; + char *str; + unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; + + cpylen = + copy_from_user(&xplatCall, pdata->reqData, sizeof(struct nwc_verify_key)); + + datalen = + sizeof(struct nwd_verify_key) + xplatCall.pDomainName->DataLen + + xplatCall.pObjectName->DataLen + xplatCall.pVerifyPassword->DataLen; + + cmdlen = sizeof(*cmd) + datalen; + cmd = (struct novfs_xplat_call_request *)kmalloc(cmdlen, GFP_KERNEL); + + if (!cmd) + return -ENOMEM; + + pNewKey = (struct nwd_verify_key *) cmd->data; + cmd->dataLen = datalen; + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_VERIFY_KEY; + + pNewKey->NameType = xplatCall.NameType; + pNewKey->ObjectType = xplatCall.ObjectType; + pNewKey->AuthType = xplatCall.AuthType; + str = (char *)pNewKey; + + /* + * Get the tree name + */ + str += sizeof(*pNewKey); + cpylen = + copy_from_user(&xferStr, xplatCall.pDomainName, + sizeof(struct nwc_string)); + pNewKey->domainNameOffset = sizeof(*pNewKey); + cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); + pNewKey->domainNameLen = xferStr.DataLen; + + /* + * Get the User Name + */ + str += pNewKey->domainNameLen; + cpylen = + copy_from_user(&xferStr, xplatCall.pObjectName, + sizeof(struct nwc_string)); + pNewKey->objectNameOffset = + pNewKey->domainNameOffset + pNewKey->domainNameLen; + cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); + pNewKey->objectNameLen = xferStr.DataLen; + + /* + * Get the Verify Password + */ + str += pNewKey->objectNameLen; + cpylen = + copy_from_user(&xferStr, xplatCall.pVerifyPassword, + sizeof(struct nwc_string)); + pNewKey->verifyPasswordOffset = + pNewKey->objectNameOffset + pNewKey->objectNameLen; + cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); + pNewKey->verifyPasswordLen = xferStr.DataLen; + + status = + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, + (void **)&reply, &replylen, + INTERRUPTIBLE); + if (reply) { + status = reply->Reply.ErrorCode; + kfree(reply); + } + kfree(cmd); + return (status); +} --- /dev/null +++ b/fs/novfs/nwcapi.h @@ -0,0 +1,1416 @@ +/* + * NetWare Redirector for Linux + * Author: Sheffer Clark + * + * This file contains all typedefs and constants for the NetWare Client APIs. + * + * Copyright (C) 2005 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ +#ifndef __NWCLNX_H__ +#define __NWCLNX_H__ + +#if 0 //sgled hack +#else //sgled hack (up to endif) + +#define NW_MAX_TREE_NAME_LEN 33 +#define NW_MAX_SERVICE_TYPE_LEN 49 +/* Transport Type - (nuint32 value) */ +#define NWC_TRAN_TYPE_IPX 0x0001 +#define NWC_TRAN_TYPE_DDP 0x0003 +#define NWC_TRAN_TYPE_ASP 0x0004 +#define NWC_TRAN_TYPE_UDP 0x0008 +#define NWC_TRAN_TYPE_TCP 0x0009 +#define NWC_TRAN_TYPE_UDP6 0x000A +#define NWC_TRAN_TYPE_TCP6 0x000B +#define NWC_TRAN_TYPE_WILD 0x8000 + +// +// DeviceIoControl requests for the NetWare Redirector +// +// Macro definition for defining DeviceIoControl function control codes. +// The function codes 0 - 2047 are reserved for Microsoft. +// Function codes 2048 - 4096 are reserved for customers. +// The NetWare Redirector will use codes beginning at 3600. +// +// METHOD_NEITHER User buffers will be passed directly from the application +// to the file system. The redirector is responsible for either probing +// and locking the buffers or using a try - except around access of the +// buffers. + +#define BASE_REQ_NUM 0x4a541000 + +// Connection functions +#define NWC_OPEN_CONN_BY_NAME (BASE_REQ_NUM + 0) +#define NWC_OPEN_CONN_BY_ADDRESS (BASE_REQ_NUM + 1) +#define NWC_OPEN_CONN_BY_REFERENCE (BASE_REQ_NUM + 2) +#define NWC_CLOSE_CONN (BASE_REQ_NUM + 3) +#define NWC_SYS_CLOSE_CONN (BASE_REQ_NUM + 4) +#define NWC_GET_CONN_INFO (BASE_REQ_NUM + 5) +#define NWC_SET_CONN_INFO (BASE_REQ_NUM + 6) +#define NWC_SCAN_CONN_INFO (BASE_REQ_NUM + 7) +#define NWC_MAKE_CONN_PERMANENT (BASE_REQ_NUM + 8) +#define NWC_LICENSE_CONN (BASE_REQ_NUM + 9) +#define NWC_UNLICENSE_CONN (BASE_REQ_NUM + 10) +#define NWC_GET_NUM_CONNS (BASE_REQ_NUM + 11) +#define NWC_GET_PREFERRED_SERVER (BASE_REQ_NUM + 12) +#define NWC_SET_PREFERRED_SERVER (BASE_REQ_NUM + 13) +#define NWC_GET_PRIMARY_CONN (BASE_REQ_NUM + 14) +#define NWC_SET_PRIMARY_CONN (BASE_REQ_NUM + 15) + +// Authentication functions +#define NWC_CHANGE_KEY (BASE_REQ_NUM + 20) +#define NWC_ENUMERATE_IDENTITIES (BASE_REQ_NUM + 21) +#define NWC_GET_IDENTITY_INFO (BASE_REQ_NUM + 22) +#define NWC_LOGIN_IDENTITY (BASE_REQ_NUM + 23) +#define NWC_LOGOUT_IDENTITY (BASE_REQ_NUM + 24) +#define NWC_SET_KEY (BASE_REQ_NUM + 25) +#define NWC_VERIFY_KEY (BASE_REQ_NUM + 26) +#define NWC_AUTHENTICATE_CONN_WITH_ID (BASE_REQ_NUM + 27) +#define NWC_UNAUTHENTICATE_CONN (BASE_REQ_NUM + 28) + +// Directory Services functions +#define NWC_GET_DEFAULT_NAME_CONTEXT (BASE_REQ_NUM + 30) +#define NWC_SET_DEFAULT_NAME_CONTEXT (BASE_REQ_NUM + 31) +#define NWC_GET_PREFERRED_DS_TREE (BASE_REQ_NUM + 32) +#define NWC_SET_PREFERRED_DS_TREE (BASE_REQ_NUM + 33) +#define NWC_GET_TREE_MONITORED_CONN_REF (BASE_REQ_NUM + 34) +#define NWC_NDS_RESOLVE_NAME_TO_ID (BASE_REQ_NUM + 35) + +// NCP Request functions +#define NWC_FRAGMENT_REQUEST (BASE_REQ_NUM + 40) +#define NWC_NCP_ORDERED_REQUEST_ALL (BASE_REQ_NUM + 41) +#define NWC_RAW_NCP_REQUEST (BASE_REQ_NUM + 42) +#define NWC_RAW_NCP_REQUEST_ALL (BASE_REQ_NUM + 43) + +// File Handle Conversion functions +#define NWC_CONVERT_LOCAL_HANDLE (BASE_REQ_NUM + 50) +#define NWC_CONVERT_NETWARE_HANDLE (BASE_REQ_NUM + 51) + +// Misc. functions +#define NWC_MAP_DRIVE (BASE_REQ_NUM + 60) +#define NWC_UNMAP_DRIVE (BASE_REQ_NUM + 61) +#define NWC_ENUMERATE_DRIVES (BASE_REQ_NUM + 62) + +#define NWC_GET_REQUESTER_VERSION (BASE_REQ_NUM + 63) +#define NWC_QUERY_FEATURE (BASE_REQ_NUM + 64) + +#define NWC_GET_CONFIGURED_NSPS (BASE_REQ_NUM + 65) + +#define NWC_GET_MOUNT_PATH (BASE_REQ_NUM + 66) + +#define NWC_GET_BROADCAST_MESSAGE (BASE_REQ_NUM + 67) + +#endif //sgled hack ------------------------------- + +#define IOC_XPLAT 0x4a540002 + +struct novfs_xplat { + int xfunction; + unsigned long reqLen; + void *reqData; + unsigned long repLen; + void *repData; + +}; + +#if 0 +N_EXTERN_LIBRARY(NWRCODE) + NWCLnxReq + (nuint32 request, nptr pInBuf, nuint32 inLen, nptr pOutBuf, nuint32 outLen); +#endif +// +// Network Name Format Type +// + +#define NWC_NAME_FORMAT_NDS 0x0001 +#define NWC_NAME_FORMAT_BIND 0x0002 +#define NWC_NAME_FORMAT_BDP 0x0004 +#define NWC_NAME_FORMAT_NDS_TREE 0x0008 +#define NWC_NAME_FORMAT_WILD 0x8000 + +// +// API String Types +// + +#define NWC_STRING_TYPE_ASCII 0x0001 // multi-byte, not really ascii +#define NWC_STRING_TYPE_UNICODE 0x0002 +#define NWC_STRING_TYPE_UTF8 0x0003 + +// +// Open Connection Flags +// + +#define NWC_OPEN_LICENSED 0x0001 +#define NWC_OPEN_UNLICENSED 0x0002 +#define NWC_OPEN_PRIVATE 0x0004 +#define NWC_OPEN_PUBLIC 0x0008 +#define NWC_OPEN_EXISTING_HANDLE 0x0010 +#define NWC_OPEN_NO_HANDLE 0x0020 +#define NWC_OPEN_PERMANENT 0x0040 +#define NWC_OPEN_DISCONNECTED 0x0080 +#define NWC_OPEN_NEAREST 0x0100 +#define NWC_OPEN_IGNORE_CACHE 0x0200 + +// +// Close Connection Flags +// + +#define NWC_CLOSE_TEMPORARY 0x0000 +#define NWC_CLOSE_PERMANENT 0x0001 + +// +// Connection Information Levels +// + +#define NWC_CONN_INFO_RETURN_ALL 0xFFFF +#define NWC_CONN_INFO_RETURN_NONE 0x0000 +#define NWC_CONN_INFO_VERSION 0x0001 +#define NWC_CONN_INFO_AUTH_STATE 0x0002 +#define NWC_CONN_INFO_BCAST_STATE 0x0003 +#define NWC_CONN_INFO_CONN_REF 0x0004 +#define NWC_CONN_INFO_TREE_NAME 0x0005 +#define NWC_CONN_INFO_WORKGROUP_ID 0x0006 +#define NWC_CONN_INFO_SECURITY_STATE 0x0007 +#define NWC_CONN_INFO_CONN_NUMBER 0x0008 +#define NWC_CONN_INFO_USER_ID 0x0009 +#define NWC_CONN_INFO_SERVER_NAME 0x000A +#define NWC_CONN_INFO_TRAN_ADDR 0x000B +#define NWC_CONN_INFO_NDS_STATE 0x000C +#define NWC_CONN_INFO_MAX_PACKET_SIZE 0x000D +#define NWC_CONN_INFO_LICENSE_STATE 0x000E +#define NWC_CONN_INFO_PUBLIC_STATE 0x000F +#define NWC_CONN_INFO_SERVICE_TYPE 0x0010 +#define NWC_CONN_INFO_DISTANCE 0x0011 +#define NWC_CONN_INFO_SERVER_VERSION 0x0012 +#define NWC_CONN_INFO_AUTH_ID 0x0013 +#define NWC_CONN_INFO_SUSPENDED 0x0014 +#define NWC_CONN_INFO_TREE_NAME_UNICODE 0x0015 +#define NWC_CONN_INFO_SERVER_NAME_UNICODE 0x0016 +#define NWC_CONN_INFO_LOCAL_TRAN_ADDR 0x0017 +#define NWC_CONN_INFO_ALTERNATE_ADDR 0x0018 +#define NWC_CONN_INFO_SERVER_GUID 0x0019 + +#define NWC_CONN_INFO_MAX_LEVEL 0x0014 + +// +// Information Versions +// + +#define NWC_INFO_VERSION_1 0x0001 +#define NWC_INFO_VERSION_2 0x0002 + +// +// Authentication State +// + +#define NWC_AUTH_TYPE_NONE 0x0000 +#define NWC_AUTH_TYPE_BINDERY 0x0001 +#define NWC_AUTH_TYPE_NDS 0x0002 +#define NWC_AUTH_TYPE_PNW 0x0003 + +#define NWC_AUTH_STATE_NONE 0x0000 +#define NWC_AUTH_STATE_BINDERY 0x0001 +#define NWC_AUTH_STATE_NDS 0x0002 +#define NWC_AUTH_STATE_PNW 0x0003 + +// +// Authentication Flags +// + +#define NWC_AUTH_PRIVATE 0x00000004 +#define NWC_AUTH_PUBLIC 0x00000008 + +// +// Broadcast State +// + +#define NWC_BCAST_PERMIT_ALL 0x0000 +#define NWC_BCAST_PERMIT_SYSTEM 0x0001 +#define NWC_BCAST_PERMIT_NONE 0x0002 +#define NWC_BCAST_PERMIT_SYSTEM_POLLED 0x0003 +#define NWC_BCAST_PERMIT_ALL_POLLED 0x0004 + +// +// Broadcast State +// + +#define NWC_NDS_NOT_CAPABLE 0x0000 +#define NWC_NDS_CAPABLE 0x0001 + +// +// License State +// + +#define NWC_NOT_LICENSED 0x0000 +#define NWC_CONNECTION_LICENSED 0x0001 +#define NWC_HANDLE_LICENSED 0x0002 + +// +// Public State +// + +#define NWC_CONN_PUBLIC 0x0000 +#define NWC_CONN_PRIVATE 0x0001 + +// +// Scan Connection Information Flags used +// for finding connections by specific criteria +// + +#define NWC_MATCH_NOT_EQUALS 0x0000 +#define NWC_MATCH_EQUALS 0x0001 +#define NWC_RETURN_PUBLIC 0x0002 +#define NWC_RETURN_PRIVATE 0x0004 +#define NWC_RETURN_LICENSED 0x0008 +#define NWC_RETURN_UNLICENSED 0x0010 + +// +// Authentication Types +// + +#define NWC_AUTHENT_BIND 0x0001 +#define NWC_AUTHENT_NDS 0x0002 +#define NWC_AUTHENT_PNW 0x0003 + +// +// Disconnected info +// + +#define NWC_SUSPENDED 0x0001 + +// +// Maximum object lengths +// + +#define MAX_DEVICE_LENGTH 16 +#define MAX_NETWORK_NAME_LENGTH 1024 +#define MAX_OBJECT_NAME_LENGTH 48 +#define MAX_PASSWORD_LENGTH 128 +#define MAX_SERVER_NAME_LENGTH 48 +#define MAX_SERVICE_TYPE_LENGTH 48 +#define MAX_TREE_NAME_LENGTH 32 +#define MAX_ADDRESS_LENGTH 32 +#define MAX_NAME_SERVICE_PROVIDERS 10 + +// +// Flags for the GetBroadcastMessage API +// + +#define MESSAGE_GET_NEXT_MESSAGE 1 +#define MESSAGE_RECEIVED_FOR_CONNECTION 2 + +// +// This constant must always be equal to the last device +// + +#define DEVICE_LAST_DEVICE 0x00000003 + +// +// Defined feature set provided by requester +// + +#ifndef NWC_FEAT_PRIV_CONN +#define NWC_FEAT_PRIV_CONN 1 +#define NWC_FEAT_REQ_AUTH 2 +#define NWC_FEAT_SECURITY 3 +#define NWC_FEAT_NDS 4 +#define NWC_FEAT_NDS_MTREE 5 +#define NWC_FEAT_PRN_CAPTURE 6 +#define NWC_FEAT_NDS_RESOLVE 7 +#endif + +//===[ Type definitions ]================================================== + + +// +// Structure for defining what a transport +// address looks like +// + +struct nwc_tran_addr { + u32 uTransportType; + u32 uAddressLength; + unsigned char *puAddress; +}; + + +struct nwc_conn_string { + char *pString; + u32 uStringType; + u32 uNameFormatType; + +}; + +//#if defined(NTYPES_H) +//typedef NWCString NwcString, *PNwcString; +//#else +struct nwc_string { + u32 DataType; + u32 BuffSize; + u32 DataLen; + void *pBuffer; + u32 CodePage; + u32 CountryCode; + +}; +//#endif + +// +// Definition of a fragment for the Raw NCP requests +// + +struct nwc_frag { + void *pData; + u32 uLength; + +}; + +// +// Current connection information available for +// enumeration using GetConnInfo and ScanConnInfo +// + +#define NW_INFO_BUFFER_SIZE NW_MAX_TREE_NAME_LEN + \ + NW_MAX_TREE_NAME_LEN + \ + NW_MAX_SERVICE_TYPE_LEN +//++======================================================================= +// API Name: NwcCloseConn +// +// Arguments In: ConnHandle - The handle to a connection that is +// no longer needed. +// +// Arguments Out: NONE +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_CONN_INVALID +// NWE_INVALID_OWNER +// NWE_RESOURCE_LOCK +// +// Abstract: This API is used by an application that opened the +// connection using one of the open connection calls +// is finished using the connection. After it is closed, +// the handle may no longer be used to access the +// connection. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_close_conn { + u32 ConnHandle; + +}; + +//++======================================================================= +// API Name: NwcConvertLocalFileHandle +// +// Arguments In: NONE +// +// Arguments Out: uConnReference - The connection reference associated +// with the returned NetWare file handle. +// +// pNetWareFileHandle - The six byte NetWare file handle +// associated with the given local file handle. +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_RESOURCE_NOT_OWNED +// +// Abstract: This API is used to return the NetWare handle that +// has been associated to a local file handle. +// In addition to returning the NetWare file handle, +// this API also returns the connection reference to +// the connection that owns the file. +// +// Notes: This API does not create a new NetWare handle, it +// only returns the existing handle associated to the +// local handle. +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_convert_local_handle { + u32 uConnReference; + unsigned char NetWareHandle[6]; + +}; + +//++======================================================================= +// API Name: NwcConvertNetWareHandle +// +// Arguments In: ConnHandle - The connection associated with the +// NetWare file handle to convert. +// +// uAccessMode - The access rights to be used when +// allocating the local file handle. +// +// pNetWareHandle - The NetWare handle that will be +// bound to the new local handle being created. +// +// uFileSize - The current file size of the NetWare +// file associated with the given NetWare file handle. +// +// Arguments Out: NONE +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_RESOURCE_NOT_OWNED +// +// Abstract: This API is used to convert a NetWare file handle +// to a local file handle. +// +// The local handle must have been created previously +// by doing a local open to \Special\$Special.net. +// +// Then an Ioctl to this function must be issued using the +// handle returned from the special net open. +// +// Notes: After making this call, the NetWare file handle +// should not be closed using the NetWare library +// call, instead it should be closed using the local +// operating system's close call. +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- +struct nwc_convert_netware_handle { + u32 ConnHandle; + u32 uAccessMode; + unsigned char NetWareHandle[6]; + u32 uFileSize; +}; + + +//++======================================================================= +// API Name: NwcGetConnInfo +// +// Arguments In: ConnHandle - Connection handle for the connection to +// get information on. +// uInfoLevel - Specifies what information should be +// returned. +// uInfoLen - Length of the ConnInfo buffer. +// +// Arguments Out: pConnInfo - A pointer to a buffer to return connection +// information in. If the caller is requesting all +// information the pointer will be to a structure of +// type NwcConnInfo. If the caller is requesting just +// a single piece of information, the pointer is the +// type of information being requested. +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_CONN_INVALID +// NWE_INVALID_OWNER +// NWE_RESOURCE_LOCK +// NWE_STRING_TRANSLATION +// +// Abstract: This API returns connection information for the specified +// connection. The requester can receive one piece of +// information or the whole information structure. +// Some of the entries in the NwcConnInfo structure are +// pointers. The requester is responsible for supplying +// valid pointers for any info specified to be returned. +// If the requester does not want a piece of information +// returned, a NULL pointer should be placed in the field. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_get_conn_info { + u32 ConnHandle; + u32 uInfoLevel; + u32 uInfoLength; + void *pConnInfo; + +}; + +//++======================================================================= +// API Name: NwcGetDefaultNameContext +// +// Arguments In:: uTreeLength - Length of tree string. +// +// pDsTreeName - Pointer to tree string (multi-byte) +// +// pNameLength - On input, this is the length of the +// name context buffer. On output, this is the actual +// length of the name context string. +// +// Arguments Out: pNameContext - The buffer to copy the default name +// context into (multi-byte). +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_BUFFER_OVERFLOW +// NWE_OBJECT_NOT_FOUND +// NWE_PARAM_INVALID +// NWE_RESOURCE_LOCK +// +// Abstract: This API returns the default name context that +// was previously set either by configuration or +// by calling NwcSetDefaultNameContext. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_get_def_name_ctx { + u32 uTreeLength; + unsigned char *pDsTreeName; + u32 uNameLength; +// unsigned short *pNameContext; + unsigned char *pNameContext; + +}; + +//++======================================================================= +// API Name: NwcGetTreeMonitoredConnReference +// +// Arguments In: NONE +// +// Arguments Out: uConnReference - The connection reference associated +// with the monitored connection. +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_OBJECT_NOT_FOUND +// NWE_RESOURCE_LOCK +// +// Abstract: This call returns a connection reference to a +// connection that is monitored. This connection +// reference may be used to open the connection. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_get_tree_monitored_conn_ref { + struct nwc_string *pTreeName; + u32 uConnReference; + +}; + + +//++======================================================================= +// API Name: NwcGetPreferredDsTree +// +// Arguments In: uTreeLength - On input, this is the length in bytes +// of the DS tree name buffer. On output, this is the +// actual length of the DS tree name string in bytes. +// +// Arguments Out: pDsTreeName - The buffer to copy the DS tree name into. +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_BUFFER_OVERFLOW +// NWE_PARAM_INVALID +// NWE_DS_PREFERRED_NOT_FOUND +// NWE_RESOURCE_LOCK +// +// Abstract: This API returns the preferred DS tree name that was +// previously set either by configuration or +// by calling NwcSetPreferredDsTree. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- +struct nwc_get_pref_ds_tree { + u32 uTreeLength; + unsigned char *pDsTreeName; +}; + +//++======================================================================= +// API Name: NwcLicenseConn +// +// Arguments In: ConnHandle - An open connection handle that is in +// an unlicensed state. +// +// Arguments Out: NONE +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_CONN_INVALID +// NWE_HANDLE_ALREADY_LICENSED +// +// +// Abstract: This API changes a connections state to licensed. +// The licensed count will be incremented, and if +// necessary, the license NCP will be sent. +// If this handle is already in a licensed state, +// an error will be returned. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_license_conn { + u32 ConnHandle; +}; + + +//++======================================================================= +// API Name: NWCGetMappedDrives +// +// Arguments In: +// Arguments Out: +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_BUFFER_OVERFLOW +// +// Abstract: This API returns the NetWare mapped drive info +// per user. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_get_mapped_drives { + u32 MapBuffLen; // Buffer length (actual buffer size returned) + struct nwc_mapped_drive_buf *MapBuffer; // Pointer to map buffer + +}; + +//++======================================================================= +// API Name: NwcGetMountPath +// +// Arguments In: MountPathLen - Length of mount path buffer +// including nul terminator. +// +// Arguments Out: MountPath - Pointer to mount path buffer +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_BUFFER_OVERFLOW +// +// Abstract: This API returns the mount point of the NOVFS file +// system. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_get_mount_path { + u32 MountPathLen; + unsigned char *pMountPath; + +}; + +//++======================================================================= +// API Name: NwcOpenConnByAddr +// +// Arguments In: pServiceType - The type of service required. +// +// uConnFlags - Specifies whether this connection +// should be public or private. +// +// pTranAddress - Specifies the transport address of +// the service to open a connection on. +// a connection to. +// +// Arguments Out: ConnHandle - The new connection handle returned. +// This handle may in turn be used for all requests +// directed to this connection. +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_INSUFFICIENT_RESOURCES +// NWE_TRAN_INVALID_TYPE +// NWE_RESOURCE_LOCK +// NWE_UNSUPPORTED_TRAN_TYPE +// +// Abstract: This API will create a service connection to +// the service specified by the transport address. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_open_conn_by_addr { + char *pServiceType; + u32 uConnFlags; + struct nwc_tran_addr *pTranAddr; + u32 ConnHandle; + +}; + +//++======================================================================= +// API Name: NwcOpenConnByName +// +// Arguments In: ConnHandle - The connection to use when resolving +// a name. For instance, if the name is a bindery name +// the requester will scan the bindery of the given +// connection to retrieve the service's address. This +// value can also be NULL if the caller doesn't care +// which connection is used to resolve the address. +// +// pName - A pointer to the name of the service trying +// to be connected to. This string is NULL terminated, +// contains no wild cards, and is a maximum of 512 +// characters long. +// +// pServiceType - The type of service required. +// +// uConnFlags - Specifies whether this connection +// should be public or private. +// +// uTranType - Specifies the preferred or required +// transport type to be used. +// NWC_TRAN_TYPE_WILD may be ORed with the other values +// or used alone. When ORed with another value, the +// wild value indicates an unmarked alternative is +// acceptable. When used alone, the current preferred +// transport is used. +// +// Arguments Out: ConnHandle - The new connection handle returned. +// This handle may in turn be used for all requests +// directed to this connection. +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_BUFFER_OVERFLOW +// NWE_INSUFFICIENT_RESOURCES +// NWE_INVALID_STRING_TYPE +// NWE_RESOURCE_LOCK +// NWE_STRING_TRANSLATION +// NWE_TRAN_INVALID_TYPE +// NWE_UNSUPPORTED_TRAN_TYPE +// +// Abstract: This API will resolve the given name to a network +// address then create a service connection to the +// specified service. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_open_conn_by_name { + u32 ConnHandle; + struct nwc_conn_string *pName; + char *pServiceType; + u32 uConnFlags; + u32 uTranType; + u32 RetConnHandle; + +}; + +//++======================================================================= +// API Name: NwcOpenConnByReference +// +// Arguments In: uConnReference - A reference handle which identifies +// a valid connection that the caller wants to obtain +// a connection handle to. A reference handle can be +// used to get information about the connection without +// actually getting a handle to it. A connection handle +// must be used to make actual requests to that +// connection. +// +// uConnFlags - Currently unused. +// +// Arguments Out: ConnHandle - The new connection handle returned. +// This handle may in turn be used for all requests +// directed to this connection. +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_CONN_INVALID +// +// Abstract: This API will open the connection associated with +// the given connection reference. The connection +// reference can be obtained by calling the +// NwcScanConnInfo API. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_open_conn_by_ref { + u32 uConnReference; + u32 uConnFlags; + u32 ConnHandle; + +}; + +//++======================================================================= +// API Name: NwcRawRequest +// +// Arguments In: ConnHandle - The connection handle of the connection +// that the request is being directed to. +// +// uFunction - The NCP function that is being called. +// +// uNumRequestFrags - The number of fragments that the +// request packet has been broken into. +// +// pRequestFrags - List of fragments that make up the +// request packet. Each fragment includes the length +// of the fragment data and a pointer to the data. +// +// uNumReplyFrags - The number of fragments the reply +// packet has been broken into. +// +// Arguments Out: pReplyFrags - List of fragments that make up the +// request packet. Each fragment includes the length +// of the fragment data and a pointer to the data. +// +// uActualReplyLength - Total size of the reply packet +// after any header and tail information is removed. +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_CONN_INVALID +// +// Abstract: API for sending raw NCP packets directly to a server. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_request { + u32 ConnHandle; + u32 uFunction; + u32 uNumRequestFrags; + struct nwc_frag *pRequestFrags; + u32 uNumReplyFrags; + struct nwc_frag *pReplyFrags; + u32 uActualReplyLength; + +}; + +//++======================================================================= +// API Name: NwcScanConnInfo +// +// Arguments In: uScanIndex - The index to be used on the next +// iteration of the scan. This value should be initially +// set to zero. The output of this parameter will be +// used in subsequent calls to this function. +// +// uScanInfoLevel - Describes the composition of the +// pScanConnInfo pointer. If this parameter contains +// NWC_CONN_INFO_RETURN_ALL, information for all +// connections will be returned. +// +// uScanInfoLen - Lenght of pScanConnInfo buffer +// +// pScanConnInfo - This parameter is a pointer to +// data that describes one piece of connection +// information. The type of this data depends on +// which level of information is being scanned for. +// For instance, if the scan is being used to find all +// connections with a particular authentication state, +// pScanConnInfo would be a "pnuint" since +// authentication state is described as nuint in the +// NwcConnInfo structure. +// +// uScanFlag - This parameter tells whether to return +// connection information for connections that match +// the scan criteria or that do not match the scan +// criteria. If the caller wants to find all the +// connections that are not in the "NOVELL_INC" DS +// tree, he would use the call as described below in +// the description except the uScanFlag parameter would +// have the value of NWC_MATCH_NOT_EQUALS. This flag +// is also used to tell the requester whether to +// return private or public, licensed or unlicensed +// connections. +// +// uReturnInfoLevel - Specifies what information +// should be returned. +// +// uReturnInfoLength - The size in bytes of pConnInfo. +// +// Arguments Out: uConnectionReference - Connection reference +// associated with the information that is being +// returned. +// +// pReturnConnInfo - A pointer to the NwcConnInfo +// structure defined above. In some of the +// structures within the union, there are pointers to +// data to be returned. It is the responsibility of +// the caller to provide pointers to valid memory +// to copy this data into. +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_RESOURCE_LOCK +// NWE_CONN_INVALID +// NWE_INVALID_LEVEL +// NWE_STRING_TRANSLATION +// NWE_INVALID_MATCH_DATA +// NWE_MATCH_FAILED +// NWE_BUFFER_OVERFLOW +// NWE_NO_MORE_ENTRIES +// +// Abstract: This API is used to return connection information +// for multiple connections. It will return one +// piece or the full structure of connection information +// for one connection at a time. This call is designed +// to scan for connections based on any piece of +// connection information as described in the +// NwcConnInfo structure. For instance, if the caller +// wants to scan for all connections in the DS tree +// "NOVELL_INC", the call would be made with the +// following paramters: +// +// uScanLevelInfo = NWC_CONN_INFO_TREE_NAME +// pScanConnInfo = "NOVELL_INC" +// uScanFlag = NWC_MATCH_EQUALS | +// NWC_RETURN_PUBLIC | +// NWC_RETURN_LICENSED +// +// The scan flag is used to tell if the scan is +// supposed to return connections that match or don't +// match. This design doesn't allow any other +// conditions for this flag (such as greater than or +// less than). +// +// If the caller specifies the uReturnInfoLevel = +// NWC_CONN_INFO_RETURN_ALL, the full NwcConnInfo +// structure is returned. The caller must supply +// data for any pointers in the NwcConnInfo structure +// (these include tree name, workgroup id, server name +// and transport address). However if the caller +// doesn't want to get a particular piece of info +// that is expecting a pointer to some data, a NULL +// pointer may be used to indicate to the requester +// that it should not return that piece of information. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_scan_conn_info { + u32 uScanIndex; + u32 uScanInfoLevel; + u32 uScanInfoLen; + void *pScanConnInfo; + u32 uScanFlags; + u32 uReturnInfoLevel; + u32 uReturnInfoLength; + u32 uConnectionReference; + void *pReturnConnInfo; + +}; + +//++======================================================================= +// API Name: NwcSetConnInfo +// +// Arguments In: ConnHandle - Connection handle for the connection to +// set information on. +// +// uInfoLevel - Specifies what information should be set. +// +// uInfoLen - Length in bytes of the information being set. +// +// pConnInfo - Connection information to set. +// +// Arguments Out: NONE +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_RESOURCE_LOCK +// NWE_CONN_INVALID +// NWE_INVALID_LEVEL +// +// +// Abstract: This API sets information in the connection associated +// with the connection handle. +// +// Notes: At this time the only setable information levels are: +// NWC_CONN_INFO_AUTH_STATE +// NWC_CONN_INFO_BCAST_STATE +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_set_conn_info { + u32 ConnHandle; + u32 uInfoLevel; + u32 uInfoLength; + void *pConnInfo; + +}; + +//++======================================================================= +// API Name: NwcSetDefaultNameContext +// +// Arguments In:: uTreeLength - Length of tree string. +// +// pDsTreeName - The tree string (multi-byte). +// +// uNameLength - The length in bytes of the name +// context string. +// +// pNameContext - The string to be used as the default +// name context (multi-byte). +// +// Arguments Out: NONE +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_PARAM_INVALID +// NWE_RESOURCE_LOCK +// NWE_STRING_TRANSLATION +// +// Abstract: This API sets the default name context. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_set_def_name_ctx { + u32 uTreeLength; + unsigned char *pDsTreeName; + u32 uNameLength; +// unsined short *pNameContext; + unsigned char *pNameContext; + +}; + +//++======================================================================= +// API Name: NwcSetPreferredDsTree +// +// Arguments In: uTreeLength - The length in bytes of the DS tree name. +// +// pDsTreeName - The string to be used as the preferred +// DS tree name. +// +// Arguments Out: NONE +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_INSUFFICIENT_RESOURCES +// NWE_RESOURCE_LOCK +// +// Abstract: This API sets the preferred DS tree name. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_set_pref_ds_tree { + u32 uTreeLength; + unsigned char *pDsTreeName; + +}; + +//++======================================================================= +// API Name: NwcSetPrimaryConnection +// +// Arguments In: ConnHandle - Connection handle associated to the +// connection reference which the caller wishes to set +// as primary. +// +// Arguments Out: NONE +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// NWE_CONN_PRIMARY_NOT_SET +// +// Abstract: This API sets the primary connection according to +// the connection handle passed in by the caller. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_set_primary_conn { + u32 ConnHandle; + +}; + + +//++======================================================================= +// API Name: NwcQueryFeature +// +// Arguments In: Feature - The number associated with a particular +// feature that the caller wants to know if the requester +// is supporting +// +// Arguments Out: +// +// Returns: STATUS_SUCCESS +// NWE_REQUESTER_FAILURE +// NWE_ACCESS_VIOLATION +// +// Abstract: +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_query_feature { + u32 Feature; + +}; + +//++======================================================================= +// API Name: NWCChangePassword +// +// Arguments In: +// +// Arguments Out: +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// +// Abstract: +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_change_key { + struct nwc_string *pDomainName; + u32 AuthType; + struct nwc_string *pObjectName; + u32 NameType; + u16 ObjectType; + struct nwc_string *pVerifyPassword; + struct nwc_string *pNewPassword; + +}; + +//++======================================================================= +// API Name: NWCEnumerateIdentities ` +// +// Arguments In: +// +// Arguments Out: +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// +// Abstract: +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_enum_ids { + u32 Iterator; + struct nwc_string *pDomainName; + u32 AuthType; + struct nwc_string *pObjectName; + u32 NameType; + u16 ObjectType; + u32 IdentityFlags; + u32 AuthenticationId; + +}; + +//++======================================================================= +// API Name: NWCGetIdentityInfo +// +// Arguments In: +// +// Arguments Out: +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// +// Abstract: +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_get_id_info { + u32 AuthenticationId; + struct nwc_string *pDomainName; + u32 AuthType; + struct nwc_string *pObjectName; + u32 NameType; + u16 ObjectType; + u32 IdentityFlags; + +}; + +//++======================================================================= +// API Name: NWCLoginIdentity +// +// Arguments In: +// +// Arguments Out: +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// +// Abstract: +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_login_id { + struct nwc_string *pDomainName; + u32 AuthType; + struct nwc_string *pObjectName; + u32 NameType; + u16 ObjectType; + u32 IdentityFlags; + struct nwc_string *pPassword; + u32 AuthenticationId; + +}; + + +//++======================================================================= +// API Name: NWCSetPassword +// +// Arguments In: +// +// Arguments Out: +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// +// Abstract: +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_set_key { + u32 ConnHandle; + u32 AuthenticationId; + struct nwc_string *pObjectName; + u16 ObjectType; + struct nwc_string *pNewPassword; + +}; + +//++======================================================================= +// API Name: NWCVerifyPassword +// +// Arguments In: +// +// Arguments Out: +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// +// Abstract: +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//++======================================================================= + +struct nwc_verify_key { + struct nwc_string *pDomainName; + u32 AuthType; + struct nwc_string *pObjectName; + u32 NameType; + u16 ObjectType; + struct nwc_string *pVerifyPassword; + +}; + +//++======================================================================= +// API Name: NwcAuthenticateWithId +// +// Arguments In: ConnHandle - The connection to be authenticated +// +// AuthenticationId - the authentication Id associated +// to the information necessary to authenticate this +// connection. +// +// Arguments Out: NONE +// +// Returns: STATUS_SUCCESS +// NWE_ACCESS_VIOLATION +// +// Abstract: This API is used to authenticate a connection using +// an authentication ID that has already been created. +// +// Notes: +// +// Environment: PASSIVE_LEVEL, LINUX +// +//=======================================================================-- + +struct nwc_auth_with_id { + u32 ConnHandle; + u32 AuthenticationId; + +}; + + +struct nwc_unmap_drive_ex { +// unsigned long connHdl; + unsigned int linkLen; + char linkData[1]; + +}; + +struct nwc_map_drive_ex { + u32 ConnHandle; + unsigned int localUid; + unsigned int linkOffsetLength; + unsigned int linkOffset; + unsigned int dirPathOffsetLength; + unsigned int dirPathOffset; +}; + +struct nwc_get_bcast_notification { + u32 uMessageFlags; + u32 uConnReference; + u32 messageLen; + char message[1]; +}; + +#endif /* __NWCLNX_H__ */ --- /dev/null +++ b/fs/novfs/nwerror.h @@ -0,0 +1,658 @@ +/* + * NetWare Redirector for Linux + * Author: Tom Buckley + * + * This file contains all return error codes. + * + * Copyright (C) 2005 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ +#ifndef __NOVFS_ERROR_H +#define __NOVFS_ERROR_H + + +/* + * Network errors + * Decimal values at end of line are 32768 lower than actual + */ + +#define SHELL_ERROR 0x8800 +#define VLM_ERROR 0x8800 +#define ALREADY_ATTACHED 0x8800 // 0 - Attach attempted to server with valid, existing connection +#define INVALID_CONNECTION 0x8801 // 1 - Request attempted with invalid or non-attached connection handle +#define DRIVE_IN_USE 0x8802 // 2 - OS/2 only (NOT USED) +#define CANT_ADD_CDS 0x8803 // 3 - Map drive attempted but unable to add new current directory structure +#define DRIVE_CANNOT_MAP 0x8803 +#define BAD_DRIVE_BASE 0x8804 // 4 - Map drive attempted with invalid path specification +#define NET_READ_ERROR 0x8805 // 5 - Attempt to receive from the selected transport failed +#define NET_RECV_ERROR 0x8805 // 5 +#define UNKNOWN_NET_ERROR 0x8806 // 6 - Network send attempted with an un-specific network error +#define SERVER_INVALID_SLOT 0x8807 // 7 - Server request attempted with invalid server connection slot +#define BAD_SERVER_SLOT 0x8807 // 7 +#define NO_SERVER_SLOTS 0x8808 // 8 - Attach attempted to server with no connection slots available +#define NET_WRITE_ERROR 0x8809 // 9 - Attempt to send on the selected transport failed +#define CONNECTION_IN_ERROR_STATE 0x8809 // Client-32 +#define NET_SEND_ERROR 0x8809 // 9 +#define SERVER_NO_ROUTE 0x880A // 10 - Attempted to find route to server where no route exists +#define BAD_LOCAL_TARGET 0x880B // 11 - OS/2 only +#define TOO_MANY_REQ_FRAGS 0x880C // 12 - Attempted request with too many request fragments specified +#define CONNECT_LIST_OVERFLOW 0x880D // 13 +#define BUFFER_OVERFLOW 0x880E // 14 - Attempt to receive more data than the reply buffer had room for +#define MORE_DATA_ERROR 0x880E // Client-32 +#define NO_CONN_TO_SERVER 0x880F // 15 +#define NO_CONNECTION_TO_SERVER 0x880F // 15 - Attempt to get connection for a server not connected +#define NO_ROUTER_FOUND 0x8810 // 16 - OS/2 only +#define BAD_FUNC_ERROR 0x8811 // 17 +#define INVALID_SHELL_CALL 0x8811 // 17 - Attempted function call to non- existent or illegal function +#define SCAN_COMPLETE 0x8812 +#define LIP_RESIZE_ERROR 0x8812 // Client-32 +#define UNSUPPORTED_NAME_FORMAT_TYPE 0x8813 +#define INVALID_DIR_HANDLE 0x8813 // Client-32 +#define HANDLE_ALREADY_LICENSED 0x8814 +#define OUT_OF_CLIENT_MEMORY 0x8814 // Client-32 +#define HANDLE_ALREADY_UNLICENSED 0x8815 +#define PATH_NOT_OURS 0x8815 // Client-32 +#define INVALID_NCP_PACKET_LENGTH 0x8816 +#define PATH_IS_PRINT_DEVICE 0x8816 // Client-32 +#define SETTING_UP_TIMEOUT 0x8817 +#define PATH_IS_EXCLUDED_DEVICE 0x8817 // Client-32 +#define SETTING_SIGNALS 0x8818 +#define PATH_IS_INVALID 0x8818 // Client-32 +#define SERVER_CONNECTION_LOST 0x8819 +#define NOT_SAME_DEVICE 0x8819 // Client-32 +#define OUT_OF_HEAP_SPACE 0x881A +#define INVALID_SERVICE_REQUEST 0x881B +#define INVALID_SEARCH_HANDLE 0x881B // Client-32 +#define INVALID_TASK_NUMBER 0x881C +#define INVALID_DEVICE_HANDLE 0x881C // Client-32 +#define INVALID_MESSAGE_LENGTH 0x881D +#define INVALID_SEM_HANDLE 0x881D // Client-32 +#define EA_SCAN_DONE 0x881E +#define INVALID_CFG_HANDLE 0x881E // Client-32 +#define BAD_CONNECTION_NUMBER 0x881F +#define INVALID_MOD_HANDLE 0x881F // Client-32 +#define ASYN_FIRST_PASS 0x8820 +#define INVALID_DEVICE_INDEX 0x8821 +#define INVALID_CONN_HANDLE 0x8822 +#define INVALID_QUEUE_ID 0x8823 +#define INVALID_PDEVICE_HANDLE 0x8824 +#define INVALID_JOB_HANDLE 0x8825 +#define INVALID_ELEMENT_ID 0x8826 +#define ALIAS_NOT_FOUND 0x8827 +#define RESOURCE_SUSPENDED 0x8828 +#define INVALID_QUEUE_SPECIFIED 0x8829 +#define DEVICE_ALREADY_OPEN 0x882A +#define JOB_ALREADY_OPEN 0x882B +#define QUEUE_NAME_ID_MISMATCH 0x882C +#define JOB_ALREADY_STARTED 0x882D +#define SPECT_DAA_TYPE_NOT_SUPPORTED 0x882E +#define INVALID_ENVIR_HANDLE 0x882F +#define NOT_SAME_CONNECTION 0x8830 // 48 - Internal server request attempted accross different server connections +#define PRIMARY_CONNECTION_NOT_SET 0x8831 // 49 - Attempt to retrieve default connection with no primary connection set +#define NO_PRIMARY_SET 0x8831 // 49 +#define KEYWORD_NOT_FOUND 0x8832 // Client-32 +#define PRINT_CAPTURE_NOT_IN_PROGRESS 0x8832 // Client-32 +#define NO_CAPTURE_SET 0x8832 // 50 +#define NO_CAPTURE_IN_PROGRESS 0x8832 // 50 - Capture information requested on port with no capture in progress +#define BAD_BUFFER_LENGTH 0x8833 // 51 +#define INVALID_BUFFER_LENGTH 0x8833 // 51 - Used to indicate length which caller requested on a GetDNC or SetDNC was too large +#define NO_USER_NAME 0x8834 // 52 +#define NO_NETWARE_PRINT_SPOOLER 0x8835 // 53 - Capture requested without having the local print spooler installed +#define INVALID_PARAMETER 0x8836 // 54 - Attempted function with an invalid function parameter specified +#define CONFIG_FILE_OPEN_FAILED 0x8837 // 55 - OS/2 only +#define NO_CONFIG_FILE 0x8838 // 56 - OS/2 only +#define CONFIG_FILE_READ_FAILED 0x8839 // 57 - OS/2 only +#define CONFIG_LINE_TOO_LONG 0x883A // 58 - OS/2 only +#define CONFIG_LINES_IGNORED 0x883B // 59 - OS/2 only +#define NOT_MY_RESOURCE 0x883C // 60 - Attempted request made with a parameter using foriegn resource +#define DAEMON_INSTALLED 0x883D // 61 - OS/2 only +#define SPOOLER_INSTALLED 0x883E // 62 - Attempted load of print spooler with print spooler already installed +#define CONN_TABLE_FULL 0x883F // 63 +#define CONNECTION_TABLE_FULL 0x883F // 63 - Attempted to allocate a connection handle with no more local connection table entries +#define CONFIG_SECTION_NOT_FOUND 0x8840 // 64 - OS/2 only +#define BAD_TRAN_TYPE 0x8841 // 65 +#define INVALID_TRANSPORT_TYPE 0x8841 // 65 - Attempted function on a connection with an invalid transport selected +#define TDS_TAG_IN_USE 0x8842 // 66 - OS/2 only +#define TDS_OUT_OF_MEMORY 0x8843 // 67 - OS/2 only +#define TDS_INVALID_TAG 0x8844 // 68 - Attempted TDS function with invalid tag +#define TDS_WRITE_TRUNCATED 0x8845 // 69 - Attempted TDS write with buffer that exceeded buffer +#define NO_CONNECTION_TO_DS 0x8846 // Client-32 +#define NO_DIRECTORY_SERVICE_CONNECTION 0x8846 // 70 +#define SERVICE_BUSY 0x8846 // 70 - Attempted request made to partially asynchronous function in busy state +#define NO_SERVER_ERROR 0x8847 // 71 - Attempted connect failed to find any servers responding +#define BAD_VLM_ERROR 0x8848 // 72 - Attempted function call to non-existant or not-loaded overlay +#define NETWORK_DRIVE_IN_USE 0x8849 // 73 - Attempted map to network drive that was already mapped +#define LOCAL_DRIVE_IN_USE 0x884A // 74 - Attempted map to local drive that was in use +#define NO_DRIVES_AVAILABLE 0x884B // 75 - Attempted map to next available drive when none were available +#define DEVICE_NOT_REDIRECTED 0x884C // 76 - The device is not redirected +#define NO_MORE_SFT_ENTRIES 0x884D // 77 - Maximum number of files was reached +#define UNLOAD_ERROR 0x884E // 78 - Attempted unload failed +#define IN_USE_ERROR 0x884F // 79 - Attempted re-use of already in use connection entry +#define TOO_MANY_REP_FRAGS 0x8850 // 80 - Attempted request with too many reply fragments specified +#define TABLE_FULL 0x8851 // 81 - Attempted to add a name into the name table after it was full +#ifndef SOCKET_NOT_OPEN +#define SOCKET_NOT_OPEN 0x8852 // 82 - Listen was posted on unopened socket +#endif +#define MEM_MGR_ERROR 0x8853 // 83 - Attempted enhanced memory operation failed +#define SFT3_ERROR 0x8854 // 84 - An SFT3 switch occured mid-transfer +#define PREFERRED_NOT_FOUND 0x8855 // 85 - the preferred directory server was not established but another directory server was returned +#define DEVICE_NOT_RECOGNIZED 0x8856 // 86 - used to determine if the device is not used by VISE so pass it on to the next redirector, if any. +#define BAD_NET_TYPE 0x8857 // 87 - the network type (Bind/NDS) does not match the server version +#define ERROR_OPENING_FILE 0x8858 // 88 - generic open failure error, invalid path, access denied, etc.. +#define NO_PREFERRED_SPECIFIED 0x8859 // 89 - no preferred name specified +#define ERROR_OPENING_SOCKET 0x885A // 90 - error opening a socket +#define REQUESTER_FAILURE 0x885A // Client-32 +#define RESOURCE_ACCESS_DENIED 0x885B // Client-32 +#define SIGNATURE_LEVEL_CONFLICT 0x8861 +#define NO_LOCK_FOUND 0x8862 // OS/2 - process lock on conn handle failed, process ID not recognized +#define LOCK_TABLE_FULL 0x8863 // OS/2 - process lock on conn handle failed, process lock table full +#define INVALID_MATCH_DATA 0x8864 +#define MATCH_FAILED 0x8865 +#define NO_MORE_ENTRIES 0x8866 +#define INSUFFICIENT_RESOURCES 0x8867 +#define STRING_TRANSLATION 0x8868 +#define STRING_TRANSLATION_NEEDED 0x8868 // Client-32 +#define ACCESS_VIOLATION 0x8869 +#define NOT_AUTHENTICATED 0x886A +#define INVALID_LEVEL 0x886B +#define RESOURCE_LOCK_ERROR 0x886C +#define INVALID_NAME_FORMAT 0x886D +#define OBJECT_EXISTS 0x886E +#define OBJECT_NOT_FOUND 0x886F +#define UNSUPPORTED_TRAN_TYPE 0x8870 +#define INVALID_STRING_TYPE 0x8871 +#define INVALID_OWNER 0x8872 +#define UNSUPPORTED_AUTHENTICATOR 0x8873 +#define IO_PENDING 0x8874 +#define INVALID_DRIVE_NUM 0x8875 +#define SHELL_FAILURE 0x88FF +#define VLM_FAILURE 0x88FF + +#define SVC_ALREADY_REGISTERED 0x8880 // Client-32 +#define SVC_REGISTRY_FULL 0x8881 // Client-32 +#define SVC_NOT_REGISTERED 0x8882 // Client-32 +#define OUT_OF_RESOURCES 0x8883 // Client-32 +#define RESOLVE_SVC_FAILED 0x8884 // Client-32 +#define CONNECT_FAILED 0x8885 // Client-32 +#define PROTOCOL_NOT_BOUND 0x8886 // Client-32 +#define AUTHENTICATION_FAILED 0x8887 // Client-32 +#define INVALID_AUTHEN_HANDLE 0x8888 // Client-32 +#define AUTHEN_HANDLE_ALREADY_EXISTS 0x8889 // Client-32 + +#define DIFF_OBJECT_ALREADY_AUTHEN 0x8890 // Client-32 +#define REQUEST_NOT_SERVICEABLE 0x8891 // Client-32 +#define AUTO_RECONNECT_SO_REBUILD 0x8892 // Client-32 +#define AUTO_RECONNECT_RETRY_REQUEST 0x8893 // Client-32 +#define ASYNC_REQUEST_IN_USE 0x8894 // Client-32 +#define ASYNC_REQUEST_CANCELED 0x8895 // Client-32 +#define SESS_SVC_ALREADY_REGISTERED 0x8896 // Client-32 +#define SESS_SVC_NOT_REGISTERED 0x8897 // Client-32 +#define PREVIOUSLY_AUTHENTICATED 0x8899 // Client-32 +#define RESOLVE_SVC_PARTIAL 0x889A // Client-32 +#define NO_DEFAULT_SPECIFIED 0x889B // Client-32 +#define HOOK_REQUEST_NOT_HANDLED 0x889C // Client-32 +#define HOOK_REQUEST_BUSY 0x889D // Client-32 +#define HOOK_REQUEST_QUEUED 0x889D // Client-32 +#define AUTO_RECONNECT_SO_IGNORE 0x889E // Client-32 +#define ASYNC_REQUEST_NOT_IN_USE 0x889F // Client-32 +#define AUTO_RECONNECT_FAILURE 0x88A0 // Client-32 +#define NET_ERROR_ABORT_APPLICATION 0x88A1 // Client-32 +#define NET_ERROR_SUSPEND_APPLICATION 0x88A2 // Client-32 +#define NET_ERROR_ABORTED_PROCESS_GROUP 0x88A3 // Client-32 +#define NET_ERROR_PASSWORD_HAS_EXPIRED 0x88A5 // Client-32 +#define NET_ERROR_NETWORK_INACTIVE 0x88A6 // Client-32 +#define REPLY_TRUNCATED 0x88E6 // 230 NLM +#define UTF8_CONVERSION_FAILED 0x88F0 // NWCALLS + +/* + * Server Errors + */ + +#define ERR_INSUFFICIENT_SPACE 0x8901 // 001 +#define NLM_INVALID_CONNECTION 0x890A // 010 +#define ERR_TIMEOUT 0x8910 // 016 - nlm connection timeout +#define ERR_NO_MORE_ENTRY 0x8914 // 020 +#define ERR_BUFFER_TOO_SMALL 0x8977 // 119 +#define ERR_VOLUME_FLAG_NOT_SET 0x8978 // 120 the service requested, not avail. on the selected vol. +#define ERR_NO_ITEMS_FOUND 0x8979 // 121 +#define ERR_CONN_ALREADY_TEMP 0x897A // 122 +#define ERR_CONN_ALREADY_LOGGED_IN 0x897B // 123 +#define ERR_CONN_NOT_AUTHENTICATED 0x897C // 124 +#define ERR_CONN_NOT_LOGGED_IN 0x897D // 125 +#define NCP_BOUNDARY_CHECK_FAILED 0x897E // 126 +#define ERR_LOCK_WAITING 0x897F // 127 +#define ERR_LOCK_FAIL 0x8980 // 128 +#define FILE_IN_USE_ERROR 0x8980 // 128 +#define NO_MORE_FILE_HANDLES 0x8981 // 129 +#define NO_OPEN_PRIVILEGES 0x8982 // 130 +#define IO_ERROR_NETWORK_DISK 0x8983 // 131 +#define ERR_AUDITING_HARD_IO_ERROR 0x8983 // 131 +#define NO_CREATE_PRIVILEGES 0x8984 // 132 +#define ERR_AUDITING_NOT_SUPV 0x8984 // 132 +#define NO_CREATE_DELETE_PRIVILEGES 0x8985 // 133 +#define CREATE_FILE_EXISTS_READ_ONLY 0x8986 // 134 +#define WILD_CARDS_IN_CREATE_FILE_NAME 0x8987 // 135 +#define CREATE_FILENAME_ERROR 0x8987 // 135 +#define INVALID_FILE_HANDLE 0x8988 // 136 +#define NO_SEARCH_PRIVILEGES 0x8989 // 137 +#define NO_DELETE_PRIVILEGES 0x898A // 138 +#define NO_RENAME_PRIVILEGES 0x898B // 139 +#define NO_MODIFY_PRIVILEGES 0x898C // 140 +#define SOME_FILES_AFFECTED_IN_USE 0x898D // 141 +#define NO_FILES_AFFECTED_IN_USE 0x898E // 142 +#define SOME_FILES_AFFECTED_READ_ONLY 0x898F // 143 +#define NO_FILES_AFFECTED_READ_ONLY 0x8990 // 144 +#define SOME_FILES_RENAMED_NAME_EXISTS 0x8991 // 145 +#define NO_FILES_RENAMED_NAME_EXISTS 0x8992 // 146 +#define NO_READ_PRIVILEGES 0x8993 // 147 +#define NO_WRITE_PRIVILEGES_OR_READONLY 0x8994 // 148 +#define FILE_DETACHED 0x8995 // 149 +#define SERVER_OUT_OF_MEMORY 0x8996 // 150 +#define ERR_TARGET_NOT_A_SUBDIRECTORY 0x8996 // 150 can be changed later (note written by server people). +#define NO_DISK_SPACE_FOR_SPOOL_FILE 0x8997 // 151 +#define ERR_AUDITING_NOT_ENABLED 0x8997 // 151 +#define VOLUME_DOES_NOT_EXIST 0x8998 // 152 +#define DIRECTORY_FULL 0x8999 // 153 +#define RENAMING_ACROSS_VOLUMES 0x899A // 154 +#define BAD_DIRECTORY_HANDLE 0x899B // 155 +#define INVALID_PATH 0x899C // 156 +#define NO_MORE_TRUSTEES 0x899C // 156 +#define NO_MORE_DIRECTORY_HANDLES 0x899D // 157 +#define INVALID_FILENAME 0x899E // 158 +#define DIRECTORY_ACTIVE 0x899F // 159 +#define DIRECTORY_NOT_EMPTY 0x89A0 // 160 +#define DIRECTORY_IO_ERROR 0x89A1 // 161 +#define READ_FILE_WITH_RECORD_LOCKED 0x89A2 // 162 +#define ERR_TRANSACTION_RESTARTED 0x89A3 // 163 +#define ERR_RENAME_DIR_INVALID 0x89A4 // 164 +#define ERR_INVALID_OPENCREATE_MODE 0x89A5 // 165 +#define ERR_ALREADY_IN_USE 0x89A6 // 166 +#define ERR_AUDITING_ACTIVE 0x89A6 // 166 +#define ERR_INVALID_RESOURCE_TAG 0x89A7 // 167 +#define ERR_ACCESS_DENIED 0x89A8 // 168 +#define ERR_AUDITING_NO_RIGHTS 0x89A8 // 168 +#define ERR_LINK_IN_PATH 0x89A9 // 169 +#define INVALID_DATA_TYPE 0x89AA // 170 +#define INVALID_DATA_STREAM 0x89BE // 190 +#define INVALID_NAME_SPACE 0x89BF // 191 +#define NO_ACCOUNTING_PRIVILEGES 0x89C0 // 192 +#define LOGIN_DENIED_NO_ACCOUNT_BALANCE 0x89C1 // 193 +#define LOGIN_DENIED_NO_CREDIT 0x89C2 // 194 +#define ERR_AUDITING_RECORD_SIZE 0x89C2 // 194 +#define ERR_TOO_MANY_HOLDS 0x89C3 // 195 +#define ACCOUNTING_DISABLED 0x89C4 // 196 +#define INTRUDER_DETECTION_LOCK 0x89C5 // 197 +#define NO_CONSOLE_OPERATOR 0x89C6 // 198 +#define NO_CONSOLE_PRIVILEGES 0x89C6 // 198 +#define ERR_Q_IO_FAILURE 0x89D0 // 208 +#define ERR_NO_QUEUE 0x89D1 // 209 +#define ERR_NO_Q_SERVER 0x89D2 // 210 +#define ERR_NO_Q_RIGHTS 0x89D3 // 211 +#define ERR_Q_FULL 0x89D4 // 212 +#define ERR_NO_Q_JOB 0x89D5 // 213 +#define ERR_NO_Q_JOB_RIGHTS 0x89D6 // 214 +#define ERR_Q_IN_SERVICE 0x89D7 // 215 +#define PASSWORD_NOT_UNIQUE 0x89D7 // 215 +#define ERR_Q_NOT_ACTIVE 0x89D8 // 216 +#define PASSWORD_TOO_SHORT 0x89D8 // 216 +#define ERR_Q_STN_NOT_SERVER 0x89D9 // 217 +#define LOGIN_DENIED_NO_CONNECTION 0x89D9 // 217 +#define ERR_MAXIMUM_LOGINS_EXCEEDED 0x89D9 // 217 +#define ERR_Q_HALTED 0x89DA // 218 +#define UNAUTHORIZED_LOGIN_TIME 0x89DA // 218 +#define UNAUTHORIZED_LOGIN_STATION 0x89DB // 219 +#define ERR_Q_MAX_SERVERS 0x89DB // 219 +#define ACCOUNT_DISABLED 0x89DC // 220 +#define PASSWORD_HAS_EXPIRED_NO_GRACE 0x89DE // 222 +#define PASSWORD_HAS_EXPIRED 0x89DF // 223 +#define E_NO_MORE_USERS 0x89E7 // 231 +#define NOT_ITEM_PROPERTY 0x89E8 // 232 +#define WRITE_PROPERTY_TO_GROUP 0x89E8 // 232 +#define MEMBER_ALREADY_EXISTS 0x89E9 // 233 +#define NO_SUCH_MEMBER 0x89EA // 234 +#define NOT_GROUP_PROPERTY 0x89EB // 235 +#define NO_SUCH_SEGMENT 0x89EC // 236 +#define PROPERTY_ALREADY_EXISTS 0x89ED // 237 +#define OBJECT_ALREADY_EXISTS 0x89EE // 238 +#define INVALID_NAME 0x89EF // 239 +#define WILD_CARD_NOT_ALLOWED 0x89F0 // 240 +#define INVALID_BINDERY_SECURITY 0x89F1 // 241 +#define NO_OBJECT_READ_PRIVILEGE 0x89F2 // 242 +#define NO_OBJECT_RENAME_PRIVILEGE 0x89F3 // 243 +#define NO_OBJECT_DELETE_PRIVILEGE 0x89F4 // 244 +#define NO_OBJECT_CREATE_PRIVILEGE 0x89F5 // 245 +#define NO_PROPERTY_DELETE_PRIVILEGE 0x89F6 // 246 +#define NO_PROPERTY_CREATE_PRIVILEGE 0x89F7 // 247 +#define NO_PROPERTY_WRITE_PRIVILEGE 0x89F8 // 248 +#define NO_FREE_CONNECTION_SLOTS 0x89F9 // 249 +#define NO_PROPERTY_READ_PRIVILEGE 0x89F9 // 249 +#define NO_MORE_SERVER_SLOTS 0x89FA // 250 +#define TEMP_REMAP_ERROR 0x89FA // 250 +#define INVALID_PARAMETERS 0x89FB // 251 +#define NO_SUCH_PROPERTY 0x89FB // 251 +#define ERR_NCP_NOT_SUPPORTED 0x89FB // 251 +#define INTERNET_PACKET_REQT_CANCELED 0x89FC // 252 +#define UNKNOWN_FILE_SERVER 0x89FC // 252 +#define MESSAGE_QUEUE_FULL 0x89FC // 252 +#define NO_SUCH_OBJECT 0x89FC // 252 +#define LOCK_COLLISION 0x89FD // 253 +#define BAD_STATION_NUMBER 0x89FD // 253 +#define INVALID_PACKET_LENGTH 0x89FD // 253 +#define UNKNOWN_REQUEST 0x89FD // 253 +#define BINDERY_LOCKED 0x89FE // 254 +#define TRUSTEE_NOT_FOUND 0x89FE // 254 +#define DIRECTORY_LOCKED 0x89FE // 254 +#define INVALID_SEMAPHORE_NAME_LENGTH 0x89FE // 254 +#define PACKET_NOT_DELIVERABLE 0x89FE // 254 +#define SERVER_BINDERY_LOCKED 0x89FE // 254 +#define SOCKET_TABLE_FULL 0x89FE // 254 +#define SPOOL_DIRECTORY_ERROR 0x89FE // 254 +#define SUPERVISOR_HAS_DISABLED_LOGIN 0x89FE // 254 +#define TIMEOUT_FAILURE 0x89FE // 254 +#define BAD_PRINTER_ERROR 0x89FF // 255 +#define BAD_RECORD_OFFSET 0x89FF // 255 +#define CLOSE_FCB_ERROR 0x89FF // 255 +#define FILE_EXTENSION_ERROR 0x89FF // 255 +#define FILE_NAME_ERROR 0x89FF // 255 +#define HARDWARE_FAILURE 0x89FF // 255 +#define INVALID_DRIVE_NUMBER 0x89FF // 255 +#define DOS_INVALID_DRIVE 0x000F // 255 +#define INVALID_INITIAL_SEMAPHORE_VALUE 0x89FF // 255 +#define INVALID_SEMAPHORE_HANDLE 0x89FF // 255 +#define IO_BOUND_ERROR 0x89FF // 255 +#define NO_FILES_FOUND_ERROR 0x89FF // 255 +#define NO_RESPONSE_FROM_SERVER 0x89FF // 255 +#define NO_SUCH_OBJECT_OR_BAD_PASSWORD 0x89FF // 255 +#define PATH_NOT_LOCATABLE 0x89FF // 255 +#define QUEUE_FULL_ERROR 0x89FF // 255 +#define REQUEST_NOT_OUTSTANDING 0x89FF // 255 +#ifndef SOCKET_ALREADY_OPEN +#define SOCKET_ALREADY_OPEN 0x89FF // 255 +#endif +#define LOCK_ERROR 0x89FF // 255 +#ifndef FAILURE +#define FAILURE 0x89FF // 255 Generic Failure +#endif + +#if 0 +#define NOT_SAME_LOCAL_DRIVE 0x89F6 +#define TARGET_DRIVE_NOT_LOCAL 0x89F7 +#define ALREADY_ATTACHED_TO_SERVER 0x89F8 // 248 +#define NOT_ATTACHED_TO_SERVER 0x89F8 +#endif + +/* + * Network errors + * Decimal values at end of line are 32768 lower than actual + */ +#define NWE_ALREADY_ATTACHED 0x8800 // 0 - Attach attempted to server with valid, existing connection +#define NWE_CONN_INVALID 0x8801 // 1 - Request attempted with invalid or non-attached connection handle +#define NWE_DRIVE_IN_USE 0x8802 // 2 - OS/2 only (NOT USED) +#define NWE_DRIVE_CANNOT_MAP 0x8803 // 3 - Map drive attempted but unable to add new current directory structure +#define NWE_DRIVE_BAD_PATH 0x8804 // 4 - Map drive attempted with invalid path specification +#define NWE_NET_RECEIVE 0x8805 // 5 - Attempt to receive from the selected transport failed +#define NWE_NET_UNKNOWN 0x8806 // 6 - Network send attempted with an un-specific network error +#define NWE_SERVER_BAD_SLOT 0x8807 // 7 - Server request attempted with invalid server connection slot +#define NWE_SERVER_NO_SLOTS 0x8808 // 8 - Attach attempted to server with no connection slots available +#define NWE_NET_SEND 0x8809 // 9 - Attempt to send on the selected transport failed +#define NWE_SERVER_NO_ROUTE 0x880A // 10 - Attempted to find route to server where no route exists +#define NWE_BAD_LOCAL_TARGET 0x880B // 11 - OS/2 only +#define NWE_REQ_TOO_MANY_REQ_FRAGS 0x880C // 12 - Attempted request with too many request fragments specified +#define NWE_CONN_LIST_OVERFLOW 0x880D // 13 +#define NWE_BUFFER_OVERFLOW 0x880E // 14 - Attempt to receive more data than the reply buffer had room for +#define NWE_SERVER_NO_CONN 0x880F // 15 - Attempt to get connection for a server not connected +#define NWE_NO_ROUTER_FOUND 0x8810 // 16 - OS/2 only +#define NWE_FUNCTION_INVALID 0x8811 // 17 - Attempted function call to non- existent or illegal function +#define NWE_SCAN_COMPLETE 0x8812 +#define NWE_UNSUPPORTED_NAME_FORMAT_TYP 0x8813 +#define NWE_HANDLE_ALREADY_LICENSED 0x8814 +#define NWE_HANDLE_ALREADY_UNLICENSED 0x8815 +#define NWE_INVALID_NCP_PACKET_LENGTH 0x8816 +#define NWE_SETTING_UP_TIMEOUT 0x8817 +#define NWE_SETTING_SIGNALS 0x8818 +#define NWE_SERVER_CONNECTION_LOST 0x8819 +#define NWE_OUT_OF_HEAP_SPACE 0x881A +#define NWE_INVALID_SERVICE_REQUEST 0x881B +#define NWE_INVALID_TASK_NUMBER 0x881C +#define NWE_INVALID_MESSAGE_LENGTH 0x881D +#define NWE_EA_SCAN_DONE 0x881E +#define NWE_BAD_CONNECTION_NUMBER 0x881F +#define NWE_MULT_TREES_NOT_SUPPORTED 0x8820 // 32 - Attempt to open a connection to a DS tree other than the default tree +#define NWE_CONN_NOT_SAME 0x8830 // 48 - Internal server request attempted across different server connections +#define NWE_CONN_PRIMARY_NOT_SET 0x8831 // 49 - Attempt to retrieve default connection with no primary connection set +#define NWE_PRN_CAPTURE_NOT_IN_PROGRESS 0x8832 // 50 - Capture information requested on port with no capture in progress +#define NWE_BUFFER_INVALID_LEN 0x8833 // 51 - Used to indicate length which caller requested on a GetDNC or SetDNC was too large +#define NWE_USER_NO_NAME 0x8834 // 52 +#define NWE_PRN_NO_LOCAL_SPOOLER 0x8835 // 53 - Capture requested without having the local print spooler installed +#define NWE_PARAM_INVALID 0x8836 // 54 - Attempted function with an invalid function parameter specified +#define NWE_CFG_OPEN_FAILED 0x8837 // 55 - OS/2 only +#define NWE_CFG_NO_FILE 0x8838 // 56 - OS/2 only +#define NWE_CFG_READ_FAILED 0x8839 // 57 - OS/2 only +#define NWE_CFG_LINE_TOO_LONG 0x883A // 58 - OS/2 only +#define NWE_CFG_LINES_IGNORED 0x883B // 59 - OS/2 only +#define NWE_RESOURCE_NOT_OWNED 0x883C // 60 - Attempted request made with a parameter using foriegn resource +#define NWE_DAEMON_INSTALLED 0x883D // 61 - OS/2 only +#define NWE_PRN_SPOOLER_INSTALLED 0x883E // 62 - Attempted load of print spooler with print spooler already installed +#define NWE_CONN_TABLE_FULL 0x883F // 63 - Attempted to allocate a connection handle with no more local connection table entries +#define NWE_CFG_SECTION_NOT_FOUND 0x8840 // 64 - OS/2 only +#define NWE_TRAN_INVALID_TYPE 0x8841 // 65 - Attempted function on a connection with an invalid transport selected +#define NWE_TDS_TAG_IN_USE 0x8842 // 66 - OS/2 only +#define NWE_TDS_OUT_OF_MEMORY 0x8843 // 67 - OS/2 only +#define NWE_TDS_INVALID_TAG 0x8844 // 68 - Attempted TDS function with invalid tag +#define NWE_TDS_WRITE_TRUNCATED 0x8845 // 69 - Attempted TDS write with buffer that exceeded buffer +#define NWE_DS_NO_CONN 0x8846 // 70 +#define NWE_SERVICE_BUSY 0x8846 // 70 - Attempted request made to partially asynchronous function in busy state +#define NWE_SERVER_NOT_FOUND 0x8847 // 71 - Attempted connect failed to find any servers responding +#define NWE_VLM_INVALID 0x8848 // 72 - Attempted function call to non-existant or not-loaded overlay +#define NWE_DRIVE_ALREADY_MAPPED 0x8849 // 73 - Attempted map to network drive that was already mapped +#define NWE_DRIVE_LOCAL_IN_USE 0x884A // 74 - Attempted map to local drive that was in use +#define NWE_DRIVE_NONE_AVAILABLE 0x884B // 75 - Attempted map to next available drive when none were available +#define NWE_DEVICE_NOT_REDIRECTED 0x884C // 76 - The device is not redirected +#define NWE_FILE_MAX_REACHED 0x884D // 77 - Maximum number of files was reached +#define NWE_UNLOAD_FAILED 0x884E // 78 - Attempted unload failed +#define NWE_CONN_IN_USE 0x884F // 79 - Attempted re-use of already in use connection entry +#define NWE_REQ_TOO_MANY_REP_FRAGS 0x8850 // 80 - Attempted request with too many reply fragments specified +#define NWE_NAME_TABLE_FULL 0x8851 // 81 - Attempted to add a name into the name table after it was full +#define NWE_SOCKET_NOT_OPEN 0x8852 // 82 - Listen was posted on unopened socket +#define NWE_MEMORY_MGR_ERROR 0x8853 // 83 - Attempted enhanced memory operation failed +#define NWE_SFT3_ERROR 0x8854 // 84 - An SFT3 switch occured mid-transfer +#define NWE_DS_PREFERRED_NOT_FOUND 0x8855 // 85 - the preferred directory server was not established but another directory server was returned +#define NWE_DEVICE_NOT_RECOGNIZED 0x8856 // 86 - used to determine if the device is not used by VISE so pass it on to the next redirector, if any. +#define NWE_NET_INVALID_TYPE 0x8857 // 87 - the network type (Bind/NDS) does not match the server version +#define NWE_FILE_OPEN_FAILED 0x8858 // 88 - generic open failure error, invalid path, access denied, etc.. +#define NWE_DS_PREFERRED_NOT_SPECIFIED 0x8859 // 89 - no preferred name specified +#define NWE_SOCKET_OPEN_FAILED 0x885A // 90 - error opening a socket +#define NWE_SIGNATURE_LEVEL_CONFLICT 0x8861 +#define NWE_NO_LOCK_FOUND 0x8862 // OS/2 - process lock on conn handle failed, process ID not recognized +#define NWE_LOCK_TABLE_FULL 0x8863 // OS/2 - process lock on conn handle failed, process lock table full +#define NWE_INVALID_MATCH_DATA 0x8864 +#define NWE_MATCH_FAILED 0x8865 +#define NWE_NO_MORE_ENTRIES 0x8866 +#define NWE_INSUFFICIENT_RESOURCES 0x8867 +#define NWE_STRING_TRANSLATION 0x8868 +#define NWE_ACCESS_VIOLATION 0x8869 +#define NWE_NOT_AUTHENTICATED 0x886A +#define NWE_INVALID_LEVEL 0x886B +#define NWE_RESOURCE_LOCK 0x886C +#define NWE_INVALID_NAME_FORMAT 0x886D +#define NWE_OBJECT_EXISTS 0x886E +#define NWE_OBJECT_NOT_FOUND 0x886F +#define NWE_UNSUPPORTED_TRAN_TYPE 0x8870 +#define NWE_INVALID_STRING_TYPE 0x8871 +#define NWE_INVALID_OWNER 0x8872 +#define NWE_UNSUPPORTED_AUTHENTICATOR 0x8873 +#define NWE_IO_PENDING 0x8874 +#define NWE_INVALID_DRIVE_NUMBER 0x8875 +#define NWE_REPLY_TRUNCATED 0x88e6 // 230 NLM +#define NWE_REQUESTER_FAILURE 0x88FF + +/* + * Server Errors + */ +#define NWE_INSUFFICIENT_SPACE 0x8901 // 001 +#define NWE_INVALID_CONNECTION 0x890a // 010 - nlm invalid connection +#define NWE_TIMEOUT 0x8910 // 016 - nlm connection timeout +#define NWE_NO_MORE_ENTRY 0x8914 // 020 +#define NWE_BUFFER_TOO_SMALL 0x8977 // 119 +#define NWE_VOL_FLAG_NOT_SET 0x8978 // 120 the service requested, not avail. on the selected vol. +#define NWE_NO_ITEMS_FOUND 0x8979 // 121 +#define NWE_CONN_ALREADY_TEMP 0x897a // 122 +#define NWE_CONN_ALREADY_LOGGED_IN 0x897b // 123 +#define NWE_CONN_NOT_AUTHENTICATED 0x897c // 124 +#define NWE_CONN_NOT_LOGGED_IN 0x897d // 125 +#define NWE_NCP_BOUNDARY_CHECK_FAILED 0x897e // 126 +#define NWE_LOCK_WAITING 0x897f // 127 +#define NWE_LOCK_FAIL 0x8980 // 128 +#define NWE_FILE_IN_USE 0x8980 // 128 +#define NWE_FILE_NO_HANDLES 0x8981 // 129 +#define NWE_FILE_NO_OPEN_PRIV 0x8982 // 130 +#define NWE_DISK_IO_ERROR 0x8983 // 131 +#define NWE_AUDITING_HARD_IO_ERROR 0x8983 // 131 +#define NWE_FILE_NO_CREATE_PRIV 0x8984 // 132 +#define NWE_AUDITING_NOT_SUPV 0x8984 // 132 +#define NWE_FILE_NO_CREATE_DEL_PRIV 0x8985 // 133 +#define NWE_FILE_EXISTS_READ_ONLY 0x8986 // 134 +#define NWE_FILE_WILD_CARDS_IN_NAME 0x8987 // 135 +#define NWE_FILE_INVALID_HANDLE 0x8988 // 136 +#define NWE_FILE_NO_SRCH_PRIV 0x8989 // 137 +#define NWE_FILE_NO_DEL_PRIV 0x898A // 138 +#define NWE_FILE_NO_RENAME_PRIV 0x898B // 139 +#define NWE_FILE_NO_MOD_PRIV 0x898C // 140 +#define NWE_FILE_SOME_IN_USE 0x898D // 141 +#define NWE_FILE_NONE_IN_USE 0x898E // 142 +#define NWE_FILE_SOME_READ_ONLY 0x898F // 143 +#define NWE_FILE_NONE_READ_ONLY 0x8990 // 144 +#define NWE_FILE_SOME_RENAMED_EXIST 0x8991 // 145 +#define NWE_FILE_NONE_RENAMED_EXIST 0x8992 // 146 +#define NWE_FILE_NO_READ_PRIV 0x8993 // 147 +#define NWE_FILE_NO_WRITE_PRIV 0x8994 // 148 +#define NWE_FILE_READ_ONLY 0x8994 // 148 +#define NWE_FILE_DETACHED 0x8995 // 149 +#define NWE_SERVER_OUT_OF_MEMORY 0x8996 // 150 +#define NWE_DIR_TARGET_INVALID 0x8996 // 150 +#define NWE_DISK_NO_SPOOL_SPACE 0x8997 // 151 +#define NWE_AUDITING_NOT_ENABLED 0x8997 // 151 +#define NWE_VOL_INVALID 0x8998 // 152 +#define NWE_DIR_FULL 0x8999 // 153 +#define NWE_VOL_RENAMING_ACROSS 0x899A // 154 +#define NWE_DIRHANDLE_INVALID 0x899B // 155 +#define NWE_PATH_INVALID 0x899C // 156 +#define NWE_TRUSTEES_NO_MORE 0x899C // 156 +#define NWE_DIRHANDLE_NO_MORE 0x899D // 157 +#define NWE_FILE_NAME_INVALID 0x899E // 158 +#define NWE_DIR_ACTIVE 0x899F // 159 +#define NWE_DIR_NOT_EMPTY 0x89A0 // 160 +#define NWE_DIR_IO_ERROR 0x89A1 // 161 +#define NWE_FILE_IO_LOCKED 0x89A2 // 162 +#define NWE_TTS_RANSACTION_RESTARTED 0x89A3 // 163 +#define NWE_TTS_TRANSACTION_RESTARTED 0x89A3 // 163 +#define NWE_DIR_RENAME_INVALID 0x89A4 // 164 +#define NWE_FILE_OPENCREAT_MODE_INVALID 0x89A5 // 165 +#define NWE_ALREADY_IN_USE 0x89A6 // 166 +#define NWE_AUDITING_ACTIVE 0x89A6 // 166 +#define NWE_RESOURCE_TAG_INVALID 0x89A7 // 167 +#define NWE_ACCESS_DENIED 0x89A8 // 168 +#define NWE_AUDITING_NO_RIGHTS 0x89A8 // 168 +#define NWE_LINK_IN_PATH 0x89A9 // 169 +#define NWE_INVALID_DATA_TYPE_FLAG 0x89AA // 170 (legacy vol with UTF8) +#define NWE_DATA_STREAM_INVALID 0x89BE // 190 +#define NWE_NAME_SPACE_INVALID 0x89BF // 191 +#define NWE_ACCTING_NO_PRIV 0x89C0 // 192 +#define NWE_ACCTING_NO_BALANCE 0x89C1 // 193 +#define NWE_ACCTING_NO_CREDIT 0x89C2 // 194 +#define NWE_AUDITING_RECORD_SIZE 0x89C2 // 194 +#define NWE_ACCTING_TOO_MANY_HOLDS 0x89C3 // 195 +#define NWE_ACCTING_DISABLED 0x89C4 // 196 +#define NWE_LOGIN_LOCKOUT 0x89C5 // 197 +#define NWE_CONSOLE_NO_PRIV 0x89C6 // 198 +#define NWE_Q_IO_FAILURE 0x89D0 // 208 +#define NWE_Q_NONE 0x89D1 // 209 +#define NWE_Q_NO_SERVER 0x89D2 // 210 +#define NWE_Q_NO_RIGHTS 0x89D3 // 211 +#define NWE_Q_FULL 0x89D4 // 212 +#define NWE_Q_NO_JOB 0x89D5 // 213 +#define NWE_Q_NO_JOB_RIGHTS 0x89D6 // 214 +#define NWE_PASSWORD_UNENCRYPTED 0x89D6 // 214 +#define NWE_Q_IN_SERVICE 0x89D7 // 215 +#define NWE_PASSWORD_NOT_UNIQUE 0x89D7 // 215 +#define NWE_Q_NOT_ACTIVE 0x89D8 // 216 +#define NWE_PASSWORD_TOO_SHORT 0x89D8 // 216 +#define NWE_Q_STN_NOT_SERVER 0x89D9 // 217 +#define NWE_LOGIN_NO_CONN 0x89D9 // 217 +#define NWE_LOGIN_MAX_EXCEEDED 0x89D9 // 217 +#define NWE_Q_HALTED 0x89DA // 218 +#define NWE_LOGIN_UNAUTHORIZED_TIME 0x89DA // 218 +#define NWE_LOGIN_UNAUTHORIZED_STATION 0x89DB // 219 +#define NWE_Q_MAX_SERVERS 0x89DB // 219 +#define NWE_ACCT_DISABLED 0x89DC // 220 +#define NWE_PASSWORD_INVALID 0x89DE // 222 +#define NWE_PASSWORD_EXPIRED 0x89DF // 223 +#define NWE_LOGIN_NO_CONN_AVAIL 0x89E0 // 224 +#define NWE_E_NO_MORE_USERS 0x89E7 // 231 +#define NWE_BIND_NOT_ITEM_PROP 0x89E8 // 232 +#define NWE_BIND_WRITE_TO_GROUP_PROP 0x89E8 // 232 +#define NWE_BIND_MEMBER_ALREADY_EXISTS 0x89E9 // 233 +#define NWE_BIND_NO_SUCH_MEMBER 0x89EA // 234 +#define NWE_BIND_NOT_GROUP_PROP 0x89EB // 235 +#define NWE_BIND_NO_SUCH_SEGMENT 0x89EC // 236 +#define NWE_BIND_PROP_ALREADY_EXISTS 0x89ED // 237 +#define NWE_BIND_OBJ_ALREADY_EXISTS 0x89EE // 238 +#define NWE_BIND_NAME_INVALID 0x89EF // 239 +#define NWE_BIND_WILDCARD_INVALID 0x89F0 // 240 +#define NWE_BIND_SECURITY_INVALID 0x89F1 // 241 +#define NWE_BIND_OBJ_NO_READ_PRIV 0x89F2 // 242 +#define NWE_BIND_OBJ_NO_RENAME_PRIV 0x89F3 // 243 +#define NWE_BIND_OBJ_NO_DELETE_PRIV 0x89F4 // 244 +#define NWE_BIND_OBJ_NO_CREATE_PRIV 0x89F5 // 245 +#define NWE_BIND_PROP_NO_DELETE_PRIV 0x89F6 // 246 +#define NWE_BIND_PROP_NO_CREATE_PRIV 0x89F7 // 247 +#define NWE_BIND_PROP_NO_WRITE_PRIV 0x89F8 // 248 +#define NWE_BIND_PROP_NO_READ_PRIV 0x89F9 // 249 +#define NWE_NO_FREE_CONN_SLOTS 0x89F9 // 249 +#define NWE_NO_MORE_SERVER_SLOTS 0x89FA // 250 +#define NWE_TEMP_REMAP_ERROR 0x89FA // 250 +#define NWE_PARAMETERS_INVALID 0x89FB // 251 +#define NWE_BIND_NO_SUCH_PROP 0x89FB // 251 +#define NWE_NCP_NOT_SUPPORTED 0x89FB // 251 +#define NWE_INET_PACKET_REQ_CANCELED 0x89FC // 252 +#define NWE_SERVER_UNKNOWN 0x89FC // 252 +#define NWE_MSG_Q_FULL 0x89FC // 252 +#define NWE_BIND_NO_SUCH_OBJ 0x89FC // 252 +#define NWE_LOCK_COLLISION 0x89FD // 253 +#define NWE_CONN_NUM_INVALID 0x89FD // 253 +#define NWE_PACKET_LEN_INVALID 0x89FD // 253 +#define NWE_UNKNOWN_REQ 0x89FD // 253 +#define NWE_BIND_LOCKED 0x89FE // 254 +#define NWE_TRUSTEE_NOT_FOUND 0x89FE // 254 +#define NWE_DIR_LOCKED 0x89FE // 254 +#define NWE_SEM_INVALID_NAME_LEN 0x89FE // 254 +#define NWE_PACKET_NOT_DELIVERABLE 0x89FE // 254 +#define NWE_SOCKET_TABLE_FULL 0x89FE // 254 +#define NWE_SPOOL_DIR_ERROR 0x89FE // 254 +#define NWE_LOGIN_DISABLED_BY_SUPER 0x89FE // 254 +#define NWE_TIMEOUT_FAILURE 0x89FE // 254 +#define NWE_FILE_EXT 0x89FF // 255 +#define NWE_FILE_NAME 0x89FF // 255 +#define NWE_HARD_FAILURE 0x89FF // 255 +#define NWE_FCB_CLOSE 0x89FF // 255 +#define NWE_IO_BOUND 0x89FF // 255 +#define NWE_BAD_SPOOL_PRINTER 0x89FF // 255 +#define NWE_BAD_RECORD_OFFSET 0x89FF // 255 +#define NWE_DRIVE_INVALID_NUM 0x89FF // 255 +#define NWE_SEM_INVALID_INIT_VAL 0x89FF // 255 +#define NWE_SEM_INVALID_HANDLE 0x89FF // 255 +#define NWE_NO_FILES_FOUND_ERROR 0x89FF // 255 +#define NWE_NO_RESPONSE_FROM_SERVER 0x89FF // 255 +#define NWE_NO_OBJ_OR_BAD_PASSWORD 0x89FF // 255 +#define NWE_PATH_NOT_LOCATABLE 0x89FF // 255 +#define NWE_Q_FULL_ERROR 0x89FF // 255 +#define NWE_REQ_NOT_OUTSTANDING 0x89FF // 255 +#define NWE_SOCKET_ALREADY_OPEN 0x89FF // 255 +#define NWE_LOCK_ERROR 0x89FF // 255 +#define NWE_FAILURE 0x89FF // 255 Generic Failure + +#endif /* __NOVFS_ERROR_H */ --- /dev/null +++ b/fs/novfs/proc.c @@ -0,0 +1,149 @@ +/* + * Novell NCP Redirector for Linux + * Author: James Turner + * + * This module contains functions that create the interface to the proc + * filesystem. + * + * Copyright (C) 2005 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#include "vfs.h" + +struct proc_dir_entry *novfs_procfs_dir; +struct proc_dir_entry *Novfs_Control; +struct proc_dir_entry *Novfs_Library; +struct proc_dir_entry *Novfs_Version; + +static struct file_operations novfs_daemon_proc_fops; +static struct file_operations novfs_lib_proc_fops; + +/*===[ Code ]=============================================================*/ + +static int Novfs_Get_Version(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + char *buf, tbuf[48]; + int len = 0, i; + + if (!off) { + buf = page + off; + *start = buf; + len = sprintf(buf, "Novfs Version=%s\n", NOVFS_VERSION_STRING); + i = novfs_daemon_getversion(tbuf, sizeof(tbuf)); + if ((i > 0) && i < (count - len)) { + len += sprintf(buf + len, "Novfsd Version=%s\n", tbuf); + } + + if (novfs_current_mnt) { + i = strlen(novfs_current_mnt); + if ((i > 0) && i < (count - len)) { + len += + sprintf(buf + len, "Novfs mount=%s\n", + novfs_current_mnt); + } + } + DbgPrint("%s", buf); + } + *eof = 1; + return (len); +} + +int novfs_proc_init(void) +{ + int retCode = 0; + + novfs_procfs_dir = proc_mkdir(MODULE_NAME, NULL); + if (novfs_procfs_dir) { + + Novfs_Control = create_proc_entry("Control", 0600, novfs_procfs_dir); + + if (Novfs_Control) { + Novfs_Control->size = 0; + memcpy(&novfs_daemon_proc_fops, + Novfs_Control->proc_fops, + sizeof(struct file_operations)); + + /* + * Setup our functions + */ + novfs_daemon_proc_fops.owner = THIS_MODULE; + novfs_daemon_proc_fops.open = novfs_daemon_open_control; + novfs_daemon_proc_fops.release = novfs_daemon_close_control; + novfs_daemon_proc_fops.read = novfs_daemon_cmd_send; + novfs_daemon_proc_fops.write = novfs_daemon_recv_reply; + novfs_daemon_proc_fops.ioctl = novfs_daemon_ioctl; + + Novfs_Control->proc_fops = &novfs_daemon_proc_fops; + } else { + remove_proc_entry(MODULE_NAME, NULL); + return (-ENOENT); + } + + Novfs_Library = create_proc_entry("Library", 0666, novfs_procfs_dir); + if (Novfs_Library) { + Novfs_Library->size = 0; + + /* + * Setup our file functions + */ + memcpy(&novfs_lib_proc_fops, Novfs_Library->proc_fops, + sizeof(struct file_operations)); + novfs_lib_proc_fops.owner = THIS_MODULE; + novfs_lib_proc_fops.open = novfs_daemon_lib_open; + novfs_lib_proc_fops.release = novfs_daemon_lib_close; + novfs_lib_proc_fops.read = novfs_daemon_lib_read; + novfs_lib_proc_fops.write = novfs_daemon_lib_write; + novfs_lib_proc_fops.llseek = novfs_daemon_lib_llseek; + novfs_lib_proc_fops.ioctl = novfs_daemon_lib_ioctl; + Novfs_Library->proc_fops = &novfs_lib_proc_fops; + } else { + remove_proc_entry("Control", novfs_procfs_dir); + remove_proc_entry(MODULE_NAME, NULL); + return (-ENOENT); + } + + Novfs_Version = + create_proc_read_entry("Version", 0444, novfs_procfs_dir, + Novfs_Get_Version, NULL); + if (Novfs_Version) { + Novfs_Version->size = 0; + } else { + remove_proc_entry("Library", novfs_procfs_dir); + remove_proc_entry("Control", novfs_procfs_dir); + remove_proc_entry(MODULE_NAME, NULL); + retCode = -ENOENT; + } + } else { + retCode = -ENOENT; + } + return (retCode); +} + +void novfs_proc_exit(void) +{ + + DbgPrint("remove_proc_entry(Version, NULL)\n"); + remove_proc_entry("Version", novfs_procfs_dir); + + DbgPrint("remove_proc_entry(Control, NULL)\n"); + remove_proc_entry("Control", novfs_procfs_dir); + + DbgPrint("remove_proc_entry(Library, NULL)\n"); + remove_proc_entry("Library", novfs_procfs_dir); + + DbgPrint("remove_proc_entry(%s, NULL)\n", + MODULE_NAME); + remove_proc_entry(MODULE_NAME, NULL); + + DbgPrint("done\n"); +} --- /dev/null +++ b/fs/novfs/profile.c @@ -0,0 +1,704 @@ +/* + * Novell NCP Redirector for Linux + * Author: James Turner + * + * This file contains a debugging code for the novfs VFS. + * + * Copyright (C) 2005 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "vfs.h" + +/*===[ Manifest constants ]===============================================*/ +#define DBGBUFFERSIZE (1024*1024*32) + +/*===[ Type definitions ]=================================================*/ +struct local_rtc_time { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +char *DbgPrintBuffer = NULL; +char DbgPrintOn = 0; +char DbgSyslogOn = 0; +char DbgProfileOn = 0; + +static unsigned long DbgPrintBufferOffset = 0; +static unsigned long DbgPrintBufferReadOffset = 0; +static unsigned long DbgPrintBufferSize = DBGBUFFERSIZE; + +static struct file_operations Dbg_proc_file_operations; +static struct file_operations dentry_proc_file_ops; +static struct file_operations inode_proc_file_ops; + +static struct proc_dir_entry *dbg_dir = NULL; +static struct proc_dir_entry *dbg_file = NULL; +static struct proc_dir_entry *dentry_file = NULL; +static struct proc_dir_entry *inode_file = NULL; + +static DECLARE_MUTEX(LocalPrint_lock); + +static ssize_t User_proc_write_DbgBuffer(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos) +{ + ssize_t retval = nbytes; + u_char *lbuf, *p; + int i; + u_long cpylen; + + lbuf = kmalloc(nbytes + 1, GFP_KERNEL); + if (lbuf) { + cpylen = copy_from_user(lbuf, buf, nbytes); + + lbuf[nbytes] = 0; + DbgPrint("%s", lbuf); + + for (i = 0; lbuf[i] && lbuf[i] != '\n'; i++) ; + + if ('\n' == lbuf[i]) { + lbuf[i] = '\0'; + } + + if (!strcmp("on", lbuf)) { + DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; + DbgPrintOn = 1; + } else if (!strcmp("off", lbuf)) { + DbgPrintOn = 0; + } else if (!strcmp("reset", lbuf)) { + DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; + } else if (NULL != (p = strchr(lbuf, ' '))) { + *p++ = '\0'; + if (!strcmp("syslog", lbuf)) { + + if (!strcmp("on", p)) { + DbgSyslogOn = 1; + } else if (!strcmp("off", p)) { + DbgSyslogOn = 0; + } + } else if (!strcmp("novfsd", lbuf)) { + novfs_daemon_debug_cmd_send(p); + } else if (!strcmp("file_update_timeout", lbuf)) { + novfs_update_timeout = + simple_strtoul(p, NULL, 0); + } else if (!strcmp("cache", lbuf)) { + if (!strcmp("on", p)) { + novfs_page_cache = 1; + } else if (!strcmp("off", p)) { + novfs_page_cache = 0; + } + } else if (!strcmp("profile", lbuf)) { + if (!strcmp("on", p)) { + DbgProfileOn = 1; + } else if (!strcmp("off", p)) { + DbgProfileOn = 0; + } + } + } + kfree(lbuf); + } + + return (retval); +} + +static ssize_t User_proc_read_DbgBuffer(struct file *file, char *buf, size_t nbytes, loff_t * ppos) +{ + ssize_t retval = 0; + size_t count; + + if (0 != (count = DbgPrintBufferOffset - DbgPrintBufferReadOffset)) { + + if (count > nbytes) { + count = nbytes; + } + + count -= + copy_to_user(buf, &DbgPrintBuffer[DbgPrintBufferReadOffset], + count); + + if (count == 0) { + if (retval == 0) + retval = -EFAULT; + } else { + DbgPrintBufferReadOffset += count; + if (DbgPrintBufferReadOffset >= DbgPrintBufferOffset) { + DbgPrintBufferOffset = + DbgPrintBufferReadOffset = 0; + } + retval = count; + } + } + + return retval; +} + +static int proc_read_DbgBuffer(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len; + + printk(KERN_ALERT "proc_read_DbgBuffer: off=%ld count=%d DbgPrintBufferOffset=%lu DbgPrintBufferReadOffset=%lu\n", off, count, DbgPrintBufferOffset, DbgPrintBufferReadOffset); + + len = DbgPrintBufferOffset - DbgPrintBufferReadOffset; + + if ((int)(DbgPrintBufferOffset - DbgPrintBufferReadOffset) > count) + len = count; + + if (len) { + memcpy(page, &DbgPrintBuffer[DbgPrintBufferReadOffset], len); + DbgPrintBufferReadOffset += len; + } + + if (DbgPrintBufferReadOffset >= DbgPrintBufferOffset) + DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; + + printk(KERN_ALERT "proc_read_DbgBuffer: return %d\n", len); + + return len; +} + +#define DBG_BUFFER_SIZE (2*1024) + +static int LocalPrint(char *Fmt, ...) +{ + int len = 0; + va_list args; + + if (DbgPrintBuffer) { + va_start(args, Fmt); + len += vsnprintf(DbgPrintBuffer + DbgPrintBufferOffset, + DbgPrintBufferSize - DbgPrintBufferOffset, + Fmt, args); + DbgPrintBufferOffset += len; + } + + return (len); +} + +int ___DbgPrint(const char *site, const char *Fmt, ...) +{ + char *buf; + int len = 0; + unsigned long offset; + va_list args; + + if ((DbgPrintBuffer && DbgPrintOn) || DbgSyslogOn) { + buf = kmalloc(DBG_BUFFER_SIZE, GFP_KERNEL); + + if (buf) { + va_start(args, Fmt); + len = snprintf(buf, DBG_BUFFER_SIZE, "[%d] %s ", current->pid, site); + len += vsnprintf(buf + len, DBG_BUFFER_SIZE - len, Fmt, + args); + if (-1 == len) { + len = DBG_BUFFER_SIZE - 1; + buf[len] = '\0'; + } + /* + len = sprintf(&DbgPrintBuffer[offset], "[%llu] ", ts); + len += vsprintf(&DbgPrintBuffer[offset+len], Fmt, args); + */ + + if (len) { + if (DbgSyslogOn) { + printk("<6>%s", buf); + } + + if (DbgPrintBuffer && DbgPrintOn) { + if ((DbgPrintBufferOffset + len) > + DbgPrintBufferSize) { + offset = DbgPrintBufferOffset; + DbgPrintBufferOffset = 0; + memset(&DbgPrintBuffer[offset], + 0, + DbgPrintBufferSize - + offset); + } + + mb(); + + if ((DbgPrintBufferOffset + len) < + DbgPrintBufferSize) { + DbgPrintBufferOffset += len; + offset = + DbgPrintBufferOffset - len; + memcpy(&DbgPrintBuffer[offset], + buf, len + 1); + } + } + } + kfree(buf); + } + } + + return (len); +} + +static void doline(unsigned char *b, unsigned char *e, unsigned char *l) +{ + unsigned char c; + + *b++ = ' '; + + while (l < e) { + c = *l++; + if ((c < ' ') || (c > '~')) { + c = '.'; + } + *b++ = c; + *b = '\0'; + } +} + +void novfs_dump(int size, void *dumpptr) +{ + unsigned char *ptr = (unsigned char *)dumpptr; + unsigned char *line = NULL, buf[100], *bptr = buf; + int i; + + if (DbgPrintBuffer || DbgSyslogOn) { + if (size) { + for (i = 0; i < size; i++) { + if (0 == (i % 16)) { + if (line) { + doline(bptr, ptr, line); + __DbgPrint("%s\n", buf); + bptr = buf; + } + bptr += sprintf(bptr, "0x%p: ", ptr); + line = ptr; + } + bptr += sprintf(bptr, "%02x ", *ptr++); + } + doline(bptr, ptr, line); + __DbgPrint("%s\n", buf); + } + } +} + +#define FEBRUARY 2 +#define STARTOFTIME 1970 +#define SECDAY 86400L +#define SECYR (SECDAY * 365) +#define leapyear(year) ((year) % 4 == 0) +#define days_in_year(a) (leapyear(a) ? 366 : 365) +#define days_in_month(a) (month_days[(a) - 1]) + +static int month_days[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) + */ +static void NovfsGregorianDay(struct local_rtc_time *tm) +{ + int leapsToDate; + int lastYear; + int day; + int MonthOffset[] = + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + + lastYear = tm->tm_year - 1; + + /* + * Number of leap corrections to apply up to end of last year + */ + leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400; + + /* + * This year is a leap year if it is divisible by 4 except when it is + * divisible by 100 unless it is divisible by 400 + * + * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be + */ + if ((tm->tm_year % 4 == 0) && + ((tm->tm_year % 100 != 0) || (tm->tm_year % 400 == 0)) && + (tm->tm_mon > 2)) { + /* + * We are past Feb. 29 in a leap year + */ + day = 1; + } else { + day = 0; + } + + day += lastYear * 365 + leapsToDate + MonthOffset[tm->tm_mon - 1] + + tm->tm_mday; + + tm->tm_wday = day % 7; +} + +static void private_to_tm(int tim, struct local_rtc_time *tm) +{ + register int i; + register long hms, day; + + day = tim / SECDAY; + hms = tim % SECDAY; + + /* Hours, minutes, seconds are easy */ + tm->tm_hour = hms / 3600; + tm->tm_min = (hms % 3600) / 60; + tm->tm_sec = (hms % 3600) % 60; + + /* Number of years in days */ + for (i = STARTOFTIME; day >= days_in_year(i); i++) + day -= days_in_year(i); + tm->tm_year = i; + + /* Number of months in days left */ + if (leapyear(tm->tm_year)) + days_in_month(FEBRUARY) = 29; + for (i = 1; day >= days_in_month(i); i++) + day -= days_in_month(i); + days_in_month(FEBRUARY) = 28; + tm->tm_mon = i; + + /* Days are what is left over (+1) from all that. */ + tm->tm_mday = day + 1; + + /* + * Determine the day of week + */ + NovfsGregorianDay(tm); +} + +char *ctime_r(time_t * clock, char *buf) +{ + struct local_rtc_time tm; + static char *DAYOFWEEK[] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; + static char *MONTHOFYEAR[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", +"Oct", "Nov", "Dec" }; + + private_to_tm(*clock, &tm); + + sprintf(buf, "%s %s %d %d:%02d:%02d %d", DAYOFWEEK[tm.tm_wday], + MONTHOFYEAR[tm.tm_mon - 1], tm.tm_mday, tm.tm_hour, tm.tm_min, + tm.tm_sec, tm.tm_year); + return (buf); +} + +static void dump(struct dentry *parent, void *pf) +{ + void (*pfunc) (char *Fmt, ...) = pf; + struct l { + struct l *next; + struct dentry *dentry; + } *l, *n, *start; + struct list_head *p; + struct dentry *d; + char *buf, *path, *sd; + char inode_number[16]; + + buf = (char *)kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + + if (NULL == buf) { + return; + } + + if (parent) { + pfunc("starting 0x%p %.*s\n", parent, parent->d_name.len, + parent->d_name.name); + if (parent->d_subdirs.next == &parent->d_subdirs) { + pfunc("No children...\n"); + } else { + start = kmalloc(sizeof(*start), GFP_KERNEL); + if (start) { + start->next = NULL; + start->dentry = parent; + l = start; + while (l) { + p = l->dentry->d_subdirs.next; + while (p != &l->dentry->d_subdirs) { + d = list_entry(p, struct dentry, + d_u.d_child); + p = p->next; + + if (d->d_subdirs.next != + &d->d_subdirs) { + n = kmalloc(sizeof + (*n), + GFP_KERNEL); + if (n) { + n->next = + l->next; + l->next = n; + n->dentry = d; + } + } else { + path = novfs_scope_dget_path(d, buf, PATH_LENGTH_BUFFER, 1); + if (path) { + pfunc + ("1-0x%p %s\n" + " d_name: %.*s\n" + " d_parent: 0x%p\n" + " d_count: %d\n" + " d_flags: 0x%x\n" + " d_subdirs: 0x%p\n" + " d_inode: 0x%p\n", + d, path, + d->d_name. + len, + d->d_name. + name, + d-> + d_parent, + atomic_read + (&d-> + d_count), + d->d_flags, + d-> + d_subdirs. + next, + d-> + d_inode); + } + } + } + l = l->next; + } + l = start; + while (l) { + d = l->dentry; + path = + novfs_scope_dget_path(d, buf, + PATH_LENGTH_BUFFER, + 1); + if (path) { + sd = " (None)"; + if (&d->d_subdirs != + d->d_subdirs.next) { + sd = ""; + } + inode_number[0] = '\0'; + if (d->d_inode) { + sprintf(inode_number, + " (%lu)", + d->d_inode-> + i_ino); + } + pfunc("0x%p %s\n" + " d_parent: 0x%p\n" + " d_count: %d\n" + " d_flags: 0x%x\n" + " d_subdirs: 0x%p%s\n" + " d_inode: 0x%p%s\n", + d, path, d->d_parent, + atomic_read(&d->d_count), + d->d_flags, + d->d_subdirs.next, sd, + d->d_inode, inode_number); + } + + n = l; + l = l->next; + kfree(n); + } + } + } + } + + kfree(buf); + +} + +static ssize_t common_read(char *buf, size_t len, loff_t * off) +{ + ssize_t retval = 0; + size_t count; + unsigned long offset = *off; + + if (0 != (count = DbgPrintBufferOffset - offset)) { + if (count > len) { + count = len; + } + + count -= copy_to_user(buf, &DbgPrintBuffer[offset], count); + + if (count == 0) { + retval = -EFAULT; + } else { + *off += (loff_t) count; + retval = count; + } + } + return retval; + +} + +static ssize_t novfs_profile_read_inode(struct file * file, char *buf, size_t len, + loff_t * off) +{ + ssize_t retval = 0; + unsigned long offset = *off; + static char save_DbgPrintOn; + + if (offset == 0) { + down(&LocalPrint_lock); + save_DbgPrintOn = DbgPrintOn; + DbgPrintOn = 0; + + DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; + novfs_dump_inode(LocalPrint); + } + + + retval = common_read(buf, len, off); + + if (0 == retval) { + DbgPrintOn = save_DbgPrintOn; + DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; + + up(&LocalPrint_lock); + } + + return retval; + +} + +static ssize_t novfs_profile_dentry_read(struct file * file, char *buf, size_t len, + loff_t * off) +{ + ssize_t retval = 0; + unsigned long offset = *off; + static char save_DbgPrintOn; + + if (offset == 0) { + down(&LocalPrint_lock); + save_DbgPrintOn = DbgPrintOn; + DbgPrintOn = 0; + DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; + dump(novfs_root, LocalPrint); + } + + retval = common_read(buf, len, off); + + if (0 == retval) { + DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; + DbgPrintOn = save_DbgPrintOn; + + up(&LocalPrint_lock); + } + + return retval; + +} + +uint64_t get_nanosecond_time() +{ + struct timespec ts; + uint64_t retVal; + + ts = current_kernel_time(); + + retVal = (uint64_t) NSEC_PER_SEC; + retVal *= (uint64_t) ts.tv_sec; + retVal += (uint64_t) ts.tv_nsec; + + return (retVal); +} + +void novfs_profile_init() +{ + if (novfs_procfs_dir) + dbg_dir = novfs_procfs_dir; + else + dbg_dir = proc_mkdir(MODULE_NAME, NULL); + + if (dbg_dir) { + dbg_file = create_proc_read_entry("Debug", + 0600, + dbg_dir, + proc_read_DbgBuffer, NULL); + if (dbg_file) { + dbg_file->size = DBGBUFFERSIZE; + memcpy(&Dbg_proc_file_operations, dbg_file->proc_fops, + sizeof(struct file_operations)); + Dbg_proc_file_operations.read = + User_proc_read_DbgBuffer; + Dbg_proc_file_operations.write = + User_proc_write_DbgBuffer; + dbg_file->proc_fops = &Dbg_proc_file_operations; + } else { + remove_proc_entry(MODULE_NAME, NULL); + vfree(DbgPrintBuffer); + DbgPrintBuffer = NULL; + } + } + + if (DbgPrintBuffer) { + if (dbg_dir) { + inode_file = create_proc_entry("inode", 0600, dbg_dir); + if (inode_file) { + inode_file->size = 0; + memcpy(&inode_proc_file_ops, + inode_file->proc_fops, + sizeof(struct file_operations)); + inode_proc_file_ops.owner = THIS_MODULE; + inode_proc_file_ops.read = + novfs_profile_read_inode; + inode_file->proc_fops = &inode_proc_file_ops; + } + + dentry_file = create_proc_entry("dentry", + 0600, dbg_dir); + if (dentry_file) { + dentry_file->size = 0; + memcpy(&dentry_proc_file_ops, + dentry_file->proc_fops, + sizeof(struct file_operations)); + dentry_proc_file_ops.owner = THIS_MODULE; + dentry_proc_file_ops.read = novfs_profile_dentry_read; + dentry_file->proc_fops = &dentry_proc_file_ops; + } + + } else { + vfree(DbgPrintBuffer); + DbgPrintBuffer = NULL; + } + } +} + +void novfs_profile_exit(void) +{ + if (dbg_file) + DbgPrint("Calling remove_proc_entry(Debug, NULL)\n"), + remove_proc_entry("Debug", dbg_dir); + if (inode_file) + DbgPrint("Calling remove_proc_entry(inode, NULL)\n"), + remove_proc_entry("inode", dbg_dir); + if (dentry_file) + DbgPrint("Calling remove_proc_entry(dentry, NULL)\n"), + remove_proc_entry("dentry", dbg_dir); + + if (dbg_dir && (dbg_dir != novfs_procfs_dir)) { + DbgPrint("Calling remove_proc_entry(%s, NULL)\n", MODULE_NAME); + remove_proc_entry(MODULE_NAME, NULL); + } +} + + --- /dev/null +++ b/fs/novfs/scope.c @@ -0,0 +1,659 @@ +/* + * Novell NCP Redirector for Linux + * Author: James Turner + * + * This file contains functions used to scope users. + * + * Copyright (C) 2005 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vfs.h" + +#define SHUTDOWN_INTERVAL 5 +#define CLEANUP_INTERVAL 10 +#define MAX_USERNAME_LENGTH 32 + + +static struct list_head Scope_List; +static struct semaphore Scope_Lock; +static struct semaphore Scope_Thread_Delay; +static int Scope_Thread_Terminate = 0; +static struct timer_list Scope_Timer; +static unsigned int Scope_Hash_Val = 1; + +static struct novfs_scope_list *Scope_Search4Scope(struct novfs_schandle Id, + int Session, int Locked) +{ + struct novfs_scope_list *scope, *rscope = NULL; + struct novfs_schandle cur_scope; + struct list_head *sl; + int offset; + + DbgPrint("Scope_Search4Scope: 0x%p:%p 0x%x 0x%x\n", Id.hTypeId, Id.hId, + Session, Locked); + + if (Session) + offset = offsetof(struct novfs_scope_list, SessionId); + else + offset = offsetof(struct novfs_scope_list, ScopeId); + + if (!Locked) { + down(&Scope_Lock); + } + + sl = Scope_List.next; + DbgPrint("Scope_Search4Scope: 0x%p\n", sl); + while (sl != &Scope_List) { + scope = list_entry(sl, struct novfs_scope_list, ScopeList); + + cur_scope = *(struct novfs_schandle *) ((char *)scope + offset); + if (SC_EQUAL(Id, cur_scope)) { + rscope = scope; + break; + } + + sl = sl->next; + } + + if (!Locked) { + up(&Scope_Lock); + } + + DbgPrint("Scope_Search4Scope: return 0x%p\n", rscope); + return (rscope); +} + +static struct novfs_scope_list *Scope_Find_Scope(int Create) +{ + struct novfs_scope_list *scope = NULL, *pscope = NULL; + struct task_struct *task; + struct novfs_schandle scopeId; + int addscope = 0; + + task = current; + + DbgPrint("Scope_Find_Scope: %d %d %d %d\n", current_uid(), + current_euid(), current_suid(), current_fsuid()); + + //scopeId = task->euid; + UID_TO_SCHANDLE(scopeId, current_euid()); + + scope = Scope_Search4Scope(scopeId, 0, 0); + + if (!scope && Create) { + scope = kmalloc(sizeof(*pscope), GFP_KERNEL); + if (scope) { + scope->ScopeId = scopeId; + SC_INITIALIZE(scope->SessionId); + scope->ScopePid = task->pid; + scope->ScopeTask = task; + scope->ScopeHash = 0; + scope->ScopeUid = current_euid(); + scope->ScopeUserName[0] = '\0'; + + if (!novfs_daemon_create_sessionId(&scope->SessionId)) { + DbgPrint("Scope_Find_Scope2: %d %d %d %d\n", + current_uid(), current_euid(), + current_suid(), current_fsuid()); + memset(scope->ScopeUserName, 0, + sizeof(scope->ScopeUserName)); + scope->ScopeUserNameLength = 0; + novfs_daemon_getpwuid(current_euid(), + sizeof(scope->ScopeUserName), + scope->ScopeUserName); + scope->ScopeUserNameLength = + strlen(scope->ScopeUserName); + addscope = 1; + } + + scope->ScopeHash = Scope_Hash_Val++; + DbgPrint("Scope_Find_Scope: Adding 0x%p\n" + " ScopeId: 0x%p:%p\n" + " SessionId: 0x%p:%p\n" + " ScopePid: %d\n" + " ScopeTask: 0x%p\n" + " ScopeHash: %u\n" + " ScopeUid: %u\n" + " ScopeUserNameLength: %u\n" + " ScopeUserName: %s\n", + scope, + scope->ScopeId.hTypeId, scope->ScopeId.hId, + scope->SessionId.hTypeId, scope->SessionId.hId, + scope->ScopePid, + scope->ScopeTask, + scope->ScopeHash, + scope->ScopeUid, + scope->ScopeUserNameLength, + scope->ScopeUserName); + + if (SC_PRESENT(scope->SessionId)) { + down(&Scope_Lock); + pscope = + Scope_Search4Scope(scopeId, 0, 1); + + if (!pscope) { + list_add(&scope->ScopeList, + &Scope_List); + } + up(&Scope_Lock); + + if (pscope) { + printk + ("<6>Scope_Find_Scope scope not added because it was already there...\n"); + novfs_daemon_destroy_sessionId(scope-> + SessionId); + kfree(scope); + scope = pscope; + addscope = 0; + } + } else { + kfree(scope); + scope = NULL; + } + } + + if (addscope) { + novfs_add_to_root(scope->ScopeUserName); + } + } + + return (scope); +} + +static int Scope_Validate_Scope(struct novfs_scope_list *Scope) +{ + struct novfs_scope_list *s; + struct list_head *sl; + int retVal = 0; + + DbgPrint("Scope_Validate_Scope: 0x%p\n", Scope); + + down(&Scope_Lock); + + sl = Scope_List.next; + while (sl != &Scope_List) { + s = list_entry(sl, struct novfs_scope_list, ScopeList); + + if (s == Scope) { + retVal = 1; + break; + } + + sl = sl->next; + } + + up(&Scope_Lock); + + return (retVal); +} + +uid_t novfs_scope_get_uid(struct novfs_scope_list *scope) +{ + uid_t uid = 0; + if (!scope) + scope = Scope_Find_Scope(1); + + if (scope && Scope_Validate_Scope(scope)) + uid = scope->ScopeUid; + return uid; +} + +char *novfs_scope_get_username(void) +{ + char *name = NULL; + struct novfs_scope_list *Scope; + + Scope = Scope_Find_Scope(1); + + if (Scope && Scope_Validate_Scope(Scope)) + name = Scope->ScopeUserName; + + return name; +} + +struct novfs_schandle novfs_scope_get_sessionId(struct novfs_scope_list + *Scope) +{ + struct novfs_schandle sessionId; + DbgPrint("Scope_Get_SessionId: 0x%p\n", Scope); + SC_INITIALIZE(sessionId); + if (!Scope) + Scope = Scope_Find_Scope(1); + + if (Scope && Scope_Validate_Scope(Scope)) + sessionId = Scope->SessionId; + DbgPrint("Scope_Get_SessionId: return 0x%p:%p\n", sessionId.hTypeId, + sessionId.hId); + return (sessionId); +} + +struct novfs_scope_list *novfs_get_scope_from_name(struct qstr * Name) +{ + struct novfs_scope_list *scope, *rscope = NULL; + struct list_head *sl; + + DbgPrint("Scope_Get_ScopefromName: %.*s\n", Name->len, Name->name); + + down(&Scope_Lock); + + sl = Scope_List.next; + while (sl != &Scope_List) { + scope = list_entry(sl, struct novfs_scope_list, ScopeList); + + if ((Name->len == scope->ScopeUserNameLength) && + (0 == strncmp(scope->ScopeUserName, Name->name, Name->len))) + { + rscope = scope; + break; + } + + sl = sl->next; + } + + up(&Scope_Lock); + + return (rscope); +} + +int novfs_scope_set_userspace(uint64_t * TotalSize, uint64_t * Free, + uint64_t * TotalEnties, uint64_t * FreeEnties) +{ + struct novfs_scope_list *scope; + int retVal = 0; + + scope = Scope_Find_Scope(1); + + if (scope) { + if (TotalSize) + scope->ScopeUSize = *TotalSize; + if (Free) + scope->ScopeUFree = *Free; + if (TotalEnties) + scope->ScopeUTEnties = *TotalEnties; + if (FreeEnties) + scope->ScopeUAEnties = *FreeEnties; + } + + return (retVal); +} + +int novfs_scope_get_userspace(uint64_t * TotalSize, uint64_t * Free, + uint64_t * TotalEnties, uint64_t * FreeEnties) +{ + struct novfs_scope_list *scope; + int retVal = 0; + + uint64_t td, fd, te, fe; + + scope = Scope_Find_Scope(1); + + td = fd = te = fe = 0; + if (scope) { + + retVal = + novfs_daemon_get_userspace(scope->SessionId, &td, &fd, &te, &fe); + + scope->ScopeUSize = td; + scope->ScopeUFree = fd; + scope->ScopeUTEnties = te; + scope->ScopeUAEnties = fe; + } + + if (TotalSize) + *TotalSize = td; + if (Free) + *Free = fd; + if (TotalEnties) + *TotalEnties = te; + if (FreeEnties) + *FreeEnties = fe; + + return (retVal); +} + +struct novfs_scope_list *novfs_get_scope(struct dentry * Dentry) +{ + struct novfs_scope_list *scope = NULL; + char *buf, *path, *cp; + struct qstr name; + + buf = (char *)kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + path = novfs_scope_dget_path(Dentry, buf, PATH_LENGTH_BUFFER, 0); + if (path) { + DbgPrint("Scope_Get_ScopefromPath: %s\n", path); + + if (*path == '/') + path++; + + cp = path; + if (*cp) { + while (*cp && (*cp != '/')) + cp++; + + *cp = '\0'; + name.hash = 0; + name.len = (int)(cp - path); + name.name = path; + scope = novfs_get_scope_from_name(&name); + } + } + kfree(buf); + } + + return (scope); +} + +static char *add_to_list(char *Name, char *List, char *EndOfList) +{ + while (*Name && (List < EndOfList)) { + *List++ = *Name++; + } + + if (List < EndOfList) { + *List++ = '\0'; + } + return (List); +} + +char *novfs_get_scopeusers(void) +{ + struct novfs_scope_list *scope; + struct list_head *sl; + int asize = 8 * MAX_USERNAME_LENGTH; + char *list, *cp, *ep; + + DbgPrint("Scope_Get_ScopeUsers\n"); + + do { /* Copy list until done or out of memory */ + list = kmalloc(asize, GFP_KERNEL); + + DbgPrint("Scope_Get_ScopeUsers list=0x%p\n", list); + if (list) { + cp = list; + ep = cp + asize; + + /* + * Add the tree and server entries + */ + cp = add_to_list(TREE_DIRECTORY_NAME, cp, ep); + cp = add_to_list(SERVER_DIRECTORY_NAME, cp, ep); + + down(&Scope_Lock); + + sl = Scope_List.next; + while ((sl != &Scope_List) && (cp < ep)) { + scope = list_entry(sl, struct novfs_scope_list, ScopeList); + + DbgPrint("Scope_Get_ScopeUsers found 0x%p %s\n", + scope, scope->ScopeUserName); + + cp = add_to_list(scope->ScopeUserName, cp, ep); + + sl = sl->next; + } + + up(&Scope_Lock); + + if (cp < ep) { + *cp++ = '\0'; + asize = 0; + } else { /* Allocation was to small, up size */ + + asize *= 4; + kfree(list); + list = NULL; + } + } else { /* if allocation fails return an empty list */ + + break; + } + } while (!list); /* List was to small try again */ + + return (list); +} + +void *novfs_scope_lookup(void) +{ + return Scope_Find_Scope(1); +} + +static void Scope_Timer_Function(unsigned long context) +{ + up(&Scope_Thread_Delay); +} + +static int Scope_Cleanup_Thread(void *Args) +{ + struct novfs_scope_list *scope, *rscope; + struct list_head *sl, cleanup; + struct task_struct *task; + + DbgPrint("Scope_Cleanup_Thread: %d\n", current->pid); + + /* + * Setup and start que timer + */ + init_timer(&Scope_Timer); + + while (0 == Scope_Thread_Terminate) { + DbgPrint("Scope_Cleanup_Thread: looping\n"); + if (Scope_Thread_Terminate) { + break; + } + + /* + * Check scope list for any terminated processes + */ + down(&Scope_Lock); + + sl = Scope_List.next; + INIT_LIST_HEAD(&cleanup); + + while (sl != &Scope_List) { + scope = list_entry(sl, struct novfs_scope_list, ScopeList); + sl = sl->next; + + rscope = NULL; + rcu_read_lock(); + for_each_process(task) { + if ((task->cred->uid == scope->ScopeUid) + || (task->cred->euid == scope->ScopeUid)) { + rscope = scope; + break; + } + } + rcu_read_unlock(); + + if (!rscope) { + list_move(&scope->ScopeList, &cleanup); + DbgPrint("Scope_Cleanup_Thread: Scope=0x%p\n", + rscope); + } + } + + up(&Scope_Lock); + + sl = cleanup.next; + while (sl != &cleanup) { + scope = list_entry(sl, struct novfs_scope_list, ScopeList); + sl = sl->next; + + DbgPrint("Scope_Cleanup_Thread: Removing 0x%p\n" + " ScopeId: 0x%p:%p\n" + " SessionId: 0x%p:%p\n" + " ScopePid: %d\n" + " ScopeTask: 0x%p\n" + " ScopeHash: %u\n" + " ScopeUid: %u\n" + " ScopeUserName: %s\n", + scope, + scope->ScopeId, + scope->SessionId, + scope->ScopePid, + scope->ScopeTask, + scope->ScopeHash, + scope->ScopeUid, scope->ScopeUserName); + if (!Scope_Search4Scope(scope->SessionId, 1, 0)) { + novfs_remove_from_root(scope->ScopeUserName); + novfs_daemon_destroy_sessionId(scope->SessionId); + } + kfree(scope); + } + + Scope_Timer.expires = jiffies + HZ * CLEANUP_INTERVAL; + Scope_Timer.data = (unsigned long)0; + Scope_Timer.function = Scope_Timer_Function; + add_timer(&Scope_Timer); + DbgPrint("Scope_Cleanup_Thread: sleeping\n"); + + if (down_interruptible(&Scope_Thread_Delay)) { + break; + } + del_timer(&Scope_Timer); + } + Scope_Thread_Terminate = 0; + + printk(KERN_INFO "Scope_Cleanup_Thread: Exit\n"); + DbgPrint("Scope_Cleanup_Thread: Exit\n"); + return (0); +} + +void novfs_scope_cleanup(void) +{ + struct novfs_scope_list *scope; + struct list_head *sl; + + DbgPrint("Scope_Cleanup:\n"); + + /* + * Check scope list for any terminated processes + */ + down(&Scope_Lock); + + sl = Scope_List.next; + + while (sl != &Scope_List) { + scope = list_entry(sl, struct novfs_scope_list, ScopeList); + sl = sl->next; + + list_del(&scope->ScopeList); + + DbgPrint("Scope_Cleanup: Removing 0x%p\n" + " ScopeId: 0x%p:%p\n" + " SessionId: 0x%p:%p\n" + " ScopePid: %d\n" + " ScopeTask: 0x%p\n" + " ScopeHash: %u\n" + " ScopeUid: %u\n" + " ScopeUserName: %s\n", + scope, + scope->ScopeId, + scope->SessionId, + scope->ScopePid, + scope->ScopeTask, + scope->ScopeHash, + scope->ScopeUid, scope->ScopeUserName); + if (!Scope_Search4Scope(scope->SessionId, 1, 1)) { + novfs_remove_from_root(scope->ScopeUserName); + novfs_daemon_destroy_sessionId(scope->SessionId); + } + kfree(scope); + } + + up(&Scope_Lock); + +} + +/* + * Walks the dentry chain building a path. + */ +char *novfs_scope_dget_path(struct dentry *Dentry, char *Buf, unsigned int Buflen, + int Flags) +{ + char *retval = &Buf[Buflen]; + struct dentry *p = Dentry; + int len; + + *(--retval) = '\0'; + Buflen--; + + do { + if (Buflen > p->d_name.len) { + retval -= p->d_name.len; + Buflen -= p->d_name.len; + memcpy(retval, p->d_name.name, p->d_name.len); + *(--retval) = '/'; + Buflen--; + p = p->d_parent; + } else { + retval = NULL; + break; + } + } while (!IS_ROOT(p)); + + if (IS_ROOT(Dentry)) { + retval++; + } + + if (Flags) { + len = strlen(p->d_sb->s_type->name); + if (Buflen - len > 0) { + retval -= len; + Buflen -= len; + memcpy(retval, p->d_sb->s_type->name, len); + *(--retval) = '/'; + Buflen--; + } + } + + return (retval); +} + +void novfs_scope_init(void) +{ + INIT_LIST_HEAD(&Scope_List); + init_MUTEX(&Scope_Lock); + init_MUTEX_LOCKED(&Scope_Thread_Delay); + kthread_run(Scope_Cleanup_Thread, NULL, "novfs_ST"); +} + +void novfs_scope_exit(void) +{ + unsigned long expires = jiffies + HZ * SHUTDOWN_INTERVAL; + + printk(KERN_INFO "Scope_Uninit: Start\n"); + + Scope_Thread_Terminate = 1; + + up(&Scope_Thread_Delay); + + mb(); + while (Scope_Thread_Terminate && (jiffies < expires)) + yield(); + /* down(&Scope_Thread_Delay); */ + printk(KERN_INFO "Scope_Uninit: Exit\n"); + +} + + --- /dev/null +++ b/fs/novfs/vfs.h @@ -0,0 +1,454 @@ +/* + * Novell NCP Redirector for Linux + * Author: James Turner + * + * Include file for novfs. + * + * Copyright (C) 2005 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ +#ifndef __NOVFS_H +#define __NOVFS_H + +#ifndef __STDC_VERSION__ +#define __STDC_VERSION__ 0L +#endif + +#include +#include + +#include "nwcapi.h" + + +#ifndef XTIER_SCHANDLE +struct novfs_schandle { + void * hTypeId; + void * hId; + +}; + +#include "commands.h" + +#define SC_PRESENT(X) ((X.hTypeId != NULL) || (X.hId != NULL)) ? 1 : 0 +#define SC_EQUAL(X, Y) ((X.hTypeId == Y.hTypeId) && (X.hId == Y.hId)) ? 1 : 0 +#define SC_INITIALIZE(X) {X.hTypeId = X.hId = NULL;} + +#define UID_TO_SCHANDLE(hSC, uid) \ + { \ + hSC.hTypeId = NULL; \ + hSC.hId = (void *)(unsigned long)(uid); \ + } + +#define XTIER_SCHANDLE +#endif + + +/*===[ Manifest constants ]===============================================*/ +#define NOVFS_MAGIC 0x4e574653 +#define MODULE_NAME "novfs" + +#define TREE_DIRECTORY_NAME ".Trees" +#define SERVER_DIRECTORY_NAME ".Servers" + +#define PATH_LENGTH_BUFFER PATH_MAX +#define NW_MAX_PATH_LENGTH 255 + +#define XA_BUFFER (8 * 1024) + +#define IOC_LOGIN 0x4a540000 +#define IOC_LOGOUT 0x4a540001 +#define IOC_XPLAT 0x4a540002 +#define IOC_SESSION 0x4a540003 +#define IOC_DEBUGPRINT 0x4a540004 + +/* + * NetWare file attributes + */ + +#define NW_ATTRIBUTE_NORMAL 0x00 +#define NW_ATTRIBUTE_READ_ONLY 0x01 +#define NW_ATTRIBUTE_HIDDEN 0x02 +#define NW_ATTRIBUTE_SYSTEM 0x04 +#define NW_ATTRIBUTE_EXECUTE_ONLY 0x08 +#define NW_ATTRIBUTE_DIRECTORY 0x10 +#define NW_ATTRIBUTE_ARCHIVE 0x20 +#define NW_ATTRIBUTE_EXECUTE 0x40 +#define NW_ATTRIBUTE_SHAREABLE 0x80 + +/* + * Define READ/WRITE flag for DATA_LIST + */ +#define DLREAD 0 +#define DLWRITE 1 + +/* + * Define list type + */ +#define USER_LIST 1 +#define SERVER_LIST 2 +#define VOLUME_LIST 3 + +/* + * Define flags used in for inodes + */ +#define USER_INODE 1 +#define UPDATE_INODE 2 + +/* + * Define flags for directory cache flags + */ +#define ENTRY_VALID 0x00000001 + +#ifdef INTENT_MAGIC +#define NDOPENFLAGS intent.it_flags +#else +#define NDOPENFLAGS intent.open.flags +#endif + +/* + * daemon_command_t flags values + */ +#define INTERRUPTIBLE 1 + +#ifndef NOVFS_VFS_MAJOR +#define NOVFS_VFS_MAJOR 0 +#endif + +#ifndef NOVFS_VFS_MINOR +#define NOVFS_VFS_MINOR 0 +#endif + +#ifndef NOVFS_VFS_SUB +#define NOVFS_VFS_SUB 0 +#endif + +#ifndef NOVFS_VFS_RELEASE +#define NOVFS_VFS_RELEASE 0 +#endif + +#define VALUE_TO_STR( value ) #value +#define DEFINE_TO_STR(value) VALUE_TO_STR(value) + +#define NOVFS_VERSION_STRING \ + DEFINE_TO_STR(NOVFS_VFS_MAJOR)"." \ + DEFINE_TO_STR(NOVFS_VFS_MINOR)"." \ + DEFINE_TO_STR(NOVFS_VFS_SUB)"-" \ + DEFINE_TO_STR(NOVFS_VFS_RELEASE) \ + "\0" + +/*===[ Type definitions ]=================================================*/ +struct novfs_entry_info { + int type; + umode_t mode; + uid_t uid; + gid_t gid; + loff_t size; + struct timespec atime; + struct timespec mtime; + struct timespec ctime; + int namelength; + unsigned char name[1]; +}; + +struct novfs_string { + int length; + unsigned char *data; +}; + +struct novfs_login { + struct novfs_string Server; + struct novfs_string UserName; + struct novfs_string Password; +}; + +struct novfs_logout { + struct novfs_string Server; +}; + +struct novfs_dir_cache { + struct list_head list; + int flags; + u64 jiffies; + ino_t ino; + loff_t size; + umode_t mode; + struct timespec atime; + struct timespec mtime; + struct timespec ctime; + unsigned long hash; + int nameLen; + char name[1]; +}; + +struct novfs_data_list { + void *page; + void *offset; + int len; + int rwflag; +}; + + +extern char *ctime_r(time_t * clock, char *buf); + +/* + * Converts a HANDLE to a u32 type. + */ +static inline u32 HandletoUint32(void * h) +{ + return (u32) ((unsigned long) h); +} + +/* + * Converts a u32 to a HANDLE type. + */ +static inline void *Uint32toHandle(u32 ui32) +{ + return ((void *) (unsigned long) ui32); +} + +/* Global variables */ + +extern struct dentry *novfs_root; +extern struct proc_dir_entry *novfs_procfs_dir; +extern unsigned long novfs_update_timeout; +extern int novfs_page_cache; +extern char *novfs_current_mnt; +extern int novfs_max_iosize; + + +/* Global functions */ +extern int novfs_remove_from_root(char *); +extern void novfs_dump_inode(void *pf); + +extern void novfs_dump(int size, void *dumpptr); + +extern int Queue_Daemon_Command(void *request, unsigned long reqlen, void *data, + int dlen, void **reply, unsigned long * replen, + int interruptible); +extern int novfs_do_login(struct ncl_string * Server, struct ncl_string* Username, struct ncl_string * Password, void **lgnId, struct novfs_schandle *Session); + +extern int novfs_proc_init(void); +extern void novfs_proc_exit(void); + +/* + * daemon.c functions + */ +extern void novfs_daemon_queue_init(void); +extern void novfs_daemon_queue_exit(void); +extern int novfs_daemon_logout(struct qstr *Server, struct novfs_schandle *Session); +extern int novfs_daemon_set_mnt_point(char *Path); +extern int novfs_daemon_create_sessionId(struct novfs_schandle * SessionId); +extern int novfs_daemon_destroy_sessionId(struct novfs_schandle SessionId); +extern int novfs_daemon_getpwuid(uid_t uid, int unamelen, char *uname); +extern int novfs_daemon_get_userspace(struct novfs_schandle SessionId, + uint64_t * TotalSize, uint64_t * TotalFree, + uint64_t * TotalDirectoryEnties, + uint64_t * FreeDirectoryEnties); +extern int novfs_daemon_debug_cmd_send(char *Command); +extern ssize_t novfs_daemon_recv_reply(struct file *file, + const char *buf, size_t nbytes, loff_t * ppos); +extern ssize_t novfs_daemon_cmd_send(struct file *file, char *buf, + size_t len, loff_t * off); +extern int novfs_daemon_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +extern int novfs_daemon_lib_close(struct inode *inode, struct file *file); +extern int novfs_daemon_lib_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +extern int novfs_daemon_lib_open(struct inode *inode, struct file *file); +extern ssize_t novfs_daemon_lib_read(struct file *file, char *buf, + size_t len, loff_t * off); +extern ssize_t novfs_daemon_lib_write(struct file *file, const char *buf, + size_t len, loff_t * off); +extern loff_t novfs_daemon_lib_llseek(struct file *file, loff_t offset, + int origin); +extern int novfs_daemon_open_control(struct inode *Inode, struct file *File); +extern int novfs_daemon_close_control(struct inode *Inode, struct file *File); +extern int novfs_daemon_getversion(char *Buf, int Length); + + +/* + * file.c functions + */ +extern int novfs_verify_file(struct qstr *Path, struct novfs_schandle SessionId); +extern int novfs_get_alltrees(struct dentry *parent); +extern int novfs_get_servers(unsigned char **ServerList, + struct novfs_schandle SessionId); +extern int novfs_get_vols(struct qstr *Server, + unsigned char **VolumeList, struct novfs_schandle SessionId); +extern int novfs_get_file_info(unsigned char *Path, + struct novfs_entry_info *Info, struct novfs_schandle SessionId); +extern int novfs_getx_file_info(char *Path, const char *Name, + char *buffer, ssize_t buffer_size, ssize_t *dataLen, + struct novfs_schandle SessionId); +extern int novfs_listx_file_info(char *Path, char *buffer, + ssize_t buffer_size, ssize_t *dataLen, + struct novfs_schandle SessionId); +extern int novfs_setx_file_info(char *Path, const char *Name, const void *Value, + unsigned long valueLen, + unsigned long *bytesWritten, int flags, + struct novfs_schandle SessionId); + +extern int novfs_get_dir_listex(unsigned char *Path, void **EnumHandle, + int *Count, struct novfs_entry_info **Info, + struct novfs_schandle SessionId); +extern int novfs_open_file(unsigned char *Path, int Flags, + struct novfs_entry_info * Info, void **Handle, + struct novfs_schandle SessionId); +extern int novfs_create(unsigned char *Path, int DirectoryFlag, + struct novfs_schandle SessionId); +extern int novfs_close_file(void * Handle, struct novfs_schandle SessionId); +extern int novfs_read_file(void * Handle, unsigned char *Buffer, + size_t * Bytes, loff_t * Offset, + struct novfs_schandle SessionId); +extern int novfs_read_pages(void * Handle, struct novfs_data_list *DList, + int DList_Cnt, size_t * Bytes, loff_t * Offset, + struct novfs_schandle SessionId); +extern int novfs_write_file(void * Handle, unsigned char *Buffer, + size_t * Bytes, loff_t * Offset, + struct novfs_schandle SessionId); +extern int novfs_write_page(void * Handle, struct page *Page, + struct novfs_schandle SessionId); +extern int novfs_write_pages(void * Handle, struct novfs_data_list *DList, + int DList_Cnt, size_t Bytes, loff_t Offset, + struct novfs_schandle SessionId); +extern int novfs_delete(unsigned char *Path, int DirectoryFlag, + struct novfs_schandle SessionId); +extern int novfs_trunc(unsigned char *Path, int PathLen, + struct novfs_schandle SessionId); +extern int novfs_trunc_ex(void * Handle, loff_t Offset, + struct novfs_schandle SessionId); +extern int novfs_rename_file(int DirectoryFlag, unsigned char *OldName, + int OldLen, unsigned char *NewName, int NewLen, + struct novfs_schandle SessionId); +extern int novfs_set_attr(unsigned char *Path, struct iattr *Attr, + struct novfs_schandle SessionId); +extern int novfs_get_file_cache_flag(unsigned char * Path, + struct novfs_schandle SessionId); +extern int novfs_set_file_lock(struct novfs_schandle SessionId, void * fhandle, + unsigned char fl_type, loff_t fl_start, + loff_t len); + +extern struct inode *novfs_get_inode(struct super_block *sb, int mode, + int dev, uid_t uid, ino_t ino, struct qstr *name); +extern int novfs_read_stream(void * ConnHandle, unsigned char * Handle, + unsigned char * Buffer, size_t * Bytes, loff_t * Offset, + int User, struct novfs_schandle SessionId); +extern int novfs_write_stream(void * ConnHandle, unsigned char * Handle, + unsigned char * Buffer, size_t * Bytes, loff_t * Offset, + struct novfs_schandle SessionId); +extern int novfs_close_stream(void * ConnHandle, unsigned char * Handle, + struct novfs_schandle SessionId); + +extern int novfs_add_to_root(char *); +extern int novfs_end_directory_enumerate(void *EnumHandle, + struct novfs_schandle SessionId); + +/* + * scope.c functions + */ +extern void novfs_scope_init(void); +extern void novfs_scope_exit(void); +extern void *novfs_scope_lookup(void); +extern uid_t novfs_scope_get_uid(struct novfs_scope_list *); +extern struct novfs_schandle novfs_scope_get_sessionId(struct + novfs_scope_list *); +extern char *novfs_get_scopeusers(void); +extern int novfs_scope_set_userspace(uint64_t * TotalSize, uint64_t * Free, + uint64_t * TotalEnties, uint64_t * FreeEnties); +extern int novfs_scope_get_userspace(uint64_t * TotalSize, uint64_t * Free, + uint64_t * TotalEnties, uint64_t * FreeEnties); +extern char *novfs_scope_dget_path(struct dentry *Dentry, char *Buf, + unsigned int Buflen, int Flags); +extern void novfs_scope_cleanup(void); +extern struct novfs_scope_list *novfs_get_scope_from_name(struct qstr *); +extern struct novfs_scope_list *novfs_get_scope(struct dentry *); +extern char *novfs_scope_get_username(void); + +/* + * profile.c functions + */ +extern u64 get_nanosecond_time(void); +extern int ___DbgPrint(const char *site, const char *Fmt, ...); +#define DbgPrint(fmt, args...) ___DbgPrint(__func__, ": " fmt "\n", ##args) +#define __DbgPrint(fmt, args...) ___DbgPrint("", fmt, ##args) + +extern void novfs_profile_init(void); +extern void novfs_profile_exit(void); + +/* + * nwcapi.c functions + */ +extern int novfs_auth_conn(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_conn_close(struct novfs_xplat *pdata, + void **Handle, struct novfs_schandle Session); +extern int novfs_get_conn_info(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_set_conn_info(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_get_daemon_ver(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_get_id_info(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_license_conn(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_login_id(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_logout_id(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_open_conn_by_addr(struct novfs_xplat *pdata, + void **Handle, struct novfs_schandle Session); +extern int novfs_open_conn_by_name(struct novfs_xplat *pdata, + void **Handle, struct novfs_schandle Session); +extern int novfs_open_conn_by_ref(struct novfs_xplat *pdata, + void **Handle, struct novfs_schandle Session); +extern int novfs_query_feature(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_raw_send(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_scan_conn_info(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_sys_conn_close(struct novfs_xplat *pdata, + unsigned long *Handle, struct novfs_schandle Session); +extern int novfs_unauthenticate(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_unlicense_conn(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_change_auth_key(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_enum_ids(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_get_default_ctx(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_get_preferred_DS_tree(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_get_tree_monitored_conn(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_set_default_ctx(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_set_preferred_DS_tree(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_set_pri_conn(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_get_pri_conn(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_set_map_drive(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_unmap_drive(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_enum_drives(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_get_bcast_msg(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_set_key_value(struct novfs_xplat *pdata, + struct novfs_schandle Session); +extern int novfs_verify_key_value(struct novfs_xplat *pdata, + struct novfs_schandle Session); + + +#endif /* __NOVFS_H */ +