Merge pull request #1507 from matt335672/drive-redirect-fixes

Drive redirect fixes, including Guacamole
This commit is contained in:
metalefty 2020-03-11 09:33:24 +09:00 committed by GitHub
commit a57e77753f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 140 additions and 98 deletions

View File

@ -36,7 +36,8 @@ enum NTSTATUS
STATUS_ACCESS_DENIED = 0xc0000022,
STATUS_OBJECT_NAME_INVALID = 0xc0000033,
STATUS_OBJECT_NAME_NOT_FOUND = 0xc0000034,
STATUS_SHARING_VIOLATION = 0xc0000043
STATUS_SHARING_VIOLATION = 0xc0000043,
STATUS_NOT_SUPPORTED = 0xc00000bb
};
#endif /* MS_ERREF_H */

View File

@ -78,6 +78,7 @@ void xfuse_devredir_cb_open_file(struct state_open *fip,
tui32 DeviceId, tui32 FileId)
{}
void xfuse_devredir_cb_read_file(struct state_read *fip,
enum NTSTATUS IoStatus,
const char *buf, size_t length)
{}
void xfuse_devredir_cb_write_file(
@ -637,6 +638,7 @@ int xfuse_create_share(tui32 device_id, const char *dirname)
}
else
{
xinode->is_redirected = 1;
xinode->device_id = device_id;
result = 0;
}
@ -653,7 +655,7 @@ int xfuse_create_share(tui32 device_id, const char *dirname)
void xfuse_delete_share(tui32 device_id)
{
xfs_delete_entries_with_device_id(g_xfs, device_id);
xfs_delete_redirected_entries_with_device_id(g_xfs, device_id);
}
/**
@ -1313,9 +1315,18 @@ void xfuse_devredir_cb_open_file(struct state_open *fip,
}
void xfuse_devredir_cb_read_file(struct state_read *fip,
enum NTSTATUS IoStatus,
const char *buf, size_t length)
{
fuse_reply_buf(fip->req, buf, length);
if (IoStatus != STATUS_SUCCESS)
{
log_error("Read NTSTATUS is %d", (int) IoStatus);
fuse_reply_err(fip->req, EIO);
}
else
{
fuse_reply_buf(fip->req, buf, length);
}
free(fip);
}
@ -1438,7 +1449,7 @@ static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
}
else
{
if (parent_xinode->device_id == 0)
if (!parent_xinode->is_redirected)
{
/* File cannot be remote - we either know about it or we don't */
if ((xinode = xfs_lookup_in_dir(g_xfs, parent, name)) != NULL)
@ -1673,13 +1684,13 @@ static void xfuse_cb_unlink(fuse_req_t req, fuse_ino_t parent,
fuse_reply_err(req, ENOTEMPTY);
}
else if (xinode->device_id == 0)
else if (!xinode->is_redirected)
{
/* specified file is a local resource */
//XFUSE_HANDLE *fh;
log_debug("LK_TODO: this is still a TODO");
fuse_reply_err(req, EINVAL);
fuse_reply_err(req, EROFS);
}
else
{
@ -1744,26 +1755,27 @@ static void xfuse_cb_rename(fuse_req_t req,
else if (!(new_parent_xinode = xfs_get(g_xfs, new_parent)))
{
log_error("inode %ld is not valid", new_parent);
fuse_reply_err(req, EINVAL);
fuse_reply_err(req, ENOENT);
}
else if (!xfs_check_move_entry(g_xfs, old_xinode->inum,
new_parent, new_name))
{
/* Catchall -see rename(2). Fix when logging is improved */
fuse_reply_err(req, EINVAL);
}
else if (new_parent_xinode->device_id != old_xinode->device_id)
else if (new_parent_xinode->is_redirected != old_xinode->is_redirected ||
new_parent_xinode->device_id != old_xinode->device_id)
{
log_error("rename across file systems not supported");
fuse_reply_err(req, EINVAL);
fuse_reply_err(req, EXDEV);
}
else if (old_xinode->device_id == 0)
else if (!old_xinode->is_redirected)
{
/* specified file is a local resource */
log_debug("LK_TODO: this is still a TODO");
fuse_reply_err(req, EINVAL);
fuse_reply_err(req, EROFS);
}
else
@ -1853,20 +1865,25 @@ static void xfuse_create_dir_or_file(fuse_req_t req, fuse_ino_t parent,
}
/* is parent inode valid? */
if (parent == FUSE_ROOT_ID ||
(xinode = xfs_get(g_xfs, parent)) == NULL ||
(xinode->mode & S_IFDIR) == 0)
if (parent == FUSE_ROOT_ID)
{
fuse_reply_err(req, EROFS);
}
else if ((xinode = xfs_get(g_xfs, parent)) == NULL)
{
log_error("inode %ld is not valid", parent);
fuse_reply_err(req, ENOENT);
}
else if (xinode->device_id == 0)
else if ((xinode->mode & S_IFDIR) == 0)
{
fuse_reply_err(req, ENOTDIR);
}
else if (!xinode->is_redirected)
{
/* specified file is a local resource */
//XFUSE_HANDLE *fh;
log_debug("LK_TODO: this is still a TODO");
fuse_reply_err(req, EINVAL);
fuse_reply_err(req, EROFS);
}
else
{
@ -1945,13 +1962,20 @@ static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino,
log_debug("Invalid access mode specified");
fuse_reply_err(req, EINVAL);
}
else if (xinode->device_id == 0)
else if (!xinode->is_redirected)
{
/* specified file is a local resource */
XFUSE_HANDLE *fh = g_new0(XFUSE_HANDLE, 1);
fh->is_loc_resource = 1;
fi->fh = (tintptr) fh;
fuse_reply_open(req, fi);
if ((fi->flags & O_ACCMODE) != O_RDONLY)
{
fuse_reply_err(req, EROFS);
}
else
{
XFUSE_HANDLE *fh = g_new0(XFUSE_HANDLE, 1);
fh->is_loc_resource = 1;
fi->fh = (tintptr) fh;
fuse_reply_open(req, fi);
}
}
else
{
@ -2017,7 +2041,7 @@ static void xfuse_cb_release(fuse_req_t req, fuse_ino_t ino, struct
log_error("inode %ld is not valid", ino);
fuse_reply_err(req, ENOENT);
}
else if (xinode->device_id == 0)
else if (!xinode->is_redirected)
{
/* specified file is a local resource */
fuse_reply_err(req, 0);
@ -2153,7 +2177,7 @@ static void xfuse_cb_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
{
/* target file is in .clipboard dir */
log_debug("THIS IS STILL A TODO!");
fuse_reply_err(req, EINVAL);
fuse_reply_err(req, EROFS);
}
else
{
@ -2283,7 +2307,7 @@ static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
/* No changes have been made */
make_fuse_attr_reply(req, xinode);
}
else if (xinode->device_id == 0)
else if (!xinode->is_redirected)
{
/* Update the local fs */
update_inode_file_attributes(&attrs, change_mask, xinode);
@ -2349,7 +2373,7 @@ static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino,
log_error("inode %ld is not valid", ino);
fuse_reply_err(req, ENOENT);
}
else if (xinode->device_id == 0)
else if (!xinode->is_redirected)
{
if ((fi->fh = (tintptr) xfs_opendir(g_xfs, ino)) == 0)
{

View File

@ -98,6 +98,7 @@ void xfuse_devredir_cb_open_file(struct state_open *fip,
tui32 DeviceId, tui32 FileId);
void xfuse_devredir_cb_read_file(struct state_read *fip,
enum NTSTATUS IoStatus,
const char *buf, size_t length);
void xfuse_devredir_cb_write_file(
struct state_write *fip,

View File

@ -344,6 +344,7 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
xino1->pub.ctime = xino1->pub.atime;
strcpy(xino1->pub.name, ".");
xino1->pub.generation = xfs->generation;
xino1->pub.is_redirected = 0;
xino1->pub.device_id = 0;
/*
@ -365,6 +366,7 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
xino2->pub.ctime = xino2->pub.atime;
strcpy(xino2->pub.name, ".delete-pending");
xino2->pub.generation = xfs->generation;
xino2->pub.is_redirected = 0;
xino2->pub.device_id = 0;
xino2->parent = NULL;
@ -469,6 +471,7 @@ xfs_add_entry(struct xfs_fs *xfs, fuse_ino_t parent_inum,
xino->pub.ctime = xino->pub.atime;
strcpy(xino->pub.name, name);
xino->pub.generation = xfs->generation;
xino->pub.is_redirected = parent->pub.is_redirected;
xino->pub.device_id = parent->pub.device_id;
xino->pub.lindex = 0;
@ -565,7 +568,7 @@ xfs_get_full_path(struct xfs_fs *xfs, fuse_ino_t inum)
*/
size_t len = 0;
XFS_INODE_ALL *p;
for (p = xino ; p->pub.inum != FUSE_ROOT_ID ; p = p->parent)
for (p = xino ; p && p->pub.inum != FUSE_ROOT_ID ; p = p->parent)
{
len += strlen(p->pub.name);
++len; /* Allow for '/' prefix */
@ -578,7 +581,7 @@ xfs_get_full_path(struct xfs_fs *xfs, fuse_ino_t inum)
char *end = result + len;
*end = '\0';
for (p = xino ; p->pub.inum != FUSE_ROOT_ID ; p = p->parent)
for (p = xino ; p && p->pub.inum != FUSE_ROOT_ID ; p = p->parent)
{
len = strlen(p->pub.name);
end -= (len + 1);
@ -816,35 +819,35 @@ xfs_get_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum)
/* ------------------------------------------------------------------------ */
void
xfs_delete_entries_with_device_id(struct xfs_fs *xfs, tui32 device_id)
xfs_delete_redirected_entries_with_device_id(struct xfs_fs *xfs,
tui32 device_id)
{
fuse_ino_t inum;
XFS_INODE_ALL *xino;
if (device_id != 0)
/* Using xfs_remove_entry() is convenient, but it recurses
* in to directories. To make sure all entries are removed, set the
* open_count of all affected files to 0 first
*/
for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum)
{
/* Using xfs_remove_entry() is convenient, but it recurses
* in to directories. To make sure all entries are removed, set the
* open_count of all affected files to 0 first
*/
for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum)
if ((xino = xfs->inode_table[inum]) != NULL &&
xino->pub.is_redirected != 0 &&
xino->pub.device_id == device_id &&
(xino->pub.mode & S_IFREG) != 0)
{
if ((xino = xfs->inode_table[inum]) != NULL &&
xino->pub.device_id == device_id &&
(xino->pub.mode & S_IFREG) != 0)
{
xino->open_count = 0;
}
xino->open_count = 0;
}
}
/* Now we can be sure everything will be deleted correctly */
for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum)
/* Now we can be sure everything will be deleted correctly */
for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum)
{
if ((xino = xfs->inode_table[inum]) != NULL &&
xino->pub.is_redirected != 0 &&
xino->pub.device_id == device_id)
{
if ((xino = xfs->inode_table[inum]) != NULL &&
xino->pub.device_id == device_id)
{
xfs_remove_entry(xfs, xino->pub.inum);
}
xfs_remove_entry(xfs, xino->pub.inum);
}
}
}

View File

@ -49,9 +49,8 @@ typedef struct xfs_inode
time_t ctime; /* Time of last status change. */
char name[XFS_MAXFILENAMELEN + 1]; /* Short name */
tui32 generation; /* Changes if inode is reused */
tui32 device_id; /* for file system redirection
* Non-redirected devices are guaranteed
* to have a device_id or zero */
char is_redirected; /* file is on redirected device */
tui32 device_id; /* device ID of redirected device */
int lindex; /* used in clipboard operations */
} XFS_INODE;
@ -271,17 +270,15 @@ unsigned int
xfs_get_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum);
/*
* Deletes all entries with the matching device id
* Deletes all redirected entries with the matching device id
*
* Files are deleted even if they are open
*
* The specified device_id must be non-zero so that the root
* filesystem is not deleted!
*
* @param device_id Device ID
*/
void
xfs_delete_entries_with_device_id(struct xfs_fs *xfs, tui32 device_id);
xfs_delete_redirected_entries_with_device_id(struct xfs_fs *xfs,
tui32 device_id);
/*
* Check an entry move will be successful

View File

@ -560,7 +560,8 @@ devredir_send_server_user_logged_on(void)
}
static void
devredir_send_server_device_announce_resp(tui32 device_id)
devredir_send_server_device_announce_resp(tui32 device_id,
enum NTSTATUS result_code)
{
struct stream *s;
int bytes;
@ -571,7 +572,7 @@ devredir_send_server_device_announce_resp(tui32 device_id)
xstream_wr_u16_le(s, RDPDR_CTYP_CORE);
xstream_wr_u16_le(s, PAKID_CORE_DEVICE_REPLY);
xstream_wr_u32_le(s, device_id);
xstream_wr_u32_le(s, 0); /* ResultCode */
xstream_wr_u32_le(s, (tui32)result_code);
/* send to client */
bytes = xstream_len(s);
@ -811,6 +812,7 @@ devredir_proc_client_devlist_announce_req(struct stream *s)
tui32 device_type;
tui32 device_data_len;
char preferred_dos_name[9];
enum NTSTATUS response_status;
/* get number of devices being announced */
xstream_rd_u32_le(s, device_count);
@ -821,19 +823,20 @@ devredir_proc_client_devlist_announce_req(struct stream *s)
{
xstream_rd_u32_le(s, device_type);
xstream_rd_u32_le(s, g_device_id);
/* get preferred DOS name
* DOS names that are 8 chars long are not NULL terminated */
for (j = 0; j < 8; j++)
{
preferred_dos_name[j] = *s->p++;
}
preferred_dos_name[8] = 0;
/* Assume this device isn't supported by us */
response_status = STATUS_NOT_SUPPORTED;
switch (device_type)
{
case RDPDR_DTYP_FILESYSTEM:
/* get preferred DOS name */
for (j = 0; j < 8; j++)
{
preferred_dos_name[j] = *s->p++;
}
/* DOS names that are 8 chars long are not NULL terminated */
preferred_dos_name[8] = 0;
/* get device data len */
xstream_rd_u32_le(s, device_data_len);
if (device_data_len)
@ -847,7 +850,7 @@ devredir_proc_client_devlist_announce_req(struct stream *s)
preferred_dos_name,
device_data_len, g_full_name_for_filesystem);
devredir_send_server_device_announce_resp(g_device_id);
response_status = STATUS_SUCCESS;
/* create share directory in xrdp file system; */
/* think of this as the mount point for this share */
@ -855,31 +858,44 @@ devredir_proc_client_devlist_announce_req(struct stream *s)
break;
case RDPDR_DTYP_SMARTCARD:
/* get preferred DOS name */
for (j = 0; j < 8; j++)
{
preferred_dos_name[j] = *s->p++;
}
/* DOS names that are 8 chars long are not NULL terminated */
preferred_dos_name[8] = 0;
/* for smart cards, device data len always 0 */
log_debug("device_type=SMARTCARD device_id=0x%x dosname=%s",
g_device_id, preferred_dos_name);
devredir_send_server_device_announce_resp(g_device_id);
response_status = STATUS_SUCCESS;
scard_device_announce(g_device_id);
break;
/* we don't yet support these devices */
case RDPDR_DTYP_SERIAL:
log_debug(
"device_type=SERIAL device_id=0x%x dosname=%s",
g_device_id, preferred_dos_name);
break;
case RDPDR_DTYP_PARALLEL:
log_debug(
"device_type=PARALLEL device_id=0x%x dosname=%s",
g_device_id, preferred_dos_name);
break;
case RDPDR_DTYP_PRINT:
log_debug("unsupported dev: 0x%x", device_type);
log_debug(
"device_type=PRINT device_id=0x%x dosname=%s",
g_device_id, preferred_dos_name);
break;
default:
log_debug(
"device_type=UNKNOWN device_id=0x%x dosname=%s",
g_device_id, preferred_dos_name);
break;
}
/* Tell the client wheth or not we're supporting this one */
devredir_send_server_device_announce_resp(g_device_id,
response_status);
}
}
@ -993,6 +1009,7 @@ devredir_proc_device_iocompletion(struct stream *s)
case CID_READ:
xstream_rd_u32_le(s, Length);
xfuse_devredir_cb_read_file((struct state_read *) irp->fuse_info,
IoStatus,
s->p, Length);
devredir_irp_delete(irp);
break;
@ -1511,10 +1528,10 @@ devredir_rmdir_or_file(struct state_remove *fusep, tui32 device_id,
/**
* Read data from previously opened file
*
* @return 0 on success, -1 on failure
* Errors are reported via xfuse_devredir_cb_read_file()
*****************************************************************************/
int
void
devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId,
tui32 Length, tui64 Offset)
{
@ -1522,7 +1539,6 @@ devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId,
IRP *irp;
IRP *new_irp;
int bytes;
int rval = -1;
xstream_new(s, 1024);
@ -1530,14 +1546,14 @@ devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId,
if ((irp = devredir_irp_find_by_fileid(FileId)) == NULL)
{
log_error("no IRP found with FileId = %d", FileId);
xfuse_devredir_cb_read_file(fusep, NULL, 0);
xfuse_devredir_cb_read_file(fusep, STATUS_UNSUCCESSFUL, NULL, 0);
xstream_free(s);
}
/* create a new IRP for this request */
else if ((new_irp = devredir_irp_new()) == NULL)
{
/* system out of memory */
xfuse_devredir_cb_read_file(fusep, NULL, 0);
xfuse_devredir_cb_read_file(fusep, STATUS_UNSUCCESSFUL, NULL, 0);
xstream_free(s);
}
else
@ -1563,13 +1579,16 @@ devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId,
bytes = xstream_len(s);
send_channel_data(g_rdpdr_chan_id, s->data, bytes);
xstream_free(s);
rval = 0;
}
return rval;
}
int
/**
* Read data from previously opened file
*
* Errors are reported via xfuse_devredir_cb_write_file()
*****************************************************************************/
void
devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId,
const char *buf, int Length, tui64 Offset)
{
@ -1577,7 +1596,6 @@ devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId,
IRP *irp;
IRP *new_irp;
int bytes;
int rval = -1;
log_debug("DeviceId=%d FileId=%d Length=%d Offset=%lld",
DeviceId, FileId, Length, (long long)Offset);
@ -1625,10 +1643,7 @@ devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId,
bytes = xstream_len(s);
send_channel_data(g_rdpdr_chan_id, s->data, bytes);
xstream_free(s);
rval = 0;
}
return rval;
}

View File

@ -78,12 +78,13 @@ int devredir_file_open(struct state_open *fusep, tui32 device_id,
int devredir_file_close(struct state_close *fusep, tui32 device_id,
tui32 file_id);
int devredir_file_read(struct state_read *fusep, tui32 device_id, tui32 FileId,
tui32 Length, tui64 Offset);
void
devredir_file_read(struct state_read *fusep, tui32 device_id, tui32 FileId,
tui32 Length, tui64 Offset);
int
void
devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId,
const char *buf, int Length, tui64 Offset);
const char *buf, int Length, tui64 Offset);
int devredir_file_rename(
struct state_rename *fusep, tui32 device_id,