mirror of https://github.com/neutrinolabs/xrdp
Add xfuse_path_in_xfuse_fs()
This commit is contained in:
parent
a7b48cd1cf
commit
b87b7f9ee8
|
@ -18,6 +18,11 @@
|
|||
|
||||
/* FUSE mount point */
|
||||
char g_fuse_root_path[256] = "";
|
||||
#ifdef XRDP_FUSE
|
||||
static const char *g_fuse_root_path_basename; /* See xfuse_path_in_xfuse_fs() */
|
||||
static int g_fuse_root_parent_dev; /* Ditto */
|
||||
static int g_fuse_root_parent_ino; /* Ditto */
|
||||
#endif
|
||||
char g_fuse_clipboard_path[256] = ""; /* for clipboard use */
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
|
@ -122,6 +127,11 @@ void xfuse_devredir_cb_rename_file(struct state_rename *fip,
|
|||
void xfuse_devredir_cb_file_close(struct state_close *fip)
|
||||
{}
|
||||
|
||||
int xfuse_path_in_xfuse_fs(const char *path)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -324,6 +334,7 @@ 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(void);
|
||||
static int xfuse_deinit_xrdp_fs(void);
|
||||
|
@ -461,6 +472,7 @@ int
|
|||
xfuse_init(void)
|
||||
{
|
||||
struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
|
||||
char *p;
|
||||
|
||||
/* if already inited, just return */
|
||||
if (g_xfuse_inited)
|
||||
|
@ -507,16 +519,59 @@ xfuse_init(void)
|
|||
g_snprintf(g_fuse_root_path, sizeof(g_fuse_root_path), "%s/%s",
|
||||
g_getenv("HOME"), g_cfg->fuse_mount_name);
|
||||
}
|
||||
|
||||
/* Remove all trailing '/' from the root path */
|
||||
p = g_fuse_root_path + g_strlen(g_fuse_root_path);
|
||||
while ( p > g_fuse_root_path && *(p - 1) == '/')
|
||||
{
|
||||
--p;
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
/* This shouldn't happen */
|
||||
if (g_strlen(g_fuse_root_path) == 0)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Fuse root path is empty after removing trailing '/'");
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_snprintf(g_fuse_clipboard_path, 255, "%s/.clipboard", g_fuse_root_path);
|
||||
|
||||
/* Get the characteristics of the parent directory of the FUSE mount
|
||||
* point. Used by xfuse_path_in_xfuse_fs() */
|
||||
p = (char *)g_strrchr(g_fuse_root_path, '/');
|
||||
if (p != NULL)
|
||||
{
|
||||
/* Temporarily finish the root path at this point */
|
||||
*p = '\0';
|
||||
g_fuse_root_path_basename = p + 1;
|
||||
g_fuse_root_parent_dev = g_file_get_device_number(g_fuse_root_path);
|
||||
g_fuse_root_parent_ino = g_file_get_inode_num(g_fuse_root_path);
|
||||
*p = '/';
|
||||
}
|
||||
else
|
||||
{
|
||||
g_fuse_root_parent_dev = -1;
|
||||
g_fuse_root_parent_ino = -1;
|
||||
}
|
||||
|
||||
if (g_fuse_root_parent_dev == -1 || g_fuse_root_parent_ino == -1)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR,
|
||||
"Unable to obtain characteristics of directory containing %s",
|
||||
g_fuse_root_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if FUSE mount point does not exist, create it */
|
||||
if (!g_directory_exist(g_fuse_root_path))
|
||||
{
|
||||
(void)g_create_path(g_fuse_root_path);
|
||||
if (!g_create_dir(g_fuse_root_path))
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_ERROR, "mkdir %s failed. If %s is already mounted, you must "
|
||||
"first unmount it", g_fuse_root_path, g_fuse_root_path);
|
||||
LOG(LOG_LEVEL_ERROR, "mkdir %s failed. If %s is already mounted, you must "
|
||||
"first unmount it", g_fuse_root_path, g_fuse_root_path);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -1491,6 +1546,77 @@ void xfuse_devredir_cb_file_close(struct state_close *fip)
|
|||
free(fip);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine is a file is in the FUSE filesystem
|
||||
*
|
||||
* The whole purpose of this function is to avoid deadlocks. If we try
|
||||
* to determine the size (or any other attribute) of a file in the FUSE
|
||||
* filesystem, the kernel will block the calling thread and send a message
|
||||
* to libfuse. Since we're single-threaded, this will result in deadlock.
|
||||
*
|
||||
* Ideally we'd use a stat() of the file to compare with a stat() of
|
||||
* the mountpoint. This won't work however, for the reasons outline above.
|
||||
*
|
||||
* A simple implementation might be to compare the start of the filename
|
||||
* with the FUSE mount point. This will work, but can easily be defeated,
|
||||
* (perhaps unintentionally) by symlinks in the path.
|
||||
*
|
||||
* The approach taken here is to record the basename of the FUSE mount
|
||||
* point directory (e.g. 'thinclient_drives') and look for that in the
|
||||
* passed-in filename as a directory element. If we find it, we look
|
||||
* at the device name and inode number of the parent directory of the
|
||||
* FUSE mount point. If these match we consider the filename to be in
|
||||
* the FUSE filesystem.
|
||||
*/
|
||||
int xfuse_path_in_xfuse_fs(const char *path)
|
||||
{
|
||||
char *wpath = NULL; /* Writeable copy of path */
|
||||
char *p;
|
||||
int blen = g_strlen(g_fuse_root_path_basename);
|
||||
int rv = 0;
|
||||
|
||||
if ((wpath = g_strdup(path)) == NULL)
|
||||
{
|
||||
LOG(LOG_LEVEL_ERROR, "system out of memory");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Look ahead in the string for the basename of the FUSE mount point */
|
||||
for (p = wpath;
|
||||
(p = g_strstr(p, g_fuse_root_path_basename)) != NULL ;
|
||||
p = p + 1)
|
||||
{
|
||||
/* Is this string preceded by a '/' ? */
|
||||
if (p == wpath || *(p - 1) != '/')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Is the string followed by a '/' or '\0' ? We know it's
|
||||
* valid to look ahead this far in the string, as g_strstr()
|
||||
* tells us it is */
|
||||
if (*(p + blen) != '/' && *(p + blen) != '\0')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Temporarily terminate the string early, and check the
|
||||
* file system characteristics of the preceding directory */
|
||||
*(p - 1) = '\0';
|
||||
|
||||
if (g_file_get_device_number(wpath) == g_fuse_root_parent_dev &&
|
||||
g_file_get_inode_num(wpath) == g_fuse_root_parent_ino)
|
||||
{
|
||||
rv = 1;
|
||||
break;
|
||||
}
|
||||
*(p - 1) = '/';
|
||||
}
|
||||
g_free(wpath);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
** **
|
||||
** callbacks for fuse **
|
||||
|
|
|
@ -114,4 +114,13 @@ void xfuse_devredir_cb_rename_file(struct state_rename *fip,
|
|||
|
||||
void xfuse_devredir_cb_file_close(struct state_close *fip);
|
||||
|
||||
/*
|
||||
* Returns true if a filesystem path lies in the FUSE filesystem
|
||||
*
|
||||
* Use to prevent deadlocks. For example, if chansrv tries to open
|
||||
* a file in the FUSE filesystem it will fail, as it will call back
|
||||
* into itself to handle the I/O
|
||||
*/
|
||||
int xfuse_path_in_xfuse_fs(const char *path);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue