o added support for deleteing files and directories

ulab-next
Laxmikant Rashinkar 12 years ago
parent 297fdaf1c6
commit 5acc54cd1d

@ -1,7 +1,7 @@
/** /**
* xrdp: A Remote Desktop Protocol server. * 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,14 +31,13 @@
* o are we calling close? * o are we calling close?
* o need to keep track of open files, reqd during rename * o need to keep track of open files, reqd during rename
* o fuse ops to support * o fuse ops to support
* o rmdir
* o rename (mv) * o rename (mv)
* o remove file
* o touch does not work * o touch does not work
* o mknod (may not be required if create is correctly implemented) * o mknod (may not be required if create is correctly implemented)
* o symlink * o symlink
* o keep track of lookup_count * o keep track of lookup_count
* o chmod must work * 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_ERROR 0
#define LOG_INFO 1 #define LOG_INFO 1
#define LOG_DEBUG 2 #define LOG_DEBUG 2
#define LOG_LEVEL LOG_ERROR #define LOG_LEVEL LOG_DEBUG
#define log_error(_params...) \ #define log_error(_params...) \
{ \ { \
@ -161,6 +160,7 @@ struct xfuse_info
tui32 device_id; tui32 device_id;
int reply_type; int reply_type;
int mode; int mode;
int type;
}; };
typedef struct xfuse_info XFUSE_INFO; typedef struct xfuse_info XFUSE_INFO;
@ -186,7 +186,7 @@ static tintptr g_bufsize = 0;
/* forward declarations for internal access */ /* forward declarations for internal access */
static int xfuse_init_xrdp_fs(); static int xfuse_init_xrdp_fs();
static int xfuse_deinit_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); static int xfuse_is_inode_valid(int ino);
// LK_TODO // 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); 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_get_dir_listing(void *fusep, tui32 device_id, char *path);
int dev_redir_file_open(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, static void xfuse_cb_rmdir(fuse_req_t req, fuse_ino_t parent,
const char *name); 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, static void xfuse_create_dir_or_file(fuse_req_t req, fuse_ino_t parent,
const char *name, mode_t mode, const char *name, mode_t mode,
struct fuse_file_info *fi, int type); 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, static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi); 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, static void xfuse_cb_read(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t off, struct fuse_file_info *fi); 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() int xfuse_init()
{ {
char *param0 = "xrdp-chansrv"; struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
char *argv[4]; char opt[1024];
/* if already inited, just return */ /* if already inited, just return */
if (g_xfuse_inited) if (g_xfuse_inited)
@ -345,8 +355,10 @@ int xfuse_init()
g_xfuse_ops.lookup = xfuse_cb_lookup; g_xfuse_ops.lookup = xfuse_cb_lookup;
g_xfuse_ops.readdir = xfuse_cb_readdir; g_xfuse_ops.readdir = xfuse_cb_readdir;
g_xfuse_ops.mkdir = xfuse_cb_mkdir; 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.open = xfuse_cb_open;
g_xfuse_ops.flush = xfuse_cb_flush;
g_xfuse_ops.read = xfuse_cb_read; g_xfuse_ops.read = xfuse_cb_read;
g_xfuse_ops.write = xfuse_cb_write; g_xfuse_ops.write = xfuse_cb_write;
g_xfuse_ops.create = xfuse_cb_create; g_xfuse_ops.create = xfuse_cb_create;
@ -365,11 +377,14 @@ int xfuse_init()
g_xfuse_ops.getxattr = xfuse_cb_getxattr; g_xfuse_ops.getxattr = xfuse_cb_getxattr;
#endif #endif
argv[0] = param0; fuse_opt_add_arg(&args, "xrdp-chansrv");
argv[1] = g_fuse_root_path; fuse_opt_add_arg(&args, g_fuse_root_path);
argv[2] = 0; #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(); xfuse_deinit();
return -1; return -1;
@ -607,35 +622,41 @@ int xfuse_file_contents_size(int stream_id, int file_size)
* @return 0 on success, -1 on failure * @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"); log_error("fuse_parse_cmdline() failed");
fuse_opt_free_args(&args); fuse_opt_free_args(args);
return -1; 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"); log_error("fuse_mount() failed");
fuse_opt_free_args(&args); fuse_opt_free_args(args);
return -1; 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) if (g_se == 0)
{ {
log_error("fuse_lowlevel_new() failed"); log_error("fuse_lowlevel_new() failed");
fuse_unmount(g_mount_point, g_ch); fuse_unmount(g_mount_point, g_ch);
g_ch = 0; g_ch = 0;
fuse_opt_free_args(&args); fuse_opt_free_args(args);
return -1; return -1;
} }
fuse_opt_free_args(&args); fuse_opt_free_args(args);
fuse_session_add_chan(g_se, g_ch); fuse_session_add_chan(g_se, g_ch);
g_bufsize = fuse_chan_bufsize(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++) 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", log_debug("pinode=%d inode=%d nentries=%d mode=0x%x name=%s",
(int) xinode->parent_inode, (int) xinode->inode, (int) xinode->parent_inode, (int) xinode->inode,
xinode->nentries, xinode->mode, xinode->name); 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++) 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 */ /* match parent inode */
if (xinode->parent_inode != pinode) 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++) 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) && if ((xinode->parent_inode == parent) &&
(strcmp(xinode->name, name) == 0)) (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++) 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 */ /* match parent inode */
if (xinode->parent_inode != fip->inode) if (xinode->parent_inode != fip->inode)
@ -1215,6 +1241,7 @@ done:
void xfuse_devredir_cb_open_file(void *vp, tui32 DeviceId, tui32 FileId) 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; XFUSE_INFO *fip = (XFUSE_INFO *) vp;
if (fip == NULL) if (fip == NULL)
@ -1225,9 +1252,8 @@ void xfuse_devredir_cb_open_file(void *vp, tui32 DeviceId, tui32 FileId)
if (fip->fi != NULL) if (fip->fi != NULL)
{ {
log_debug("$$$$$$$$$$$$$$$ allocationg fh");
/* LK_TODO fH NEEDS TO BE RELEASED WHEN THE FILE IS CLOSED */ /* 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) if ((fh = calloc(1, sizeof(XFUSE_HANDLE))) == NULL)
{ {
log_error("system out of memory"); 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->DeviceId = DeviceId;
fh->FileId = FileId; fh->FileId = FileId;
fip->fi->fh = (uint64_t) fh; fip->fi->fh = (uint64_t) ((long) fh);
} }
if (fip->invoke_fuse) 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", "DeviceId=%d FileId=%d req=%p fi=%p",
fh->DeviceId, fh->FileId, fip->req, fip->fi); 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); fuse_reply_open(fip->req, fip->fi);
} }
else if (fip->reply_type == RT_FUSE_REPLY_CREATE) else if (fip->reply_type == RT_FUSE_REPLY_CREATE)
{ {
XRDP_INODE *xinode;
struct fuse_entry_param e; struct fuse_entry_param e;
// LK_TODO // LK_TODO
@ -1316,14 +1345,9 @@ void xfuse_devredir_cb_read_file(void *vp, char *buf, size_t length)
fip = (XFUSE_INFO *) vp; fip = (XFUSE_INFO *) vp;
if (fip == NULL) if (fip == NULL)
goto done; return;
fuse_reply_buf(fip->req, buf, length); fuse_reply_buf(fip->req, buf, length);
done:
fh = (XFUSE_HANDLE *) fip->fi->fh;
free(fh);
free(fip); free(fip);
} }
@ -1335,7 +1359,7 @@ void xfuse_devredir_cb_write_file(void *vp, char *buf, size_t length)
fip = (XFUSE_INFO *) vp; fip = (XFUSE_INFO *) vp;
if (fip == NULL) if (fip == NULL)
goto done; return;
fuse_reply_write(fip->req, length); fuse_reply_write(fip->req, length);
@ -1345,11 +1369,65 @@ void xfuse_devredir_cb_write_file(void *vp, char *buf, size_t length)
else else
log_error("inode at inode_table[%d] is NULL", fip->inode); 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;
fh = (XFUSE_HANDLE *) fip->fi->fh; fip = (XFUSE_INFO *) vp;
free(fh); if (fip == NULL)
return;
if (IoStatus != 0)
{
fuse_reply_err(fip->req, EBADF);
free(fip); 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);
} }
/****************************************************************************** /******************************************************************************
@ -1387,7 +1465,8 @@ static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
#if 0 #if 0
for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) 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 */ /* match parent inode */
if (xinode->parent_inode != parent) 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++) 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) if (xinode->parent_inode == ino)
xfuse_dirbuf_add(req, &b, xinode->name, xinode->inode); 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, static void xfuse_cb_rmdir(fuse_req_t req, fuse_ino_t parent,
const char *name) 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; XRDP_INODE *xinode;
char *cptr;
char full_path[4096];
tui32 device_id;
log_debug("entered: parent=%d name=%s", parent, name); 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; 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); log_debug("cannot rmdir; lookup count is %d", xinode->nentries);
fuse_reply_err(req, ENOTEMPTY); fuse_reply_err(req, ENOTEMPTY);
return; 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_HANDLE *fh;
XFUSE_INFO *fusep; XFUSE_INFO *fusep;
long handle;
log_debug("want_bytes %d bytes at off %d", size, off); 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); fuse_reply_err(req, EINVAL);
return; 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) 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_HANDLE *fh;
XFUSE_INFO *fusep; XFUSE_INFO *fusep;
long handle;
log_debug("write %d bytes at off %d", size, off); 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); fuse_reply_err(req, EINVAL);
return; return;
} }
fh = (XFUSE_HANDLE *) fi->fh;
handle = fi->fh;
fh = (XFUSE_HANDLE *) handle;
if (fh->DeviceId == 0) if (fh->DeviceId == 0)
{ {

@ -1,7 +1,7 @@
/** /**
* xrdp: A Remote Desktop Protocol server. * 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 mode; /* File mode. */
tui32 nlink; /* symbolic link count. */ tui32 nlink; /* symbolic link count. */
tui32 nentries; /* number of entries in a dir */ tui32 nentries; /* number of entries in a dir */
tui32 nopen; /* number of simultaneous opens */
tui32 uid; /* User ID of the file's owner. */ tui32 uid; /* User ID of the file's owner. */
tui32 gid; /* Group ID of the file's group. */ tui32 gid; /* Group ID of the file's group. */
size_t size; /* Size of file, in bytes. */ 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_file_contents_size(int stream_id, int file_size);
int xfuse_add_clip_dir_item(char *filename, int flags, int size, int lindex); 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(void *vp, struct xrdp_inode *xinode);
void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus); 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_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_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 #endif

@ -663,6 +663,7 @@ void dev_redir_proc_device_iocompletion(struct stream *s)
switch (irp->completion_type) switch (irp->completion_type)
{ {
case CID_CREATE_DIR_REQ: case CID_CREATE_DIR_REQ:
log_debug("got CID_CREATE_DIR_REQ");
if (IoStatus != NT_STATUS_SUCCESS) if (IoStatus != NT_STATUS_SUCCESS)
{ {
/* we were trying to create a request to enumerate a dir */ /* 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; break;
case CID_READ: case CID_READ:
log_debug("got CID_READ");
stream_rd_u32_le(s, Length); stream_rd_u32_le(s, Length);
fuse_data = dev_redir_fuse_data_dequeue(irp); fuse_data = dev_redir_fuse_data_dequeue(irp);
xfuse_devredir_cb_read_file(fuse_data->data_ptr, s->p, Length); xfuse_devredir_cb_read_file(fuse_data->data_ptr, s->p, Length);
break; break;
case CID_WRITE: case CID_WRITE:
log_debug("got CID_WRITE");
stream_rd_u32_le(s, Length); stream_rd_u32_le(s, Length);
fuse_data = dev_redir_fuse_data_dequeue(irp); fuse_data = dev_redir_fuse_data_dequeue(irp);
xfuse_devredir_cb_write_file(fuse_data->data_ptr, s->p, Length); 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); dev_redir_irp_delete(irp);
break; 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: case CID_DIRECTORY_CONTROL:
log_debug("got CID_DIRECTORY_CONTROL"); log_debug("got CID_DIRECTORY_CONTROL");
@ -716,6 +726,18 @@ void dev_redir_proc_device_iocompletion(struct stream *s)
CompletionId, IoStatus); CompletionId, IoStatus);
break; 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: default:
log_error("got unknown CompletionID: DeviceId=0x%x " log_error("got unknown CompletionID: DeviceId=0x%x "
"CompletionId=0x%x IoStatus=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; 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 * 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, Component);
stream_wr_u16_le(s, PacketId); 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);
}

@ -18,6 +18,8 @@
* limitations under the License. * limitations under the License.
*/ */
// LK_TODO dev_redir_xxx should become devredir_xxx
#if !defined(DEVREDIR_H) #if !defined(DEVREDIR_H)
#define 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, void dev_redir_insert_rdpdr_header(struct stream *s, tui16 Component,
tui16 PacketId); 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 */ /* called from FUSE module */
int dev_redir_get_dir_listing(void *fusep, tui32 device_id, char *path); 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 dev_redir_file_open(void *fusep, tui32 device_id, char *path,
int mode, int type); 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, int dev_redir_file_read(void *fusep, tui32 device_id, tui32 FileId,
tui32 Length, tui64 Offset); tui32 Length, tui64 Offset);
@ -141,7 +148,7 @@ int dev_redir_file_read(void *fusep, tui32 device_id, tui32 FileId,
#define LOG_DEBUG 2 #define LOG_DEBUG 2
#ifndef LOG_LEVEL #ifndef LOG_LEVEL
#define LOG_LEVEL LOG_ERROR #define LOG_LEVEL LOG_DEBUG
#endif #endif
#define log_error(_params...) \ #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 * CreateOptions Mask [MS-SMB2] section 2.2.13 SMB2 CREATE Request
*/ */
#define CO_FILE_DIRECTORY_FILE 0x00000001 enum CREATE_OPTIONS
#define CO_FILE_WRITE_THROUGH 0x00000002 {
#define CO_FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 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 * CreateDispositions Mask [MS-SMB2] section 2.2.13
@ -323,32 +334,38 @@ int send_channel_data(int chan_id, char *data, int size);
#define NT_STATUS_SUCCESS 0x00000000 #define NT_STATUS_SUCCESS 0x00000000
#define NT_STATUS_UNSUCCESSFUL 0xC0000001 #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 * CompletionID types, used in IRPs to indicate I/O operation
*/ */
enum enum COMPLETION_ID
{ {
CID_CREATE_DIR_REQ = 1, CID_CREATE_DIR_REQ = 1,
CID_CREATE_OPEN_REQ, CID_CREATE_OPEN_REQ,
CID_READ, CID_READ,
CID_WRITE, CID_WRITE,
CID_DIRECTORY_CONTROL, CID_DIRECTORY_CONTROL,
CID_CLOSE CID_CLOSE,
CID_FILE_CLOSE,
CID_RMDIR_OR_FILE,
CID_RMDIR_OR_FILE_RESP
}; };
#if 0 enum FS_INFORMATION_CLASS
#define CID_CLOSE 0x0002 {
#define CID_READ 0x0003 FileBasicInformation = 0x00000004, /* set atime, mtime, ctime etc */
#define CID_WRITE 0x0004 FileEndOfFileInformation = 0x00000014, /* set EOF info */
#define CID_DEVICE_CONTROL 0x0005 FileDispositionInformation = 0x0000000D, /* mark a file for deletion */
#define CID_QUERY_VOLUME_INFORMATION 0x0006 FileRenameInformation = 0x0000000A, /* rename a file */
#define CID_SET_VOLUME_INFORMATION 0x0007 FileAllocationInformation = 0x00000013 /* set file allocation size */
#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 * constants for drive dir query

Loading…
Cancel
Save