o in file system redirection, added support for renaming files and directories
This commit is contained in:
@@ -30,11 +30,10 @@
|
||||
* 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 need to use dir notification for changed files and update xrdp fs
|
||||
* o fuse ops to support
|
||||
* o rename (mv)
|
||||
* 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
|
||||
@@ -75,6 +74,7 @@ void xfuse_devredir_cb_read_file(void *vp, char *buf, size_t length) {}
|
||||
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_rmdir_or_file(void *vp, tui32 IoStatus) {}
|
||||
void xfuse_devredir_cb_rename_file(void *vp, tui32 IoStatus) {}
|
||||
void xfuse_devredir_cb_file_close(void *vp) {}
|
||||
|
||||
#else
|
||||
@@ -115,7 +115,7 @@ void xfuse_devredir_cb_file_close(void *vp) {}
|
||||
#define LOG_ERROR 0
|
||||
#define LOG_INFO 1
|
||||
#define LOG_DEBUG 2
|
||||
#define LOG_LEVEL LOG_DEBUG
|
||||
#define LOG_LEVEL LOG_ERROR
|
||||
|
||||
#define log_error(_params...) \
|
||||
{ \
|
||||
@@ -144,6 +144,8 @@ void xfuse_devredir_cb_file_close(void *vp) {}
|
||||
} \
|
||||
}
|
||||
|
||||
#define OP_RENAME_FILE 0x01
|
||||
|
||||
/* the xrdp file system in memory */
|
||||
struct xrdp_fs
|
||||
{
|
||||
@@ -168,8 +170,10 @@ struct xfuse_info
|
||||
struct fuse_file_info *fi;
|
||||
fuse_req_t req;
|
||||
fuse_ino_t inode;
|
||||
fuse_ino_t new_inode;
|
||||
int invoke_fuse;
|
||||
char name[1024];
|
||||
char new_name[1024];
|
||||
tui32 device_id;
|
||||
int reply_type;
|
||||
int mode;
|
||||
@@ -221,12 +225,15 @@ static struct xrdp_inode * xfuse_create_file_in_xrdp_fs(tui32 device_id,
|
||||
int type);
|
||||
|
||||
static int xfuse_does_file_exist(int parent, char *name);
|
||||
static int xfuse_delete_file(int parent, char *name);
|
||||
static int xfuse_delete_file_with_xinode(XRDP_INODE *xinode);
|
||||
static int xfuse_delete_dir_with_xinode(XRDP_INODE *xinode);
|
||||
|
||||
/* 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,
|
||||
int mode, int type);
|
||||
int mode, int type, char *gen_buf);
|
||||
|
||||
int dev_redir_file_read(void *fusep, tui32 device_id, tui32 FileId,
|
||||
tui32 Length, tui64 Offset);
|
||||
@@ -257,6 +264,10 @@ static void xfuse_cb_rmdir(fuse_req_t req, fuse_ino_t parent,
|
||||
static void xfuse_cb_unlink(fuse_req_t req, fuse_ino_t parent,
|
||||
const char *name);
|
||||
|
||||
static void xfuse_cb_rename(fuse_req_t req,
|
||||
fuse_ino_t old_parent, const char *old_name,
|
||||
fuse_ino_t new_parent, const char *new_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);
|
||||
@@ -370,6 +381,7 @@ int xfuse_init()
|
||||
g_xfuse_ops.mkdir = xfuse_cb_mkdir;
|
||||
g_xfuse_ops.rmdir = xfuse_cb_rmdir;
|
||||
g_xfuse_ops.unlink = xfuse_cb_unlink;
|
||||
g_xfuse_ops.rename = xfuse_cb_rename;
|
||||
g_xfuse_ops.open = xfuse_cb_open;
|
||||
g_xfuse_ops.flush = xfuse_cb_flush;
|
||||
g_xfuse_ops.read = xfuse_cb_read;
|
||||
@@ -1104,6 +1116,56 @@ static int xfuse_does_file_exist(int parent, char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xfuse_delete_file(int parent, char *name)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int xfuse_delete_file_with_xinode(XRDP_INODE *xinode)
|
||||
{
|
||||
/* make sure it is not a dir */
|
||||
if ((xinode == NULL) || (xinode->mode & S_IFDIR))
|
||||
return -1;
|
||||
|
||||
g_xrdp_fs.inode_table[xinode->parent_inode]->nentries--;
|
||||
g_xrdp_fs.inode_table[xinode->inode] = NULL;
|
||||
free(xinode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xfuse_delete_dir_with_xinode(XRDP_INODE *xinode)
|
||||
{
|
||||
XRDP_INODE *xip;
|
||||
int i;
|
||||
|
||||
/* make sure it is not a file */
|
||||
if ((xinode == NULL) || (xinode->mode & S_IFREG))
|
||||
return -1;
|
||||
|
||||
for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++)
|
||||
{
|
||||
if ((xip = g_xrdp_fs.inode_table[i]) == NULL)
|
||||
continue;
|
||||
|
||||
/* look for child inodes */
|
||||
if (xip->parent_inode == xinode->inode)
|
||||
{
|
||||
/* got one, delete it */
|
||||
g_xrdp_fs.inode_table[xip->inode] = NULL;
|
||||
free(xip);
|
||||
}
|
||||
}
|
||||
|
||||
/* our parent will have one less dir */
|
||||
g_xrdp_fs.inode_table[xinode->parent_inode]->nentries--;
|
||||
|
||||
g_xrdp_fs.inode_table[xinode->inode] = NULL;
|
||||
free(xinode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
** **
|
||||
** callbacks for devredir **
|
||||
@@ -1421,6 +1483,64 @@ void xfuse_devredir_cb_rmdir_or_file(void *vp, tui32 IoStatus)
|
||||
free(fip);
|
||||
}
|
||||
|
||||
void xfuse_devredir_cb_rename_file(void *vp, tui32 IoStatus)
|
||||
{
|
||||
XFUSE_INFO *fip;
|
||||
XRDP_INODE *old_xinode;
|
||||
XRDP_INODE *new_xinode;
|
||||
|
||||
fip = (XFUSE_INFO *) vp;
|
||||
if (fip == NULL)
|
||||
return;
|
||||
|
||||
if (IoStatus != 0)
|
||||
{
|
||||
fuse_reply_err(fip->req, EEXIST);
|
||||
free(fip);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* update xrdp file system
|
||||
*/
|
||||
|
||||
/* if destination dir/file exists, delete it */
|
||||
if (xfuse_does_file_exist(fip->new_inode, fip->new_name))
|
||||
{
|
||||
new_xinode = xfuse_get_inode_from_pinode_name(fip->new_inode,
|
||||
fip->new_name);
|
||||
|
||||
if (new_xinode->mode & S_IFREG)
|
||||
xfuse_delete_file_with_xinode(new_xinode);
|
||||
else
|
||||
xfuse_delete_dir_with_xinode(new_xinode);
|
||||
|
||||
new_xinode = NULL;
|
||||
}
|
||||
|
||||
old_xinode = xfuse_get_inode_from_pinode_name(fip->inode, fip->name);
|
||||
if (old_xinode == NULL)
|
||||
{
|
||||
fuse_reply_err(fip->req, EBADF);
|
||||
free(fip);
|
||||
return;
|
||||
}
|
||||
|
||||
old_xinode->parent_inode = fip->new_inode;
|
||||
strcpy(old_xinode->name, fip->new_name);
|
||||
|
||||
if (fip->inode != fip->new_inode)
|
||||
{
|
||||
/* file has been moved to a different dir */
|
||||
old_xinode->is_synced = 1;
|
||||
g_xrdp_fs.inode_table[fip->inode]->nentries--;
|
||||
g_xrdp_fs.inode_table[fip->new_inode]->nentries++;
|
||||
}
|
||||
|
||||
fuse_reply_err(fip->req, 0);
|
||||
free(fip);
|
||||
}
|
||||
|
||||
void xfuse_devredir_cb_file_close(void *vp)
|
||||
{
|
||||
XFUSE_INFO *fip;
|
||||
@@ -1864,6 +1984,142 @@ static void xfuse_remove_dir_or_file(fuse_req_t req, fuse_ino_t parent,
|
||||
}
|
||||
}
|
||||
|
||||
static void xfuse_cb_rename(fuse_req_t req,
|
||||
fuse_ino_t old_parent, const char *old_name,
|
||||
fuse_ino_t new_parent, const char *new_name)
|
||||
{
|
||||
XRDP_INODE *old_xinode;
|
||||
XFUSE_INFO *fip;
|
||||
tui32 new_device_id;
|
||||
char *cptr;
|
||||
char old_full_path[1024];
|
||||
char new_full_path[1024];
|
||||
char *cp;
|
||||
|
||||
tui32 device_id;
|
||||
|
||||
log_debug("entered: old_parent=%d old_name=%s new_parent=%d new_name=%s",
|
||||
old_parent, old_name, new_parent, new_name);
|
||||
xfuse_dump_fs();
|
||||
|
||||
/* is old_parent inode valid? */
|
||||
if (!xfuse_is_inode_valid(old_parent))
|
||||
{
|
||||
log_error("inode %d is not valid", old_parent);
|
||||
fuse_reply_err(req, EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* is new_parent inode valid? */
|
||||
if (!xfuse_is_inode_valid(new_parent))
|
||||
{
|
||||
log_error("inode %d is not valid", new_parent);
|
||||
fuse_reply_err(req, EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((old_name == NULL) || (strlen(old_name) == 0))
|
||||
{
|
||||
fuse_reply_err(req, EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((new_name == NULL) || (strlen(new_name) == 0))
|
||||
{
|
||||
fuse_reply_err(req, EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
old_xinode = xfuse_get_inode_from_pinode_name(old_parent, old_name);
|
||||
if (old_xinode == NULL)
|
||||
{
|
||||
log_error("did not find file with pinode=%d name=%s",
|
||||
old_parent, old_name);
|
||||
fuse_reply_err(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if file is open, cannot rename */
|
||||
if (old_xinode->nopen != 0)
|
||||
{
|
||||
fuse_reply_err(req, EBUSY);
|
||||
return;
|
||||
}
|
||||
|
||||
/* rename across file systems not yet supported */
|
||||
new_device_id = xfuse_get_device_id_for_inode(new_parent, new_full_path);
|
||||
strcat(new_full_path, "/");
|
||||
strcat(new_full_path, new_name);
|
||||
|
||||
if (new_device_id != old_xinode->device_id)
|
||||
{
|
||||
log_error("rename across file systems not supported");
|
||||
fuse_reply_err(req, EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (old_xinode->device_id == 0)
|
||||
{
|
||||
/* specified file is a local resource */
|
||||
log_debug("LK_TODO: this is still a TODO");
|
||||
fuse_reply_err(req, EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* resource is on a redirected share */
|
||||
|
||||
device_id = old_xinode->device_id;
|
||||
|
||||
xfuse_get_device_id_for_inode(old_parent, old_full_path);
|
||||
strcat(old_full_path, "/");
|
||||
strcat(old_full_path, old_name);
|
||||
|
||||
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 = old_parent;
|
||||
fip->new_inode = new_parent;
|
||||
strncpy(fip->name, old_name, 1024);
|
||||
strncpy(fip->new_name, new_name, 1024);
|
||||
fip->name[1023] = 0;
|
||||
fip->new_name[1023] = 0;
|
||||
fip->invoke_fuse = 1;
|
||||
fip->device_id = device_id;
|
||||
|
||||
if ((cp = strchr(new_full_path, '/')) == NULL)
|
||||
cp = "\\";
|
||||
|
||||
/* we want path minus 'root node of the share' */
|
||||
if ((cptr = strchr(old_full_path, '/')) == NULL)
|
||||
{
|
||||
/* get dev_redir to open the remote file */
|
||||
if (dev_redir_file_open((void *) fip, device_id, "\\",
|
||||
O_RDWR, S_IFREG | OP_RENAME_FILE, cp))
|
||||
{
|
||||
log_error("failed to send dev_redir_file_open() cmd");
|
||||
fuse_reply_err(req, EREMOTEIO);
|
||||
free(fip);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dev_redir_file_open((void *) fip, device_id, cptr,
|
||||
O_RDWR, S_IFREG | OP_RENAME_FILE, cp))
|
||||
{
|
||||
log_error("failed to send dev_redir_file_open() cmd");
|
||||
fuse_reply_err(req, EREMOTEIO);
|
||||
free(fip);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a directory or file
|
||||
*
|
||||
@@ -1943,7 +2199,8 @@ static void xfuse_create_dir_or_file(fuse_req_t req, fuse_ino_t parent,
|
||||
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))
|
||||
if (dev_redir_file_open((void *) fip, device_id, "\\",
|
||||
O_CREAT, type, NULL))
|
||||
{
|
||||
log_error("failed to send dev_redir_open_file() cmd");
|
||||
fuse_reply_err(req, EREMOTEIO);
|
||||
@@ -1951,7 +2208,8 @@ static void xfuse_create_dir_or_file(fuse_req_t req, fuse_ino_t parent,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dev_redir_file_open((void *) fip, device_id, cptr, O_CREAT, type))
|
||||
if (dev_redir_file_open((void *) fip, device_id, cptr,
|
||||
O_CREAT, type, NULL))
|
||||
{
|
||||
log_error("failed to send dev_redir_get_dir_listing() cmd");
|
||||
fuse_reply_err(req, EREMOTEIO);
|
||||
@@ -2021,7 +2279,7 @@ static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino,
|
||||
{
|
||||
/* get dev_redir to open the remote file */
|
||||
if (dev_redir_file_open((void *) fip, device_id, "\\",
|
||||
fi->flags, S_IFREG))
|
||||
fi->flags, S_IFREG, NULL))
|
||||
{
|
||||
log_error("failed to send dev_redir_open_file() cmd");
|
||||
fuse_reply_err(req, EREMOTEIO);
|
||||
@@ -2030,7 +2288,7 @@ static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino,
|
||||
else
|
||||
{
|
||||
if (dev_redir_file_open((void *) fip, device_id, cptr,
|
||||
fi->flags, S_IFREG))
|
||||
fi->flags, S_IFREG, NULL))
|
||||
{
|
||||
log_error("failed to send dev_redir_get_dir_listing() cmd");
|
||||
fuse_reply_err(req, EREMOTEIO);
|
||||
|
||||
@@ -58,6 +58,7 @@ 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_rename_file(void *vp, tui32 IoStatus);
|
||||
void xfuse_devredir_cb_file_close(void *vp);
|
||||
|
||||
#endif
|
||||
|
||||
+178
-83
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* xrdp device redirection - only drive redirection is currently supported
|
||||
*
|
||||
* 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.
|
||||
@@ -662,87 +662,99 @@ 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)
|
||||
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 */
|
||||
/* that does not exist; let FUSE know */
|
||||
fuse_data = dev_redir_fuse_data_dequeue(irp);
|
||||
if (fuse_data)
|
||||
{
|
||||
/* 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;
|
||||
xfuse_devredir_cb_enum_dir_done(fuse_data->data_ptr,
|
||||
IoStatus);
|
||||
free(fuse_data);
|
||||
}
|
||||
|
||||
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:
|
||||
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);
|
||||
break;
|
||||
|
||||
case CID_CLOSE:
|
||||
log_debug("got CID_CLOSE");
|
||||
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");
|
||||
|
||||
dev_redir_proc_query_dir_response(irp, s, DeviceId,
|
||||
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;
|
||||
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;
|
||||
|
||||
default:
|
||||
log_error("got unknown CompletionID: DeviceId=0x%x "
|
||||
"CompletionId=0x%x IoStatus=0x%x",
|
||||
DeviceId, CompletionId, IoStatus);
|
||||
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:
|
||||
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);
|
||||
break;
|
||||
|
||||
case CID_CLOSE:
|
||||
log_debug("got CID_CLOSE");
|
||||
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");
|
||||
|
||||
dev_redir_proc_query_dir_response(irp, s, DeviceId,
|
||||
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;
|
||||
|
||||
case CID_RENAME_FILE:
|
||||
log_debug("got CID_RENAME_FILE");
|
||||
stream_rd_u32_le(s, irp->FileId);
|
||||
devredir_proc_cid_rename_file(irp, IoStatus);
|
||||
return;
|
||||
break;
|
||||
|
||||
case CID_RENAME_FILE_RESP:
|
||||
log_debug("got CID_RENAME_FILE_RESP");
|
||||
devredir_proc_cid_rename_file_resp(irp, IoStatus);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("got unknown CompletionID: DeviceId=0x%x "
|
||||
"CompletionId=0x%x IoStatus=0x%x",
|
||||
DeviceId, CompletionId, IoStatus);
|
||||
break;
|
||||
}
|
||||
|
||||
if (fuse_data)
|
||||
@@ -898,32 +910,40 @@ 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 mode, int type, char *gen_buf)
|
||||
{
|
||||
tui32 DesiredAccess;
|
||||
tui32 CreateOptions;
|
||||
tui32 CreateDisposition;
|
||||
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;
|
||||
|
||||
if (type & OP_RENAME_FILE)
|
||||
{
|
||||
irp->completion_type = CID_RENAME_FILE;
|
||||
strcpy(irp->gen_buf, gen_buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
irp->completion_type = CID_CREATE_OPEN_REQ;
|
||||
}
|
||||
|
||||
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");
|
||||
log_debug("open file in O_CREAT");
|
||||
DesiredAccess = DA_FILE_READ_DATA | DA_FILE_WRITE_DATA | DA_SYNCHRONIZE;
|
||||
|
||||
if (type == S_IFDIR)
|
||||
if (type & S_IFDIR)
|
||||
{
|
||||
log_debug("creating dir");
|
||||
CreateOptions = CO_FILE_DIRECTORY_FILE | CO_FILE_SYNCHRONOUS_IO_NONALERT;
|
||||
@@ -1471,3 +1491,78 @@ void devredir_proc_cid_rmdir_or_file_resp(IRP *irp, tui32 IoStatus)
|
||||
irp->completion_id,
|
||||
IRP_MJ_CLOSE, 0, 32);
|
||||
}
|
||||
|
||||
void devredir_proc_cid_rename_file(IRP *irp, tui32 IoStatus)
|
||||
{
|
||||
struct stream *s;
|
||||
int bytes;
|
||||
int sblen; /* SetBuffer length */
|
||||
int flen; /*FileNameLength */
|
||||
|
||||
|
||||
if (IoStatus != NT_STATUS_SUCCESS)
|
||||
{
|
||||
FUSE_DATA *fuse_data = dev_redir_fuse_data_dequeue(irp);
|
||||
if (fuse_data)
|
||||
{
|
||||
xfuse_devredir_cb_rename_file(fuse_data->data_ptr, IoStatus);
|
||||
free(fuse_data);
|
||||
}
|
||||
dev_redir_irp_delete(irp);
|
||||
return;
|
||||
}
|
||||
|
||||
stream_new(s, 1024);
|
||||
|
||||
irp->completion_type = CID_RENAME_FILE_RESP;
|
||||
dev_redir_insert_dev_io_req_header(s, irp->device_id, irp->FileId,
|
||||
irp->completion_id,
|
||||
IRP_MJ_SET_INFORMATION, 0);
|
||||
|
||||
flen = strlen(irp->gen_buf) * 2 + 2;
|
||||
sblen = 6 + flen;
|
||||
|
||||
stream_wr_u32_le(s, FileRenameInformation);
|
||||
stream_wr_u32_le(s, sblen); /* Length */
|
||||
stream_seek(s, 24); /* padding */
|
||||
stream_wr_u8(s, 1); /* ReplaceIfExists */
|
||||
stream_wr_u8(s, 0); /* RootDirectory */
|
||||
stream_wr_u32_le(s, flen); /* FileNameLength */
|
||||
|
||||
/* filename in unicode */
|
||||
devredir_cvt_to_unicode(s->p, irp->gen_buf);
|
||||
stream_seek(s, flen);
|
||||
|
||||
/* 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_rename_file_resp(IRP *irp, tui32 IoStatus)
|
||||
{
|
||||
FUSE_DATA *fuse_data;
|
||||
|
||||
fuse_data = dev_redir_fuse_data_dequeue(irp);
|
||||
if (fuse_data)
|
||||
{
|
||||
xfuse_devredir_cb_rename_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);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* xrdp device redirection - we mainly use it for drive redirection
|
||||
*
|
||||
* 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.
|
||||
@@ -53,8 +53,8 @@ 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 */
|
||||
char gen_buf[1024]; /* for general use */
|
||||
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 */
|
||||
@@ -131,12 +131,14 @@ void dev_redir_insert_rdpdr_header(struct stream *s, tui16 Component,
|
||||
|
||||
void devredir_proc_cid_rmdir_or_file(IRP *irp, tui32 IoStatus);
|
||||
void devredir_proc_cid_rmdir_or_file_resp(IRP *irp, tui32 IoStatus);
|
||||
void devredir_proc_cid_rename_file(IRP *irp, tui32 IoStatus);
|
||||
void devredir_proc_cid_rename_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 mode, int type, char *gen_buf);
|
||||
|
||||
int devredir_file_close(void *fusep, tui32 device_id, tui32 file_id);
|
||||
|
||||
@@ -149,7 +151,7 @@ int dev_redir_file_read(void *fusep, tui32 device_id, tui32 FileId,
|
||||
#define LOG_DEBUG 2
|
||||
|
||||
#ifndef LOG_LEVEL
|
||||
#define LOG_LEVEL LOG_DEBUG
|
||||
#define LOG_LEVEL LOG_ERROR
|
||||
#endif
|
||||
|
||||
#define log_error(_params...) \
|
||||
@@ -356,7 +358,9 @@ enum COMPLETION_ID
|
||||
CID_CLOSE,
|
||||
CID_FILE_CLOSE,
|
||||
CID_RMDIR_OR_FILE,
|
||||
CID_RMDIR_OR_FILE_RESP
|
||||
CID_RMDIR_OR_FILE_RESP,
|
||||
CID_RENAME_FILE,
|
||||
CID_RENAME_FILE_RESP
|
||||
};
|
||||
|
||||
enum FS_INFORMATION_CLASS
|
||||
@@ -407,4 +411,6 @@ enum FS_INFORMATION_CLASS
|
||||
#define EPOCH_DIFF 11644473600LL
|
||||
#define WINDOWS_TO_LINUX_TIME(_t) ((_t) / 10000000) - EPOCH_DIFF;
|
||||
|
||||
#define OP_RENAME_FILE 0x01
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user