diff options
Diffstat (limited to 'sesman/chansrv/chansrv_fuse.c')
-rw-r--r-- | sesman/chansrv/chansrv_fuse.c | 2359 |
1 files changed, 1878 insertions, 481 deletions
diff --git a/sesman/chansrv/chansrv_fuse.c b/sesman/chansrv/chansrv_fuse.c index eb60f63a..c55fd57f 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) Jay Sorg 2012 + * Copyright (C) Laxmikant Rashinkar 2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,62 @@ * limitations under the License. */ -#ifdef XRDP_FUSE +/* + * TODO + * o need to support sym links + * o when creating dir/file, ensure it does not already exist + * o enable changing metadata for files/folders (time, owner, mode etc) + * o do not allow dirs to be created in ino==1 except for .clipbard and share mounts + * o xrdp_fs needs to grow dynamically - currently it is fixed at 1k or 4k + * o fix the HACK where I have to use my own buf instead of g_buffer + * this is in func xfuse_check_wait_objs() + * o if fuse mount point is already mounted, I get segfault + * o in open, check for modes such as O_TRUNC, O_APPEND + * o copying over an existing file does not work + * 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 + * + */ + +/* FUSE mount point */ +char g_fuse_root_path[256] = ""; + +#ifndef XRDP_FUSE + +/****************************************************************************** +** ** +** when FUSE is NOT enabled in xrdp ** +** ** +******************************************************************************/ + +#include "arch.h" + +/* dummy calls when XRDP_FUSE is not defined */ +int xfuse_init() {} +int xfuse_deinit() {} +int xfuse_check_wait_objs(void) {} +int xfuse_get_wait_objs(tbus *objs, int *count, int *timeout) {} +int xfuse_clear_clip_dir(void) {} +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) {} + +#else + +/****************************************************************************** +** ** +** when FUSE is enabled in xrdp ** +** ** +******************************************************************************/ #define FUSE_USE_VERSION 26 #define _FILE_OFFSET_BITS 64 @@ -24,692 +79,2034 @@ #include <fuse/fuse_lowlevel.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> #include <errno.h> -#include <fcntl.h> +#include <time.h> #include <unistd.h> +#include <string.h> +#include <pthread.h> +#include <sched.h> + #include "arch.h" -#include "parse.h" -#include "list.h" #include "os_calls.h" -#include "chansrv.h" #include "chansrv_fuse.h" -#include "clipboard_file.h" - -#define LLOG_LEVEL 1 -#define LLOGLN(_level, _args) \ - do \ - { \ - if (_level < LLOG_LEVEL) \ - { \ - g_write("chansrv:fuse [%10.10u]: ", g_time3()); \ - g_writeln _args ; \ - } \ - } \ - while (0) -char g_fuse_root_path[256] = ""; +#define min(x, y) ((x) < (y) ? (x) : (y)) -static struct fuse_chan *g_ch = 0; -static struct fuse_session *g_se = 0; -static char *g_mountpoint = 0; -static tintptr g_bufsize = 0; -static char *g_buffer = 0; -static int g_fd = 0; -static time_t g_time = 0; -static int g_uid = 0; -static int g_gid = 0; - -/* used for file data request sent to client */ -struct req_list_item -{ - fuse_req_t req; - int stream_id; - int lindex; - int off; - int size; +#define XFUSE_ATTR_TIMEOUT 1.0 +#define XFUSE_ENTRY_TIMEOUT 1.0 + +#define DOTDOT_INODE 0 +#define DOT_INODE 0 +#define FIRST_INODE 1 + +/* module based logging */ +#define LOG_ERROR 0 +#define LOG_INFO 1 +#define LOG_DEBUG 2 +#define LOG_LEVEL LOG_ERROR + +#define log_error(_params...) \ +{ \ + g_write("[%10.10u]: FUSE %s: %d : ERROR: ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ +} + +#define log_info(_params...) \ +{ \ + if (LOG_INFO <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: FUSE %s: %d : ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ + } \ +} + +#define log_debug(_params...) \ +{ \ + if (LOG_DEBUG <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: FUSE %s: %d : ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ + } \ +} + +/* the xrdp file system in memory */ +struct xrdp_fs +{ + struct xrdp_inode **inode_table; /* a table of entries; can grow */ + unsigned int max_entries; /* size of inode_table[] */ + unsigned int num_entries; /* num entries available in inode_table */ + unsigned int next_node; /* next free node number */ }; -static struct list *g_req_list = 0; struct dirbuf { char *p; - int size; - int alloc_bytes; + size_t size; +}; + +/* FUSE reply types */ +#define RT_FUSE_REPLY_OPEN 1 +#define RT_FUSE_REPLY_CREATE 2 + +struct xfuse_info +{ + struct fuse_file_info *fi; + fuse_req_t req; + fuse_ino_t inode; + int invoke_fuse; + char name[1024]; + tui32 device_id; + int reply_type; + int mode; }; +typedef struct xfuse_info XFUSE_INFO; -struct xfuse_file_info -{ - int ino; - int lindex; - char pathname[256]; - char filename[256]; - int flags; - int size; - tui64 time; - struct xfuse_file_info* child; - struct xfuse_file_info* parent; - struct xfuse_file_info* next; - struct xfuse_file_info* prev; +struct xfuse_handle +{ + tui32 DeviceId; + tui32 FileId; }; +typedef struct xfuse_handle XFUSE_HANDLE; + +/* globals */ + +static struct xrdp_fs g_xrdp_fs; /* an inst of xrdp file system */ +static char *g_mount_point = 0; /* our FUSE mount point */ +static struct fuse_lowlevel_ops g_xfuse_ops; /* setup FUSE callbacks */ +static int g_xfuse_inited = 0; /* true when FUSE is inited */ +static struct fuse_chan *g_ch = 0; +static struct fuse_session *g_se = 0; +static char *g_buffer = 0; +static int g_fd = 0; +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_is_inode_valid(int ino); + +// LK_TODO +#if 0 +static void xfuse_create_file(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode, int type); +#endif + +static void xfuse_dump_fs(); +static void xfuse_dump_xrdp_inode(struct xrdp_inode *xino); +static tui32 xfuse_get_device_id_for_inode(tui32 ino, char *full_path); +static void fuse_reverse_pathname(char *full_path, char *reverse_path); + +static struct xrdp_inode * xfuse_get_inode_from_pinode_name(tui32 pinode, + const char *name); -static struct xfuse_file_info *g_fuse_files = 0; -static struct fuse_lowlevel_ops g_xrdp_ll_oper; -static int g_ino = 2; +static struct xrdp_inode * xfuse_create_file_in_xrdp_fs(tui32 device_id, + int pinode, char *name, + int type); -/*****************************************************************************/ -static struct xfuse_file_info *APP_CC -fuse_find_file_info_by_name(struct xfuse_file_info *ffi, const char *filename) +static int xfuse_does_file_exist(int parent, char *name); + +/* forward declarations for calls we make into dev_redir */ +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 dev_redir_file_read(void *fusep, tui32 device_id, tui32 FileId, + tui32 Length, tui64 Offset); + +int dev_redir_file_write(void *fusep, tui32 device_id, tui32 FileId, + const char *buf, tui32 Length, tui64 Offset); + +/* forward declarations for FUSE callbacks */ +static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent, + const char *name); + +static void xfuse_cb_getattr(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + +/* this is not a callback, but its's used by xfuse_cb_readdir() */ +static void xfuse_dirbuf_add(fuse_req_t req, struct dirbuf *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); + +static void xfuse_cb_mkdir(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode); + +static void xfuse_cb_rmdir(fuse_req_t req, fuse_ino_t parent, + const char *name); + +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); + +static void xfuse_cb_open(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); + +static void xfuse_cb_write(fuse_req_t req, fuse_ino_t ino, const char *buf, + size_t size, off_t off, struct fuse_file_info *fi); + +static void xfuse_cb_create(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode, + struct fuse_file_info *fi); + +// LK_TODO may not need to be implemented +#if 0 +static void xfuse_cb_statfs(fuse_req_t req, fuse_ino_t ino); + +static void xfuse_cb_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, + const char *value, size_t size, int flags); + +static void xfuse_cb_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, + size_t size); + +static void xfuse_cb_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size); + +static void xfuse_cb_access(fuse_req_t req, fuse_ino_t ino, int mask); + +static void xfuse_cb_getlk(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, struct flock *lock); + +static void xfuse_cb_setlk(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, struct flock *lock, + int sleep); + +static void xfuse_cb_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, + struct fuse_file_info *fi, unsigned flags, + const void *in_buf, size_t in_bufsz, + size_t out_bufsz); + +static void xfuse_cb_poll(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, + struct fuse_pollhandle *ph); +#endif + +static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, + int to_set, struct fuse_file_info *fi); + +/***************************************************************************** +** ** +** public functions - can be called from any code path ** +** ** +*****************************************************************************/ + +/** + * Initialize FUSE subsystem + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int xfuse_init() { - struct xfuse_file_info *rv; - struct xfuse_file_info *rv1; + char *param0 = "xrdp-chansrv"; + char *argv[4]; - rv = ffi; - while (rv != 0) + /* if already inited, just return */ + if (g_xfuse_inited) { - if (g_strcmp(rv->filename, filename) == 0) - { - return rv; - } - if (rv->flags & 1) + log_debug("already inited"); + return 1; + } + + if (g_ch != 0) + { + log_error("g_ch is not zero"); + return -1; + } + + /* define FUSE mount point to ~/xrdp_client */ + g_snprintf(g_fuse_root_path, 255, "%s/xrdp_client", g_getenv("HOME")); + + /* if FUSE mount point does not exist, create it */ + if (!g_directory_exist(g_fuse_root_path)) + { + if (!g_create_dir(g_fuse_root_path)) { - rv1 = fuse_find_file_info_by_name(rv->child, filename); - if (rv1 != 0) - { - return rv1; - } + log_error("mkdir %s failed. If %s is already mounted, you must " + "first unmount it", g_fuse_root_path, g_fuse_root_path); + return -1; } - rv = rv->next; } + + /* setup xrdp file system */ + if (xfuse_init_xrdp_fs()) + return -1; + + /* 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.open = xfuse_cb_open; + g_xfuse_ops.read = xfuse_cb_read; + g_xfuse_ops.write = xfuse_cb_write; + g_xfuse_ops.create = xfuse_cb_create; + g_xfuse_ops.getattr = xfuse_cb_getattr; + g_xfuse_ops.setattr = xfuse_cb_setattr; + +#if 0 + g_xfuse_ops.statfs = xfuse_cb_statfs; + g_xfuse_ops.listxattr = xfuse_cb_listxattr; + g_xfuse_ops.getlk = xfuse_cb_getlk; + g_xfuse_ops.setlk = xfuse_cb_setlk; + g_xfuse_ops.ioctl = xfuse_cb_ioctl; + g_xfuse_ops.poll = xfuse_cb_poll; + g_xfuse_ops.access = xfuse_cb_access; + g_xfuse_ops.setxattr = xfuse_cb_setxattr; + g_xfuse_ops.getxattr = xfuse_cb_getxattr; +#endif + + argv[0] = param0; + argv[1] = g_fuse_root_path; + argv[2] = 0; + + if (xfuse_init_lib(2, argv)) + { + xfuse_deinit(); + return -1; + } + + g_xfuse_inited = 1; return 0; } -/*****************************************************************************/ -static struct xfuse_file_info *APP_CC -fuse_find_file_info_by_ino(struct xfuse_file_info *ffi, int ino) +/** + * De-initialize FUSE subsystem + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int xfuse_deinit() { - struct xfuse_file_info *rv; - struct xfuse_file_info *rv1; + xfuse_deinit_xrdp_fs(); - rv = ffi; - while (rv != 0) + if (g_ch != 0) { - if (rv->ino == ino) - { - return rv; - } - if (rv->flags & 1) - { - rv1 = fuse_find_file_info_by_ino(rv->child, ino); - if (rv1 != 0) - { - return rv1; - } - } - rv = rv->next; + fuse_session_remove_chan(g_ch); + fuse_unmount(g_mount_point, g_ch); + g_ch = 0; + } + + if (g_se != 0) + { + fuse_session_destroy(g_se); + g_se = 0; + } + + if (g_buffer != 0) + { + g_free(g_buffer); + g_buffer = 0; + } + + g_xfuse_inited = 0; + return 0; +} + +/** + * + * + * @return 0 on success, -1 on failure + *****************************************************************************/ +int xfuse_check_wait_objs(void) +{ + struct fuse_chan *tmpch; + int rval; + +#define HACK + +#ifdef HACK +char buf[135168]; +#endif + + if (g_ch == 0) + return 0; + + if (g_tcp_select(g_fd, 0) & 1) + { + tmpch = g_ch; + +#ifdef HACK + rval = fuse_chan_recv(&tmpch, buf, g_bufsize); +#else + rval = fuse_chan_recv(&tmpch, g_buffer, g_bufsize); +#endif + if (rval == -EINTR) + return -1; + + if (rval == -ENODEV) + return -1; + + if (rval <= 0) + return -1; + +#ifdef HACK + fuse_session_process(g_se, buf, rval, tmpch); +#else + fuse_session_process(g_se, g_buffer, rval, tmpch); +#endif } + + return 0; +} + +/** + * + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int xfuse_get_wait_objs(tbus *objs, int *count, int *timeout) +{ + int lcount; + + if (g_ch == 0) + return 0; + + lcount = *count; + objs[lcount] = g_fd; + lcount++; + *count = lcount; + return 0; } -/*****************************************************************************/ -static int APP_CC -xrdp_ffi2stat(struct xfuse_file_info *ffi, struct stat *stbuf) +/** + * @brief Create specified share directory. + * + * This code gets called from devredir + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int xfuse_create_share(tui32 device_id, char *dirname) { - stbuf->st_ino = ffi->ino; - if (ffi->flags & 1) + /* LK_TODO need to specify parent dir, mode */ + + XFUSE_INFO *fip; + XRDP_INODE *xinode; + tui32 saved_inode; + + if (dirname == NULL || strlen(dirname) == 0) + return -1; + + if ((xinode = calloc(1, sizeof(struct xrdp_inode))) == NULL) { - stbuf->st_mode = S_IFDIR | 0755; - stbuf->st_nlink = 2; - stbuf->st_uid = g_uid; - stbuf->st_gid = g_gid; - stbuf->st_atime = g_time; - stbuf->st_mtime = g_time; - stbuf->st_ctime = g_time; + log_debug("calloc() failed"); + return -1; } - else + + if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL) { - stbuf->st_mode = S_IFREG | 0664; - stbuf->st_nlink = 1; - stbuf->st_size = ffi->size; - stbuf->st_uid = g_uid; - stbuf->st_gid = g_gid; - stbuf->st_atime = g_time; - stbuf->st_mtime = g_time; - stbuf->st_ctime = g_time; + log_error("system out of memory"); + return -1; } + + /* create directory entry */ + xinode->parent_inode = 1; + xinode->inode = g_xrdp_fs.next_node++; + xinode->mode = 0755 | S_IFDIR; + xinode->nlink = 1; + xinode->uid = getuid(); + xinode->gid = getgid(); + xinode->size = 0; + xinode->atime = time(0); + xinode->mtime = time(0); + xinode->ctime = time(0); + strcpy(xinode->name, dirname); + xinode->device_id = device_id; + + g_xrdp_fs.num_entries++; + saved_inode = xinode->inode; + + /* insert it in xrdp fs */ + g_xrdp_fs.inode_table[xinode->inode] = xinode; + log_debug("created new share named %s at inode_table[%d]", + dirname, (int) xinode->inode); + + /* update nentries in parent inode */ + xinode = g_xrdp_fs.inode_table[1]; + if (xinode == NULL) + return -1; + xinode->nentries++; + + /* enumerate root dir, do not call FUSE when done */ + fip->req = NULL; + fip->inode = 1; // LK_TODO saved_inode; + strncpy(fip->name, dirname, 1024); + fip->name[1023] = 0; + fip->device_id = device_id; + + dev_redir_get_dir_listing((void *) fip, device_id, "\\"); + return 0; } -/*****************************************************************************/ -static void DEFAULT_CC -xrdp_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) +/** + * + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int xfuse_clear_clip_dir(void) +{ + return 0; // CLIPBOARD_TODO +} + +/** + * + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int xfuse_file_contents_range(int stream_id, char *data, int data_bytes) +{ + return 0; // CLIPBOARD_TODO +} + +/** + * + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int xfuse_add_clip_dir_item(char *filename, int flags, int size, int lindex) +{ + return 0; // CLIPBOARD_TODO +} + +/** + * + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +int xfuse_file_contents_size(int stream_id, int file_size) +{ + return 0; // CLIPBOARD_TODO +} + +/***************************************************************************** +** ** +** private functions - can only be called from within this file ** +** ** +*****************************************************************************/ + +/** + * Initialize FUSE library + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +static int xfuse_init_lib(int argc, char **argv) { - struct xfuse_file_info *ffi; - struct fuse_entry_param e; + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - LLOGLN(10, ("xrdp_ll_lookup: name %s", name)); - if (parent != 1) + if (fuse_parse_cmdline(&args, &g_mount_point, 0, 0) < 0) { - fuse_reply_err(req, ENOENT); + log_error("fuse_parse_cmdline() failed"); + fuse_opt_free_args(&args); + return -1; } - else + + if ((g_ch = fuse_mount(g_mount_point, &args)) == 0) { - ffi = fuse_find_file_info_by_name(g_fuse_files, name); - if (ffi != 0) - { - LLOGLN(10, ("xrdp_ll_lookup: name %s ino %d", name, ffi->ino)); - g_memset(&e, 0, sizeof(e)); - e.ino = ffi->ino; - e.attr_timeout = 1.0; - e.entry_timeout = 1.0; - xrdp_ffi2stat(ffi, &e.attr); - fuse_reply_entry(req, &e); - return; - } + log_error("fuse_mount() failed"); + fuse_opt_free_args(&args); + return -1; } - fuse_reply_err(req, ENOENT); + + 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); + return -1; + } + + fuse_opt_free_args(&args); + fuse_session_add_chan(g_se, g_ch); + g_bufsize = fuse_chan_bufsize(g_ch); + + g_buffer = calloc(g_bufsize, 1); + g_fd = fuse_chan_fd(g_ch); + + return 0; } -/*****************************************************************************/ -static void DEFAULT_CC -xrdp_ll_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) +/** + * Initialize xrdp file system + * + * @return 0 on success, -1 on failure + * + *****************************************************************************/ + +static int xfuse_init_xrdp_fs() { - struct stat stbuf; - struct xfuse_file_info *ffi; + struct xrdp_inode *xino; - LLOGLN(10, ("xrdp_ll_getattr: ino %d", ino)); - g_memset(&stbuf, 0, sizeof(stbuf)); - if (ino == 1) + g_xrdp_fs.inode_table = calloc(4096, sizeof(struct xrdp_inode *)); + if (g_xrdp_fs.inode_table == NULL) { - stbuf.st_mode = S_IFDIR | 0755; - stbuf.st_nlink = 2; - stbuf.st_uid = g_uid; - stbuf.st_gid = g_gid; - stbuf.st_atime = g_time; - stbuf.st_mtime = g_time; - stbuf.st_ctime = g_time; - fuse_reply_attr(req, &stbuf, 1.0); - return; + log_error("system out of memory"); + return -1; } - ffi = fuse_find_file_info_by_ino(g_fuse_files, ino); - if (ffi == 0) + + /* + * index 0 is our .. dir + */ + + if ((xino = calloc(1, sizeof(struct xrdp_inode))) == NULL) { - LLOGLN(0, ("xrdp_ll_getattr: fuse_find_file_info_by_ino failed ino %d", ino)); - fuse_reply_err(req, ENOENT); + log_error("system out of memory"); + free(g_xrdp_fs.inode_table); + return -1; } - else if (xrdp_ffi2stat(ffi, &stbuf) == -1) + g_xrdp_fs.inode_table[0] = xino; + xino->parent_inode = 0; + xino->inode = 0; + xino->mode = S_IFDIR | 0755; + xino->nentries = 1; + xino->uid = getuid(); + xino->gid = getgid(); + xino->size = 0; + xino->atime = time(0); + xino->mtime = time(0); + xino->ctime = time(0); + strcpy(xino->name, ".."); + + /* + * index 1 is our . dir + */ + + if ((xino = calloc(1, sizeof(struct xrdp_inode))) == NULL) { - fuse_reply_err(req, ENOENT); + log_error("system out of memory"); + free(g_xrdp_fs.inode_table[0]); + free(g_xrdp_fs.inode_table); + return -1; } - else + g_xrdp_fs.inode_table[1] = xino; + xino->parent_inode = 0; + xino->inode = 1; + xino->mode = S_IFDIR | 0755; + xino->nentries = 1; + xino->uid = getuid(); + xino->gid = getgid(); + xino->size = 0; + xino->atime = time(0); + xino->mtime = time(0); + xino->ctime = time(0); + strcpy(xino->name, "."); + + /* + * index 2 is for clipboard use + */ + + if ((xino = calloc(1, sizeof(struct xrdp_inode))) == NULL) { - fuse_reply_attr(req, &stbuf, 1.0); + log_error("system out of memory"); + free(g_xrdp_fs.inode_table[0]); + free(g_xrdp_fs.inode_table[1]); + free(g_xrdp_fs.inode_table); + return -1; } + + g_xrdp_fs.inode_table[2] = xino; + xino->parent_inode = 1; + xino->inode = 2; + xino->nentries = 1; + xino->mode = S_IFDIR | 0755; + xino->uid = getuid(); + xino->gid = getgid(); + xino->size = 0; + xino->atime = time(0); + xino->mtime = time(0); + xino->ctime = time(0); + strcpy(xino->name, ".clipboard"); + + g_xrdp_fs.max_entries = 1024; + g_xrdp_fs.num_entries = 3; + g_xrdp_fs.next_node = 3; + + return 0; } -/*****************************************************************************/ -static void APP_CC -dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name, fuse_ino_t ino) +/** + * zap the xrdp file system + * + * @return 0 on success, -1 on failure + *****************************************************************************/ + +static int xfuse_deinit_xrdp_fs() { - struct stat stbuf; - char *newp; - int oldsize; - - oldsize = b->size; - b->size += fuse_add_direntry(req, 0, 0, name, 0, 0); - LLOGLN(10, ("1 %d %d %d", b->alloc_bytes, b->size, oldsize)); - if (b->size > b->alloc_bytes) - { - b->alloc_bytes = (b->size + 1023) & (~1023); - LLOGLN(10, ("2 %d %d %d", b->alloc_bytes, b->size, oldsize)); - newp = g_malloc(b->alloc_bytes, 0); - g_memcpy(newp, b->p, oldsize); - g_free(b->p); - b->p = newp; - } - g_memset(&stbuf, 0, sizeof(stbuf)); - stbuf.st_ino = ino; - fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, - &stbuf, b->size); + return 0; +} + +/** + * determine if specified ino exists in xrdp file system + * + * @return 1 if it does, 0 otherwise + *****************************************************************************/ + +static int xfuse_is_inode_valid(int ino) +{ + /* our lowest ino is FIRST_INODE */ + if (ino < FIRST_INODE) + return 0; + + /* is ino present in our table? */ + if (ino >= g_xrdp_fs.next_node) + return 0; + + return 1; } -#define lmin(x, y) ((x) < (y) ? (x) : (y)) +/** + * @brief Create a directory or regular file. + *****************************************************************************/ + +// LK_TODO +#if 0 +static void xfuse_create_file(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode, int type) +{ + struct xrdp_inode *xinode; + struct fuse_entry_param e; + + log_debug("parent=%d name=%s", (int) parent, name); + + /* do we have a valid parent inode? */ + if (!xfuse_is_inode_valid(parent)) + { + log_error("inode %d is not valid", parent); + fuse_reply_err(req, EBADF); + } + + if ((xinode = calloc(1, sizeof(struct xrdp_inode))) == NULL) + { + log_error("calloc() failed"); + fuse_reply_err(req, ENOMEM); + } + + /* create directory entry */ + xinode->parent_inode = parent; + xinode->inode = g_xrdp_fs.next_node++; /* TODO should be thread safe */ + xinode->mode = mode | type; + xinode->uid = getuid(); + xinode->gid = getgid(); + xinode->size = 0; + xinode->atime = time(0); + xinode->mtime = time(0); + xinode->ctime = time(0); + strcpy(xinode->name, name); + + g_xrdp_fs.num_entries++; + + /* insert it in xrdp fs */ + g_xrdp_fs.inode_table[xinode->inode] = xinode; + log_debug("inserted new dir at inode_table[%d]", (int) xinode->inode); + + xfuse_dump_fs(); + + log_debug("new inode=%d", (int) xinode->inode); -/*****************************************************************************/ -static int APP_CC -reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize, - off_t off, size_t maxsize) + /* setup return value */ + 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 = 0; + 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); +} +#endif + +static void xfuse_dump_fs() { - LLOGLN(10, ("reply_buf_limited: %d", maxsize)); - if (off < bufsize) + int i; + struct xrdp_inode *xinode; + + log_debug("found %d entries", g_xrdp_fs.num_entries - FIRST_INODE); + + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) { - return fuse_reply_buf(req, buf + off, - lmin(bufsize - off, maxsize)); + xinode = g_xrdp_fs.inode_table[i]; + 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); } - else + log_debug(""); +} + +/** + * Dump contents of xinode structure + * + * @param xino xinode structure to dump + *****************************************************************************/ + +static void xfuse_dump_xrdp_inode(struct xrdp_inode *xino) +{ + log_debug("--- dumping struct xinode ---"); + log_debug("name: %s", xino->name); + log_debug("parent_inode: %ld", xino->parent_inode); + log_debug("inode: %ld", xino->inode); + log_debug("mode: %o", xino->mode); + log_debug("nlink: %d", xino->nlink); + log_debug("uid: %d", xino->uid); + log_debug("gid: %d", xino->gid); + log_debug("size: %ld", xino->size); + log_debug("device_id: %d", xino->device_id); + log_debug(""); +} + +/** + * Return the device_id associated with specified inode and copy the + * full path to the specified inode into full_path + * + * @param ino the inode + * @param full_path full path to the inode + * + * @return the device_id of specified inode + *****************************************************************************/ + +static tui32 xfuse_get_device_id_for_inode(tui32 ino, char *full_path) +{ + tui32 parent_inode = 0; + tui32 child_inode = ino; + char reverse_path[4096]; + + reverse_path[0] = 0; + full_path[0] = 0; + + /* ino == 1 is a special case; we already know that it is not */ + /* associated with any device redirection */ + if (ino == 1) + return 0; + + while (1) { - return fuse_reply_buf(req, 0, 0); + strcat(reverse_path, g_xrdp_fs.inode_table[child_inode]->name); + + parent_inode = g_xrdp_fs.inode_table[child_inode]->parent_inode; + if (parent_inode == 1) + break; + + strcat(reverse_path, "/"); + child_inode = parent_inode; } + + fuse_reverse_pathname(full_path, reverse_path); + + return g_xrdp_fs.inode_table[child_inode]->device_id; } -/*****************************************************************************/ -static void DEFAULT_CC -xrdp_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t off, struct fuse_file_info *fi) +/** + * Reverse the pathname in 'reverse_path' and insert it into 'full_path' + * + * Example: abba/music/share1 becomes share1/music/abba + * + * @param full_path path name in the correct order + * @param reverse_path path name in the reverse order + *****************************************************************************/ + +static void fuse_reverse_pathname(char *full_path, char *reverse_path) { - struct xfuse_file_info *ffi; - struct dirbuf b; + char *cptr; - LLOGLN(10, ("xrdp_ll_readdir: ino %d", ino)); - if (ino != 1) + full_path[0] = 0; + + while ((cptr = strrchr(reverse_path, '/')) != NULL) { - fuse_reply_err(req, ENOTDIR); + strcat(full_path, cptr + 1); + strcat(full_path, "/"); + cptr[0] = 0; } - else + strcat(full_path, reverse_path); +} + +/** + * Return the inode that matches the name and parent inode + *****************************************************************************/ + +static struct xrdp_inode * xfuse_get_inode_from_pinode_name(tui32 pinode, + const char *name) +{ + int i; + struct xrdp_inode * xinode; + + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) { - ffi = g_fuse_files; - g_memset(&b, 0, sizeof(b)); - dirbuf_add(req, &b, ".", 1); - dirbuf_add(req, &b, "..", 1); - while (ffi != 0) - { - LLOGLN(10, ("xrdp_ll_readdir: %s", ffi->filename)); - dirbuf_add(req, &b, ffi->filename, ffi->ino); - ffi = ffi->next; - } - reply_buf_limited(req, b.p, b.size, off, size); - g_free(b.p); + xinode = g_xrdp_fs.inode_table[i]; + + /* match parent inode */ + if (xinode->parent_inode != pinode) + continue; + + /* match name */ + if (strcmp(xinode->name, name) != 0) + continue; + + return xinode; } + return NULL; } -/*****************************************************************************/ -static void DEFAULT_CC -xrdp_ll_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) +/** + * Create file in xrdp file system + * + * @param pinode the parent inode + * @param name filename + * + * @return XRDP_INODE on success, NULL on failure + *****************************************************************************/ + +static struct xrdp_inode * xfuse_create_file_in_xrdp_fs(tui32 device_id, + int pinode, char *name, + int type) { - LLOGLN(10, ("xrdp_ll_open: ino %d", (int)ino)); - if (ino == 1) + XRDP_INODE *xinode; + XRDP_INODE *xinodep; + + if ((name == NULL) || (strlen(name) == 0)) + return NULL; + + if ((xinode = calloc(1, sizeof(XRDP_INODE))) == NULL) { - fuse_reply_err(req, EISDIR); + log_error("system out of memory"); + return NULL; } - else if ((fi->flags & 3) != O_RDONLY) + + 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->nlink = 1; + xinode->uid = getuid(); + xinode->gid = getgid(); + xinode->atime = time(0); + xinode->mtime = time(0); + xinode->ctime = time(0); + xinode->device_id = device_id; + xinode->is_synced = 1; + strcpy(xinode->name, name); + + if (type == S_IFDIR) { - fuse_reply_err(req, EACCES); + xinode->mode = 0755 | type; + xinode->size = 4096; } else { - fuse_reply_open(req, fi); + xinode->mode = 0644 | type; + xinode->size = 0; } + + g_xrdp_fs.inode_table[xinode->inode] = xinode; + g_xrdp_fs.num_entries++; /* TODO should be thread safe */ + + /* bump up lookup count in parent dir */ + xinodep = g_xrdp_fs.inode_table[pinode]; + xinodep->nentries++; + + log_debug("LK_TODO: incremented nentries; parent=%d nentries=%d", + pinode, xinodep->nentries); + + /* LK_TODO */ + xfuse_dump_fs(); + + return xinode; } -/*****************************************************************************/ -static void DEFAULT_CC -xrdp_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size, - off_t off, struct fuse_file_info *fi) +/** + * Check if specified file exists + * + * @param parent parent inode of file + * @param name flilename or dirname + * + * @return 1 if specified file exists, 0 otherwise + *****************************************************************************/ + +static int xfuse_does_file_exist(int parent, char *name) { - char *data; - int stream_id; - struct xfuse_file_info *ffi; - struct req_list_item *rli; + int i; + XRDP_INODE *xinode; - LLOGLN(10, ("xrdp_ll_read: %d %d %d", (int)ino, (int)off, (int)size)); - ffi = fuse_find_file_info_by_ino(g_fuse_files, ino); - if (ffi != 0) + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) { - /* reply later */ - stream_id = 0; - rli = (struct req_list_item *) - g_malloc(sizeof(struct req_list_item), 1); - rli->req = req; - rli->stream_id = stream_id; - rli->lindex = ffi->lindex; - rli->off = off; - rli->size = size; - list_add_item(g_req_list, (tbus)rli); - if (g_req_list->count == 1) + xinode = g_xrdp_fs.inode_table[i]; + + if ((xinode->parent_inode == parent) && + (strcmp(xinode->name, name) == 0)) { - clipboard_request_file_data(rli->stream_id, rli->lindex, - rli->off, rli->size); + return 1; } + } + + return 0; +} + +/****************************************************************************** +** ** +** callbacks for devredir ** +** ** +******************************************************************************/ + +/** + * Add a file or directory to xrdp file system + *****************************************************************************/ + +void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode) +{ + XFUSE_INFO *fip = (XFUSE_INFO *) vp; + XRDP_INODE *target_inode; + + if ((fip == NULL) || (xinode == NULL)) + { + log_error("fip or xinode are NULL"); + return; + } + + /* do we have a valid inode? */ + 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; } - LLOGLN(0, ("xrdp_ll_read: fuse_find_file_info_by_ino failed ino %d", (int)ino)); - data = (char *)g_malloc(size, 1); - fuse_reply_buf(req, data, size); - g_free(data); + /* 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) + return; + + xinode->parent_inode = target_inode->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 */ + g_xrdp_fs.inode_table[xinode->inode] = xinode; + + /* bump up lookup count */ + xinode = g_xrdp_fs.inode_table[target_inode->inode]; + xinode->nentries++; + + log_debug("added %s to pinode=%d, nentries=%d target_inode->inode=%d", + fip->name, fip->inode, xinode->nentries, target_inode->inode); } -/*****************************************************************************/ -/* returns error */ -static int APP_CC -fuse_init_lib(int argc, char **argv) +/** + *****************************************************************************/ + +void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus) { - struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - int error; + struct xrdp_inode *xinode; + struct fuse_entry_param e; + int i; - error = fuse_parse_cmdline(&args, &g_mountpoint, 0, 0); - if (error == -1) + XFUSE_INFO *fip = (XFUSE_INFO *) vp; + + xfuse_dump_fs(); + + if (fip == NULL) { - LLOGLN(0, ("fuse_init_lib: fuse_parse_cmdline failed")); - fuse_opt_free_args(&args); - return 1; + log_debug("fip is NULL"); + goto done; } - g_ch = fuse_mount(g_mountpoint, &args); - if (g_ch == 0) + + if (IoStatus != 0) { - LLOGLN(0, ("fuse_init_lib: fuse_mount failed")); - fuse_opt_free_args(&args); - return 1; + /* command failed */ + if (fip->invoke_fuse) + fuse_reply_err(fip->req, ENOENT); + goto done; } - g_se = fuse_lowlevel_new(&args, &g_xrdp_ll_oper, - sizeof(g_xrdp_ll_oper), 0); - if (g_se == 0) + + /* do we have a valid inode? */ + if (!xfuse_is_inode_valid(fip->inode)) { - LLOGLN(0, ("fuse_init_lib: fuse_lowlevel_new failed")); - fuse_unmount(g_mountpoint, g_ch); - g_ch = 0; - fuse_opt_free_args(&args); - return 1; + log_error("inode %d is not valid", fip->inode); + if (fip->invoke_fuse) + fuse_reply_err(fip->req, EBADF); + goto done; } - fuse_opt_free_args(&args); - fuse_session_add_chan(g_se, g_ch); - g_bufsize = fuse_chan_bufsize(g_ch); - g_buffer = g_malloc(g_bufsize, 0); - g_fd = fuse_chan_fd(g_ch); - return 0; + + log_debug("looking for parent_inode=%d name=%s", fip->inode, fip->name); + + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) + { + xinode = g_xrdp_fs.inode_table[i]; + + /* 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); } -/*****************************************************************************/ -static int APP_CC -fuse_delete_dir_items(struct xfuse_file_info *ffi) +void xfuse_devredir_cb_open_file(void *vp, tui32 DeviceId, tui32 FileId) { - struct xfuse_file_info *ffi1; + XFUSE_HANDLE *fh; + + XFUSE_INFO *fip = (XFUSE_INFO *) vp; + if (fip == NULL) + { + log_debug("fip is NULL"); + goto done; + } - while (ffi != 0) + if (fip->fi != NULL) { - if (ffi->flags & 1) + log_debug("$$$$$$$$$$$$$$$ allocationg fh"); + + /* LK_TODO fH NEEDS TO BE RELEASED WHEN THE FILE IS CLOSED */ + if ((fh = calloc(1, sizeof(XFUSE_HANDLE))) == NULL) { - fuse_delete_dir_items(ffi->child); + log_error("system out of memory"); + free(fip); + if (fip->invoke_fuse) + fuse_reply_err(fip->req, ENOMEM); + return; } - ffi1 = ffi; - ffi = ffi->next; - g_free(ffi1); + + /* save file handle for later use */ + fh->DeviceId = DeviceId; + fh->FileId = FileId; + + fip->fi->fh = (uint64_t) fh; } - return 0; + + if (fip->invoke_fuse) + { + if (fip->reply_type == RT_FUSE_REPLY_OPEN) + { + log_debug("LK_TODO sending fuse_reply_open(); " + "DeviceId=%d FileId=%d req=%p fi=%p", + fh->DeviceId, fh->FileId, fip->req, fip->fi); + + 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 +#if 0 + if ((xinode = g_xrdp_fs.inode_table[fip->inode]) == NULL) + { + log_error("inode at inode_table[%d] is NULL", fip->inode); + fuse_reply_err(fip->req, EBADF); + goto done; + } +#else + /* create entry in xrdp file system */ + xinode = xfuse_create_file_in_xrdp_fs(fip->device_id, fip->inode, + fip->name, fip->mode); + if (xinode == NULL) + { + fuse_reply_err(fip->req, ENOMEM); + return; + } +#endif + memset(&e, 0, sizeof(struct fuse_entry_param)); + + 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; + + if (fip->mode == S_IFDIR) + fuse_reply_entry(fip->req, &e); + else + fuse_reply_create(fip->req, &e, fip->fi); + } + else + { + log_error("invalid reply type: %d", fip->reply_type); + } + } + +done: + + free(fip); } -/*****************************************************************************/ -int APP_CC -fuse_clear_clip_dir(void) +void xfuse_devredir_cb_read_file(void *vp, char *buf, size_t length) { - fuse_delete_dir_items(g_fuse_files); - g_fuse_files = 0; - return 0; + XFUSE_HANDLE *fh; + XFUSE_INFO *fip; + + fip = (XFUSE_INFO *) vp; + if (fip == NULL) + goto done; + + fuse_reply_buf(fip->req, buf, length); + +done: + + fh = (XFUSE_HANDLE *) fip->fi->fh; + free(fh); + free(fip); } -/*****************************************************************************/ -/* returns error */ -int APP_CC -fuse_add_clip_dir_item(char *filename, int flags, int size, int lindex) +void xfuse_devredir_cb_write_file(void *vp, char *buf, size_t length) { - struct xfuse_file_info *ffi; - struct xfuse_file_info *ffi1; + XRDP_INODE *xinode; + XFUSE_HANDLE *fh; + XFUSE_INFO *fip; - LLOGLN(10, ("fuse_add_clip_dir_item: adding %s ino %d", filename, g_ino)); - ffi = g_fuse_files; - if (ffi == 0) - { - ffi1 = (struct xfuse_file_info *) - g_malloc(sizeof(struct xfuse_file_info), 1); - ffi1->flags = flags; - ffi1->ino = g_ino++; - ffi1->lindex = lindex; - ffi1->size = size; - g_strncpy(ffi1->filename, filename, 255); - g_fuse_files = ffi1; - return 0; - } - while (ffi->next != 0) - { - ffi = ffi->next; - } - ffi1 = (struct xfuse_file_info *) - g_malloc(sizeof(struct xfuse_file_info), 1); - ffi1->flags = flags; - ffi1->ino = g_ino++; - ffi1->lindex = lindex; - ffi1->size = size; - g_strncpy(ffi1->filename, filename, 255); - ffi->next = ffi1; - return 0; + fip = (XFUSE_INFO *) vp; + if (fip == NULL) + goto done; + + 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[%d] is NULL", fip->inode); + +done: + + fh = (XFUSE_HANDLE *) fip->fi->fh; + free(fh); + free(fip); } -/*****************************************************************************/ -int APP_CC -fuse_get_wait_objs(tbus *objs, int *count, int *timeout) +/****************************************************************************** +** ** +** callbacks for fuse ** +** ** +******************************************************************************/ + +/** + * Look up a directory entry by name and get its attributes + * + *****************************************************************************/ + +static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { - int lcount; + XFUSE_INFO *fip; + XRDP_INODE *xinode; + struct fuse_entry_param e; + tui32 device_id; + char full_path[4096]; + char *cptr; - LLOGLN(10, ("fuse_get_wait_objs:")); - if (g_ch == 0) + log_debug("ENTERED: looking for parent=%d name=%s", (int) parent, name); + + xfuse_dump_fs(); + + if (!xfuse_is_inode_valid(parent)) { - return 0; + log_error("inode %d is not valid", parent); + fuse_reply_err(req, EBADF); + return; } - lcount = *count; - objs[lcount] = g_fd; - lcount++; - *count = lcount; - return 0; -} +// LK_TODO +#if 0 + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) + { + xinode = g_xrdp_fs.inode_table[i]; -/*****************************************************************************/ -int APP_CC -fuse_check_wait_objs(void) -{ - struct fuse_chan *tmpch; - int res; + /* match parent inode */ + if (xinode->parent_inode != parent) + continue; - LLOGLN(10, ("fuse_check_wait_objs:")); - if (g_ch == 0) + /* match name */ + if (strcmp(xinode->name, name) != 0) + continue; + + /* got a full match; if this dir is located on a remote device */ + /* and is not synced, do a remote look up */ + if ((xinode->device_id != 0) && (!xinode->is_synced)) + goto do_remote_lookup; + + 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 in xrdp fs; returning"); + return; + } +#else + if ((xinode = xfuse_get_inode_from_pinode_name(parent, name)) != NULL) { - return 0; + /* got a full match; if this dir is located on a remote device */ + /* and is not synced, do a remote look up */ + if ((xinode->device_id != 0) && (!xinode->is_synced)) + goto do_remote_lookup; + + 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 in xrdp fs; returning"); + return; } - if (g_tcp_select(g_fd, 0) & 1) + +#endif + +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(...) */ + device_id = xfuse_get_device_id_for_inode((tui32) parent, full_path); + if (device_id != 0) { - LLOGLN(10, ("fuse_check_wait_objs: fd is set")); - tmpch = g_ch; - res = fuse_chan_recv(&tmpch, g_buffer, g_bufsize); - if (res == -EINTR) + log_debug("did not find entry; redirecting call to dev_redir"); + + if ((fip = calloc(1, sizeof(XFUSE_INFO))) == NULL) { - return 0; + log_error("system out of memory"); + fuse_reply_err(req, ENOMEM); + return; } - if (res <= 0) + fip->req = req; + fip->inode = parent; + strncpy(fip->name, name, 1024); + fip->name[1023] = 0; + fip->invoke_fuse = 1; + fip->device_id = device_id; + + strcat(full_path, "/"); + strcat(full_path, name); + + /* we want path minus 'root node of the share' */ + if ((cptr = strchr(full_path, '/')) == NULL) { - return 1; + /* 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 + { + log_debug("dev_redir_get_dir_listing() called"); + } + } - fuse_session_process(g_se, g_buffer, res, tmpch); + 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); + } + } + + log_debug("cmd sent; reting"); + return; } - return 0; + + log_debug("parent=%d name=%s not found", (int) parent, name); + fuse_reply_err(req, ENOENT); } -/*****************************************************************************/ -/* returns error */ -int APP_CC -fuse_init(void) +/** + * Get file attributes + *****************************************************************************/ + +static void xfuse_cb_getattr(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) { - char *param0 = "xrdp-chansrv"; - char *argv[4]; + struct xrdp_inode *xino; + struct stat stbuf; - if (g_ch != 0) + (void) fi; + + log_debug("ino=%d", (int) ino); + + /* if ino is not valid, just return */ + if (!xfuse_is_inode_valid(ino)) { - return 0; + log_error("inode %d is not valid", ino); + fuse_reply_err(req, EBADF); + return; } - g_snprintf(g_fuse_root_path, 255, "%s/xrdp_client", g_getenv("HOME")); - LLOGLN(0, ("fuse_init: using root_path [%s]", g_fuse_root_path)); - if (!g_directory_exist(g_fuse_root_path)) + + xino = g_xrdp_fs.inode_table[ino]; + xfuse_dump_xrdp_inode(xino); + + memset(&stbuf, 0, sizeof(stbuf)); + stbuf.st_ino = ino; + stbuf.st_mode = xino->mode; + stbuf.st_nlink = xino->nlink; + stbuf.st_size = xino->size; + + fuse_reply_attr(req, &stbuf, 1.0); +} + +/** + * + *****************************************************************************/ + +static void xfuse_dirbuf_add(fuse_req_t req, struct dirbuf *b, + const char *name, fuse_ino_t ino) +{ + struct stat stbuf; + size_t oldsize = b->size; + + log_debug("adding ino=%d name=%s", (int) ino, name); + + b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0); + b->p = (char *) realloc(b->p, b->size); + + memset(&stbuf, 0, sizeof(stbuf)); + stbuf.st_ino = ino; + fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf, + b->size); +} + +/** + * + *****************************************************************************/ + +static void xfuse_cb_readdir(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; + + log_debug("looking for dir with inode=%d", ino); + + if (!xfuse_is_inode_valid(ino)) { - if (!g_create_dir(g_fuse_root_path)) - { - LLOGLN(0, ("fuse_init: g_create_dir failed [%s]", - g_fuse_root_path)); - return 1; - } + log_error("inode %d is not valid", ino); + fuse_reply_err(req, EBADF); + return; + } + + /* does this dir have any entries? */ + xinode = g_xrdp_fs.inode_table[ino]; + memset(&b, 0, sizeof(b)); + if (ino == 1) + { + xfuse_dirbuf_add(req, &b, ".", 1); + xfuse_dirbuf_add(req, &b, "..", 1); + } + else + { + xfuse_dirbuf_add(req, &b, ".", xinode->inode); + xfuse_dirbuf_add(req, &b, "..", xinode->parent_inode); } - g_time = g_time1(); - g_uid = g_getuid(); - g_gid = g_getgid(); - argv[0] = param0; - argv[1] = g_fuse_root_path; - argv[2] = 0; - g_memset(&g_xrdp_ll_oper, 0, sizeof(g_xrdp_ll_oper)); - g_xrdp_ll_oper.lookup = xrdp_ll_lookup; - g_xrdp_ll_oper.getattr = xrdp_ll_getattr; - g_xrdp_ll_oper.readdir = xrdp_ll_readdir; - g_xrdp_ll_oper.open = xrdp_ll_open; - g_xrdp_ll_oper.read = xrdp_ll_read; + for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++) + { + xinode = g_xrdp_fs.inode_table[i]; + if (xinode->parent_inode == ino) + xfuse_dirbuf_add(req, &b, xinode->name, xinode->inode); + } - g_req_list = list_create(); - g_req_list->auto_free = 1; + if (off < b.size) + fuse_reply_buf(req, b.p + off, min(b.size - off, size)); + else + fuse_reply_buf(req, NULL, 0); - return fuse_init_lib(2, argv); + free(b.p); } -/*****************************************************************************/ -/* returns error */ -int APP_CC -fuse_deinit(void) +/** + * Create a directory + *****************************************************************************/ + +static void xfuse_cb_mkdir(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode) { - LLOGLN(0, ("fuse_deinit:")); - if (g_ch != 0) + XRDP_INODE *xinode; + struct fuse_entry_param e; + + if ((xinode = xfuse_get_inode_from_pinode_name(parent, name)) != NULL) { - LLOGLN(0, ("fuse_deinit: calling fuse_unmount")); - fuse_session_remove_chan(g_ch); - fuse_unmount(g_mountpoint, g_ch); - g_ch = 0; + /* dir already exists, just return it */ + memset(&e, 0, sizeof(struct fuse_entry_param)); + + 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); + return; } - if (g_se != 0) + + /* dir does not exist, create it */ + xfuse_create_dir_or_file(req, parent, name, mode, NULL, S_IFDIR); +} + +/** + * Remove specified dir + *****************************************************************************/ + +static void xfuse_cb_rmdir(fuse_req_t req, fuse_ino_t parent, + const char *name) +{ + XRDP_INODE *xinode; + + log_debug("entered: parent=%d name=%s", parent, name); + + /* is parent inode valid? */ + if (!xfuse_is_inode_valid(parent)) { - LLOGLN(0, ("fuse_deinit: calling fuse_session_destroy")); - fuse_session_destroy(g_se); - g_se = 0; + log_error("inode %d is not valid", parent); + fuse_reply_err(req, EBADF); + return; } - if (g_buffer != 0) + + if ((xinode = xfuse_get_inode_from_pinode_name(parent, name)) == NULL) { - g_free(g_buffer); - g_buffer = 0; + log_error("did not find file with pinode=%d name=%s", parent, name); + fuse_reply_err(req, EBADF); + return; } - if (g_req_list != 0) + + log_debug("nentries is %d", xinode->nentries); + + if (xinode->nentries != 0) { - list_delete(g_req_list); - g_req_list = 0; + log_debug("cannot rmdir; lookup count is %d", xinode->nentries); + fuse_reply_err(req, ENOTEMPTY); + return; } - return 0; + fuse_reply_err(req, 0); + } -/*****************************************************************************/ -int APP_CC -fuse_file_contents_size(int stream_id, int file_size) +/** + * Create a directory or file + * + * @param req opaque FUSE object + * @param parent parent inode + * @param name name of dir or file to create + * @param mode creation mode + * @param fi for storing file handles + * @param type S_IFDIR for dir and S_IFREG for file + *****************************************************************************/ + +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) { - LLOGLN(10, ("fuse_file_contents_size: file_size %d", file_size)); - return 0; + XFUSE_INFO *fip; // LK_TODO use only XFUSE_INFO instead of struct + char *cptr; + char full_path[1024]; + tui32 device_id; + + full_path[0] = 0; + + log_debug("entered: type = %s", (type == S_IFDIR) ? "dir" : "file"); + + /* name must be valid */ + if ((name == NULL) || (strlen(name) == 0)) + { + log_error("invalid name"); + fuse_reply_err(req, EBADF); + return; + } + + /* is parent inode valid? */ + if (!xfuse_is_inode_valid(parent)) + { + log_error("inode %d is not valid", parent); + fuse_reply_err(req, EBADF); + return; + } + + device_id = xfuse_get_device_id_for_inode(parent, full_path); + 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->fi = fi; + fip->inode = parent; + fip->invoke_fuse = 1; + fip->device_id = device_id; + fip->mode = type; + fip->reply_type = RT_FUSE_REPLY_CREATE; + strncpy(fip->name, name, 1024); + fip->name[1023] = 0; + + /* LK_TODO need to handle open permissions */ + + /* we want path minus 'root node of the share' */ + if ((cptr = strchr(full_path, '/')) == NULL) + { + /* get dev_redir to open the remote file */ + if (dev_redir_file_open((void *) fip, device_id, "\\", O_CREAT, type)) + { + log_error("failed to send dev_redir_open_file() cmd"); + fuse_reply_err(req, EREMOTEIO); + } + } + else + { + if (dev_redir_file_open((void *) fip, device_id, cptr, O_CREAT, type)) + { + log_error("failed to send dev_redir_get_dir_listing() cmd"); + fuse_reply_err(req, EREMOTEIO); + } + } } -/*****************************************************************************/ -int APP_CC -fuse_file_contents_range(int stream_id, char *data, int data_bytes) +/** + * Open specified file + *****************************************************************************/ + +static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi) { - struct req_list_item *rli; + XRDP_INODE *xinode; + XFUSE_INFO *fip; + char *cptr; + char full_path[4096]; + tui32 device_id; + + log_debug("LK_TODO: open_flags=0x%x req=%p fi=%p", + fi->flags, req, fi); + + if (!xfuse_is_inode_valid(ino)) + { + log_error("inode %d is not valid", ino); + fuse_reply_err(req, EBADF); + return; + } - LLOGLN(10, ("fuse_file_contents_range: data_bytes %d", data_bytes)); - rli = (struct req_list_item *)list_get_item(g_req_list, 0); - if (rli != 0) + /* if ino points to a dir, fail the open request */ + xinode = g_xrdp_fs.inode_table[ino]; + if (xinode->mode & S_IFDIR) { - fuse_reply_buf(rli->req, data, data_bytes); - list_remove_item(g_req_list, 0); - if (g_req_list->count > 0) + log_debug("reading a dir not allowed!"); + fuse_reply_err(req, EISDIR); + return; + } + + device_id = xfuse_get_device_id_for_inode((tui32) ino, full_path); + if (device_id) + { + /* specified file resides on redirected share */ + + log_debug("LK_TODO looking for file %s in DeviceId=%d", full_path, device_id); + + 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 = device_id; + fip->fi = fi; + strncpy(fip->name, full_path, 1024); + fip->name[1023] = 0; + fip->reply_type = RT_FUSE_REPLY_OPEN; + + /* LK_TODO need to handle open permissions */ + + /* we want path minus 'root node of the share' */ + if ((cptr = strchr(full_path, '/')) == NULL) { - /* send next request */ - rli = (struct req_list_item *)list_get_item(g_req_list, 0); - if (rli != 0) + /* get dev_redir to open the remote file */ + if (dev_redir_file_open((void *) fip, device_id, "\\", + fi->flags, S_IFREG)) { - clipboard_request_file_data(rli->stream_id, rli->lindex, - rli->off, rli->size); + log_error("failed to send dev_redir_open_file() cmd"); + fuse_reply_err(req, EREMOTEIO); } - else + } + else + { + if (dev_redir_file_open((void *) fip, device_id, cptr, + fi->flags, S_IFREG)) { - LLOGLN(0, ("fuse_file_contents_range: error")); + log_error("failed to send dev_redir_get_dir_listing() cmd"); + fuse_reply_err(req, EREMOTEIO); } } } else { - LLOGLN(0, ("fuse_file_contents_range: error")); + /* specified file is a local resource */ + //XFUSE_HANDLE *fh; + + log_debug("LK_TODO: this is still a TODO"); + fuse_reply_err(req, EINVAL); } - return 0; } -#else +/** + *****************************************************************************/ -#include "arch.h" +static void xfuse_cb_read(fuse_req_t req, fuse_ino_t ino, size_t size, + off_t off, struct fuse_file_info *fi) +{ + XFUSE_HANDLE *fh; + XFUSE_INFO *fusep; -char g_fuse_root_path[256] = ""; + log_debug("want_bytes %d bytes at off %d", size, off); + + if (fi->fh == 0) + { + log_debug("LK_TODO: looks like fi->fh is corrupted"); + fuse_reply_err(req, EINVAL); + return; + } + fh = (XFUSE_HANDLE *) fi->fh; + + if (fh->DeviceId == 0) + { + /* target file is in .clipboard dir */ + log_debug(">>>>>>>>>>>>>>>>> THIS IS STILL A TODO!"); + return; + } + + /* target file is on a remote device */ + + if ((fusep = calloc(1, sizeof(XFUSE_INFO))) == NULL) + { + log_error("system out of memory"); + fuse_reply_err(req, ENOMEM); + return; + } + fusep->req = req; + fusep->inode = ino; + fusep->invoke_fuse = 1; + fusep->device_id = fh->DeviceId; + fusep->fi = fi; -/*****************************************************************************/ -int APP_CC -fuse_get_wait_objs(tbus *objs, int *count, int *timeout) + dev_redir_file_read(fusep, fh->DeviceId, fh->FileId, size, off); + log_debug("exiting"); +} + +static void xfuse_cb_write(fuse_req_t req, fuse_ino_t ino, const char *buf, + size_t size, off_t off, struct fuse_file_info *fi) { - return 0; + XFUSE_HANDLE *fh; + XFUSE_INFO *fusep; + + log_debug("write %d bytes at off %d", size, off); + + if (fi->fh == 0) + { + log_debug("LK_TODO: looks like fi->fh is corrupted"); + fuse_reply_err(req, EINVAL); + return; + } + fh = (XFUSE_HANDLE *) fi->fh; + + if (fh->DeviceId == 0) + { + /* target file is in .clipboard dir */ + log_debug(">>>>>>>>>>>>>>>>> THIS IS STILL A TODO!"); + return; + } + + /* target file is on a remote device */ + + if ((fusep = calloc(1, sizeof(XFUSE_INFO))) == NULL) + { + log_error("system out of memory"); + fuse_reply_err(req, ENOMEM); + return; + } + fusep->req = req; + fusep->inode = ino; + fusep->invoke_fuse = 1; + fusep->device_id = fh->DeviceId; + fusep->fi = fi; + + dev_redir_file_write(fusep, fh->DeviceId, fh->FileId, buf, size, off); + log_debug("exiting"); } -/*****************************************************************************/ -int APP_CC -fuse_check_wait_objs(void) +static void xfuse_cb_create(fuse_req_t req, fuse_ino_t parent, + const char *name, mode_t mode, + struct fuse_file_info *fi) { - return 0; + xfuse_create_dir_or_file(req, parent, name, mode, fi, S_IFREG); } -/*****************************************************************************/ -int APP_CC -fuse_init(void) +// LK_TODO may not need to implement the following funcs + +#if 0 +static void xfuse_cb_statfs(fuse_req_t req, fuse_ino_t ino) { - return 0; + log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered"); + fuse_reply_err(req, ENOMEM); } -/*****************************************************************************/ -int APP_CC -fuse_deinit(void) +static void xfuse_cb_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, + const char *value, size_t size, int flags) { - return 0; + log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered"); + fuse_reply_err(req, ENOMEM); + } -/*****************************************************************************/ -int APP_CC -fuse_clear_clip_dir(void) +static void xfuse_cb_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, + size_t size) { - return 0; + log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered"); + fuse_reply_err(req, ENOMEM); + } -/*****************************************************************************/ -int APP_CC -fuse_add_clip_dir_item(char *filename, int flags, int size, int lindex) +static void xfuse_cb_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) { - return 0; + log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered"); + fuse_reply_err(req, ENOMEM); + } -/*****************************************************************************/ -int APP_CC -fuse_file_contents_size(int stream_id, int file_size) +static void xfuse_cb_access(fuse_req_t req, fuse_ino_t ino, int mask) { - return 0; + log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered"); + fuse_reply_err(req, ENOMEM); + } -/*****************************************************************************/ -int APP_CC -fuse_file_contents_range(int stream_id, char *data, int data_bytes) +static void xfuse_cb_getlk(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, struct flock *lock) { - return 0; + log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered"); + fuse_reply_err(req, ENOMEM); + +} + +static void xfuse_cb_setlk(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, struct flock *lock, + int sleep) +{ + log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered"); + fuse_reply_err(req, ENOMEM); + +} + +static void xfuse_cb_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, + struct fuse_file_info *fi, unsigned flags, + const void *in_buf, size_t in_bufsz, + size_t out_bufsz) +{ + log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered"); + fuse_reply_err(req, ENOMEM); + } +static void xfuse_cb_poll(fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi, + struct fuse_pollhandle *ph) +{ + log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered"); + fuse_reply_err(req, ENOMEM); + +} #endif + +static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, + int to_set, struct fuse_file_info *fi) +{ + XRDP_INODE *xinode; + + log_debug(">>>>>>>>>>>>>>>> LK_TODO: entered to_set=0x%x", to_set); + + 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 (to_set & FUSE_SET_ATTR_MODE) + { + xinode->mode = attr->st_mode; + log_debug(">>>>>>>>>>>>>>>> LK_TODO: FUSE_SET_ATTR_MODE"); + + } + + if (to_set & FUSE_SET_ATTR_UID) + { + xinode->uid = attr->st_uid; + log_debug(">>>>>>>>>>>>>>>> LK_TODO: FUSE_SET_ATTR_UID"); + } + + if (to_set & FUSE_SET_ATTR_GID) + { + xinode->gid = attr->st_gid; + log_debug(">>>>>>>>>>>>>>>> LK_TODO: FUSE_SET_ATTR_GID"); + } + + if (to_set & FUSE_SET_ATTR_SIZE) + { + log_debug("previous file size: %d", attr->st_size); + xinode->size = attr->st_size; + log_debug("returning file size: %d", xinode->size); + } + + if (to_set & FUSE_SET_ATTR_ATIME) + { + xinode->atime = attr->st_atime; + log_debug(">>>>>>>>>>>>>>>> LK_TODO: FUSE_SET_ATTR_ATIME"); + } + + if (to_set & FUSE_SET_ATTR_MTIME) + { + xinode->mtime = attr->st_mtime; + log_debug(">>>>>>>>>>>>>>>> LK_TODO: FUSE_SET_ATTR_MTIME"); + } + + if (to_set & FUSE_SET_ATTR_ATIME_NOW) + { + xinode->atime = attr->st_atime; + log_debug(">>>>>>>>>>>>>>>> LK_TODO: FUSE_SET_ATTR_ATIME_NOW"); + } + + if (to_set & FUSE_SET_ATTR_MTIME_NOW) + { + xinode->mtime = attr->st_mtime; + log_debug(">>>>>>>>>>>>>>>> LK_TODO: FUSE_SET_ATTR_MTIME_NOW"); + } + + fuse_reply_attr(req, attr, 1.0); /* LK_TODO just faking for now */ +} + +#endif /* end else #ifndef XRDP_FUSE */ |