commit
52f1e6b27a
@ -7,6 +7,8 @@
|
|||||||
* Copyright 2012 Gerald Richter
|
* Copyright 2012 Gerald Richter
|
||||||
* Copyright 2015 Thincast Technologies GmbH
|
* Copyright 2015 Thincast Technologies GmbH
|
||||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||||
|
* Copyright 2016 Inuvika Inc.
|
||||||
|
* Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -59,6 +61,8 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#pragma comment(lib, "Shlwapi.lib")
|
#pragma comment(lib, "Shlwapi.lib")
|
||||||
#include <Shlwapi.h>
|
#include <Shlwapi.h>
|
||||||
|
#else
|
||||||
|
#include <winpr/path.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "drive_file.h"
|
#include "drive_file.h"
|
||||||
@ -507,18 +511,23 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
|
|||||||
{
|
{
|
||||||
char* s = NULL;
|
char* s = NULL;
|
||||||
mode_t m;
|
mode_t m;
|
||||||
UINT64 size;
|
INT64 size;
|
||||||
int status;
|
int status;
|
||||||
char* fullpath;
|
char* fullpath;
|
||||||
struct STAT st;
|
ULARGE_INTEGER liCreationTime;
|
||||||
#if defined(__linux__) && !defined(ANDROID) || defined(sun)
|
ULARGE_INTEGER liLastAccessTime;
|
||||||
struct timespec tv[2];
|
ULARGE_INTEGER liLastWriteTime;
|
||||||
#else
|
ULARGE_INTEGER liChangeTime;
|
||||||
struct timeval tv[2];
|
FILETIME ftCreationTime;
|
||||||
#endif
|
FILETIME ftLastAccessTime;
|
||||||
UINT64 LastWriteTime;
|
FILETIME ftLastWriteTime;
|
||||||
|
FILETIME* pftCreationTime = NULL;
|
||||||
|
FILETIME* pftLastAccessTime = NULL;
|
||||||
|
FILETIME* pftLastWriteTime = NULL;
|
||||||
UINT32 FileAttributes;
|
UINT32 FileAttributes;
|
||||||
UINT32 FileNameLength;
|
UINT32 FileNameLength;
|
||||||
|
HANDLE hFd;
|
||||||
|
LARGE_INTEGER liSize;
|
||||||
|
|
||||||
m = 0;
|
m = 0;
|
||||||
|
|
||||||
@ -526,55 +535,73 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN
|
|||||||
{
|
{
|
||||||
case FileBasicInformation:
|
case FileBasicInformation:
|
||||||
/* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
|
/* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
|
||||||
Stream_Seek_UINT64(input); /* CreationTime */
|
Stream_Read_UINT64(input, liCreationTime.QuadPart);
|
||||||
Stream_Seek_UINT64(input); /* LastAccessTime */
|
Stream_Read_UINT64(input, liLastAccessTime.QuadPart);
|
||||||
Stream_Read_UINT64(input, LastWriteTime);
|
Stream_Read_UINT64(input, liLastWriteTime.QuadPart);
|
||||||
Stream_Seek_UINT64(input); /* ChangeTime */
|
Stream_Read_UINT64(input, liChangeTime.QuadPart);
|
||||||
Stream_Read_UINT32(input, FileAttributes);
|
Stream_Read_UINT32(input, FileAttributes);
|
||||||
|
|
||||||
if (FSTAT(file->fd, &st) != 0)
|
if (!PathFileExistsA(file->fullpath))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
hFd = CreateFileA(file->fullpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
tv[0].tv_sec = st.st_atime;
|
if (hFd == INVALID_HANDLE_VALUE)
|
||||||
tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime);
|
|
||||||
#ifndef WIN32
|
|
||||||
/* TODO on win32 */
|
|
||||||
#ifdef ANDROID
|
|
||||||
tv[0].tv_usec = 0;
|
|
||||||
tv[1].tv_usec = 0;
|
|
||||||
utimes(file->fullpath, tv);
|
|
||||||
#elif defined (__linux__) || defined (sun)
|
|
||||||
tv[0].tv_nsec = 0;
|
|
||||||
tv[1].tv_nsec = 0;
|
|
||||||
futimens(file->fd, tv);
|
|
||||||
#else
|
|
||||||
tv[0].tv_usec = 0;
|
|
||||||
tv[1].tv_usec = 0;
|
|
||||||
futimes(file->fd, tv);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (FileAttributes > 0)
|
|
||||||
{
|
{
|
||||||
m = st.st_mode;
|
WLog_ERR(TAG, "Unable to set file time %s to %d", file->fullpath);
|
||||||
if ((FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
|
return FALSE;
|
||||||
m |= S_IWUSR;
|
|
||||||
else
|
|
||||||
m &= ~S_IWUSR;
|
|
||||||
if (m != st.st_mode)
|
|
||||||
fchmod(file->fd, st.st_mode);
|
|
||||||
}
|
}
|
||||||
#endif
|
if (liCreationTime.QuadPart != 0)
|
||||||
|
{
|
||||||
|
ftCreationTime.dwHighDateTime = liCreationTime.HighPart;
|
||||||
|
ftCreationTime.dwLowDateTime = liCreationTime.LowPart;
|
||||||
|
pftCreationTime = &ftCreationTime;
|
||||||
|
}
|
||||||
|
if (liLastAccessTime.QuadPart != 0)
|
||||||
|
{
|
||||||
|
ftLastAccessTime.dwHighDateTime = liLastAccessTime.HighPart;
|
||||||
|
ftLastAccessTime.dwLowDateTime = liLastAccessTime.LowPart;
|
||||||
|
pftLastAccessTime = &ftLastAccessTime;
|
||||||
|
}
|
||||||
|
if (liLastWriteTime.QuadPart != 0)
|
||||||
|
{
|
||||||
|
ftLastWriteTime.dwHighDateTime = liLastWriteTime.HighPart;
|
||||||
|
ftLastWriteTime.dwLowDateTime = liLastWriteTime.LowPart;
|
||||||
|
pftLastWriteTime = &ftLastWriteTime;
|
||||||
|
}
|
||||||
|
if (liChangeTime.QuadPart != 0 && liChangeTime.QuadPart > liLastWriteTime.QuadPart)
|
||||||
|
{
|
||||||
|
ftLastWriteTime.dwHighDateTime = liChangeTime.HighPart;
|
||||||
|
ftLastWriteTime.dwLowDateTime = liChangeTime.LowPart;
|
||||||
|
pftLastWriteTime = &ftLastWriteTime;
|
||||||
|
}
|
||||||
|
if (!SetFileTime(hFd, pftCreationTime, pftLastAccessTime, pftLastWriteTime))
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "Unable to set file time %s to %d", file->fullpath);
|
||||||
|
CloseHandle(hFd);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
CloseHandle(hFd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FileEndOfFileInformation:
|
case FileEndOfFileInformation:
|
||||||
/* http://msdn.microsoft.com/en-us/library/cc232067.aspx */
|
/* http://msdn.microsoft.com/en-us/library/cc232067.aspx */
|
||||||
case FileAllocationInformation:
|
case FileAllocationInformation:
|
||||||
/* http://msdn.microsoft.com/en-us/library/cc232076.aspx */
|
/* http://msdn.microsoft.com/en-us/library/cc232076.aspx */
|
||||||
Stream_Read_UINT64(input, size);
|
Stream_Read_INT64(input, size);
|
||||||
#ifndef _WIN32
|
|
||||||
if (ftruncate(file->fd, size) != 0)
|
hFd = CreateFileA(file->fullpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (hFd == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "Unable to truncate %s to %d", file->fullpath, size);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
#endif
|
}
|
||||||
|
liSize.QuadPart = size;
|
||||||
|
if (SetFilePointerEx(hFd, liSize, NULL, FILE_BEGIN) == 0)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "Unable to truncate %s to %d", file->fullpath, size);
|
||||||
|
CloseHandle(hFd);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
CloseHandle(hFd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FileDispositionInformation:
|
case FileDispositionInformation:
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
* Copyright 2012 Gerald Richter
|
* Copyright 2012 Gerald Richter
|
||||||
* Copyright 2015 Thincast Technologies GmbH
|
* Copyright 2015 Thincast Technologies GmbH
|
||||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||||
|
* Copyright 2016 Inuvika Inc.
|
||||||
|
* Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -84,8 +86,6 @@ typedef UINT32 mode_t;
|
|||||||
|
|
||||||
#define FILE_TIME_SYSTEM_TO_RDP(_t) \
|
#define FILE_TIME_SYSTEM_TO_RDP(_t) \
|
||||||
(((UINT64)(_t) + EPOCH_DIFF) * 10000000LL)
|
(((UINT64)(_t) + EPOCH_DIFF) * 10000000LL)
|
||||||
#define FILE_TIME_RDP_TO_SYSTEM(_t) \
|
|
||||||
(((_t) == 0LL || (_t) == (UINT64)(-1LL)) ? 0 : (time_t)((_t) / 10000000LL - EPOCH_DIFF))
|
|
||||||
|
|
||||||
#define FILE_ATTR_SYSTEM_TO_RDP(_f, _st) ( \
|
#define FILE_ATTR_SYSTEM_TO_RDP(_f, _st) ( \
|
||||||
(S_ISDIR(_st.st_mode) ? FILE_ATTRIBUTE_DIRECTORY : 0) | \
|
(S_ISDIR(_st.st_mode) ? FILE_ATTRIBUTE_DIRECTORY : 0) | \
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
# FreeRDP cmake build script
|
# FreeRDP cmake build script
|
||||||
#
|
#
|
||||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||||
|
# Copyright 2016 Inuvika Inc.
|
||||||
|
# Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@ -32,6 +34,10 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE
|
|||||||
|
|
||||||
|
|
||||||
target_link_libraries(${MODULE_NAME} winpr freerdp)
|
target_link_libraries(${MODULE_NAME} winpr freerdp)
|
||||||
|
if(APPLE AND (NOT IOS))
|
||||||
|
find_library(CORESERVICES_LIBRARY CoreServices)
|
||||||
|
target_link_libraries(${MODULE_NAME} ${CORESERVICES_LIBRARY})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")
|
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")
|
||||||
|
@ -46,6 +46,15 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __MACOSX__
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
@ -103,6 +112,45 @@ static UINT rdpdr_send_device_list_remove_request(rdpdrPlugin* rdpdr, UINT32 cou
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
BOOL check_path(char* path)
|
||||||
|
{
|
||||||
|
UINT type = GetDriveTypeA(path);
|
||||||
|
if (!(type == DRIVE_REMOVABLE || type == DRIVE_CDROM || type == DRIVE_REMOTE))
|
||||||
|
return FALSE;
|
||||||
|
return GetVolumeInformationA(path, NULL, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void first_hotplug(rdpdrPlugin *rdpdr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char drive_path[5] = { 'c', ':', '\\', '\0' };
|
||||||
|
|
||||||
|
DWORD unitmask = GetLogicalDrives();
|
||||||
|
|
||||||
|
for (i = 0; i < 26; i++)
|
||||||
|
{
|
||||||
|
if (unitmask & 0x01)
|
||||||
|
{
|
||||||
|
RDPDR_DRIVE* drive;
|
||||||
|
|
||||||
|
drive_path[0] = 'A' + i;
|
||||||
|
drive_path[1] = ':';
|
||||||
|
|
||||||
|
if (check_path(drive_path))
|
||||||
|
{
|
||||||
|
drive = (RDPDR_DRIVE*)malloc(sizeof(RDPDR_DRIVE));
|
||||||
|
ZeroMemory(drive, sizeof(RDPDR_DRIVE));
|
||||||
|
drive->Type = RDPDR_DTYP_FILESYSTEM;
|
||||||
|
drive->Path = _strdup(drive_path);
|
||||||
|
drive_path[1] = '\0';
|
||||||
|
drive->Name = _strdup(drive_path);
|
||||||
|
devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive, rdpdr->rdpcontext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unitmask = unitmask >> 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
rdpdrPlugin *rdpdr;
|
rdpdrPlugin *rdpdr;
|
||||||
@ -131,17 +179,21 @@ LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
|||||||
RDPDR_DRIVE* drive;
|
RDPDR_DRIVE* drive;
|
||||||
|
|
||||||
drive_path[0] = 'A' + i;
|
drive_path[0] = 'A' + i;
|
||||||
|
drive_path[1] = ':';
|
||||||
|
|
||||||
drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE));
|
if (check_path(drive_path))
|
||||||
ZeroMemory(drive, sizeof(RDPDR_DRIVE));
|
{
|
||||||
|
drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE));
|
||||||
|
ZeroMemory(drive, sizeof(RDPDR_DRIVE));
|
||||||
|
|
||||||
drive->Type = RDPDR_DTYP_FILESYSTEM;
|
drive->Type = RDPDR_DTYP_FILESYSTEM;
|
||||||
|
|
||||||
drive->Path = _strdup(drive_path);
|
drive->Path = _strdup(drive_path);
|
||||||
drive_path[1] = '\0';
|
drive_path[1] = '\0';
|
||||||
drive->Name = _strdup(drive_path);
|
drive->Name = _strdup(drive_path);
|
||||||
devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive, rdpdr->rdpcontext);
|
devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive, rdpdr->rdpcontext);
|
||||||
rdpdr_send_device_list_announce_request(rdpdr, TRUE);
|
rdpdr_send_device_list_announce_request(rdpdr, TRUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
unitmask = unitmask >> 1;
|
unitmask = unitmask >> 1;
|
||||||
}
|
}
|
||||||
@ -275,6 +327,242 @@ static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif __MACOSX__
|
||||||
|
|
||||||
|
#define MAX_USB_DEVICES 100
|
||||||
|
|
||||||
|
typedef struct _hotplug_dev
|
||||||
|
{
|
||||||
|
char* path;
|
||||||
|
BOOL to_add;
|
||||||
|
} hotplug_dev;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function description
|
||||||
|
*
|
||||||
|
* @return 0 on success, otherwise a Win32 error code
|
||||||
|
*/
|
||||||
|
static UINT handle_hotplug(rdpdrPlugin* rdpdr)
|
||||||
|
{
|
||||||
|
struct dirent *pDirent;
|
||||||
|
DIR *pDir;
|
||||||
|
char fullpath[PATH_MAX];
|
||||||
|
char* szdir = (char*)"/Volumes";
|
||||||
|
struct stat buf;
|
||||||
|
hotplug_dev dev_array[MAX_USB_DEVICES];
|
||||||
|
int count;
|
||||||
|
DEVICE_DRIVE_EXT *device_ext;
|
||||||
|
ULONG_PTR *keys;
|
||||||
|
int i, j;
|
||||||
|
int size = 0;
|
||||||
|
UINT error;
|
||||||
|
UINT32 ids[1];
|
||||||
|
|
||||||
|
pDir = opendir (szdir);
|
||||||
|
if (pDir == NULL)
|
||||||
|
{
|
||||||
|
printf ("Cannot open directory\n");
|
||||||
|
return ERROR_OPEN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((pDirent = readdir(pDir)) != NULL)
|
||||||
|
{
|
||||||
|
if (pDirent->d_name[0] != '.')
|
||||||
|
{
|
||||||
|
sprintf(fullpath, "%s/%s", szdir, pDirent->d_name);
|
||||||
|
lstat(fullpath, &buf);
|
||||||
|
if(S_ISDIR(buf.st_mode))
|
||||||
|
{
|
||||||
|
dev_array[size].path = _strdup(fullpath);
|
||||||
|
if (!dev_array[size].path)
|
||||||
|
{
|
||||||
|
closedir (pDir);
|
||||||
|
error = CHANNEL_RC_NO_MEMORY;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
dev_array[size++].to_add = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir (pDir);
|
||||||
|
|
||||||
|
/* delete removed devices */
|
||||||
|
count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys);
|
||||||
|
|
||||||
|
for (j = 0; j < count; j++)
|
||||||
|
{
|
||||||
|
BOOL dev_found = FALSE;
|
||||||
|
|
||||||
|
device_ext = (DEVICE_DRIVE_EXT *)ListDictionary_GetItemValue(rdpdr->devman->devices, (void *)keys[j]);
|
||||||
|
if (!device_ext)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (device_ext->path == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* not plugable device */
|
||||||
|
if (strstr(device_ext->path, "/Volumes/") == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
if (strstr(device_ext->path, dev_array[i].path) != NULL)
|
||||||
|
{
|
||||||
|
dev_found = TRUE;
|
||||||
|
dev_array[i].to_add = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dev_found)
|
||||||
|
{
|
||||||
|
devman_unregister_device(rdpdr->devman, (void *)keys[j]);
|
||||||
|
ids[0] = keys[j];
|
||||||
|
if ((error = rdpdr_send_device_list_remove_request(rdpdr, 1, ids)))
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "rdpdr_send_device_list_remove_request failed with error %lu!", error);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add new devices */
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
RDPDR_DRIVE* drive;
|
||||||
|
|
||||||
|
if (dev_array[i].to_add)
|
||||||
|
{
|
||||||
|
char* name;
|
||||||
|
|
||||||
|
drive = (RDPDR_DRIVE*) calloc(1, sizeof(RDPDR_DRIVE));
|
||||||
|
if (!drive)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "calloc failed!");
|
||||||
|
error = CHANNEL_RC_NO_MEMORY;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
drive->Type = RDPDR_DTYP_FILESYSTEM;
|
||||||
|
|
||||||
|
drive->Path = dev_array[i].path;
|
||||||
|
dev_array[i].path = NULL;
|
||||||
|
|
||||||
|
name = strrchr(drive->Path, '/') + 1;
|
||||||
|
drive->Name = _strdup(name);
|
||||||
|
if (!drive->Name)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "_strdup failed!");
|
||||||
|
free(drive->Path);
|
||||||
|
free(drive);
|
||||||
|
error = CHANNEL_RC_NO_MEMORY;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if ((error = devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE *)drive, rdpdr->rdpcontext)))
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "devman_load_device_service failed!");
|
||||||
|
free(drive->Path);
|
||||||
|
free(drive->Name);
|
||||||
|
free(drive);
|
||||||
|
error = CHANNEL_RC_NO_MEMORY;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
free (dev_array[i].path);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void drive_hotplug_fsevent_callback(ConstFSEventStreamRef streamRef, void *clientCallBackInfo,
|
||||||
|
size_t numEvents, void *eventPaths, const FSEventStreamEventFlags eventFlags[],
|
||||||
|
const FSEventStreamEventId eventIds[])
|
||||||
|
{
|
||||||
|
rdpdrPlugin* rdpdr;
|
||||||
|
int i;
|
||||||
|
UINT error;
|
||||||
|
char **paths = (char**)eventPaths;
|
||||||
|
|
||||||
|
rdpdr = (rdpdrPlugin*) clientCallBackInfo;
|
||||||
|
|
||||||
|
for (i=0; i<numEvents; i++)
|
||||||
|
{
|
||||||
|
if (strcmp(paths[i], "/Volumes/") == 0)
|
||||||
|
{
|
||||||
|
if ((error = handle_hotplug(rdpdr)))
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "handle_hotplug failed with error %lu!", error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
rdpdr_send_device_list_announce_request(rdpdr, TRUE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void first_hotplug(rdpdrPlugin *rdpdr)
|
||||||
|
{
|
||||||
|
UINT error;
|
||||||
|
if ((error = handle_hotplug(rdpdr)))
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "handle_hotplug failed with error %lu!", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* drive_hotplug_thread_func(void* arg)
|
||||||
|
{
|
||||||
|
rdpdrPlugin* rdpdr;
|
||||||
|
FSEventStreamRef fsev;
|
||||||
|
UINT error;
|
||||||
|
|
||||||
|
rdpdr = (rdpdrPlugin*) arg;
|
||||||
|
CFStringRef path = CFSTR("/Volumes/");
|
||||||
|
CFArrayRef pathsToWatch = CFArrayCreate(kCFAllocatorMalloc, (const void**)&path, 1, NULL);
|
||||||
|
FSEventStreamContext ctx;
|
||||||
|
ZeroMemory(&ctx, sizeof(ctx));
|
||||||
|
ctx.info = arg;
|
||||||
|
fsev = FSEventStreamCreate(kCFAllocatorMalloc, drive_hotplug_fsevent_callback, &ctx, pathsToWatch, kFSEventStreamEventIdSinceNow, 1, kFSEventStreamCreateFlagNone);
|
||||||
|
|
||||||
|
rdpdr->runLoop = CFRunLoopGetCurrent();
|
||||||
|
FSEventStreamScheduleWithRunLoop(fsev, rdpdr->runLoop, kCFRunLoopDefaultMode);
|
||||||
|
FSEventStreamStart(fsev);
|
||||||
|
CFRunLoopRun();
|
||||||
|
FSEventStreamStop(fsev);
|
||||||
|
FSEventStreamRelease(fsev);
|
||||||
|
|
||||||
|
ExitThread(CHANNEL_RC_OK);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function description
|
||||||
|
*
|
||||||
|
* @return 0 on success, otherwise a Win32 error code
|
||||||
|
*/
|
||||||
|
static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr)
|
||||||
|
{
|
||||||
|
UINT error;
|
||||||
|
if (rdpdr->hotplugThread)
|
||||||
|
{
|
||||||
|
CFRunLoopStop(rdpdr->runLoop);
|
||||||
|
|
||||||
|
if (WaitForSingleObject(rdpdr->hotplugThread, INFINITE) == WAIT_FAILED)
|
||||||
|
{
|
||||||
|
error = GetLastError();
|
||||||
|
WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
rdpdr->hotplugThread = NULL;
|
||||||
|
}
|
||||||
|
return CHANNEL_RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define MAX_USB_DEVICES 100
|
#define MAX_USB_DEVICES 100
|
||||||
@ -506,7 +794,16 @@ cleanup:
|
|||||||
for (i = 0; i < size; i++)
|
for (i = 0; i < size; i++)
|
||||||
free (dev_array[i].path);
|
free (dev_array[i].path);
|
||||||
|
|
||||||
return error ? error : rdpdr_send_device_list_announce_request(rdpdr, TRUE);
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void first_hotplug(rdpdrPlugin *rdpdr)
|
||||||
|
{
|
||||||
|
UINT error;
|
||||||
|
if ((error = handle_hotplug(rdpdr)))
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "handle_hotplug failed with error %lu!", error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* drive_hotplug_thread_func(void* arg)
|
static void* drive_hotplug_thread_func(void* arg)
|
||||||
@ -516,7 +813,7 @@ static void* drive_hotplug_thread_func(void* arg)
|
|||||||
fd_set rfds;
|
fd_set rfds;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
int rv;
|
int rv;
|
||||||
UINT error;
|
UINT error = 0;
|
||||||
DWORD status;
|
DWORD status;
|
||||||
|
|
||||||
rdpdr = (rdpdrPlugin*) arg;
|
rdpdr = (rdpdrPlugin*) arg;
|
||||||
@ -542,12 +839,6 @@ static void* drive_hotplug_thread_func(void* arg)
|
|||||||
tv.tv_sec = 1;
|
tv.tv_sec = 1;
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
if ((error = handle_hotplug(rdpdr)))
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "handle_hotplug failed with error %lu!", error);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((rv = select(mfd+1, NULL, NULL, &rfds, &tv)) >= 0)
|
while ((rv = select(mfd+1, NULL, NULL, &rfds, &tv)) >= 0)
|
||||||
{
|
{
|
||||||
status = WaitForSingleObject(rdpdr->stopEvent, 0);
|
status = WaitForSingleObject(rdpdr->stopEvent, 0);
|
||||||
@ -568,6 +859,8 @@ static void* drive_hotplug_thread_func(void* arg)
|
|||||||
WLog_ERR(TAG, "handle_hotplug failed with error %lu!", error);
|
WLog_ERR(TAG, "handle_hotplug failed with error %lu!", error);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
rdpdr_send_device_list_announce_request(rdpdr, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
FD_ZERO(&rfds);
|
FD_ZERO(&rfds);
|
||||||
@ -643,6 +936,7 @@ static UINT rdpdr_process_connect(rdpdrPlugin* rdpdr)
|
|||||||
|
|
||||||
if (device->Name && (strcmp(device->Name, "*") == 0))
|
if (device->Name && (strcmp(device->Name, "*") == 0))
|
||||||
{
|
{
|
||||||
|
first_hotplug(rdpdr);
|
||||||
if (!(rdpdr->hotplugThread = CreateThread(NULL, 0,
|
if (!(rdpdr->hotplugThread = CreateThread(NULL, 0,
|
||||||
(LPTHREAD_START_ROUTINE) drive_hotplug_thread_func, rdpdr, 0, NULL)))
|
(LPTHREAD_START_ROUTINE) drive_hotplug_thread_func, rdpdr, 0, NULL)))
|
||||||
{
|
{
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
* Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
* Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||||
* Copyright 2015 Thincast Technologies GmbH
|
* Copyright 2015 Thincast Technologies GmbH
|
||||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||||
|
* Copyright 2016 Inuvika Inc.
|
||||||
|
* Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -36,6 +38,10 @@
|
|||||||
#include <freerdp/channels/rdpdr.h>
|
#include <freerdp/channels/rdpdr.h>
|
||||||
#include <freerdp/channels/log.h>
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
|
#ifdef __MACOSX__
|
||||||
|
#include <CoreServices/CoreServices.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TAG CHANNELS_TAG("rdpdr.client")
|
#define TAG CHANNELS_TAG("rdpdr.client")
|
||||||
|
|
||||||
typedef struct rdpdr_plugin rdpdrPlugin;
|
typedef struct rdpdr_plugin rdpdrPlugin;
|
||||||
@ -64,6 +70,8 @@ struct rdpdr_plugin
|
|||||||
HANDLE hotplugThread;
|
HANDLE hotplugThread;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HWND hotplug_wnd;
|
HWND hotplug_wnd;
|
||||||
|
#elif __MACOSX__
|
||||||
|
CFRunLoopRef runLoop;
|
||||||
#else
|
#else
|
||||||
HANDLE stopEvent;
|
HANDLE stopEvent;
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user