diff --git a/sesman/chansrv/chansrv_fuse.c b/sesman/chansrv/chansrv_fuse.c index be7bb7c9..6256ccf9 100644 --- a/sesman/chansrv/chansrv_fuse.c +++ b/sesman/chansrv/chansrv_fuse.c @@ -72,7 +72,7 @@ int xfuse_file_contents_size(int stream_id, int file_size) { r int xfuse_add_clip_dir_item(const char *filename, int flags, int size, int lindex) { return 0; } int xfuse_create_share(tui32 device_id, const char *dirname) { return 0; } void xfuse_devredir_cb_open_file(void *vp, tui32 IoStatus, tui32 DeviceId, tui32 FileId) {} -void xfuse_devredir_cb_write_file(void *vp, const char *buf, size_t length) {} +void xfuse_devredir_cb_write_file(void *vp, tui32 IoStatus, const char *buf, size_t length) {} void xfuse_devredir_cb_read_file(void *vp, const char *buf, size_t length) {} int xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) { return 0; } void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus) {} @@ -1639,12 +1639,12 @@ void xfuse_devredir_cb_open_file(void *vp, tui32 IoStatus, tui32 DeviceId, { switch (IoStatus) { - case 0xC0000022: + case NT_STATUS_ACCESS_DENIED: fuse_reply_err(fip->req, EACCES); break; - case 0xC0000033: - case 0xC0000034: + case NT_STATUS_OBJECT_NAME_INVALID: + case NT_STATUS_OBJECT_NAME_NOT_FOUND: fuse_reply_err(fip->req, ENOENT); break; @@ -1762,7 +1762,10 @@ void xfuse_devredir_cb_read_file(void *vp, const char *buf, size_t length) free(fip); } -void xfuse_devredir_cb_write_file(void *vp, const char *buf, size_t length) +void xfuse_devredir_cb_write_file(void *vp, + tui32 IoStatus, + const char *buf, + size_t length) { XRDP_INODE *xinode; XFUSE_INFO *fip; @@ -1771,20 +1774,34 @@ void xfuse_devredir_cb_write_file(void *vp, const char *buf, size_t length) if ((fip == NULL) || (fip->req == NULL) || (fip->fi == NULL)) { log_error("fip, fip->req or fip->fi is NULL"); - return; } - - log_debug("+++ XFUSE_INFO=%p, XFUSE_INFO->fi=%p XFUSE_INFO->fi->fh=0x%llx", - fip, fip->fi, (long long) fip->fi->fh); - - fuse_reply_write(fip->req, length); - - /* update file size */ - if ((xinode = g_xrdp_fs.inode_table[fip->inode]) != NULL) - xinode->size += length; else - log_error("inode at inode_table[%ld] is NULL", fip->inode); + { + log_debug( + "+++ XFUSE_INFO=%p, XFUSE_INFO->fi=%p XFUSE_INFO->fi->fh=0x%llx", + fip, fip->fi, (long long) fip->fi->fh); + if (IoStatus != NT_STATUS_SUCCESS) + { + log_error("Write NTSTATUS is %d", (int) IoStatus); + fuse_reply_err(fip->req, EIO); + } + else + { + fuse_reply_write(fip->req, length); + + /* update file size */ + if ((xinode = g_xrdp_fs.inode_table[fip->inode]) != NULL) + { + xinode->size += length; + } + else + { + log_error("inode at inode_table[%ld] is NULL", fip->inode); + } + + } + } free(fip); } @@ -2551,11 +2568,24 @@ static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino, } if (xinode->mode & S_IFDIR) { - log_debug("reading a dir not allowed!"); + log_debug("reading/writing a dir not allowed!"); fuse_reply_err(req, EISDIR); return; } + switch (fi->flags & O_ACCMODE) + { + case O_RDONLY: + case O_WRONLY: + case O_RDWR: + break; + + default: + log_debug("Invalid access mode specified"); + fuse_reply_err(req, EINVAL); + return; + } + device_id = xfuse_get_device_id_for_inode(ino, full_path); if (xinode->is_loc_resource) @@ -2594,7 +2624,12 @@ static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino, { cptr = "\\"; } - /* get dev_redir to open the remote file */ + /* get dev_redir to open the remote file + * + * For a successful call, if the caller has set O_TRUNC when writing + * the file, fuse should call us back via fuse_cb_setattr() to set + * the size to zero - we don't need to do this ourselves. + */ if (dev_redir_file_open((void *) fip, device_id, cptr, fi->flags, S_IFREG, NULL)) { diff --git a/sesman/chansrv/chansrv_fuse.h b/sesman/chansrv/chansrv_fuse.h index 7183c038..945a4bef 100644 --- a/sesman/chansrv/chansrv_fuse.h +++ b/sesman/chansrv/chansrv_fuse.h @@ -58,7 +58,11 @@ int xfuse_add_clip_dir_item(const char *filename, int flags, int size, int linde int 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 IoStatus, tui32 DeviceId, tui32 FileId); -void xfuse_devredir_cb_write_file(void *vp, const char *buf, size_t length); +void xfuse_devredir_cb_write_file( + void *vp, + tui32 IoStatus, + const char *buf, + size_t length); void xfuse_devredir_cb_read_file(void *vp, const 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); diff --git a/sesman/chansrv/devredir.c b/sesman/chansrv/devredir.c index 03fcfc68..e2a29394 100644 --- a/sesman/chansrv/devredir.c +++ b/sesman/chansrv/devredir.c @@ -822,7 +822,8 @@ dev_redir_proc_device_iocompletion(struct stream *s) } else { - xfuse_devredir_cb_write_file(fuse_data->data_ptr, s->p, Length); + xfuse_devredir_cb_write_file(fuse_data->data_ptr, IoStatus, + s->p, Length); devredir_irp_delete(irp); } break; @@ -1107,14 +1108,30 @@ dev_redir_file_open(void *fusep, tui32 device_id, const char *path, } else { - log_debug("open file in O_RDWR"); #if 1 - /* without the 0x00000010 rdesktop opens files in */ - /* O_RDONLY instead of O_RDWR mode */ - if (mode & O_RDWR) - DesiredAccess = DA_FILE_READ_DATA | DA_FILE_WRITE_DATA | DA_SYNCHRONIZE | 0x00000010; - else - DesiredAccess = DA_FILE_READ_DATA | DA_SYNCHRONIZE; + switch(mode & O_ACCMODE) + { + case O_RDONLY: + log_debug("open file in O_RDONLY"); + DesiredAccess = DA_FILE_READ_DATA | DA_SYNCHRONIZE; + break; + + case O_WRONLY: + log_debug("open file in O_WRONLY"); + DesiredAccess = DA_FILE_WRITE_DATA | DA_SYNCHRONIZE; + break; + + default: + /* + * The access mode could conceivably be invalid here, + * but we assume this has been checked by the caller + */ + log_debug("open file in O_RDWR"); + /* without the 0x00000010 rdesktop opens files in */ + /* O_RDONLY instead of O_RDWR mode */ + DesiredAccess = DA_FILE_READ_DATA | DA_FILE_WRITE_DATA | + DA_SYNCHRONIZE | 0x00000010; + } CreateOptions = CO_FILE_SYNCHRONOUS_IO_NONALERT; CreateDisposition = CD_FILE_OPEN; // WAS 1 @@ -1283,7 +1300,7 @@ dev_redir_file_write(void *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_write_file(fusep, NULL, 0); + xfuse_devredir_cb_write_file(fusep, NT_STATUS_UNSUCCESSFUL, NULL, 0); xstream_free(s); return -1; } @@ -1292,7 +1309,7 @@ dev_redir_file_write(void *fusep, tui32 DeviceId, tui32 FileId, if ((new_irp = devredir_irp_clone(irp)) == NULL) { /* system out of memory */ - xfuse_devredir_cb_write_file(fusep, NULL, 0); + xfuse_devredir_cb_write_file(fusep, NT_STATUS_UNSUCCESSFUL, NULL, 0); xstream_free(s); return -1; } diff --git a/sesman/chansrv/devredir.h b/sesman/chansrv/devredir.h index 558975ff..00ed5dda 100644 --- a/sesman/chansrv/devredir.h +++ b/sesman/chansrv/devredir.h @@ -260,6 +260,9 @@ enum CREATE_OPTIONS #define NT_STATUS_SUCCESS 0x00000000 #define NT_STATUS_UNSUCCESSFUL 0xC0000001 +#define NT_STATUS_ACCESS_DENIED 0xC0000022 +#define NT_STATUS_OBJECT_NAME_INVALID 0xC0000033 +#define NT_STATUS_OBJECT_NAME_NOT_FOUND 0xC0000034 /* * File system ioctl codes