summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaxmikant Rashinkar <lk@maya32.(none)>2013-03-18 19:43:20 -0700
committerLaxmikant Rashinkar <lk@maya32.(none)>2013-03-18 19:43:20 -0700
commit5acc54cd1d1f84a6907102e3d133eb687b0eadad (patch)
treeaca8e47a2d20d70acc62ad63ff97437436b92588
parent297fdaf1c6615a856aaaa16072eb8538f39faf19 (diff)
downloadxrdp-proprietary-5acc54cd1d1f84a6907102e3d133eb687b0eadad.tar.gz
xrdp-proprietary-5acc54cd1d1f84a6907102e3d133eb687b0eadad.zip
o added support for deleteing files and directories
-rw-r--r--sesman/chansrv/chansrv_fuse.c309
-rw-r--r--sesman/chansrv/chansrv_fuse.h7
-rw-r--r--sesman/chansrv/devredir.c143
-rw-r--r--sesman/chansrv/devredir.h53
4 files changed, 444 insertions, 68 deletions
diff --git a/sesman/chansrv/chansrv_fuse.c b/sesman/chansrv/chansrv_fuse.c
index c55fd57f..9b16c9a3 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) Laxmikant Rashinkar 2013
+ * Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,14 +31,13 @@
* 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
+ * o cat >> file is not working
*
*/
@@ -103,7 +102,7 @@ int xfuse_add_clip_dir_item(char *filename, int flags, int size, int lindex) {}
#define LOG_ERROR 0
#define LOG_INFO 1
#define LOG_DEBUG 2
-#define LOG_LEVEL LOG_ERROR
+#define LOG_LEVEL LOG_DEBUG
#define log_error(_params...) \
{ \
@@ -161,6 +160,7 @@ struct xfuse_info
tui32 device_id;
int reply_type;
int mode;
+ int type;
};
typedef struct xfuse_info XFUSE_INFO;
@@ -186,7 +186,7 @@ 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_init_lib(struct fuse_args *args);
static int xfuse_is_inode_valid(int ino);
// LK_TODO
@@ -209,7 +209,7 @@ static struct xrdp_inode * xfuse_create_file_in_xrdp_fs(tui32 device_id,
static int xfuse_does_file_exist(int parent, char *name);
-/* forward declarations for calls we make into dev_redir */
+/* forward declarations for calls we make into devredir */
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,
@@ -241,6 +241,13 @@ static void xfuse_cb_mkdir(fuse_req_t req, fuse_ino_t parent,
static void xfuse_cb_rmdir(fuse_req_t req, fuse_ino_t parent,
const char *name);
+static void xfuse_cb_unlink(fuse_req_t req, fuse_ino_t parent,
+ const char *name);
+
+/* this is not a callback, but it is used by the above two functions */
+static void xfuse_remove_dir_or_file(fuse_req_t req, fuse_ino_t parent,
+ const char *name, int type);
+
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);
@@ -248,6 +255,9 @@ static void xfuse_create_dir_or_file(fuse_req_t req, fuse_ino_t parent,
static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
+static void xfuse_cb_flush(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);
@@ -306,8 +316,8 @@ static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int xfuse_init()
{
- char *param0 = "xrdp-chansrv";
- char *argv[4];
+ struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
+ char opt[1024];
/* if already inited, just return */
if (g_xfuse_inited)
@@ -345,8 +355,10 @@ int xfuse_init()
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.rmdir = xfuse_cb_rmdir;
+ g_xfuse_ops.unlink = xfuse_cb_unlink;
g_xfuse_ops.open = xfuse_cb_open;
+ g_xfuse_ops.flush = xfuse_cb_flush;
g_xfuse_ops.read = xfuse_cb_read;
g_xfuse_ops.write = xfuse_cb_write;
g_xfuse_ops.create = xfuse_cb_create;
@@ -365,11 +377,14 @@ int xfuse_init()
g_xfuse_ops.getxattr = xfuse_cb_getxattr;
#endif
- argv[0] = param0;
- argv[1] = g_fuse_root_path;
- argv[2] = 0;
+ fuse_opt_add_arg(&args, "xrdp-chansrv");
+ fuse_opt_add_arg(&args, g_fuse_root_path);
+#if 0
+ sprintf(opt, "-o uid=%d,gid=%d", g_getuid(), g_getgid());
+ fuse_opt_add_arg(&args, opt);
+#endif
- if (xfuse_init_lib(2, argv))
+ if (xfuse_init_lib(&args))
{
xfuse_deinit();
return -1;
@@ -607,35 +622,41 @@ int xfuse_file_contents_size(int stream_id, int file_size)
* @return 0 on success, -1 on failure
*****************************************************************************/
-static int xfuse_init_lib(int argc, char **argv)
+static int xfuse_init_lib(struct fuse_args *args)
{
- struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+ // LK_TODO
+ {
+ int i;
- if (fuse_parse_cmdline(&args, &g_mount_point, 0, 0) < 0)
+ for (i = 0; i < args->argc; i++)
+ log_debug("+++++++++++++ argc=%d argv=%s", i, args->argv[i]);
+ }
+
+ if (fuse_parse_cmdline(args, &g_mount_point, 0, 0) < 0)
{
log_error("fuse_parse_cmdline() failed");
- fuse_opt_free_args(&args);
+ fuse_opt_free_args(args);
return -1;
}
- if ((g_ch = fuse_mount(g_mount_point, &args)) == 0)
+ if ((g_ch = fuse_mount(g_mount_point, args)) == 0)
{
log_error("fuse_mount() failed");
- fuse_opt_free_args(&args);
+ fuse_opt_free_args(args);
return -1;
}
- g_se = fuse_lowlevel_new(&args, &g_xfuse_ops, sizeof(g_xfuse_ops), 0);
+ 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);
+ fuse_opt_free_args(args);
return -1;
}
- fuse_opt_free_args(&args);
+ fuse_opt_free_args(args);
fuse_session_add_chan(g_se, g_ch);
g_bufsize = fuse_chan_bufsize(g_ch);
@@ -851,7 +872,9 @@ static void xfuse_dump_fs()
for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++)
{
- xinode = g_xrdp_fs.inode_table[i];
+ if ((xinode = g_xrdp_fs.inode_table[i]) == NULL)
+ continue;
+
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);
@@ -957,7 +980,8 @@ static struct xrdp_inode * xfuse_get_inode_from_pinode_name(tui32 pinode,
for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++)
{
- xinode = g_xrdp_fs.inode_table[i];
+ if ((xinode = g_xrdp_fs.inode_table[i]) == NULL)
+ continue;
/* match parent inode */
if (xinode->parent_inode != pinode)
@@ -1054,7 +1078,8 @@ static int xfuse_does_file_exist(int parent, char *name)
for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++)
{
- xinode = g_xrdp_fs.inode_table[i];
+ if ((xinode = g_xrdp_fs.inode_table[i]) == NULL)
+ continue;
if ((xinode->parent_inode == parent) &&
(strcmp(xinode->name, name) == 0))
@@ -1166,7 +1191,8 @@ void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus)
for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++)
{
- xinode = g_xrdp_fs.inode_table[i];
+ if ((xinode = g_xrdp_fs.inode_table[i]) == NULL)
+ continue;
/* match parent inode */
if (xinode->parent_inode != fip->inode)
@@ -1214,7 +1240,8 @@ done:
void xfuse_devredir_cb_open_file(void *vp, tui32 DeviceId, tui32 FileId)
{
- XFUSE_HANDLE *fh;
+ XFUSE_HANDLE *fh;
+ XRDP_INODE *xinode;
XFUSE_INFO *fip = (XFUSE_INFO *) vp;
if (fip == NULL)
@@ -1225,9 +1252,8 @@ void xfuse_devredir_cb_open_file(void *vp, tui32 DeviceId, tui32 FileId)
if (fip->fi != NULL)
{
- log_debug("$$$$$$$$$$$$$$$ allocationg fh");
-
/* LK_TODO fH NEEDS TO BE RELEASED WHEN THE FILE IS CLOSED */
+ /* LK_TODO nopen needs to be decremented when file is closed */
if ((fh = calloc(1, sizeof(XFUSE_HANDLE))) == NULL)
{
log_error("system out of memory");
@@ -1241,7 +1267,7 @@ void xfuse_devredir_cb_open_file(void *vp, tui32 DeviceId, tui32 FileId)
fh->DeviceId = DeviceId;
fh->FileId = FileId;
- fip->fi->fh = (uint64_t) fh;
+ fip->fi->fh = (uint64_t) ((long) fh);
}
if (fip->invoke_fuse)
@@ -1252,11 +1278,14 @@ void xfuse_devredir_cb_open_file(void *vp, tui32 DeviceId, tui32 FileId)
"DeviceId=%d FileId=%d req=%p fi=%p",
fh->DeviceId, fh->FileId, fip->req, fip->fi);
+ /* update open count */
+ if ((xinode = g_xrdp_fs.inode_table[fip->inode]) != NULL)
+ xinode->nopen++;
+
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
@@ -1316,14 +1345,9 @@ void xfuse_devredir_cb_read_file(void *vp, char *buf, size_t length)
fip = (XFUSE_INFO *) vp;
if (fip == NULL)
- goto done;
+ return;
fuse_reply_buf(fip->req, buf, length);
-
-done:
-
- fh = (XFUSE_HANDLE *) fip->fi->fh;
- free(fh);
free(fip);
}
@@ -1335,7 +1359,7 @@ void xfuse_devredir_cb_write_file(void *vp, char *buf, size_t length)
fip = (XFUSE_INFO *) vp;
if (fip == NULL)
- goto done;
+ return;
fuse_reply_write(fip->req, length);
@@ -1345,13 +1369,67 @@ void xfuse_devredir_cb_write_file(void *vp, char *buf, size_t length)
else
log_error("inode at inode_table[%d] is NULL", fip->inode);
-done:
+ free(fip);
+}
+
+void xfuse_devredir_cb_rmdir_or_file(void *vp, tui32 IoStatus)
+{
+ XFUSE_INFO *fip;
+ XRDP_INODE *xinode;
+
+ fip = (XFUSE_INFO *) vp;
+ if (fip == NULL)
+ return;
- fh = (XFUSE_HANDLE *) fip->fi->fh;
- free(fh);
+ if (IoStatus != 0)
+ {
+ fuse_reply_err(fip->req, EBADF);
+ free(fip);
+ return;
+ }
+
+ /* now delete the item in xrdp fs */
+ xinode = xfuse_get_inode_from_pinode_name(fip->inode, fip->name);
+ if (xinode == NULL)
+ {
+ fuse_reply_err(fip->req, EBADF);
+ free(fip);
+ return;
+ }
+
+ g_xrdp_fs.inode_table[xinode->inode] = NULL;
+ free(xinode);
+
+ /* update parent */
+ xinode = g_xrdp_fs.inode_table[fip->inode];
+ xinode->nentries--;
+
+ fuse_reply_err(fip->req, 0);
free(fip);
}
+void xfuse_devredir_cb_file_close(void *vp)
+{
+ XFUSE_INFO *fip;
+ XRDP_INODE *xinode;
+
+ fip = (XFUSE_INFO *) vp;
+ if (fip == NULL)
+ return;
+
+ if ((xinode = g_xrdp_fs.inode_table[fip->inode]) == NULL)
+ fuse_reply_err(fip->req, EBADF);
+
+ log_debug("before: inode=%d nopen=%d", xinode->inode, xinode->nopen);
+
+ if (xinode->nopen > 0)
+ xinode->nopen--;
+
+ log_debug("after: inode=%d nopen=%d", xinode->inode, xinode->nopen);
+
+ fuse_reply_err(fip->req, 0);
+}
+
/******************************************************************************
** **
** callbacks for fuse **
@@ -1387,7 +1465,8 @@ static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
#if 0
for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++)
{
- xinode = g_xrdp_fs.inode_table[i];
+ if ((xinode = g_xrdp_fs.inode_table[i]) == NULL)
+ continue;
/* match parent inode */
if (xinode->parent_inode != parent)
@@ -1601,7 +1680,9 @@ static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++)
{
- xinode = g_xrdp_fs.inode_table[i];
+ if ((xinode = g_xrdp_fs.inode_table[i]) == NULL)
+ continue;
+
if (xinode->parent_inode == ino)
xfuse_dirbuf_add(req, &b, xinode->name, xinode->inode);
}
@@ -1658,7 +1739,29 @@ static void xfuse_cb_mkdir(fuse_req_t req, fuse_ino_t parent,
static void xfuse_cb_rmdir(fuse_req_t req, fuse_ino_t parent,
const char *name)
{
+ xfuse_remove_dir_or_file(req, parent, name, 1);
+}
+
+static void xfuse_cb_unlink(fuse_req_t req, fuse_ino_t parent,
+ const char *name)
+{
+ xfuse_remove_dir_or_file(req, parent, name, 2);
+}
+
+/**
+ * Remove a dir or file
+ *
+ * @param type 1=dir, 2=file
+ *****************************************************************************/
+
+static void xfuse_remove_dir_or_file(fuse_req_t req, fuse_ino_t parent,
+ const char *name, int type)
+{
+ XFUSE_INFO *fip;
XRDP_INODE *xinode;
+ char *cptr;
+ char full_path[4096];
+ tui32 device_id;
log_debug("entered: parent=%d name=%s", parent, name);
@@ -1677,16 +1780,75 @@ static void xfuse_cb_rmdir(fuse_req_t req, fuse_ino_t parent,
return;
}
- log_debug("nentries is %d", xinode->nentries);
+ device_id = xfuse_get_device_id_for_inode(parent, full_path);
+
+ log_debug("path=%s nentries=%d", full_path, xinode->nentries);
- if (xinode->nentries != 0)
+ if ((type == 1) && (xinode->nentries != 0))
{
log_debug("cannot rmdir; lookup count is %d", xinode->nentries);
fuse_reply_err(req, ENOTEMPTY);
return;
}
- fuse_reply_err(req, 0);
+ else if ((type == 2) && (xinode->nopen != 0))
+ {
+ log_debug("cannot unlink; open count is %d", xinode->nopen);
+ fuse_reply_err(req, EBUSY);
+ return;
+ }
+ 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->inode = parent;
+ fip->invoke_fuse = 1;
+ fip->device_id = device_id;
+ strncpy(fip->name, name, 1024);
+ fip->name[1023] = 0;
+ fip->type = type;
+
+ /* we want path minus 'root node of the share' */
+ if ((cptr = strchr(full_path, '/')) == NULL)
+ {
+ /* get dev_redir to open the remote file */
+ if (devredir_rmdir_or_file((void *) fip, device_id, "\\", O_RDWR))
+ {
+ log_error("failed to send dev_redir_open_file() cmd");
+ fuse_reply_err(req, EREMOTEIO);
+ free(fip);
+ return;
+ }
+ }
+ else
+ {
+ if (devredir_rmdir_or_file((void *) fip, device_id, cptr, O_RDWR))
+ {
+ log_error("failed to send dev_redir_get_dir_listing() cmd");
+ fuse_reply_err(req, EREMOTEIO);
+ free(fip);
+ return;
+ }
+ }
}
/**
@@ -1872,6 +2034,49 @@ static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino,
}
}
+static void xfuse_cb_flush(fuse_req_t req, fuse_ino_t ino, struct
+ fuse_file_info *fi)
+{
+ XFUSE_INFO *fip = NULL;
+ XFUSE_HANDLE *handle = (XFUSE_HANDLE *) fi->fh;
+
+ if (!xfuse_is_inode_valid(ino))
+ {
+ log_error("inode %d is not valid", ino);
+ fuse_reply_err(req, EBADF);
+ return;
+ }
+
+ if (handle->DeviceId == 0)
+ {
+ /* specified file is a local resource */
+ log_debug("LK_TODO: this is still a TODO");
+ fuse_reply_err(req, EBADF);
+ 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->inode = ino;
+ fip->invoke_fuse = 1;
+ fip->device_id = handle->DeviceId;
+ fip->fi = fi;
+
+ if (devredir_file_close((void *) fip, fip->device_id, handle->FileId))
+ {
+ log_error("failed to send devredir_close_file() cmd");
+ fuse_reply_err(req, EREMOTEIO);
+ }
+}
+
/**
*****************************************************************************/
@@ -1880,6 +2085,7 @@ static void xfuse_cb_read(fuse_req_t req, fuse_ino_t ino, size_t size,
{
XFUSE_HANDLE *fh;
XFUSE_INFO *fusep;
+ long handle;
log_debug("want_bytes %d bytes at off %d", size, off);
@@ -1889,7 +2095,11 @@ static void xfuse_cb_read(fuse_req_t req, fuse_ino_t ino, size_t size,
fuse_reply_err(req, EINVAL);
return;
}
- fh = (XFUSE_HANDLE *) fi->fh;
+
+ log_debug("$$$$$$$$$$$$$ LK_TODO: fh=0x%llx", fi->fh);
+
+ handle = fi->fh;
+ fh = (XFUSE_HANDLE *) handle;
if (fh->DeviceId == 0)
{
@@ -1921,6 +2131,7 @@ static void xfuse_cb_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
{
XFUSE_HANDLE *fh;
XFUSE_INFO *fusep;
+ long handle;
log_debug("write %d bytes at off %d", size, off);
@@ -1930,7 +2141,9 @@ static void xfuse_cb_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
fuse_reply_err(req, EINVAL);
return;
}
- fh = (XFUSE_HANDLE *) fi->fh;
+
+ handle = fi->fh;
+ fh = (XFUSE_HANDLE *) handle;
if (fh->DeviceId == 0)
{
diff --git a/sesman/chansrv/chansrv_fuse.h b/sesman/chansrv/chansrv_fuse.h
index 34c4ba7e..00130381 100644
--- a/sesman/chansrv/chansrv_fuse.h
+++ b/sesman/chansrv/chansrv_fuse.h
@@ -1,7 +1,7 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
- * Copyright (C) Laxmikant Rashinkar 2013
+ * Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@ struct xrdp_inode
tui32 mode; /* File mode. */
tui32 nlink; /* symbolic link count. */
tui32 nentries; /* number of entries in a dir */
+ tui32 nopen; /* number of simultaneous opens */
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. */
@@ -51,10 +52,12 @@ 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 */
+/* functions that are invoked 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);
+void xfuse_devredir_cb_rmdir_or_file(void *vp, tui32 IoStatus);
+void xfuse_devredir_cb_file_close(void *vp);
#endif
diff --git a/sesman/chansrv/devredir.c b/sesman/chansrv/devredir.c
index d9296356..4cd328dc 100644
--- a/sesman/chansrv/devredir.c
+++ b/sesman/chansrv/devredir.c
@@ -663,6 +663,7 @@ void dev_redir_proc_device_iocompletion(struct stream *s)
switch (irp->completion_type)
{
case CID_CREATE_DIR_REQ:
+ log_debug("got CID_CREATE_DIR_REQ");
if (IoStatus != NT_STATUS_SUCCESS)
{
/* we were trying to create a request to enumerate a dir */
@@ -693,12 +694,14 @@ void dev_redir_proc_device_iocompletion(struct stream *s)
break;
case CID_READ:
+ log_debug("got 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:
+ log_debug("got 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);
@@ -709,6 +712,13 @@ void dev_redir_proc_device_iocompletion(struct stream *s)
dev_redir_irp_delete(irp);
break;
+ case CID_FILE_CLOSE:
+ log_debug("got CID_FILE_CLOSE");
+ fuse_data = dev_redir_fuse_data_dequeue(irp);
+ xfuse_devredir_cb_file_close(fuse_data->data_ptr);
+ dev_redir_irp_delete(irp);
+ break;
+
case CID_DIRECTORY_CONTROL:
log_debug("got CID_DIRECTORY_CONTROL");
@@ -716,6 +726,18 @@ void dev_redir_proc_device_iocompletion(struct stream *s)
CompletionId, IoStatus);
break;
+ case CID_RMDIR_OR_FILE:
+ log_debug("got CID_RMDIR_OR_FILE");
+ stream_rd_u32_le(s, irp->FileId);
+ devredir_proc_cid_rmdir_or_file(irp, IoStatus);
+ return;
+ break;
+
+ case CID_RMDIR_OR_FILE_RESP:
+ log_debug("got CID_RMDIR_OR_FILE_RESP");
+ devredir_proc_cid_rmdir_or_file_resp(irp, IoStatus);
+ break;
+
default:
log_error("got unknown CompletionID: DeviceId=0x%x "
"CompletionId=0x%x IoStatus=0x%x",
@@ -938,6 +960,65 @@ int dev_redir_file_open(void *fusep, tui32 device_id, char *path,
return rval;
}
+int devredir_file_close(void *fusep, tui32 device_id, tui32 file_id)
+{
+ IRP *irp;
+
+ if ((irp = dev_redir_irp_new()) == NULL)
+ return -1;
+
+ irp->completion_id = g_completion_id++;
+ irp->completion_type = CID_FILE_CLOSE;
+ irp->device_id = device_id;
+ dev_redir_fuse_data_enqueue(irp, fusep);
+
+ return dev_redir_send_drive_close_request(RDPDR_CTYP_CORE,
+ PAKID_CORE_DEVICE_IOREQUEST,
+ device_id,
+ file_id,
+ irp->completion_id,
+ IRP_MJ_CLOSE,
+ 0, 32);
+}
+
+/**
+ * Remove (delete) a directory
+ *****************************************************************************/
+
+int devredir_rmdir_or_file(void *fusep, tui32 device_id, char *path, int mode)
+{
+ 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_RMDIR_OR_FILE;
+ irp->device_id = device_id;
+ strcpy(irp->pathname, path);
+ dev_redir_fuse_data_enqueue(irp, fusep);
+
+ // LK_TODO
+ //DesiredAccess = DA_DELETE | DA_FILE_READ_DATA | DA_FILE_WRITE_DATA | DA_SYNCHRONIZE;
+ DesiredAccess = DA_DELETE | DA_FILE_READ_ATTRIBUTES | DA_SYNCHRONIZE;
+
+ CreateOptions = CO_FILE_DELETE_ON_CLOSE | CO_FILE_DIRECTORY_FILE |
+ CO_FILE_SYNCHRONOUS_IO_NONALERT;
+
+ CreateDisposition = CD_FILE_OPEN; // WAS 1
+
+ rval = dev_redir_send_drive_create_request(device_id, path,
+ DesiredAccess, CreateOptions,
+ CreateDisposition,
+ irp->completion_id);
+
+ return rval;
+}
+
/**
* Read data from previously opened file
*
@@ -1328,3 +1409,65 @@ void dev_redir_insert_rdpdr_header(struct stream *s, tui16 Component,
stream_wr_u16_le(s, Component);
stream_wr_u16_le(s, PacketId);
}
+
+void devredir_proc_cid_rmdir_or_file(IRP *irp, tui32 IoStatus)
+{
+ struct stream *s;
+ int bytes;
+
+ if (IoStatus != NT_STATUS_SUCCESS)
+ {
+ FUSE_DATA *fuse_data = dev_redir_fuse_data_dequeue(irp);
+ if (fuse_data)
+ {
+ xfuse_devredir_cb_rmdir_or_file(fuse_data->data_ptr, IoStatus);
+ free(fuse_data);
+ }
+ dev_redir_irp_delete(irp);
+ return;
+ }
+
+ stream_new(s, 1024);
+
+ irp->completion_type = CID_RMDIR_OR_FILE_RESP;
+ dev_redir_insert_dev_io_req_header(s, irp->device_id, irp->FileId,
+ irp->completion_id,
+ IRP_MJ_SET_INFORMATION, 0);
+
+ stream_wr_u32_le(s, FileDispositionInformation);
+ stream_wr_u32_le(s, 0); /* length is zero */
+ stream_seek(s, 24); /* padding */
+
+ /* send to client */
+ bytes = stream_len(s);
+ send_channel_data(g_rdpdr_chan_id, s->data, bytes);
+ stream_free(s);
+
+ return;
+}
+
+void devredir_proc_cid_rmdir_or_file_resp(IRP *irp, tui32 IoStatus)
+{
+ FUSE_DATA *fuse_data;
+
+ fuse_data = dev_redir_fuse_data_dequeue(irp);
+ if (fuse_data)
+ {
+ xfuse_devredir_cb_rmdir_or_file(fuse_data->data_ptr, IoStatus);
+ free(fuse_data);
+ }
+
+ if (IoStatus != NT_STATUS_SUCCESS)
+ {
+ dev_redir_irp_delete(irp);
+ return;
+ }
+
+ irp->completion_type = CID_CLOSE;
+ dev_redir_send_drive_close_request(RDPDR_CTYP_CORE,
+ PAKID_CORE_DEVICE_IOREQUEST,
+ irp->device_id,
+ irp->FileId,
+ irp->completion_id,
+ IRP_MJ_CLOSE, 0, 32);
+}
diff --git a/sesman/chansrv/devredir.h b/sesman/chansrv/devredir.h
index 84ab3a86..74615973 100644
--- a/sesman/chansrv/devredir.h
+++ b/sesman/chansrv/devredir.h
@@ -18,6 +18,8 @@
* limitations under the License.
*/
+// LK_TODO dev_redir_xxx should become devredir_xxx
+
#if !defined(DEVREDIR_H)
#define DEVREDIR_H
@@ -126,12 +128,17 @@ int dev_redir_string_ends_with(char *string, char c);
void dev_redir_insert_rdpdr_header(struct stream *s, tui16 Component,
tui16 PacketId);
+void devredir_proc_cid_rmdir_or_file(IRP *irp, tui32 IoStatus);
+void devredir_proc_cid_rmdir_or_file_resp(IRP *irp, tui32 IoStatus);
+
/* 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 devredir_file_close(void *fusep, tui32 device_id, tui32 file_id);
+
int dev_redir_file_read(void *fusep, tui32 device_id, tui32 FileId,
tui32 Length, tui64 Offset);
@@ -141,7 +148,7 @@ int dev_redir_file_read(void *fusep, tui32 device_id, tui32 FileId,
#define LOG_DEBUG 2
#ifndef LOG_LEVEL
-#define LOG_LEVEL LOG_ERROR
+#define LOG_LEVEL LOG_DEBUG
#endif
#define log_error(_params...) \
@@ -276,9 +283,13 @@ int send_channel_data(int chan_id, char *data, int size);
* 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
+enum CREATE_OPTIONS
+{
+ CO_FILE_DIRECTORY_FILE = 0x00000001,
+ CO_FILE_WRITE_THROUGH = 0x00000002,
+ CO_FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020,
+ CO_FILE_DELETE_ON_CLOSE = 0x00001000
+};
/*
* CreateDispositions Mask [MS-SMB2] section 2.2.13
@@ -324,31 +335,37 @@ int send_channel_data(int chan_id, char *data, int size);
#define NT_STATUS_UNSUCCESSFUL 0xC0000001
/*
+ * File system ioctl codes
+ * MS-FSCC section 2.3 FSCTL Structures
+ */
+#define FSCTL_DELETE_OBJECT_ID 0x900a0
+
+
+/*
* CompletionID types, used in IRPs to indicate I/O operation
*/
-enum
+enum COMPLETION_ID
{
CID_CREATE_DIR_REQ = 1,
CID_CREATE_OPEN_REQ,
CID_READ,
CID_WRITE,
CID_DIRECTORY_CONTROL,
- CID_CLOSE
+ CID_CLOSE,
+ CID_FILE_CLOSE,
+ CID_RMDIR_OR_FILE,
+ CID_RMDIR_OR_FILE_RESP
};
-#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
+enum FS_INFORMATION_CLASS
+{
+ FileBasicInformation = 0x00000004, /* set atime, mtime, ctime etc */
+ FileEndOfFileInformation = 0x00000014, /* set EOF info */
+ FileDispositionInformation = 0x0000000D, /* mark a file for deletion */
+ FileRenameInformation = 0x0000000A, /* rename a file */
+ FileAllocationInformation = 0x00000013 /* set file allocation size */
+};
/*
* constants for drive dir query