diff options
author | Laxmikant Rashinkar <LK.Rashinkar@gmail.com> | 2013-04-20 16:42:49 -0700 |
---|---|---|
committer | Laxmikant Rashinkar <LK.Rashinkar@gmail.com> | 2013-04-20 16:42:49 -0700 |
commit | 97c483c8b3d76a943fc315e58db798256ee1e488 (patch) | |
tree | 37d216de043cd3f43a6d00d583b7b10c4019b031 /sesman/chansrv | |
parent | 2d89ae1f3855997bb1e75f8cde24f227c7342a68 (diff) | |
download | xrdp-proprietary-97c483c8b3d76a943fc315e58db798256ee1e488.tar.gz xrdp-proprietary-97c483c8b3d76a943fc315e58db798256ee1e488.zip |
swapped cb_lookup and cb_readdir
Diffstat (limited to 'sesman/chansrv')
-rw-r--r-- | sesman/chansrv/chansrv_fuse.c | 660 | ||||
-rw-r--r-- | sesman/chansrv/devredir.c | 71 | ||||
-rw-r--r-- | sesman/chansrv/devredir.h | 3 |
3 files changed, 675 insertions, 59 deletions
diff --git a/sesman/chansrv/chansrv_fuse.c b/sesman/chansrv/chansrv_fuse.c index 79bf8714..76608be0 100644 --- a/sesman/chansrv/chansrv_fuse.c +++ b/sesman/chansrv/chansrv_fuse.c @@ -41,7 +41,7 @@ * */ -// LK_TODO #define USE_SYNC_FLAG +//#define USE_SYNC_FLAG /* FUSE mount point */ char g_fuse_root_path[256] = ""; @@ -139,7 +139,7 @@ void xfuse_devredir_cb_file_close(void *vp) {} #define log_debug(_params...) \ { \ - if (LOG_DEBUG <= LOG_LEVEL) \ + if (LOG_DEBUG <= LOG_LEVEL) \ { \ g_write("[%10.10u]: FUSE %s: %d : ", \ g_time3(), __func__, __LINE__); \ @@ -164,6 +164,13 @@ struct dirbuf size_t size; }; +struct dirbuf1 +{ + char buf[4096]; + int bytes_in_buf; + int first_time; +}; + /* FUSE reply types */ #define RT_FUSE_REPLY_OPEN 1 #define RT_FUSE_REPLY_CREATE 2 @@ -181,6 +188,9 @@ struct xfuse_info int reply_type; int mode; int type; + size_t size; + off_t off; + struct dirbuf1 dirbuf1; }; typedef struct xfuse_info XFUSE_INFO; @@ -227,10 +237,13 @@ static struct xrdp_inode * xfuse_create_file_in_xrdp_fs(tui32 device_id, int pinode, char *name, 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); +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 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); /* forward declarations for calls we make into devredir */ int dev_redir_get_dir_listing(void *fusep, tui32 device_id, char *path); @@ -255,6 +268,9 @@ static void xfuse_cb_getattr(fuse_req_t req, fuse_ino_t ino, static void xfuse_dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name, fuse_ino_t ino); +static int xfuse_dirbuf_add1(fuse_req_t req, struct dirbuf1 *b, + const char *name, fuse_ino_t ino); + static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi); @@ -410,6 +426,10 @@ int xfuse_init() #if 0 sprintf(opt, "-o uid=%d,gid=%d", g_getuid(), g_getgid()); fuse_opt_add_arg(&args, opt); +#else + /* disable multi threading */ + sprintf(opt, "-s"); + fuse_opt_add_arg(&args, opt); #endif if (xfuse_init_lib(&args)) @@ -548,12 +568,6 @@ int xfuse_create_share(tui32 device_id, char *dirname) return -1; } - if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL) - { - log_error("system out of memory"); - return -1; - } - /* create directory entry */ xinode->parent_inode = 1; xinode->inode = g_xrdp_fs.next_node++; @@ -582,6 +596,13 @@ int xfuse_create_share(tui32 device_id, char *dirname) return -1; xinode->nentries++; +#if 0 + if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL) + { + log_error("system out of memory"); + return -1; + } + /* enumerate root dir, do not call FUSE when done */ fip->req = NULL; fip->inode = 1; // LK_TODO saved_inode; @@ -590,6 +611,7 @@ int xfuse_create_share(tui32 device_id, char *dirname) fip->device_id = device_id; dev_redir_get_dir_listing((void *) fip, device_id, "\\"); +#endif return 0; } @@ -652,14 +674,6 @@ int xfuse_file_contents_size(int stream_id, int file_size) static int xfuse_init_lib(struct fuse_args *args) { - // LK_TODO - { - int i; - - 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"); @@ -785,7 +799,7 @@ static int xfuse_init_xrdp_fs() xino->ctime = time(0); strcpy(xino->name, ".clipboard"); - g_xrdp_fs.max_entries = 1024; + g_xrdp_fs.max_entries = 4096; g_xrdp_fs.num_entries = 3; g_xrdp_fs.next_node = 3; @@ -865,6 +879,7 @@ static void xfuse_create_file(fuse_req_t req, fuse_ino_t parent, /* insert it in xrdp fs */ g_xrdp_fs.inode_table[xinode->inode] = xinode; + xfuse_update_xrdpfs_size(); log_debug("inserted new dir at inode_table[%d]", (int) xinode->inode); xfuse_dump_fs(); @@ -1064,7 +1079,7 @@ static struct xrdp_inode * xfuse_create_file_in_xrdp_fs(tui32 device_id, log_debug("S_IFDIR=0x%x S_IFREG=0x%x type=0x%x", S_IFDIR, S_IFREG, type); xinode->parent_inode = pinode; - xinode->inode = g_xrdp_fs.next_node++; /* TODO should be thread safe */ + xinode->inode = g_xrdp_fs.next_node++; xinode->nlink = 1; xinode->uid = getuid(); xinode->gid = getgid(); @@ -1087,13 +1102,14 @@ static struct xrdp_inode * xfuse_create_file_in_xrdp_fs(tui32 device_id, } g_xrdp_fs.inode_table[xinode->inode] = xinode; - g_xrdp_fs.num_entries++; /* TODO should be thread safe */ + g_xrdp_fs.num_entries++; /* bump up lookup count in parent dir */ xinodep = g_xrdp_fs.inode_table[pinode]; xinodep->nentries++; + xfuse_update_xrdpfs_size(); - log_debug("LK_TODO: incremented nentries; parent=%d nentries=%d", + log_debug("incremented nentries; parent=%d nentries=%d", pinode, xinodep->nentries); /* LK_TODO */ @@ -1181,6 +1197,85 @@ static int xfuse_delete_dir_with_xinode(XRDP_INODE *xinode) return 0; } +static void xfuse_update_xrdpfs_size() +{ + void *vp; + int diff; + + diff = g_xrdp_fs.max_entries - g_xrdp_fs.num_entries; + if (diff > 100) + return; + + /* extend memory */ + vp = realloc(g_xrdp_fs.inode_table, + (g_xrdp_fs.max_entries + 100) * sizeof(struct xrdp_inode *)); + + if (vp == NULL) + { + log_error("system out of memory"); + return; + } + + /* zero newly added memory */ + memset(vp + g_xrdp_fs.max_entries * sizeof(struct xrdp_inode *), + 0, + 100 * sizeof(struct xrdp_inode *)); + + g_xrdp_fs.max_entries += 100; + g_xrdp_fs.inode_table = vp; +} + +static void xfuse_enum_dir(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t off, struct fuse_file_info *fi) +{ + XRDP_INODE *xinode; + XRDP_INODE *xinode1; + struct dirbuf b; + int first_time = 1; + int i; + + memset(&b, 0, sizeof(struct dirbuf)); + + 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 != ino) + continue; + + if (first_time) + { + first_time = 0; + if (ino == 1) + { + xfuse_dirbuf_add(req, &b, ".", 1); + xfuse_dirbuf_add(req, &b, "..", 1); + } + else + { + xinode1 = g_xrdp_fs.inode_table[ino]; + xfuse_dirbuf_add(req, &b, ".", ino); + xfuse_dirbuf_add(req, &b, "..", xinode1->parent_inode); + } + } + + xfuse_dirbuf_add(req, &b, xinode->name, xinode->inode); + } + + if (!first_time) + { + if (off < b.size) + fuse_reply_buf(req, b.p + off, min(b.size - off, size)); + else + fuse_reply_buf(req, NULL, 0); + } + + if (b.p) + free(b.p); +} + /****************************************************************************** ** ** ** callbacks for devredir ** @@ -1191,47 +1286,63 @@ static int xfuse_delete_dir_with_xinode(XRDP_INODE *xinode) * Add a file or directory to xrdp file system *****************************************************************************/ -void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) +/* LK_TODO delete this after testing */ +#if 0 +void ___xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) { - XFUSE_INFO *fip = (XFUSE_INFO *) vp; - XRDP_INODE *target_inode; + XFUSE_INFO *fip = (XFUSE_INFO *) vp; + XRDP_INODE *xip = NULL; + + log_debug("<<<<<< entered"); if ((fip == NULL) || (xinode == NULL)) { log_error("fip or xinode are NULL"); + printf("RASH_TODO: fip or xinode are NULL - leaving\n"); return; } -/* LK_TODO */ -#if 0 + log_debug("req=%p", fip->req); + /* do we have a valid inode? */ if (!xfuse_is_inode_valid(fip->inode)) { log_error("inode %d is not valid", fip->inode); + printf("RASH_TODO: inode %d is not valid - leaving\n", (tui32) fip->inode); return; } -#endif /* if filename is . or .. don't add it */ if ((strcmp(xinode->name, ".") == 0) || (strcmp(xinode->name, "..") == 0)) { free(xinode); + printf("RASH_TODO: not adding ./.. - leaving\n"); return; } +// LK_TODO +#if 0 /* we have a parent inode and a dir name; what we need is the xinode */ /* that matches the parent inode and the dir name */ target_inode = xfuse_get_inode_from_pinode_name(fip->inode, fip->name); if (target_inode == 0) + { + log_debug("did not find entry with inode=%d name=%s", + fip->inode, fip->name); return; + } +#endif - if (xfuse_does_file_exist(target_inode->inode, xinode->name)) + 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); - return; + xinode = xip; + goto update_fuse; } - xinode->parent_inode = target_inode->inode; + xinode->parent_inode = fip->inode; xinode->inode = g_xrdp_fs.next_node++; xinode->uid = getuid(); xinode->gid = getgid(); @@ -1239,15 +1350,116 @@ void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) g_xrdp_fs.num_entries++; - /* insert it in xrdp fs */ + /* 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; + xfuse_update_xrdpfs_size(); - /* bump up lookup count */ - xinode = g_xrdp_fs.inode_table[target_inode->inode]; - xinode->nentries++; +update_fuse: - log_debug("added %s to pinode=%d, nentries=%d target_inode->inode=%d", - fip->name, fip->inode, xinode->nentries, target_inode->inode); +#if 1 + /* let FUSE know about this entry */ + if (fip->invoke_fuse) + { + struct dirbuf b; + + memset(&b, 0, sizeof(struct dirbuf)); + + /* RASH_TODO if we are not using dirbuf, change this code */ + if (fip->dirbuf == NULL) + { + fip->dirbuf = calloc(1, sizeof(struct dirbuf)); + xfuse_dirbuf_add(fip->req, &b, ".", xinode->inode); + xfuse_dirbuf_add(fip->req, &b, "..", xinode->parent_inode); + } + + xfuse_dirbuf_add(fip->req, &b, xinode->name, xinode->inode); + + if (fip->off < b.size) + { + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): req=%p off=%d\n", + fip->req, (tui32) fip->off); + + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): dumping req b4\n\n"); + g_hexdump((char *) fip->req, 128); + + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): dumping buf b4\n\n"); + g_hexdump(b.p, b.size); + + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): calling fuse\n"); + + fuse_reply_buf(fip->req, b.p, b.size); + + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): calling fuse...done\n"); + + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): dumping req aft\n\n"); + g_hexdump((char *) fip->req, 128); + + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): dumping buf aft\n\n"); + g_hexdump(b.p, b.size); + } + else + { + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): calling fuse with NULL\n"); + fuse_reply_buf(fip->req, NULL, 0); + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): calling fuse with NULL...done\n"); + } + + log_debug("added inode=%d name=%s to FUSE", (tui32) xinode->inode, xinode->name); + } +#endif + + log_debug("leaving"); + printf("RASH_TODO: xfuse_devredir_cb_enum_dir(): leaving\n"); +} +#endif + +void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) +{ + XFUSE_INFO *fip = (XFUSE_INFO *) vp; + XRDP_INODE *xip = NULL; + + if ((fip == NULL) || (xinode == NULL)) + { + log_error("fip or xinode are NULL"); + return; + } + + + if (!xfuse_is_inode_valid(fip->inode)) + { + log_error("inode %d is not valid", fip->inode); + return; + } + + /* if filename is . or .. don't add it */ + if ((strcmp(xinode->name, ".") == 0) || (strcmp(xinode->name, "..") == 0)) + { + free(xinode); + return; + } + + 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; + return; + } + + xinode->parent_inode = fip->inode; + xinode->inode = g_xrdp_fs.next_node++; + xinode->uid = getuid(); + xinode->gid = getgid(); + xinode->device_id = fip->device_id; + + g_xrdp_fs.num_entries++; + + /* 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; + xfuse_update_xrdpfs_size(); } /** @@ -1255,12 +1467,122 @@ 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); + + 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; + + 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; + } +#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; + + xinode->is_synced = 1; + + 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 + fuse_reply_buf(fip->req, b.buf, b.bytes_in_buf); +#endif + fuse_reply_buf(fip->req, NULL, 0); + } + else + { + fuse_reply_buf(fip->req, NULL, 0); + } + } + else + { + fuse_reply_err(fip->req, ENOENT); + } + +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) @@ -1599,6 +1921,49 @@ void xfuse_devredir_cb_file_close(void *vp) static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { + XRDP_INODE *xinode; + struct fuse_entry_param e; + + log_debug("looking for parent=%d name=%s", (int) parent, name); + xfuse_dump_fs(); + + if (!xfuse_is_inode_valid(parent)) + { + log_error("inode %d is not valid", parent); + fuse_reply_err(req, EBADF); + return; + } + + xinode = xfuse_get_inode_from_pinode_name(parent, name); + if (xinode == NULL) + { + log_debug("did not find entry for parent=%d name=%s", parent, name); + fuse_reply_err(req, ENOENT); + return; + } + + 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; + + fuse_reply_entry(req, &e); + log_debug("found entry for parent=%d name=%s", parent, name); + return; +} + +static void xfuse_cb_lookup_TODO(fuse_req_t req, fuse_ino_t parent, const char *name) +{ XFUSE_INFO *fip; XRDP_INODE *xinode; struct fuse_entry_param e; @@ -1606,6 +1971,9 @@ static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) char full_path[4096]; char *cptr; + /* SPEEDUP_TODO */ + printf("###### cb_lookup: looking for parent=%d name=%s\n", (int) parent, name); + log_debug("ENTERED: looking for parent=%d name=%s", (int) parent, name); xfuse_dump_fs(); @@ -1619,7 +1987,7 @@ static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) if ((xinode = xfuse_get_inode_from_pinode_name(parent, name)) != NULL) { - log_debug("LK_TODO: got match: device_id=%d", xinode->device_id); + log_debug("got match: device_id=%d", xinode->device_id); /* got a full match; if this dir is located on a remote device */ /* and is not synced, do a remote look up */ @@ -1659,13 +2027,15 @@ do_remote_lookup: /* if ino belongs to a redirected share, pass the call to devredir; */ /* when done, devredir will invoke xfuse_devredir_cb_enum_dir_done(...) */ strcpy(full_path, name); - log_debug("LK_TODO: full_path=%s name=%s", full_path, name); + log_debug("full_path=%s name=%s", full_path, name); device_id = xfuse_get_device_id_for_inode((tui32) parent, full_path); log_debug("device_id=%d", device_id); if (device_id != 0) { log_debug("did not find entry; redirecting call to dev_redir"); + printf("????????? xfuse_cb_lookup() doing remote lookup for %s\n", name); + if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL) { log_error("system out of memory"); @@ -1729,7 +2099,7 @@ static void xfuse_cb_getattr(fuse_req_t req, fuse_ino_t ino, (void) fi; - log_debug("ino=%d", (int) ino); + log_debug("req=%p ino=%d", req, (int) ino); /* if ino is not valid, just return */ if (!xfuse_is_inode_valid(ino)) @@ -1740,7 +2110,6 @@ static void xfuse_cb_getattr(fuse_req_t req, fuse_ino_t ino, } xino = g_xrdp_fs.inode_table[ino]; - xfuse_dump_xrdp_inode(xino); memset(&stbuf, 0, sizeof(stbuf)); stbuf.st_ino = ino; @@ -1749,6 +2118,7 @@ static void xfuse_cb_getattr(fuse_req_t req, fuse_ino_t ino, stbuf.st_size = xino->size; fuse_reply_attr(req, &stbuf, 1.0); + log_debug("exiting"); } /** @@ -1772,6 +2142,34 @@ static void xfuse_dirbuf_add(fuse_req_t req, struct dirbuf *b, b->size); } +static int xfuse_dirbuf_add1(fuse_req_t req, struct dirbuf1 *b, + const char *name, fuse_ino_t ino) +{ + struct stat stbuf; + int len; + + len = fuse_add_direntry(req, NULL, 0, name, NULL, 0); + if (b->bytes_in_buf + len > 4096) + { + log_debug("not adding entry because dirbuf overflow would occur"); + return -1; + } + + memset(&stbuf, 0, sizeof(stbuf)); + stbuf.st_ino = ino; + + fuse_add_direntry(req, + &b->buf[b->bytes_in_buf], /* index where new entry will be added to buf */ + 4096 - len, /* remaining size of buf */ + name, /* name of entry */ + &stbuf, /* file attributes */ + b->bytes_in_buf + len /* offset of next entry */ + ); + + b->bytes_in_buf += len; + return 0; +} + /** * *****************************************************************************/ @@ -1779,12 +2177,184 @@ static void xfuse_dirbuf_add(fuse_req_t req, struct dirbuf *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; + + log_debug("req=%p inode=%d size=%d offset=%d", req, ino, size, off); + + if (!xfuse_is_inode_valid(ino)) + { + log_error("inode %d is not valid", ino); + fuse_reply_err(req, EBADF); + return; + } + + xinode = g_xrdp_fs.inode_table[ino]; + if (xinode->device_id == 0) + { + /* enumerate local resources */ + xfuse_enum_dir(req, ino, size, off, fi); + return; + } + + /* enumerate resources on a remote device */ + +// lK_TODO +#if 0 +{ + struct dirbuf b; + + memset(&b, 0, sizeof(struct dirbuf)); + xfuse_dirbuf_add(req, &b, ".", 1); + xfuse_dirbuf_add(req, &b, "..", 1); + xfuse_dirbuf_add(req, &b, "f2", 2); + if (off < b.size) + fuse_reply_buf(req, b.p + off, min(b.size - off, b.size)); + else + fuse_reply_buf(req, NULL, 0); + + xfuse_dirbuf_add(req, &b, "f3", 3); + if (off < b.size) + fuse_reply_buf(req, b.p + off, min(b.size - off, b.size)); + else + fuse_reply_buf(req, NULL, 0); + + xfuse_dirbuf_add(req, &b, "f4", 4); + if (off < b.size) + fuse_reply_buf(req, b.p + off, min(b.size - off, b.size)); + else + fuse_reply_buf(req, NULL, 0); + + xfuse_dirbuf_add(req, &b, "f5", 5); + if (off < b.size) + fuse_reply_buf(req, b.p + off, min(b.size - off, b.size)); + else + fuse_reply_buf(req, NULL, 0); + + xfuse_dirbuf_add(req, &b, "f6", 6); + if (off < b.size) + fuse_reply_buf(req, b.p + off, min(b.size - off, b.size)); + else + fuse_reply_buf(req, NULL, 0); + + xfuse_dirbuf_add(req, &b, "f7", 7); + if (off < b.size) + fuse_reply_buf(req, b.p + off, min(b.size - off, b.size)); + else + fuse_reply_buf(req, NULL, 0); + + xfuse_dirbuf_add(req, &b, "f8", 8); + if (off < b.size) + fuse_reply_buf(req, b.p + off, min(b.size - off, b.size)); + else + fuse_reply_buf(req, NULL, 0); + + xfuse_dirbuf_add(req, &b, "f9", 9); + if (off < b.size) + fuse_reply_buf(req, b.p + off, min(b.size - off, b.size)); + else + fuse_reply_buf(req, NULL, 0); + + xfuse_dirbuf_add(req, &b, "f10", 10); + if (off < b.size) + fuse_reply_buf(req, b.p + off, min(b.size - off, b.size)); + else + fuse_reply_buf(req, NULL, 0); + + xfuse_dirbuf_add(req, &b, "f11", 11); + if (off < b.size) + fuse_reply_buf(req, b.p + off, min(b.size - off, b.size)); + else + fuse_reply_buf(req, NULL, 0); + + xfuse_dirbuf_add(req, &b, "f12", 12); + if (off < b.size) + fuse_reply_buf(req, b.p + off, min(b.size - off, b.size)); + else + fuse_reply_buf(req, NULL, 0); + + fuse_reply_buf(req, NULL, 0); + return; +} +#endif + +#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); + + 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 = size; + fip->off = off; + 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); + } + } +} + + + + + + + +static void xfuse_cb_readdir_TODO(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t off, struct fuse_file_info *fi) +{ struct xrdp_inode *xinode; struct dirbuf b; int i; (void) fi; + /* SPEEDUP_TODO */ + printf("++++++ cb_readdir: looking for inode=%d\n", (int) ino); + log_debug("looking for dir with inode=%d", ino); if (!xfuse_is_inode_valid(ino)) @@ -1823,6 +2393,8 @@ static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, fuse_reply_buf(req, NULL, 0); free(b.p); + + printf("++++++ cb_readdir: leaving\n"); } /** @@ -2132,7 +2704,7 @@ 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) { - XFUSE_INFO *fip; // LK_TODO use only XFUSE_INFO instead of struct + XFUSE_INFO *fip; char *cptr; char full_path[1024]; tui32 device_id; diff --git a/sesman/chansrv/devredir.c b/sesman/chansrv/devredir.c index 37afad26..f09d7f07 100644 --- a/sesman/chansrv/devredir.c +++ b/sesman/chansrv/devredir.c @@ -381,7 +381,7 @@ int dev_redir_send_drive_create_request(tui32 device_id, char *path, int bytes; int len; - log_debug("LK_TODO: DesiredAccess=0x%x CreateDisposition=0x%x CreateOptions=0x%x", + log_debug("DesiredAccess=0x%x CreateDisposition=0x%x CreateOptions=0x%x", DesiredAccess, CreateDisposition, CreateOptions); /* to store path as unicode */ @@ -482,7 +482,11 @@ void dev_redir_send_drive_dir_request(IRP *irp, tui32 device_id, IRP_MJ_DIRECTORY_CONTROL, IRP_MN_QUERY_DIRECTORY); +#ifdef USE_SHORT_NAMES_IN_DIR_LISTING + stream_wr_u32_le(s, FileBothDirectoryInformation); /* FsInformationClass */ +#else stream_wr_u32_le(s, FileDirectoryInformation); /* FsInformationClass */ +#endif stream_wr_u8(s, InitialQuery); /* InitialQuery */ if (!InitialQuery) @@ -651,8 +655,7 @@ void dev_redir_proc_device_iocompletion(struct stream *s) /* LK_TODO need to check for IoStatus */ - log_debug("entered: IoStatus=0x%x CompletionId=%d", - IoStatus, CompletionId); + log_debug("entered: IoStatus=0x%x CompletionId=%d", IoStatus, CompletionId); if ((irp = dev_redir_irp_find(CompletionId)) == NULL) { @@ -682,6 +685,7 @@ void dev_redir_proc_device_iocompletion(struct stream *s) 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; @@ -788,6 +792,12 @@ void dev_redir_proc_query_dir_response(IRP *irp, tui32 FileNameLength; tui32 status; +#ifdef USE_SHORT_NAMES_IN_DIR_LISTING + tui32 EaSize; + tui8 ShortNameLength; + tui8 Reserved; +#endif + char filename[256]; int i = 0; @@ -828,18 +838,30 @@ void dev_redir_proc_query_dir_response(IRP *irp, stream_rd_u32_le(s_in, FileAttributes); stream_rd_u32_le(s_in, FileNameLength); +#ifdef USE_SHORT_NAMES_IN_DIR_LISTING + stream_rd_u32_le(s_in, EaSize); + stream_rd_u8(s_in, ShortNameLength); + stream_rd_u8(s_in, Reserved); + stream_seek(s_in, 23); /* ShortName in Unicode */ +#endif devredir_cvt_from_unicode_len(filename, s_in->p, FileNameLength); +#ifdef USE_SHORT_NAMES_IN_DIR_LISTING + i += 70 + 23 + FileNameLength; +#else i += 64 + FileNameLength; - - log_debug("NextEntryOffset: 0x%x", NextEntryOffset); - log_debug("CreationTime: 0x%llx", CreationTime); - log_debug("LastAccessTime: 0x%llx", LastAccessTime); - log_debug("LastWriteTime: 0x%llx", LastWriteTime); - log_debug("ChangeTime: 0x%llx", ChangeTime); - log_debug("EndOfFile: %lld", EndOfFile); - log_debug("FileAttributes: 0x%x", FileAttributes); - log_debug("FileNameLength: 0x%x", FileNameLength); +#endif + //log_debug("NextEntryOffset: 0x%x", NextEntryOffset); + //log_debug("CreationTime: 0x%llx", CreationTime); + //log_debug("LastAccessTime: 0x%llx", LastAccessTime); + //log_debug("LastWriteTime: 0x%llx", LastWriteTime); + //log_debug("ChangeTime: 0x%llx", ChangeTime); + //log_debug("EndOfFile: %lld", EndOfFile); + //log_debug("FileAttributes: 0x%x", FileAttributes); +#ifdef USE_SHORT_NAMES_IN_DIR_LISTING + //log_debug("ShortNameLength: %d", ShortNameLength); +#endif + //log_debug("FileNameLength: %d", FileNameLength); log_debug("FileName: %s", filename); if ((xinode = calloc(1, sizeof(struct xrdp_inode))) == NULL) @@ -886,6 +908,9 @@ int dev_redir_get_dir_listing(void *fusep, tui32 device_id, char *path) if ((irp = dev_redir_irp_new()) == NULL) return -1; + /* cvt / to windows compatible \ */ + devredir_cvt_slash(path); + irp->completion_id = g_completion_id++; irp->completion_type = CID_CREATE_DIR_REQ; irp->device_id = device_id; @@ -895,6 +920,7 @@ int dev_redir_get_dir_listing(void *fusep, tui32 device_id, char *path) DesiredAccess = DA_FILE_READ_DATA | DA_SYNCHRONIZE; CreateOptions = CO_FILE_DIRECTORY_FILE | CO_FILE_SYNCHRONOUS_IO_NONALERT; CreateDisposition = CD_FILE_OPEN; + rval = dev_redir_send_drive_create_request(device_id, path, DesiredAccess, CreateOptions, CreateDisposition, @@ -905,7 +931,6 @@ int dev_redir_get_dir_listing(void *fusep, tui32 device_id, char *path) /* when we get a respone to dev_redir_send_drive_create_request(), we */ /* call dev_redir_send_drive_dir_request(), which needs the following */ /* at the end of the path argument */ - if (dev_redir_string_ends_with(irp->pathname, '\\')) strcat(irp->pathname, "*"); else @@ -964,7 +989,7 @@ int dev_redir_file_open(void *fusep, tui32 device_id, char *path, } else //if (mode & O_RDWR) { - log_debug("LK_TODO: open file in O_RDWR"); + log_debug("open file in O_RDWR"); DesiredAccess = DA_FILE_READ_DATA | DA_FILE_WRITE_DATA | DA_SYNCHRONIZE; CreateOptions = CO_FILE_SYNCHRONOUS_IO_NONALERT; CreateDisposition = CD_FILE_OPEN; // WAS 1 @@ -972,7 +997,7 @@ int dev_redir_file_open(void *fusep, tui32 device_id, char *path, #if 0 else { - log_debug("LK_TODO: open file in O_RDONLY"); + log_debug("open file in O_RDONLY"); DesiredAccess = DA_FILE_READ_DATA | DA_SYNCHRONIZE; CreateOptions = CO_FILE_SYNCHRONOUS_IO_NONALERT; CreateDisposition = CD_FILE_OPEN; @@ -1408,6 +1433,22 @@ void dev_redir_insert_dev_io_req_header(struct stream *s, stream_wr_u32_le(s, MinorFunction); } +/** + * Convert / to windows compatible \ + *****************************************************************************/ + +void devredir_cvt_slash(char *path) +{ + char *cptr = path; + + while (*cptr != 0) + { + if (*cptr == '/') + *cptr = '\\'; + cptr++; + } +} + void devredir_cvt_to_unicode(char *unicode, char *path) { int len = strlen(path); diff --git a/sesman/chansrv/devredir.h b/sesman/chansrv/devredir.h index 231c2626..5bc85ede 100644 --- a/sesman/chansrv/devredir.h +++ b/sesman/chansrv/devredir.h @@ -37,6 +37,8 @@ #include "log.h" #include "chansrv_fuse.h" +#define USE_SHORT_NAMES_IN_DIR_LISTING + typedef struct fuse_data FUSE_DATA; struct fuse_data { @@ -123,6 +125,7 @@ void dev_redir_insert_dev_io_req_header(struct stream *s, tui32 MajorFunction, tui32 MinorFunction); +void devredir_cvt_slash(char *path); void devredir_cvt_to_unicode(char *unicode, char *path); void devredir_cvt_from_unicode_len(char *path, char *unicode, int len); int dev_redir_string_ends_with(char *string, char c); |