Merge branch 'master' of github.com:FreeRDP/FreeRDP-1.0
This commit is contained in:
commit
42c17867b6
@ -23,7 +23,6 @@
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/utils/memory.h>
|
||||
#include <freerdp/utils/stream.h>
|
||||
#include <freerdp/utils/thread.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
#include <freerdp/utils/wait_obj.h>
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
# limitations under the License.
|
||||
|
||||
set(DISK_SRCS
|
||||
disk_file.c
|
||||
disk_file.h
|
||||
disk_main.c
|
||||
)
|
||||
|
||||
|
576
channels/rdpdr/disk/disk_file.c
Normal file
576
channels/rdpdr/disk/disk_file.c
Normal file
@ -0,0 +1,576 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol client.
|
||||
* File System Virtual Channel
|
||||
*
|
||||
* Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <freerdp/utils/memory.h>
|
||||
#include <freerdp/utils/stream.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "rdpdr_constants.h"
|
||||
#include "rdpdr_types.h"
|
||||
#include "disk_file.h"
|
||||
|
||||
#define FILE_TIME_SYSTEM_TO_RDP(_t) \
|
||||
(((uint64)(_t) + 11644473600LL) * 10000000LL)
|
||||
#define FILE_TIME_RDP_TO_SYSTEM(_t) \
|
||||
(((_t) == 0LL || (_t) == (uint64)(-1LL)) ? 0 : (time_t)((_t) / 10000000LL - 11644473600LL))
|
||||
|
||||
#define FILE_ATTR_SYSTEM_TO_RDP(_f, _st) ( \
|
||||
(S_ISDIR(_st.st_mode) ? FILE_ATTRIBUTE_DIRECTORY : 0) | \
|
||||
(_f->filename[0] == '.' ? FILE_ATTRIBUTE_HIDDEN : 0) | \
|
||||
(_f->delete_pending ? FILE_ATTRIBUTE_TEMPORARY : 0) | \
|
||||
(st.st_mode & S_IWUSR ? 0 : FILE_ATTRIBUTE_READONLY))
|
||||
|
||||
static void disk_file_fix_path(char* path)
|
||||
{
|
||||
int len;
|
||||
int i;
|
||||
|
||||
len = strlen(path);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (path[i] == '\\')
|
||||
path[i] = '/';
|
||||
}
|
||||
if (len > 0 && path[len - 1] == '/')
|
||||
path[len - 1] = '\0';
|
||||
}
|
||||
|
||||
static char* disk_file_combine_fullpath(const char* base_path, const char* path)
|
||||
{
|
||||
char* fullpath;
|
||||
|
||||
fullpath = xmalloc(strlen(base_path) + strlen(path) + 1);
|
||||
strcpy(fullpath, base_path);
|
||||
strcat(fullpath, path);
|
||||
disk_file_fix_path(fullpath);
|
||||
|
||||
return fullpath;
|
||||
}
|
||||
|
||||
static boolean disk_file_remove_dir(const char* path)
|
||||
{
|
||||
DIR* dir;
|
||||
struct dirent* pdirent;
|
||||
struct stat st;
|
||||
char* p;
|
||||
boolean ret;
|
||||
|
||||
dir = opendir(path);
|
||||
if (dir == NULL)
|
||||
return False;
|
||||
|
||||
pdirent = readdir(dir);
|
||||
while (pdirent)
|
||||
{
|
||||
if (strcmp(pdirent->d_name, ".") == 0 || strcmp(pdirent->d_name, "..") == 0)
|
||||
{
|
||||
pdirent = readdir(dir);
|
||||
continue;
|
||||
}
|
||||
|
||||
p = xmalloc(strlen(path) + strlen(pdirent->d_name) + 2);
|
||||
sprintf(p, "%s/%s", path, pdirent->d_name);
|
||||
if (stat(p, &st) != 0)
|
||||
{
|
||||
DEBUG_WARN("stat %s failed.", p);
|
||||
ret = False;
|
||||
}
|
||||
else if (S_ISDIR(st.st_mode))
|
||||
{
|
||||
ret = disk_file_remove_dir(p);
|
||||
}
|
||||
else if (unlink(p) < 0)
|
||||
{
|
||||
DEBUG_WARN("unlink %s failed.", p);
|
||||
ret = False;
|
||||
}
|
||||
else
|
||||
ret = True;
|
||||
xfree(p);
|
||||
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
pdirent = readdir(dir);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
if (ret)
|
||||
{
|
||||
if (rmdir(path) < 0)
|
||||
{
|
||||
DEBUG_WARN("rmdir %s failed.", path);
|
||||
ret = False;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void disk_file_set_fullpath(DISK_FILE* file, char* fullpath)
|
||||
{
|
||||
xfree(file->fullpath);
|
||||
file->fullpath = fullpath;
|
||||
file->filename = strrchr(file->fullpath, '/');
|
||||
if (file->filename == NULL)
|
||||
file->filename = file->fullpath;
|
||||
else
|
||||
file->filename += 1;
|
||||
}
|
||||
|
||||
static boolean disk_file_init(DISK_FILE* file, uint32 DesiredAccess, uint32 CreateDisposition, uint32 CreateOptions)
|
||||
{
|
||||
const static int mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
|
||||
struct stat st;
|
||||
boolean exists;
|
||||
int oflag = 0;
|
||||
|
||||
if (stat(file->fullpath, &st) == 0)
|
||||
{
|
||||
file->is_dir = (S_ISDIR(st.st_mode) ? True : False);
|
||||
exists = True;
|
||||
}
|
||||
else
|
||||
{
|
||||
file->is_dir = ((CreateOptions & FILE_DIRECTORY_FILE) ? True : False);
|
||||
if (file->is_dir)
|
||||
{
|
||||
if (mkdir(file->fullpath, mode) != 0)
|
||||
return False;
|
||||
}
|
||||
exists = False;
|
||||
}
|
||||
if (file->is_dir)
|
||||
{
|
||||
file->dir = opendir(file->fullpath);
|
||||
if (file->dir == NULL)
|
||||
return False;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (CreateDisposition)
|
||||
{
|
||||
case FILE_SUPERSEDE:
|
||||
oflag = O_TRUNC | O_CREAT;
|
||||
break;
|
||||
case FILE_OPEN:
|
||||
break;
|
||||
case FILE_CREATE:
|
||||
oflag = O_CREAT | O_EXCL;
|
||||
break;
|
||||
case FILE_OPEN_IF:
|
||||
oflag = O_CREAT;
|
||||
break;
|
||||
case FILE_OVERWRITE:
|
||||
oflag = O_TRUNC;
|
||||
break;
|
||||
case FILE_OVERWRITE_IF:
|
||||
oflag = O_TRUNC | O_CREAT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!exists && (CreateOptions & FILE_DELETE_ON_CLOSE))
|
||||
file->delete_pending = True;
|
||||
|
||||
if ((DesiredAccess & GENERIC_ALL)
|
||||
|| (DesiredAccess & GENERIC_WRITE)
|
||||
|| (DesiredAccess & FILE_WRITE_DATA)
|
||||
|| (DesiredAccess & FILE_APPEND_DATA))
|
||||
{
|
||||
oflag |= O_RDWR;
|
||||
}
|
||||
else
|
||||
{
|
||||
oflag |= O_RDONLY;
|
||||
}
|
||||
|
||||
file->fd = open(file->fullpath, oflag, mode);
|
||||
if (file->fd == -1)
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
DISK_FILE* disk_file_new(const char* base_path, const char* path, uint32 id,
|
||||
uint32 DesiredAccess, uint32 CreateDisposition, uint32 CreateOptions)
|
||||
{
|
||||
DISK_FILE* file;
|
||||
|
||||
file = xnew(DISK_FILE);
|
||||
file->id = id;
|
||||
disk_file_set_fullpath(file, disk_file_combine_fullpath(base_path, path));
|
||||
file->fd = -1;
|
||||
|
||||
if (!disk_file_init(file, DesiredAccess, CreateDisposition, CreateOptions))
|
||||
{
|
||||
disk_file_free(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
void disk_file_free(DISK_FILE* file)
|
||||
{
|
||||
if (file->fd != -1)
|
||||
close(file->fd);
|
||||
if (file->dir != NULL)
|
||||
closedir(file->dir);
|
||||
|
||||
if (file->delete_pending)
|
||||
{
|
||||
if (file->is_dir)
|
||||
disk_file_remove_dir(file->fullpath);
|
||||
else
|
||||
unlink(file->fullpath);
|
||||
}
|
||||
|
||||
xfree(file->fullpath);
|
||||
xfree(file);
|
||||
}
|
||||
|
||||
boolean disk_file_seek(DISK_FILE* file, uint64 Offset)
|
||||
{
|
||||
if (file->is_dir || file->fd == -1)
|
||||
return False;
|
||||
|
||||
if (lseek(file->fd, Offset, SEEK_SET) == (off_t)-1)
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
boolean disk_file_read(DISK_FILE* file, uint8* buffer, uint32* Length)
|
||||
{
|
||||
ssize_t r;
|
||||
|
||||
if (file->is_dir || file->fd == -1)
|
||||
return False;
|
||||
|
||||
r = read(file->fd, buffer, *Length);
|
||||
if (r < 0)
|
||||
return False;
|
||||
*Length = (uint32)r;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
boolean disk_file_write(DISK_FILE* file, uint8* buffer, uint32 Length)
|
||||
{
|
||||
ssize_t r;
|
||||
|
||||
if (file->is_dir || file->fd == -1)
|
||||
return False;
|
||||
|
||||
while (Length > 0)
|
||||
{
|
||||
r = write(file->fd, buffer, Length);
|
||||
if (r == -1)
|
||||
return False;
|
||||
Length -= r;
|
||||
buffer += r;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
boolean disk_file_query_information(DISK_FILE* file, uint32 FsInformationClass, STREAM* output)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(file->fullpath, &st) != 0)
|
||||
{
|
||||
stream_write_uint32(output, 0); /* Length */
|
||||
return False;
|
||||
}
|
||||
switch (FsInformationClass)
|
||||
{
|
||||
case FileBasicInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
|
||||
stream_write_uint32(output, 36); /* Length */
|
||||
stream_check_size(output, 36);
|
||||
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* CreationTime */
|
||||
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_atime)); /* LastAccessTime */
|
||||
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* LastWriteTime */
|
||||
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_ctime)); /* ChangeTime */
|
||||
stream_write_uint32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */
|
||||
/* Reserved(4), MUST NOT be added! */
|
||||
break;
|
||||
|
||||
case FileStandardInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232088.aspx */
|
||||
stream_write_uint32(output, 22); /* Length */
|
||||
stream_check_size(output, 22);
|
||||
stream_write_uint64(output, st.st_size); /* AllocationSize */
|
||||
stream_write_uint64(output, st.st_size); /* EndOfFile */
|
||||
stream_write_uint32(output, st.st_nlink); /* NumberOfLinks */
|
||||
stream_write_uint8(output, file->delete_pending ? 1 : 0); /* DeletePending */
|
||||
stream_write_uint8(output, file->is_dir ? 1 : 0); /* Directory */
|
||||
/* Reserved(2), MUST NOT be added! */
|
||||
break;
|
||||
|
||||
case FileAttributeTagInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232093.aspx */
|
||||
stream_write_uint32(output, 8); /* Length */
|
||||
stream_check_size(output, 8);
|
||||
stream_write_uint32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */
|
||||
stream_write_uint32(output, 0); /* ReparseTag */
|
||||
break;
|
||||
|
||||
default:
|
||||
stream_write_uint32(output, 0); /* Length */
|
||||
DEBUG_WARN("invalid FsInformationClass %d", FsInformationClass);
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
boolean disk_file_set_information(DISK_FILE* file, uint32 FsInformationClass, uint32 Length, STREAM* input)
|
||||
{
|
||||
struct stat st;
|
||||
struct timeval tv[2];
|
||||
uint64 LastWriteTime;
|
||||
uint32 FileAttributes;
|
||||
mode_t m;
|
||||
uint64 size;
|
||||
uint32 FileNameLength;
|
||||
UNICONV* uniconv;
|
||||
char* s;
|
||||
char* p;
|
||||
char* fullpath;
|
||||
|
||||
switch (FsInformationClass)
|
||||
{
|
||||
case FileBasicInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
|
||||
stream_seek_uint64(input); /* CreationTime */
|
||||
stream_seek_uint64(input); /* LastAccessTime */
|
||||
stream_read_uint64(input, LastWriteTime);
|
||||
stream_seek_uint64(input); /* ChangeTime */
|
||||
stream_read_uint32(input, FileAttributes);
|
||||
|
||||
if (fstat(file->fd, &st) != 0)
|
||||
return False;
|
||||
tv[0].tv_sec = st.st_atime;
|
||||
tv[0].tv_usec = 0;
|
||||
tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime);
|
||||
tv[1].tv_usec = 0;
|
||||
futimes(file->fd, tv);
|
||||
|
||||
if (FileAttributes > 0)
|
||||
{
|
||||
m = st.st_mode;
|
||||
if ((FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
|
||||
m |= S_IWUSR;
|
||||
else
|
||||
m &= ~S_IWUSR;
|
||||
if (m != st.st_mode)
|
||||
fchmod(file->fd, st.st_mode);
|
||||
}
|
||||
break;
|
||||
|
||||
case FileEndOfFileInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232067.aspx */
|
||||
case FileAllocationInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232076.aspx */
|
||||
stream_read_uint64(input, size);
|
||||
ftruncate(file->fd, size);
|
||||
break;
|
||||
|
||||
case FileDispositionInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232098.aspx */
|
||||
stream_read_uint8(input, file->delete_pending);
|
||||
break;
|
||||
|
||||
case FileRenameInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232085.aspx */
|
||||
stream_seek_uint8(input); /* ReplaceIfExists */
|
||||
stream_seek_uint8(input); /* RootDirectory */
|
||||
stream_read_uint32(input, FileNameLength);
|
||||
uniconv = freerdp_uniconv_new();
|
||||
s = freerdp_uniconv_in(uniconv, stream_get_tail(input), FileNameLength);
|
||||
freerdp_uniconv_free(uniconv);
|
||||
fullpath = xmalloc(strlen(file->fullpath) + strlen(s) + 2);
|
||||
strcpy(fullpath, file->fullpath);
|
||||
p = strrchr(fullpath, '/');
|
||||
if (p == NULL)
|
||||
p = fullpath;
|
||||
else
|
||||
p++;
|
||||
strcpy(p, s[0] == '\\' || s[0] == '/' ? s + 1 : s);
|
||||
xfree(s);
|
||||
disk_file_fix_path(fullpath);
|
||||
|
||||
if (rename(file->fullpath, fullpath) == 0)
|
||||
{
|
||||
DEBUG_SVC("renamed %s to %s", file->fullpath, fullpath);
|
||||
disk_file_set_fullpath(file, fullpath);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_WARN("rename %s to %s failed", file->fullpath, fullpath);
|
||||
free(fullpath);
|
||||
return False;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_WARN("invalid FsInformationClass %d", FsInformationClass);
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
boolean disk_file_query_directory(DISK_FILE* file, uint32 FsInformationClass, uint8 InitialQuery,
|
||||
const char* path, STREAM* output)
|
||||
{
|
||||
struct dirent* ent;
|
||||
char* ent_path;
|
||||
struct stat st;
|
||||
UNICONV* uniconv;
|
||||
size_t len;
|
||||
boolean ret;
|
||||
|
||||
DEBUG_SVC("path %s FsInformationClass %d", path, FsInformationClass);
|
||||
|
||||
if (InitialQuery != 0)
|
||||
{
|
||||
rewinddir(file->dir);
|
||||
}
|
||||
|
||||
ent = readdir(file->dir);
|
||||
if (ent == NULL)
|
||||
{
|
||||
stream_write_uint32(output, 0); /* Length */
|
||||
stream_write_uint8(output, 0); /* Padding */
|
||||
return False;
|
||||
}
|
||||
|
||||
memset(&st, 0, sizeof(struct stat));
|
||||
ent_path = xmalloc(strlen(file->fullpath) + strlen(ent->d_name) + 2);
|
||||
sprintf(ent_path, "%s/%s", file->fullpath, ent->d_name);
|
||||
if (stat(ent_path, &st) != 0)
|
||||
{
|
||||
DEBUG_WARN("stat %s failed.", ent_path);
|
||||
}
|
||||
xfree(ent_path);
|
||||
|
||||
uniconv = freerdp_uniconv_new();
|
||||
ent_path = freerdp_uniconv_out(uniconv, ent->d_name, &len);
|
||||
freerdp_uniconv_free(uniconv);
|
||||
|
||||
ret = True;
|
||||
switch (FsInformationClass)
|
||||
{
|
||||
case FileDirectoryInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232097.aspx */
|
||||
stream_write_uint32(output, 64 + len); /* Length */
|
||||
stream_check_size(output, 64 + len);
|
||||
stream_write_uint32(output, 0); /* NextEntryOffset */
|
||||
stream_write_uint32(output, 0); /* FileIndex */
|
||||
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* CreationTime */
|
||||
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_atime)); /* LastAccessTime */
|
||||
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* LastWriteTime */
|
||||
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_ctime)); /* ChangeTime */
|
||||
stream_write_uint64(output, st.st_size); /* EndOfFile */
|
||||
stream_write_uint64(output, st.st_size); /* AllocationSize */
|
||||
stream_write_uint32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */
|
||||
stream_write_uint32(output, len); /* FileNameLength */
|
||||
stream_write(output, ent_path, len);
|
||||
break;
|
||||
|
||||
case FileFullDirectoryInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232068.aspx */
|
||||
stream_write_uint32(output, 68 + len); /* Length */
|
||||
stream_check_size(output, 68 + len);
|
||||
stream_write_uint32(output, 0); /* NextEntryOffset */
|
||||
stream_write_uint32(output, 0); /* FileIndex */
|
||||
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* CreationTime */
|
||||
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_atime)); /* LastAccessTime */
|
||||
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* LastWriteTime */
|
||||
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_ctime)); /* ChangeTime */
|
||||
stream_write_uint64(output, st.st_size); /* EndOfFile */
|
||||
stream_write_uint64(output, st.st_size); /* AllocationSize */
|
||||
stream_write_uint32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */
|
||||
stream_write_uint32(output, len); /* FileNameLength */
|
||||
stream_write_uint32(output, 0); /* EaSize */
|
||||
stream_write(output, ent_path, len);
|
||||
break;
|
||||
|
||||
case FileBothDirectoryInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232095.aspx */
|
||||
stream_write_uint32(output, 93 + len); /* Length */
|
||||
stream_check_size(output, 93 + len);
|
||||
stream_write_uint32(output, 0); /* NextEntryOffset */
|
||||
stream_write_uint32(output, 0); /* FileIndex */
|
||||
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* CreationTime */
|
||||
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_atime)); /* LastAccessTime */
|
||||
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_mtime)); /* LastWriteTime */
|
||||
stream_write_uint64(output, FILE_TIME_SYSTEM_TO_RDP(st.st_ctime)); /* ChangeTime */
|
||||
stream_write_uint64(output, st.st_size); /* EndOfFile */
|
||||
stream_write_uint64(output, st.st_size); /* AllocationSize */
|
||||
stream_write_uint32(output, FILE_ATTR_SYSTEM_TO_RDP(file, st)); /* FileAttributes */
|
||||
stream_write_uint32(output, len); /* FileNameLength */
|
||||
stream_write_uint32(output, 0); /* EaSize */
|
||||
stream_write_uint8(output, 0); /* ShortNameLength */
|
||||
/* Reserved(1), MUST NOT be added! */
|
||||
stream_write_zero(output, 24); /* ShortName */
|
||||
stream_write(output, ent_path, len);
|
||||
break;
|
||||
|
||||
case FileNamesInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232077.aspx */
|
||||
stream_write_uint32(output, 12 + len); /* Length */
|
||||
stream_check_size(output, 12 + len);
|
||||
stream_write_uint32(output, 0); /* NextEntryOffset */
|
||||
stream_write_uint32(output, 0); /* FileIndex */
|
||||
stream_write_uint32(output, len); /* FileNameLength */
|
||||
stream_write(output, ent_path, len);
|
||||
break;
|
||||
|
||||
default:
|
||||
stream_write_uint32(output, 0); /* Length */
|
||||
stream_write_uint8(output, 0); /* Padding */
|
||||
DEBUG_WARN("invalid FsInformationClass %d", FsInformationClass);
|
||||
ret = False;
|
||||
break;
|
||||
}
|
||||
|
||||
xfree(ent_path);
|
||||
|
||||
return ret;
|
||||
}
|
52
channels/rdpdr/disk/disk_file.h
Normal file
52
channels/rdpdr/disk/disk_file.h
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol client.
|
||||
* File System Virtual Channel
|
||||
*
|
||||
* Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __DISK_FILE_H
|
||||
#define __DISK_FILE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
|
||||
typedef struct _DISK_FILE DISK_FILE;
|
||||
struct _DISK_FILE
|
||||
{
|
||||
uint32 id;
|
||||
boolean is_dir;
|
||||
int fd;
|
||||
DIR* dir;
|
||||
char* fullpath;
|
||||
char* filename;
|
||||
boolean delete_pending;
|
||||
};
|
||||
|
||||
DISK_FILE* disk_file_new(const char* base_path, const char* path, uint32 id,
|
||||
uint32 DesiredAccess, uint32 CreateDisposition, uint32 CreateOptions);
|
||||
void disk_file_free(DISK_FILE* file);
|
||||
|
||||
boolean disk_file_seek(DISK_FILE* file, uint64 Offset);
|
||||
boolean disk_file_read(DISK_FILE* file, uint8* buffer, uint32* Length);
|
||||
boolean disk_file_write(DISK_FILE* file, uint8* buffer, uint32 Length);
|
||||
boolean disk_file_query_information(DISK_FILE* file, uint32 FsInformationClass, STREAM* output);
|
||||
boolean disk_file_set_information(DISK_FILE* file, uint32 FsInformationClass, uint32 Length, STREAM* input);
|
||||
boolean disk_file_query_directory(DISK_FILE* file, uint32 FsInformationClass, uint8 InitialQuery,
|
||||
const char* path, STREAM* output);
|
||||
|
||||
#endif /* __DISK_FILE_H */
|
@ -22,41 +22,16 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fnmatch.h>
|
||||
#include <utime.h>
|
||||
#include <freerdp/utils/memory.h>
|
||||
#include <freerdp/utils/stream.h>
|
||||
#include <freerdp/utils/unicode.h>
|
||||
#include <freerdp/utils/list.h>
|
||||
#include <freerdp/utils/thread.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "rdpdr_constants.h"
|
||||
#include "rdpdr_types.h"
|
||||
|
||||
typedef struct _FILE_INFO FILE_INFO;
|
||||
struct _FILE_INFO
|
||||
{
|
||||
uint32 file_id;
|
||||
uint32 file_attr;
|
||||
boolean is_dir;
|
||||
int fd;
|
||||
DIR* dir;
|
||||
char* fullpath;
|
||||
char* pattern;
|
||||
boolean delete_pending;
|
||||
};
|
||||
#include "disk_file.h"
|
||||
|
||||
typedef struct _DISK_DEVICE DISK_DEVICE;
|
||||
struct _DISK_DEVICE
|
||||
@ -65,19 +40,528 @@ struct _DISK_DEVICE
|
||||
|
||||
char* path;
|
||||
LIST* files;
|
||||
|
||||
LIST* irp_list;
|
||||
freerdp_thread* thread;
|
||||
};
|
||||
|
||||
void disk_irp_request(DEVICE* device, IRP* irp)
|
||||
static DISK_FILE* disk_get_file_by_id(DISK_DEVICE* disk, uint32 id)
|
||||
{
|
||||
DISK_DEVICE* disk = (DISK_DEVICE*)device;
|
||||
LIST_ITEM* item;
|
||||
DISK_FILE* file;
|
||||
|
||||
IFCALL(irp->Complete, irp);
|
||||
for (item = disk->files->head; item; item = item->next)
|
||||
{
|
||||
file = (DISK_FILE*)item->data;
|
||||
if (file->id == id)
|
||||
return file;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void disk_free(DEVICE* device)
|
||||
static void disk_process_irp_create(DISK_DEVICE* disk, IRP* irp)
|
||||
{
|
||||
DISK_FILE* file;
|
||||
uint32 DesiredAccess;
|
||||
uint32 CreateDisposition;
|
||||
uint32 CreateOptions;
|
||||
uint32 PathLength;
|
||||
UNICONV* uniconv;
|
||||
char* path;
|
||||
uint32 FileId;
|
||||
uint8 Information;
|
||||
|
||||
stream_read_uint32(irp->input, DesiredAccess);
|
||||
stream_seek(irp->input, 16); /* AllocationSize(8), FileAttributes(4), SharedAccess(4) */
|
||||
stream_read_uint32(irp->input, CreateDisposition);
|
||||
stream_read_uint32(irp->input, CreateOptions);
|
||||
stream_read_uint32(irp->input, PathLength);
|
||||
|
||||
uniconv = freerdp_uniconv_new();
|
||||
path = freerdp_uniconv_in(uniconv, stream_get_tail(irp->input), PathLength);
|
||||
freerdp_uniconv_free(uniconv);
|
||||
|
||||
FileId = irp->devman->id_sequence++;
|
||||
file = disk_file_new(disk->path, path, FileId,
|
||||
DesiredAccess, CreateDisposition, CreateOptions);
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
FileId = 0;
|
||||
Information = 0;
|
||||
|
||||
DEBUG_WARN("failed to create %s.", path);
|
||||
}
|
||||
else
|
||||
{
|
||||
list_enqueue(disk->files, file);
|
||||
|
||||
switch (CreateDisposition)
|
||||
{
|
||||
case FILE_SUPERSEDE:
|
||||
case FILE_OPEN:
|
||||
case FILE_CREATE:
|
||||
case FILE_OVERWRITE:
|
||||
Information = FILE_SUPERSEDED;
|
||||
break;
|
||||
case FILE_OPEN_IF:
|
||||
Information = FILE_OPENED;
|
||||
break;
|
||||
case FILE_OVERWRITE_IF:
|
||||
Information = FILE_OVERWRITTEN;
|
||||
break;
|
||||
default:
|
||||
Information = 0;
|
||||
break;
|
||||
}
|
||||
DEBUG_SVC("%s(%d) created.", file->fullpath, file->id);
|
||||
}
|
||||
|
||||
stream_write_uint32(irp->output, FileId);
|
||||
stream_write_uint8(irp->output, Information);
|
||||
|
||||
xfree(path);
|
||||
|
||||
irp->Complete(irp);
|
||||
}
|
||||
|
||||
static void disk_process_irp_close(DISK_DEVICE* disk, IRP* irp)
|
||||
{
|
||||
DISK_FILE* file;
|
||||
|
||||
file = disk_get_file_by_id(disk, irp->FileId);
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
|
||||
DEBUG_WARN("FileId %d not valid.", irp->FileId);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_SVC("%s(%d) closed.", file->fullpath, file->id);
|
||||
|
||||
list_remove(disk->files, file);
|
||||
disk_file_free(file);
|
||||
}
|
||||
|
||||
stream_write_zero(irp->output, 5); /* Padding(5) */
|
||||
|
||||
irp->Complete(irp);
|
||||
}
|
||||
|
||||
static void disk_process_irp_read(DISK_DEVICE* disk, IRP* irp)
|
||||
{
|
||||
DISK_FILE* file;
|
||||
uint32 Length;
|
||||
uint64 Offset;
|
||||
uint8* buffer = NULL;
|
||||
|
||||
stream_read_uint32(irp->input, Length);
|
||||
stream_read_uint64(irp->input, Offset);
|
||||
|
||||
file = disk_get_file_by_id(disk, irp->FileId);
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
Length = 0;
|
||||
|
||||
DEBUG_WARN("FileId %d not valid.", irp->FileId);
|
||||
}
|
||||
else if (!disk_file_seek(file, Offset))
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
Length = 0;
|
||||
|
||||
DEBUG_WARN("seek %s(%d) failed.", file->fullpath, file->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = (uint8*)xmalloc(Length);
|
||||
if (!disk_file_read(file, buffer, &Length))
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
xfree(buffer);
|
||||
buffer = NULL;
|
||||
Length = 0;
|
||||
|
||||
DEBUG_WARN("read %s(%d) failed.", file->fullpath, file->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_SVC("read %llu-%llu from %s(%d).", Offset, Offset + Length, file->fullpath, file->id);
|
||||
}
|
||||
}
|
||||
|
||||
stream_write_uint32(irp->output, Length);
|
||||
if (Length > 0)
|
||||
{
|
||||
stream_check_size(irp->output, Length);
|
||||
stream_write(irp->output, buffer, Length);
|
||||
}
|
||||
xfree(buffer);
|
||||
|
||||
irp->Complete(irp);
|
||||
}
|
||||
|
||||
static void disk_process_irp_write(DISK_DEVICE* disk, IRP* irp)
|
||||
{
|
||||
DISK_FILE* file;
|
||||
uint32 Length;
|
||||
uint64 Offset;
|
||||
|
||||
stream_read_uint32(irp->input, Length);
|
||||
stream_read_uint64(irp->input, Offset);
|
||||
stream_seek(irp->input, 20); /* Padding */
|
||||
|
||||
file = disk_get_file_by_id(disk, irp->FileId);
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
Length = 0;
|
||||
|
||||
DEBUG_WARN("FileId %d not valid.", irp->FileId);
|
||||
}
|
||||
else if (!disk_file_seek(file, Offset))
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
Length = 0;
|
||||
|
||||
DEBUG_WARN("seek %s(%d) failed.", file->fullpath, file->id);
|
||||
}
|
||||
else if (!disk_file_write(file, stream_get_tail(irp->input), Length))
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
Length = 0;
|
||||
|
||||
DEBUG_WARN("write %s(%d) failed.", file->fullpath, file->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_SVC("write %llu-%llu to %s(%d).", Offset, Offset + Length, file->fullpath, file->id);
|
||||
}
|
||||
|
||||
stream_write_uint32(irp->output, Length);
|
||||
stream_write_uint8(irp->output, 0); /* Padding */
|
||||
|
||||
irp->Complete(irp);
|
||||
}
|
||||
|
||||
static void disk_process_irp_query_information(DISK_DEVICE* disk, IRP* irp)
|
||||
{
|
||||
DISK_FILE* file;
|
||||
uint32 FsInformationClass;
|
||||
|
||||
stream_read_uint32(irp->input, FsInformationClass);
|
||||
|
||||
file = disk_get_file_by_id(disk, irp->FileId);
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
|
||||
DEBUG_WARN("FileId %d not valid.", irp->FileId);
|
||||
}
|
||||
else if (!disk_file_query_information(file, FsInformationClass, irp->output))
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
|
||||
DEBUG_WARN("FsInformationClass %d on %s(%d) failed.", FsInformationClass, file->fullpath, file->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_SVC("FsInformationClass %d on %s(%d).", FsInformationClass, file->fullpath, file->id);
|
||||
}
|
||||
|
||||
irp->Complete(irp);
|
||||
}
|
||||
|
||||
static void disk_process_irp_set_information(DISK_DEVICE* disk, IRP* irp)
|
||||
{
|
||||
DISK_FILE* file;
|
||||
uint32 FsInformationClass;
|
||||
uint32 Length;
|
||||
|
||||
stream_read_uint32(irp->input, FsInformationClass);
|
||||
stream_read_uint32(irp->input, Length);
|
||||
stream_seek(irp->input, 24); /* Padding */
|
||||
|
||||
file = disk_get_file_by_id(disk, irp->FileId);
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
|
||||
DEBUG_WARN("FileId %d not valid.", irp->FileId);
|
||||
}
|
||||
else if (!disk_file_set_information(file, FsInformationClass, Length, irp->input))
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
|
||||
DEBUG_WARN("FsInformationClass %d on %s(%d) failed.", FsInformationClass, file->fullpath, file->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_SVC("FsInformationClass %d on %s(%d) ok.", FsInformationClass, file->fullpath, file->id);
|
||||
}
|
||||
|
||||
stream_write_uint32(irp->output, Length);
|
||||
|
||||
irp->Complete(irp);
|
||||
}
|
||||
|
||||
static void disk_process_irp_query_volume_information(DISK_DEVICE* disk, IRP* irp)
|
||||
{
|
||||
uint32 FsInformationClass;
|
||||
STREAM* output = irp->output;
|
||||
|
||||
stream_read_uint32(irp->input, FsInformationClass);
|
||||
|
||||
switch (FsInformationClass)
|
||||
{
|
||||
case FileFsVolumeInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232108.aspx */
|
||||
stream_write_uint32(output, 34); /* Length */
|
||||
stream_check_size(output, 34);
|
||||
stream_write_uint64(output, 0); /* VolumeCreationTime */
|
||||
stream_write_uint32(output, 0); /* VolumeSerialNumber */
|
||||
stream_write_uint32(output, 16); /* VolumeLabelLength */
|
||||
stream_write_uint8(output, 0); /* SupportsObjects */
|
||||
stream_write_uint8(output, 0); /* Reserved */
|
||||
stream_write(output, "F\0R\0E\0E\0R\0D\0P\0\0\0", 16); /* VolumeLabel (Unicode) */
|
||||
break;
|
||||
|
||||
case FileFsSizeInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232107.aspx */
|
||||
stream_write_uint32(output, 24); /* Length */
|
||||
stream_check_size(output, 24);
|
||||
stream_write_uint64(output, 0x1000000); /* TotalAllocationUnits */
|
||||
stream_write_uint64(output, 0x800000); /* AvailableAllocationUnits */
|
||||
stream_write_uint32(output, 1); /* SectorsPerAllocationUnit */
|
||||
stream_write_uint32(output, 0x400); /* BytesPerSector */
|
||||
break;
|
||||
|
||||
case FileFsAttributeInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232101.aspx */
|
||||
stream_write_uint32(output, 22); /* Length */
|
||||
stream_check_size(output, 22);
|
||||
stream_write_uint32(output,
|
||||
FILE_CASE_SENSITIVE_SEARCH |
|
||||
FILE_CASE_PRESERVED_NAMES |
|
||||
FILE_UNICODE_ON_DISK); /* FileSystemAttributes */
|
||||
stream_write_uint32(output, 510); /* MaximumComponentNameLength */
|
||||
stream_write_uint32(output, 10); /* FileSystemNameLength */
|
||||
stream_write(output, "F\0A\0T\03\02\0", 10); /* FileSystemName */
|
||||
break;
|
||||
|
||||
case FileFsFullSizeInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232104.aspx */
|
||||
stream_write_uint32(output, 32); /* Length */
|
||||
stream_check_size(output, 32);
|
||||
stream_write_uint64(output, 0x1000000); /* TotalAllocationUnits */
|
||||
stream_write_uint64(output, 0x800000); /* CallerAvailableAllocationUnits */
|
||||
stream_write_uint64(output, 0x800000); /* ActualAvailableAllocationUnits */
|
||||
stream_write_uint32(output, 1); /* SectorsPerAllocationUnit */
|
||||
stream_write_uint32(output, 0x400); /* BytesPerSector */
|
||||
break;
|
||||
|
||||
case FileFsDeviceInformation:
|
||||
/* http://msdn.microsoft.com/en-us/library/cc232109.aspx */
|
||||
stream_write_uint32(output, 8); /* Length */
|
||||
stream_check_size(output, 8);
|
||||
stream_write_uint32(output, FILE_DEVICE_DISK); /* DeviceType */
|
||||
stream_write_uint32(output, 0); /* Characteristics */
|
||||
break;
|
||||
|
||||
default:
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
stream_write_uint32(output, 0); /* Length */
|
||||
DEBUG_WARN("invalid FsInformationClass %d", FsInformationClass);
|
||||
break;
|
||||
}
|
||||
|
||||
irp->Complete(irp);
|
||||
}
|
||||
|
||||
static void disk_process_irp_query_directory(DISK_DEVICE* disk, IRP* irp)
|
||||
{
|
||||
DISK_FILE* file;
|
||||
uint32 FsInformationClass;
|
||||
uint8 InitialQuery;
|
||||
uint32 PathLength;
|
||||
UNICONV* uniconv;
|
||||
char* path;
|
||||
|
||||
stream_read_uint32(irp->input, FsInformationClass);
|
||||
stream_read_uint8(irp->input, InitialQuery);
|
||||
stream_read_uint32(irp->input, PathLength);
|
||||
stream_seek(irp->input, 23); /* Padding */
|
||||
|
||||
uniconv = freerdp_uniconv_new();
|
||||
path = freerdp_uniconv_in(uniconv, stream_get_tail(irp->input), PathLength);
|
||||
freerdp_uniconv_free(uniconv);
|
||||
|
||||
file = disk_get_file_by_id(disk, irp->FileId);
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
stream_write_uint32(irp->output, 0); /* Length */
|
||||
DEBUG_WARN("FileId %d not valid.", irp->FileId);
|
||||
}
|
||||
else if (!disk_file_query_directory(file, FsInformationClass, InitialQuery, path, irp->output))
|
||||
{
|
||||
irp->IoStatus = STATUS_NO_MORE_FILES;
|
||||
}
|
||||
|
||||
xfree(path);
|
||||
|
||||
irp->Complete(irp);
|
||||
}
|
||||
|
||||
static void disk_process_irp_directory_control(DISK_DEVICE* disk, IRP* irp)
|
||||
{
|
||||
switch (irp->MinorFunction)
|
||||
{
|
||||
case IRP_MN_QUERY_DIRECTORY:
|
||||
disk_process_irp_query_directory(disk, irp);
|
||||
break;
|
||||
|
||||
case IRP_MN_NOTIFY_CHANGE_DIRECTORY: /* TODO */
|
||||
irp->Discard(irp);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_WARN("MinorFunction 0x%X not supported", irp->MinorFunction);
|
||||
irp->IoStatus = STATUS_NOT_SUPPORTED;
|
||||
stream_write_uint32(irp->output, 0); /* Length */
|
||||
irp->Complete(irp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void disk_process_irp_device_control(DISK_DEVICE* disk, IRP* irp)
|
||||
{
|
||||
stream_write_uint32(irp->output, 0); /* OutputBufferLength */
|
||||
irp->Complete(irp);
|
||||
}
|
||||
|
||||
static void disk_process_irp(DISK_DEVICE* disk, IRP* irp)
|
||||
{
|
||||
switch (irp->MajorFunction)
|
||||
{
|
||||
case IRP_MJ_CREATE:
|
||||
disk_process_irp_create(disk, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_CLOSE:
|
||||
disk_process_irp_close(disk, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_READ:
|
||||
disk_process_irp_read(disk, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_WRITE:
|
||||
disk_process_irp_write(disk, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_QUERY_INFORMATION:
|
||||
disk_process_irp_query_information(disk, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_SET_INFORMATION:
|
||||
disk_process_irp_set_information(disk, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_QUERY_VOLUME_INFORMATION:
|
||||
disk_process_irp_query_volume_information(disk, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_DIRECTORY_CONTROL:
|
||||
disk_process_irp_directory_control(disk, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
disk_process_irp_device_control(disk, irp);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_WARN("MajorFunction 0x%X not supported", irp->MajorFunction);
|
||||
irp->IoStatus = STATUS_NOT_SUPPORTED;
|
||||
irp->Complete(irp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void disk_process_irp_list(DISK_DEVICE* disk)
|
||||
{
|
||||
IRP* irp;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (freerdp_thread_is_stopped(disk->thread))
|
||||
break;
|
||||
|
||||
freerdp_thread_lock(disk->thread);
|
||||
irp = (IRP*)list_dequeue(disk->irp_list);
|
||||
freerdp_thread_unlock(disk->thread);
|
||||
|
||||
if (irp == NULL)
|
||||
break;
|
||||
|
||||
disk_process_irp(disk, irp);
|
||||
}
|
||||
}
|
||||
|
||||
static void* disk_thread_func(void* arg)
|
||||
{
|
||||
DISK_DEVICE* disk = (DISK_DEVICE*)arg;
|
||||
|
||||
while (1)
|
||||
{
|
||||
freerdp_thread_wait(disk->thread);
|
||||
|
||||
if (freerdp_thread_is_stopped(disk->thread))
|
||||
break;
|
||||
|
||||
freerdp_thread_reset(disk->thread);
|
||||
disk_process_irp_list(disk);
|
||||
}
|
||||
|
||||
freerdp_thread_quit(disk->thread);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void disk_irp_request(DEVICE* device, IRP* irp)
|
||||
{
|
||||
DISK_DEVICE* disk = (DISK_DEVICE*)device;
|
||||
|
||||
freerdp_thread_lock(disk->thread);
|
||||
list_enqueue(disk->irp_list, irp);
|
||||
freerdp_thread_unlock(disk->thread);
|
||||
|
||||
freerdp_thread_signal(disk->thread);
|
||||
}
|
||||
|
||||
static void disk_free(DEVICE* device)
|
||||
{
|
||||
DISK_DEVICE* disk = (DISK_DEVICE*)device;
|
||||
IRP* irp;
|
||||
DISK_FILE* file;
|
||||
|
||||
freerdp_thread_stop(disk->thread);
|
||||
|
||||
while ((irp = (IRP*)list_dequeue(disk->irp_list)) != NULL)
|
||||
irp->Discard(irp);
|
||||
list_free(disk->irp_list);
|
||||
|
||||
while ((file = (DISK_FILE*)list_dequeue(disk->files)) != NULL)
|
||||
disk_file_free(file);
|
||||
list_free(disk->files);
|
||||
xfree(disk);
|
||||
}
|
||||
@ -109,7 +593,12 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
disk->path = path;
|
||||
disk->files = list_new();
|
||||
|
||||
disk->irp_list = list_new();
|
||||
disk->thread = freerdp_thread_new();
|
||||
|
||||
pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)disk);
|
||||
|
||||
freerdp_thread_start(disk->thread, disk_thread_func, disk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -91,14 +91,14 @@ void stream_extend(STREAM* stream);
|
||||
*_s->p++ = ((_v) >> 16) & 0xFF; \
|
||||
*_s->p++ = ((_v) >> 24) & 0xFF; } while (0)
|
||||
#define stream_write_uint64(_s, _v) do { \
|
||||
*_s->p++ = (_v) & 0xFF; \
|
||||
*_s->p++ = ((_v) >> 8) & 0xFF; \
|
||||
*_s->p++ = ((_v) >> 16) & 0xFF; \
|
||||
*_s->p++ = ((_v) >> 24) & 0xFF; \
|
||||
*_s->p++ = ((_v) >> 32) & 0xFF; \
|
||||
*_s->p++ = ((_v) >> 40) & 0xFF; \
|
||||
*_s->p++ = ((_v) >> 48) & 0xFF; \
|
||||
*_s->p++ = ((_v) >> 56) & 0xFF; } while (0)
|
||||
*_s->p++ = (uint64)(_v) & 0xFF; \
|
||||
*_s->p++ = ((uint64)(_v) >> 8) & 0xFF; \
|
||||
*_s->p++ = ((uint64)(_v) >> 16) & 0xFF; \
|
||||
*_s->p++ = ((uint64)(_v) >> 24) & 0xFF; \
|
||||
*_s->p++ = ((uint64)(_v) >> 32) & 0xFF; \
|
||||
*_s->p++ = ((uint64)(_v) >> 40) & 0xFF; \
|
||||
*_s->p++ = ((uint64)(_v) >> 48) & 0xFF; \
|
||||
*_s->p++ = ((uint64)(_v) >> 56) & 0xFF; } while (0)
|
||||
#define stream_write(_s, _b, _n) do { \
|
||||
memcpy(_s->p, (_b), (_n)); \
|
||||
_s->p += (_n); \
|
||||
@ -133,6 +133,7 @@ void stream_extend(STREAM* stream);
|
||||
#define stream_seek_uint8(_s) stream_seek(_s, 1)
|
||||
#define stream_seek_uint16(_s) stream_seek(_s, 2)
|
||||
#define stream_seek_uint32(_s) stream_seek(_s, 4)
|
||||
#define stream_seek_uint64(_s) stream_seek(_s, 8)
|
||||
|
||||
#define stream_read_uint16_be(_s, _v) do { _v = \
|
||||
(((uint16)(*_s->p)) << 8) + \
|
||||
|
@ -20,22 +20,34 @@
|
||||
#ifndef __THREAD_UTILS_H
|
||||
#define __THREAD_UTILS_H
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define freerdp_thread_create(_proc, _arg) do { \
|
||||
DWORD thread; \
|
||||
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_proc, _arg, 0, &thread); \
|
||||
while (0)
|
||||
|
||||
#else
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/utils/mutex.h>
|
||||
#include <freerdp/utils/wait_obj.h>
|
||||
#ifndef _WIN32
|
||||
#include <pthread.h>
|
||||
#define freerdp_thread_create(_proc, _arg) do { \
|
||||
pthread_t thread; \
|
||||
pthread_create(&thread, 0, _proc, _arg); \
|
||||
pthread_detach(thread); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct _freerdp_thread freerdp_thread;
|
||||
struct _freerdp_thread
|
||||
{
|
||||
freerdp_mutex* mutex;
|
||||
|
||||
struct wait_obj* signals[5];
|
||||
int num_signals;
|
||||
|
||||
int status;
|
||||
};
|
||||
|
||||
freerdp_thread* freerdp_thread_new(void);
|
||||
void freerdp_thread_start(freerdp_thread* thread, void* func, void* arg);
|
||||
void freerdp_thread_stop(freerdp_thread* thread);
|
||||
|
||||
#define freerdp_thread_wait(_t) wait_obj_select(_t->signals, _t->num_signals, -1)
|
||||
#define freerdp_thread_is_stopped(_t) wait_obj_is_set(_t->signals[0])
|
||||
#define freerdp_thread_quit(_t) _t->status = -1
|
||||
#define freerdp_thread_signal(_t) wait_obj_set(_t->signals[1])
|
||||
#define freerdp_thread_reset(_t) wait_obj_clear(_t->signals[1])
|
||||
#define freerdp_thread_lock(_t) freerdp_mutex_lock(_t->mutex)
|
||||
#define freerdp_thread_unlock(_t) freerdp_mutex_unlock(_t->mutex)
|
||||
|
||||
#endif /* __THREAD_UTILS_H */
|
||||
|
@ -32,6 +32,7 @@ set(FREERDP_UTILS_SRCS
|
||||
semaphore.c
|
||||
stream.c
|
||||
svc_plugin.c
|
||||
thread.c
|
||||
unicode.c
|
||||
wait_obj.c)
|
||||
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/utils/memory.h>
|
||||
#include <freerdp/utils/mutex.h>
|
||||
@ -30,7 +29,6 @@
|
||||
#include <freerdp/utils/stream.h>
|
||||
#include <freerdp/utils/list.h>
|
||||
#include <freerdp/utils/thread.h>
|
||||
#include <freerdp/utils/wait_obj.h>
|
||||
#include <freerdp/utils/event.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
@ -77,12 +75,7 @@ struct rdp_svc_plugin_private
|
||||
STREAM* data_in;
|
||||
|
||||
LIST* data_in_list;
|
||||
freerdp_mutex* data_in_mutex;
|
||||
|
||||
struct wait_obj* signals[5];
|
||||
int num_signals;
|
||||
|
||||
int thread_status;
|
||||
freerdp_thread* thread;
|
||||
};
|
||||
|
||||
static rdpSvcPlugin* svc_plugin_find_by_init_handle(void* init_handle)
|
||||
@ -176,11 +169,11 @@ static void svc_plugin_process_received(rdpSvcPlugin* plugin, void* pData, uint3
|
||||
item = xnew(svc_data_in_item);
|
||||
item->data_in = data_in;
|
||||
|
||||
freerdp_mutex_lock(plugin->priv->data_in_mutex);
|
||||
freerdp_thread_lock(plugin->priv->thread);
|
||||
list_enqueue(plugin->priv->data_in_list, item);
|
||||
freerdp_mutex_unlock(plugin->priv->data_in_mutex);
|
||||
freerdp_thread_unlock(plugin->priv->thread);
|
||||
|
||||
wait_obj_set(plugin->priv->signals[1]);
|
||||
freerdp_thread_signal(plugin->priv->thread);
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,11 +184,11 @@ static void svc_plugin_process_event(rdpSvcPlugin* plugin, FRDP_EVENT* event_in)
|
||||
item = xnew(svc_data_in_item);
|
||||
item->event_in = event_in;
|
||||
|
||||
freerdp_mutex_lock(plugin->priv->data_in_mutex);
|
||||
freerdp_thread_lock(plugin->priv->thread);
|
||||
list_enqueue(plugin->priv->data_in_list, item);
|
||||
freerdp_mutex_unlock(plugin->priv->data_in_mutex);
|
||||
freerdp_thread_unlock(plugin->priv->thread);
|
||||
|
||||
wait_obj_set(plugin->priv->signals[1]);
|
||||
freerdp_thread_signal(plugin->priv->thread);
|
||||
}
|
||||
|
||||
static void svc_plugin_open_event(uint32 openHandle, uint32 event, void* pData, uint32 dataLength,
|
||||
@ -233,12 +226,12 @@ static void svc_plugin_process_data_in(rdpSvcPlugin* plugin)
|
||||
while (1)
|
||||
{
|
||||
/* terminate signal */
|
||||
if (wait_obj_is_set(plugin->priv->signals[0]))
|
||||
if (freerdp_thread_is_stopped(plugin->priv->thread))
|
||||
break;
|
||||
|
||||
freerdp_mutex_lock(plugin->priv->data_in_mutex);
|
||||
freerdp_thread_lock(plugin->priv->thread);
|
||||
item = list_dequeue(plugin->priv->data_in_list);
|
||||
freerdp_mutex_unlock(plugin->priv->data_in_mutex);
|
||||
freerdp_thread_unlock(plugin->priv->thread);
|
||||
|
||||
if (item != NULL)
|
||||
{
|
||||
@ -264,22 +257,16 @@ static void* svc_plugin_thread_func(void* arg)
|
||||
|
||||
while (1)
|
||||
{
|
||||
wait_obj_select(plugin->priv->signals, plugin->priv->num_signals, -1);
|
||||
freerdp_thread_wait(plugin->priv->thread);
|
||||
|
||||
/* terminate signal */
|
||||
if (wait_obj_is_set(plugin->priv->signals[0]))
|
||||
if (freerdp_thread_is_stopped(plugin->priv->thread))
|
||||
break;
|
||||
|
||||
/* data_in signal */
|
||||
if (wait_obj_is_set(plugin->priv->signals[1]))
|
||||
{
|
||||
wait_obj_clear(plugin->priv->signals[1]);
|
||||
/* process data in */
|
||||
svc_plugin_process_data_in(plugin);
|
||||
}
|
||||
freerdp_thread_reset(plugin->priv->thread);
|
||||
svc_plugin_process_data_in(plugin);
|
||||
}
|
||||
|
||||
plugin->priv->thread_status = -1;
|
||||
freerdp_thread_quit(plugin->priv->thread);
|
||||
|
||||
DEBUG_SVC("out");
|
||||
|
||||
@ -299,45 +286,22 @@ static void svc_plugin_process_connected(rdpSvcPlugin* plugin, void* pData, uint
|
||||
}
|
||||
|
||||
plugin->priv->data_in_list = list_new();
|
||||
plugin->priv->data_in_mutex = freerdp_mutex_new();
|
||||
plugin->priv->thread = freerdp_thread_new();
|
||||
|
||||
/* terminate signal */
|
||||
plugin->priv->signals[plugin->priv->num_signals++] = wait_obj_new();
|
||||
/* data_in signal */
|
||||
plugin->priv->signals[plugin->priv->num_signals++] = wait_obj_new();
|
||||
|
||||
plugin->priv->thread_status = 1;
|
||||
|
||||
freerdp_thread_create(svc_plugin_thread_func, plugin);
|
||||
freerdp_thread_start(plugin->priv->thread, svc_plugin_thread_func, plugin);
|
||||
}
|
||||
|
||||
static void svc_plugin_process_terminated(rdpSvcPlugin* plugin)
|
||||
{
|
||||
svc_data_in_item* item;
|
||||
struct timespec ts;
|
||||
int i;
|
||||
|
||||
wait_obj_set(plugin->priv->signals[0]);
|
||||
i = 0;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 10000000;
|
||||
while (plugin->priv->thread_status > 0 && i < 1000)
|
||||
{
|
||||
i++;
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
freerdp_thread_stop(plugin->priv->thread);
|
||||
|
||||
plugin->channel_entry_points.pVirtualChannelClose(plugin->priv->open_handle);
|
||||
xfree(plugin->channel_entry_points.pExtendedData);
|
||||
|
||||
svc_plugin_remove(plugin);
|
||||
|
||||
for (i = 0; i < plugin->priv->num_signals; i++)
|
||||
wait_obj_free(plugin->priv->signals[i]);
|
||||
plugin->priv->num_signals = 0;
|
||||
|
||||
freerdp_mutex_free(plugin->priv->data_in_mutex);
|
||||
|
||||
while ((item = list_dequeue(plugin->priv->data_in_list)) != NULL)
|
||||
svc_data_in_item_free(item);
|
||||
list_free(plugin->priv->data_in_list);
|
||||
|
81
libfreerdp-utils/thread.c
Normal file
81
libfreerdp-utils/thread.c
Normal file
@ -0,0 +1,81 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol client.
|
||||
* Thread Utils
|
||||
*
|
||||
* Copyright 2011 Vic Lee
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <freerdp/utils/memory.h>
|
||||
#include <freerdp/utils/thread.h>
|
||||
|
||||
freerdp_thread* freerdp_thread_new(void)
|
||||
{
|
||||
freerdp_thread* thread;
|
||||
|
||||
thread = xnew(freerdp_thread);
|
||||
thread->mutex = freerdp_mutex_new();
|
||||
thread->signals[0] = wait_obj_new();
|
||||
thread->signals[1] = wait_obj_new();
|
||||
thread->num_signals = 2;
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
void freerdp_thread_start(freerdp_thread* thread, void* func, void* arg)
|
||||
{
|
||||
thread->status = 1;
|
||||
|
||||
#ifdef _WIN32
|
||||
{
|
||||
DWORD th;
|
||||
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, arg, 0, &th);
|
||||
}
|
||||
#else
|
||||
{
|
||||
pthread_t th;
|
||||
pthread_create(&th, 0, func, arg);
|
||||
pthread_detach(th);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void freerdp_thread_stop(freerdp_thread* thread)
|
||||
{
|
||||
struct timespec ts;
|
||||
int i;
|
||||
|
||||
wait_obj_set(thread->signals[0]);
|
||||
i = 0;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 10000000;
|
||||
while (thread->status > 0 && i < 1000)
|
||||
{
|
||||
i++;
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < thread->num_signals; i++)
|
||||
wait_obj_free(thread->signals[i]);
|
||||
thread->num_signals = 0;
|
||||
|
||||
freerdp_mutex_free(thread->mutex);
|
||||
thread->mutex = NULL;
|
||||
|
||||
xfree(thread);
|
||||
}
|
Loading…
Reference in New Issue
Block a user