Merge branch 'devel' into v0.9
This commit is contained in:
commit
f2bd1af772
@ -543,6 +543,7 @@
|
||||
#define RDP_DATA_PDU_POINTER 27
|
||||
#define RDP_DATA_PDU_INPUT 28
|
||||
#define RDP_DATA_PDU_SYNCHRONISE 31
|
||||
#define PDUTYPE2_REFRESH_RECT 33
|
||||
#define RDP_DATA_PDU_PLAY_SOUND 34
|
||||
#define RDP_DATA_PDU_LOGON 38
|
||||
#define RDP_DATA_PDU_FONT2 39
|
||||
|
@ -150,6 +150,11 @@ AC_ARG_ENABLE(rfxcodec, AS_HELP_STRING([--disable-rfxcodec],
|
||||
[], [enable_rfxcodec=yes])
|
||||
AM_CONDITIONAL(XRDP_RFXCODEC, [test x$enable_rfxcodec = xyes])
|
||||
|
||||
AC_ARG_ENABLE(rdpsndaudin, AS_HELP_STRING([--enable-rdpsndaudin],
|
||||
[Use rdpsnd audio in (default: no)]),
|
||||
[], [enable_rdpsndaudin=no])
|
||||
AM_CONDITIONAL(XRDP_RDPSNDAUDIN, [test x$enable_rdpsndaudin = xyes])
|
||||
|
||||
# Don't fail without working nasm if rfxcodec is not enabled
|
||||
if test "x$enable_rfxcodec" != xyes; then
|
||||
with_simd=no
|
||||
@ -390,6 +395,7 @@ echo " vsock $enable_vsock"
|
||||
echo " pam $enable_pam"
|
||||
echo " kerberos $enable_kerberos"
|
||||
echo " debug $enable_xrdpdebug"
|
||||
echo " rdpsndaudin $enable_rdpsndaudin"
|
||||
echo ""
|
||||
echo " strict_locations $enable_strict_locations"
|
||||
echo " prefix $prefix"
|
||||
|
@ -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.
|
||||
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"
|
||||
All entries in the \fB[SessionVariables]\fR section are set as
|
||||
environment variables in the user's session.
|
||||
|
@ -30,7 +30,6 @@ default build will install the following
|
||||
startwm.sh
|
||||
xrdp.ini
|
||||
xrdp_keyboard.ini
|
||||
xrdp.sh
|
||||
|
||||
/etc/xrdp/pulse
|
||||
default.pa
|
||||
|
@ -1,6 +1,5 @@
|
||||
EXTRA_DIST = \
|
||||
keymap-names.txt \
|
||||
xrdp.sh \
|
||||
xrdp-sesman.service.in \
|
||||
xrdp.service.in
|
||||
|
||||
@ -61,7 +60,6 @@ if LINUX
|
||||
SUBDIRS += \
|
||||
pam.d \
|
||||
pulse
|
||||
dist_startscript_SCRIPTS = xrdp.sh
|
||||
if HAVE_SYSTEMD
|
||||
systemdsystemunit_DATA = \
|
||||
xrdp-sesman.service \
|
||||
|
@ -8,6 +8,7 @@ outfile="$3"
|
||||
|
||||
service="xrdp-sesman"
|
||||
pamdir="/etc/pam.d"
|
||||
pamdir_suse="/usr/etc/pam.d"
|
||||
|
||||
guess_rules ()
|
||||
{
|
||||
@ -16,6 +17,11 @@ guess_rules ()
|
||||
return
|
||||
fi
|
||||
|
||||
if test -s "$pamdir_suse/common-account"; then
|
||||
rules="suse"
|
||||
return
|
||||
fi
|
||||
|
||||
if test -s "$pamdir/common-account"; then
|
||||
if grep "^@include" "$pamdir/passwd" >/dev/null 2>&1; then
|
||||
rules="debian"
|
||||
|
@ -1,153 +0,0 @@
|
||||
#!/bin/sh
|
||||
# xrdp control script
|
||||
# Written : 1-13-2006 - Mark Balliet - posicat@pobox.com
|
||||
# maintaned by Jay Sorg
|
||||
# chkconfig: 2345 11 89
|
||||
# description: starts xrdp
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: xrdp
|
||||
# Required-Start:
|
||||
# Required-Stop:
|
||||
# Should-Start:
|
||||
# Should-Stop:
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Start and stop xrdp
|
||||
# Description: starts xrdp
|
||||
### END INIT INFO
|
||||
|
||||
SBINDIR=/usr/local/sbin
|
||||
LOG=/dev/null
|
||||
CFGDIR=/etc/xrdp
|
||||
|
||||
if ! test -x $SBINDIR/xrdp
|
||||
then
|
||||
echo "xrdp is not executable"
|
||||
exit 0
|
||||
fi
|
||||
if ! test -x $SBINDIR/xrdp-sesman
|
||||
then
|
||||
echo "xrdp-sesman is not executable"
|
||||
exit 0
|
||||
fi
|
||||
if ! test -x $CFGDIR/startwm.sh
|
||||
then
|
||||
echo "startwm.sh is not executable"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
xrdp_start()
|
||||
{
|
||||
echo -n "Starting: xrdp and sesman . . "
|
||||
$SBINDIR/xrdp >> $LOG
|
||||
$SBINDIR/xrdp-sesman >> $LOG
|
||||
echo "."
|
||||
sleep 1
|
||||
return 0;
|
||||
}
|
||||
|
||||
xrdp_stop()
|
||||
{
|
||||
echo -n "Stopping: xrdp and sesman . . "
|
||||
$SBINDIR/xrdp-sesman --kill >> $LOG
|
||||
$SBINDIR/xrdp --kill >> $LOG
|
||||
echo "."
|
||||
return 0;
|
||||
}
|
||||
|
||||
is_xrdp_running()
|
||||
{
|
||||
ps u --noheading -C xrdp | grep -q -i xrdp
|
||||
if test $? -eq 0
|
||||
then
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
fi
|
||||
}
|
||||
|
||||
is_sesman_running()
|
||||
{
|
||||
ps u --noheading -C xrdp-sesman | grep -q -i xrdp-sesman
|
||||
if test $? -eq 0
|
||||
then
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
fi
|
||||
}
|
||||
|
||||
check_up()
|
||||
{
|
||||
# Cleanup : If sesman isn't running, but the pid exists, erase it.
|
||||
is_sesman_running
|
||||
if test $? -eq 0
|
||||
then
|
||||
if test -e /var/run/xrdp-sesman.pid
|
||||
then
|
||||
rm /var/run/xrdp-sesman.pid
|
||||
fi
|
||||
fi
|
||||
# Cleanup : If xrdp isn't running, but the pid exists, erase it.
|
||||
is_xrdp_running
|
||||
if test $? -eq 0
|
||||
then
|
||||
if test -e /var/run/xrdp.pid
|
||||
then
|
||||
rm /var/run/xrdp.pid
|
||||
fi
|
||||
fi
|
||||
return 0;
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
check_up
|
||||
is_xrdp_running
|
||||
if ! test $? -eq 0
|
||||
then
|
||||
echo "xrdp is already loaded"
|
||||
exit 1
|
||||
fi
|
||||
is_sesman_running
|
||||
if ! test $? -eq 0
|
||||
then
|
||||
echo "sesman is already loaded"
|
||||
exit 1
|
||||
fi
|
||||
xrdp_start
|
||||
;;
|
||||
stop)
|
||||
check_up
|
||||
is_xrdp_running
|
||||
if test $? -eq 0
|
||||
then
|
||||
echo "xrdp is not loaded."
|
||||
fi
|
||||
is_sesman_running
|
||||
if test $? -eq 0
|
||||
then
|
||||
echo "sesman is not loaded."
|
||||
fi
|
||||
xrdp_stop
|
||||
;;
|
||||
force-reload|restart)
|
||||
check_up
|
||||
echo "Restarting xrdp ..."
|
||||
xrdp_stop
|
||||
is_xrdp_running
|
||||
while ! test $? -eq 0
|
||||
do
|
||||
check_up
|
||||
sleep 1
|
||||
is_xrdp_running
|
||||
done
|
||||
xrdp_start
|
||||
;;
|
||||
*)
|
||||
echo "Usage: xrdp.sh {start|stop|restart|force-reload}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit 0
|
@ -1044,9 +1044,12 @@ xrdp_rdp_process_data_sync(struct xrdp_rdp *self)
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 2.2.11.2.1 Refresh Rect PDU Data (TS_REFRESH_RECT_PDU) */
|
||||
static int
|
||||
xrdp_rdp_process_screen_update(struct xrdp_rdp *self, struct stream *s)
|
||||
{
|
||||
int index;
|
||||
int num_rects;
|
||||
int left;
|
||||
int top;
|
||||
int right;
|
||||
@ -1054,19 +1057,34 @@ xrdp_rdp_process_screen_update(struct xrdp_rdp *self, struct stream *s)
|
||||
int cx;
|
||||
int cy;
|
||||
|
||||
in_uint8s(s, 4); /* op */
|
||||
if (!s_check_rem(s, 4))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint8(s, num_rects);
|
||||
in_uint8s(s, 3); /* pad */
|
||||
g_writeln("xrdp_rdp_process_screen_update: num_rects %d", num_rects);
|
||||
for (index = 0; index < num_rects; index++)
|
||||
{
|
||||
if (!s_check_rem(s, 8))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
/* Inclusive Rectangle (TS_RECTANGLE16) */
|
||||
in_uint16_le(s, left);
|
||||
in_uint16_le(s, top);
|
||||
in_uint16_le(s, right);
|
||||
in_uint16_le(s, bottom);
|
||||
g_writeln(" left %d top %d right %d bottom %d",
|
||||
left, top, right, bottom);
|
||||
cx = (right - left) + 1;
|
||||
cy = (bottom - top) + 1;
|
||||
|
||||
if (self->session->callback != 0)
|
||||
{
|
||||
self->session->callback(self->session->id, 0x4444, left, top, cx, cy);
|
||||
self->session->callback(self->session->id, 0x4444,
|
||||
left, top, cx, cy);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1307,7 +1325,7 @@ xrdp_rdp_process_data(struct xrdp_rdp *self, struct stream *s)
|
||||
case RDP_DATA_PDU_SYNCHRONISE: /* 31(0x1f) */
|
||||
xrdp_rdp_process_data_sync(self);
|
||||
break;
|
||||
case 33: /* 33(0x21) ?? Invalidate an area I think */
|
||||
case PDUTYPE2_REFRESH_RECT:
|
||||
xrdp_rdp_process_screen_update(self, s);
|
||||
break;
|
||||
case 35: /* 35(0x23) PDUTYPE2_SUPPRESS_OUTPUT */
|
||||
|
@ -37,6 +37,10 @@ AM_CPPFLAGS += -DXRDP_MP3LAME
|
||||
CHANSRV_EXTRA_LIBS += -lmp3lame
|
||||
endif
|
||||
|
||||
if XRDP_RDPSNDAUDIN
|
||||
AM_CPPFLAGS += -DXRDP_RDPSNDAUDIN
|
||||
endif
|
||||
|
||||
AM_CFLAGS = $(X_CFLAGS)
|
||||
|
||||
sbin_PROGRAMS = \
|
||||
@ -49,6 +53,8 @@ xrdp_chansrv_SOURCES = \
|
||||
chansrv_common.h \
|
||||
chansrv_fuse.c \
|
||||
chansrv_fuse.h \
|
||||
chansrv_xfs.c \
|
||||
chansrv_xfs.h \
|
||||
clipboard.c \
|
||||
clipboard.h \
|
||||
clipboard_common.h \
|
||||
@ -61,6 +67,10 @@ xrdp_chansrv_SOURCES = \
|
||||
irp.c \
|
||||
irp.h \
|
||||
mlog.h \
|
||||
ms-erref.h \
|
||||
ms-fscc.h \
|
||||
ms-rdpefs.h \
|
||||
ms-smb2.h \
|
||||
rail.c \
|
||||
rail.h \
|
||||
smartcard.c \
|
||||
|
@ -407,7 +407,7 @@ process_message_channel_setup(struct stream *s)
|
||||
|
||||
if (g_rdpdr_index >= 0)
|
||||
{
|
||||
dev_redir_init();
|
||||
devredir_init();
|
||||
xfuse_init();
|
||||
}
|
||||
|
||||
@ -458,7 +458,7 @@ process_message_channel_data(struct stream *s)
|
||||
}
|
||||
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)
|
||||
{
|
||||
@ -1412,7 +1412,7 @@ channel_thread_loop(void *in_val)
|
||||
LOGM((LOG_LEVEL_INFO, "channel_thread_loop: g_term_event set"));
|
||||
clipboard_deinit();
|
||||
sound_deinit();
|
||||
dev_redir_deinit();
|
||||
devredir_deinit();
|
||||
rail_deinit();
|
||||
break;
|
||||
}
|
||||
@ -1434,7 +1434,7 @@ channel_thread_loop(void *in_val)
|
||||
"trans_check_wait_objs error resetting"));
|
||||
clipboard_deinit();
|
||||
sound_deinit();
|
||||
dev_redir_deinit();
|
||||
devredir_deinit();
|
||||
rail_deinit();
|
||||
/* 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();
|
||||
xcommon_check_wait_objs();
|
||||
sound_check_wait_objs();
|
||||
dev_redir_check_wait_objs();
|
||||
devredir_check_wait_objs();
|
||||
xfuse_check_wait_objs();
|
||||
timeout = -1;
|
||||
num_objs = 0;
|
||||
@ -1479,7 +1479,7 @@ channel_thread_loop(void *in_val)
|
||||
&timeout);
|
||||
xcommon_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);
|
||||
get_timeout(&timeout);
|
||||
} /* end while (g_obj_wait(objs, num_objs, 0, 0, timeout) == 0) */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -19,55 +19,98 @@
|
||||
#ifndef _CHANSRV_FUSE_H
|
||||
#define _CHANSRV_FUSE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <time.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()
|
||||
*
|
||||
* The string storage the name field points to is only valid
|
||||
* for the duration of the xfuse_devredir_add_file_or_dir()
|
||||
* call
|
||||
*/
|
||||
/* Used to pass file info back to chansrv_fuse from devredir */
|
||||
struct file_attr
|
||||
{
|
||||
const char *name; /* Name of file or directory */
|
||||
tui32 mode; /* File mode. */
|
||||
size_t size; /* Size of file, in bytes. */
|
||||
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. */
|
||||
};
|
||||
|
||||
/* 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_deinit(void);
|
||||
int xfuse_check_wait_objs(void);
|
||||
int xfuse_get_wait_objs(tbus *objs, int *count, int *timeout);
|
||||
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_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_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 */
|
||||
struct xrdp_inode *xfuse_devredir_add_file_or_dir(
|
||||
void *vp,
|
||||
void xfuse_devredir_cb_enum_dir_add_entry(
|
||||
struct state_dirscan *fip,
|
||||
const char *name,
|
||||
const struct file_attr *fattr);
|
||||
void xfuse_devredir_cb_enum_dir_done(struct state_dirscan *fip,
|
||||
enum NTSTATUS IoStatus);
|
||||
|
||||
void xfuse_devredir_cb_lookup_entry(struct state_lookup *fip,
|
||||
enum NTSTATUS IoStatus,
|
||||
const struct file_attr *file_info);
|
||||
void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus);
|
||||
void xfuse_devredir_cb_lookup_entry(void *vp, tui32 IoStatus,
|
||||
struct xrdp_inode *xinode);
|
||||
void xfuse_devredir_cb_open_file(void *vp, tui32 IoStatus, tui32 DeviceId, tui32 FileId);
|
||||
|
||||
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 *vp,
|
||||
tui32 IoStatus,
|
||||
const char *buf,
|
||||
struct state_write *fip,
|
||||
enum NTSTATUS IoStatus,
|
||||
off_t offset,
|
||||
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_rename_file(void *vp, tui32 IoStatus);
|
||||
void xfuse_devredir_cb_file_close(void *vp);
|
||||
|
||||
void xfuse_devredir_cb_rmdir_or_file(struct state_remove *fip,
|
||||
enum NTSTATUS IoStatus);
|
||||
|
||||
void xfuse_devredir_cb_rename_file(struct state_rename *fip,
|
||||
enum NTSTATUS IoStatus);
|
||||
|
||||
void xfuse_devredir_cb_file_close(struct state_close *fip);
|
||||
|
||||
#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 = (char *) 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.
|
||||
*/
|
||||
|
||||
// LK_TODO dev_redir_xxx should become devredir_xxx
|
||||
|
||||
#if !defined(DEVREDIR_H)
|
||||
#define DEVREDIR_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);
|
||||
FUSE_DATA *devredir_fuse_data_dequeue(IRP *irp);
|
||||
int devredir_fuse_data_enqueue(IRP *irp, void *vp);
|
||||
|
||||
int dev_redir_init(void);
|
||||
int dev_redir_deinit(void);
|
||||
|
||||
int dev_redir_data_in(struct stream* s, int chan_id, int chan_flags,
|
||||
int devredir_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);
|
||||
int devredir_get_wait_objs(tbus* objs, int* count, int* timeout);
|
||||
int devredir_check_wait_objs(void);
|
||||
|
||||
/* misc stuff */
|
||||
void devredir_insert_DeviceIoRequest(struct stream *s,
|
||||
tui32 DeviceId,
|
||||
tui32 FileId,
|
||||
tui32 CompletionId,
|
||||
tui32 MajorFunction,
|
||||
tui32 MinorFunction);
|
||||
enum IRP_MJ MajorFunction,
|
||||
enum IRP_MN MinorFunction);
|
||||
|
||||
void devredir_cvt_slash(char *path);
|
||||
void devredir_cvt_to_unicode(char *unicode, const char *path);
|
||||
void devredir_cvt_from_unicode_len(char *path, char *unicode, int len);
|
||||
int dev_redir_string_ends_with(const char *string, char c);
|
||||
|
||||
void devredir_insert_RDPDR_header(struct stream *s, tui16 Component,
|
||||
tui16 PacketId);
|
||||
/* 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_close;
|
||||
|
||||
/* 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,
|
||||
const char *entry);
|
||||
int devredir_get_dir_listing(struct state_dirscan *fusep, tui32 device_id,
|
||||
const char *path);
|
||||
|
||||
int dev_redir_file_open(void *fusep, tui32 device_id, const char *path,
|
||||
int mode, int type, const char *gen_buf);
|
||||
int devredir_lookup_entry(struct state_lookup *fusep, tui32 device_id,
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
int devredir_file_rename(
|
||||
struct state_rename *fusep, tui32 device_id,
|
||||
const char *old_name,
|
||||
const char *new_name);
|
||||
|
||||
int
|
||||
devredir_rmdir_or_file(void *fusep, tui32 device_id, const char *path, int mode);
|
||||
|
||||
/*
|
||||
* 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
|
||||
devredir_rmdir_or_file(struct state_remove *fusep, tui32 device_id,
|
||||
const char *path);
|
||||
|
||||
#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
|
||||
*****************************************************************************/
|
||||
|
||||
IRP * devredir_irp_clone(IRP *irp)
|
||||
IRP * devredir_irp_with_pathname_new(const char *pathname)
|
||||
{
|
||||
IRP *new_irp;
|
||||
IRP *prev;
|
||||
IRP *next;
|
||||
unsigned int len = g_strlen(pathname);
|
||||
IRP * irp = devredir_irp_with_pathnamelen_new(len);
|
||||
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;
|
||||
}
|
||||
|
||||
/* save link pointers */
|
||||
prev = new_irp->prev;
|
||||
next = new_irp->next;
|
||||
irp->pathname = (char *)irp + sizeof(IRP); /* Initialise pathname pointer */
|
||||
|
||||
/* copy all members */
|
||||
g_memcpy(new_irp, irp, sizeof(IRP));
|
||||
/* insert at end of linked list */
|
||||
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 */
|
||||
new_irp->prev = prev;
|
||||
new_irp->next = next;
|
||||
|
||||
return new_irp;
|
||||
log_debug("new IRP=%p", irp);
|
||||
return irp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,11 +29,49 @@
|
||||
#endif
|
||||
#include "chansrv_fuse.h"
|
||||
|
||||
typedef struct fuse_data FUSE_DATA;
|
||||
struct fuse_data
|
||||
/* Opaque data types to us */
|
||||
typedef struct xfuse_info XFUSE_INFO;
|
||||
|
||||
enum irp_lookup_state
|
||||
{
|
||||
void *data_ptr;
|
||||
FUSE_DATA *next;
|
||||
E_LOOKUP_GET_FH = 0,
|
||||
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 */
|
||||
@ -46,15 +84,18 @@ struct irp
|
||||
tui32 DeviceId; /* identifies remote device */
|
||||
tui32 FileId; /* RDP client provided unique number */
|
||||
char completion_type; /* describes I/O type */
|
||||
char pathname[256]; /* absolute pathname */
|
||||
char *pathname; /* absolute pathname
|
||||
* Allocate with
|
||||
* devredir_irp_with_pathname_new() */
|
||||
union
|
||||
{
|
||||
char buf[1024]; /* General character data */
|
||||
struct file_attr fattr; /* Used to assemble file attributes */
|
||||
} gen; /* for general use */
|
||||
int type;
|
||||
FUSE_DATA *fd_head; /* point to first FUSE opaque object */
|
||||
FUSE_DATA *fd_tail; /* point to last FUSE opaque object */
|
||||
struct irp_lookup lookup; /* Used by lookup */
|
||||
struct irp_setattr setattr; /* Used by setattr */
|
||||
struct irp_write write; /* Used by write */
|
||||
struct irp_create create; /* Used by create */
|
||||
struct irp_rename rename; /* Use by rename */
|
||||
} gen; /* Additional state data for some ops */
|
||||
void *fuse_info; /* Fuse info pointer for FUSE calls */
|
||||
IRP *next; /* point to next IRP */
|
||||
IRP *prev; /* point to previous IRP */
|
||||
int scard_index; /* used to smart card to locate dev */
|
||||
@ -65,7 +106,13 @@ struct irp
|
||||
};
|
||||
|
||||
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);
|
||||
IRP * devredir_irp_find(tui32 completion_id);
|
||||
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 */
|
||||
|
||||
|
||||
|
@ -871,7 +871,7 @@ scard_make_new_ioctl(IRP *irp, tui32 ioctl)
|
||||
irp->FileId,
|
||||
irp->CompletionId,
|
||||
IRP_MJ_DEVICE_CONTROL,
|
||||
0);
|
||||
IRP_MN_NONE);
|
||||
|
||||
xstream_wr_u32_le(s, 2048); /* OutputBufferLength */
|
||||
s_push_layer(s, iso_hdr, 4); /* InputBufferLength - insert later */
|
||||
|
@ -1438,6 +1438,7 @@ sound_check_wait_objs(void)
|
||||
static int
|
||||
sound_send_server_input_formats(void)
|
||||
{
|
||||
#if defined(XRDP_RDPSNDAUDIN)
|
||||
struct stream *s;
|
||||
int bytes;
|
||||
int index;
|
||||
@ -1492,6 +1493,10 @@ sound_send_server_input_formats(void)
|
||||
bytes = (int)(s->end - s->data);
|
||||
send_channel_data(g_rdpsnd_chan_id, s->data, bytes);
|
||||
free_stream(s);
|
||||
#else
|
||||
/* avoid warning */
|
||||
(void)g_wave_inp_formats;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -51,16 +51,6 @@ config_read(struct config_sesman *cfg)
|
||||
|
||||
if (-1 == fd)
|
||||
{
|
||||
//if (g_cfg->log.fd >= 0)
|
||||
//{
|
||||
/* logging is already active */
|
||||
log_message(LOG_LEVEL_ALWAYS, "error opening %s in \
|
||||
config_read", cfg_file);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
g_printf("error opening %s in config_read", cfg_file);
|
||||
//}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -212,15 +202,6 @@ config_read_globals(int file, struct config_sesman *cf, struct list *param_n,
|
||||
g_free(buf);
|
||||
}
|
||||
|
||||
log_message(LOG_LEVEL_TRACE, "config loaded in %s at %s:%d", __func__, __FILE__, __LINE__);
|
||||
log_message(LOG_LEVEL_TRACE, " listen_address = %s", cf->listen_address);
|
||||
log_message(LOG_LEVEL_TRACE, " listen_port = %s", cf->listen_port);
|
||||
log_message(LOG_LEVEL_TRACE, " enable_user_wm = %d", cf->enable_user_wm);
|
||||
log_message(LOG_LEVEL_TRACE, " default_wm = %s", cf->default_wm);
|
||||
log_message(LOG_LEVEL_TRACE, " user_wm = %s", cf->user_wm);
|
||||
log_message(LOG_LEVEL_TRACE, " reconnect_sh = %s", cf->reconnect_sh);
|
||||
log_message(LOG_LEVEL_TRACE, " auth_file_path = %s", cf->auth_file_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -342,12 +342,33 @@ main(int argc, char **argv)
|
||||
g_exit(1);
|
||||
}
|
||||
|
||||
log_message(LOG_LEVEL_TRACE, "config loaded in %s at %s:%d", __func__, __FILE__, __LINE__);
|
||||
log_message(LOG_LEVEL_TRACE, " listen_address = %s", g_cfg->listen_address);
|
||||
log_message(LOG_LEVEL_TRACE, " listen_port = %s", g_cfg->listen_port);
|
||||
log_message(LOG_LEVEL_TRACE, " enable_user_wm = %d", g_cfg->enable_user_wm);
|
||||
log_message(LOG_LEVEL_TRACE, " default_wm = %s", g_cfg->default_wm);
|
||||
log_message(LOG_LEVEL_TRACE, " user_wm = %s", g_cfg->user_wm);
|
||||
log_message(LOG_LEVEL_TRACE, " reconnect_sh = %s", g_cfg->reconnect_sh);
|
||||
log_message(LOG_LEVEL_TRACE, " auth_file_path = %s", g_cfg->auth_file_path);
|
||||
|
||||
if (daemon)
|
||||
{
|
||||
/* not to spit on the console, shut up stdout/stderr before anything's logged */
|
||||
g_file_close(0);
|
||||
g_file_close(1);
|
||||
g_file_close(2);
|
||||
|
||||
if (g_file_open("/dev/null") < 0)
|
||||
{
|
||||
}
|
||||
|
||||
if (g_file_open("/dev/null") < 0)
|
||||
{
|
||||
}
|
||||
|
||||
if (g_file_open("/dev/null") < 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/* libscp initialization */
|
||||
@ -372,17 +393,6 @@ main(int argc, char **argv)
|
||||
g_exit(0);
|
||||
}
|
||||
|
||||
if (g_file_open("/dev/null") < 0)
|
||||
{
|
||||
}
|
||||
|
||||
if (g_file_open("/dev/null") < 0)
|
||||
{
|
||||
}
|
||||
|
||||
if (g_file_open("/dev/null") < 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/* signal handling */
|
||||
|
@ -105,6 +105,9 @@ param=96
|
||||
[Chansrv]
|
||||
; drive redirection, defaults to xrdp_client if not set
|
||||
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]
|
||||
PULSE_SCRIPT=@sesmansysconfdir@/pulse/default.pa
|
||||
|
@ -163,6 +163,13 @@ xrdp_child(int sig)
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void
|
||||
xrdp_hang_up(int sig)
|
||||
{
|
||||
log_message(LOG_LEVEL_INFO, "caught SIGHUP, noop...");
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* called in child just after fork */
|
||||
int
|
||||
@ -647,6 +654,7 @@ main(int argc, char **argv)
|
||||
g_signal_pipe(pipe_sig); /* SIGPIPE */
|
||||
g_signal_terminate(xrdp_shutdown); /* SIGTERM */
|
||||
g_signal_child_stop(xrdp_child); /* SIGCHLD */
|
||||
g_signal_hang_up(xrdp_hang_up); /* SIGHUP */
|
||||
g_sync_mutex = tc_mutex_create();
|
||||
g_sync1_mutex = tc_mutex_create();
|
||||
pid = g_getpid();
|
||||
|
@ -356,6 +356,53 @@ xrdp_listen_parse_integer(char *strout, int strout_max,
|
||||
return count;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
xrdp_listen_parse_vsock(char *strout, int strout_max,
|
||||
const char *strin, int strin_max)
|
||||
{
|
||||
int count;
|
||||
int in;
|
||||
int strin_index;
|
||||
int strout_index;
|
||||
|
||||
strin_index = 0;
|
||||
strout_index = 0;
|
||||
in = 0;
|
||||
count = 0;
|
||||
while ((strin_index < strin_max) && (strout_index < strout_max))
|
||||
{
|
||||
if (in)
|
||||
{
|
||||
if ((strin[strin_index] >= '0') && (strin[strin_index] <= '9'))
|
||||
{
|
||||
strout[strout_index++] = strin[strin_index++];
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((strin[strin_index] >= '0') && (strin[strin_index] <= '9')) ||
|
||||
(strin[strin_index] == '-'))
|
||||
{
|
||||
in = 1;
|
||||
strout[strout_index++] = strin[strin_index++];
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
strin_index++;
|
||||
count++;
|
||||
}
|
||||
strout[strout_index] = 0;
|
||||
return count;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
xrdp_listen_parse_ipv4(char *strout, int strout_max,
|
||||
@ -559,10 +606,10 @@ xrdp_listen_pp(struct xrdp_listen *self, int *index,
|
||||
{
|
||||
str += 8;
|
||||
lindex += 8;
|
||||
bytes = xrdp_listen_parse_integer(address, 128, str, str_end - str);
|
||||
bytes = xrdp_listen_parse_vsock(address, 128, str, str_end - str);
|
||||
str += bytes;
|
||||
lindex += bytes;
|
||||
bytes = xrdp_listen_parse_integer(port, 128, str, str_end - str);
|
||||
bytes = xrdp_listen_parse_vsock(port, 128, str, str_end - str);
|
||||
str += bytes;
|
||||
lindex += bytes;
|
||||
*mode = TRANS_MODE_VSOCK;
|
||||
|
@ -1430,6 +1430,14 @@ xrdp_mm_connect_chansrv(struct xrdp_mm *self, const char *ip, const char *port)
|
||||
|
||||
self->usechansrv = 1;
|
||||
|
||||
if (self->wm->client_info->channels_allowed == 0)
|
||||
{
|
||||
log_message(LOG_LEVEL_DEBUG, "%s: "
|
||||
"skip connecting to chansrv because all channels are disabled",
|
||||
__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* connect channel redir */
|
||||
if ((g_strcmp(ip, "127.0.0.1") == 0) || (ip[0] == 0))
|
||||
{
|
||||
|
26
xup/xup.c
26
xup/xup.c
@ -1111,6 +1111,19 @@ process_server_paint_rect_shmem(struct mod *amod, struct stream *s)
|
||||
amod->screen_shmem_id_mapped = 1;
|
||||
}
|
||||
}
|
||||
else if (amod->screen_shmem_id != shmem_id)
|
||||
{
|
||||
amod->screen_shmem_id = shmem_id;
|
||||
g_shmdt(amod->screen_shmem_pixels);
|
||||
amod->screen_shmem_pixels = (char *) g_shmat(amod->screen_shmem_id);
|
||||
if (amod->screen_shmem_pixels == (void*)-1)
|
||||
{
|
||||
/* failed */
|
||||
amod->screen_shmem_id = 0;
|
||||
amod->screen_shmem_pixels = 0;
|
||||
amod->screen_shmem_id_mapped = 0;
|
||||
}
|
||||
}
|
||||
if (amod->screen_shmem_pixels != 0)
|
||||
{
|
||||
bmpdata = amod->screen_shmem_pixels + shmem_offset;
|
||||
@ -1249,6 +1262,19 @@ process_server_paint_rect_shmem_ex(struct mod *amod, struct stream *s)
|
||||
amod->screen_shmem_id_mapped = 1;
|
||||
}
|
||||
}
|
||||
else if (amod->screen_shmem_id != shmem_id)
|
||||
{
|
||||
amod->screen_shmem_id = shmem_id;
|
||||
g_shmdt(amod->screen_shmem_pixels);
|
||||
amod->screen_shmem_pixels = (char *) g_shmat(amod->screen_shmem_id);
|
||||
if (amod->screen_shmem_pixels == (void*)-1)
|
||||
{
|
||||
/* failed */
|
||||
amod->screen_shmem_id = 0;
|
||||
amod->screen_shmem_pixels = 0;
|
||||
amod->screen_shmem_id_mapped = 0;
|
||||
}
|
||||
}
|
||||
if (amod->screen_shmem_pixels != 0)
|
||||
{
|
||||
bmpdata = amod->screen_shmem_pixels + shmem_offset;
|
||||
|
Loading…
Reference in New Issue
Block a user