Merge pull request #307 from derfian/drive-redirection-offsets
Fix device redirection offsets
This commit is contained in:
commit
ff875768ed
4
disk.c
4
disk.c
@ -582,7 +582,7 @@ disk_close(RD_NTHANDLE handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static RD_NTSTATUS
|
static RD_NTSTATUS
|
||||||
disk_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
|
disk_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
@ -623,7 +623,7 @@ disk_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32
|
|||||||
}
|
}
|
||||||
|
|
||||||
static RD_NTSTATUS
|
static RD_NTSTATUS
|
||||||
disk_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
|
disk_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
|
@ -119,17 +119,17 @@ parallel_close(RD_NTHANDLE handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static RD_NTSTATUS
|
static RD_NTSTATUS
|
||||||
parallel_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
|
parallel_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result)
|
||||||
{
|
{
|
||||||
UNUSED(offset);
|
UNUSED(offset); /* Offset must always be zero according to MS-RDPESP */
|
||||||
*result = read(handle, data, length);
|
*result = read(handle, data, length);
|
||||||
return RD_STATUS_SUCCESS;
|
return RD_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RD_NTSTATUS
|
static RD_NTSTATUS
|
||||||
parallel_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
|
parallel_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result)
|
||||||
{
|
{
|
||||||
UNUSED(offset);
|
UNUSED(offset); /* Offset must always be zero according to MS-RDPESP */
|
||||||
int rc = RD_STATUS_SUCCESS;
|
int rc = RD_STATUS_SUCCESS;
|
||||||
|
|
||||||
int n = write(handle, data, length);
|
int n = write(handle, data, length);
|
||||||
|
@ -144,9 +144,9 @@ printer_close(RD_NTHANDLE handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static RD_NTSTATUS
|
static RD_NTSTATUS
|
||||||
printer_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
|
printer_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result)
|
||||||
{
|
{
|
||||||
UNUSED(offset);
|
UNUSED(offset); /* Currently unused, MS-RDPEPC reserves for later use */
|
||||||
PRINTER *pprinter_data;
|
PRINTER *pprinter_data;
|
||||||
|
|
||||||
pprinter_data = get_printer_data(handle);
|
pprinter_data = get_printer_data(handle);
|
||||||
|
30
rdpdr.c
30
rdpdr.c
@ -3,7 +3,7 @@
|
|||||||
Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
|
Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
|
||||||
Copyright 2004-2011 Peter Astrand <astrand@cendio.se> for Cendio AB
|
Copyright 2004-2011 Peter Astrand <astrand@cendio.se> for Cendio AB
|
||||||
Copyright 2010-2017 Henrik Andersson <hean01@cendio.se> for Cendio AB
|
Copyright 2010-2017 Henrik Andersson <hean01@cendio.se> for Cendio AB
|
||||||
Copyright 2017 Karl Mikaelsson <derfian@cendio.se> for Cendio AB
|
Copyright 2017-2019 Karl Mikaelsson <derfian@cendio.se> for Cendio AB
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -86,7 +86,8 @@ char *g_rdpdr_clientname = NULL;
|
|||||||
/* if multiple IOs are being done on the same FD */
|
/* if multiple IOs are being done on the same FD */
|
||||||
struct async_iorequest
|
struct async_iorequest
|
||||||
{
|
{
|
||||||
uint32 fd, major, minor, offset, device, id, length, partial_len;
|
uint32 fd, major, minor, device, id, length, partial_len;
|
||||||
|
uint64 offset;
|
||||||
long timeout, /* Total timeout */
|
long timeout, /* Total timeout */
|
||||||
itv_timeout; /* Interval timeout (between serial characters) */
|
itv_timeout; /* Interval timeout (between serial characters) */
|
||||||
uint8 *buffer;
|
uint8 *buffer;
|
||||||
@ -146,7 +147,7 @@ rdpdr_handle_ok(uint32 device, RD_NTHANDLE handle)
|
|||||||
static RD_BOOL
|
static RD_BOOL
|
||||||
add_async_iorequest(uint32 device, uint32 file, uint32 id, uint32 major, uint32 length,
|
add_async_iorequest(uint32 device, uint32 file, uint32 id, uint32 major, uint32 length,
|
||||||
DEVICE_FNS * fns, uint32 total_timeout, uint32 interval_timeout, uint8 * buffer,
|
DEVICE_FNS * fns, uint32 total_timeout, uint32 interval_timeout, uint8 * buffer,
|
||||||
uint32 offset)
|
uint64 offset)
|
||||||
{
|
{
|
||||||
struct async_iorequest *iorq;
|
struct async_iorequest *iorq;
|
||||||
|
|
||||||
@ -395,6 +396,7 @@ rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, ui
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Processes a DR_DEVICE_IOREQUEST (minus the leading header field) */
|
||||||
static void
|
static void
|
||||||
rdpdr_process_irp(STREAM s)
|
rdpdr_process_irp(STREAM s)
|
||||||
{
|
{
|
||||||
@ -409,10 +411,11 @@ rdpdr_process_irp(STREAM s)
|
|||||||
major,
|
major,
|
||||||
minor,
|
minor,
|
||||||
device,
|
device,
|
||||||
offset,
|
|
||||||
bytes_out,
|
bytes_out,
|
||||||
share_mode, disposition, total_timeout, interval_timeout, flags_and_attributes = 0;
|
share_mode, disposition, total_timeout, interval_timeout, flags_and_attributes = 0;
|
||||||
|
|
||||||
|
uint64 offset;
|
||||||
|
|
||||||
char *filename;
|
char *filename;
|
||||||
uint32 filename_len;
|
uint32 filename_len;
|
||||||
|
|
||||||
@ -534,11 +537,12 @@ rdpdr_process_irp(STREAM s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
in_uint32_le(s, length);
|
in_uint32_le(s, length);
|
||||||
in_uint32_le(s, offset);
|
in_uint64_le(s, offset);
|
||||||
|
in_uint8s(s, 20); /* 20 bytes of padding */
|
||||||
|
|
||||||
logger(Protocol, Debug,
|
logger(Protocol, Debug,
|
||||||
"rdpdr_process_irp(), IRP Read length=%d, offset=%d", length,
|
"rdpdr_process_irp(), IRP Read length=%d, offset=%ld",
|
||||||
offset);
|
length, offset);
|
||||||
|
|
||||||
if (!rdpdr_handle_ok(device, file))
|
if (!rdpdr_handle_ok(device, file))
|
||||||
{
|
{
|
||||||
@ -588,10 +592,12 @@ rdpdr_process_irp(STREAM s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
in_uint32_le(s, length);
|
in_uint32_le(s, length);
|
||||||
in_uint32_le(s, offset);
|
in_uint64_le(s, offset);
|
||||||
in_uint8s(s, 0x18);
|
in_uint8s(s, 20); /* 20 bytes of padding before WriteData */
|
||||||
|
|
||||||
logger(Protocol, Debug, "rdpdr_process_irp(), IRP Write length=%d", result);
|
logger(Protocol, Debug,
|
||||||
|
"rdpdr_process_irp(), IRP Write length=%d, offset=%ld",
|
||||||
|
result, offset);
|
||||||
|
|
||||||
if (!rdpdr_handle_ok(device, file))
|
if (!rdpdr_handle_ok(device, file))
|
||||||
{
|
{
|
||||||
@ -875,8 +881,8 @@ rdpdr_process(STREAM s)
|
|||||||
logger(Protocol, Debug, "rdpdr_process()");
|
logger(Protocol, Debug, "rdpdr_process()");
|
||||||
/* hexdump(s->p, s->end - s->p); */
|
/* hexdump(s->p, s->end - s->p); */
|
||||||
|
|
||||||
in_uint16(s, component);
|
in_uint16(s, component); /* RDPDR_HEADER.Component */
|
||||||
in_uint16(s, pakid);
|
in_uint16(s, pakid); /* RDPDR_HEADER.PacketId */
|
||||||
|
|
||||||
if (component == RDPDR_CTYP_CORE)
|
if (component == RDPDR_CTYP_CORE)
|
||||||
{
|
{
|
||||||
|
4
scard.c
4
scard.c
@ -120,7 +120,7 @@ scard_close(RD_NTHANDLE handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static RD_NTSTATUS
|
static RD_NTSTATUS
|
||||||
scard_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
|
scard_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result)
|
||||||
{
|
{
|
||||||
UNUSED(handle);
|
UNUSED(handle);
|
||||||
UNUSED(data);
|
UNUSED(data);
|
||||||
@ -131,7 +131,7 @@ scard_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint3
|
|||||||
}
|
}
|
||||||
|
|
||||||
static RD_NTSTATUS
|
static RD_NTSTATUS
|
||||||
scard_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
|
scard_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result)
|
||||||
{
|
{
|
||||||
UNUSED(handle);
|
UNUSED(handle);
|
||||||
UNUSED(data);
|
UNUSED(data);
|
||||||
|
10
serial.c
10
serial.c
@ -628,9 +628,9 @@ serial_close(RD_NTHANDLE handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static RD_NTSTATUS
|
static RD_NTSTATUS
|
||||||
serial_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
|
serial_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result)
|
||||||
{
|
{
|
||||||
UNUSED(offset);
|
UNUSED(offset); /* Offset must always be zero according to MS-RDPESP */
|
||||||
long timeout;
|
long timeout;
|
||||||
SERIAL_DEVICE *pser_inf;
|
SERIAL_DEVICE *pser_inf;
|
||||||
struct termios *ptermios;
|
struct termios *ptermios;
|
||||||
@ -684,13 +684,11 @@ serial_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint
|
|||||||
}
|
}
|
||||||
|
|
||||||
static RD_NTSTATUS
|
static RD_NTSTATUS
|
||||||
serial_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
|
serial_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset, uint32 * result)
|
||||||
{
|
{
|
||||||
UNUSED(offset);
|
UNUSED(offset); /* Offset must always be zero according to MS-RDPESP */
|
||||||
SERIAL_DEVICE *pser_inf;
|
SERIAL_DEVICE *pser_inf;
|
||||||
|
|
||||||
/* FIXME: offset is not used ? */
|
|
||||||
|
|
||||||
pser_inf = get_serial_info(handle);
|
pser_inf = get_serial_info(handle);
|
||||||
|
|
||||||
*result = write(handle, data, length);
|
*result = write(handle, data, length);
|
||||||
|
17
stream.h
17
stream.h
@ -3,6 +3,7 @@
|
|||||||
Parsing primitives
|
Parsing primitives
|
||||||
Copyright (C) Matthew Chapman 1999-2008
|
Copyright (C) Matthew Chapman 1999-2008
|
||||||
Copyright 2012-2017 Henrik Andersson <hean01@cendio.se> for Cendio AB
|
Copyright 2012-2017 Henrik Andersson <hean01@cendio.se> for Cendio AB
|
||||||
|
Copyright 2019 Karl Mikaelsson <derfian@cendio.se> for Cendio AB
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -62,42 +63,56 @@ size_t in_ansi_string(STREAM s, char *string, size_t len);
|
|||||||
#if defined(L_ENDIAN) && !defined(NEED_ALIGN)
|
#if defined(L_ENDIAN) && !defined(NEED_ALIGN)
|
||||||
#define in_uint16_le(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; }
|
#define in_uint16_le(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; }
|
||||||
#define in_uint32_le(s,v) { v = *(uint32 *)((s)->p); (s)->p += 4; }
|
#define in_uint32_le(s,v) { v = *(uint32 *)((s)->p); (s)->p += 4; }
|
||||||
|
#define in_uint64_le(s,v) { v = *(uint64 *)((s)->p); (s)->p += 8; }
|
||||||
#define out_uint16_le(s,v) { *(uint16 *)((s)->p) = v; (s)->p += 2; }
|
#define out_uint16_le(s,v) { *(uint16 *)((s)->p) = v; (s)->p += 2; }
|
||||||
#define out_uint32_le(s,v) { *(uint32 *)((s)->p) = v; (s)->p += 4; }
|
#define out_uint32_le(s,v) { *(uint32 *)((s)->p) = v; (s)->p += 4; }
|
||||||
|
#define out_uint64_le(s,v) { *(uint64 *)((s)->p) = v; (s)->p += 8; }
|
||||||
#else
|
#else
|
||||||
#define in_uint16_le(s,v) { v = *((s)->p++); v += *((s)->p++) << 8; }
|
#define in_uint16_le(s,v) { v = *((s)->p++); v += *((s)->p++) << 8; }
|
||||||
#define in_uint32_le(s,v) { in_uint16_le(s,v) \
|
#define in_uint32_le(s,v) { in_uint16_le(s,v) \
|
||||||
v += *((s)->p++) << 16; v += *((s)->p++) << 24; }
|
v += *((s)->p++) << 16; v += *((s)->p++) << 24; }
|
||||||
|
#define in_uint64_le(s,v) { in_uint32_le(s,v) \
|
||||||
|
v += *((s)->p++) << 32; v += *((s)->p++) << 40; \
|
||||||
|
v += *((s)->p++) << 48; v += *((s)->p++) << 56; }
|
||||||
#define out_uint16_le(s,v) { *((s)->p++) = (v) & 0xff; *((s)->p++) = ((v) >> 8) & 0xff; }
|
#define out_uint16_le(s,v) { *((s)->p++) = (v) & 0xff; *((s)->p++) = ((v) >> 8) & 0xff; }
|
||||||
#define out_uint32_le(s,v) { out_uint16_le(s, (v) & 0xffff); out_uint16_le(s, ((v) >> 16) & 0xffff); }
|
#define out_uint32_le(s,v) { out_uint16_le(s, (v) & 0xffff); out_uint16_le(s, ((v) >> 16) & 0xffff); }
|
||||||
|
#define out_uint64_le(s,v) { out_uint32_le(s, (v) & 0xffffffff); out_uint32_le(s, ((v) >> 32) & 0xffffffff); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define out_uint64_le(s,v) { out_uint32_le(s, (v) & 0xffffffff); out_uint32_le(s, ((v) >> 32) & 0xffffffff); }
|
|
||||||
|
|
||||||
#if defined(B_ENDIAN) && !defined(NEED_ALIGN)
|
#if defined(B_ENDIAN) && !defined(NEED_ALIGN)
|
||||||
#define in_uint16_be(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; }
|
#define in_uint16_be(s,v) { v = *(uint16 *)((s)->p); (s)->p += 2; }
|
||||||
#define in_uint32_be(s,v) { v = *(uint32 *)((s)->p); (s)->p += 4; }
|
#define in_uint32_be(s,v) { v = *(uint32 *)((s)->p); (s)->p += 4; }
|
||||||
|
#define in_uint64_be(s,v) { v = *(uint64 *)((s)->p); (s)->p += 8; }
|
||||||
#define out_uint16_be(s,v) { *(uint16 *)((s)->p) = v; (s)->p += 2; }
|
#define out_uint16_be(s,v) { *(uint16 *)((s)->p) = v; (s)->p += 2; }
|
||||||
#define out_uint32_be(s,v) { *(uint32 *)((s)->p) = v; (s)->p += 4; }
|
#define out_uint32_be(s,v) { *(uint32 *)((s)->p) = v; (s)->p += 4; }
|
||||||
|
#define out_uint64_be(s,v) { *(uint64 *)((s)->p) = v; (s)->p += 8; }
|
||||||
|
|
||||||
#define B_ENDIAN_PREFERRED
|
#define B_ENDIAN_PREFERRED
|
||||||
#define in_uint16(s,v) in_uint16_be(s,v)
|
#define in_uint16(s,v) in_uint16_be(s,v)
|
||||||
#define in_uint32(s,v) in_uint32_be(s,v)
|
#define in_uint32(s,v) in_uint32_be(s,v)
|
||||||
|
#define in_uint64(s,v) in_uint64_be(s,v)
|
||||||
|
|
||||||
#define out_uint16(s,v) out_uint16_be(s,v)
|
#define out_uint16(s,v) out_uint16_be(s,v)
|
||||||
#define out_uint32(s,v) out_uint32_be(s,v)
|
#define out_uint32(s,v) out_uint32_be(s,v)
|
||||||
|
#define out_uint64(s,v) out_uint64_be(s,v)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define in_uint16_be(s,v) { v = *((s)->p++); next_be(s,v); }
|
#define in_uint16_be(s,v) { v = *((s)->p++); next_be(s,v); }
|
||||||
#define in_uint32_be(s,v) { in_uint16_be(s,v); next_be(s,v); next_be(s,v); }
|
#define in_uint32_be(s,v) { in_uint16_be(s,v); next_be(s,v); next_be(s,v); }
|
||||||
|
#define in_uint64_be(s,v) { in_uint32_be(s,v); next_be(s,v); next_be(s,v); next_be(s,v); next_be(s,v); }
|
||||||
#define out_uint16_be(s,v) { *((s)->p++) = ((v) >> 8) & 0xff; *((s)->p++) = (v) & 0xff; }
|
#define out_uint16_be(s,v) { *((s)->p++) = ((v) >> 8) & 0xff; *((s)->p++) = (v) & 0xff; }
|
||||||
#define out_uint32_be(s,v) { out_uint16_be(s, ((v) >> 16) & 0xffff); out_uint16_be(s, (v) & 0xffff); }
|
#define out_uint32_be(s,v) { out_uint16_be(s, ((v) >> 16) & 0xffff); out_uint16_be(s, (v) & 0xffff); }
|
||||||
|
#define out_uint64_be(s,v) { out_uint32_be(s, ((v) >> 32) & 0xffffffff); out_uint32_be(s, (v) & 0xffffffff); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef B_ENDIAN_PREFERRED
|
#ifndef B_ENDIAN_PREFERRED
|
||||||
#define in_uint16(s,v) in_uint16_le(s,v)
|
#define in_uint16(s,v) in_uint16_le(s,v)
|
||||||
#define in_uint32(s,v) in_uint32_le(s,v)
|
#define in_uint32(s,v) in_uint32_le(s,v)
|
||||||
|
#define in_uint64(s,v) in_uint64_le(s,v)
|
||||||
#define out_uint16(s,v) out_uint16_le(s,v)
|
#define out_uint16(s,v) out_uint16_le(s,v)
|
||||||
#define out_uint32(s,v) out_uint32_le(s,v)
|
#define out_uint32(s,v) out_uint32_le(s,v)
|
||||||
|
#define out_uint64(s,v) out_uint64_le(s,v)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define in_uint8(s,v) v = *((s)->p++);
|
#define in_uint8(s,v) v = *((s)->p++);
|
||||||
|
7
types.h
7
types.h
@ -22,6 +22,7 @@
|
|||||||
#ifndef _TYPES_H
|
#ifndef _TYPES_H
|
||||||
#define _TYPES_H
|
#define _TYPES_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
|
|
||||||
@ -42,6 +43,8 @@ typedef unsigned short uint16;
|
|||||||
typedef signed short sint16;
|
typedef signed short sint16;
|
||||||
typedef unsigned int uint32;
|
typedef unsigned int uint32;
|
||||||
typedef signed int sint32;
|
typedef signed int sint32;
|
||||||
|
typedef uint64_t uint64;
|
||||||
|
typedef int64_t sint64;
|
||||||
|
|
||||||
#define RD_UINT32_MAX (uint32)(-1)
|
#define RD_UINT32_MAX (uint32)(-1)
|
||||||
|
|
||||||
@ -216,9 +219,9 @@ typedef struct _DEVICE_FNS
|
|||||||
uint32 create_disposition, uint32 flags_and_attributes,
|
uint32 create_disposition, uint32 flags_and_attributes,
|
||||||
char *filename, RD_NTHANDLE * handle);
|
char *filename, RD_NTHANDLE * handle);
|
||||||
RD_NTSTATUS(*close) (RD_NTHANDLE handle);
|
RD_NTSTATUS(*close) (RD_NTHANDLE handle);
|
||||||
RD_NTSTATUS(*read) (RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset,
|
RD_NTSTATUS(*read) (RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset,
|
||||||
uint32 * result);
|
uint32 * result);
|
||||||
RD_NTSTATUS(*write) (RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset,
|
RD_NTSTATUS(*write) (RD_NTHANDLE handle, uint8 * data, uint32 length, uint64 offset,
|
||||||
uint32 * result);
|
uint32 * result);
|
||||||
RD_NTSTATUS(*device_control) (RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out);
|
RD_NTSTATUS(*device_control) (RD_NTHANDLE handle, uint32 request, STREAM in, STREAM out);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user