summaryrefslogtreecommitdiffstats
path: root/sesman
diff options
context:
space:
mode:
authorLaxmikant Rashinkar <LK.Rashinkar@gmail.com>2013-03-08 15:37:30 -0800
committerLaxmikant Rashinkar <LK.Rashinkar@gmail.com>2013-03-08 15:37:30 -0800
commit78d4e19258388d547c5760578df5f59ec36c8824 (patch)
tree29bef3f3f29b5be81412543e2b1d90aa699bd94c /sesman
parentb53cefbea45575ab3772a2705d67c2a293437401 (diff)
downloadxrdp-proprietary-78d4e19258388d547c5760578df5f59ec36c8824.tar.gz
xrdp-proprietary-78d4e19258388d547c5760578df5f59ec36c8824.zip
o early checkin for drive redirection
o basic drive redirection is working o functions currently supported: open: read, write, create, get/set attribute o requires latest NeutrinoRDP to work o note: clipboard is broken because of the move from linked lists to inodes in the FUSE code
Diffstat (limited to 'sesman')
-rw-r--r--sesman/chansrv/chansrv.c9
-rw-r--r--sesman/chansrv/chansrv_fuse.c2359
-rw-r--r--sesman/chansrv/chansrv_fuse.h73
-rw-r--r--sesman/chansrv/clipboard.c6
-rw-r--r--sesman/chansrv/clipboard_file.c8
-rw-r--r--sesman/chansrv/devredir.c1283
-rw-r--r--sesman/chansrv/devredir.h379
7 files changed, 3589 insertions, 528 deletions
diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c
index 9d55388e..74e2db4a 100644
--- a/sesman/chansrv/chansrv.c
+++ b/sesman/chansrv/chansrv.c
@@ -376,7 +376,7 @@ process_message_channel_setup(struct stream *s)
if (g_cliprdr_index >= 0)
{
clipboard_init();
- fuse_init();
+ xfuse_init();
}
if (g_rdpsnd_index >= 0)
@@ -387,6 +387,7 @@ process_message_channel_setup(struct stream *s)
if (g_rdpdr_index >= 0)
{
dev_redir_init();
+ xfuse_init();
}
if (g_rail_index >= 0)
@@ -953,7 +954,7 @@ channel_thread_loop(void *in_val)
xcommon_check_wait_objs();
sound_check_wait_objs();
dev_redir_check_wait_objs();
- fuse_check_wait_objs();
+ xfuse_check_wait_objs();
timeout = -1;
num_objs = 0;
objs[num_objs] = g_term_event;
@@ -965,8 +966,8 @@ channel_thread_loop(void *in_val)
xcommon_get_wait_objs(objs, &num_objs, &timeout);
sound_get_wait_objs(objs, &num_objs, &timeout);
dev_redir_get_wait_objs(objs, &num_objs, &timeout);
- fuse_get_wait_objs(objs, &num_objs, &timeout);
- }
+ xfuse_get_wait_objs(objs, &num_objs, &timeout);
+ } /* end while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) */
}
trans_delete(g_lis_trans);
diff --git a/sesman/chansrv/chansrv_fuse.c b/sesman/chansrv/chansrv_fuse.c
index eb60f63a..c55fd57f 100644
--- a/sesman/chansrv/chansrv_fuse.c
+++ b/sesman/chansrv/chansrv_fuse.c
@@ -1,7 +1,7 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
- * Copyright (C) Jay Sorg 2012
+ * Copyright (C) Laxmikant Rashinkar 2013
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,62 @@
* limitations under the License.
*/
-#ifdef XRDP_FUSE
+/*
+ * TODO
+ * o need to support sym links
+ * o when creating dir/file, ensure it does not already exist
+ * o enable changing metadata for files/folders (time, owner, mode etc)
+ * o do not allow dirs to be created in ino==1 except for .clipbard and share mounts
+ * o xrdp_fs needs to grow dynamically - currently it is fixed at 1k or 4k
+ * o fix the HACK where I have to use my own buf instead of g_buffer
+ * this is in func xfuse_check_wait_objs()
+ * o if fuse mount point is already mounted, I get segfault
+ * o in open, check for modes such as O_TRUNC, O_APPEND
+ * o copying over an existing file does not work
+ * o are we calling close?
+ * o need to keep track of open files, reqd during rename
+ * o fuse ops to support
+ * o rmdir
+ * o rename (mv)
+ * o remove file
+ * o touch does not work
+ * o mknod (may not be required if create is correctly implemented)
+ * o symlink
+ * o keep track of lookup_count
+ * o chmod must work
+ *
+ */
+
+/* FUSE mount point */
+char g_fuse_root_path[256] = "";
+
+#ifndef XRDP_FUSE
+
+/******************************************************************************
+** **
+** when FUSE is NOT enabled in xrdp **
+** **
+******************************************************************************/
+
+#include "arch.h"
+
+/* dummy calls when XRDP_FUSE is not defined */
+int xfuse_init() {}
+int xfuse_deinit() {}
+int xfuse_check_wait_objs(void) {}
+int xfuse_get_wait_objs(tbus *objs, int *count, int *timeout) {}
+int xfuse_clear_clip_dir(void) {}
+int xfuse_file_contents_range(int stream_id, char *data, int data_bytes) {}
+int xfuse_file_contents_size(int stream_id, int file_size) {}
+int xfuse_add_clip_dir_item(char *filename, int flags, int size, int lindex) {}
+
+#else
+
+/******************************************************************************
+** **
+** when FUSE is enabled in xrdp **
+** **
+******************************************************************************/
#define FUSE_USE_VERSION 26
#define _FILE_OFFSET_BITS 64
@@ -24,692 +79,2034 @@
#include <fuse/fuse_lowlevel.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <errno.h>
-#include <fcntl.h>
+#include <time.h>
#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+#include <sched.h>
+
#include "arch.h"
-#include "parse.h"
-#include "list.h"
#include "os_calls.h"
-#include "chansrv.h"
#include "chansrv_fuse.h"
-#include "clipboard_file.h"
-
-#define LLOG_LEVEL 1
-#define LLOGLN(_level, _args) \
- do \
- { \
- if (_level < LLOG_LEVEL) \
- { \
- g_write("chansrv:fuse [%10.10u]: ", g_time3()); \
- g_writeln _args ; \
- } \
- } \
- while (0)
-char g_fuse_root_path[256] = "";
+#define min(x, y) ((x) < (y) ? (x) : (y))
-static struct fuse_chan *g_ch = 0;
-static struct fuse_session *g_se = 0;
-static char *g_mountpoint = 0;
-static tintptr g_bufsize = 0;
-static char *g_buffer = 0;
-static int g_fd = 0;
-static time_t g_time = 0;
-static int g_uid = 0;
-static int g_gid = 0;
-
-/* used for file data request sent to client */
-struct req_list_item
-{
- fuse_req_t req;
- int stream_id;
- int lindex;
- int off;
- int size;
+#define XFUSE_ATTR_TIMEOUT 1.0
+#define XFUSE_ENTRY_TIMEOUT 1.0
+
+#define DOTDOT_INODE 0
+#define DOT_INODE 0
+#define FIRST_INODE 1
+
+/* module based logging */
+#define LOG_ERROR 0
+#define LOG_INFO 1
+#define LOG_DEBUG 2
+#define LOG_LEVEL LOG_ERROR
+
+#define log_error(_params...) \
+{ \
+ g_write("[%10.10u]: FUSE %s: %d : ERROR: ", \
+ g_time3(), __func__, __LINE__); \
+ g_writeln (_params); \
+}
+
+#define log_info(_params...) \
+{ \
+ if (LOG_INFO <= LOG_LEVEL) \
+ { \
+ g_write("[%10.10u]: FUSE %s: %d : ", \
+ g_time3(), __func__, __LINE__); \
+ g_writeln (_params); \
+ } \
+}
+
+#define log_debug(_params...) \
+{ \
+ if (LOG_DEBUG <= LOG_LEVEL) \
+ { \
+ g_write("[%10.10u]: FUSE %s: %d : ", \
+ g_time3(), __func__, __LINE__); \
+ g_writeln (_params); \
+ } \
+}
+
+/* the xrdp file system in memory */
+struct xrdp_fs
+{
+ struct xrdp_inode **inode_table; /* a table of entries; can grow */
+ unsigned int max_entries; /* size of inode_table[] */
+ unsigned int num_entries; /* num entries available in inode_table */
+ unsigned int next_node; /* next free node number */
};
-static struct list *g_req_list = 0;
struct dirbuf
{
char *p;
- int size;
- int alloc_bytes;
+ size_t size;
+};
+
+/* FUSE reply types */
+#define RT_FUSE_REPLY_OPEN 1
+#define RT_FUSE_REPLY_CREATE 2
+
+struct xfuse_info
+{
+ struct fuse_file_info *fi;
+ fuse_req_t req;
+ fuse_ino_t inode;
+ int invoke_fuse;
+ char name[1024];
+ tui32 device_id;
+ int reply_type;
+ int mode;
};
+typedef struct xfuse_info XFUSE_INFO;
-struct xfuse_file_info
-{
- int ino;
- int lindex;
- char pathname[256];
- char filename[256];
- int flags;
- int size;
- tui64 time;
- struct xfuse_file_info* child;
- struct xfuse_file_info* parent;
- struct xfuse_file_info* next;
- struct xfuse_file_info* prev;
+struct xfuse_handle
+{
+ tui32 DeviceId;
+ tui32 FileId;
};
+typedef struct xfuse_handle XFUSE_HANDLE;
+
+/* globals */
+
+static struct xrdp_fs g_xrdp_fs; /* an inst of xrdp file system */
+static char *g_mount_point = 0; /* our FUSE mount point */
+static struct fuse_lowlevel_ops g_xfuse_ops; /* setup FUSE callbacks */
+static int g_xfuse_inited = 0; /* true when FUSE is inited */
+static struct fuse_chan *g_ch = 0;
+static struct fuse_session *g_se = 0;
+static char *g_buffer = 0;
+static int g_fd = 0;
+static tintptr g_bufsize = 0;
+
+/* forward declarations for internal access */
+static int xfuse_init_xrdp_fs();
+static int xfuse_deinit_xrdp_fs();
+static int xfuse_init_lib(int argc, char **argv);
+static int xfuse_is_inode_valid(int ino);
+
+// LK_TODO
+#if 0
+static void xfuse_create_file(fuse_req_t req, fuse_ino_t parent,
+ const char *name, mode_t mode, int type);
+#endif
+
+static void xfuse_dump_fs();
+static void xfuse_dump_xrdp_inode(struct xrdp_inode *xino);
+static tui32 xfuse_get_device_id_for_inode(tui32 ino, char *full_path);
+static void fuse_reverse_pathname(char *full_path, char *reverse_path);
+
+static struct xrdp_inode * xfuse_get_inode_from_pinode_name(tui32 pinode,
+ const char *name);
-static struct xfuse_file_info *g_fuse_files = 0;
-static struct fuse_lowlevel_ops g_xrdp_ll_oper;
-static int g_ino = 2;
+static struct xrdp_inode * xfuse_create_file_in_xrdp_fs(tui32 device_id,
+ int pinode, char *name,
+ int type);
-/*****************************************************************************/
-static struct xfuse_file_info *APP_CC
-fuse_find_file_info_by_name(struct xfuse_file_info *ffi, const char *filename)
+static int xfuse_does_file_exist(int parent, char *name);
+
+/* forward declarations for calls we make into dev_redir */
+int dev_redir_get_dir_listing(void *fusep, tui32 device_id, char *path);
+
+int dev_redir_file_open(void *fusep, tui32 device_id, char *path,
+ int mode, int type);
+
+int dev_redir_file_read(void *fusep, tui32 device_id, tui32 FileId,
+ tui32 Length, tui64 Offset);
+
+int dev_redir_file_write(void *fusep, tui32 device_id, tui32 FileId,
+ const char *buf, tui32 Length, tui64 Offset);
+
+/* forward declarations for FUSE callbacks */
+static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent,
+ const char *name);
+
+static void xfuse_cb_getattr(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi);
+
+/* this is not a callback, but its's used by xfuse_cb_readdir() */
+static void xfuse_dirbuf_add(fuse_req_t req, struct dirbuf *b,
+ const char *name, fuse_ino_t ino);
+
+static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+ off_t off, struct fuse_file_info *fi);
+
+static void xfuse_cb_mkdir(fuse_req_t req, fuse_ino_t parent,
+ const char *name, mode_t mode);
+
+static void xfuse_cb_rmdir(fuse_req_t req, fuse_ino_t parent,
+ const char *name);
+
+static void xfuse_create_dir_or_file(fuse_req_t req, fuse_ino_t parent,
+ const char *name, mode_t mode,
+ struct fuse_file_info *fi, int type);
+
+static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi);
+
+static void xfuse_cb_read(fuse_req_t req, fuse_ino_t ino, size_t size,
+ off_t off, struct fuse_file_info *fi);
+
+static void xfuse_cb_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
+ size_t size, off_t off, struct fuse_file_info *fi);
+
+static void xfuse_cb_create(fuse_req_t req, fuse_ino_t parent,
+ const char *name, mode_t mode,
+ struct fuse_file_info *fi);
+
+// LK_TODO may not need to be implemented
+#if 0
+static void xfuse_cb_statfs(fuse_req_t req, fuse_ino_t ino);
+
+static void xfuse_cb_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+ const char *value, size_t size, int flags);
+
+static void xfuse_cb_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+ size_t size);
+
+static void xfuse_cb_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size);
+
+static void xfuse_cb_access(fuse_req_t req, fuse_ino_t ino, int mask);
+
+static void xfuse_cb_getlk(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi, struct flock *lock);
+
+static void xfuse_cb_setlk(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi, struct flock *lock,
+ int sleep);
+
+static void xfuse_cb_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
+ struct fuse_file_info *fi, unsigned flags,
+ const void *in_buf, size_t in_bufsz,
+ size_t out_bufsz);
+
+static void xfuse_cb_poll(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi,
+ struct fuse_pollhandle *ph);
+#endif
+
+static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+ int to_set, struct fuse_file_info *fi);
+
+/*****************************************************************************
+** **
+** public functions - can be called from any code path **
+** **
+*****************************************************************************/
+
+/**
+ * Initialize FUSE subsystem
+ *
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+
+int xfuse_init()
{
- struct xfuse_file_info *rv;
- struct xfuse_file_info *rv1;
+ char *param0 = "xrdp-chansrv";
+ char *argv[4];
- rv = ffi;
- while (rv != 0)
+ /* if already inited, just return */
+ if (g_xfuse_inited)
{
- if (g_strcmp(rv->filename, filename) == 0)
- {
- return rv;
- }
- if (rv->flags & 1)
+ log_debug("already inited");
+ return 1;
+ }
+
+ if (g_ch != 0)
+ {
+ log_error("g_ch is not zero");
+ return -1;
+ }
+
+ /* define FUSE mount point to ~/xrdp_client */
+ g_snprintf(g_fuse_root_path, 255, "%s/xrdp_client", g_getenv("HOME"));
+
+ /* if FUSE mount point does not exist, create it */
+ if (!g_directory_exist(g_fuse_root_path))
+ {
+ if (!g_create_dir(g_fuse_root_path))
{
- rv1 = fuse_find_file_info_by_name(rv->child, filename);
- if (rv1 != 0)
- {
- return rv1;
- }
+ log_error("mkdir %s failed. If %s is already mounted, you must "
+ "first unmount it", g_fuse_root_path, g_fuse_root_path);
+ return -1;
}
- rv = rv->next;
}
+
+ /* setup xrdp file system */
+ if (xfuse_init_xrdp_fs())
+ return -1;
+
+ /* setup FUSE callbacks */
+ g_memset(&g_xfuse_ops, 0, sizeof(g_xfuse_ops));
+ g_xfuse_ops.lookup = xfuse_cb_lookup;
+ g_xfuse_ops.readdir = xfuse_cb_readdir;
+ g_xfuse_ops.mkdir = xfuse_cb_mkdir;
+ //g_xfuse_ops.rmdir = xfuse_cb_rmdir;
+ g_xfuse_ops.open = xfuse_cb_open;
+ g_xfuse_ops.read = xfuse_cb_read;
+ g_xfuse_ops.write = xfuse_cb_write;
+ g_xfuse_ops.create = xfuse_cb_create;
+ g_xfuse_ops.getattr = xfuse_cb_getattr;
+ g_xfuse_ops.setattr = xfuse_cb_setattr;
+
+#if 0
+ g_xfuse_ops.statfs = xfuse_cb_statfs;
+ g_xfuse_ops.listxattr = xfuse_cb_listxattr;
+ g_xfuse_ops.getlk = xfuse_cb_getlk;
+ g_xfuse_ops.setlk = xfuse_cb_setlk;
+ g_xfuse_ops.ioctl = xfuse_cb_ioctl;
+ g_xfuse_ops.poll = xfuse_cb_poll;
+ g_xfuse_ops.access = xfuse_cb_access;
+ g_xfuse_ops.setxattr = xfuse_cb_setxattr;
+ g_xfuse_ops.getxattr = xfuse_cb_getxattr;
+#endif
+
+ argv[0] = param0;
+ argv[1] = g_fuse_root_path;
+ argv[2] = 0;
+
+ if (xfuse_init_lib(2, argv))
+ {
+ xfuse_deinit();
+ return -1;
+ }
+
+ g_xfuse_inited = 1;
return 0;
}
-/*****************************************************************************/
-static struct xfuse_file_info *APP_CC
-fuse_find_file_info_by_ino(struct xfuse_file_info *ffi, int ino)
+/**
+ * De-initialize FUSE subsystem
+ *
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+
+int xfuse_deinit()
{
- struct xfuse_file_info *rv;
- struct xfuse_file_info *rv1;
+ xfuse_deinit_xrdp_fs();
- rv = ffi;
- while (rv != 0)
+ if (g_ch != 0)
{
- if (rv->ino == ino)
- {
- return rv;
- }
- if (rv->flags & 1)
- {
- rv1 = fuse_find_file_info_by_ino(rv->child, ino);
- if (rv1 != 0)
- {
- return rv1;
- }
- }
- rv = rv->next;
+ fuse_session_remove_chan(g_ch);
+ fuse_unmount(g_mount_point, g_ch);
+ g_ch = 0;
+ }
+
+ if (g_se != 0)
+ {
+ fuse_session_destroy(g_se);
+ g_se = 0;
+ }
+
+ if (g_buffer != 0)
+ {
+ g_free(g_buffer);
+ g_buffer = 0;
+ }
+
+ g_xfuse_inited = 0;
+ return 0;
+}
+
+/**
+ *
+ *
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+int xfuse_check_wait_objs(void)
+{
+ struct fuse_chan *tmpch;
+ int rval;
+
+#define HACK
+
+#ifdef HACK
+char buf[135168];
+#endif
+
+ if (g_ch == 0)
+ return 0;
+
+ if (g_tcp_select(g_fd, 0) & 1)
+ {
+ tmpch = g_ch;
+
+#ifdef HACK
+ rval = fuse_chan_recv(&tmpch, buf, g_bufsize);
+#else
+ rval = fuse_chan_recv(&tmpch, g_buffer, g_bufsize);
+#endif
+ if (rval == -EINTR)
+ return -1;
+
+ if (rval == -ENODEV)
+ return -1;
+
+ if (rval <= 0)
+ return -1;
+
+#ifdef HACK
+ fuse_session_process(g_se, buf, rval, tmpch);
+#else
+ fuse_session_process(g_se, g_buffer, rval, tmpch);
+#endif
}
+
+ return 0;
+}
+
+/**
+ *
+ *
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+
+int xfuse_get_wait_objs(tbus *objs, int *count, int *timeout)
+{
+ int lcount;
+
+ if (g_ch == 0)
+ return 0;
+
+ lcount = *count;
+ objs[lcount] = g_fd;
+ lcount++;
+ *count = lcount;
+
return 0;
}
-/*****************************************************************************/
-static int APP_CC
-xrdp_ffi2stat(struct xfuse_file_info *ffi, struct stat *stbuf)
+/**
+ * @brief Create specified share directory.
+ *
+ * This code gets called from devredir
+ *
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+
+int xfuse_create_share(tui32 device_id, char *dirname)
{
- stbuf->st_ino = ffi->ino;
- if (ffi->flags & 1)
+ /* LK_TODO need to specify parent dir, mode */
+
+ XFUSE_INFO *fip;
+ XRDP_INODE *xinode;
+ tui32 saved_inode;
+
+ if (dirname == NULL || strlen(dirname) == 0)
+ return -1;
+
+ if ((xinode = calloc(1, sizeof(struct xrdp_inode))) == NULL)
{
- stbuf->st_mode = S_IFDIR | 0755;
- stbuf->st_nlink = 2;
- stbuf->st_uid = g_uid;
- stbuf->st_gid = g_gid;
- stbuf->st_atime = g_time;
- stbuf->st_mtime = g_time;
- stbuf->st_ctime = g_time;
+ log_debug("calloc() failed");
+ return -1;
}
- else
+
+ if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL)
{
- stbuf->st_mode = S_IFREG | 0664;
- stbuf->st_nlink = 1;
- stbuf->st_size = ffi->size;
- stbuf->st_uid = g_uid;
- stbuf->st_gid = g_gid;
- stbuf->st_atime = g_time;
- stbuf->st_mtime = g_time;
- stbuf->st_ctime = g_time;
+ log_error("system out of memory");
+ return -1;
}
+
+ /* create directory entry */
+ xinode->parent_inode = 1;
+ xinode->inode = g_xrdp_fs.next_node++;
+ xinode->mode = 0755 | S_IFDIR;
+ xinode->nlink = 1;
+ xinode->uid = getuid();
+ xinode->gid = getgid();
+ xinode->size = 0;
+ xinode->atime = time(0);
+ xinode->mtime = time(0);
+ xinode->ctime = time(0);
+ strcpy(xinode->name, dirname);
+ xinode->device_id = device_id;
+
+ g_xrdp_fs.num_entries++;
+ saved_inode = xinode->inode;
+
+ /* insert it in xrdp fs */
+ g_xrdp_fs.inode_table[xinode->inode] = xinode;
+ log_debug("created new share named %s at inode_table[%d]",
+ dirname, (int) xinode->inode);
+
+ /* update nentries in parent inode */
+ xinode = g_xrdp_fs.inode_table[1];
+ if (xinode == NULL)
+ return -1;
+ xinode->nentries++;
+
+ /* enumerate root dir, do not call FUSE when done */
+ fip->req = NULL;
+ fip->inode = 1; // LK_TODO saved_inode;
+ strncpy(fip->name, dirname, 1024);
+ fip->name[1023] = 0;
+ fip->device_id = device_id;
+
+ dev_redir_get_dir_listing((void *) fip, device_id, "\\");
+
return 0;
}
-/*****************************************************************************/
-static void DEFAULT_CC
-xrdp_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
+/**
+ *
+ *
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+
+int xfuse_clear_clip_dir(void)
+{
+ return 0; // CLIPBOARD_TODO
+}
+
+/**
+ *
+ *
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+
+int xfuse_file_contents_range(int stream_id, char *data, int data_bytes)
+{
+ return 0; // CLIPBOARD_TODO
+}
+
+/**
+ *
+ *
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+
+int xfuse_add_clip_dir_item(char *filename, int flags, int size, int lindex)
+{
+ return 0; // CLIPBOARD_TODO
+}
+
+/**
+ *
+ *
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+
+int xfuse_file_contents_size(int stream_id, int file_size)
+{
+ return 0; // CLIPBOARD_TODO
+}
+
+/*****************************************************************************
+** **
+** private functions - can only be called from within this file **
+** **
+*****************************************************************************/
+
+/**
+ * Initialize FUSE library
+ *
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+
+static int xfuse_init_lib(int argc, char **argv)
{
- struct xfuse_file_info *ffi;
- struct fuse_entry_param e;
+ struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
- LLOGLN(10, ("xrdp_ll_lookup: name %s", name));
- if (parent != 1)
+ if (fuse_parse_cmdline(&args, &g_mount_point, 0, 0) < 0)
{
- fuse_reply_err(req, ENOENT);
+ log_error("fuse_parse_cmdline() failed");
+ fuse_opt_free_args(&args);
+ return -1;
}
- else
+
+ if ((g_ch = fuse_mount(g_mount_point, &args)) == 0)
{
- ffi = fuse_find_file_info_by_name(g_fuse_files, name);
- if (ffi != 0)
- {
- LLOGLN(10, ("xrdp_ll_lookup: name %s ino %d", name, ffi->ino));
- g_memset(&e, 0, sizeof(e));
- e.ino = ffi->ino;
- e.attr_timeout = 1.0;
- e.entry_timeout = 1.0;
- xrdp_ffi2stat(ffi, &e.attr);
- fuse_reply_entry(req, &e);
- return;
- }
+ log_error("fuse_mount() failed");
+ fuse_opt_free_args(&args);
+ return -1;
}
- fuse_reply_err(req, ENOENT);
+
+ g_se = fuse_lowlevel_new(&args, &g_xfuse_ops, sizeof(g_xfuse_ops), 0);
+ if (g_se == 0)
+ {
+ log_error("fuse_lowlevel_new() failed");
+ fuse_unmount(g_mount_point, g_ch);
+ g_ch = 0;
+ fuse_opt_free_args(&args);
+ return -1;
+ }
+
+ fuse_opt_free_args(&args);
+ fuse_session_add_chan(g_se, g_ch);
+ g_bufsize = fuse_chan_bufsize(g_ch);
+
+ g_buffer = calloc(g_bufsize, 1);
+ g_fd = fuse_chan_fd(g_ch);
+
+ return 0;
}
-/*****************************************************************************/
-static void DEFAULT_CC
-xrdp_ll_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+/**
+ * Initialize xrdp file system
+ *
+ * @return 0 on success, -1 on failure
+ *
+ *****************************************************************************/
+
+static int xfuse_init_xrdp_fs()
{
- struct stat stbuf;
- struct xfuse_file_info *ffi;
+ struct xrdp_inode *xino;
- LLOGLN(10, ("xrdp_ll_getattr: ino %d", ino));
- g_memset(&stbuf, 0, sizeof(stbuf));
- if (ino == 1)
+ g_xrdp_fs.inode_table = calloc(4096, sizeof(struct xrdp_inode *));
+ if (g_xrdp_fs.inode_table == NULL)
{
- stbuf.st_mode = S_IFDIR | 0755;
- stbuf.st_nlink = 2;
- stbuf.st_uid = g_uid;
- stbuf.st_gid = g_gid;
- stbuf.st_atime = g_time;
- stbuf.st_mtime = g_time;
- stbuf.st_ctime = g_time;
- fuse_reply_attr(req, &stbuf, 1.0);
- return;
+ log_error("system out of memory");
+ return -1;
}
- ffi = fuse_find_file_info_by_ino(g_fuse_files, ino);
- if (ffi == 0)
+
+ /*
+ * index 0 is our .. dir
+ */
+
+ if ((xino = calloc(1, sizeof(struct xrdp_inode))) == NULL)
{
- LLOGLN(0, ("xrdp_ll_getattr: fuse_find_file_info_by_ino failed ino %d", ino));
- fuse_reply_err(req, ENOENT);
+ log_error("system out of memory");
+ free(g_xrdp_fs.inode_table);
+ return -1;
}
- else if (xrdp_ffi2stat(ffi, &stbuf) == -1)
+ g_xrdp_fs.inode_table[0] = xino;
+ xino->parent_inode = 0;
+ xino->inode = 0;
+ xino->mode = S_IFDIR | 0755;
+ xino->nentries = 1;
+ xino->uid = getuid();
+ xino->gid = getgid();
+ xino->size = 0;
+ xino->atime = time(0);
+ xino->mtime = time(0);
+ xino->ctime = time(0);
+ strcpy(xino->name, "..");
+
+ /*
+ * index 1 is our . dir
+ */
+
+ if ((xino = calloc(1, sizeof(struct xrdp_inode))) == NULL)
{
- fuse_reply_err(req, ENOENT);
+ log_error("system out of memory");
+ free(g_xrdp_fs.inode_table[0]);
+ free(g_xrdp_fs.inode_table);
+ return -1;
}
- else
+ g_xrdp_fs.inode_table[1] = xino;
+ xino->parent_inode = 0;
+ xino->inode = 1;
+ xino->mode = S_IFDIR | 0755;
+ xino->nentries = 1;
+ xino->uid = getuid();
+ xino->gid = getgid();
+ xino->size = 0;
+ xino->atime = time(0);
+ xino->mtime = time(0);
+ xino->ctime = time(0);
+ strcpy(xino->name, ".");
+
+ /*
+ * index 2 is for clipboard use
+ */
+
+ if ((xino = calloc(1, sizeof(struct xrdp_inode))) == NULL)
{
- fuse_reply_attr(req, &stbuf, 1.0);
+ log_error("system out of memory");
+ free(g_xrdp_fs.inode_table[0]);
+ free(g_xrdp_fs.inode_table[1]);
+ free(g_xrdp_fs.inode_table);
+ return -1;
}
+
+ g_xrdp_fs.inode_table[2] = xino;
+ xino->parent_inode = 1;
+ xino->inode = 2;
+ xino->nentries = 1;
+ xino->mode = S_IFDIR | 0755;
+ xino->uid = getuid();
+ xino->gid = getgid();
+ xino->size = 0;
+ xino->atime = time(0);
+ xino->mtime = time(0);
+ xino->ctime = time(0);
+ strcpy(xino->name, ".clipboard");
+
+ g_xrdp_fs.max_entries = 1024;
+ g_xrdp_fs.num_entries = 3;
+ g_xrdp_fs.next_node = 3;
+
+ return 0;
}
-/*****************************************************************************/
-static void APP_CC
-dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name, fuse_ino_t ino)
+/**
+ * zap the xrdp file system
+ *
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+
+static int xfuse_deinit_xrdp_fs()
{
- struct stat stbuf;
- char *newp;
- int oldsize;
-
- oldsize = b->size;
- b->size += fuse_add_direntry(req, 0, 0, name, 0, 0);
- LLOGLN(10, ("1 %d %d %d", b->alloc_bytes, b->size, oldsize));
- if (b->size > b->alloc_bytes)
- {
- b->alloc_bytes = (b->size + 1023) & (~1023);
- LLOGLN(10, ("2 %d %d %d", b->alloc_bytes, b->size, oldsize));
- newp = g_malloc(b->alloc_bytes, 0);
- g_memcpy(newp, b->p, oldsize);
- g_free(b->p);
- b->p = newp;
- }
- g_memset(&stbuf, 0, sizeof(stbuf));
- stbuf.st_ino = ino;
- fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name,
- &stbuf, b->size);
+ return 0;
+}
+
+/**
+ * determine if specified ino exists in xrdp file system
+ *
+ * @return 1 if it does, 0 otherwise
+ *****************************************************************************/
+
+static int xfuse_is_inode_valid(int ino)
+{
+ /* our lowest ino is FIRST_INODE */
+ if (ino < FIRST_INODE)
+ return 0;
+
+ /* is ino present in our table? */
+ if (ino >= g_xrdp_fs.next_node)
+ return 0;
+
+ return 1;
}
-#define lmin(x, y) ((x) < (y) ? (x) : (y))
+/**
+ * @brief Create a directory or regular file.
+ *****************************************************************************/
+
+// LK_TODO
+#if 0
+static void xfuse_create_file(fuse_req_t req, fuse_ino_t parent,
+ const char *name, mode_t mode, int type)
+{
+ struct xrdp_inode *xinode;
+ struct fuse_entry_param e;
+
+ log_debug("parent=%d name=%s", (int) parent, name);
+
+ /* do we have a valid parent inode? */
+ if (!xfuse_is_inode_valid(parent))
+ {
+ log_error("inode %d is not valid", parent);
+ fuse_reply_err(req, EBADF);
+ }
+
+ if ((xinode = calloc(1, sizeof(struct xrdp_inode))) == NULL)
+ {
+ log_error("calloc() failed");
+ fuse_reply_err(req, ENOMEM);
+ }
+
+ /* create directory entry */
+ xinode->parent_inode = parent;
+ xinode->inode = g_xrdp_fs.next_node++; /* TODO should be thread safe */
+ xinode->mode = mode | type;
+ xinode->uid = getuid();
+ xinode->gid = getgid();
+ xinode->size = 0;
+ xinode->atime = time(0);
+ xinode->mtime = time(0);
+ xinode->ctime = time(0);
+ strcpy(xinode->name, name);
+
+ g_xrdp_fs.num_entries++;
+
+ /* insert it in xrdp fs */
+ g_xrdp_fs.inode_table[xinode->inode] = xinode;
+ log_debug("inserted new dir at inode_table[%d]", (int) xinode->inode);
+
+ xfuse_dump_fs();
+
+ log_debug("new inode=%d", (int) xinode->inode);
-/*****************************************************************************/
-static int APP_CC
-reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
- off_t off, size_t maxsize)
+ /* setup return value */
+ memset(&e, 0, sizeof(e));
+ e.ino = xinode->inode;
+ e.attr_timeout = XFUSE_ATTR_TIMEOUT;
+ e.entry_timeout = XFUSE_ENTRY_TIMEOUT;
+ e.attr.st_ino = xinode->inode;
+ e.attr.st_mode = xinode->mode;
+ e.attr.st_nlink = xinode->nlink;
+ e.attr.st_uid = xinode->uid;
+ e.attr.st_gid = xinode->gid;
+ e.attr.st_size = 0;
+ e.attr.st_atime = xinode->atime;
+ e.attr.st_mtime = xinode->mtime;
+ e.attr.st_ctime = xinode->ctime;
+ e.generation = 1;
+
+ fuse_reply_entry(req, &e);
+}
+#endif
+
+static void xfuse_dump_fs()
{
- LLOGLN(10, ("reply_buf_limited: %d", maxsize));
- if (off < bufsize)
+ int i;
+ struct xrdp_inode *xinode;
+
+ log_debug("found %d entries", g_xrdp_fs.num_entries - FIRST_INODE);
+
+ for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++)
{
- return fuse_reply_buf(req, buf + off,
- lmin(bufsize - off, maxsize));
+ xinode = g_xrdp_fs.inode_table[i];
+ log_debug("pinode=%d inode=%d nentries=%d mode=0x%x name=%s",
+ (int) xinode->parent_inode, (int) xinode->inode,
+ xinode->nentries, xinode->mode, xinode->name);
}
- else
+ log_debug("");
+}
+
+/**
+ * Dump contents of xinode structure
+ *
+ * @param xino xinode structure to dump
+ *****************************************************************************/
+
+static void xfuse_dump_xrdp_inode(struct xrdp_inode *xino)
+{
+ log_debug("--- dumping struct xinode ---");
+ log_debug("name: %s", xino->name);
+ log_debug("parent_inode: %ld", xino->parent_inode);
+ log_debug("inode: %ld", xino->inode);
+ log_debug("mode: %o", xino->mode);
+ log_debug("nlink: %d", xino->nlink);
+ log_debug("uid: %d", xino->uid);
+ log_debug("gid: %d", xino->gid);
+ log_debug("size: %ld", xino->size);
+ log_debug("device_id: %d", xino->device_id);
+ log_debug("");
+}
+
+/**
+ * Return the device_id associated with specified inode and copy the
+ * full path to the specified inode into full_path
+ *
+ * @param ino the inode
+ * @param full_path full path to the inode
+ *
+ * @return the device_id of specified inode
+ *****************************************************************************/
+
+static tui32 xfuse_get_device_id_for_inode(tui32 ino, char *full_path)
+{
+ tui32 parent_inode = 0;
+ tui32 child_inode = ino;
+ char reverse_path[4096];
+
+ reverse_path[0] = 0;
+ full_path[0] = 0;
+
+ /* ino == 1 is a special case; we already know that it is not */
+ /* associated with any device redirection */
+ if (ino == 1)
+ return 0;
+
+ while (1)
{
- return fuse_reply_buf(req, 0, 0);
+ strcat(reverse_path, g_xrdp_fs.inode_table[child_inode]->name);
+
+ parent_inode = g_xrdp_fs.inode_table[child_inode]->parent_inode;
+ if (parent_inode == 1)
+ break;
+
+ strcat(reverse_path, "/");
+ child_inode = parent_inode;
}
+
+ fuse_reverse_pathname(full_path, reverse_path);
+
+ return g_xrdp_fs.inode_table[child_inode]->device_id;
}
-/*****************************************************************************/
-static void DEFAULT_CC
-xrdp_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
- off_t off, struct fuse_file_info *fi)
+/**
+ * Reverse the pathname in 'reverse_path' and insert it into 'full_path'
+ *
+ * Example: abba/music/share1 becomes share1/music/abba
+ *
+ * @param full_path path name in the correct order
+ * @param reverse_path path name in the reverse order
+ *****************************************************************************/
+
+static void fuse_reverse_pathname(char *full_path, char *reverse_path)
{
- struct xfuse_file_info *ffi;
- struct dirbuf b;
+ char *cptr;
- LLOGLN(10, ("xrdp_ll_readdir: ino %d", ino));
- if (ino != 1)
+ full_path[0] = 0;
+
+ while ((cptr = strrchr(reverse_path, '/')) != NULL)
{
- fuse_reply_err(req, ENOTDIR);
+ strcat(full_path, cptr + 1);
+ strcat(full_path, "/");
+ cptr[0] = 0;
}
- else
+ strcat(full_path, reverse_path);
+}
+
+/**
+ * Return the inode that matches the name and parent inode
+ *****************************************************************************/
+
+static struct xrdp_inode * xfuse_get_inode_from_pinode_name(tui32 pinode,
+ const char *name)
+{
+ int i;
+ struct xrdp_inode * xinode;
+
+ for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++)
{
- ffi = g_fuse_files;
- g_memset(&b, 0, sizeof(b));
- dirbuf_add(req, &b, ".", 1);
- dirbuf_add(req, &b, "..", 1);
- while (ffi != 0)
- {
- LLOGLN(10, ("xrdp_ll_readdir: %s", ffi->filename));
- dirbuf_add(req, &b, ffi->filename, ffi->ino);
- ffi = ffi->next;
- }
- reply_buf_limited(req, b.p, b.size, off, size);
- g_free(b.p);
+ xinode = g_xrdp_fs.inode_table[i];
+
+ /* match parent inode */
+ if (xinode->parent_inode != pinode)
+ continue;
+
+ /* match name */
+ if (strcmp(xinode->name, name) != 0)
+ continue;
+
+ return xinode;
}
+ return NULL;
}
-/*****************************************************************************/
-static void DEFAULT_CC
-xrdp_ll_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
+/**
+ * Create file in xrdp file system
+ *
+ * @param pinode the parent inode
+ * @param name filename
+ *
+ * @return XRDP_INODE on success, NULL on failure
+ *****************************************************************************/
+
+static struct xrdp_inode * xfuse_create_file_in_xrdp_fs(tui32 device_id,
+ int pinode, char *name,
+ int type)
{
- LLOGLN(10, ("xrdp_ll_open: ino %d", (int)ino));
- if (ino == 1)
+ XRDP_INODE *xinode;
+ XRDP_INODE *xinodep;
+
+ if ((name == NULL) || (strlen(name) == 0))
+ return NULL;
+
+ if ((xinode = calloc(1, sizeof(XRDP_INODE))) == NULL)
{
- fuse_reply_err(req, EISDIR);
+ log_error("system out of memory");
+ return NULL;
}
- else if ((fi->flags & 3) != O_RDONLY)
+
+ log_debug("S_IFDIR=0x%x S_IFREG=0x%x type=0x%x", S_IFDIR, S_IFREG, type);
+
+ xinode->parent_inode = pinode;
+ xinode->inode = g_xrdp_fs.next_node++; /* TODO should be thread safe */
+ xinode->nlink = 1;
+ xinode->uid = getuid();
+ xinode->gid = getgid();
+ xinode->atime = time(0);
+ xinode->mtime = time(0);
+ xinode->ctime = time(0);
+ xinode->device_id = device_id;
+ xinode->is_synced = 1;
+ strcpy(xinode->name, name);
+
+ if (type == S_IFDIR)
{
- fuse_reply_err(req, EACCES);
+ xinode->mode = 0755 | type;
+ xinode->size = 4096;
}
else
{
- fuse_reply_open(req, fi);
+ xinode->mode = 0644 | type;
+ xinode->size = 0;
}
+
+ g_xrdp_fs.inode_table[xinode->inode] = xinode;
+ g_xrdp_fs.num_entries++; /* TODO should be thread safe */
+
+ /* bump up lookup count in parent dir */
+ xinodep = g_xrdp_fs.inode_table[pinode];
+ xinodep->nentries++;
+
+ log_debug("LK_TODO: incremented nentries; parent=%d nentries=%d",
+ pinode, xinodep->nentries);
+
+ /* LK_TODO */
+ xfuse_dump_fs();
+
+ return xinode;
}
-/*****************************************************************************/
-static void DEFAULT_CC
-xrdp_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size,
- off_t off, struct fuse_file_info *fi)
+/**
+ * Check if specified file exists
+ *
+ * @param parent parent inode of file
+ * @param name flilename or dirname
+ *
+ * @return 1 if specified file exists, 0 otherwise
+ *****************************************************************************/
+
+static int xfuse_does_file_exist(int parent, char *name)
{
- char *data;
- int stream_id;
- struct xfuse_file_info *ffi;
- struct req_list_item *rli;
+ int i;
+ XRDP_INODE *xinode;
- LLOGLN(10, ("xrdp_ll_read: %d %d %d", (int)ino, (int)off, (int)size));
- ffi = fuse_find_file_info_by_ino(g_fuse_files, ino);
- if (ffi != 0)
+ for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++)
{
- /* reply later */
- stream_id = 0;
- rli = (struct req_list_item *)
- g_malloc(sizeof(struct req_list_item), 1);
- rli->req = req;
- rli->stream_id = stream_id;
- rli->lindex = ffi->lindex;
- rli->off = off;
- rli->size = size;
- list_add_item(g_req_list, (tbus)rli);
- if (g_req_list->count == 1)
+ xinode = g_xrdp_fs.inode_table[i];
+
+ if ((xinode->parent_inode == parent) &&
+ (strcmp(xinode->name, name) == 0))
{
- clipboard_request_file_data(rli->stream_id, rli->lindex,
- rli->off, rli->size);
+ return 1;
}
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+** **
+** callbacks for devredir **
+** **
+******************************************************************************/
+
+/**
+ * Add a file or directory to xrdp file system
+ *****************************************************************************/
+
+void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode)
+{
+ XFUSE_INFO *fip = (XFUSE_INFO *) vp;
+ XRDP_INODE *target_inode;
+
+ if ((fip == NULL) || (xinode == NULL))
+ {
+ log_error("fip or xinode are NULL");
+ return;
+ }
+
+ /* do we have a valid inode? */
+ if (!xfuse_is_inode_valid(fip->inode))
+ {
+ log_error("inode %d is not valid", fip->inode);
+ return;
+ }
+
+ /* if filename is . or .. don't add it */
+ if ((strcmp(xinode->name, ".") == 0) || (strcmp(xinode->name, "..") == 0))
+ {
+ free(xinode);
return;
}
- LLOGLN(0, ("xrdp_ll_read: fuse_find_file_info_by_ino failed ino %d", (int)ino));
- data = (char *)g_malloc(size, 1);
- fuse_reply_buf(req, data, size);
- g_free(data);
+ /* we have a parent inode and a dir name; what we need is the xinode */
+ /* that matches the parent inode and the dir name */
+ target_inode = xfuse_get_inode_from_pinode_name(fip->inode, fip->name);
+ if (target_inode == 0)
+ return;
+
+ xinode->parent_inode = target_inode->inode;
+ xinode->inode = g_xrdp_fs.next_node++;
+ xinode->uid = getuid();
+ xinode->gid = getgid();
+ xinode->device_id = fip->device_id;
+
+ g_xrdp_fs.num_entries++;
+
+ /* insert it in xrdp fs */
+ g_xrdp_fs.inode_table[xinode->inode] = xinode;
+
+ /* bump up lookup count */
+ xinode = g_xrdp_fs.inode_table[target_inode->inode];
+ xinode->nentries++;
+
+ log_debug("added %s to pinode=%d, nentries=%d target_inode->inode=%d",
+ fip->name, fip->inode, xinode->nentries, target_inode->inode);
}
-/*****************************************************************************/
-/* returns error */
-static int APP_CC
-fuse_init_lib(int argc, char **argv)
+/**
+ *****************************************************************************/
+
+void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus)
{
- struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
- int error;
+ struct xrdp_inode *xinode;
+ struct fuse_entry_param e;
+ int i;
- error = fuse_parse_cmdline(&args, &g_mountpoint, 0, 0);
- if (error == -1)
+ XFUSE_INFO *fip = (XFUSE_INFO *) vp;
+
+ xfuse_dump_fs();
+
+ if (fip == NULL)
{
- LLOGLN(0, ("fuse_init_lib: fuse_parse_cmdline failed"));
- fuse_opt_free_args(&args);
- return 1;
+ log_debug("fip is NULL");
+ goto done;
}
- g_ch = fuse_mount(g_mountpoint, &args);
- if (g_ch == 0)
+
+ if (IoStatus != 0)
{
- LLOGLN(0, ("fuse_init_lib: fuse_mount failed"));
- fuse_opt_free_args(&args);
- return 1;
+ /* command failed */
+ if (fip->invoke_fuse)
+ fuse_reply_err(fip->req, ENOENT);
+ goto done;
}
- g_se = fuse_lowlevel_new(&args, &g_xrdp_ll_oper,
- sizeof(g_xrdp_ll_oper), 0);
- if (g_se == 0)
+
+ /* do we have a valid inode? */
+ if (!xfuse_is_inode_valid(fip->inode))
{
- LLOGLN(0, ("fuse_init_lib: fuse_lowlevel_new failed"));
- fuse_unmount(g_mountpoint, g_ch);
- g_ch = 0;
- fuse_opt_free_args(&args);
- return 1;
+ log_error("inode %d is not valid", fip->inode);
+ if (fip->invoke_fuse)
+ fuse_reply_err(fip->req, EBADF);
+ goto done;
}
- fuse_opt_free_args(&args);
- fuse_session_add_chan(g_se, g_ch);
- g_bufsize = fuse_chan_bufsize(g_ch);
- g_buffer = g_malloc(g_bufsize, 0);
- g_fd = fuse_chan_fd(g_ch);
- return 0;
+
+ log_debug("looking for parent_inode=%d name=%s", fip->inode, fip->name);
+
+ for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++)
+ {
+ xinode = g_xrdp_fs.inode_table[i];
+
+ /* match parent inode */
+ if (xinode->parent_inode != fip->inode)
+ continue;
+
+ /* match name */
+ if (strcmp(xinode->name, fip->name) != 0)
+ continue;
+
+ memset(&e, 0, sizeof(e));
+ e.ino = xinode->inode;
+ e.attr_timeout = XFUSE_ATTR_TIMEOUT;
+ e.entry_timeout = XFUSE_ENTRY_TIMEOUT;
+ e.attr.st_ino = xinode->inode;
+ e.attr.st_mode = xinode->mode;
+ e.attr.st_nlink = xinode->nlink;
+ e.attr.st_uid = xinode->uid;
+ e.attr.st_gid = xinode->gid;
+ e.attr.st_size = xinode->size;
+ e.attr.st_atime = xinode->atime;
+ e.attr.st_mtime = xinode->mtime;
+ e.attr.st_ctime = xinode->ctime;
+ e.generation = 1;
+
+ xinode->is_synced = 1;
+
+ if (fip->invoke_fuse)
+ fuse_reply_entry(fip->req, &e);
+
+ break;
+ }
+
+ if (i == g_xrdp_fs.num_entries)
+ {
+ /* requested entry not found */
+ log_debug("did NOT find entry");
+ if (fip->invoke_fuse)
+ fuse_reply_err(fip->req, ENOENT);
+ }
+
+done:
+
+ free(fip);
}
-/*****************************************************************************/
-static int APP_CC
-fuse_delete_dir_items(struct xfuse_file_info *ffi)
+void xfuse_devredir_cb_open_file(void *vp, tui32 DeviceId, tui32 FileId)
{
- struct xfuse_file_info *ffi1;
+ XFUSE_HANDLE *fh;
+
+ XFUSE_INFO *fip = (XFUSE_INFO *) vp;
+ if (fip == NULL)
+ {
+ log_debug("fip is NULL");
+ goto done;
+ }
- while (ffi != 0)
+ if (fip->fi != NULL)
{
- if (ffi->flags & 1)
+ log_debug("$$$$$$$$$$$$$$$ allocationg fh");
+
+ /* LK_TODO fH NEEDS TO BE RELEASED WHEN THE FILE IS CLOSED */
+ if ((fh = calloc(1, sizeof(XFUSE_HANDLE))) == NULL)
{
- fuse_delete_dir_items(ffi->child);
+ log_error("system out of memory");
+ free(fip);
+ if (fip->invoke_fuse)
+ fuse_reply_err(fip->req, ENOMEM);
+ return;
}
- ffi1 = ffi;
- ffi = ffi->next;
- g_free(ffi1);
+
+ /* save file handle for later use */
+ fh->DeviceId = DeviceId;
+ fh->FileId = FileId;
+
+ fip->fi->fh = (uint64_t) fh;
}
- return 0;
+
+ if (fip->invoke_fuse)
+ {
+ if (fip->reply_type == RT_FUSE_REPLY_OPEN)
+ {
+ log_debug("LK_TODO sending fuse_reply_open(); "
+ "DeviceId=%d FileId=%d req=%p fi=%p",
+ fh->DeviceId, fh->FileId, fip->req, fip->fi);
+
+ fuse_reply_open(fip->req, fip->fi);
+ }
+ else if (fip->reply_type == RT_FUSE_REPLY_CREATE)
+ {
+ XRDP_INODE *xinode;
+ struct fuse_entry_param e;
+
+// LK_TODO
+#if 0
+ if ((xinode = g_xrdp_fs.inode_table[fip->inode]) == NULL)
+ {
+ log_error("inode at inode_table[%d] is NULL", fip->inode);
+ fuse_reply_err(fip->req, EBADF);
+ goto done;
+ }
+#else
+ /* create entry in xrdp file system */
+ xinode = xfuse_create_file_in_xrdp_fs(fip->device_id, fip->inode,
+ fip->name, fip->mode);
+ if (xinode == NULL)
+ {
+ fuse_reply_err(fip->req, ENOMEM);
+ return;
+ }
+#endif
+ memset(&e, 0, sizeof(struct fuse_entry_param));
+
+ e.ino = xinode->inode;
+ e.attr_timeout = XFUSE_ATTR_TIMEOUT;
+ e.entry_timeout = XFUSE_ENTRY_TIMEOUT;
+ e.attr.st_ino = xinode->inode;
+ e.attr.st_mode = xinode->mode;
+ e.attr.st_nlink = xinode->nlink;
+ e.attr.st_uid = xinode->uid;
+ e.attr.st_gid = xinode->gid;
+ e.attr.st_size = xinode->size;
+ e.attr.st_atime = xinode->atime;
+ e.attr.st_mtime = xinode->mtime;
+ e.attr.st_ctime = xinode->ctime;
+ e.generation = 1;
+
+ if (fip->mode == S_IFDIR)
+ fuse_reply_entry(fip->req, &e);
+ else
+ fuse_reply_create(fip->req, &e, fip->fi);
+ }
+ else
+ {
+ log_error("invalid reply type: %d", fip->reply_type);
+ }
+ }
+
+done:
+
+ free(fip);
}
-/*****************************************************************************/
-int APP_CC
-fuse_clear_clip_dir(void)
+void xfuse_devredir_cb_read_file(void *vp, char *buf, size_t length)
{
- fuse_delete_dir_items(g_fuse_files);
- g_fuse_files = 0;
- return 0;
+ XFUSE_HANDLE *fh;
+ XFUSE_INFO *fip;
+
+ fip = (XFUSE_INFO *) vp;
+ if (fip == NULL)
+ goto done;
+
+ fuse_reply_buf(fip->req, buf, length);
+
+done:
+
+ fh = (XFUSE_HANDLE *) fip->fi->fh;
+ free(fh);
+ free(fip);
}
-/*****************************************************************************/
-/* returns error */
-int APP_CC
-fuse_add_clip_dir_item(char *filename, int flags, int size, int lindex)
+void xfuse_devredir_cb_write_file(void *vp, char *buf, size_t length)
{
- struct xfuse_file_info *ffi;
- struct xfuse_file_info *ffi1;
+ XRDP_INODE *xinode;
+ XFUSE_HANDLE *fh;
+ XFUSE_INFO *fip;
- LLOGLN(10, ("fuse_add_clip_dir_item: adding %s ino %d", filename, g_ino));
- ffi = g_fuse_files;
- if (ffi == 0)
- {
- ffi1 = (struct xfuse_file_info *)
- g_malloc(sizeof(struct xfuse_file_info), 1);
- ffi1->flags = flags;
- ffi1->ino = g_ino++;
- ffi1->lindex = lindex;
- ffi1->size = size;
- g_strncpy(ffi1->filename, filename, 255);
- g_fuse_files = ffi1;
- return 0;
- }
- while (ffi->next != 0)
- {
- ffi = ffi->next;
- }
- ffi1 = (struct xfuse_file_info *)
- g_malloc(sizeof(struct xfuse_file_info), 1);
- ffi1->flags = flags;
- ffi1->ino = g_ino++;
- ffi1->lindex = lindex;
- ffi1->size = size;
- g_strncpy(ffi1->filename, filename, 255);
- ffi->next = ffi1;
- return 0;
+ fip = (XFUSE_INFO *) vp;
+ if (fip == NULL)
+ goto done;
+
+ fuse_reply_write(fip->req, length);
+
+ /* update file size */
+ if ((xinode = g_xrdp_fs.inode_table[fip->inode]) != NULL)
+ xinode->size += length;
+ else
+ log_error("inode at inode_table[%d] is NULL", fip->inode);
+
+done:
+
+ fh = (XFUSE_HANDLE *) fip->fi->fh;
+ free(fh);
+ free(fip);
}
-/*****************************************************************************/
-int APP_CC
-fuse_get_wait_objs(tbus *objs, int *count, int *timeout)
+/******************************************************************************
+** **
+** callbacks for fuse **
+** **
+******************************************************************************/
+
+/**
+ * Look up a directory entry by name and get its attributes
+ *
+ *****************************************************************************/
+
+static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
{
- int lcount;
+ XFUSE_INFO *fip;
+ XRDP_INODE *xinode;
+ struct fuse_entry_param e;
+ tui32 device_id;
+ char full_path[4096];
+ char *cptr;
- LLOGLN(10, ("fuse_get_wait_objs:"));
- if (g_ch == 0)
+ log_debug("ENTERED: looking for parent=%d name=%s", (int) parent, name);
+
+ xfuse_dump_fs();
+
+ if (!xfuse_is_inode_valid(parent))
{
- return 0;
+ log_error("inode %d is not valid", parent);
+ fuse_reply_err(req, EBADF);
+ return;
}
- lcount = *count;
- objs[lcount] = g_fd;
- lcount++;
- *count = lcount;
- return 0;
-}
+// LK_TODO
+#if 0
+ for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++)
+ {
+ xinode = g_xrdp_fs.inode_table[i];
-/*****************************************************************************/
-int APP_CC
-fuse_check_wait_objs(void)
-{
- struct fuse_chan *tmpch;
- int res;
+ /* match parent inode */
+ if (xinode->parent_inode != parent)
+ continue;
- LLOGLN(10, ("fuse_check_wait_objs:"));
- if (g_ch == 0)
+ /* match name */
+ if (strcmp(xinode->name, name) != 0)
+ continue;
+
+ /* got a full match; if this dir is located on a remote device */
+ /* and is not synced, do a remote look up */
+ if ((xinode->device_id != 0) && (!xinode->is_synced))
+ goto do_remote_lookup;
+
+ memset(&e, 0, sizeof(e));
+ e.ino = xinode->inode;
+ e.attr_timeout = XFUSE_ATTR_TIMEOUT;
+ e.entry_timeout = XFUSE_ENTRY_TIMEOUT;
+ e.attr.st_ino = xinode->inode;
+ e.attr.st_mode = xinode->mode;
+ e.attr.st_nlink = xinode->nlink;
+ e.attr.st_uid = xinode->uid;
+ e.attr.st_gid = xinode->gid;
+ e.attr.st_size = xinode->size;
+ e.attr.st_atime = xinode->atime;
+ e.attr.st_mtime = xinode->mtime;
+ e.attr.st_ctime = xinode->ctime;
+ e.generation = 1;
+
+ fuse_reply_entry(req, &e);
+ log_debug("found entry in xrdp fs; returning");
+ return;
+ }
+#else
+ if ((xinode = xfuse_get_inode_from_pinode_name(parent, name)) != NULL)
{
- return 0;
+ /* got a full match; if this dir is located on a remote device */
+ /* and is not synced, do a remote look up */
+ if ((xinode->device_id != 0) && (!xinode->is_synced))
+ goto do_remote_lookup;
+
+ memset(&e, 0, sizeof(e));
+ e.ino = xinode->inode;
+ e.attr_timeout = XFUSE_ATTR_TIMEOUT;
+ e.entry_timeout = XFUSE_ENTRY_TIMEOUT;
+ e.attr.st_ino = xinode->inode;
+ e.attr.st_mode = xinode->mode;
+ e.attr.st_nlink = xinode->nlink;
+ e.attr.st_uid = xinode->uid;
+ e.attr.st_gid = xinode->gid;
+ e.attr.st_size = xinode->size;
+ e.attr.st_atime = xinode->atime;
+ e.attr.st_mtime = xinode->mtime;
+ e.attr.st_ctime = xinode->ctime;
+ e.generation = 1;
+
+ fuse_reply_entry(req, &e);
+ log_debug("found entry in xrdp fs; returning");
+ return;
}
- if (g_tcp_select(g_fd, 0) & 1)
+
+#endif
+
+do_remote_lookup:
+
+ /* if ino belongs to a redirected share, pass the call to devredir; */
+ /* when done, devredir will invoke xfuse_devredir_cb_enum_dir_done(...) */
+ device_id = xfuse_get_device_id_for_inode((tui32) parent, full_path);
+ if (device_id != 0)
{
- LLOGLN(10, ("fuse_check_wait_objs: fd is set"));
- tmpch = g_ch;
- res = fuse_chan_recv(&tmpch, g_buffer, g_bufsize);
- if (res == -EINTR)
+ log_debug("did not find entry; redirecting call to dev_redir");
+
+ if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL)
{
- return 0;
+ log_error("system out of memory");
+ fuse_reply_err(req, ENOMEM);
+ return;
}
- if (res <= 0)
+ fip->req = req;
+ fip->inode = parent;
+ strncpy(fip->name, name, 1024);
+ fip->name[1023] = 0;
+ fip->invoke_fuse = 1;
+ fip->device_id = device_id;
+
+ strcat(full_path, "/");
+ strcat(full_path, name);
+
+ /* we want path minus 'root node of the share' */
+ if ((cptr = strchr(full_path, '/')) == NULL)
{
- return 1;
+ /* enumerate root dir */
+ if (dev_redir_get_dir_listing((void *) fip, device_id, "\\"))
+ {
+ log_error("failed to send dev_redir_get_dir_listing() cmd");
+ fuse_reply_buf(req, NULL, 0);
+ }
+ else
+ {
+ log_debug("dev_redir_get_dir_listing() called");
+ }
+
}
- fuse_session_process(g_se, g_buffer, res, tmpch);
+ else
+ {
+ if (dev_redir_get_dir_listing((void *) fip, device_id, cptr))
+ {
+ log_error("failed to send dev_redir_get_dir_listing() cmd");
+ fuse_reply_buf(req, NULL, 0);
+ }
+ }
+
+ log_debug("cmd sent; reting");
+ return;
}
- return 0;
+
+ log_debug("parent=%d name=%s not found", (int) parent, name);
+ fuse_reply_err(req, ENOENT);
}
-/*****************************************************************************/
-/* returns error */
-int APP_CC
-fuse_init(void)
+/**
+ * Get file attributes
+ *****************************************************************************/
+
+static void xfuse_cb_getattr(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi)
{
- char *param0 = "xrdp-chansrv";
- char *argv[4];
+ struct xrdp_inode *xino;
+ struct stat stbuf;
- if (g_ch != 0)
+ (void) fi;
+
+ log_debug("ino=%d", (int) ino);
+
+ /* if ino is not valid, just return */
+ if (!xfuse_is_inode_valid(ino))
{
- return 0;
+ log_error("inode %d is not valid", ino);
+ fuse_reply_err(req, EBADF);
+ return;
}
- g_snprintf(g_fuse_root_path, 255, "%s/xrdp_client", g_getenv("HOME"));
- LLOGLN(0, ("fuse_init: using root_path [%s]", g_fuse_root_path));
- if (!g_directory_exist(g_fuse_root_path))
+
+ xino = g_xrdp_fs.inode_table[ino];
+ xfuse_dump_xrdp_inode(xino);
+
+ memset(&stbuf, 0, sizeof(stbuf));
+ stbuf.st_ino = ino;
+ stbuf.st_mode = xino->mode;
+ stbuf.st_nlink = xino->nlink;
+ stbuf.st_size = xino->size;
+
+ fuse_reply_attr(req, &stbuf, 1.0);
+}
+
+/**
+ *
+ *****************************************************************************/
+
+static void xfuse_dirbuf_add(fuse_req_t req, struct dirbuf *b,
+ const char *name, fuse_ino_t ino)
+{
+ struct stat stbuf;
+ size_t oldsize = b->size;
+
+ log_debug("adding ino=%d name=%s", (int) ino, name);
+
+ b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
+ b->p = (char *) realloc(b->p, b->size);
+
+ memset(&stbuf, 0, sizeof(stbuf));
+ stbuf.st_ino = ino;
+ fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
+ b->size);
+}
+
+/**
+ *
+ *****************************************************************************/
+
+static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
+ off_t off, struct fuse_file_info *fi)
+{
+ struct xrdp_inode *xinode;
+ struct dirbuf b;
+ int i;
+
+ (void) fi;
+
+ log_debug("looking for dir with inode=%d", ino);
+
+ if (!xfuse_is_inode_valid(ino))
{
- if (!g_create_dir(g_fuse_root_path))
- {
- LLOGLN(0, ("fuse_init: g_create_dir failed [%s]",
- g_fuse_root_path));
- return 1;
- }
+ log_error("inode %d is not valid", ino);
+ fuse_reply_err(req, EBADF);
+ return;
+ }
+
+ /* does this dir have any entries? */
+ xinode = g_xrdp_fs.inode_table[ino];
+ memset(&b, 0, sizeof(b));
+ if (ino == 1)
+ {
+ xfuse_dirbuf_add(req, &b, ".", 1);
+ xfuse_dirbuf_add(req, &b, "..", 1);
+ }
+ else
+ {
+ xfuse_dirbuf_add(req, &b, ".", xinode->inode);
+ xfuse_dirbuf_add(req, &b, "..", xinode->parent_inode);
}
- g_time = g_time1();
- g_uid = g_getuid();
- g_gid = g_getgid();
- argv[0] = param0;
- argv[1] = g_fuse_root_path;
- argv[2] = 0;
- g_memset(&g_xrdp_ll_oper, 0, sizeof(g_xrdp_ll_oper));
- g_xrdp_ll_oper.lookup = xrdp_ll_lookup;
- g_xrdp_ll_oper.getattr = xrdp_ll_getattr;
- g_xrdp_ll_oper.readdir = xrdp_ll_readdir;
- g_xrdp_ll_oper.open = xrdp_ll_open;
- g_xrdp_ll_oper.read = xrdp_ll_read;
+ for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++)
+ {
+ xinode = g_xrdp_fs.inode_table[i];
+ if (xinode->parent_inode == ino)
+ xfuse_dirbuf_add(req, &b, xinode->name, xinode->inode);
+ }
- g_req_list = list_create();
- g_req_list->auto_free = 1;
+ if (off < b.size)
+ fuse_reply_buf(req, b.p + off, min(b.size - off, size));
+ else
+ fuse_reply_buf(req, NULL, 0);
- return fuse_init_lib(2, argv);
+ free(b.p);
}
-/*****************************************************************************/
-/* returns error */
-int APP_CC
-fuse_deinit(void)
+/**
+ * Create a directory
+ *****************************************************************************/
+
+static void xfuse_cb_mkdir(fuse_req_t req, fuse_ino_t parent,
+ const char *name, mode_t mode)
{
- LLOGLN(0, ("fuse_deinit:"));
- if (g_ch != 0)
+ XRDP_INODE *xinode;
+ struct fuse_entry_param e;
+
+ if ((xinode = xfuse_get_inode_from_pinode_name(parent, name)) != NULL)
{
- LLOGLN(0, ("fuse_deinit: calling fuse_unmount"));
- fuse_session_remove_chan(g_ch);
- fuse_unmount(g_mountpoint, g_ch);
- g_ch = 0;
+ /* dir already exists, just return it */
+ memset(&e, 0, sizeof(struct fuse_entry_param));
+
+ e.ino = xinode->inode;
+ e.attr_timeout = XFUSE_ATTR_TIMEOUT;
+ e.entry_timeout = XFUSE_ENTRY_TIMEOUT;
+ e.attr.st_ino = xinode->inode;
+ e.attr.st_mode = xinode->mode;
+ e.attr.st_nlink = xinode->nlink;
+ e.attr.st_uid = xinode->uid;
+ e.attr.st_gid = xinode->gid;
+ e.attr.st_size = xinode->size;
+ e.attr.st_atime = xinode->atime;
+ e.attr.st_mtime = xinode->mtime;
+ e.attr.st_ctime = xinode->ctime;
+ e.generation = 1;
+
+ fuse_reply_entry(req, &e);
+ return;
}
- if (g_se != 0)
+
+ /* dir does not exist, create it */
+ xfuse_create_dir_or_file(req, parent, name, mode, NULL, S_IFDIR);
+}
+
+/**
+ * Remove specified dir
+ *****************************************************************************/
+
+static void xfuse_cb_rmdir(fuse_req_t req, fuse_ino_t parent,
+ const char *name)
+{
+ XRDP_INODE *xinode;
+
+ log_debug("entered: parent=%d name=%s", parent, name);
+
+ /* is parent inode valid? */
+ if (!xfuse_is_inode_valid(parent))
{
- LLOGLN(0, ("fuse_deinit: calling fuse_session_destroy"));
- fuse_session_destroy(g_se);
- g_se = 0;
+ log_error("inode %d is not valid", parent);
+ fuse_reply_err(req, EBADF);
+ return;
}
- if (g_buffer != 0)
+
+ if ((xinode = xfuse_get_inode_from_pinode_name(parent, name)) == NULL)
{
- g_free(g_buffer);
- g_buffer = 0;
+ log_error("did not find file with pinode=%d name=%s", parent, name);
+ fuse_reply_err(req, EBADF);
+ return;
}
- if (g_req_list != 0)
+
+ log_debug("nentries is %d", xinode->nentries);
+
+ if (xinode->nentries != 0)
{
- list_delete(g_req_list);
- g_req_list = 0;
+ log_debug("cannot rmdir; lookup count is %d", xinode->nentries);
+ fuse_reply_err(req, ENOTEMPTY);
+ return;
}
- return 0;
+ fuse_reply_err(req, 0);
+
}
-/*****************************************************************************/
-int APP_CC
-fuse_file_contents_size(int stream_id, int file_size)
+/**
+ * Create a directory or file
+ *
+ * @param req opaque FUSE object
+ * @param parent parent inode
+ * @param name name of dir or file to create
+ * @param mode creation mode
+ * @param fi for storing file handles
+ * @param type S_IFDIR for dir and S_IFREG for file
+ *****************************************************************************/
+
+static void xfuse_create_dir_or_file(fuse_req_t req, fuse_ino_t parent,
+ const char *name, mode_t mode,
+ struct fuse_file_info *fi, int type)
{
- LLOGLN(10, ("fuse_file_contents_size: file_size %d", file_size));
- return 0;
+ XFUSE_INFO *fip; // LK_TODO use only XFUSE_INFO instead of struct
+ char *cptr;
+ char full_path[1024];
+ tui32 device_id;
+
+ full_path[0] = 0;
+
+ log_debug("entered: type = %s", (type == S_IFDIR) ? "dir" : "file");
+
+ /* name must be valid */
+ if ((name == NULL) || (strlen(name) == 0))
+ {
+ log_error("invalid name");
+ fuse_reply_err(req, EBADF);
+ return;
+ }
+
+ /* is parent inode valid? */
+ if (!xfuse_is_inode_valid(parent))
+ {
+ log_error("inode %d is not valid", parent);
+ fuse_reply_err(req, EBADF);
+ return;
+ }
+
+ device_id = xfuse_get_device_id_for_inode(parent, full_path);
+ strcat(full_path, "/");
+ strcat(full_path, name);
+
+ if (device_id == 0)
+ {
+ /* specified file is a local resource */
+ //XFUSE_HANDLE *fh;
+
+ log_debug("LK_TODO: this is still a TODO");
+ fuse_reply_err(req, EINVAL);
+ return;
+ }
+
+ /* specified file resides on redirected share */
+
+ if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL)
+ {
+ log_error("system out of memory");
+ fuse_reply_err(req, ENOMEM);
+ return;
+ }
+
+ fip->req = req;
+ fip->fi = fi;
+ fip->inode = parent;
+ fip->invoke_fuse = 1;
+ fip->device_id = device_id;
+ fip->mode = type;
+ fip->reply_type = RT_FUSE_REPLY_CREATE;
+ strncpy(fip->name, name, 1024);
+ fip->name[1023] = 0;
+
+ /* LK_TODO need to handle open permissions */
+
+ /* we want path minus 'root node of the share' */
+ if ((cptr = strchr(full_path, '/')) == NULL)
+ {
+ /* get dev_redir to open the remote file */
+ if (dev_redir_file_open((void *) fip, device_id, "\\", O_CREAT, type))
+ {
+ log_error("failed to send dev_redir_open_file() cmd");
+ fuse_reply_err(req, EREMOTEIO);
+ }
+ }
+ else
+ {
+ if (dev_redir_file_open((void *) fip, device_id, cptr, O_CREAT, type))
+ {
+ log_error("failed to send dev_redir_get_dir_listing() cmd");
+ fuse_reply_err(req, EREMOTEIO);
+ }
+ }
}
-/*****************************************************************************/
-int APP_CC
-fuse_file_contents_range(int stream_id, char *data, int data_bytes)
+/**
+ * Open specified file
+ *****************************************************************************/
+
+static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi)
{
- struct req_list_item *rli;
+ XRDP_INODE *xinode;
+ XFUSE_INFO *fip;
+ char *cptr;
+ char full_path[4096];
+ tui32 device_id;
+
+ log_debug("LK_TODO: open_flags=0x%x req=%p fi=%p",
+ fi->flags, req, fi);
+
+ if (!xfuse_is_inode_valid(ino))
+ {
+ log_error("inode %d is not valid", ino);
+ fuse_reply_err(req, EBADF);
+ return;
+ }
- LLOGLN(10, ("fuse_file_contents_range: data_bytes %d", data_bytes));
- rli = (struct req_list_item *)list_get_item(g_req_list, 0);
- if (rli != 0)
+ /* if ino points to a dir, fail the open request */
+ xinode = g_xrdp_fs.inode_table[ino];
+ if (xinode->mode & S_IFDIR)
{
- fuse_reply_buf(rli->req, data, data_bytes);
- list_remove_item(g_req_list, 0);
- if (g_req_list->count > 0)
+ log_debug("reading a dir not allowed!");
+ fuse_reply_err(req, EISDIR);
+ return;
+ }
+
+ device_id = xfuse_get_device_id_for_inode((tui32) ino, full_path);
+ if (device_id)
+ {
+ /* specified file resides on redirected share */
+
+ log_debug("LK_TODO looking for file %s in DeviceId=%d", full_path, device_id);
+
+ if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL)
+ {
+ log_error("system out of memory");
+ fuse_reply_err(req, ENOMEM);
+ return;
+ }
+
+ fip->req = req;
+ fip->inode = ino;
+ fip->invoke_fuse = 1;
+ fip->device_id = device_id;
+ fip->fi = fi;
+ strncpy(fip->name, full_path, 1024);
+ fip->name[1023] = 0;
+ fip->reply_type = RT_FUSE_REPLY_OPEN;
+
+ /* LK_TODO need to handle open permissions */
+
+ /* we want path minus 'root node of the share' */
+ if ((cptr = strchr(full_path, '/')) == NULL)
{
- /* send next request */
- rli = (struct req_list_item *)list_get_item(g_req_list, 0);
- if (rli != 0)
+ /* get dev_redir to open the remote file */
+ if (dev_redir_file_open((void *) fip, device_id, "\\",
+ fi->flags, S_IFREG))
{
- clipboard_request_file_data(rli->stream_id, rli->lindex,
- rli->off, rli->size);
+ log_error("failed to send dev_redir_open_file() cmd");
+ fuse_reply_err(req, EREMOTEIO);
}
- else
+ }
+ else
+ {
+ if (dev_redir_file_open((void *) fip, device_id, cptr,
+ fi->flags, S_IFREG))
{
- LLOGLN(0, ("fuse_file_contents_range: error"));
+ log_error("failed to send dev_redir_get_dir_listing() cmd");
+ fuse_reply_err(req, EREMOTEIO);
}
}
}
else
{
- LLOGLN(0, ("fuse_file_contents_range: error"));
+ /* specified file is a local resource */
+ //XFUSE_HANDLE *fh;
+
+ log_debug("LK_TODO: this is still a TODO");
+ fuse_reply_err(req, EINVAL);
}
- return 0;
}
-#else
+/**
+ *****************************************************************************/
-#include "arch.h"
+static void xfuse_cb_read(fuse_req_t req, fuse_ino_t ino, size_t size,
+ off_t off, struct fuse_file_info *fi)
+{
+ XFUSE_HANDLE *fh;
+ XFUSE_INFO *fusep;
-char g_fuse_root_path[256] = "";
+ log_debug("want_bytes %d bytes at off %d", size, off);
+
+ if (fi->fh == 0)
+ {
+ log_debug("LK_TODO: looks like fi->fh is corrupted");
+ fuse_reply_err(req, EINVAL);
+ return;
+ }
+ fh = (XFUSE_HANDLE *) fi->fh;
+
+ if (fh->DeviceId == 0)
+ {
+ /* target file is in .clipboard dir */
+ log_debug(">>>>>>>>>>>>>>>>> THIS IS STILL A TODO!");
+ return;
+ }
+
+ /* target file is on a remote device */
+
+ if ((fusep = calloc(1, sizeof(XFUSE_INFO))) == NULL)
+ {
+ log_error("system out of memory");
+ fuse_reply_err(req, ENOMEM);
+ return;
+ }
+ fusep->req = req;
+ fusep->inode = ino;
+ fusep->invoke_fuse = 1;
+ fusep->device_id = fh->DeviceId;
+ fusep->fi = fi;
-/*****************************************************************************/
-int APP_CC
-fuse_get_wait_objs(tbus *objs, int *count, int *timeout)
+ dev_redir_file_read(fusep, fh->DeviceId, fh->FileId, size, off);
+ log_debug("exiting");
+}
+
+static void xfuse_cb_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
+ size_t size, off_t off, struct fuse_file_info *fi)
{
- return 0;
+ XFUSE_HANDLE *fh;
+ XFUSE_INFO *fusep;
+
+ log_debug("write %d bytes at off %d", size, off);
+
+ if (fi->fh == 0)
+ {
+ log_debug("LK_TODO: looks like fi->fh is corrupted");
+ fuse_reply_err(req, EINVAL);
+ return;
+ }
+ fh = (XFUSE_HANDLE *) fi->fh;
+
+ if (fh->DeviceId == 0)
+ {
+ /* target file is in .clipboard dir */
+ log_debug(">>>>>>>>>>>>>>>>> THIS IS STILL A TODO!");
+ return;
+ }
+
+ /* target file is on a remote device */
+
+ if ((fusep = calloc(1, sizeof(XFUSE_INFO))) == NULL)
+ {
+ log_error("system out of memory");
+ fuse_reply_err(req, ENOMEM);
+ return;
+ }
+ fusep->req = req;
+ fusep->inode = ino;
+ fusep->invoke_fuse = 1;
+ fusep->device_id = fh->DeviceId;
+ fusep->fi = fi;
+
+ dev_redir_file_write(fusep, fh->DeviceId, fh->FileId, buf, size, off);
+ log_debug("exiting");
}
-/*****************************************************************************/
-int APP_CC
-fuse_check_wait_objs(void)
+static void xfuse_cb_create(fuse_req_t req, fuse_ino_t parent,
+ const char *name, mode_t mode,
+ struct fuse_file_info *fi)
{
- return 0;
+ xfuse_create_dir_or_file(req, parent, name, mode, fi, S_IFREG);
}
-/*****************************************************************************/
-int APP_CC
-fuse_init(void)
+// LK_TODO may not need to implement the following funcs
+
+#if 0
+static void xfuse_cb_statfs(fuse_req_t req, fuse_ino_t ino)
{
- return 0;
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered");
+ fuse_reply_err(req, ENOMEM);
}
-/*****************************************************************************/
-int APP_CC
-fuse_deinit(void)
+static void xfuse_cb_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+ const char *value, size_t size, int flags)
{
- return 0;
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered");
+ fuse_reply_err(req, ENOMEM);
+
}
-/*****************************************************************************/
-int APP_CC
-fuse_clear_clip_dir(void)
+static void xfuse_cb_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
+ size_t size)
{
- return 0;
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered");
+ fuse_reply_err(req, ENOMEM);
+
}
-/*****************************************************************************/
-int APP_CC
-fuse_add_clip_dir_item(char *filename, int flags, int size, int lindex)
+static void xfuse_cb_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
{
- return 0;
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered");
+ fuse_reply_err(req, ENOMEM);
+
}
-/*****************************************************************************/
-int APP_CC
-fuse_file_contents_size(int stream_id, int file_size)
+static void xfuse_cb_access(fuse_req_t req, fuse_ino_t ino, int mask)
{
- return 0;
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered");
+ fuse_reply_err(req, ENOMEM);
+
}
-/*****************************************************************************/
-int APP_CC
-fuse_file_contents_range(int stream_id, char *data, int data_bytes)
+static void xfuse_cb_getlk(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi, struct flock *lock)
{
- return 0;
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered");
+ fuse_reply_err(req, ENOMEM);
+
+}
+
+static void xfuse_cb_setlk(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi, struct flock *lock,
+ int sleep)
+{
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered");
+ fuse_reply_err(req, ENOMEM);
+
+}
+
+static void xfuse_cb_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
+ struct fuse_file_info *fi, unsigned flags,
+ const void *in_buf, size_t in_bufsz,
+ size_t out_bufsz)
+{
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered");
+ fuse_reply_err(req, ENOMEM);
+
}
+static void xfuse_cb_poll(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi,
+ struct fuse_pollhandle *ph)
+{
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered");
+ fuse_reply_err(req, ENOMEM);
+
+}
#endif
+
+static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
+ int to_set, struct fuse_file_info *fi)
+{
+ XRDP_INODE *xinode;
+
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered to_set=0x%x", to_set);
+
+ if (!xfuse_is_inode_valid(ino))
+ {
+ log_error("inode %d is not valid", ino);
+ fuse_reply_err(req, EBADF);
+ return;
+ }
+
+ xinode = g_xrdp_fs.inode_table[ino];
+
+ if (to_set & FUSE_SET_ATTR_MODE)
+ {
+ xinode->mode = attr->st_mode;
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: FUSE_SET_ATTR_MODE");
+
+ }
+
+ if (to_set & FUSE_SET_ATTR_UID)
+ {
+ xinode->uid = attr->st_uid;
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: FUSE_SET_ATTR_UID");
+ }
+
+ if (to_set & FUSE_SET_ATTR_GID)
+ {
+ xinode->gid = attr->st_gid;
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: FUSE_SET_ATTR_GID");
+ }
+
+ if (to_set & FUSE_SET_ATTR_SIZE)
+ {
+ log_debug("previous file size: %d", attr->st_size);
+ xinode->size = attr->st_size;
+ log_debug("returning file size: %d", xinode->size);
+ }
+
+ if (to_set & FUSE_SET_ATTR_ATIME)
+ {
+ xinode->atime = attr->st_atime;
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: FUSE_SET_ATTR_ATIME");
+ }
+
+ if (to_set & FUSE_SET_ATTR_MTIME)
+ {
+ xinode->mtime = attr->st_mtime;
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: FUSE_SET_ATTR_MTIME");
+ }
+
+ if (to_set & FUSE_SET_ATTR_ATIME_NOW)
+ {
+ xinode->atime = attr->st_atime;
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: FUSE_SET_ATTR_ATIME_NOW");
+ }
+
+ if (to_set & FUSE_SET_ATTR_MTIME_NOW)
+ {
+ xinode->mtime = attr->st_mtime;
+ log_debug(">>>>>>>>>>>>>>>> LK_TODO: FUSE_SET_ATTR_MTIME_NOW");
+ }
+
+ fuse_reply_attr(req, attr, 1.0); /* LK_TODO just faking for now */
+}
+
+#endif /* end else #ifndef XRDP_FUSE */
diff --git a/sesman/chansrv/chansrv_fuse.h b/sesman/chansrv/chansrv_fuse.h
index 0ccde368..34c4ba7e 100644
--- a/sesman/chansrv/chansrv_fuse.h
+++ b/sesman/chansrv/chansrv_fuse.h
@@ -1,23 +1,60 @@
+/**
+ * xrdp: A Remote Desktop Protocol server.
+ *
+ * Copyright (C) Laxmikant Rashinkar 2013
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
-#if !defined(CHANSRV_FUSE_H)
-#define CHANSRV_FUSE_H
+#ifndef _CHANSRV_FUSE_H
+#define _CHANSRV_FUSE_H
-int APP_CC
-fuse_clear_clip_dir(void);
-int APP_CC
-fuse_add_clip_dir_item(char *filename, int flags, int size, int lindex);
-int APP_CC
-fuse_get_wait_objs(tbus *objs, int *count, int *timeout);
-int APP_CC
-fuse_check_wait_objs(void);
-int APP_CC
-fuse_init(void);
-int APP_CC
-fuse_deinit(void);
+/* a file or dir entry in the xrdp file system */
+struct xrdp_inode
+{
+ tui32 parent_inode; /* Parent serial number. */
+ tui32 inode; /* File serial number. */
+ tui32 mode; /* File mode. */
+ tui32 nlink; /* symbolic link count. */
+ tui32 nentries; /* number of entries in a dir */
+ tui32 uid; /* User ID of the file's owner. */
+ tui32 gid; /* Group ID of the file's group. */
+ size_t size; /* Size of file, in bytes. */
+ time_t atime; /* Time of last access. */
+ time_t mtime; /* Time of last modification. */
+ time_t ctime; /* Time of last status change. */
+ char name[256]; /* Dir or filename */
+ tui32 device_id; /* for file system redirection */
+ char is_synced; /* dir struct has been read from */
+ /* remote device, done just once */
+};
+typedef struct xrdp_inode XRDP_INODE; // LK_TODO use this instead of using struct xrdp_inode
-int APP_CC
-fuse_file_contents_size(int stream_id, int file_size);
-int APP_CC
-fuse_file_contents_range(int stream_id, char *data, int data_bytes);
+int xfuse_init();
+int xfuse_deinit();
+int xfuse_check_wait_objs(void);
+int xfuse_get_wait_objs(tbus *objs, int *count, int *timeout);
+int xfuse_create_share(tui32 share_id, char *dirname);
+
+int xfuse_clear_clip_dir(void);
+int xfuse_file_contents_range(int stream_id, char *data, int data_bytes);
+int xfuse_file_contents_size(int stream_id, int file_size);
+int xfuse_add_clip_dir_item(char *filename, int flags, int size, int lindex);
+
+/* functions that are inovked from devredir */
+void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode);
+void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus);
+void xfuse_devredir_cb_open_file(void *vp, tui32 DeviceId, tui32 FileId);
+void xfuse_devredir_cb_read_file(void *vp, char *buf, size_t length);
#endif
diff --git a/sesman/chansrv/clipboard.c b/sesman/chansrv/clipboard.c
index d277d474..27c45fff 100644
--- a/sesman/chansrv/clipboard.c
+++ b/sesman/chansrv/clipboard.c
@@ -320,7 +320,7 @@ clipboard_init(void)
return 0;
}
- fuse_init();
+ xfuse_init();
xcommon_init();
g_incr_max_req_size = XMaxRequestSize(g_display) * 4 - 24;
g_memset(&g_clip_c2s, 0, sizeof(g_clip_c2s));
@@ -464,7 +464,7 @@ clipboard_deinit(void)
g_wnd = 0;
}
- fuse_deinit();
+ xfuse_deinit();
g_free(g_clip_c2s.data);
g_clip_c2s.data = 0;
@@ -968,7 +968,7 @@ clipboard_process_format_announce(struct stream *s, int clip_msg_status,
LLOGLN(10, ("clipboard_process_format_announce %d", clip_msg_len));
clipboard_send_format_ack();
- fuse_clear_clip_dir();
+ xfuse_clear_clip_dir();
g_clip_c2s.converted = 0;
desc[0] = 0;
diff --git a/sesman/chansrv/clipboard_file.c b/sesman/chansrv/clipboard_file.c
index 121d96a7..1942999d 100644
--- a/sesman/chansrv/clipboard_file.c
+++ b/sesman/chansrv/clipboard_file.c
@@ -534,13 +534,13 @@ clipboard_process_file_response(struct stream *s, int clip_msg_status,
in_uint32_le(s, file_size);
LLOGLN(10, ("clipboard_process_file_response: streamId %d "
"file_size %d", streamId, file_size));
- fuse_file_contents_size(streamId, file_size);
+ xfuse_file_contents_size(streamId, file_size);
}
else if (g_file_request_sent_type == CB_FILECONTENTS_RANGE)
{
g_file_request_sent_type = 0;
in_uint32_le(s, streamId);
- fuse_file_contents_range(streamId, s->p, clip_msg_len - 4);
+ xfuse_file_contents_range(streamId, s->p, clip_msg_len - 4);
}
else
{
@@ -604,7 +604,7 @@ clipboard_c2s_in_files(struct stream *s, char *file_list)
LLOGLN(0, ("clipboard_c2s_in_files: error cItems %d too big", cItems));
return 1;
}
- fuse_clear_clip_dir();
+ xfuse_clear_clip_dir();
LLOGLN(10, ("clipboard_c2s_in_files: cItems %d", cItems));
cfd = (struct clip_file_desc *)
g_malloc(sizeof(struct clip_file_desc), 0);
@@ -620,7 +620,7 @@ clipboard_c2s_in_files(struct stream *s, char *file_list)
"supported [%s]", cfd->cFileName));
continue;
}
- fuse_add_clip_dir_item(cfd->cFileName, 0, cfd->fileSizeLow, lindex);
+ xfuse_add_clip_dir_item(cfd->cFileName, 0, cfd->fileSizeLow, lindex);
g_strcpy(ptr, "file://");
ptr += 7;
diff --git a/sesman/chansrv/devredir.c b/sesman/chansrv/devredir.c
index e6407211..d9296356 100644
--- a/sesman/chansrv/devredir.c
+++ b/sesman/chansrv/devredir.c
@@ -1,7 +1,9 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
- * Copyright (C) Jay Sorg 2009-2012
+ * xrdp device redirection - only drive redirection is currently supported
+ *
+ * Copyright (C) Laxmikant Rashinkar 2013
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,16 +18,85 @@
* limitations under the License.
*/
-#include "arch.h"
-#include "parse.h"
-#include "os_calls.h"
+/*
+ * TODO
+ * o there is one difference in the protocol initialization
+ * sequence upon reconnection: if a user is already logged on,
+ * send a SERVER_USER_LOGGED_ON msg as per section 3.3.5.1.5
+ *
+ * o how to announce / delete a drive after a connection has been
+ * established?
+ *
+ * o need to support multiple drives;
+ * o for multiple drives, we cannot have global device_id's and file_id's
+ * and all functions must be reenterant
+ * o replace printf's with log_xxx
+ * o mark local funcs with static
+ */
+
+#include "devredir.h"
+/* globals */
extern int g_rdpdr_chan_id; /* in chansrv.c */
+int g_is_printer_redir_supported = 0;
+int g_is_port_redir_supported = 0;
+int g_is_drive_redir_supported = 0;
+int g_is_smartcard_redir_supported = 0;
+int g_drive_redir_version = 1;
+char g_preferred_dos_name_for_filesystem[9];
+char g_full_name_for_filesystem[1024];
+tui32 g_completion_id = 1;
+
+tui32 g_clientID; /* unique client ID - announced by client */
+tui32 g_device_id; /* unique device ID - announced by client */
+tui16 g_client_rdp_version; /* returned by client */
+IRP *g_irp_head = NULL;
+struct stream *g_input_stream = NULL;
+
+void xfuse_devredir_cb_write_file(void *vp, char *buf, size_t length);
/*****************************************************************************/
int APP_CC
dev_redir_init(void)
{
+ struct stream *s;
+ int bytes;
+ int fd;
+
+ union _u
+ {
+ tui32 clientID;
+ char buf[4];
+ } u;
+
+ /* get a random number that will act as a unique clientID */
+ if ((fd = open("/dev/urandom", O_RDONLY)))
+ {
+ read(fd, u.buf, 4);
+ close(fd);
+ }
+ else
+ {
+ /* /dev/urandom did not work - use address of struct s */
+ tui64 u64 = (tui64) &s;
+ u.clientID = (tui32) u64;
+ }
+
+ /* setup stream */
+ stream_new(s, 1024);
+
+ /* initiate drive redirection protocol by sending Server Announce Req */
+ stream_wr_u16_le(s, RDPDR_CTYP_CORE);
+ stream_wr_u16_le(s, PAKID_CORE_SERVER_ANNOUNCE);
+ stream_wr_u16_le(s, 0x0001); /* server major ver */
+ stream_wr_u16_le(s, 0x000C); /* server minor ver - pretend 2 b Win 7 */
+ stream_wr_u32_le(s, u.clientID); /* unique ClientID */
+
+ /* send data to client */
+ bytes = stream_len(s);
+ send_channel_data(g_rdpdr_chan_id, s->data, bytes);
+
+ stream_free(s);
return 0;
}
@@ -36,12 +107,127 @@ dev_redir_deinit(void)
return 0;
}
-/*****************************************************************************/
+/**
+ * @brief process incoming data
+ *
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+
int APP_CC
dev_redir_data_in(struct stream *s, int chan_id, int chan_flags, int length,
int total_length)
{
- return 0;
+ struct stream *ls;
+ tui16 comp_type;
+ tui16 pktID;
+ tui16 minor_ver;
+ int rv = 0;
+
+ /*
+ * handle packet fragmentation
+ */
+ if ((chan_flags & 3) == 3)
+ {
+ /* all data contained in one packet */
+ ls = s;
+ }
+ else
+ {
+ /* is this is the first packet? */
+ if (chan_flags & 1)
+ stream_new(g_input_stream, total_length);
+
+ stream_copyin(g_input_stream, s->p, length);
+
+ /* in last packet, chan_flags & 0x02 will be true */
+ if ((chan_flags & 2) == 0)
+ return 0;
+
+ g_input_stream->p = g_input_stream->data;
+ ls = g_input_stream;
+ }
+
+ /* read header from incoming data */
+ stream_rd_u16_le(ls, comp_type);
+ stream_rd_u16_le(ls, pktID);
+
+ /* for now we only handle core type, not printers */
+ if (comp_type != RDPDR_CTYP_CORE)
+ {
+ log_error("invalid component type in response; expected 0x%x got 0x%x",
+ RDPDR_CTYP_CORE, comp_type);
+
+ rv = -1;
+ goto done;
+ }
+
+ /* figure out what kind of response we have gotten */
+ switch (pktID)
+ {
+ case PAKID_CORE_CLIENTID_CONFIRM:
+ stream_seek(ls, 2); /* major version, we ignore it */
+ stream_rd_u16_le(ls, minor_ver);
+ stream_rd_u32_le(ls, g_clientID);
+
+ g_client_rdp_version = minor_ver;
+
+ switch (minor_ver)
+ {
+ case RDP_CLIENT_50:
+ break;
+
+ case RDP_CLIENT_51:
+ break;
+
+ case RDP_CLIENT_52:
+ break;
+
+ case RDP_CLIENT_60_61:
+ break;
+ }
+ // LK_TODO dev_redir_send_server_clientID_confirm();
+ break;
+
+ case PAKID_CORE_CLIENT_NAME:
+ /* client is telling us its computer name; do we even care? */
+
+ /* let client know loggin was successful */
+ dev_redir_send_server_user_logged_on();
+ usleep(1000 * 100);
+
+ /* let client know our capabilites */
+ dev_redir_send_server_core_cap_req();
+
+ /* send confirm clientID */
+ dev_redir_send_server_clientID_confirm();
+ break;
+
+ case PAKID_CORE_CLIENT_CAPABILITY:
+ dev_redir_proc_client_core_cap_resp(ls);
+ break;
+
+ case PAKID_CORE_DEVICELIST_ANNOUNCE:
+ dev_redir_proc_client_devlist_announce_req(ls);
+ break;
+
+ case PAKID_CORE_DEVICE_IOCOMPLETION:
+ dev_redir_proc_device_iocompletion(ls);
+ break;
+
+ default:
+ log_error("got unknown response 0x%x", pktID);
+ break;
+ }
+
+done:
+
+ if (g_input_stream)
+ {
+ stream_free(g_input_stream);
+ g_input_stream = NULL;
+ }
+
+ return rv;
}
/*****************************************************************************/
@@ -57,3 +243,1088 @@ dev_redir_check_wait_objs(void)
{
return 0;
}
+
+/**
+ * @brief let client know our capabilities
+ *****************************************************************************/
+
+void dev_redir_send_server_core_cap_req()
+{
+ struct stream *s;
+ int bytes;
+
+ stream_new(s, 1024);
+
+ /* setup header */
+ stream_wr_u16_le(s, RDPDR_CTYP_CORE);
+ stream_wr_u16_le(s, PAKID_CORE_SERVER_CAPABILITY);
+
+ stream_wr_u16_le(s, 5); /* num of caps we are sending */
+ stream_wr_u16_le(s, 0x0000); /* padding */
+
+ /* setup general capability */
+ stream_wr_u16_le(s, CAP_GENERAL_TYPE); /* CapabilityType */
+ stream_wr_u16_le(s, 44); /* CapabilityLength - len of this */
+ /* CAPABILITY_SET in bytes, inc */
+ /* the header */
+ stream_wr_u32_le(s, 2); /* Version */
+ stream_wr_u32_le(s, 2); /* O.S type */
+ stream_wr_u32_le(s, 0); /* O.S version */
+ stream_wr_u16_le(s, 1); /* protocol major version */
+ stream_wr_u16_le(s, g_client_rdp_version); /* protocol minor version */
+ stream_wr_u32_le(s, 0xffff); /* I/O code 1 */
+ stream_wr_u32_le(s, 0); /* I/O code 2 */
+ stream_wr_u32_le(s, 7); /* Extended PDU */
+ stream_wr_u32_le(s, 0); /* extra flags 1 */
+ stream_wr_u32_le(s, 0); /* extra flags 2 */
+ stream_wr_u32_le(s, 2); /* special type device cap */
+
+ /* setup printer capability */
+ stream_wr_u16_le(s, CAP_PRINTER_TYPE);
+ stream_wr_u16_le(s, 8);
+ stream_wr_u32_le(s, 1);
+
+ /* setup serial port capability */
+ stream_wr_u16_le(s, CAP_PORT_TYPE);
+ stream_wr_u16_le(s, 8);
+ stream_wr_u32_le(s, 1);
+
+ /* setup file system capability */
+ stream_wr_u16_le(s, CAP_DRIVE_TYPE); /* CapabilityType */
+ stream_wr_u16_le(s, 8); /* CapabilityLength - len of this */
+ /* CAPABILITY_SET in bytes, inc */
+ /* the header */
+ stream_wr_u32_le(s, 2); /* Version */
+
+ /* setup smart card capability */
+ stream_wr_u16_le(s, CAP_SMARTCARD_TYPE);
+ stream_wr_u16_le(s, 8);
+ stream_wr_u32_le(s, 1);
+
+ /* send to client */
+ bytes = stream_len(s);
+ send_channel_data(g_rdpdr_chan_id, s->data, bytes);
+
+ stream_free(s);
+}
+
+void dev_redir_send_server_clientID_confirm()
+{
+ struct stream *s;
+ int bytes;
+
+ stream_new(s, 1024);
+
+ /* setup stream */
+ stream_wr_u16_le(s, RDPDR_CTYP_CORE);
+ stream_wr_u16_le(s, PAKID_CORE_CLIENTID_CONFIRM);
+ stream_wr_u16_le(s, 0x0001);
+ stream_wr_u16_le(s, g_client_rdp_version);
+ stream_wr_u32_le(s, g_clientID);
+
+ /* send to client */
+ bytes = stream_len(s);
+ send_channel_data(g_rdpdr_chan_id, s->data, bytes);
+
+ stream_free(s);
+}
+
+void dev_redir_send_server_user_logged_on()
+{
+ struct stream *s;
+ int bytes;
+
+ stream_new(s, 1024);
+
+ /* setup stream */
+ stream_wr_u16_le(s, RDPDR_CTYP_CORE);
+ stream_wr_u16_le(s, PAKID_CORE_USER_LOGGEDON);
+
+ /* send to client */
+ bytes = stream_len(s);
+ send_channel_data(g_rdpdr_chan_id, s->data, bytes);
+
+ stream_free(s);
+}
+
+void dev_redir_send_server_device_announce_resp(tui32 device_id)
+{
+ struct stream *s;
+ int bytes;
+
+ stream_new(s, 1024);
+
+ /* setup stream */
+ stream_wr_u16_le(s, RDPDR_CTYP_CORE);
+ stream_wr_u16_le(s, PAKID_CORE_DEVICE_REPLY);
+ stream_wr_u32_le(s, device_id);
+ stream_wr_u32_le(s, 0); /* ResultCode */
+
+ /* send to client */
+ bytes = stream_len(s);
+ send_channel_data(g_rdpdr_chan_id, s->data, bytes);
+
+ stream_free(s);
+}
+
+/**
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+
+int dev_redir_send_drive_create_request(tui32 device_id, char *path,
+ tui32 DesiredAccess,
+ tui32 CreateOptions,
+ tui32 CreateDisposition,
+ tui32 completion_id)
+{
+ struct stream *s;
+ int bytes;
+ int len;
+
+ log_debug("LK_TODO: DesiredAccess=0x%x CreateDisposition=0x%x CreateOptions=0x%x",
+ DesiredAccess, CreateDisposition, CreateOptions);
+
+ /* to store path as unicode */
+ len = strlen(path) * 2 + 2;
+
+ stream_new(s, 1024 + len);
+
+ dev_redir_insert_dev_io_req_header(s,
+ device_id,
+ 0,
+ completion_id,
+ IRP_MJ_CREATE,
+ 0);
+
+ stream_wr_u32_le(s, DesiredAccess); /* DesiredAccess */
+ stream_wr_u32_le(s, 0); /* AllocationSize high unused */
+ stream_wr_u32_le(s, 0); /* AllocationSize low unused */
+ stream_wr_u32_le(s, 0); /* FileAttributes */
+ stream_wr_u32_le(s, 0); /* SharedAccess */
+ stream_wr_u32_le(s, CreateDisposition); /* CreateDisposition */
+ stream_wr_u32_le(s, CreateOptions); /* CreateOptions */
+ stream_wr_u32_le(s, len); /* PathLength */
+ devredir_cvt_to_unicode(s->p, path); /* path in unicode */
+ stream_seek(s, len);
+
+ /* send to client */
+ bytes = stream_len(s);
+ send_channel_data(g_rdpdr_chan_id, s->data, bytes);
+
+ stream_free(s);
+ return 0;
+}
+
+/**
+ * Close a request previously created by dev_redir_send_drive_create_request()
+ *****************************************************************************/
+
+int dev_redir_send_drive_close_request(tui16 Component, tui16 PacketId,
+ tui32 DeviceId,
+ tui32 FileId,
+ tui32 CompletionId,
+ tui32 MajorFunction,
+ tui32 MinorFunc,
+ int pad_len)
+{
+ struct stream *s;
+ int bytes;
+
+ stream_new(s, 1024);
+
+ dev_redir_insert_dev_io_req_header(s, DeviceId, FileId, CompletionId,
+ MajorFunction, MinorFunc);
+
+ if (pad_len)
+ stream_seek(s, pad_len);
+
+ /* send to client */
+ bytes = stream_len(s);
+ send_channel_data(g_rdpdr_chan_id, s->data, bytes);
+
+ stream_free(s);
+ return 0;
+}
+
+/**
+ * @brief ask client to enumerate directory
+ *
+ * Server Drive Query Directory Request
+ * DR_DRIVE_QUERY_DIRECTORY_REQ
+ *
+ *****************************************************************************/
+// LK_TODO Path needs to be Unicode
+void dev_redir_send_drive_dir_request(IRP *irp, tui32 device_id,
+ tui32 InitialQuery, char *Path)
+{
+ struct stream *s;
+ int bytes;
+ char upath[4096]; // LK_TODO need to malloc this
+ int path_len = 0;
+
+ /* during Initial Query, Path cannot be NULL */
+ if (InitialQuery)
+ {
+ if (Path == NULL)
+ return;
+
+ path_len = strlen(Path) * 2 + 2;
+ devredir_cvt_to_unicode(upath, Path);
+ }
+
+ stream_new(s, 1024 + path_len);
+
+ irp->completion_type = CID_DIRECTORY_CONTROL;
+ dev_redir_insert_dev_io_req_header(s,
+ device_id,
+ irp->FileId,
+ irp->completion_id,
+ IRP_MJ_DIRECTORY_CONTROL,
+ IRP_MN_QUERY_DIRECTORY);
+
+ stream_wr_u32_le(s, FileDirectoryInformation); /* FsInformationClass */
+ stream_wr_u8(s, InitialQuery); /* InitialQuery */
+
+ if (!InitialQuery)
+ {
+ stream_wr_u32_le(s, 0); /* PathLength */
+ stream_seek(s, 23);
+ }
+ else
+ {
+ stream_wr_u32_le(s, path_len); /* PathLength */
+ stream_seek(s, 23); /* Padding */
+ stream_wr_string(s, upath, path_len);
+ }
+
+ /* send to client */
+ bytes = stream_len(s);
+ send_channel_data(g_rdpdr_chan_id, s->data, bytes);
+
+ stream_free(s);
+}
+
+/******************************************************************************
+** process data received from client **
+******************************************************************************/
+
+/**
+ * @brief process client's repsonse to our core_capability_req() msg
+ *
+ * @param s stream containing client's response
+ *****************************************************************************/
+void dev_redir_proc_client_core_cap_resp(struct stream *s)
+{
+ int i;
+ tui16 num_caps;
+ tui16 cap_type;
+ tui16 cap_len;
+ tui32 cap_version;
+
+ stream_rd_u16_le(s, num_caps);
+ stream_seek(s, 2); /* padding */
+
+ for (i = 0; i < num_caps; i++)
+ {
+ stream_rd_u16_le(s, cap_type);
+ stream_rd_u16_le(s, cap_len);
+ stream_rd_u32_le(s, cap_version);
+
+ /* remove header length and version */
+ cap_len -= 8;
+
+ switch (cap_type)
+ {
+ case CAP_GENERAL_TYPE:
+ log_debug("got CAP_GENERAL_TYPE");
+ stream_seek(s, cap_len);
+ break;
+
+ case CAP_PRINTER_TYPE:
+ log_debug("got CAP_PRINTER_TYPE");
+ g_is_printer_redir_supported = 1;
+ stream_seek(s, cap_len);
+ break;
+
+ case CAP_PORT_TYPE:
+ log_debug("got CAP_PORT_TYPE");
+ g_is_port_redir_supported = 1;
+ stream_seek(s, cap_len);
+ break;
+
+ case CAP_DRIVE_TYPE:
+ log_debug("got CAP_DRIVE_TYPE");
+ g_is_drive_redir_supported = 1;
+ if (cap_version == 2)
+ g_drive_redir_version = 2;
+ stream_seek(s, cap_len);
+ break;
+
+ case CAP_SMARTCARD_TYPE:
+ log_debug("got CAP_SMARTCARD_TYPE");
+ g_is_smartcard_redir_supported = 1;
+ stream_seek(s, cap_len);
+ break;
+ }
+ }
+}
+
+void dev_redir_proc_client_devlist_announce_req(struct stream *s)
+{
+ int i;
+ int j;
+ tui32 device_count;
+ tui32 device_type;
+ tui32 device_data_len;
+
+ /* get number of devices being announced */
+ stream_rd_u32_le(s, device_count);
+
+ log_debug("num of devices announced: %d", device_count);
+
+ for (i = 0; i < device_count; i++)
+ {
+ stream_rd_u32_le(s, device_type);
+ stream_rd_u32_le(s, g_device_id); /* LK_TODO need to support */
+ /* multiple drives */
+
+ switch (device_type)
+ {
+ case RDPDR_DTYP_FILESYSTEM:
+ /* get preferred DOS name */
+ for (j = 0; j < 8; j++)
+ {
+ g_preferred_dos_name_for_filesystem[j] = *s->p++;
+ }
+
+ /* DOS names that are 8 chars long are not NULL terminated */
+ g_preferred_dos_name_for_filesystem[8] = 0;
+
+ /* LK_TODO need to check for invalid chars in DOS name */
+ /* see section 2.2.1.3 of the protocol documentation */
+
+ /* get device data len */
+ stream_rd_u32_le(s, device_data_len);
+ if (device_data_len)
+ {
+ stream_rd_string(g_full_name_for_filesystem, s,
+ device_data_len);
+ }
+
+ log_debug("device_type=FILE_SYSTEM device_id=0x%x dosname=%s "
+ "device_data_len=%d full_name=%s", g_device_id,
+ g_preferred_dos_name_for_filesystem,
+ device_data_len, g_full_name_for_filesystem);
+
+ dev_redir_send_server_device_announce_resp(g_device_id);
+
+ /* create share directory in xrdp file system; */
+ /* think of this as the mount point for this share */
+ xfuse_create_share(g_device_id,
+ g_preferred_dos_name_for_filesystem);
+ break;
+
+ /* we don't yet support these devices */
+ case RDPDR_DTYP_SERIAL:
+ case RDPDR_DTYP_PARALLEL:
+ case RDPDR_DTYP_PRINT:
+ case RDPDR_DTYP_SMARTCARD:
+ log_debug("unsupported dev: 0x%x", device_type);
+ break;
+ }
+ }
+}
+
+void dev_redir_proc_device_iocompletion(struct stream *s)
+{
+ FUSE_DATA *fuse_data = NULL;
+ IRP *irp = NULL;
+
+ tui32 DeviceId;
+ tui32 CompletionId;
+ tui32 IoStatus;
+ tui32 Length;
+
+ stream_rd_u32_le(s, DeviceId);
+ stream_rd_u32_le(s, CompletionId);
+ stream_rd_u32_le(s, IoStatus);
+
+ /* LK_TODO need to check for IoStatus */
+
+ log_debug("entered: IoStatus=0x%x CompletionId=%d",
+ IoStatus, CompletionId);
+
+ if ((irp = dev_redir_irp_find(CompletionId)) == NULL)
+ {
+ log_error("IRP with completion ID %d not found", CompletionId);
+ return;
+ }
+
+ switch (irp->completion_type)
+ {
+ case CID_CREATE_DIR_REQ:
+ if (IoStatus != NT_STATUS_SUCCESS)
+ {
+ /* we were trying to create a request to enumerate a dir */
+ /* that does not exist; let FUSE know */
+ fuse_data = dev_redir_fuse_data_dequeue(irp);
+ if (fuse_data)
+ {
+ xfuse_devredir_cb_enum_dir_done(fuse_data->data_ptr,
+ IoStatus);
+ free(fuse_data);
+ }
+ return;
+ }
+
+ stream_rd_u32_le(s, irp->FileId);
+ log_debug("got CID_CREATE_DIR_REQ IoStatus=0x%x FileId=%d",
+ IoStatus, irp->FileId);
+ dev_redir_send_drive_dir_request(irp, DeviceId, 1, irp->pathname);
+ break;
+
+ case CID_CREATE_OPEN_REQ:
+ stream_rd_u32_le(s, irp->FileId);
+ log_debug("got CID_CREATE_OPEN_REQ IoStatus=0x%x FileId=%d",
+ IoStatus, irp->FileId);
+ fuse_data = dev_redir_fuse_data_dequeue(irp);
+ xfuse_devredir_cb_open_file(fuse_data->data_ptr,
+ DeviceId, irp->FileId);
+ break;
+
+ case CID_READ:
+ stream_rd_u32_le(s, Length);
+ fuse_data = dev_redir_fuse_data_dequeue(irp);
+ xfuse_devredir_cb_read_file(fuse_data->data_ptr, s->p, Length);
+ break;
+
+ case CID_WRITE:
+ stream_rd_u32_le(s, Length);
+ fuse_data = dev_redir_fuse_data_dequeue(irp);
+ xfuse_devredir_cb_write_file(fuse_data->data_ptr, s->p, Length);
+ break;
+
+ case CID_CLOSE:
+ log_debug("got CID_CLOSE");
+ dev_redir_irp_delete(irp);
+ break;
+
+ case CID_DIRECTORY_CONTROL:
+ log_debug("got CID_DIRECTORY_CONTROL");
+
+ dev_redir_proc_query_dir_response(irp, s, DeviceId,
+ CompletionId, IoStatus);
+ break;
+
+ default:
+ log_error("got unknown CompletionID: DeviceId=0x%x "
+ "CompletionId=0x%x IoStatus=0x%x",
+ DeviceId, CompletionId, IoStatus);
+ break;
+ }
+
+ if (fuse_data)
+ free(fuse_data);
+
+ log_debug("exiting");
+}
+
+void dev_redir_proc_query_dir_response(IRP *irp,
+ struct stream *s_in,
+ tui32 DeviceId,
+ tui32 CompletionId,
+ tui32 IoStatus)
+{
+ FUSE_DATA *fuse_data = NULL;
+ XRDP_INODE *xinode = NULL;
+
+ tui32 Length;
+ tui32 NextEntryOffset;
+ tui64 CreationTime;
+ tui64 LastAccessTime;
+ tui64 LastWriteTime;
+ tui64 ChangeTime;
+ tui64 EndOfFile;
+ tui32 FileAttributes;
+ tui32 FileNameLength;
+ tui32 status;
+
+ char filename[256];
+ int i = 0;
+
+ stream_rd_u32_le(s_in, Length);
+
+ if ((IoStatus == NT_STATUS_UNSUCCESSFUL) ||
+ (IoStatus == STATUS_NO_MORE_FILES))
+ {
+ status = (IoStatus == STATUS_NO_MORE_FILES) ? 0 : IoStatus;
+ fuse_data = dev_redir_fuse_data_dequeue(irp);
+ xfuse_devredir_cb_enum_dir_done(fuse_data->data_ptr, status);
+ irp->completion_type = CID_CLOSE;
+ dev_redir_send_drive_close_request(RDPDR_CTYP_CORE,
+ PAKID_CORE_DEVICE_IOREQUEST,
+ DeviceId,
+ irp->FileId,
+ irp->completion_id,
+ IRP_MJ_CLOSE, 0, 32);
+ free(fuse_data);
+ return;
+ }
+
+ /* TODO check status for errors */
+
+ /* process FILE_DIRECTORY_INFORMATION structures */
+ while (i < Length)
+ {
+ log_debug("processing FILE_DIRECTORY_INFORMATION structs");
+
+ stream_rd_u32_le(s_in, NextEntryOffset);
+ stream_seek(s_in, 4); /* FileIndex */
+ stream_rd_u64_le(s_in, CreationTime);
+ stream_rd_u64_le(s_in, LastAccessTime);
+ stream_rd_u64_le(s_in, LastWriteTime);
+ stream_rd_u64_le(s_in, ChangeTime);
+ stream_rd_u64_le(s_in, EndOfFile);
+ stream_seek(s_in, 8); /* AllocationSize */
+ stream_rd_u32_le(s_in, FileAttributes);
+ stream_rd_u32_le(s_in, FileNameLength);
+
+ devredir_cvt_from_unicode_len(filename, s_in->p, FileNameLength);
+
+ i += 64 + FileNameLength;
+
+ log_debug("NextEntryOffset: 0x%x", NextEntryOffset);
+ log_debug("CreationTime: 0x%llx", CreationTime);
+ log_debug("LastAccessTime: 0x%llx", LastAccessTime);
+ log_debug("LastWriteTime: 0x%llx", LastWriteTime);
+ log_debug("ChangeTime: 0x%llx", ChangeTime);
+ log_debug("EndOfFile: %lld", EndOfFile);
+ log_debug("FileAttributes: 0x%x", FileAttributes);
+ log_debug("FileNameLength: 0x%x", FileNameLength);
+ log_debug("FileName: %s", filename);
+
+ if ((xinode = calloc(1, sizeof(struct xrdp_inode))) == NULL)
+ {
+ log_error("system out of memory");
+ fuse_data = dev_redir_fuse_data_peek(irp);
+ xfuse_devredir_cb_enum_dir(fuse_data->data_ptr, NULL);
+ return;
+ }
+
+ strcpy(xinode->name, filename);
+ xinode->size = (size_t) EndOfFile;
+ xinode->mode = WINDOWS_TO_LINUX_FILE_PERM(FileAttributes);
+ xinode->atime = WINDOWS_TO_LINUX_TIME(LastAccessTime);
+ xinode->mtime = WINDOWS_TO_LINUX_TIME(LastWriteTime);
+ xinode->ctime = WINDOWS_TO_LINUX_TIME(CreationTime);
+
+ /* add this entry to xrdp file system */
+ fuse_data = dev_redir_fuse_data_peek(irp);
+ xfuse_devredir_cb_enum_dir(fuse_data->data_ptr, xinode);
+ }
+
+ dev_redir_send_drive_dir_request(irp, DeviceId, 0, NULL);
+}
+
+/**
+ * FUSE calls this function whenever it wants us to enumerate a dir
+ *
+ * @param fusep opaque data struct that we just pass back to FUSE when done
+ * @param device_id device_id of the redirected share
+ * @param path the dir path to enumerate
+ *
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+
+int dev_redir_get_dir_listing(void *fusep, tui32 device_id, char *path)
+{
+ tui32 DesiredAccess;
+ tui32 CreateOptions;
+ tui32 CreateDisposition;
+ int rval;
+ IRP *irp;
+
+ if ((irp = dev_redir_irp_new()) == NULL)
+ return -1;
+
+ irp->completion_id = g_completion_id++;
+ irp->completion_type = CID_CREATE_DIR_REQ;
+ irp->device_id = device_id;
+ strcpy(irp->pathname, path);
+ dev_redir_fuse_data_enqueue(irp, fusep);
+
+ DesiredAccess = DA_FILE_READ_DATA | DA_SYNCHRONIZE;
+ CreateOptions = CO_FILE_DIRECTORY_FILE | CO_FILE_SYNCHRONOUS_IO_NONALERT;
+ CreateDisposition = CD_FILE_OPEN;
+ rval = dev_redir_send_drive_create_request(device_id, path,
+ DesiredAccess, CreateOptions,
+ CreateDisposition,
+ irp->completion_id);
+
+ log_debug("looking for device_id=%d path=%s", device_id, path);
+
+ /* when we get a respone to dev_redir_send_drive_create_request(), we */
+ /* call dev_redir_send_drive_dir_request(), which needs the following */
+ /* at the end of the path argument */
+
+ if (dev_redir_string_ends_with(irp->pathname, '\\'))
+ strcat(irp->pathname, "*");
+ else
+ strcat(irp->pathname, "\\*");
+
+ return rval;
+}
+
+int dev_redir_file_open(void *fusep, tui32 device_id, char *path,
+ int mode, int type)
+{
+ tui32 DesiredAccess;
+ tui32 CreateOptions;
+ tui32 CreateDisposition;
+ int rval;
+ IRP *irp;
+
+ log_debug("device_id=%d path=%s mode=0x%x", device_id, path, mode);
+ log_debug("O_RDONLY=0x%x O_RDWR=0x%x O_CREAT=0x%x", O_RDONLY, O_RDWR, O_CREAT);
+
+ if ((irp = dev_redir_irp_new()) == NULL)
+ return -1;
+
+ irp->completion_id = g_completion_id++;
+ irp->completion_type = CID_CREATE_OPEN_REQ;
+ irp->device_id = device_id;
+ strcpy(irp->pathname, path);
+ dev_redir_fuse_data_enqueue(irp, fusep);
+
+ if (mode & O_CREAT)
+ {
+ log_debug("LK_TODO: open file in O_CREAT");
+ DesiredAccess = DA_FILE_READ_DATA | DA_FILE_WRITE_DATA | DA_SYNCHRONIZE;
+
+ if (type == S_IFDIR)
+ {
+ log_debug("creating dir");
+ CreateOptions = CO_FILE_DIRECTORY_FILE | CO_FILE_SYNCHRONOUS_IO_NONALERT;
+ }
+ else
+ {
+ log_debug("creating file");
+ CreateOptions = CO_FILE_SYNCHRONOUS_IO_NONALERT;
+ }
+
+ CreateDisposition = CD_FILE_CREATE;
+ }
+ else //if (mode & O_RDWR)
+ {
+ log_debug("LK_TODO: open file in O_RDWR");
+ DesiredAccess = DA_FILE_READ_DATA | DA_FILE_WRITE_DATA | DA_SYNCHRONIZE;
+ CreateOptions = CO_FILE_SYNCHRONOUS_IO_NONALERT;
+ CreateDisposition = CD_FILE_OPEN; // WAS 1
+ }
+#if 0
+ else
+ {
+ log_debug("LK_TODO: open file in O_RDONLY");
+ DesiredAccess = DA_FILE_READ_DATA | DA_SYNCHRONIZE;
+ CreateOptions = CO_FILE_SYNCHRONOUS_IO_NONALERT;
+ CreateDisposition = CD_FILE_OPEN;
+ }
+#endif
+ rval = dev_redir_send_drive_create_request(device_id, path,
+ DesiredAccess, CreateOptions,
+ CreateDisposition,
+ irp->completion_id);
+
+ return rval;
+}
+
+/**
+ * Read data from previously opened file
+ *
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+
+int dev_redir_file_read(void *fusep, tui32 DeviceId, tui32 FileId,
+ tui32 Length, tui64 Offset)
+{
+ struct stream *s;
+ IRP *irp;
+ int bytes;
+
+ stream_new(s, 1024);
+
+ if ((irp = dev_redir_irp_find_by_fileid(FileId)) == NULL)
+ {
+ log_error("no IRP found with FileId = %d", FileId);
+ xfuse_devredir_cb_read_file(fusep, NULL, 0);
+ return -1;
+ }
+
+ irp->completion_type = CID_READ;
+ dev_redir_fuse_data_enqueue(irp, fusep);
+ dev_redir_insert_dev_io_req_header(s,
+ DeviceId,
+ FileId,
+ irp->completion_id,
+ IRP_MJ_READ,
+ 0);
+
+ stream_wr_u32_le(s, Length);
+ stream_wr_u64_le(s, Offset);
+ stream_seek(s, 20);
+
+ /* send to client */
+ bytes = stream_len(s);
+ send_channel_data(g_rdpdr_chan_id, s->data, bytes);
+ stream_free(s);
+
+ return 0;
+}
+
+int dev_redir_file_write(void *fusep, tui32 DeviceId, tui32 FileId,
+ const char *buf, tui32 Length, tui64 Offset)
+{
+ struct stream *s;
+ IRP *irp;
+ int bytes;
+
+ stream_new(s, 1024 + Length);
+
+ if ((irp = dev_redir_irp_find_by_fileid(FileId)) == NULL)
+ {
+ log_error("no IRP found with FileId = %d", FileId);
+ xfuse_devredir_cb_write_file(fusep, NULL, 0);
+ return -1;
+ }
+
+ irp->completion_type = CID_WRITE;
+ dev_redir_fuse_data_enqueue(irp, fusep);
+ dev_redir_insert_dev_io_req_header(s,
+ DeviceId,
+ FileId,
+ irp->completion_id,
+ IRP_MJ_WRITE,
+ 0);
+
+ stream_wr_u32_le(s, Length);
+ stream_wr_u64_le(s, Offset);
+ stream_seek(s, 20); /* padding */
+
+ /* now insert real data */
+ stream_copyin(s, buf, Length);
+
+ /* send to client */
+ bytes = stream_len(s);
+ send_channel_data(g_rdpdr_chan_id, s->data, bytes);
+ stream_free(s);
+
+ return 0;
+}
+
+/******************************************************************************
+** FIFO for FUSE_DATA **
+******************************************************************************/
+
+/**
+ * Return FUSE_DATA at the head of the queue without removing it
+ *
+ * @return FUSE_DATA on success, or NULL on failure
+ *****************************************************************************/
+
+void *dev_redir_fuse_data_peek(IRP *irp)
+{
+ return irp->fd_head;
+}
+
+/**
+ * Return oldest FUSE_DATA from queue
+ *
+ * @return FUSE_DATA on success, NULL on failure
+ *****************************************************************************/
+
+void *dev_redir_fuse_data_dequeue(IRP *irp)
+{
+ FUSE_DATA *head;
+
+ if ((irp == NULL) || (irp->fd_head == NULL))
+ return NULL;
+
+ if (irp->fd_head->next == NULL)
+ {
+ /* only one element in queue */
+ head = irp->fd_head;
+ irp->fd_head = NULL;
+ irp->fd_tail = NULL;
+ return head;
+ }
+
+ /* more than one element in queue */
+ head = irp->fd_head;
+ irp->fd_head = head->next;
+
+ return head;
+}
+
+/**
+ * Insert specified FUSE_DATA at the end of our queue
+ *
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+
+int dev_redir_fuse_data_enqueue(IRP *irp, void *vp)
+{
+ FUSE_DATA *fd;
+ FUSE_DATA *tail;
+
+ if (irp == NULL)
+ return -1;
+
+ if ((fd = calloc(1, sizeof(FUSE_DATA))) == NULL)
+ return -1;
+
+ fd->data_ptr = vp;
+ fd->next = NULL;
+
+ if (irp->fd_tail == NULL)
+ {
+ /* queue is empty, insert at head */
+ irp->fd_head = fd;
+ irp->fd_tail = fd;
+ return 0;
+ }
+
+ /* queue is not empty, insert at tail end */
+ tail = irp->fd_tail;
+ tail->next = fd;
+ irp->fd_tail = fd;
+ return 0;
+}
+
+/******************************************************************************
+** IRP stuff **
+******************************************************************************/
+
+/**
+ * Create a new IRP and append to linked list
+ *
+ * @return new IRP or NULL on error
+ *****************************************************************************/
+
+IRP * dev_redir_irp_new()
+{
+ IRP *irp;
+ IRP *irp_last;
+
+ /* create new IRP */
+ if ((irp = calloc(1, sizeof(IRP))) == NULL)
+ {
+ log_error("system out of memory!");
+ return NULL;
+ }
+
+ /* insert at end of linked list */
+ if ((irp_last = dev_redir_irp_get_last()) == NULL)
+ {
+ /* list is empty, this is the first entry */
+ g_irp_head = irp;
+ }
+ else
+ {
+ irp_last->next = irp;
+ irp->prev = irp_last;
+ }
+
+ return irp;
+}
+
+/**
+ * Delete specified IRP from linked list
+ *
+ * @return 0 on success, -1 on failure
+ *****************************************************************************/
+
+int dev_redir_irp_delete(IRP *irp)
+{
+ IRP *lirp = g_irp_head;
+
+ if ((irp == NULL) || (lirp == NULL))
+ return -1;
+
+ dev_redir_irp_dump(); // LK_TODO
+
+ while (lirp)
+ {
+ if (lirp == irp)
+ break;
+
+ lirp = lirp->next;
+ }
+
+ if (lirp == NULL)
+ return -1; /* did not find specified irp */
+
+ if (lirp->prev == NULL)
+ {
+ /* we are at head of linked list */
+ if (lirp->next == NULL)
+ {
+ /* only one element in list */
+ free(lirp);
+ g_irp_head = NULL;
+ dev_redir_irp_dump(); // LK_TODO
+ return 0;
+ }
+
+ lirp->next->prev = NULL;
+ g_irp_head = lirp->next;
+ free(lirp);
+ }
+ else if (lirp->next == NULL)
+ {
+ /* we are at tail of linked list */
+ lirp->prev->next = NULL;
+ free(lirp);
+ }
+ else
+ {
+ /* we are in between */
+ lirp->prev->next = lirp->next;
+ lirp->next->prev = lirp->prev;
+ free(lirp);
+ }
+
+ dev_redir_irp_dump(); // LK_TODO
+
+ return 0;
+}
+
+/**
+ * Return IRP containing specified completion_id
+ *****************************************************************************/
+
+IRP *dev_redir_irp_find(tui32 completion_id)
+{
+ IRP *irp = g_irp_head;
+
+ while (irp)
+ {
+ if (irp->completion_id == completion_id)
+ return irp;
+
+ irp = irp->next;
+ }
+
+ return NULL;
+}
+
+IRP * dev_redir_irp_find_by_fileid(tui32 FileId)
+{
+ IRP *irp = g_irp_head;
+
+ while (irp)
+ {
+ if (irp->FileId == FileId)
+ return irp;
+
+ irp = irp->next;
+ }
+
+ return NULL;
+}
+
+/**
+ * Return last IRP in linked list
+ *****************************************************************************/
+
+IRP * dev_redir_irp_get_last()
+{
+ IRP *irp = g_irp_head;
+
+ while (irp)
+ {
+ if (irp->next == NULL)
+ break;
+
+ irp = irp->next;
+ }
+
+ return irp;
+}
+
+void dev_redir_irp_dump()
+{
+ IRP *irp = g_irp_head;
+
+ log_debug("------- dumping IRPs --------");
+ while (irp)
+ {
+ log_debug(" completion_id=%d\tcompletion_type=%d\tFileId=%d",
+ irp->completion_id, irp->completion_type, irp->FileId);
+
+ irp = irp->next;
+ }
+ log_debug("------- dumping IRPs done ---");
+}
+
+/******************************************************************************
+** miscellaneous stuff **
+******************************************************************************/
+
+void dev_redir_insert_dev_io_req_header(struct stream *s,
+ tui32 DeviceId,
+ tui32 FileId,
+ tui32 CompletionId,
+ tui32 MajorFunction,
+ tui32 MinorFunction)
+{
+ /* setup DR_DEVICE_IOREQUEST header */
+ stream_wr_u16_le(s, RDPDR_CTYP_CORE);
+ stream_wr_u16_le(s, PAKID_CORE_DEVICE_IOREQUEST);
+ stream_wr_u32_le(s, DeviceId);
+ stream_wr_u32_le(s, FileId);
+ stream_wr_u32_le(s, CompletionId);
+ stream_wr_u32_le(s, MajorFunction);
+ stream_wr_u32_le(s, MinorFunction);
+}
+
+void devredir_cvt_to_unicode(char *unicode, char *path)
+{
+ int len = strlen(path);
+ int i;
+ int j = 0;
+
+ for (i = 0; i < len; i++)
+ {
+ unicode[j++] = path[i];
+ unicode[j++] = 0x00;
+ }
+ unicode[j++] = 0x00;
+ unicode[j++] = 0x00;
+}
+
+void devredir_cvt_from_unicode_len(char *path, char *unicode, int len)
+{
+ int i;
+ int j;
+
+ for (i = 0, j = 0; i < len; i += 2)
+ {
+ path[j++] = unicode[i];
+ }
+ path[j] = 0;
+}
+
+int dev_redir_string_ends_with(char *string, char c)
+{
+ int len;
+
+ len = strlen(string);
+ return (string[len - 1] == c) ? 1 : 0;
+}
+
+void dev_redir_insert_rdpdr_header(struct stream *s, tui16 Component,
+ tui16 PacketId)
+{
+ stream_wr_u16_le(s, Component);
+ stream_wr_u16_le(s, PacketId);
+}
diff --git a/sesman/chansrv/devredir.h b/sesman/chansrv/devredir.h
index 3ec08a51..84ab3a86 100644
--- a/sesman/chansrv/devredir.h
+++ b/sesman/chansrv/devredir.h
@@ -1,7 +1,9 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
- * Copyright (C) Jay Sorg 2009-2012
+ * xrdp device redirection - we mainly use it for drive redirection
+ *
+ * Copyright (C) Laxmikant Rashinkar 2013
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,19 +21,372 @@
#if !defined(DEVREDIR_H)
#define DEVREDIR_H
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <string.h>
+
#include "arch.h"
#include "parse.h"
+#include "os_calls.h"
+#include "log.h"
+#include "chansrv_fuse.h"
+
+typedef struct fuse_data FUSE_DATA;
+struct fuse_data
+{
+ void *data_ptr;
+ FUSE_DATA *next;
+};
+
+/* An I/O Resource Packet to track dev_dir I/O calls */
+
+typedef struct irp IRP;
+
+struct irp
+{
+ tui32 completion_id; /* unique number */
+ char completion_type; /* describes I/O type */
+ tui32 FileId; /* RDP client provided unique number */
+ //void *fusep; /* opaque FUSE info */
+ char pathname[256]; /* absolute pathname */
+ tui32 device_id; /* identifies remote device */
+ FUSE_DATA *fd_head; /* point to first FUSE opaque object */
+ FUSE_DATA *fd_tail; /* point to last FUSE opaque object */
+ IRP *next; /* point to next IRP */
+ IRP *prev; /* point to previous IRP */
+};
+
+void *dev_redir_fuse_data_peek(IRP *irp);
+void *dev_redir_fuse_data_dequeue(IRP *irp);
+int dev_redir_fuse_data_enqueue(IRP *irp, void *vp);
+
+IRP * dev_redir_irp_new();
+IRP * dev_redir_irp_find(tui32 completion_id);
+IRP * dev_redir_irp_find_by_fileid(tui32 FileId);
+IRP * dev_redir_irp_get_last();
+int dev_redir_irp_delete(IRP *irp);
+void dev_redir_irp_dump();
+
+int APP_CC dev_redir_init(void);
+int APP_CC dev_redir_deinit(void);
+
+int APP_CC dev_redir_data_in(struct stream* s, int chan_id, int chan_flags,
+ int length, int total_length);
+
+int APP_CC dev_redir_get_wait_objs(tbus* objs, int* count, int* timeout);
+int APP_CC dev_redir_check_wait_objs(void);
+
+void dev_redir_send_server_core_cap_req();
+void dev_redir_send_server_clientID_confirm();
+void dev_redir_send_server_user_logged_on();
+void dev_redir_send_server_device_announce_resp(tui32 device_id);
+
+void dev_redir_send_drive_dir_request(IRP *irp, tui32 device_id,
+ tui32 InitialQuery, char *Path);
+
+int dev_redir_send_drive_create_request(tui32 device_id, char *path,
+ tui32 DesiredAccess,
+ tui32 CreateOptions,
+ tui32 CreateDisposition,
+ tui32 completion_id);
+
+int dev_redir_send_drive_close_request(tui16 Component, tui16 PacketId,
+ tui32 DeviceId,
+ tui32 FileId,
+ tui32 CompletionId,
+ tui32 MajorFunction,
+ tui32 MinorFunc,
+ int pad_len);
+
+void dev_redir_proc_client_devlist_announce_req(struct stream *s);
+void dev_redir_proc_client_core_cap_resp(struct stream *s);
+void dev_redir_proc_device_iocompletion(struct stream *s);
+
+void dev_redir_proc_query_dir_response(IRP *irp,
+ struct stream *s,
+ tui32 DeviceId,
+ tui32 CompletionId,
+ tui32 IoStatus);
+
+/* misc stuff */
+void dev_redir_insert_dev_io_req_header(struct stream *s,
+ tui32 DeviceId,
+ tui32 FileId,
+ tui32 CompletionId,
+ tui32 MajorFunction,
+ tui32 MinorFunction);
+
+void devredir_cvt_to_unicode(char *unicode, char *path);
+void devredir_cvt_from_unicode_len(char *path, char *unicode, int len);
+int dev_redir_string_ends_with(char *string, char c);
+
+void dev_redir_insert_rdpdr_header(struct stream *s, tui16 Component,
+ tui16 PacketId);
+
+/* called from FUSE module */
+int dev_redir_get_dir_listing(void *fusep, tui32 device_id, char *path);
+
+int dev_redir_file_open(void *fusep, tui32 device_id, char *path,
+ int mode, int type);
+
+int dev_redir_file_read(void *fusep, tui32 device_id, tui32 FileId,
+ tui32 Length, tui64 Offset);
+
+/* module based logging */
+#define LOG_ERROR 0
+#define LOG_INFO 1
+#define LOG_DEBUG 2
+
+#ifndef LOG_LEVEL
+#define LOG_LEVEL LOG_ERROR
+#endif
+
+#define log_error(_params...) \
+{ \
+ g_write("[%10.10u]: DEV_REDIR %s: %d : ERROR: ", \
+ g_time3(), __func__, __LINE__); \
+ g_writeln (_params); \
+}
+
+#define log_info(_params...) \
+{ \
+ if (LOG_INFO <= LOG_LEVEL) \
+ { \
+ g_write("[%10.10u]: DEV_REDIR %s: %d : ", \
+ g_time3(), __func__, __LINE__); \
+ g_writeln (_params); \
+ } \
+}
+
+#define log_debug(_params...) \
+{ \
+ if (LOG_DEBUG <= LOG_LEVEL) \
+ { \
+ g_write("[%10.10u]: DEV_REDIR %s: %d : ", \
+ g_time3(), __func__, __LINE__); \
+ g_writeln (_params); \
+ } \
+}
+
+int send_channel_data(int chan_id, char *data, int size);
+
+/*
+ * RDPDR_HEADER definitions
+ */
+
+/* device redirector core component; most of the packets in this protocol */
+/* are sent under this component ID */
+#define RDPDR_CTYP_CORE 0x4472
+
+/* printing component. the packets that use this ID are typically about */
+/* printer cache management and identifying XPS printers */
+#define RDPDR_CTYP_PRN 0x5052
+
+/* Server Announce Request, as specified in section 2.2.2.2 */
+#define PAKID_CORE_SERVER_ANNOUNCE 0x496E
+
+/* Client Announce Reply and Server Client ID Confirm, as specified in */
+/* sections 2.2.2.3 and 2.2.2.6. */
+#define PAKID_CORE_CLIENTID_CONFIRM 0x4343
+
+/* Client Name Request, as specified in section 2.2.2.4 */
+#define PAKID_CORE_CLIENT_NAME 0x434E
+
+/* Client Device List Announce Request, as specified in section 2.2.2.9 */
+#define PAKID_CORE_DEVICELIST_ANNOUNCE 0x4441
+
+/* Server Device Announce Response, as specified in section 2.2.2.1 */
+#define PAKID_CORE_DEVICE_REPLY 0x6472
+
+/* Device I/O Request, as specified in section 2.2.1.4 */
+#define PAKID_CORE_DEVICE_IOREQUEST 0x4952
+
+/* Device I/O Response, as specified in section 2.2.1.5 */
+#define PAKID_CORE_DEVICE_IOCOMPLETION 0x4943
+
+/* Server Core Capability Request, as specified in section 2.2.2.7 */
+#define PAKID_CORE_SERVER_CAPABILITY 0x5350
+
+/* Client Core Capability Response, as specified in section 2.2.2.8 */
+#define PAKID_CORE_CLIENT_CAPABILITY 0x4350
+
+/* Client Drive Device List Remove, as specified in section 2.2.3.2 */
+#define PAKID_CORE_DEVICELIST_REMOVE 0x444D
+
+/* Add Printer Cachedata, as specified in [MS-RDPEPC] section 2.2.2.3 */
+#define PAKID_PRN_CACHE_DATA 0x5043
+
+/* Server User Logged On, as specified in section 2.2.2.5 */
+#define PAKID_CORE_USER_LOGGEDON 0x554C
+
+/* Server Printer Set XPS Mode, as specified in [MS-RDPEPC] section 2.2.2.2 */
+#define PAKID_PRN_USING_XPS 0x5543
+
+/*
+ * Capability header definitions
+ */
+
+#define CAP_GENERAL_TYPE 0x0001 /* General cap set - GENERAL_CAPS_SET */
+#define CAP_PRINTER_TYPE 0x0002 /* Print cap set - PRINTER_CAPS_SET */
+#define CAP_PORT_TYPE 0x0003 /* Port cap set - PORT_CAPS_SET */
+#define CAP_DRIVE_TYPE 0x0004 /* Drive cap set - DRIVE_CAPS_SET */
+#define CAP_SMARTCARD_TYPE 0x0005 /* Smart card cap set - SMARTCARD_CAPS_SET */
+
+/* client minor versions */
+#define RDP_CLIENT_50 0x0002
+#define RDP_CLIENT_51 0x0005
+#define RDP_CLIENT_52 0x000a
+#define RDP_CLIENT_60_61 0x000c
+
+/* used in device announce list */
+#define RDPDR_DTYP_SERIAL 0x0001
+#define RDPDR_DTYP_PARALLEL 0x0002
+#define RDPDR_DTYP_PRINT 0x0004
+#define RDPDR_DTYP_FILESYSTEM 0x0008
+#define RDPDR_DTYP_SMARTCARD 0x0020
+
+/*
+ * DesiredAccess Mask [MS-SMB2] section 2.2.13.1.1
+ */
+
+#define DA_FILE_READ_DATA 0x00000001
+#define DA_FILE_WRITE_DATA 0x00000002
+#define DA_FILE_APPEND_DATA 0x00000004
+#define DA_FILE_READ_EA 0x00000008 /* rd extended attributes */
+#define DA_FILE_WRITE_EA 0x00000010 /* wr extended attributes */
+#define DA_FILE_EXECUTE 0x00000020
+#define DA_FILE_READ_ATTRIBUTES 0x00000080
+#define DA_FILE_WRITE_ATTRIBUTES 0x00000100
+#define DA_DELETE 0x00010000
+#define DA_READ_CONTROL 0x00020000 /* rd security descriptor */
+#define DA_WRITE_DAC 0x00040000
+#define DA_WRITE_OWNER 0x00080000
+#define DA_SYNCHRONIZE 0x00100000
+#define DA_ACCESS_SYSTEM_SECURITY 0x01000000
+#define DA_MAXIMUM_ALLOWED 0x02000000
+#define DA_GENERIC_ALL 0x10000000
+#define DA_GENERIC_EXECUTE 0x20000000
+#define DA_GENERIC_WRITE 0x40000000
+#define DA_GENERIC_READ 0x80000000
+
+/*
+ * CreateOptions Mask [MS-SMB2] section 2.2.13 SMB2 CREATE Request
+ */
+
+#define CO_FILE_DIRECTORY_FILE 0x00000001
+#define CO_FILE_WRITE_THROUGH 0x00000002
+#define CO_FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
+
+/*
+ * CreateDispositions Mask [MS-SMB2] section 2.2.13
+ */
+
+#define CD_FILE_SUPERSEDE 0x00000000
+#define CD_FILE_OPEN 0x00000001
+#define CD_FILE_CREATE 0x00000002
+#define CD_FILE_OPEN_IF 0x00000003
+#define CD_FILE_OVERWRITE 0x00000004
+#define CD_FILE_OVERWRITE_IF 0x00000005
+
+/*
+ * Device I/O Request MajorFunction definitions
+ */
+
+#define IRP_MJ_CREATE 0x00000000
+#define IRP_MJ_CLOSE 0x00000002
+#define IRP_MJ_READ 0x00000003
+#define IRP_MJ_WRITE 0x00000004
+#define IRP_MJ_DEVICE_CONTROL 0x0000000E
+#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0000000A
+#define IRP_MJ_SET_VOLUME_INFORMATION 0x0000000B
+#define IRP_MJ_QUERY_INFORMATION 0x00000005
+#define IRP_MJ_SET_INFORMATION 0x00000006
+#define IRP_MJ_DIRECTORY_CONTROL 0x0000000C
+#define IRP_MJ_LOCK_CONTROL 0x00000011
+
+/*
+ * Device I/O Request MinorFunction definitions
+ *
+ * Only valid when MajorFunction code = IRP_MJ_DIRECTORY_CONTROL
+ */
+
+#define IRP_MN_QUERY_DIRECTORY 0x00000001
+#define IRP_MN_NOTIFY_CHANGE_DIRECTORY 0x00000002
+
+/*
+ * NTSTATUS codes (used by IoStatus)
+ */
+
+#define NT_STATUS_SUCCESS 0x00000000
+#define NT_STATUS_UNSUCCESSFUL 0xC0000001
+
+/*
+ * CompletionID types, used in IRPs to indicate I/O operation
+ */
+
+enum
+{
+ CID_CREATE_DIR_REQ = 1,
+ CID_CREATE_OPEN_REQ,
+ CID_READ,
+ CID_WRITE,
+ CID_DIRECTORY_CONTROL,
+ CID_CLOSE
+};
+
+#if 0
+#define CID_CLOSE 0x0002
+#define CID_READ 0x0003
+#define CID_WRITE 0x0004
+#define CID_DEVICE_CONTROL 0x0005
+#define CID_QUERY_VOLUME_INFORMATION 0x0006
+#define CID_SET_VOLUME_INFORMATION 0x0007
+#define CID_QUERY_INFORMATION 0x0008
+#define CID_SET_INFORMATION 0x0009
+#define CID_DIRECTORY_CONTROL 0x000a
+#define CID_LOCK_CONTROL 0x000b
+#endif
+
+/*
+ * constants for drive dir query
+ */
+
+/* Basic information about a file or directory. Basic information is */
+/* defined as the file's name, time stamp, and size, or its attributes */
+#define FileDirectoryInformation 0x00000001
+
+/* Full information about a file or directory. Full information is defined */
+/* as all the basic information, plus extended attribute size. */
+#define FileFullDirectoryInformation 0x00000002
+
+/* Basic information plus extended attribute size and short name */
+/* about a file or directory. */
+#define FileBothDirectoryInformation 0x00000003
+
+/* Detailed information on the names of files in a directory. */
+#define FileNamesInformation 0x0000000C
+
+/*
+ * NTSTATUS Codes of interest to us
+ */
+
+/* No more files were found which match the file specification */
+#define STATUS_NO_MORE_FILES 0x80000006
+
+/* Windows file attributes */
+#define W_FILE_ATTRIBUTE_DIRECTORY 0x00000010
+#define W_FILE_ATTRIBUTE_READONLY 0x00000001
+
+#define WINDOWS_TO_LINUX_FILE_PERM(_a) \
+ (((_a) & W_FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR | 0100 : S_IFREG) |\
+ (((_a) & W_FILE_ATTRIBUTE_READONLY) ? 0444 : 0644)
-int APP_CC
-dev_redir_init(void);
-int APP_CC
-dev_redir_deinit(void);
-int APP_CC
-dev_redir_data_in(struct stream* s, int chan_id, int chan_flags, int length,
- int total_length);
-int APP_CC
-dev_redir_get_wait_objs(tbus* objs, int* count, int* timeout);
-int APP_CC
-dev_redir_check_wait_objs(void);
+/* winodws time starts on Jan 1, 1601 */
+/* Linux time starts on Jan 1, 1970 */
+#define EPOCH_DIFF 11644473600LL
+#define WINDOWS_TO_LINUX_TIME(_t) ((_t) / 10000000) - EPOCH_DIFF;
#endif