diff options
Diffstat (limited to 'sesman/chansrv/chansrv_fuse.c')
-rw-r--r-- | sesman/chansrv/chansrv_fuse.c | 585 |
1 files changed, 327 insertions, 258 deletions
diff --git a/sesman/chansrv/chansrv_fuse.c b/sesman/chansrv/chansrv_fuse.c index 661d0bca..572679eb 100644 --- a/sesman/chansrv/chansrv_fuse.c +++ b/sesman/chansrv/chansrv_fuse.c @@ -125,6 +125,13 @@ void xfuse_devredir_cb_file_close(void *vp) {} g_writeln (_params); \ } +#define log_always(_params...) \ +{ \ + g_write("[%10.10u]: FUSE %s: %d : ALWAYS: ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ +} + #define log_info(_params...) \ { \ if (LOG_INFO <= LOG_LEVEL) \ @@ -210,6 +217,12 @@ struct req_list_item int size; }; +struct dir_info +{ + /* last index accessed in g_xrdp_fs.inode_table[] */ + int index; +}; + static struct list *g_req_list = 0; static struct xrdp_fs g_xrdp_fs; /* an inst of xrdp file system */ static char *g_mount_point = 0; /* our FUSE mount point */ @@ -249,6 +262,7 @@ 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); +static int xfuse_recursive_delete_dir_with_xinode(XRDP_INODE *xinode); static void xfuse_update_xrdpfs_size(); static void xfuse_enum_dir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi); @@ -331,6 +345,16 @@ int clipboard_request_file_data(int stream_id, int lindex, int offset, static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi); +static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + +static void xfuse_cb_releasedir(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + +/* misc calls */ +static void xfuse_mark_as_stale(int pinode); +static void xfuse_delete_stale_entries(int pinode); + /***************************************************************************** ** ** ** public functions - can be called from any code path ** @@ -381,20 +405,22 @@ int xfuse_init() /* setup FUSE callbacks */ g_memset(&g_xfuse_ops, 0, sizeof(g_xfuse_ops)); - 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.unlink = xfuse_cb_unlink; - g_xfuse_ops.rename = xfuse_cb_rename; - g_xfuse_ops.open = xfuse_cb_open; - g_xfuse_ops.release = xfuse_cb_release; - g_xfuse_ops.read = xfuse_cb_read; - g_xfuse_ops.write = xfuse_cb_write; - g_xfuse_ops.create = xfuse_cb_create; + 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.unlink = xfuse_cb_unlink; + g_xfuse_ops.rename = xfuse_cb_rename; + g_xfuse_ops.open = xfuse_cb_open; + g_xfuse_ops.release = xfuse_cb_release; + g_xfuse_ops.read = xfuse_cb_read; + g_xfuse_ops.write = xfuse_cb_write; + g_xfuse_ops.create = xfuse_cb_create; //g_xfuse_ops.fsync = xfuse_cb_fsync; /* LK_TODO delete this */ - g_xfuse_ops.getattr = xfuse_cb_getattr; - g_xfuse_ops.setattr = xfuse_cb_setattr; + g_xfuse_ops.getattr = xfuse_cb_getattr; + g_xfuse_ops.setattr = xfuse_cb_setattr; + g_xfuse_ops.opendir = xfuse_cb_opendir; + g_xfuse_ops.releasedir = xfuse_cb_releasedir; fuse_opt_add_arg(&args, "xrdp-chansrv"); fuse_opt_add_arg(&args, g_fuse_root_path); @@ -1160,9 +1186,6 @@ static struct xrdp_inode * xfuse_create_file_in_xrdp_fs(tui32 device_id, log_debug("incremented nentries; parent=%d nentries=%d", pinode, xinodep->nentries); - /* LK_TODO */ - xfuse_dump_fs(); - return xinode; } @@ -1245,6 +1268,52 @@ static int xfuse_delete_dir_with_xinode(XRDP_INODE *xinode) return 0; } +/** + * Recursively delete dir with specified inode + *****************************************************************************/ + +static int xfuse_recursive_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 */ + if (xip->mode & S_IFREG) + { + /* regular file */ + g_xrdp_fs.inode_table[xip->parent_inode]->nentries--; + g_xrdp_fs.inode_table[xip->inode] = NULL; + free(xip); + } + else + { + /* got another dir */ + xfuse_recursive_delete_dir_with_xinode(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; +} + static void xfuse_update_xrdpfs_size() { void *vp; @@ -1273,6 +1342,8 @@ static void xfuse_update_xrdpfs_size() g_xrdp_fs.inode_table = vp; } +/* LK_TODO do we still need this function */ +#if 0 static void xfuse_enum_dir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { @@ -1323,6 +1394,7 @@ static void xfuse_enum_dir(fuse_req_t req, fuse_ino_t ino, size_t size, if (b.p) free(b.p); } +#endif /****************************************************************************** ** ** @@ -1336,8 +1408,8 @@ static void xfuse_enum_dir(fuse_req_t req, fuse_ino_t ino, size_t size, void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) { - XFUSE_INFO *fip = (XFUSE_INFO *) vp; - XRDP_INODE *xip = NULL; + XFUSE_INFO *fip = (XFUSE_INFO *) vp; + XRDP_INODE *xip = NULL; if ((fip == NULL) || (xinode == NULL)) { @@ -1345,14 +1417,14 @@ void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) return; } - log_debug("fip->req=%p", fip->req); - if (!xfuse_is_inode_valid(fip->inode)) { log_error("inode %d is not valid", fip->inode); return; } + log_debug("parent_inode=%d name=%s", fip->inode, xinode->name); + /* if filename is . or .. don't add it */ if ((strcmp(xinode->name, ".") == 0) || (strcmp(xinode->name, "..") == 0)) { @@ -1360,12 +1432,14 @@ void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) return; } + xfuse_dump_fs(); + if ((xip = xfuse_get_inode_from_pinode_name(fip->inode, xinode->name)) != NULL) { log_debug("inode=%d name=%s already exists in xrdp_fs; not adding it", fip->inode, xinode->name); free(xinode); - xinode = xip; + xip->stale = 0; return; } @@ -1379,8 +1453,10 @@ void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) /* insert it in xrdp fs and update lookup count */ g_xrdp_fs.inode_table[xinode->inode] = xinode; - g_xrdp_fs.inode_table[fip->inode]->nentries++; /* this was missing */ + g_xrdp_fs.inode_table[fip->inode]->nentries++; xfuse_update_xrdpfs_size(); + + xfuse_dump_fs(); } /** @@ -1388,27 +1464,18 @@ void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus) { - log_debug(">>>>>> vp=%p IoStatus=0x%x", vp, IoStatus); + XFUSE_INFO *fip; + struct dir_info *di; - if (vp == NULL) - return; - - XRDP_INODE *xinode; - XRDP_INODE *ti; - struct dirbuf1 b; - int i; - int first_time = 1; - - XFUSE_INFO *fip = (XFUSE_INFO *) vp; + log_debug("vp=%p IoStatus=0x%x", vp, IoStatus); + fip = (XFUSE_INFO *) vp; if (fip == NULL) { log_debug("fip is NULL"); - goto done; + return; } - log_debug("fip->req=%p", fip->req); - if (IoStatus != 0) { /* command failed */ @@ -1425,168 +1492,22 @@ void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus) fuse_reply_err(fip->req, EBADF); goto done; } -#if 0 - memset(&b, 0, sizeof(struct dirbuf)); -#else - b.bytes_in_buf = 0; -#endif - for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) - { - if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) - continue; - /* match parent inode */ - if (xinode->parent_inode != fip->inode) - continue; + xfuse_delete_stale_entries(fip->inode); - xinode->is_synced = 1; + /* this will be used by xfuse_cb_readdir() */ + di = calloc(1, sizeof(struct dir_info)); + di->index = FIRST_INODE; + fip->fi->fh = (long) di; - if (first_time) - { - first_time = 0; - ti = g_xrdp_fs.inode_table[fip->inode]; -#if 0 - xfuse_dirbuf_add(fip->req, &b, ".", fip->inode); - xfuse_dirbuf_add(fip->req, &b, "..", ti->parent_inode); -#else - xfuse_dirbuf_add1(fip->req, &b, ".", fip->inode); - xfuse_dirbuf_add1(fip->req, &b, "..", ti->parent_inode); -#endif - } -#if 0 - xfuse_dirbuf_add(fip->req, &b, xinode->name, xinode->inode); -#else - xfuse_dirbuf_add1(fip->req, &b, xinode->name, xinode->inode); -#endif - } - - if ((first_time == 0) && (fip->invoke_fuse)) - { - if (fip->off < b.bytes_in_buf) - { -#if 0 - fuse_reply_buf(fip->req, b.p + fip->off, - min(b.size - fip->off, fip->size)); -#else - log_debug("calling fuse_reply_buf() with data..."); - fuse_reply_buf(fip->req, b.buf, b.bytes_in_buf); - log_debug("calling fuse_reply_buf() with data...done"); -#endif - } - else - { - log_debug("calling fuse_reply_buf() with NULL..."); - fuse_reply_buf(fip->req, NULL, 0); - log_debug("calling fuse_reply_buf() with NULL...done"); - } - } - else - { - log_debug("calling fuse_reply_err()..."); - fuse_reply_err(fip->req, ENOENT); - log_debug("calling fuse_reply_err()...done"); - } + fuse_reply_open(fip->req, fip->fi); done: -#if 0 - if (b.p) - free(b.p); -#endif - - if (!fip) - printf("###### %s : %s : %d: fip is NULL\n", __FILE__, __func__, __LINE__); - if (fip) free(fip); } -void xfuse_devredir_cb_enum_dir_done_TODO(void *vp, tui32 IoStatus) -{ - struct xrdp_inode *xinode; - struct fuse_entry_param e; - int i; - - XFUSE_INFO *fip = (XFUSE_INFO *) vp; - - printf("--------- xfuse_devredir_cb_enum_dir_done() entered\n"); - - xfuse_dump_fs(); - - if (fip == NULL) - { - log_debug("fip is NULL"); - goto done; - } - - if (IoStatus != 0) - { - /* command failed */ - if (fip->invoke_fuse) - fuse_reply_err(fip->req, ENOENT); - goto done; - } - - /* do we have a valid inode? */ - if (!xfuse_is_inode_valid(fip->inode)) - { - log_error("inode %d is not valid", fip->inode); - if (fip->invoke_fuse) - fuse_reply_err(fip->req, EBADF); - goto done; - } - - log_debug("looking for parent_inode=%d name=%s", fip->inode, fip->name); - - for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) - { - if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) - continue; - - /* match parent inode */ - if (xinode->parent_inode != fip->inode) - continue; - - /* match name */ - if (strcmp(xinode->name, fip->name) != 0) - continue; - - memset(&e, 0, sizeof(e)); - e.ino = xinode->inode; - e.attr_timeout = XFUSE_ATTR_TIMEOUT; - e.entry_timeout = XFUSE_ENTRY_TIMEOUT; - e.attr.st_ino = xinode->inode; - e.attr.st_mode = xinode->mode; - e.attr.st_nlink = xinode->nlink; - e.attr.st_uid = xinode->uid; - e.attr.st_gid = xinode->gid; - e.attr.st_size = xinode->size; - e.attr.st_atime = xinode->atime; - e.attr.st_mtime = xinode->mtime; - e.attr.st_ctime = xinode->ctime; - e.generation = 1; - - xinode->is_synced = 1; - - if (fip->invoke_fuse) - fuse_reply_entry(fip->req, &e); - - break; - } - - if (i == g_xrdp_fs.num_entries) - { - /* requested entry not found */ - log_debug("did NOT find entry"); - if (fip->invoke_fuse) - fuse_reply_err(fip->req, ENOENT); - } - -done: - - free(fip); -} - void xfuse_devredir_cb_open_file(void *vp, tui32 IoStatus, tui32 DeviceId, tui32 FileId) { @@ -1652,7 +1573,7 @@ void xfuse_devredir_cb_open_file(void *vp, tui32 IoStatus, tui32 DeviceId, { if (fip->reply_type == RT_FUSE_REPLY_OPEN) { - log_debug("LK_TODO sending fuse_reply_open(); " + log_debug("sending fuse_reply_open(); " "DeviceId=%d FileId=%d req=%p fi=%p", fh->DeviceId, fh->FileId, fip->req, fip->fi); @@ -1984,7 +1905,7 @@ static void xfuse_cb_getattr(fuse_req_t req, fuse_ino_t ino, xino = g_xrdp_fs.inode_table[ino]; memset(&stbuf, 0, sizeof(stbuf)); - stbuf.st_ino = ino; + stbuf.st_ino = ino; stbuf.st_mode = xino->mode; stbuf.st_nlink = xino->nlink; stbuf.st_size = xino->size; @@ -2049,14 +1970,17 @@ static int xfuse_dirbuf_add1(fuse_req_t req, struct dirbuf1 *b, static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { - XRDP_INODE *xinode; - XFUSE_INFO *fip; - tui32 device_id; - char full_path[4096]; - char *cptr; + XRDP_INODE *xinode; + XRDP_INODE *ti; + struct dir_info *di; + struct dirbuf1 b; + int i; + int first_time; - log_debug("req=%p inode=%d size=%d offset=%d", req, ino, size, off); + log_debug("req=%p inode=%d name=%s size=%d offset=%d", req, ino, + g_xrdp_fs.inode_table[ino]->name, size, off); + /* do we have a valid inode? */ if (!xfuse_is_inode_valid(ino)) { log_error("inode %d is not valid", ino); @@ -2064,80 +1988,44 @@ static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, return; } - if (ino == 1) + di = (struct dir_info *) fi->fh; + if (di == NULL) { - /* special case; enumerate top level dir */ - log_debug("enumerating top level dir"); - xfuse_enum_dir(req, ino, size, off, fi); + /* something seriously wrong somewhere! */ + fuse_reply_buf(req, 0, 0); return; } - xinode = g_xrdp_fs.inode_table[ino]; - if (xinode->is_loc_resource) - { - /* enumerate local resources */ - xfuse_enum_dir(req, ino, size, off, fi); - return; - } - - /* enumerate resources on a remote device */ - -#ifdef USE_SYNC_FLAG - if (xinode->is_synced) - { - xfuse_enum_dir(req, ino, size, off, fi); - return; - } - else - { - goto do_remote_lookup; - } -#endif - -do_remote_lookup: - - log_debug("did not find entry; redirecting call to dev_redir"); - device_id = xfuse_get_device_id_for_inode((tui32) ino, full_path); - log_debug("dev_id=%d ino=%d full_path=%s", device_id, ino, full_path); + b.bytes_in_buf = 0; + first_time = (di->index == FIRST_INODE) ? 1 : 0; - if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL) + for (i = di->index; i < g_xrdp_fs.num_entries; i++, di->index++) { - log_error("system out of memory"); - fuse_reply_err(req, ENOMEM); - return; - } - - fip->req = req; - fip->inode = ino; - fip->size = size; - fip->off = off; - fip->fi = fi; - fip->dirbuf1.first_time = 1; - fip->dirbuf1.bytes_in_buf = 0; + if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) + continue; - fip->invoke_fuse = 1; - fip->device_id = device_id; + /* match parent inode */ + if (xinode->parent_inode != ino) + continue; - log_debug("fip->req=%p", fip->req); + xinode->is_synced = 1; - /* we want path minus 'root node of the share' */ - if ((cptr = strchr(full_path, '/')) == NULL) - { - /* enumerate root dir */ - if (dev_redir_get_dir_listing((void *) fip, device_id, "\\")) + if (first_time) { - log_error("failed to send dev_redir_get_dir_listing() cmd"); - fuse_reply_buf(req, NULL, 0); + first_time = 0; + ti = g_xrdp_fs.inode_table[ino]; + xfuse_dirbuf_add1(req, &b, ".", ino); + xfuse_dirbuf_add1(req, &b, "..", ti->parent_inode); } + + if (xfuse_dirbuf_add1(req, &b, xinode->name, xinode->inode)) + break; /* buffer is full */ } + + if (b.bytes_in_buf) + fuse_reply_buf(req, b.buf, b.bytes_in_buf); else - { - if (dev_redir_get_dir_listing((void *) fip, device_id, cptr)) - { - log_error("failed to send dev_redir_get_dir_listing() cmd"); - fuse_reply_buf(req, NULL, 0); - } - } + fuse_reply_buf(req, NULL, 0); } /** @@ -2681,7 +2569,7 @@ static void xfuse_cb_release(fuse_req_t req, fuse_ino_t ino, struct FileId = handle->FileId; free(handle); - fip->fi->fh = NULL; + fip->fi->fh = 0; xinode->close_in_progress = 1; if (devredir_file_close((void *) fip, fip->device_id, handle->FileId)) @@ -2925,4 +2813,185 @@ static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, fuse_reply_attr(req, &st, 1.0); /* LK_TODO just faking for now */ } +static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + struct dir_info *di; + XRDP_INODE *xinode; + XFUSE_INFO *fip; + tui32 device_id; + char full_path[4096]; + char *cptr; + + log_debug("inode=%d name=%s", ino, g_xrdp_fs.inode_table[ino]->name); + + if (!xfuse_is_inode_valid(ino)) + { + log_error("inode %d is not valid", ino); + fuse_reply_err(req, EBADF); + return; + } + + if (ino == 1) + goto done; /* special case; enumerate top level dir */ + + xinode = g_xrdp_fs.inode_table[ino]; + + if (xinode->is_loc_resource) + goto done; + + /* enumerate resources on a remote device */ + +#ifdef USE_SYNC_FLAG + if (xinode->is_synced) + { + xfuse_enum_dir(req, ino, size, off, fi); + return; + } + else + { + goto do_remote_lookup; + } +#endif + +do_remote_lookup: + + xfuse_mark_as_stale((int) ino); + + log_debug("did not find entry; redirecting call to dev_redir"); + device_id = xfuse_get_device_id_for_inode((tui32) ino, full_path); + + log_debug("dev_id=%d ino=%d full_path=%s", device_id, ino, full_path); + + 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->size = 0; + fip->off = 0; + fip->fi = fi; + fip->dirbuf1.first_time = 1; + fip->dirbuf1.bytes_in_buf = 0; + + fip->invoke_fuse = 1; + fip->device_id = device_id; + + /* we want path minus 'root node of the share' */ + if ((cptr = strchr(full_path, '/')) == NULL) + { + /* enumerate root dir */ + if (dev_redir_get_dir_listing((void *) fip, device_id, "\\")) + { + log_error("failed to send dev_redir_get_dir_listing() cmd"); + fuse_reply_buf(req, NULL, 0); + } + } + else + { + if (dev_redir_get_dir_listing((void *) fip, device_id, cptr)) + { + log_error("failed to send dev_redir_get_dir_listing() cmd"); + fuse_reply_buf(req, NULL, 0); + } + } + + return; + +done: + + di = calloc(1, sizeof(struct dir_info)); + di->index = FIRST_INODE; + fi->fh = (long) di; + fuse_reply_open(req, fi); +} + +/** + *****************************************************************************/ + +static void xfuse_cb_releasedir(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) +{ + struct dir_info *di; + + di = (struct dir_info *) (tintptr) fi->fh; + if (di) + free(di); + + fuse_reply_err(req, 0); +} + +/****************************************************************************** + * miscellaneous functions + *****************************************************************************/ + +/** + * Mark all files with matching parent inode as stale + * + * @param pinode the parent inode + *****************************************************************************/ + +static void +xfuse_mark_as_stale(int pinode) +{ + int i; + XRDP_INODE *xinode; + + if ((pinode < FIRST_INODE) || (pinode >= g_xrdp_fs.num_entries)) + return; + + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) + { + if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) + continue; + + /* match parent inode */ + if (xinode->parent_inode != pinode) + continue; + + /* got a match */ + xinode->stale = 1; + } +} + +/** + * Delete all files with matching parent inode that are marked as stale + * + * @param pinode the parent inode + *****************************************************************************/ + +static void +xfuse_delete_stale_entries(int pinode) +{ + int i; + XRDP_INODE *xinode; + + if ((pinode < FIRST_INODE) || (pinode >= g_xrdp_fs.num_entries)) + return; + + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) + { + if ((xinode = g_xrdp_fs.inode_table[i]) == NULL) + continue; + + /* match parent inode */ + if (xinode->parent_inode != pinode) + continue; + + /* got a match, but is it stale? */ + if (!xinode->stale) + continue; + + /* ok to delete */ + if (xinode->mode & S_IFREG) + xfuse_delete_file_with_xinode(xinode); + else + xfuse_recursive_delete_dir_with_xinode(xinode); + } +} + #endif /* end else #ifndef XRDP_FUSE */ |