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 @@ -323,32 +334,38 @@ int send_channel_data(int chan_id, char *data, int size); #define NT_STATUS_SUCCESS 0x00000000 #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