Significant remote file system improvements
- Reimplemented inode store in separate module chansrv_xfs.[hc] - Allowed atimes and mtimes to be written to Windows side - Mapped file user write bit to (inverted) Windows FILE_ATTRIBUTE_READONLY bit - Mapped file user execute bit to Windows FILE_ATTRIBUTE_SYSTEM bit - Implemented improved security for remotely mounted drives - Implemented USB device removal, allowing hot-plug/remove of memory sticks - Fixed pagefile.sys breaking Ubuntu file browser - Fixed write offset bug - Allowed renaming of open files - Improved reported error codes - Fixed various memory leaks - Addressed valgrind errors related to struct fuse_file_info pointers.
This commit is contained in:
parent
352107fc5f
commit
4d8f2b5a31
@ -225,6 +225,14 @@ Following parameters can be used in the \fB[Chansrv]\fR section.
|
|||||||
Directory for drive redirection, relative to the user home directory.
|
Directory for drive redirection, relative to the user home directory.
|
||||||
Created if it doesn't exist. If not specified, defaults to \fIxrdp_client\fR.
|
Created if it doesn't exist. If not specified, defaults to \fIxrdp_client\fR.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fBFileUmask\fR=\fImode\fR
|
||||||
|
Additional umask to apply to files in the \fBFuseMountName\fR directory.
|
||||||
|
The default value of 077 prevents other users on the system from reading
|
||||||
|
files on your redirected drives. This may not be approprate for all
|
||||||
|
environents, and so you can change this value to allow other users to
|
||||||
|
access your remote files if required.
|
||||||
|
|
||||||
.SH "SESSIONS VARIABLES"
|
.SH "SESSIONS VARIABLES"
|
||||||
All entries in the \fB[SessionVariables]\fR section are set as
|
All entries in the \fB[SessionVariables]\fR section are set as
|
||||||
environment variables in the user's session.
|
environment variables in the user's session.
|
||||||
|
@ -53,6 +53,8 @@ xrdp_chansrv_SOURCES = \
|
|||||||
chansrv_common.h \
|
chansrv_common.h \
|
||||||
chansrv_fuse.c \
|
chansrv_fuse.c \
|
||||||
chansrv_fuse.h \
|
chansrv_fuse.h \
|
||||||
|
chansrv_xfs.c \
|
||||||
|
chansrv_xfs.h \
|
||||||
clipboard.c \
|
clipboard.c \
|
||||||
clipboard.h \
|
clipboard.h \
|
||||||
clipboard_common.h \
|
clipboard_common.h \
|
||||||
|
@ -407,7 +407,7 @@ process_message_channel_setup(struct stream *s)
|
|||||||
|
|
||||||
if (g_rdpdr_index >= 0)
|
if (g_rdpdr_index >= 0)
|
||||||
{
|
{
|
||||||
dev_redir_init();
|
devredir_init();
|
||||||
xfuse_init();
|
xfuse_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,7 +458,7 @@ process_message_channel_data(struct stream *s)
|
|||||||
}
|
}
|
||||||
else if (chan_id == g_rdpdr_chan_id)
|
else if (chan_id == g_rdpdr_chan_id)
|
||||||
{
|
{
|
||||||
rv = dev_redir_data_in(s, chan_id, chan_flags, length, total_length);
|
rv = devredir_data_in(s, chan_id, chan_flags, length, total_length);
|
||||||
}
|
}
|
||||||
else if (chan_id == g_rail_chan_id)
|
else if (chan_id == g_rail_chan_id)
|
||||||
{
|
{
|
||||||
@ -1412,7 +1412,7 @@ channel_thread_loop(void *in_val)
|
|||||||
LOGM((LOG_LEVEL_INFO, "channel_thread_loop: g_term_event set"));
|
LOGM((LOG_LEVEL_INFO, "channel_thread_loop: g_term_event set"));
|
||||||
clipboard_deinit();
|
clipboard_deinit();
|
||||||
sound_deinit();
|
sound_deinit();
|
||||||
dev_redir_deinit();
|
devredir_deinit();
|
||||||
rail_deinit();
|
rail_deinit();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1434,7 +1434,7 @@ channel_thread_loop(void *in_val)
|
|||||||
"trans_check_wait_objs error resetting"));
|
"trans_check_wait_objs error resetting"));
|
||||||
clipboard_deinit();
|
clipboard_deinit();
|
||||||
sound_deinit();
|
sound_deinit();
|
||||||
dev_redir_deinit();
|
devredir_deinit();
|
||||||
rail_deinit();
|
rail_deinit();
|
||||||
/* delete g_con_trans */
|
/* delete g_con_trans */
|
||||||
trans_delete(g_con_trans);
|
trans_delete(g_con_trans);
|
||||||
@ -1460,7 +1460,7 @@ channel_thread_loop(void *in_val)
|
|||||||
api_con_trans_list_check_wait_objs();
|
api_con_trans_list_check_wait_objs();
|
||||||
xcommon_check_wait_objs();
|
xcommon_check_wait_objs();
|
||||||
sound_check_wait_objs();
|
sound_check_wait_objs();
|
||||||
dev_redir_check_wait_objs();
|
devredir_check_wait_objs();
|
||||||
xfuse_check_wait_objs();
|
xfuse_check_wait_objs();
|
||||||
timeout = -1;
|
timeout = -1;
|
||||||
num_objs = 0;
|
num_objs = 0;
|
||||||
@ -1479,7 +1479,7 @@ channel_thread_loop(void *in_val)
|
|||||||
&timeout);
|
&timeout);
|
||||||
xcommon_get_wait_objs(objs, &num_objs, &timeout);
|
xcommon_get_wait_objs(objs, &num_objs, &timeout);
|
||||||
sound_get_wait_objs(objs, &num_objs, &timeout);
|
sound_get_wait_objs(objs, &num_objs, &timeout);
|
||||||
dev_redir_get_wait_objs(objs, &num_objs, &timeout);
|
devredir_get_wait_objs(objs, &num_objs, &timeout);
|
||||||
xfuse_get_wait_objs(objs, &num_objs, &timeout);
|
xfuse_get_wait_objs(objs, &num_objs, &timeout);
|
||||||
get_timeout(&timeout);
|
get_timeout(&timeout);
|
||||||
} /* end while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) */
|
} /* end while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) */
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -21,53 +21,94 @@
|
|||||||
|
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
|
|
||||||
/*
|
#include "ms-erref.h"
|
||||||
* a file or dir entry in the xrdp file system (opaque type externally) */
|
|
||||||
struct xrdp_inode;
|
|
||||||
|
|
||||||
/* Used to pass file info in to xfuse_devredir_add_file_or_dir()
|
/* Used to pass file info back to chansrv_fuse from devredir */
|
||||||
*
|
|
||||||
* The string storage the name field points to is only valid
|
|
||||||
* for the duration of the xfuse_devredir_add_file_or_dir()
|
|
||||||
* call
|
|
||||||
*/
|
|
||||||
struct file_attr
|
struct file_attr
|
||||||
{
|
{
|
||||||
const char *name; /* Name of file or directory */
|
|
||||||
tui32 mode; /* File mode. */
|
tui32 mode; /* File mode. */
|
||||||
size_t size; /* Size of file, in bytes. */
|
size_t size; /* Size of file, in bytes. */
|
||||||
time_t atime; /* Time of last access. */
|
time_t atime; /* Time of last access. */
|
||||||
time_t mtime; /* Time of last modification. */
|
time_t mtime; /* Time of last modification. */
|
||||||
time_t ctime; /* Time of last status change. */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Bitmask values used to identify individual elements in
|
||||||
|
* struct file_attr
|
||||||
|
*/
|
||||||
|
#define TO_SET_MODE (1<<0)
|
||||||
|
#define TO_SET_SIZE (1<<1)
|
||||||
|
#define TO_SET_ATIME (1<<2)
|
||||||
|
#define TO_SET_MTIME (1<<3)
|
||||||
|
#define TO_SET_ALL (TO_SET_MODE | TO_SET_SIZE | TO_SET_ATIME | TO_SET_MTIME)
|
||||||
|
|
||||||
|
/* Private type passed into and back-from devredir */
|
||||||
|
typedef struct xfuse_info XFUSE_INFO;
|
||||||
|
|
||||||
int xfuse_init(void);
|
int xfuse_init(void);
|
||||||
int xfuse_deinit(void);
|
int xfuse_deinit(void);
|
||||||
int xfuse_check_wait_objs(void);
|
int xfuse_check_wait_objs(void);
|
||||||
int xfuse_get_wait_objs(tbus *objs, int *count, int *timeout);
|
int xfuse_get_wait_objs(tbus *objs, int *count, int *timeout);
|
||||||
int xfuse_create_share(tui32 share_id, const char *dirname);
|
int xfuse_create_share(tui32 share_id, const char *dirname);
|
||||||
|
void xfuse_delete_share(tui32 share_id);
|
||||||
|
|
||||||
int xfuse_clear_clip_dir(void);
|
int xfuse_clear_clip_dir(void);
|
||||||
int xfuse_file_contents_range(int stream_id, const char *data, int data_bytes);
|
int xfuse_file_contents_range(int stream_id, const char *data, int data_bytes);
|
||||||
int xfuse_file_contents_size(int stream_id, int file_size);
|
int xfuse_file_contents_size(int stream_id, int file_size);
|
||||||
int xfuse_add_clip_dir_item(const char *filename, int flags, int size, int lindex);
|
int xfuse_add_clip_dir_item(const char *filename,
|
||||||
|
int flags, int size, int lindex);
|
||||||
|
|
||||||
|
/* State pointer types (opaque outside this module), used for
|
||||||
|
* callback data
|
||||||
|
*/
|
||||||
|
struct state_dirscan;
|
||||||
|
struct state_lookup;
|
||||||
|
struct state_setattr;
|
||||||
|
struct state_open;
|
||||||
|
struct state_create;
|
||||||
|
struct state_read;
|
||||||
|
struct state_write;
|
||||||
|
struct state_remove;
|
||||||
|
struct state_rename;
|
||||||
|
struct state_close;
|
||||||
|
|
||||||
|
|
||||||
/* functions that are invoked from devredir */
|
/* functions that are invoked from devredir */
|
||||||
struct xrdp_inode *xfuse_devredir_add_file_or_dir(
|
void xfuse_devredir_cb_enum_dir_add_entry(
|
||||||
void *vp,
|
struct state_dirscan *fip,
|
||||||
const struct file_attr *file_info);
|
const char *name,
|
||||||
void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus);
|
const struct file_attr *fattr);
|
||||||
void xfuse_devredir_cb_lookup_entry(void *vp, tui32 IoStatus,
|
void xfuse_devredir_cb_enum_dir_done(struct state_dirscan *fip,
|
||||||
struct xrdp_inode *xinode);
|
enum NTSTATUS IoStatus);
|
||||||
void xfuse_devredir_cb_open_file(void *vp, tui32 IoStatus, tui32 DeviceId, tui32 FileId);
|
|
||||||
|
void xfuse_devredir_cb_lookup_entry(struct state_lookup *fip,
|
||||||
|
enum NTSTATUS IoStatus,
|
||||||
|
const struct file_attr *file_info);
|
||||||
|
|
||||||
|
void xfuse_devredir_cb_setattr(struct state_setattr *fip,
|
||||||
|
enum NTSTATUS IoStatus);
|
||||||
|
|
||||||
|
void xfuse_devredir_cb_create_file(struct state_create *fip,
|
||||||
|
enum NTSTATUS IoStatus,
|
||||||
|
tui32 DeviceId, tui32 FileId);
|
||||||
|
|
||||||
|
void xfuse_devredir_cb_open_file(struct state_open *fip,
|
||||||
|
enum NTSTATUS IoStatus,
|
||||||
|
tui32 DeviceId, tui32 FileId);
|
||||||
|
|
||||||
|
void xfuse_devredir_cb_read_file(struct state_read *fip,
|
||||||
|
const char *buf, size_t length);
|
||||||
void xfuse_devredir_cb_write_file(
|
void xfuse_devredir_cb_write_file(
|
||||||
void *vp,
|
struct state_write *fip,
|
||||||
tui32 IoStatus,
|
enum NTSTATUS IoStatus,
|
||||||
const char *buf,
|
off_t offset,
|
||||||
size_t length);
|
size_t length);
|
||||||
void xfuse_devredir_cb_read_file(void *vp, const char *buf, size_t length);
|
|
||||||
void xfuse_devredir_cb_rmdir_or_file(void *vp, tui32 IoStatus);
|
void xfuse_devredir_cb_rmdir_or_file(struct state_remove *fip,
|
||||||
void xfuse_devredir_cb_rename_file(void *vp, tui32 IoStatus);
|
enum NTSTATUS IoStatus);
|
||||||
void xfuse_devredir_cb_file_close(void *vp);
|
|
||||||
|
void xfuse_devredir_cb_rename_file(struct state_rename *fip,
|
||||||
|
enum NTSTATUS IoStatus);
|
||||||
|
|
||||||
|
void xfuse_devredir_cb_file_close(struct state_close *fip);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
909
sesman/chansrv/chansrv_xfs.c
Normal file
909
sesman/chansrv/chansrv_xfs.c
Normal file
@ -0,0 +1,909 @@
|
|||||||
|
/**
|
||||||
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* This file implements the interface in chansrv_fuse_fs.h
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#if defined(HAVE_CONFIG_H)
|
||||||
|
#include <config_ac.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "os_calls.h"
|
||||||
|
|
||||||
|
#include "chansrv_xfs.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip this module if FUSE is not supported. A standards-compliant C
|
||||||
|
* translation unit must contain at least one declaration (C99:6.9), and we've
|
||||||
|
* fulfilled that requirement by this stage.
|
||||||
|
*/
|
||||||
|
#ifdef XRDP_FUSE
|
||||||
|
|
||||||
|
#define INODE_TABLE_ALLOCATION_INITIAL 4096
|
||||||
|
#define INODE_TABLE_ALLOCATION_GRANULARITY 100
|
||||||
|
|
||||||
|
/* inum of the delete pending directory */
|
||||||
|
#define DELETE_PENDING_ID 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A double-linked list of inodes, sorted by inum
|
||||||
|
*
|
||||||
|
* The elements in the list are sorted in increasing inum order, as this
|
||||||
|
* allows a directory enumeration to be easily resumed if elements
|
||||||
|
* are removed or added. See xfs_readdir() for details on this.
|
||||||
|
*/
|
||||||
|
typedef struct xfs_inode_all XFS_INODE_ALL;
|
||||||
|
typedef struct xfs_list
|
||||||
|
{
|
||||||
|
XFS_INODE_ALL *begin;
|
||||||
|
XFS_INODE_ALL *end;
|
||||||
|
} XFS_LIST;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A complete inode, including the private elements used by the
|
||||||
|
* implementation
|
||||||
|
*/
|
||||||
|
typedef struct xfs_inode_all
|
||||||
|
{
|
||||||
|
XFS_INODE pub; /* Public elements */
|
||||||
|
/*
|
||||||
|
* Directory linkage elements
|
||||||
|
*
|
||||||
|
* Because we don't support hard-linking, elements can be stored in
|
||||||
|
* one and only one directory:-
|
||||||
|
*/
|
||||||
|
struct xfs_inode_all *parent; /* Parent inode */
|
||||||
|
struct xfs_inode_all *next; /* Next entry in parent */
|
||||||
|
struct xfs_inode_all *previous; /* Previous entry in parent */
|
||||||
|
XFS_LIST dir; /* Directory only - children */
|
||||||
|
/*
|
||||||
|
* Other private elements
|
||||||
|
*/
|
||||||
|
unsigned int open_count; /* Regular files only */
|
||||||
|
} XFS_INODE_ALL;
|
||||||
|
|
||||||
|
|
||||||
|
/* the xrdp file system in memory
|
||||||
|
*
|
||||||
|
* inode_table allows for O(1) access to any file based on the inum.
|
||||||
|
* Index 0 is unused, so we can use an inode of zero for
|
||||||
|
* an invalid inode, and avoid off-by-one errors index
|
||||||
|
* 1 is our '.' directory.
|
||||||
|
* 2 is the delete pending directory, where we can place
|
||||||
|
* inodes with a positive open count which are
|
||||||
|
* deleted.
|
||||||
|
* free_list List of free inode numbers. Allows for O(1) access to
|
||||||
|
* a free node, provided the free list is not empty.
|
||||||
|
*/
|
||||||
|
struct xfs_fs
|
||||||
|
{
|
||||||
|
XFS_INODE_ALL **inode_table; /* a table of entries; can grow. */
|
||||||
|
fuse_ino_t *free_list; /* Free inodes */
|
||||||
|
unsigned int inode_count; /* Current number of inodes */
|
||||||
|
unsigned int free_count; /* Size of free_list */
|
||||||
|
unsigned int generation; /* Changes when an inode is deleted */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A directory handle
|
||||||
|
*
|
||||||
|
* inum inum of the directory being scanned
|
||||||
|
* generation Generation of the inum we opened
|
||||||
|
*/
|
||||||
|
struct xfs_dir_handle
|
||||||
|
{
|
||||||
|
fuse_ino_t inum;
|
||||||
|
tui32 generation;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* module based logging */
|
||||||
|
#define LOG_ERROR 0
|
||||||
|
#define LOG_INFO 1
|
||||||
|
#define LOG_DEBUG 2
|
||||||
|
#ifndef LOG_LEVEL
|
||||||
|
#define LOG_LEVEL LOG_ERROR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define log_error(_params...) \
|
||||||
|
{ \
|
||||||
|
g_write("[%10.10u]: XFS %s: %d : ERROR: ", \
|
||||||
|
g_time3(), __func__, __LINE__); \
|
||||||
|
g_writeln (_params); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define log_always(_params...) \
|
||||||
|
{ \
|
||||||
|
g_write("[%10.10u]: XFS %s: %d : ALWAYS: ", \
|
||||||
|
g_time3(), __func__, __LINE__); \
|
||||||
|
g_writeln (_params); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define log_info(_params...) \
|
||||||
|
{ \
|
||||||
|
if (LOG_INFO <= LOG_LEVEL) \
|
||||||
|
{ \
|
||||||
|
g_write("[%10.10u]: XFS %s: %d : ", \
|
||||||
|
g_time3(), __func__, __LINE__); \
|
||||||
|
g_writeln (_params); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define log_debug(_params...) \
|
||||||
|
{ \
|
||||||
|
if (LOG_DEBUG <= LOG_LEVEL) \
|
||||||
|
{ \
|
||||||
|
g_write("[%10.10u]: XFS %s: %d : ", \
|
||||||
|
g_time3(), __func__, __LINE__); \
|
||||||
|
g_writeln (_params); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
static int
|
||||||
|
grow_xfs(struct xfs_fs *xfs, unsigned int extra_inodes)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
unsigned int new_count = xfs->inode_count + extra_inodes;
|
||||||
|
XFS_INODE_ALL **new_table;
|
||||||
|
fuse_ino_t *new_free_list;
|
||||||
|
|
||||||
|
new_table = (XFS_INODE_ALL **)
|
||||||
|
realloc(xfs->inode_table, new_count * sizeof(new_table[0]));
|
||||||
|
if (new_table != NULL)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
for (i = xfs->inode_count ; i < new_count ; ++i)
|
||||||
|
{
|
||||||
|
new_table[i] = NULL;
|
||||||
|
}
|
||||||
|
xfs->inode_table = new_table;
|
||||||
|
|
||||||
|
new_free_list = (fuse_ino_t *)
|
||||||
|
realloc(xfs->free_list,
|
||||||
|
new_count * sizeof(new_free_list[0]));
|
||||||
|
if (new_free_list)
|
||||||
|
{
|
||||||
|
/* Add the new inodes in to the new_free_list, so the lowest
|
||||||
|
* number is allocated first
|
||||||
|
*/
|
||||||
|
i = new_count;
|
||||||
|
while (i > xfs->inode_count)
|
||||||
|
{
|
||||||
|
new_free_list[xfs->free_count++] = --i;
|
||||||
|
}
|
||||||
|
|
||||||
|
xfs->free_list = new_free_list;
|
||||||
|
xfs->inode_count = new_count;
|
||||||
|
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
static void
|
||||||
|
add_inode_to_list(XFS_LIST *list, XFS_INODE_ALL *xino)
|
||||||
|
{
|
||||||
|
fuse_ino_t inum = xino->pub.inum;
|
||||||
|
|
||||||
|
/* Find the element we need to insert after */
|
||||||
|
XFS_INODE_ALL *predecessor = list->end;
|
||||||
|
while (predecessor != NULL && predecessor->pub.inum > inum)
|
||||||
|
{
|
||||||
|
predecessor = predecessor->previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (predecessor == NULL)
|
||||||
|
{
|
||||||
|
/* Inserting at the beginning */
|
||||||
|
/* Set up links in node */
|
||||||
|
xino->next = list->begin;
|
||||||
|
xino->previous = NULL;
|
||||||
|
|
||||||
|
/* Set up back-link to node */
|
||||||
|
if (list->begin == NULL)
|
||||||
|
{
|
||||||
|
/* We are the last node */
|
||||||
|
list->end = xino;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
list->begin->previous = xino;
|
||||||
|
}
|
||||||
|
/* Set up forward-link to node */
|
||||||
|
list->begin = xino;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Set up links in node */
|
||||||
|
xino->next = predecessor->next;
|
||||||
|
xino->previous = predecessor;
|
||||||
|
|
||||||
|
/* Set up back-link to node */
|
||||||
|
if (predecessor->next == NULL)
|
||||||
|
{
|
||||||
|
list->end = xino;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
predecessor->next->previous = xino;
|
||||||
|
}
|
||||||
|
/* Set up forward-link to node */
|
||||||
|
predecessor->next = xino;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
static void
|
||||||
|
remove_inode_from_list(XFS_LIST *list, XFS_INODE_ALL *xino)
|
||||||
|
{
|
||||||
|
if (xino->previous == NULL)
|
||||||
|
{
|
||||||
|
/* First element */
|
||||||
|
list->begin = xino->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xino->previous->next = xino->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xino->next == NULL)
|
||||||
|
{
|
||||||
|
/* Last element */
|
||||||
|
list->end = xino->previous;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xino->next->previous = xino->previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
static void
|
||||||
|
link_inode_into_directory_node(XFS_INODE_ALL *dinode, XFS_INODE_ALL *xino)
|
||||||
|
{
|
||||||
|
xino->parent = dinode;
|
||||||
|
add_inode_to_list(&dinode->dir, xino);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
static void
|
||||||
|
unlink_inode_from_parent(XFS_INODE_ALL *xino)
|
||||||
|
{
|
||||||
|
remove_inode_from_list(&xino->parent->dir, xino);
|
||||||
|
|
||||||
|
xino->next = NULL;
|
||||||
|
xino->previous = NULL;
|
||||||
|
xino->parent = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
struct xfs_fs *
|
||||||
|
xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
struct xfs_fs *xfs = g_new0(struct xfs_fs, 1);
|
||||||
|
XFS_INODE_ALL *xino1 = NULL;
|
||||||
|
XFS_INODE_ALL *xino2 = NULL;
|
||||||
|
|
||||||
|
if (xfs != NULL)
|
||||||
|
{
|
||||||
|
xfs->inode_count = 0;
|
||||||
|
xfs->free_count = 0;
|
||||||
|
xfs->inode_table = NULL;
|
||||||
|
xfs->free_list = NULL;
|
||||||
|
xfs->generation = 1;
|
||||||
|
|
||||||
|
if (!grow_xfs(xfs, INODE_TABLE_ALLOCATION_INITIAL) ||
|
||||||
|
(xino1 = g_new0(XFS_INODE_ALL, 1)) == NULL ||
|
||||||
|
(xino2 = g_new0(XFS_INODE_ALL, 1)) == NULL)
|
||||||
|
{
|
||||||
|
free(xino1);
|
||||||
|
free(xino2);
|
||||||
|
xfs_delete_xfs_fs(xfs);
|
||||||
|
xfs = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The use of grow_xfs to allocate the inode table will make
|
||||||
|
* inodes 0, 1 (FUSE_ROOT_ID) and 2 (DELETE_PENDING_ID) the first
|
||||||
|
* available free inodes. We can ignore these */
|
||||||
|
xfs->free_count -= 3;
|
||||||
|
|
||||||
|
xfs->inode_table[0] = NULL;
|
||||||
|
xfs->inode_table[FUSE_ROOT_ID] = xino1;
|
||||||
|
xfs->inode_table[DELETE_PENDING_ID] = xino2;
|
||||||
|
|
||||||
|
xino1->pub.inum = FUSE_ROOT_ID;
|
||||||
|
xino1->pub.mode = (S_IFDIR | 0777) & ~umask;
|
||||||
|
xino1->pub.uid = uid;
|
||||||
|
xino1->pub.gid = gid;
|
||||||
|
xino1->pub.size = 0;
|
||||||
|
xino1->pub.atime = time(0);
|
||||||
|
xino1->pub.mtime = xino1->pub.atime;
|
||||||
|
xino1->pub.ctime = xino1->pub.atime;
|
||||||
|
strcpy(xino1->pub.name, ".");
|
||||||
|
xino1->pub.generation = xfs->generation;
|
||||||
|
xino1->pub.device_id = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FUSE_ROOT_ID has no parent rather than being a parent
|
||||||
|
* of itself. This is intentional */
|
||||||
|
xino1->parent = NULL;
|
||||||
|
xino1->next = NULL;
|
||||||
|
xino1->previous = NULL;
|
||||||
|
xino1->dir.begin = NULL;
|
||||||
|
xino1->dir.end = NULL;
|
||||||
|
|
||||||
|
xino2->pub.inum = DELETE_PENDING_ID;
|
||||||
|
xino2->pub.mode = (S_IFDIR | 0777) & ~umask;
|
||||||
|
xino2->pub.uid = uid;
|
||||||
|
xino2->pub.gid = gid;
|
||||||
|
xino2->pub.size = 0;
|
||||||
|
xino2->pub.atime = time(0);
|
||||||
|
xino2->pub.mtime = xino2->pub.atime;
|
||||||
|
xino2->pub.ctime = xino2->pub.atime;
|
||||||
|
strcpy(xino2->pub.name, ".delete-pending");
|
||||||
|
xino2->pub.generation = xfs->generation;
|
||||||
|
xino2->pub.device_id = 0;
|
||||||
|
|
||||||
|
xino2->parent = NULL;
|
||||||
|
xino2->next = NULL;
|
||||||
|
xino2->previous = NULL;
|
||||||
|
xino2->dir.begin = NULL;
|
||||||
|
xino2->dir.end = NULL;
|
||||||
|
/*
|
||||||
|
* Uncomment this line to make the .delete-pending
|
||||||
|
* directory visible to the user in the root
|
||||||
|
*/
|
||||||
|
/* link_inode_into_directory_node(xino1, xino2); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return xfs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
void
|
||||||
|
xfs_delete_xfs_fs(struct xfs_fs *xfs)
|
||||||
|
{
|
||||||
|
if (xfs != NULL && xfs->inode_table != NULL)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0 ; i < xfs->inode_count; ++i)
|
||||||
|
{
|
||||||
|
free(xfs->inode_table[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(xfs->inode_table);
|
||||||
|
free(xfs->free_list);
|
||||||
|
free(xfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
XFS_INODE *
|
||||||
|
xfs_add_entry(struct xfs_fs *xfs, fuse_ino_t parent_inum,
|
||||||
|
const char *name, mode_t mode)
|
||||||
|
{
|
||||||
|
XFS_INODE *result = NULL;
|
||||||
|
XFS_INODE_ALL *parent = NULL;
|
||||||
|
|
||||||
|
/* Checks:-
|
||||||
|
* 1) the parent exists (and is a directory)
|
||||||
|
* 2) the caller is not inserting into the .delete-pending directory,
|
||||||
|
* 3) Name's not too long
|
||||||
|
* 4) Entry does not already exist
|
||||||
|
*/
|
||||||
|
if (parent_inum < xfs->inode_count &&
|
||||||
|
((parent = xfs->inode_table[parent_inum]) != NULL) &&
|
||||||
|
(parent->pub.mode & S_IFDIR) != 0 &&
|
||||||
|
parent_inum != DELETE_PENDING_ID &&
|
||||||
|
strlen(name) <= XFS_MAXFILENAMELEN &&
|
||||||
|
!xfs_lookup_in_dir(xfs, parent_inum, name))
|
||||||
|
{
|
||||||
|
/* Sanitise the mode so one-and-only-one of S_IFDIR and
|
||||||
|
* S_IFREG is set */
|
||||||
|
if ((mode & S_IFDIR) != 0)
|
||||||
|
{
|
||||||
|
mode = (mode & 0777) | S_IFDIR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mode = (mode & 0777) | S_IFREG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Space for a new entry? */
|
||||||
|
if (xfs->free_count > 0 ||
|
||||||
|
grow_xfs(xfs, INODE_TABLE_ALLOCATION_GRANULARITY))
|
||||||
|
{
|
||||||
|
XFS_INODE_ALL *xino = NULL;
|
||||||
|
|
||||||
|
if ((xino = g_new0(XFS_INODE_ALL, 1)) != NULL)
|
||||||
|
{
|
||||||
|
fuse_ino_t inum = xfs->free_list[--xfs->free_count];
|
||||||
|
if (xfs->inode_table[inum] != NULL)
|
||||||
|
{
|
||||||
|
log_error("Unexpected non-NULL value in inode table "
|
||||||
|
"entry %ld", inum);
|
||||||
|
}
|
||||||
|
xfs->inode_table[inum] = xino;
|
||||||
|
xino->pub.inum = inum;
|
||||||
|
xino->pub.mode = mode;
|
||||||
|
xino->pub.uid = parent->pub.uid;
|
||||||
|
xino->pub.gid = parent->pub.gid;
|
||||||
|
if (mode & S_IFDIR)
|
||||||
|
{
|
||||||
|
xino->pub.size = 4096;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xino->pub.size = 0;
|
||||||
|
}
|
||||||
|
xino->pub.atime = time(0);
|
||||||
|
xino->pub.mtime = xino->pub.atime;
|
||||||
|
xino->pub.ctime = xino->pub.atime;
|
||||||
|
strcpy(xino->pub.name, name);
|
||||||
|
xino->pub.generation = xfs->generation;
|
||||||
|
xino->pub.device_id = parent->pub.device_id;
|
||||||
|
xino->pub.lindex = 0;
|
||||||
|
|
||||||
|
xino->parent = NULL;
|
||||||
|
xino->next = NULL;
|
||||||
|
xino->previous = NULL;
|
||||||
|
link_inode_into_directory_node(parent, xino);
|
||||||
|
result = &xino->pub;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
void
|
||||||
|
xfs_remove_directory_contents(struct xfs_fs *xfs, fuse_ino_t inum)
|
||||||
|
{
|
||||||
|
XFS_INODE_ALL *xino = NULL;
|
||||||
|
|
||||||
|
if (inum < xfs->inode_count &&
|
||||||
|
((xino = xfs->inode_table[inum]) != NULL) &&
|
||||||
|
((xino->pub.mode & S_IFDIR) != 0))
|
||||||
|
{
|
||||||
|
XFS_INODE_ALL *e;
|
||||||
|
while ((e = xino->dir.end) != NULL)
|
||||||
|
{
|
||||||
|
xfs_remove_entry(xfs, e->pub.inum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
void
|
||||||
|
xfs_remove_entry(struct xfs_fs *xfs, fuse_ino_t inum)
|
||||||
|
{
|
||||||
|
XFS_INODE_ALL *xino = NULL;
|
||||||
|
|
||||||
|
if (inum < xfs->inode_count &&
|
||||||
|
((xino = xfs->inode_table[inum]) != NULL))
|
||||||
|
{
|
||||||
|
if ((xino->pub.mode & S_IFDIR) != 0)
|
||||||
|
{
|
||||||
|
xfs_remove_directory_contents(xfs, inum);
|
||||||
|
}
|
||||||
|
|
||||||
|
unlink_inode_from_parent(xino);
|
||||||
|
if ((xino->pub.mode & S_IFREG) != 0 && xino->open_count > 0)
|
||||||
|
{
|
||||||
|
link_inode_into_directory_node(
|
||||||
|
xfs->inode_table[DELETE_PENDING_ID], xino);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xfs->free_list[xfs->free_count++] = inum;
|
||||||
|
xfs->inode_table[inum] = NULL;
|
||||||
|
/*
|
||||||
|
* Bump the generation when we return an inum to the free list,
|
||||||
|
* so that the caller can distinguish re-uses of the same inum.
|
||||||
|
*/
|
||||||
|
++xfs->generation;
|
||||||
|
free(xino);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
XFS_INODE *
|
||||||
|
xfs_get(struct xfs_fs *xfs, fuse_ino_t inum)
|
||||||
|
{
|
||||||
|
return (inum < xfs->inode_count) ? &xfs->inode_table[inum]->pub : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
char *
|
||||||
|
xfs_get_full_path(struct xfs_fs *xfs, fuse_ino_t inum)
|
||||||
|
{
|
||||||
|
char *result = NULL;
|
||||||
|
XFS_INODE_ALL *xino = NULL;
|
||||||
|
|
||||||
|
if (inum < xfs->inode_count &&
|
||||||
|
((xino = xfs->inode_table[inum]) != NULL))
|
||||||
|
{
|
||||||
|
if (xino->pub.inum == FUSE_ROOT_ID)
|
||||||
|
{
|
||||||
|
return strdup("/");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Add up the lengths of all the names up to the root,
|
||||||
|
* allowing one extra char for a '/' prefix for each element
|
||||||
|
*/
|
||||||
|
size_t len = 0;
|
||||||
|
XFS_INODE_ALL *p;
|
||||||
|
for (p = xino ; p->pub.inum != FUSE_ROOT_ID ; p = p->parent)
|
||||||
|
{
|
||||||
|
len += strlen(p->pub.name);
|
||||||
|
++len; /* Allow for '/' prefix */
|
||||||
|
}
|
||||||
|
|
||||||
|
result = malloc(len + 1);
|
||||||
|
if (result != NULL)
|
||||||
|
{
|
||||||
|
/* Construct the path from the end */
|
||||||
|
char *end = result + len;
|
||||||
|
*end = '\0';
|
||||||
|
|
||||||
|
for (p = xino ; p->pub.inum != FUSE_ROOT_ID ; p = p->parent)
|
||||||
|
{
|
||||||
|
len = strlen(p->pub.name);
|
||||||
|
end -= (len + 1);
|
||||||
|
*end = '/';
|
||||||
|
memcpy(end + 1, p->pub.name, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
XFS_INODE *
|
||||||
|
xfs_lookup_in_dir(struct xfs_fs *xfs, fuse_ino_t inum, const char *name)
|
||||||
|
{
|
||||||
|
XFS_INODE_ALL *xino;
|
||||||
|
XFS_INODE *result = NULL;
|
||||||
|
if (inum < xfs->inode_count &&
|
||||||
|
((xino = xfs->inode_table[inum]) != NULL) &&
|
||||||
|
(xino->pub.mode & S_IFDIR) != 0)
|
||||||
|
{
|
||||||
|
XFS_INODE_ALL *p;
|
||||||
|
for (p = xino->dir.begin ; p != NULL; p = p->next)
|
||||||
|
{
|
||||||
|
if (strcmp(p->pub.name, name) == 0)
|
||||||
|
{
|
||||||
|
result = &p->pub;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
int
|
||||||
|
xfs_is_dir_empty(struct xfs_fs *xfs, fuse_ino_t inum)
|
||||||
|
{
|
||||||
|
XFS_INODE_ALL *xino = NULL;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
if (inum < xfs->inode_count &&
|
||||||
|
((xino = xfs->inode_table[inum]) != NULL) &&
|
||||||
|
(xino->pub.mode & S_IFDIR) != 0)
|
||||||
|
{
|
||||||
|
result = (xino->dir.begin == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
unsigned int
|
||||||
|
xfs_is_under(struct xfs_fs *xfs, fuse_ino_t dir, fuse_ino_t entry)
|
||||||
|
{
|
||||||
|
unsigned int result = 0;
|
||||||
|
|
||||||
|
XFS_INODE_ALL *dxino = NULL;
|
||||||
|
XFS_INODE_ALL *exino = NULL;
|
||||||
|
|
||||||
|
if (dir < xfs->inode_count &&
|
||||||
|
((dxino = xfs->inode_table[dir]) != NULL) &&
|
||||||
|
(dxino->pub.mode & S_IFDIR) != 0 &&
|
||||||
|
entry < xfs->inode_count &&
|
||||||
|
((exino = xfs->inode_table[entry]) != NULL))
|
||||||
|
{
|
||||||
|
unsigned int count = 0;
|
||||||
|
|
||||||
|
while (exino != NULL && exino != dxino)
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
exino = exino->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exino != NULL)
|
||||||
|
{
|
||||||
|
result = count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
struct xfs_dir_handle *
|
||||||
|
xfs_opendir(struct xfs_fs *xfs, fuse_ino_t dir)
|
||||||
|
{
|
||||||
|
XFS_INODE_ALL *xino = NULL;
|
||||||
|
struct xfs_dir_handle *result = NULL;
|
||||||
|
|
||||||
|
if (dir < xfs->inode_count &&
|
||||||
|
((xino = xfs->inode_table[dir]) != NULL) &&
|
||||||
|
(xino->pub.mode & S_IFDIR) != 0)
|
||||||
|
{
|
||||||
|
result = g_new0(struct xfs_dir_handle, 1);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
result->inum = xino->pub.inum;
|
||||||
|
result->generation = xino->pub.generation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
XFS_INODE *
|
||||||
|
xfs_readdir(struct xfs_fs *xfs, struct xfs_dir_handle *handle, off_t *off)
|
||||||
|
{
|
||||||
|
XFS_INODE_ALL *result = NULL;
|
||||||
|
XFS_INODE_ALL *dxino = NULL;
|
||||||
|
XFS_INODE_ALL *xino = NULL;
|
||||||
|
|
||||||
|
/* Check the direcory is still valid */
|
||||||
|
if (handle->inum < xfs->inode_count &&
|
||||||
|
((dxino = xfs->inode_table[handle->inum]) != NULL) &&
|
||||||
|
(dxino->pub.mode & S_IFDIR) != 0 &&
|
||||||
|
handle->generation == dxino->pub.generation)
|
||||||
|
{
|
||||||
|
fuse_ino_t inum;
|
||||||
|
|
||||||
|
if (*off == (off_t) -1)
|
||||||
|
{
|
||||||
|
/* We're at the end already */
|
||||||
|
}
|
||||||
|
else if ((inum = *off) == 0)
|
||||||
|
{
|
||||||
|
/* First call */
|
||||||
|
result = dxino->dir.begin;
|
||||||
|
}
|
||||||
|
else if (inum < xfs->inode_count &&
|
||||||
|
(xino = xfs->inode_table[inum]) != 0 &&
|
||||||
|
xino->parent == dxino)
|
||||||
|
{
|
||||||
|
/* The node we're pointing to is still valid */
|
||||||
|
result = xino;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The file we wanted has been pulled out from under us.
|
||||||
|
* We will look forward in the inode table to try to
|
||||||
|
* discover the next inode in the directory. Because
|
||||||
|
* files are stored in inode order, this guarantees
|
||||||
|
* we'll meet POSIX requirements.
|
||||||
|
*/
|
||||||
|
for (inum = inum + 1 ; inum < xfs->inode_count ; ++inum)
|
||||||
|
{
|
||||||
|
if ((xino = xfs->inode_table[inum]) != 0 &&
|
||||||
|
xino->parent == dxino)
|
||||||
|
{
|
||||||
|
result = xino;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the offset */
|
||||||
|
if (result == NULL || result->next == NULL)
|
||||||
|
{
|
||||||
|
/* We're done */
|
||||||
|
*off = (off_t) -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*off = (off_t)result->next->pub.inum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Caller only sees public interface to the result */
|
||||||
|
return (result) ? &result->pub : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
void
|
||||||
|
xfs_closedir(struct xfs_fs *xfs, struct xfs_dir_handle *handle)
|
||||||
|
{
|
||||||
|
free(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
void
|
||||||
|
xfs_increment_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum)
|
||||||
|
{
|
||||||
|
XFS_INODE_ALL *xino;
|
||||||
|
if (inum < xfs->inode_count &&
|
||||||
|
((xino = xfs->inode_table[inum]) != NULL) &&
|
||||||
|
(xino->pub.mode & S_IFREG) != 0)
|
||||||
|
{
|
||||||
|
++xino->open_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
void
|
||||||
|
xfs_decrement_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum)
|
||||||
|
{
|
||||||
|
XFS_INODE_ALL *xino;
|
||||||
|
if (inum < xfs->inode_count &&
|
||||||
|
((xino = xfs->inode_table[inum]) != NULL) &&
|
||||||
|
(xino->pub.mode & S_IFREG) != 0)
|
||||||
|
{
|
||||||
|
if (xino->open_count > 0)
|
||||||
|
{
|
||||||
|
--xino->open_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xino->open_count == 0 &&
|
||||||
|
xino->parent == xfs->inode_table[DELETE_PENDING_ID])
|
||||||
|
{
|
||||||
|
/* We can get rid of this one now */
|
||||||
|
xfs_remove_entry(xfs, inum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
unsigned int
|
||||||
|
xfs_get_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum)
|
||||||
|
{
|
||||||
|
unsigned int result = 0;
|
||||||
|
XFS_INODE_ALL *xino;
|
||||||
|
if (inum < xfs->inode_count &&
|
||||||
|
((xino = xfs->inode_table[inum]) != NULL) &&
|
||||||
|
(xino->pub.mode & S_IFREG) != 0)
|
||||||
|
{
|
||||||
|
result = xino->open_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
void
|
||||||
|
xfs_delete_entries_with_device_id(struct xfs_fs *xfs, tui32 device_id)
|
||||||
|
{
|
||||||
|
fuse_ino_t inum;
|
||||||
|
XFS_INODE_ALL *xino;
|
||||||
|
|
||||||
|
if (device_id != 0)
|
||||||
|
{
|
||||||
|
/* Using xfs_remove_entry() is convenient, but it recurses
|
||||||
|
* in to directories. To make sure all entries are removed, set the
|
||||||
|
* open_count of all affected files to 0 first
|
||||||
|
*/
|
||||||
|
for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum)
|
||||||
|
{
|
||||||
|
if ((xino = xfs->inode_table[inum]) != NULL &&
|
||||||
|
xino->pub.device_id == device_id &&
|
||||||
|
(xino->pub.mode & S_IFREG) != 0)
|
||||||
|
{
|
||||||
|
xino->open_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we can be sure everything will be deleted correctly */
|
||||||
|
for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum)
|
||||||
|
{
|
||||||
|
if ((xino = xfs->inode_table[inum]) != NULL &&
|
||||||
|
xino->pub.device_id == device_id)
|
||||||
|
{
|
||||||
|
xfs_remove_entry(xfs, xino->pub.inum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
int
|
||||||
|
xfs_check_move_entry(struct xfs_fs *xfs, fuse_ino_t inum,
|
||||||
|
fuse_ino_t new_parent_inum, const char *name)
|
||||||
|
{
|
||||||
|
XFS_INODE_ALL *xino;
|
||||||
|
XFS_INODE_ALL *parent;
|
||||||
|
|
||||||
|
return
|
||||||
|
(strlen(name) <= XFS_MAXFILENAMELEN &&
|
||||||
|
inum < xfs->inode_count &&
|
||||||
|
((xino = xfs->inode_table[inum]) != NULL) &&
|
||||||
|
new_parent_inum != DELETE_PENDING_ID &&
|
||||||
|
new_parent_inum < xfs->inode_count &&
|
||||||
|
((parent = xfs->inode_table[new_parent_inum]) != NULL) &&
|
||||||
|
(parent->pub.mode & S_IFDIR) != 0 &&
|
||||||
|
xfs_is_under(xfs, inum, new_parent_inum) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
int
|
||||||
|
xfs_move_entry(struct xfs_fs *xfs, fuse_ino_t inum,
|
||||||
|
fuse_ino_t new_parent_inum, const char *name)
|
||||||
|
{
|
||||||
|
int result = EINVAL;
|
||||||
|
XFS_INODE_ALL *xino;
|
||||||
|
XFS_INODE_ALL *parent;
|
||||||
|
XFS_INODE *dest;
|
||||||
|
|
||||||
|
if (xfs_check_move_entry(xfs, inum, new_parent_inum, name))
|
||||||
|
{
|
||||||
|
xino = xfs->inode_table[inum];
|
||||||
|
parent = xfs->inode_table[new_parent_inum];
|
||||||
|
|
||||||
|
if (xino->parent != parent)
|
||||||
|
{
|
||||||
|
/* We're moving between directories */
|
||||||
|
|
||||||
|
/* Does the target name already exist in the destination? */
|
||||||
|
if ((dest = xfs_lookup_in_dir(xfs, new_parent_inum, name)) != NULL)
|
||||||
|
{
|
||||||
|
xfs_remove_entry(xfs, dest->inum);
|
||||||
|
}
|
||||||
|
|
||||||
|
unlink_inode_from_parent(xino);
|
||||||
|
link_inode_into_directory_node(parent, xino);
|
||||||
|
strcpy(xino->pub.name, name);
|
||||||
|
}
|
||||||
|
else if (strcmp(xino->pub.name, name) != 0)
|
||||||
|
{
|
||||||
|
/* Same directory, but name has changed */
|
||||||
|
if ((dest = xfs_lookup_in_dir(xfs, new_parent_inum, name)) != NULL)
|
||||||
|
{
|
||||||
|
xfs_remove_entry(xfs, dest->inum);
|
||||||
|
}
|
||||||
|
strcpy(xino->pub.name, name);
|
||||||
|
}
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif /* XRDP_FUSE */
|
321
sesman/chansrv/chansrv_xfs.h
Normal file
321
sesman/chansrv/chansrv_xfs.h
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
/**
|
||||||
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* This file is the interface to the FUSE file system used by
|
||||||
|
* chansrv
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CHANSRV_XFS
|
||||||
|
#define _CHANSRV_XFS
|
||||||
|
|
||||||
|
/* Skip this include if there's no FUSE */
|
||||||
|
#ifdef XRDP_FUSE
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <fuse_lowlevel.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "arch.h"
|
||||||
|
|
||||||
|
#define XFS_MAXFILENAMELEN 255
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Incomplete types for the public interface
|
||||||
|
*/
|
||||||
|
struct xfs_fs;
|
||||||
|
struct xfs_dir_handle;
|
||||||
|
|
||||||
|
typedef struct xfs_inode
|
||||||
|
{
|
||||||
|
fuse_ino_t inum; /* File serial number. */
|
||||||
|
mode_t mode; /* File mode. */
|
||||||
|
uid_t uid; /* User ID of the file's owner. */
|
||||||
|
gid_t gid; /* Group ID of the file's group. */
|
||||||
|
off_t size; /* Size of file, in bytes. */
|
||||||
|
time_t atime; /* Time of last access. */
|
||||||
|
time_t mtime; /* Time of last modification. */
|
||||||
|
time_t ctime; /* Time of last status change. */
|
||||||
|
char name[XFS_MAXFILENAMELEN + 1]; /* Short name */
|
||||||
|
tui32 generation; /* Changes if inode is reused */
|
||||||
|
tui32 device_id; /* for file system redirection
|
||||||
|
* Non-redirected devices are guaranteed
|
||||||
|
* to have a device_id or zero */
|
||||||
|
int lindex; /* used in clipboard operations */
|
||||||
|
} XFS_INODE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a new filesystem instance
|
||||||
|
*
|
||||||
|
* @param umask Umask to apply to initial data structures
|
||||||
|
* @param uid Owner UID for initial root directory
|
||||||
|
* @param gid Owner GID for initial root directory
|
||||||
|
* @return Pointer to instance, or NULL if no memory
|
||||||
|
*/
|
||||||
|
struct xfs_fs *
|
||||||
|
xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete a filesystem instance
|
||||||
|
*
|
||||||
|
* @param xfs Filesystem instance
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
xfs_delete_xfs_fs(struct xfs_fs *xfs);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add an entry to the filesystem
|
||||||
|
*
|
||||||
|
* The returned element has default values inherited from the parent
|
||||||
|
*
|
||||||
|
* The specified mode is sanitised in that:-
|
||||||
|
* - Bits other than the lowest nine permissions bits, the directory
|
||||||
|
* bit (S_IFDIR) and the regular bit (S_IFREG) are cleared.
|
||||||
|
* - S_IFREG is cleared if S_IFDIR is set
|
||||||
|
* - S_IFREG is set if neither S_IFDIR or S_IFREG is set
|
||||||
|
*
|
||||||
|
* NULL is returned for one of the following conditions:-
|
||||||
|
* - the parent does not exist
|
||||||
|
* - the parent is not a directory
|
||||||
|
* - the name length exceeds XFS_MAXFILENAMELEN
|
||||||
|
* - the entry already exists
|
||||||
|
* - memory is exhausted.
|
||||||
|
*
|
||||||
|
* @param xfs filesystem instance
|
||||||
|
* @param parent_inode parent inode
|
||||||
|
* @param name Name of entry
|
||||||
|
* @param mode Initial mode for file.
|
||||||
|
* @return inode, or NULL
|
||||||
|
*/
|
||||||
|
XFS_INODE *
|
||||||
|
xfs_add_entry(struct xfs_fs *xfs, fuse_ino_t parent_inum,
|
||||||
|
const char *name, mode_t mode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete the contents of a directory
|
||||||
|
*
|
||||||
|
* If normal files are opened when they are deleted, the inode is not
|
||||||
|
* released until the open count goes to zero.
|
||||||
|
*
|
||||||
|
* @param xfs filesystem instance
|
||||||
|
* @param inode Reference to entry to delete
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
xfs_remove_directory_contents(struct xfs_fs *xfs, fuse_ino_t inum);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete an entry from the filesystem
|
||||||
|
*
|
||||||
|
* If normal files are opened when they are deleted, the inode is not
|
||||||
|
* released until the open count goes to zero.
|
||||||
|
*
|
||||||
|
* For directories, the contents are removed first.
|
||||||
|
*
|
||||||
|
* @param xfs filesystem instance
|
||||||
|
* @param inode Reference to entry to delete
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
xfs_remove_entry(struct xfs_fs *xfs, fuse_ino_t inum);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get an XFS_INODE for an inum
|
||||||
|
*
|
||||||
|
* @param xfs filesystem instance
|
||||||
|
* @param inum Inumber
|
||||||
|
* @return Pointer to XFS_INODE
|
||||||
|
*/
|
||||||
|
XFS_INODE *
|
||||||
|
xfs_get(struct xfs_fs *xfs, fuse_ino_t inum);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the full path for an inum
|
||||||
|
*
|
||||||
|
* The path is dynamically allocated, and must be freed after use
|
||||||
|
*
|
||||||
|
* @param xfs filesystem instance
|
||||||
|
* @param inum Inumber to get path for
|
||||||
|
* @return Full path (free after use)
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
xfs_get_full_path(struct xfs_fs *xfs, fuse_ino_t inum);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lookup a file in a directory
|
||||||
|
*
|
||||||
|
* @param xfs filesystem instance
|
||||||
|
* @param inum Inumber of the directory
|
||||||
|
* @param name Name of the file to lookup
|
||||||
|
* @return Pointer to XFS_INODE if found
|
||||||
|
*/
|
||||||
|
XFS_INODE *
|
||||||
|
xfs_lookup_in_dir(struct xfs_fs *xfs, fuse_ino_t inum, const char *name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inquires as to whether a directory is empty.
|
||||||
|
*
|
||||||
|
* The caller must check that the inum is actually a directory, or
|
||||||
|
* the result is undefined.
|
||||||
|
*
|
||||||
|
* @param xfs filesystem instance
|
||||||
|
* @param inum Inumber of the directory
|
||||||
|
* @return True if the directory is empty
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xfs_is_dir_empty(struct xfs_fs *xfs, fuse_ino_t inum);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inquires as to whether an entry is under a directory.
|
||||||
|
*
|
||||||
|
* This can be used to check for invalid renames, where we try to
|
||||||
|
* rename a directory into one of its sub-directories.
|
||||||
|
*
|
||||||
|
* Returned value means one of the following:-
|
||||||
|
* 0 Entry is not related to the directory
|
||||||
|
* 1 Entry is an immediate member of the directory
|
||||||
|
* 2.. Entry is a few levels below the directory
|
||||||
|
*
|
||||||
|
* @param xfs filesystem instance
|
||||||
|
* @param dir Inumber of the directory
|
||||||
|
* @param entry Inumber of the entry
|
||||||
|
* @return Nesting count of entry in the directory, or 0 for
|
||||||
|
* no nesting
|
||||||
|
*/
|
||||||
|
unsigned int
|
||||||
|
xfs_is_under(struct xfs_fs *xfs, fuse_ino_t dir, fuse_ino_t entry);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Opens a directory for reading
|
||||||
|
*
|
||||||
|
* @param xfs filesystem instance
|
||||||
|
* @param dir Inumber of the directory
|
||||||
|
* @return handle to be passed to xfs_readdir() and xfs_closedir()
|
||||||
|
*/
|
||||||
|
struct xfs_dir_handle *
|
||||||
|
xfs_opendir(struct xfs_fs *xfs, fuse_ino_t dir);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets the next entry from a directory
|
||||||
|
*
|
||||||
|
* This function is safe to call while the filesystem is being modified.
|
||||||
|
* Whether files added or removed from the directory in question are
|
||||||
|
* returned or not is unspecified by this interface.
|
||||||
|
*
|
||||||
|
* @param xfs filesystem instance
|
||||||
|
* @param handle Handle from xfs_opendir
|
||||||
|
* @param off Offset (by reference). Pass in zero to get the first
|
||||||
|
* entry. After the call, the offset is updated so that
|
||||||
|
* the next call gets the next entry.
|
||||||
|
*
|
||||||
|
* @return pointer to details of file entry, or NULL if no more
|
||||||
|
* entries are available.
|
||||||
|
*/
|
||||||
|
XFS_INODE *
|
||||||
|
xfs_readdir(struct xfs_fs *xfs, struct xfs_dir_handle *handle, off_t *off);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Closes a directory opened for reading
|
||||||
|
*
|
||||||
|
* @param xfs filesystem instance
|
||||||
|
* @param handle Earlier result of readdir() call
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
xfs_closedir(struct xfs_fs *xfs, struct xfs_dir_handle *handle);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Increment the file open count
|
||||||
|
*
|
||||||
|
* The file open count is used to be sure when an entry can be deleted from
|
||||||
|
* the data structures. It allows us to remove an entry while still retaining
|
||||||
|
* enough state to manage the file
|
||||||
|
*
|
||||||
|
* This call is only necessary for regular files - not directories
|
||||||
|
*
|
||||||
|
* @param xfs filesystem instance
|
||||||
|
* @param inum File to increment the count of
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
xfs_increment_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decrement the file open count
|
||||||
|
*
|
||||||
|
* This call will ensure that deleted inodes are cleared up at the appropriate
|
||||||
|
* time.
|
||||||
|
*
|
||||||
|
* This call is only necessary for regular files - not directories
|
||||||
|
*
|
||||||
|
* @param xfs filesystem instance
|
||||||
|
* @param inum File to decrement the count of
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
xfs_decrement_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the file open count for a regular file
|
||||||
|
*/
|
||||||
|
unsigned int
|
||||||
|
xfs_get_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Deletes all entries with the matching device id
|
||||||
|
*
|
||||||
|
* Files are deleted even if they are open
|
||||||
|
*
|
||||||
|
* The specified device_id must be non-zero so that the root
|
||||||
|
* filesystem is not deleted!
|
||||||
|
*
|
||||||
|
* @param device_id Device ID
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
xfs_delete_entries_with_device_id(struct xfs_fs *xfs, tui32 device_id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check an entry move will be successful
|
||||||
|
*
|
||||||
|
* A move will fail if:-
|
||||||
|
* - Any of the parameters are invalid
|
||||||
|
* - if the entry is a directory, and the new parent is below the
|
||||||
|
* entry in the existing hierarchy.
|
||||||
|
*
|
||||||
|
* @param xfs filesystem instance
|
||||||
|
* @param inum Inumber of entry
|
||||||
|
* @param new_parent New parent
|
||||||
|
* @param name New name
|
||||||
|
*
|
||||||
|
* @result != 0 if all looks OK
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xfs_check_move_entry(struct xfs_fs *xfs, fuse_ino_t inum,
|
||||||
|
fuse_ino_t new_parent_inum, const char *name);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Move (rename) an entry
|
||||||
|
*
|
||||||
|
* @param xfs filesystem instance
|
||||||
|
* @param inum Inumber of entry
|
||||||
|
* @param new_parent New parent
|
||||||
|
* @param name New name
|
||||||
|
*
|
||||||
|
* @result 0, or a suitable errno value.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xfs_move_entry(struct xfs_fs *xfs, fuse_ino_t inum,
|
||||||
|
fuse_ino_t new_parent_inum, const char *name);
|
||||||
|
|
||||||
|
#endif /* XRDP_FUSE */
|
||||||
|
#endif /* _CHANSRV_XFS */
|
File diff suppressed because it is too large
Load Diff
@ -18,334 +18,80 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// LK_TODO dev_redir_xxx should become devredir_xxx
|
|
||||||
|
|
||||||
#if !defined(DEVREDIR_H)
|
#if !defined(DEVREDIR_H)
|
||||||
#define DEVREDIR_H
|
#define DEVREDIR_H
|
||||||
|
|
||||||
#include "irp.h"
|
#include "irp.h"
|
||||||
|
#include "ms-rdpefs.h"
|
||||||
|
|
||||||
#define USE_SHORT_NAMES_IN_DIR_LISTING
|
int devredir_init(void);
|
||||||
|
int devredir_deinit(void);
|
||||||
|
|
||||||
FUSE_DATA *devredir_fuse_data_peek(IRP *irp);
|
int devredir_data_in(struct stream* s, int chan_id, int chan_flags,
|
||||||
FUSE_DATA *devredir_fuse_data_dequeue(IRP *irp);
|
int length, int total_length);
|
||||||
int devredir_fuse_data_enqueue(IRP *irp, void *vp);
|
|
||||||
|
|
||||||
int dev_redir_init(void);
|
int devredir_get_wait_objs(tbus* objs, int* count, int* timeout);
|
||||||
int dev_redir_deinit(void);
|
int devredir_check_wait_objs(void);
|
||||||
|
|
||||||
int dev_redir_data_in(struct stream* s, int chan_id, int chan_flags,
|
|
||||||
int length, int total_length);
|
|
||||||
|
|
||||||
int dev_redir_get_wait_objs(tbus* objs, int* count, int* timeout);
|
|
||||||
int dev_redir_check_wait_objs(void);
|
|
||||||
|
|
||||||
void dev_redir_send_server_core_cap_req(void);
|
|
||||||
void dev_redir_send_server_clientID_confirm(void);
|
|
||||||
void dev_redir_send_server_user_logged_on(void);
|
|
||||||
void devredir_send_server_device_announce_resp(tui32 device_id);
|
|
||||||
|
|
||||||
void dev_redir_send_drive_dir_request(IRP *irp, tui32 device_id,
|
|
||||||
tui32 InitialQuery, char *Path);
|
|
||||||
|
|
||||||
int dev_redir_send_drive_create_request(tui32 device_id,
|
|
||||||
const char *path,
|
|
||||||
tui32 DesiredAccess,
|
|
||||||
tui32 CreateOptions,
|
|
||||||
tui32 CreateDisposition,
|
|
||||||
tui32 completion_id);
|
|
||||||
|
|
||||||
int dev_redir_send_drive_close_request(tui16 Component, tui16 PacketId,
|
|
||||||
tui32 DeviceId,
|
|
||||||
tui32 FileId,
|
|
||||||
tui32 CompletionId,
|
|
||||||
tui32 MajorFunction,
|
|
||||||
tui32 MinorFunc,
|
|
||||||
int pad_len);
|
|
||||||
|
|
||||||
void devredir_proc_client_devlist_announce_req(struct stream *s);
|
|
||||||
void dev_redir_proc_client_core_cap_resp(struct stream *s);
|
|
||||||
void dev_redir_proc_device_iocompletion(struct stream *s);
|
|
||||||
|
|
||||||
void dev_redir_proc_query_dir_response(IRP *irp,
|
|
||||||
struct stream *s,
|
|
||||||
tui32 DeviceId,
|
|
||||||
tui32 CompletionId,
|
|
||||||
tui32 IoStatus);
|
|
||||||
|
|
||||||
/* misc stuff */
|
/* misc stuff */
|
||||||
void devredir_insert_DeviceIoRequest(struct stream *s,
|
void devredir_insert_DeviceIoRequest(struct stream *s,
|
||||||
tui32 DeviceId,
|
tui32 DeviceId,
|
||||||
tui32 FileId,
|
tui32 FileId,
|
||||||
tui32 CompletionId,
|
tui32 CompletionId,
|
||||||
tui32 MajorFunction,
|
enum IRP_MJ MajorFunction,
|
||||||
tui32 MinorFunction);
|
enum IRP_MN MinorFunction);
|
||||||
|
|
||||||
void devredir_cvt_slash(char *path);
|
/* State pointer types (opaque outside this module), used for
|
||||||
void devredir_cvt_to_unicode(char *unicode, const char *path);
|
* callback data
|
||||||
void devredir_cvt_from_unicode_len(char *path, char *unicode, int len);
|
*/
|
||||||
int dev_redir_string_ends_with(const char *string, char c);
|
struct state_dirscan;
|
||||||
|
struct state_lookup;
|
||||||
void devredir_insert_RDPDR_header(struct stream *s, tui16 Component,
|
struct state_setattr;
|
||||||
tui16 PacketId);
|
struct state_open;
|
||||||
|
struct state_create;
|
||||||
|
struct state_read;
|
||||||
|
struct state_write;
|
||||||
|
struct state_remove;
|
||||||
|
struct state_close;
|
||||||
|
|
||||||
/* called from FUSE module */
|
/* called from FUSE module */
|
||||||
int dev_redir_get_dir_listing(void *fusep, tui32 device_id, const char *path);
|
|
||||||
|
|
||||||
int dev_redir_lookup_entry(void *fusep, tui32 device_id, const char *dirpath,
|
int devredir_get_dir_listing(struct state_dirscan *fusep, tui32 device_id,
|
||||||
const char *entry);
|
const char *path);
|
||||||
|
|
||||||
int dev_redir_file_open(void *fusep, tui32 device_id, const char *path,
|
int devredir_lookup_entry(struct state_lookup *fusep, tui32 device_id,
|
||||||
int mode, int type, const char *gen_buf);
|
const char *path);
|
||||||
|
|
||||||
int devredir_file_close(void *fusep, tui32 device_id, tui32 file_id);
|
int devredir_setattr_for_entry(
|
||||||
|
struct state_setattr *fusep, tui32 device_id,
|
||||||
|
const char *filename,
|
||||||
|
const struct file_attr *fattr,
|
||||||
|
tui32 to_set);
|
||||||
|
|
||||||
int devredir_file_read(void *fusep, tui32 device_id, tui32 FileId,
|
int devredir_file_create(
|
||||||
|
struct state_create *fusep, tui32 device_id,
|
||||||
|
const char *path, int mode);
|
||||||
|
|
||||||
|
int devredir_file_open(struct state_open *fusep, tui32 device_id,
|
||||||
|
const char *path, int flags);
|
||||||
|
|
||||||
|
int devredir_file_close(struct state_close *fusep, tui32 device_id,
|
||||||
|
tui32 file_id);
|
||||||
|
|
||||||
|
int devredir_file_read(struct state_read *fusep, tui32 device_id, tui32 FileId,
|
||||||
tui32 Length, tui64 Offset);
|
tui32 Length, tui64 Offset);
|
||||||
|
|
||||||
int
|
int
|
||||||
dev_redir_file_write(void *fusep, tui32 DeviceId, tui32 FileId,
|
devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId,
|
||||||
const char *buf, int Length, tui64 Offset);
|
const char *buf, int Length, tui64 Offset);
|
||||||
|
|
||||||
|
int devredir_file_rename(
|
||||||
|
struct state_rename *fusep, tui32 device_id,
|
||||||
|
const char *old_name,
|
||||||
|
const char *new_name);
|
||||||
|
|
||||||
int
|
int
|
||||||
devredir_rmdir_or_file(void *fusep, tui32 device_id, const char *path, int mode);
|
devredir_rmdir_or_file(struct state_remove *fusep, tui32 device_id,
|
||||||
|
const char *path);
|
||||||
/*
|
|
||||||
* RDPDR_HEADER definitions
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* device redirector core component; most of the packets in this protocol */
|
|
||||||
/* are sent under this component ID */
|
|
||||||
#define RDPDR_CTYP_CORE 0x4472
|
|
||||||
|
|
||||||
/* printing component. the packets that use this ID are typically about */
|
|
||||||
/* printer cache management and identifying XPS printers */
|
|
||||||
#define RDPDR_CTYP_PRN 0x5052
|
|
||||||
|
|
||||||
/* Server Announce Request, as specified in section 2.2.2.2 */
|
|
||||||
#define PAKID_CORE_SERVER_ANNOUNCE 0x496E
|
|
||||||
|
|
||||||
/* Client Announce Reply and Server Client ID Confirm, as specified in */
|
|
||||||
/* sections 2.2.2.3 and 2.2.2.6. */
|
|
||||||
#define PAKID_CORE_CLIENTID_CONFIRM 0x4343
|
|
||||||
|
|
||||||
/* Client Name Request, as specified in section 2.2.2.4 */
|
|
||||||
#define PAKID_CORE_CLIENT_NAME 0x434E
|
|
||||||
|
|
||||||
/* Client Device List Announce Request, as specified in section 2.2.2.9 */
|
|
||||||
#define PAKID_CORE_DEVICELIST_ANNOUNCE 0x4441
|
|
||||||
|
|
||||||
/* Server Device Announce Response, as specified in section 2.2.2.1 */
|
|
||||||
#define PAKID_CORE_DEVICE_REPLY 0x6472
|
|
||||||
|
|
||||||
/* Device I/O Request, as specified in section 2.2.1.4 */
|
|
||||||
#define PAKID_CORE_DEVICE_IOREQUEST 0x4952
|
|
||||||
|
|
||||||
/* Device I/O Response, as specified in section 2.2.1.5 */
|
|
||||||
#define PAKID_CORE_DEVICE_IOCOMPLETION 0x4943
|
|
||||||
|
|
||||||
/* Server Core Capability Request, as specified in section 2.2.2.7 */
|
|
||||||
#define PAKID_CORE_SERVER_CAPABILITY 0x5350
|
|
||||||
|
|
||||||
/* Client Core Capability Response, as specified in section 2.2.2.8 */
|
|
||||||
#define PAKID_CORE_CLIENT_CAPABILITY 0x4350
|
|
||||||
|
|
||||||
/* Client Drive Device List Remove, as specified in section 2.2.3.2 */
|
|
||||||
#define PAKID_CORE_DEVICELIST_REMOVE 0x444D
|
|
||||||
|
|
||||||
/* Add Printer Cachedata, as specified in [MS-RDPEPC] section 2.2.2.3 */
|
|
||||||
#define PAKID_PRN_CACHE_DATA 0x5043
|
|
||||||
|
|
||||||
/* Server User Logged On, as specified in section 2.2.2.5 */
|
|
||||||
#define PAKID_CORE_USER_LOGGEDON 0x554C
|
|
||||||
|
|
||||||
/* Server Printer Set XPS Mode, as specified in [MS-RDPEPC] section 2.2.2.2 */
|
|
||||||
#define PAKID_PRN_USING_XPS 0x5543
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Capability header definitions
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define CAP_GENERAL_TYPE 0x0001 /* General cap set - GENERAL_CAPS_SET */
|
|
||||||
#define CAP_PRINTER_TYPE 0x0002 /* Print cap set - PRINTER_CAPS_SET */
|
|
||||||
#define CAP_PORT_TYPE 0x0003 /* Port cap set - PORT_CAPS_SET */
|
|
||||||
#define CAP_DRIVE_TYPE 0x0004 /* Drive cap set - DRIVE_CAPS_SET */
|
|
||||||
#define CAP_SMARTCARD_TYPE 0x0005 /* Smart card cap set - SMARTCARD_CAPS_SET */
|
|
||||||
|
|
||||||
/* client minor versions */
|
|
||||||
#define RDP_CLIENT_50 0x0002
|
|
||||||
#define RDP_CLIENT_51 0x0005
|
|
||||||
#define RDP_CLIENT_52 0x000a
|
|
||||||
#define RDP_CLIENT_60_61 0x000c
|
|
||||||
|
|
||||||
/* used in device announce list */
|
|
||||||
#define RDPDR_DTYP_SERIAL 0x0001
|
|
||||||
#define RDPDR_DTYP_PARALLEL 0x0002
|
|
||||||
#define RDPDR_DTYP_PRINT 0x0004
|
|
||||||
#define RDPDR_DTYP_FILESYSTEM 0x0008
|
|
||||||
#define RDPDR_DTYP_SMARTCARD 0x0020
|
|
||||||
|
|
||||||
/*
|
|
||||||
* DesiredAccess Mask [MS-SMB2] section 2.2.13.1.1
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define DA_FILE_READ_DATA 0x00000001
|
|
||||||
#define DA_FILE_WRITE_DATA 0x00000002
|
|
||||||
#define DA_FILE_APPEND_DATA 0x00000004
|
|
||||||
#define DA_FILE_READ_EA 0x00000008 /* rd extended attributes */
|
|
||||||
#define DA_FILE_WRITE_EA 0x00000010 /* wr extended attributes */
|
|
||||||
#define DA_FILE_EXECUTE 0x00000020
|
|
||||||
#define DA_FILE_READ_ATTRIBUTES 0x00000080
|
|
||||||
#define DA_FILE_WRITE_ATTRIBUTES 0x00000100
|
|
||||||
#define DA_DELETE 0x00010000
|
|
||||||
#define DA_READ_CONTROL 0x00020000 /* rd security descriptor */
|
|
||||||
#define DA_WRITE_DAC 0x00040000
|
|
||||||
#define DA_WRITE_OWNER 0x00080000
|
|
||||||
#define DA_SYNCHRONIZE 0x00100000
|
|
||||||
#define DA_ACCESS_SYSTEM_SECURITY 0x01000000
|
|
||||||
#define DA_MAXIMUM_ALLOWED 0x02000000
|
|
||||||
#define DA_GENERIC_ALL 0x10000000
|
|
||||||
#define DA_GENERIC_EXECUTE 0x20000000
|
|
||||||
#define DA_GENERIC_WRITE 0x40000000
|
|
||||||
#define DA_GENERIC_READ 0x80000000
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CreateOptions Mask [MS-SMB2] section 2.2.13 SMB2 CREATE Request
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum CREATE_OPTIONS
|
|
||||||
{
|
|
||||||
CO_FILE_DIRECTORY_FILE = 0x00000001,
|
|
||||||
CO_FILE_WRITE_THROUGH = 0x00000002,
|
|
||||||
CO_FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020,
|
|
||||||
CO_FILE_DELETE_ON_CLOSE = 0x00001000
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CreateDispositions Mask [MS-SMB2] section 2.2.13
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define CD_FILE_SUPERSEDE 0x00000000
|
|
||||||
#define CD_FILE_OPEN 0x00000001
|
|
||||||
#define CD_FILE_CREATE 0x00000002
|
|
||||||
#define CD_FILE_OPEN_IF 0x00000003
|
|
||||||
#define CD_FILE_OVERWRITE 0x00000004
|
|
||||||
#define CD_FILE_OVERWRITE_IF 0x00000005
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Device I/O Request MajorFunction definitions
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define IRP_MJ_CREATE 0x00000000
|
|
||||||
#define IRP_MJ_CLOSE 0x00000002
|
|
||||||
#define IRP_MJ_READ 0x00000003
|
|
||||||
#define IRP_MJ_WRITE 0x00000004
|
|
||||||
#define IRP_MJ_DEVICE_CONTROL 0x0000000E
|
|
||||||
#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0000000A
|
|
||||||
#define IRP_MJ_SET_VOLUME_INFORMATION 0x0000000B
|
|
||||||
#define IRP_MJ_QUERY_INFORMATION 0x00000005
|
|
||||||
#define IRP_MJ_SET_INFORMATION 0x00000006
|
|
||||||
#define IRP_MJ_DIRECTORY_CONTROL 0x0000000C
|
|
||||||
#define IRP_MJ_LOCK_CONTROL 0x00000011
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Device I/O Request MinorFunction definitions
|
|
||||||
*
|
|
||||||
* Only valid when MajorFunction code = IRP_MJ_DIRECTORY_CONTROL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define IRP_MN_QUERY_DIRECTORY 0x00000001
|
|
||||||
#define IRP_MN_NOTIFY_CHANGE_DIRECTORY 0x00000002
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NTSTATUS codes (used by IoStatus) - see section 2.3 of MS-ERREF
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define NT_STATUS_SUCCESS 0x00000000
|
|
||||||
#define NT_STATUS_UNSUCCESSFUL 0xC0000001
|
|
||||||
#define NT_STATUS_NO_SUCH_FILE 0xC000000F
|
|
||||||
#define NT_STATUS_ACCESS_DENIED 0xC0000022
|
|
||||||
#define NT_STATUS_OBJECT_NAME_INVALID 0xC0000033
|
|
||||||
#define NT_STATUS_OBJECT_NAME_NOT_FOUND 0xC0000034
|
|
||||||
|
|
||||||
/*
|
|
||||||
* File system ioctl codes
|
|
||||||
* MS-FSCC section 2.3 FSCTL Structures
|
|
||||||
*/
|
|
||||||
#define FSCTL_DELETE_OBJECT_ID 0x900a0
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CompletionID types, used in IRPs to indicate I/O operation
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum COMPLETION_ID
|
|
||||||
{
|
|
||||||
CID_CREATE_DIR_REQ = 1,
|
|
||||||
CID_DIRECTORY_CONTROL,
|
|
||||||
CID_CREATE_OPEN_REQ,
|
|
||||||
CID_READ,
|
|
||||||
CID_WRITE,
|
|
||||||
CID_CLOSE,
|
|
||||||
CID_FILE_CLOSE,
|
|
||||||
CID_RMDIR_OR_FILE,
|
|
||||||
CID_RMDIR_OR_FILE_RESP,
|
|
||||||
CID_RENAME_FILE,
|
|
||||||
CID_RENAME_FILE_RESP,
|
|
||||||
CID_LOOKUP_BASIC_ENTRY,
|
|
||||||
CID_LOOKUP_STD_ENTRY,
|
|
||||||
CID_LOOKUP_ENTRY_RESP
|
|
||||||
};
|
|
||||||
|
|
||||||
enum FS_INFORMATION_CLASS
|
|
||||||
{
|
|
||||||
FileBasicInformation = 0x00000004, /* set atime, mtime, ctime etc */
|
|
||||||
FileStandardInformation = 0x00000005, /* Alloc size, EOF #links, etc */
|
|
||||||
FileEndOfFileInformation = 0x00000014, /* set EOF info */
|
|
||||||
FileDispositionInformation = 0x0000000D, /* mark a file for deletion */
|
|
||||||
FileRenameInformation = 0x0000000A, /* rename a file */
|
|
||||||
FileAllocationInformation = 0x00000013 /* set file allocation size */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* constants for drive dir query
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Basic information about a file or directory. Basic information is */
|
|
||||||
/* defined as the file's name, time stamp, and size, or its attributes */
|
|
||||||
#define FileDirectoryInformation 0x00000001
|
|
||||||
|
|
||||||
/* Full information about a file or directory. Full information is defined */
|
|
||||||
/* as all the basic information, plus extended attribute size. */
|
|
||||||
#define FileFullDirectoryInformation 0x00000002
|
|
||||||
|
|
||||||
/* Basic information plus extended attribute size and short name */
|
|
||||||
/* about a file or directory. */
|
|
||||||
#define FileBothDirectoryInformation 0x00000003
|
|
||||||
|
|
||||||
/* Detailed information on the names of files in a directory. */
|
|
||||||
#define FileNamesInformation 0x0000000C
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NTSTATUS Codes of interest to us
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* No more files were found which match the file specification */
|
|
||||||
#define STATUS_NO_MORE_FILES 0x80000006
|
|
||||||
|
|
||||||
/* Windows file attributes */
|
|
||||||
#define W_FILE_ATTRIBUTE_DIRECTORY 0x00000010
|
|
||||||
#define W_FILE_ATTRIBUTE_READONLY 0x00000001
|
|
||||||
|
|
||||||
#define WINDOWS_TO_LINUX_FILE_PERM(_a) \
|
|
||||||
(((_a) & W_FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR | 0100 : S_IFREG) |\
|
|
||||||
(((_a) & W_FILE_ATTRIBUTE_READONLY) ? 0444 : 0644)
|
|
||||||
|
|
||||||
/* Windows time starts on Jan 1, 1601 */
|
|
||||||
/* Linux time starts on Jan 1, 1970 */
|
|
||||||
#define EPOCH_DIFF 11644473600LL
|
|
||||||
#define WINDOWS_TO_LINUX_TIME(_t) ((_t) / 10000000) - EPOCH_DIFF;
|
|
||||||
|
|
||||||
#define OP_RENAME_FILE 0x01
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -105,32 +105,67 @@ IRP * devredir_irp_new(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clone specified IRP
|
* Create a new IRP with a copied pathname, and append to linked list.
|
||||||
|
*
|
||||||
|
* Allocation is made in such a way that the IRP can be freed with a single
|
||||||
|
* free() operation
|
||||||
*
|
*
|
||||||
* @return new IRP or NULL on error
|
* @return new IRP or NULL on error
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
IRP * devredir_irp_clone(IRP *irp)
|
IRP * devredir_irp_with_pathname_new(const char *pathname)
|
||||||
{
|
{
|
||||||
IRP *new_irp;
|
unsigned int len = g_strlen(pathname);
|
||||||
IRP *prev;
|
IRP * irp = devredir_irp_with_pathnamelen_new(len);
|
||||||
IRP *next;
|
if (irp != NULL)
|
||||||
|
{
|
||||||
|
g_strcpy(irp->pathname, pathname);
|
||||||
|
}
|
||||||
|
|
||||||
if ((new_irp = devredir_irp_new()) == NULL)
|
return irp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new IRP with space allocated for a pathname, and append to
|
||||||
|
* linked list.
|
||||||
|
*
|
||||||
|
* Allocation is made in such a way that the IRP can be freed with a single
|
||||||
|
* free() operation
|
||||||
|
*
|
||||||
|
* @return new IRP or NULL on error
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
IRP * devredir_irp_with_pathnamelen_new(unsigned int pathnamelen)
|
||||||
|
{
|
||||||
|
IRP *irp;
|
||||||
|
IRP *irp_last;
|
||||||
|
|
||||||
|
log_debug("entered");
|
||||||
|
|
||||||
|
/* create new IRP with space on end for the pathname and a terminator */
|
||||||
|
irp = (IRP *)g_malloc(sizeof(IRP) + (pathnamelen + 1), 1);
|
||||||
|
if (irp == NULL)
|
||||||
|
{
|
||||||
|
log_error("system out of memory!");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* save link pointers */
|
irp->pathname = (char *)irp + sizeof(IRP); /* Initialise pathname pointer */
|
||||||
prev = new_irp->prev;
|
|
||||||
next = new_irp->next;
|
|
||||||
|
|
||||||
/* copy all members */
|
/* insert at end of linked list */
|
||||||
g_memcpy(new_irp, irp, sizeof(IRP));
|
if ((irp_last = devredir_irp_get_last()) == NULL)
|
||||||
|
{
|
||||||
|
/* list is empty, this is the first entry */
|
||||||
|
g_irp_head = irp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
irp_last->next = irp;
|
||||||
|
irp->prev = irp_last;
|
||||||
|
}
|
||||||
|
|
||||||
/* restore link pointers */
|
log_debug("new IRP=%p", irp);
|
||||||
new_irp->prev = prev;
|
return irp;
|
||||||
new_irp->next = next;
|
|
||||||
|
|
||||||
return new_irp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,11 +29,49 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "chansrv_fuse.h"
|
#include "chansrv_fuse.h"
|
||||||
|
|
||||||
typedef struct fuse_data FUSE_DATA;
|
/* Opaque data types to us */
|
||||||
struct fuse_data
|
typedef struct xfuse_info XFUSE_INFO;
|
||||||
|
|
||||||
|
enum irp_lookup_state
|
||||||
{
|
{
|
||||||
void *data_ptr;
|
E_LOOKUP_GET_FH = 0,
|
||||||
FUSE_DATA *next;
|
E_LOOKUP_CHECK_BASIC,
|
||||||
|
E_LOOKUP_CHECK_EOF
|
||||||
|
} ;
|
||||||
|
|
||||||
|
enum irp_setattr_state
|
||||||
|
{
|
||||||
|
E_SETATTR_GET_FH = 0,
|
||||||
|
E_SETATTR_CHECK_BASIC,
|
||||||
|
E_SETATTR_CHECK_EOF
|
||||||
|
} ;
|
||||||
|
|
||||||
|
struct irp_lookup
|
||||||
|
{
|
||||||
|
enum irp_lookup_state state; /* Next state to consider */
|
||||||
|
struct file_attr fattr; /* Attributes to get */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct irp_setattr
|
||||||
|
{
|
||||||
|
enum irp_setattr_state state; /* Next state to consider */
|
||||||
|
tui32 to_set; /* Bit mask for elements in use */
|
||||||
|
struct file_attr fattr; /* Attributes to set */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct irp_write
|
||||||
|
{
|
||||||
|
tui64 offset; /* Offset the write was made at */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct irp_create
|
||||||
|
{
|
||||||
|
int creating_dir; /* We're creating a directory */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct irp_rename
|
||||||
|
{
|
||||||
|
char *new_name; /* New name for file */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* An I/O Resource Packet to track I/O calls */
|
/* An I/O Resource Packet to track I/O calls */
|
||||||
@ -46,15 +84,18 @@ struct irp
|
|||||||
tui32 DeviceId; /* identifies remote device */
|
tui32 DeviceId; /* identifies remote device */
|
||||||
tui32 FileId; /* RDP client provided unique number */
|
tui32 FileId; /* RDP client provided unique number */
|
||||||
char completion_type; /* describes I/O type */
|
char completion_type; /* describes I/O type */
|
||||||
char pathname[256]; /* absolute pathname */
|
char *pathname; /* absolute pathname
|
||||||
|
* Allocate with
|
||||||
|
* devredir_irp_with_pathname_new() */
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
char buf[1024]; /* General character data */
|
struct irp_lookup lookup; /* Used by lookup */
|
||||||
struct file_attr fattr; /* Used to assemble file attributes */
|
struct irp_setattr setattr; /* Used by setattr */
|
||||||
} gen; /* for general use */
|
struct irp_write write; /* Used by write */
|
||||||
int type;
|
struct irp_create create; /* Used by create */
|
||||||
FUSE_DATA *fd_head; /* point to first FUSE opaque object */
|
struct irp_rename rename; /* Use by rename */
|
||||||
FUSE_DATA *fd_tail; /* point to last FUSE opaque object */
|
} gen; /* Additional state data for some ops */
|
||||||
|
void *fuse_info; /* Fuse info pointer for FUSE calls */
|
||||||
IRP *next; /* point to next IRP */
|
IRP *next; /* point to next IRP */
|
||||||
IRP *prev; /* point to previous IRP */
|
IRP *prev; /* point to previous IRP */
|
||||||
int scard_index; /* used to smart card to locate dev */
|
int scard_index; /* used to smart card to locate dev */
|
||||||
@ -65,7 +106,13 @@ struct irp
|
|||||||
};
|
};
|
||||||
|
|
||||||
IRP * devredir_irp_new(void);
|
IRP * devredir_irp_new(void);
|
||||||
IRP * devredir_irp_clone(IRP *irp);
|
/* As above, but allocates sufficent space for the specified
|
||||||
|
* pathname, and copies it in to the pathname field */
|
||||||
|
IRP * devredir_irp_with_pathname_new(const char *pathname);
|
||||||
|
/* As above, but specifies a pathname length with pathname
|
||||||
|
* initially set to "". Use if you need to modify the pathname
|
||||||
|
* significantly */
|
||||||
|
IRP * devredir_irp_with_pathnamelen_new(unsigned int pathnamelen);
|
||||||
int devredir_irp_delete(IRP *irp);
|
int devredir_irp_delete(IRP *irp);
|
||||||
IRP * devredir_irp_find(tui32 completion_id);
|
IRP * devredir_irp_find(tui32 completion_id);
|
||||||
IRP * devredir_irp_find_by_fileid(tui32 FileId);
|
IRP * devredir_irp_find_by_fileid(tui32 FileId);
|
||||||
|
44
sesman/chansrv/ms-erref.h
Normal file
44
sesman/chansrv/ms-erref.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
|
*
|
||||||
|
* MS-ERREF : Definitions from [MS-ERREF]
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* References to MS-ERREF are currently correct for v20180912 of that
|
||||||
|
* document
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(MS_ERREF_H)
|
||||||
|
#define MS_ERREF_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NTSTATUS codes (section 2.3)
|
||||||
|
*/
|
||||||
|
enum NTSTATUS
|
||||||
|
{
|
||||||
|
NT_STATUS_SUCCESS = 0x00000000,
|
||||||
|
NT_STATUS_UNSUCCESSFUL = 0xC0000001,
|
||||||
|
NT_STATUS_NO_SUCH_FILE = 0xC000000F,
|
||||||
|
NT_STATUS_ACCESS_DENIED = 0xC0000022,
|
||||||
|
NT_STATUS_OBJECT_NAME_INVALID = 0xC0000033,
|
||||||
|
NT_STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034,
|
||||||
|
NT_STATUS_SHARING_VIOLATION = 0xC0000043,
|
||||||
|
NT_STATUS_NO_MORE_FILES = 0x80000006
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* MS_ERREF_H */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
64
sesman/chansrv/ms-fscc.h
Normal file
64
sesman/chansrv/ms-fscc.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
|
*
|
||||||
|
* MS-FSCC : Definitions from [MS-FSCC]
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* References to MS-FSCC are currently correct for v20190923 of that
|
||||||
|
* document
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(MS_FSCC_H)
|
||||||
|
#define MS_FSCC_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File system ioctl codes (section 2.3)
|
||||||
|
*/
|
||||||
|
#define FSCTL_DELETE_OBJECT_ID 0x900a0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File information classes (section 2.4)
|
||||||
|
*/
|
||||||
|
enum FS_INFORMATION_CLASS
|
||||||
|
{
|
||||||
|
FileAllocationInformation = 19, /* Set */
|
||||||
|
FileBasicInformation = 4, /* Query, Set */
|
||||||
|
FileBothDirectoryInformation = 3, /* Query */
|
||||||
|
FileDirectoryInformation = 1, /* Query */
|
||||||
|
FileDispositionInformation = 13, /* Set */
|
||||||
|
FileEndOfFileInformation = 20, /* Set */
|
||||||
|
FileFullDirectoryInformation = 2, /* Query */
|
||||||
|
FileNamesInformation = 12, /* Query */
|
||||||
|
FileRenameInformation = 10, /* Set */
|
||||||
|
FileStandardInformation = 5 /* Query */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Size of structs above without trailing RESERVED fields (MS-RDPEFS
|
||||||
|
* 2.2.3.3.8)
|
||||||
|
*/
|
||||||
|
#define FILE_BASIC_INFORMATION_SIZE 36
|
||||||
|
#define FILE_STD_INFORMATION_SIZE 22
|
||||||
|
#define FILE_END_OF_FILE_INFORMATION_SIZE 8
|
||||||
|
|
||||||
|
/* Windows file attributes (section 2.6) */
|
||||||
|
#define W_FILE_ATTRIBUTE_DIRECTORY 0x00000010
|
||||||
|
#define W_FILE_ATTRIBUTE_READONLY 0x00000001
|
||||||
|
#define W_FILE_ATTRIBUTE_SYSTEM 0x00000004
|
||||||
|
#define W_FILE_ATTRIBUTE_NORMAL 0x00000080
|
||||||
|
|
||||||
|
#endif /* MS_FSCC_H */
|
||||||
|
|
||||||
|
|
||||||
|
|
125
sesman/chansrv/ms-rdpefs.h
Normal file
125
sesman/chansrv/ms-rdpefs.h
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/**
|
||||||
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
|
*
|
||||||
|
* MS-RDPEFS : Definitions from [MS-RDPEFS]
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* References to MS-RDPEFS are currently correct for v20180912 of that
|
||||||
|
* document
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(MS_RDPEFS_H)
|
||||||
|
#define MS_RDPEFS_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RDPDR_HEADER definitions (2.2.1.1)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* device redirector core component; most of the packets in this protocol */
|
||||||
|
/* are sent under this component ID */
|
||||||
|
#define RDPDR_CTYP_CORE 0x4472
|
||||||
|
|
||||||
|
/* printing component. the packets that use this ID are typically about */
|
||||||
|
/* printer cache management and identifying XPS printers */
|
||||||
|
#define RDPDR_CTYP_PRN 0x5052
|
||||||
|
|
||||||
|
/* Server Announce Request, as specified in section 2.2.2.2 */
|
||||||
|
#define PAKID_CORE_SERVER_ANNOUNCE 0x496E
|
||||||
|
|
||||||
|
/* Client Announce Reply and Server Client ID Confirm, as specified in */
|
||||||
|
/* sections 2.2.2.3 and 2.2.2.6. */
|
||||||
|
#define PAKID_CORE_CLIENTID_CONFIRM 0x4343
|
||||||
|
|
||||||
|
/* Client Name Request, as specified in section 2.2.2.4 */
|
||||||
|
#define PAKID_CORE_CLIENT_NAME 0x434E
|
||||||
|
|
||||||
|
/* Client Device List Announce Request, as specified in section 2.2.2.9 */
|
||||||
|
#define PAKID_CORE_DEVICELIST_ANNOUNCE 0x4441
|
||||||
|
|
||||||
|
/* Server Device Announce Response, as specified in section 2.2.2.1 */
|
||||||
|
#define PAKID_CORE_DEVICE_REPLY 0x6472
|
||||||
|
|
||||||
|
/* Device I/O Request, as specified in section 2.2.1.4 */
|
||||||
|
#define PAKID_CORE_DEVICE_IOREQUEST 0x4952
|
||||||
|
|
||||||
|
/* Device I/O Response, as specified in section 2.2.1.5 */
|
||||||
|
#define PAKID_CORE_DEVICE_IOCOMPLETION 0x4943
|
||||||
|
|
||||||
|
/* Server Core Capability Request, as specified in section 2.2.2.7 */
|
||||||
|
#define PAKID_CORE_SERVER_CAPABILITY 0x5350
|
||||||
|
|
||||||
|
/* Client Core Capability Response, as specified in section 2.2.2.8 */
|
||||||
|
#define PAKID_CORE_CLIENT_CAPABILITY 0x4350
|
||||||
|
|
||||||
|
/* Client Drive Device List Remove, as specified in section 2.2.3.2 */
|
||||||
|
#define PAKID_CORE_DEVICELIST_REMOVE 0x444D
|
||||||
|
|
||||||
|
/* Add Printer Cachedata, as specified in [MS-RDPEPC] section 2.2.2.3 */
|
||||||
|
#define PAKID_PRN_CACHE_DATA 0x5043
|
||||||
|
|
||||||
|
/* Server User Logged On, as specified in section 2.2.2.5 */
|
||||||
|
#define PAKID_CORE_USER_LOGGEDON 0x554C
|
||||||
|
|
||||||
|
/* Server Printer Set XPS Mode, as specified in [MS-RDPEPC] section 2.2.2.2 */
|
||||||
|
#define PAKID_PRN_USING_XPS 0x5543
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Capability header definitions (2.2.1.2)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CAP_GENERAL_TYPE 0x0001 /* General cap set - GENERAL_CAPS_SET */
|
||||||
|
#define CAP_PRINTER_TYPE 0x0002 /* Print cap set - PRINTER_CAPS_SET */
|
||||||
|
#define CAP_PORT_TYPE 0x0003 /* Port cap set - PORT_CAPS_SET */
|
||||||
|
#define CAP_DRIVE_TYPE 0x0004 /* Drive cap set - DRIVE_CAPS_SET */
|
||||||
|
#define CAP_SMARTCARD_TYPE 0x0005 /* Smart card cap set - SMARTCARD_CAPS_SET */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device announce header (2.2.1.3)
|
||||||
|
*/
|
||||||
|
#define RDPDR_DTYP_SERIAL 0x0001
|
||||||
|
#define RDPDR_DTYP_PARALLEL 0x0002
|
||||||
|
#define RDPDR_DTYP_PRINT 0x0004
|
||||||
|
#define RDPDR_DTYP_FILESYSTEM 0x0008
|
||||||
|
#define RDPDR_DTYP_SMARTCARD 0x0020
|
||||||
|
|
||||||
|
/* Device I/O Request definitions (2.2.1.4) */
|
||||||
|
/* MajorFunction */
|
||||||
|
enum IRP_MJ
|
||||||
|
{
|
||||||
|
IRP_MJ_CREATE = 0x00000000,
|
||||||
|
IRP_MJ_CLOSE = 0x00000002,
|
||||||
|
IRP_MJ_READ = 0x00000003,
|
||||||
|
IRP_MJ_WRITE = 0x00000004,
|
||||||
|
IRP_MJ_DEVICE_CONTROL = 0x0000000E,
|
||||||
|
IRP_MJ_QUERY_VOLUME_INFORMATION = 0x0000000A,
|
||||||
|
IRP_MJ_SET_VOLUME_INFORMATION = 0x0000000B,
|
||||||
|
IRP_MJ_QUERY_INFORMATION = 0x00000005,
|
||||||
|
IRP_MJ_SET_INFORMATION = 0x00000006,
|
||||||
|
IRP_MJ_DIRECTORY_CONTROL = 0x0000000C,
|
||||||
|
IRP_MJ_LOCK_CONTROL = 0x00000011
|
||||||
|
};
|
||||||
|
|
||||||
|
/* MinorFunction */
|
||||||
|
/* Set to zero unless MajorFunction code == IRP_MJ_DIRECTORY_CONTROL */
|
||||||
|
enum IRP_MN
|
||||||
|
{
|
||||||
|
IRP_MN_NONE = 0x00000000, /* Name not in MS docs */
|
||||||
|
IRP_MN_QUERY_DIRECTORY = 0x00000001,
|
||||||
|
IRP_MN_NOTIFY_CHANGE_DIRECTORY = 0x00000002
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* MS_RDPEFS_H */
|
||||||
|
|
||||||
|
|
79
sesman/chansrv/ms-smb2.h
Normal file
79
sesman/chansrv/ms-smb2.h
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* xrdp: A Remote Desktop Protocol server.
|
||||||
|
*
|
||||||
|
* MS-SMB2 : Definitions from [MS-SMB2]
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* References to MS-SMB2 are currently correct for v20190923 of that
|
||||||
|
* document
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(MS_SMB2_H)
|
||||||
|
#define MS_SMB2_H
|
||||||
|
|
||||||
|
/* SMB2 CREATE request values (section 2.2.13) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ShareAccess Mask. Currently, this is referred
|
||||||
|
* to in MS-RDPEFS 2.2.1.4.1 as 'SharedAccess' rather than 'ShareAccess'.
|
||||||
|
*/
|
||||||
|
#define SA_FILE_SHARE_READ 0x00000001
|
||||||
|
#define SA_FILE_SHARE_WRITE 0x00000002
|
||||||
|
#define SA_FILE_SHARE_DELETE 0x00000004
|
||||||
|
|
||||||
|
/* CreateDisposition Mask */
|
||||||
|
#define CD_FILE_SUPERSEDE 0x00000000
|
||||||
|
#define CD_FILE_OPEN 0x00000001
|
||||||
|
#define CD_FILE_CREATE 0x00000002
|
||||||
|
#define CD_FILE_OPEN_IF 0x00000003
|
||||||
|
#define CD_FILE_OVERWRITE 0x00000004
|
||||||
|
#define CD_FILE_OVERWRITE_IF 0x00000005
|
||||||
|
|
||||||
|
/* CreateOptions Mask */
|
||||||
|
enum CREATE_OPTIONS
|
||||||
|
{
|
||||||
|
CO_FILE_DIRECTORY_FILE = 0x00000001,
|
||||||
|
CO_FILE_WRITE_THROUGH = 0x00000002,
|
||||||
|
CO_FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020,
|
||||||
|
CO_FILE_DELETE_ON_CLOSE = 0x00001000
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DesiredAccess Mask (section 2.2.13.1.1)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DA_FILE_READ_DATA 0x00000001
|
||||||
|
#define DA_FILE_WRITE_DATA 0x00000002
|
||||||
|
#define DA_FILE_APPEND_DATA 0x00000004
|
||||||
|
#define DA_FILE_READ_EA 0x00000008 /* rd extended attributes */
|
||||||
|
#define DA_FILE_WRITE_EA 0x00000010 /* wr extended attributes */
|
||||||
|
#define DA_FILE_EXECUTE 0x00000020
|
||||||
|
#define DA_FILE_READ_ATTRIBUTES 0x00000080
|
||||||
|
#define DA_FILE_WRITE_ATTRIBUTES 0x00000100
|
||||||
|
#define DA_DELETE 0x00010000
|
||||||
|
#define DA_READ_CONTROL 0x00020000 /* rd security descriptor */
|
||||||
|
#define DA_WRITE_DAC 0x00040000
|
||||||
|
#define DA_WRITE_OWNER 0x00080000
|
||||||
|
#define DA_SYNCHRONIZE 0x00100000
|
||||||
|
#define DA_ACCESS_SYSTEM_SECURITY 0x01000000
|
||||||
|
#define DA_MAXIMUM_ALLOWED 0x02000000
|
||||||
|
#define DA_GENERIC_ALL 0x10000000
|
||||||
|
#define DA_GENERIC_EXECUTE 0x20000000
|
||||||
|
#define DA_GENERIC_WRITE 0x40000000
|
||||||
|
#define DA_GENERIC_READ 0x80000000
|
||||||
|
|
||||||
|
#endif /* MS_SMB2_H */
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -105,6 +105,9 @@ param=96
|
|||||||
[Chansrv]
|
[Chansrv]
|
||||||
; drive redirection, defaults to xrdp_client if not set
|
; drive redirection, defaults to xrdp_client if not set
|
||||||
FuseMountName=thinclient_drives
|
FuseMountName=thinclient_drives
|
||||||
|
; this value allows only the user to acess their own mapped drives.
|
||||||
|
; Make this more permissive (e.g. 022) if required.
|
||||||
|
FileUmask=077
|
||||||
|
|
||||||
[SessionVariables]
|
[SessionVariables]
|
||||||
PULSE_SCRIPT=@sesmansysconfdir@/pulse/default.pa
|
PULSE_SCRIPT=@sesmansysconfdir@/pulse/default.pa
|
||||||
|
Loading…
Reference in New Issue
Block a user