15978 lines
430 KiB
Plaintext
15978 lines
430 KiB
Plaintext
From 9297af3ffd8a1c98f35fb7a273386576e061ff16 Mon Sep 17 00:00:00 2001
|
|
From: Greg Kroah-Hartman <gregkh@suse.de>
|
|
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 <ldiverson@novell.com>
|
|
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
|
|
|
---
|
|
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 <linux/module.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/mount.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/list.h>
|
|
+#include <linux/timer.h>
|
|
+#include <linux/poll.h>
|
|
+#include <linux/pagemap.h>
|
|
+#include <linux/smp_lock.h>
|
|
+#include <linux/semaphore.h>
|
|
+#include <asm/uaccess.h>
|
|
+#include <asm/atomic.h>
|
|
+#include <linux/time.h>
|
|
+
|
|
+#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 <linux/module.h>
|
|
+#include <linux/kthread.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/file.h>
|
|
+#include <linux/sched.h>
|
|
+#include <linux/dcache.h>
|
|
+#include <linux/pagemap.h>
|
|
+#include <linux/stat.h>
|
|
+#include <linux/slab.h>
|
|
+#include <asm/uaccess.h>
|
|
+
|
|
+#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 <linux/module.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/dcache.h>
|
|
+#include <linux/mount.h>
|
|
+#include <linux/pagemap.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/smp_lock.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/unistd.h>
|
|
+#include <asm/statfs.h>
|
|
+#include <asm/uaccess.h>
|
|
+#include <linux/ctype.h>
|
|
+#include <linux/statfs.h>
|
|
+#include <linux/pagevec.h>
|
|
+#include <linux/writeback.h>
|
|
+#include <linux/backing-dev.h>
|
|
+#include <linux/mm.h>
|
|
+#include <linux/file.h>
|
|
+
|
|
+/*===[ 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 = "<NULL>";
|
|
+ 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 = "<NULL>";
|
|
+ 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 = "<NULL>";
|
|
+ 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 = "<NULL>";
|
|
+ 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 = "<NULL>";
|
|
+ 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 = "<NULL>";
|
|
+ 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 <linux/module.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/list.h>
|
|
+#include <linux/timer.h>
|
|
+#include <linux/poll.h>
|
|
+#include <linux/semaphore.h>
|
|
+#include <asm/uaccess.h>
|
|
+
|
|
+#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 <linux/module.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/proc_fs.h>
|
|
+#include <linux/smp_lock.h>
|
|
+
|
|
+#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 <linux/module.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/proc_fs.h>
|
|
+#include <linux/sched.h>
|
|
+#include <asm/uaccess.h>
|
|
+#include <linux/vmalloc.h>
|
|
+#include <linux/time.h>
|
|
+
|
|
+#include <linux/profile.h>
|
|
+#include <linux/notifier.h>
|
|
+
|
|
+#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 <linux/version.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/kthread.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/file.h>
|
|
+#include <linux/sched.h>
|
|
+#include <linux/personality.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/synclink.h>
|
|
+#include <linux/smp_lock.h>
|
|
+#include <linux/semaphore.h>
|
|
+#include <linux/security.h>
|
|
+#include <linux/syscalls.h>
|
|
+
|
|
+#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 <linux/version.h>
|
|
+#include <linux/namei.h>
|
|
+
|
|
+#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 */
|
|
+
|