mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 17:44:45 +00:00
Some preliminary work on the SM to make it manage environment servers.
svn path=/trunk/; revision=13449
This commit is contained in:
parent
e8a6256e32
commit
9e799af696
7 changed files with 379 additions and 105 deletions
116
reactos/subsys/smss/client.c
Normal file
116
reactos/subsys/smss/client.c
Normal file
|
@ -0,0 +1,116 @@
|
|||
/* $Id: smss.c 12852 2005-01-06 13:58:04Z mf $
|
||||
*
|
||||
* client.c - Session Manager client Management
|
||||
*
|
||||
* ReactOS Operating System
|
||||
*
|
||||
* --------------------------------------------------------------------
|
||||
*
|
||||
* This software is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; see the file COPYING.LIB. If not, write
|
||||
* to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
|
||||
* MA 02139, USA.
|
||||
*
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
#define NTOS_MODE_USER
|
||||
#include <ntos.h>
|
||||
#include <sm/api.h>
|
||||
#include "smss.h"
|
||||
|
||||
/* Private ADT */
|
||||
|
||||
typedef struct _SM_CLIENT_DATA
|
||||
{
|
||||
USHORT SubsystemId;
|
||||
BOOL Initialized;
|
||||
HANDLE ServerProcess;
|
||||
HANDLE ApiPort;
|
||||
HANDLE SbApiPort;
|
||||
struct _SM_CLIENT_DATA * Next;
|
||||
|
||||
} SM_CLIENT_DATA, *PSM_CLIENT_DATA;
|
||||
|
||||
|
||||
struct _SM_CLIENT_DIRECTORY
|
||||
{
|
||||
RTL_CRITICAL_SECTION Lock;
|
||||
ULONG Count;
|
||||
PSM_CLIENT_DATA Client;
|
||||
|
||||
} SmpClientDirectory;
|
||||
|
||||
/**********************************************************************
|
||||
* SmpInitializeClientManagement/0
|
||||
*/
|
||||
VOID STDCALL
|
||||
SmpInitializeClientManagement (VOID)
|
||||
{
|
||||
RtlInitializeCriticalSection(& SmpClientDirectory.Lock);
|
||||
SmpClientDirectory.Count = 0;
|
||||
SmpClientDirectory.Client = NULL;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* SmpCreateClient/1
|
||||
*/
|
||||
NTSTATUS STDCALL
|
||||
SmpCreateClient(SM_PORT_MESSAGE Request)
|
||||
{
|
||||
PSM_CLIENT_DATA pClient = NULL;
|
||||
|
||||
/*
|
||||
* Allocate the storage for client data
|
||||
*/
|
||||
pClient = RtlAllocateHeap (SmpHeap,
|
||||
HEAP_ZERO_MEMORY,
|
||||
sizeof (SM_CLIENT_DATA));
|
||||
if (NULL == pClient) return STATUS_NO_MEMORY;
|
||||
/*
|
||||
* Initialize the client data
|
||||
*/
|
||||
// TODO
|
||||
/*
|
||||
* Insert the new descriptor in the
|
||||
* client directory.
|
||||
*/
|
||||
RtlEnterCriticalSection (& SmpClientDirectory.Lock);
|
||||
if (NULL == SmpClientDirectory.Client)
|
||||
{
|
||||
SmpClientDirectory.Client = pClient;
|
||||
} else {
|
||||
PSM_CLIENT_DATA pCD = NULL;
|
||||
|
||||
for (pCD=SmpClientDirectory.Client;
|
||||
(NULL != pCD->Next);
|
||||
pCD = pCD->Next);
|
||||
pCD->Next = pClient;
|
||||
}
|
||||
++ SmpClientDirectory.Count;
|
||||
RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* SmpDestroyClient/1
|
||||
*/
|
||||
NTSTATUS STDCALL
|
||||
SmpDestroyClient (ULONG SubsystemId)
|
||||
{
|
||||
RtlEnterCriticalSection (& SmpClientDirectory.Lock);
|
||||
/* TODO */
|
||||
RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* EOF */
|
92
reactos/subsys/smss/debug.c
Normal file
92
reactos/subsys/smss/debug.c
Normal file
|
@ -0,0 +1,92 @@
|
|||
/* $Id: smss.c 12852 2005-01-06 13:58:04Z mf $
|
||||
*
|
||||
* client.c - Session Manager client Management
|
||||
*
|
||||
* ReactOS Operating System
|
||||
*
|
||||
* --------------------------------------------------------------------
|
||||
*
|
||||
* This software is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; see the file COPYING.LIB. If not, write
|
||||
* to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
|
||||
* MA 02139, USA.
|
||||
*
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
#define NTOS_MODE_USER
|
||||
#include <ntos.h>
|
||||
#include <rosrtl/string.h>
|
||||
#include <sm/api.h>
|
||||
#include "smss.h"
|
||||
|
||||
/* GLOBALS ***********************************************************/
|
||||
|
||||
HANDLE DbgSsApiPort = INVALID_HANDLE_VALUE;
|
||||
HANDLE DbgUiApiPort = INVALID_HANDLE_VALUE;
|
||||
|
||||
/* FUNCTIONS *********************************************************/
|
||||
|
||||
NTSTATUS STDCALL
|
||||
SmpInitializeDbgSs (VOID)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
UNICODE_STRING UnicodeString;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
|
||||
|
||||
/* Create the \DbgSsApiPort object (LPC) */
|
||||
RtlRosInitUnicodeStringFromLiteral(&UnicodeString,
|
||||
L"\\DbgSsApiPort");
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&UnicodeString,
|
||||
PORT_ALL_ACCESS,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
Status = NtCreatePort(&DbgSsApiPort,
|
||||
&ObjectAttributes,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return(Status);
|
||||
}
|
||||
DbgPrint("SMSS: %s: \\DbgSsApiPort created\n",__FUNCTION__);
|
||||
|
||||
/* Create the \DbgUiApiPort object (LPC) */
|
||||
RtlRosInitUnicodeStringFromLiteral(&UnicodeString,
|
||||
L"\\DbgUiApiPort");
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&UnicodeString,
|
||||
PORT_ALL_ACCESS,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
Status = NtCreatePort(&DbgUiApiPort,
|
||||
&ObjectAttributes,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return(Status);
|
||||
}
|
||||
DbgPrint("SMSS: %s: \\DbgUiApiPort created\n",__FUNCTION__);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
#include <ntdll/rtl.h>
|
||||
#include <ntdll/ldr.h>
|
||||
#include <rosrtl/string.h>
|
||||
|
||||
#include <sm/api.h>
|
||||
#include "smss.h"
|
||||
|
||||
#define NDEBUG
|
||||
|
@ -41,8 +41,7 @@
|
|||
|
||||
/* GLOBALS ******************************************************************/
|
||||
|
||||
HANDLE DbgSsApiPort = INVALID_HANDLE_VALUE;
|
||||
HANDLE DbgUiApiPort = INVALID_HANDLE_VALUE;
|
||||
HANDLE SmpHeap = NULL;
|
||||
|
||||
PWSTR SmSystemEnvironment = NULL;
|
||||
|
||||
|
@ -824,6 +823,20 @@ InitSessionManager(HANDLE Children[])
|
|||
HANDLE CsrssInitEvent;
|
||||
WCHAR UnicodeBuffer[MAX_PATH];
|
||||
|
||||
/* Create our own heap */
|
||||
SmpHeap = RtlCreateHeap(HEAP_GROWABLE,
|
||||
NULL,
|
||||
65536,
|
||||
65536,
|
||||
NULL,
|
||||
NULL);
|
||||
if (NULL == SmpHeap)
|
||||
{
|
||||
DbgPrint("SMSS: %s: failed to create private heap, aborting\n",__FUNCTION__);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
|
||||
/* Create object directories */
|
||||
Status = SmCreateObjectDirectories();
|
||||
if (!NT_SUCCESS(Status))
|
||||
|
@ -832,8 +845,8 @@ InitSessionManager(HANDLE Children[])
|
|||
return(Status);
|
||||
}
|
||||
|
||||
/* Create the SmApiPort object (LPC) */
|
||||
Status = SmCreateApiPort();
|
||||
/* Create the \SmApiPort object (LPC) */
|
||||
Status = SmpCreateApiPort();
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("SM: Failed to create SmApiPort (Status %lx)\n", Status);
|
||||
|
@ -916,6 +929,13 @@ InitSessionManager(HANDLE Children[])
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize SM client management:
|
||||
* this MUST be done before any
|
||||
* subsystem server is run.
|
||||
*/
|
||||
SmpInitializeClientManagement();
|
||||
|
||||
DPRINT("SM: loading subsystems\n");
|
||||
|
||||
/* Load the subsystems */
|
||||
|
@ -1043,50 +1063,15 @@ InitSessionManager(HANDLE Children[])
|
|||
}
|
||||
Children[CHILD_WINLOGON] = ProcessInfo.ProcessHandle;
|
||||
|
||||
/* Create the \DbgSsApiPort object (LPC) */
|
||||
RtlRosInitUnicodeStringFromLiteral(&UnicodeString,
|
||||
L"\\DbgSsApiPort");
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&UnicodeString,
|
||||
PORT_ALL_ACCESS,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
Status = NtCreatePort(&DbgSsApiPort,
|
||||
&ObjectAttributes,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
|
||||
/* Initialize the DBGSS */
|
||||
Status = SmpInitializeDbgSs();
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DisplayString(L"SM: DbgSs initialization failed!\n");
|
||||
NtTerminateProcess(Children[CHILD_WINLOGON],0);
|
||||
NtTerminateProcess(Children[CHILD_CSRSS],0);
|
||||
return(Status);
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
DisplayString(L"SM: DbgSsApiPort created...\n");
|
||||
#endif
|
||||
|
||||
/* Create the \DbgUiApiPort object (LPC) */
|
||||
RtlRosInitUnicodeStringFromLiteral(&UnicodeString,
|
||||
L"\\DbgUiApiPort");
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&UnicodeString,
|
||||
PORT_ALL_ACCESS,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
Status = NtCreatePort(&DbgUiApiPort,
|
||||
&ObjectAttributes,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return(Status);
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
DisplayString (L"SM: DbgUiApiPort created...\n");
|
||||
#endif
|
||||
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ TARGET_CFLAGS = -D__NTAPP__
|
|||
# require os code to explicitly request A/W version of structs/functions
|
||||
TARGET_CFLAGS += -D_DISABLE_TIDENTS -Wall -Werror
|
||||
|
||||
TARGET_OBJECTS = $(TARGET_NAME).o init.o smapi.o
|
||||
TARGET_OBJECTS = $(TARGET_NAME).o init.o smapi.o client.o debug.o
|
||||
|
||||
include $(PATH_TO_TOP)/rules.mak
|
||||
|
||||
|
|
|
@ -5,10 +5,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <ddk/ntddk.h>
|
||||
#include <ntdll/rtl.h>
|
||||
/*#include <ddk/ntddk.h>
|
||||
#include <ntdll/rtl.h>*/
|
||||
#define NTOS_MODE_USER
|
||||
#include <ntos.h>
|
||||
#include <sm/api.h>
|
||||
#include <rosrtl/string.h>
|
||||
|
||||
#include "smss.h"
|
||||
|
||||
#define NDEBUG
|
||||
|
@ -17,62 +19,123 @@
|
|||
|
||||
static HANDLE SmApiPort = INVALID_HANDLE_VALUE;
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
/* SM API **********************************************************************/
|
||||
|
||||
#define SMAPI(n) \
|
||||
NTSTATUS FASTCALL n (PSM_PORT_MESSAGE Request)
|
||||
|
||||
VOID STDCALL
|
||||
SmApiThread(HANDLE Port)
|
||||
SMAPI(SmInvalid)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG Unknown;
|
||||
PLPC_MESSAGE Reply = NULL;
|
||||
LPC_MESSAGE Message;
|
||||
|
||||
#ifndef NDEBUG
|
||||
DisplayString(L"SmApiThread: running\n");
|
||||
#endif
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
DisplayString(L"SmApiThread: waiting for message\n");
|
||||
#endif
|
||||
|
||||
Status = NtReplyWaitReceivePort(Port,
|
||||
&Unknown,
|
||||
Reply,
|
||||
&Message);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
DisplayString(L"SmApiThread: message received\n");
|
||||
#endif
|
||||
|
||||
if (Message.MessageType == LPC_CONNECTION_REQUEST)
|
||||
{
|
||||
// SmHandleConnectionRequest (Port, &Message);
|
||||
Reply = NULL;
|
||||
}
|
||||
else if (Message.MessageType == LPC_DEBUG_EVENT)
|
||||
{
|
||||
// DbgSsHandleKmApiMsg (&Message, 0);
|
||||
Reply = NULL;
|
||||
}
|
||||
else if (Message.MessageType == LPC_PORT_CLOSED)
|
||||
{
|
||||
Reply = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reply = &Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
DbgPrint("SMSS: %s called\n",__FUNCTION__);
|
||||
Request->Status = STATUS_NOT_IMPLEMENTED;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SMAPI(SmCompSes)
|
||||
{
|
||||
DbgPrint("SMSS: %s called\n",__FUNCTION__);
|
||||
Request->Status = STATUS_NOT_IMPLEMENTED;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
SMAPI(SmExecPgm)
|
||||
{
|
||||
DbgPrint("SMSS: %s called\n",__FUNCTION__);
|
||||
Request->Status = STATUS_NOT_IMPLEMENTED;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* SM API Table */
|
||||
typedef NTSTATUS (FASTCALL * SM_PORT_API)(PSM_PORT_MESSAGE);
|
||||
|
||||
SM_PORT_API SmApi [] =
|
||||
{
|
||||
SmInvalid, /* unused */
|
||||
SmCompSes,
|
||||
SmInvalid, /* obsolete */
|
||||
SmInvalid, /* unknown */
|
||||
SmExecPgm
|
||||
};
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* NAME
|
||||
* SmpHandleConnectionRequest/2
|
||||
*
|
||||
* REMARKS
|
||||
* Quoted in http://support.microsoft.com/kb/258060/EN-US/
|
||||
*/
|
||||
NTSTATUS STDCALL
|
||||
SmpHandleConnectionRequest (HANDLE Port, PSM_PORT_MESSAGE Request)
|
||||
{
|
||||
DbgPrint("SMSS: %s called\n",__FUNCTION__);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* NAME
|
||||
* SmpApiThread/1
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Entry point for the listener thread of LPC port "\SmApiPort".
|
||||
*/
|
||||
VOID STDCALL
|
||||
SmpApiThread(HANDLE Port)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
ULONG Unknown = 0;
|
||||
PLPC_MESSAGE Reply = NULL;
|
||||
SM_PORT_MESSAGE Request = {{0}};
|
||||
|
||||
DbgPrint("SMSS: %s running.\n",__FUNCTION__);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
DbgPrint("SMSS: %s: waiting for message\n",__FUNCTION__);
|
||||
|
||||
Status = NtReplyWaitReceivePort(Port,
|
||||
& Unknown,
|
||||
Reply,
|
||||
(PLPC_MESSAGE) & Request);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
DbgPrint("SMSS: %s: message received\n",__FUNCTION__);
|
||||
|
||||
switch (Request.Header.MessageType)
|
||||
{
|
||||
case LPC_CONNECTION_REQUEST:
|
||||
SmpHandleConnectionRequest (Port, &Request);
|
||||
Reply = NULL;
|
||||
break;
|
||||
case LPC_DEBUG_EVENT:
|
||||
// DbgSsHandleKmApiMsg (&Request, 0);
|
||||
Reply = NULL;
|
||||
break;
|
||||
case LPC_PORT_CLOSED:
|
||||
Reply = NULL;
|
||||
break;
|
||||
default:
|
||||
if ((Request.ApiIndex) &&
|
||||
(Request.ApiIndex < (sizeof SmApi / sizeof SmApi[0])))
|
||||
{
|
||||
Status = SmApi[Request.ApiIndex](&Request);
|
||||
Reply = (PLPC_MESSAGE) & Request;
|
||||
} else {
|
||||
Request.Status = STATUS_NOT_IMPLEMENTED;
|
||||
Reply = (PLPC_MESSAGE) & Request;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* NAME
|
||||
* SmpCreateApiPort/0
|
||||
*
|
||||
* DECRIPTION
|
||||
*/
|
||||
NTSTATUS
|
||||
SmCreateApiPort(VOID)
|
||||
SmpCreateApiPort(VOID)
|
||||
{
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
UNICODE_STRING UnicodeString;
|
||||
|
@ -103,7 +166,7 @@ SmCreateApiPort(VOID)
|
|||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
(PTHREAD_START_ROUTINE)SmApiThread,
|
||||
(PTHREAD_START_ROUTINE)SmpApiThread,
|
||||
(PVOID)SmApiPort,
|
||||
NULL,
|
||||
NULL);
|
||||
|
@ -114,7 +177,7 @@ SmCreateApiPort(VOID)
|
|||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
(PTHREAD_START_ROUTINE)SmApiThread,
|
||||
(PTHREAD_START_ROUTINE)SmpApiThread,
|
||||
(PVOID)SmApiPort,
|
||||
NULL,
|
||||
NULL);
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
* Compiled successfully with egcs 1.1.2
|
||||
*/
|
||||
#include <ddk/ntddk.h>
|
||||
|
||||
#include <sm/api.h>
|
||||
#include "smss.h"
|
||||
|
||||
#define NDEBUG
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#ifndef _SMSS_H_INCLUDED_
|
||||
#define _SMSS_H_INCLUDED_
|
||||
|
||||
|
@ -15,6 +14,9 @@
|
|||
/* FUNCTIONS ***********/
|
||||
|
||||
/* init.c */
|
||||
|
||||
extern HANDLE SmpHeap;
|
||||
|
||||
NTSTATUS
|
||||
InitSessionManager(HANDLE Children[]);
|
||||
|
||||
|
@ -23,16 +25,32 @@ InitSessionManager(HANDLE Children[]);
|
|||
void DisplayString (LPCWSTR lpwString);
|
||||
void PrintString (char* fmt,...);
|
||||
|
||||
|
||||
/* smapi.c */
|
||||
|
||||
NTSTATUS
|
||||
SmCreateApiPort(VOID);
|
||||
SmpCreateApiPort(VOID);
|
||||
|
||||
VOID STDCALL
|
||||
SmApiThread(HANDLE Port);
|
||||
SmpApiThread(HANDLE Port);
|
||||
|
||||
/* client.c */
|
||||
|
||||
VOID STDCALL
|
||||
SmpInitializeClientManagement(VOID);
|
||||
|
||||
NTSTATUS STDCALL
|
||||
SmpCreateClient(SM_PORT_MESSAGE);
|
||||
|
||||
NTSTATUS STDCALL
|
||||
SmpDestroyClient(ULONG);
|
||||
|
||||
/* debug.c */
|
||||
|
||||
extern HANDLE DbgSsApiPort;
|
||||
extern HANDLE DbgUiApiPort;
|
||||
|
||||
NTSTATUS STDCALL
|
||||
SmpInitializeDbgSs(VOID);
|
||||
|
||||
#endif /* _SMSS_H_INCLUDED_ */
|
||||
|
||||
|
|
Loading…
Reference in a new issue