mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-15 00:44:19 +09:00
[client,cliprdr] refactor file clipboard
This commit is contained in:
@@ -54,7 +54,6 @@
|
||||
|
||||
#include <freerdp/client/client_cliprdr_file.h>
|
||||
|
||||
#define MAX_CLIP_DATA_DIR_LEN 10
|
||||
#define NO_CLIP_DATA_ID (UINT64_C(1) << 32)
|
||||
#define WIN32_FILETIME_TO_UNIX_EPOCH INT64_C(11644473600)
|
||||
|
||||
@@ -83,7 +82,10 @@ struct sCliprdrFuseFile
|
||||
CliprdrFuseFile* parent;
|
||||
wArrayList* children;
|
||||
|
||||
char* filename;
|
||||
size_t filename_len;
|
||||
const char* filename;
|
||||
|
||||
size_t filename_with_root_len;
|
||||
char* filename_with_root;
|
||||
UINT32 list_idx;
|
||||
fuse_ino_t ino;
|
||||
@@ -209,22 +211,40 @@ static void fuse_file_free(void* data)
|
||||
free(fuse_file);
|
||||
}
|
||||
|
||||
static CliprdrFuseFile* fuse_file_new(void)
|
||||
WINPR_ATTR_FORMAT_ARG(1, 2)
|
||||
WINPR_ATTR_MALLOC(fuse_file_free, 1)
|
||||
static CliprdrFuseFile* fuse_file_new(WINPR_FORMAT_ARG const char* fmt, ...)
|
||||
{
|
||||
CliprdrFuseFile* fuse_file = NULL;
|
||||
|
||||
fuse_file = calloc(1, sizeof(CliprdrFuseFile));
|
||||
if (!fuse_file)
|
||||
CliprdrFuseFile* file = calloc(1, sizeof(CliprdrFuseFile));
|
||||
if (!file)
|
||||
return NULL;
|
||||
|
||||
fuse_file->children = ArrayList_New(FALSE);
|
||||
if (!fuse_file->children)
|
||||
file->children = ArrayList_New(FALSE);
|
||||
if (!file->children)
|
||||
goto fail;
|
||||
|
||||
WINPR_ASSERT(fmt);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
const int rc =
|
||||
winpr_vasprintf(&file->filename_with_root, &file->filename_with_root_len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
if (file->filename_with_root && (file->filename_with_root_len > 0))
|
||||
{
|
||||
free(fuse_file);
|
||||
return NULL;
|
||||
file->filename_len = 0;
|
||||
file->filename = strrchr(file->filename_with_root, '/') + 1;
|
||||
if (file->filename)
|
||||
file->filename_len = strnlen(file->filename, file->filename_with_root_len);
|
||||
}
|
||||
|
||||
return fuse_file;
|
||||
return file;
|
||||
fail:
|
||||
fuse_file_free(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void clip_data_entry_free(void* data)
|
||||
@@ -393,7 +413,7 @@ static BOOL notify_delete_child(void* data, WINPR_ATTR_UNUSED size_t index, va_l
|
||||
|
||||
WINPR_ASSERT(file_context->fuse_sess);
|
||||
fuse_lowlevel_notify_delete(file_context->fuse_sess, parent->ino, child->ino, child->filename,
|
||||
strlen(child->filename));
|
||||
child->filename_len);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -478,7 +498,7 @@ static void clear_selection(CliprdrFileContext* file_context, BOOL all_selection
|
||||
{
|
||||
fuse_lowlevel_notify_delete(file_context->fuse_sess, file_context->root_dir->ino,
|
||||
clip_data_dir->ino, clip_data_dir->filename,
|
||||
strlen(clip_data_dir->filename));
|
||||
clip_data_dir->filename_len);
|
||||
}
|
||||
}
|
||||
ArrayList_Free(clear_context.fuse_files);
|
||||
@@ -671,7 +691,7 @@ get_fuse_file_by_name_from_parent(WINPR_ATTR_UNUSED CliprdrFileContext* file_con
|
||||
|
||||
WINPR_ASSERT(child);
|
||||
|
||||
if (strcmp(name, child->filename) == 0)
|
||||
if (strncmp(name, child->filename, child->filename_len + 1) == 0)
|
||||
return child;
|
||||
}
|
||||
|
||||
@@ -1696,34 +1716,17 @@ static CliprdrFuseFile* clip_data_dir_new(CliprdrFileContext* file_context, BOOL
|
||||
UINT32 clip_data_id)
|
||||
{
|
||||
CliprdrFuseFile* root_dir = NULL;
|
||||
CliprdrFuseFile* clip_data_dir = NULL;
|
||||
size_t path_length = 0;
|
||||
|
||||
WINPR_ASSERT(file_context);
|
||||
|
||||
clip_data_dir = fuse_file_new();
|
||||
UINT64 data_id = clip_data_id;
|
||||
if (!has_clip_data_id)
|
||||
data_id = NO_CLIP_DATA_ID;
|
||||
|
||||
CliprdrFuseFile* clip_data_dir = fuse_file_new("/%" PRIu64, data_id);
|
||||
if (!clip_data_dir)
|
||||
return NULL;
|
||||
|
||||
path_length = 1 + MAX_CLIP_DATA_DIR_LEN + 1;
|
||||
|
||||
clip_data_dir->filename_with_root = calloc(path_length, sizeof(char));
|
||||
if (!clip_data_dir->filename_with_root)
|
||||
{
|
||||
WLog_Print(file_context->log, WLOG_ERROR, "Failed to allocate filename");
|
||||
fuse_file_free(clip_data_dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (has_clip_data_id)
|
||||
(void)_snprintf(clip_data_dir->filename_with_root, path_length, "/%u",
|
||||
(unsigned)clip_data_id);
|
||||
else
|
||||
(void)_snprintf(clip_data_dir->filename_with_root, path_length, "/%" PRIu64,
|
||||
NO_CLIP_DATA_ID);
|
||||
|
||||
clip_data_dir->filename = strrchr(clip_data_dir->filename_with_root, '/') + 1;
|
||||
|
||||
clip_data_dir->ino = get_next_free_inode(file_context);
|
||||
clip_data_dir->is_directory = TRUE;
|
||||
clip_data_dir->is_readonly = TRUE;
|
||||
@@ -1778,7 +1781,8 @@ static BOOL is_fuse_file_not_parent(WINPR_ATTR_UNUSED const void* key, void* val
|
||||
if (!fuse_file->is_directory)
|
||||
return TRUE;
|
||||
|
||||
if (strcmp(find_context->parent_path, fuse_file->filename_with_root) == 0)
|
||||
if (strncmp(find_context->parent_path, fuse_file->filename_with_root,
|
||||
fuse_file->filename_with_root_len + 1) == 0)
|
||||
{
|
||||
find_context->parent = fuse_file;
|
||||
return FALSE;
|
||||
@@ -1812,126 +1816,122 @@ static CliprdrFuseFile* get_parent_directory(CliprdrFileContext* file_context, c
|
||||
return find_context.parent;
|
||||
}
|
||||
|
||||
// NOLINTBEGIN(clang-analyzer-unix.Malloc) HashTable_Insert owns fuse_file
|
||||
static BOOL selection_handle_file(CliprdrFileContext* file_context,
|
||||
CliprdrFuseClipDataEntry* clip_data_entry, uint32_t index,
|
||||
const FILEDESCRIPTORW* file)
|
||||
{
|
||||
|
||||
WINPR_ASSERT(file_context);
|
||||
WINPR_ASSERT(clip_data_entry);
|
||||
WINPR_ASSERT(file);
|
||||
|
||||
CliprdrFuseFile* clip_data_dir = clip_data_entry->clip_data_dir;
|
||||
WINPR_ASSERT(clip_data_dir);
|
||||
|
||||
char filename[ARRAYSIZE(file->cFileName) * 8] = { 0 };
|
||||
const SSIZE_T filenamelen = ConvertWCharNToUtf8(file->cFileName, ARRAYSIZE(file->cFileName),
|
||||
filename, ARRAYSIZE(filename) - 1);
|
||||
if (filenamelen < 0)
|
||||
{
|
||||
WLog_Print(file_context->log, WLOG_ERROR, "Failed to convert filename");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (size_t j = 0; filename[j]; ++j)
|
||||
{
|
||||
if (filename[j] == '\\')
|
||||
filename[j] = '/';
|
||||
}
|
||||
|
||||
BOOL crc = FALSE;
|
||||
CliprdrFuseFile* fuse_file = fuse_file_new(
|
||||
"%.*s/%s", WINPR_ASSERTING_INT_CAST(int, clip_data_dir->filename_with_root_len),
|
||||
clip_data_dir->filename_with_root, filename);
|
||||
if (!fuse_file)
|
||||
{
|
||||
WLog_Print(file_context->log, WLOG_ERROR, "Failed to create FUSE file");
|
||||
goto end;
|
||||
}
|
||||
|
||||
fuse_file->parent = get_parent_directory(file_context, fuse_file->filename_with_root);
|
||||
if (!fuse_file->parent)
|
||||
{
|
||||
WLog_Print(file_context->log, WLOG_ERROR, "Found no parent for FUSE file");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!ArrayList_Append(fuse_file->parent->children, fuse_file))
|
||||
{
|
||||
WLog_Print(file_context->log, WLOG_ERROR, "Failed to append FUSE file");
|
||||
goto end;
|
||||
}
|
||||
|
||||
fuse_file->list_idx = index;
|
||||
fuse_file->ino = get_next_free_inode(file_context);
|
||||
fuse_file->has_clip_data_id = clip_data_entry->has_clip_data_id;
|
||||
fuse_file->clip_data_id = clip_data_entry->clip_data_id;
|
||||
if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
fuse_file->is_directory = TRUE;
|
||||
if (file->dwFileAttributes & FILE_ATTRIBUTE_READONLY)
|
||||
fuse_file->is_readonly = TRUE;
|
||||
if (file->dwFlags & FD_FILESIZE)
|
||||
{
|
||||
fuse_file->size = ((UINT64)file->nFileSizeHigh << 32) + file->nFileSizeLow;
|
||||
fuse_file->has_size = TRUE;
|
||||
}
|
||||
if (file->dwFlags & FD_WRITESTIME)
|
||||
{
|
||||
INT64 filetime = 0;
|
||||
|
||||
filetime = file->ftLastWriteTime.dwHighDateTime;
|
||||
filetime <<= 32;
|
||||
filetime += file->ftLastWriteTime.dwLowDateTime;
|
||||
|
||||
fuse_file->last_write_time_unix =
|
||||
1LL * filetime / (10LL * 1000LL * 1000LL) - WIN32_FILETIME_TO_UNIX_EPOCH;
|
||||
fuse_file->has_last_write_time = TRUE;
|
||||
}
|
||||
|
||||
if (!HashTable_Insert(file_context->inode_table, (void*)(uintptr_t)fuse_file->ino, fuse_file))
|
||||
{
|
||||
WLog_Print(file_context->log, WLOG_ERROR, "Failed to insert inode into inode table");
|
||||
goto end;
|
||||
}
|
||||
|
||||
crc = TRUE;
|
||||
|
||||
end:
|
||||
if (!crc)
|
||||
{
|
||||
fuse_file_free(fuse_file);
|
||||
clear_entry_selection(clip_data_entry);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
// NOLINTEND(clang-analyzer-unix.Malloc) HashTable_Insert owns fuse_file
|
||||
|
||||
static BOOL set_selection_for_clip_data_entry(CliprdrFileContext* file_context,
|
||||
CliprdrFuseClipDataEntry* clip_data_entry,
|
||||
const FILEDESCRIPTORW* files, UINT32 n_files)
|
||||
{
|
||||
CliprdrFuseFile* clip_data_dir = NULL;
|
||||
|
||||
WINPR_ASSERT(file_context);
|
||||
WINPR_ASSERT(clip_data_entry);
|
||||
WINPR_ASSERT(files);
|
||||
|
||||
clip_data_dir = clip_data_entry->clip_data_dir;
|
||||
WINPR_ASSERT(clip_data_dir);
|
||||
|
||||
if (clip_data_entry->has_clip_data_id)
|
||||
WLog_Print(file_context->log, WLOG_DEBUG, "Setting selection for clipDataId %u",
|
||||
clip_data_entry->clip_data_id);
|
||||
else
|
||||
WLog_Print(file_context->log, WLOG_DEBUG, "Setting selection");
|
||||
|
||||
// NOLINTBEGIN(clang-analyzer-unix.Malloc) HashTable_Insert owns fuse_file
|
||||
for (UINT32 i = 0; i < n_files; ++i)
|
||||
{
|
||||
const FILEDESCRIPTORW* file = &files[i];
|
||||
CliprdrFuseFile* fuse_file = NULL;
|
||||
char* filename = NULL;
|
||||
size_t path_length = 0;
|
||||
|
||||
fuse_file = fuse_file_new();
|
||||
if (!fuse_file)
|
||||
{
|
||||
WLog_Print(file_context->log, WLOG_ERROR, "Failed to create FUSE file");
|
||||
clear_entry_selection(clip_data_entry);
|
||||
if (!selection_handle_file(file_context, clip_data_entry, i, file))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
filename = ConvertWCharToUtf8Alloc(file->cFileName, NULL);
|
||||
if (!filename)
|
||||
{
|
||||
WLog_Print(file_context->log, WLOG_ERROR, "Failed to convert filename");
|
||||
fuse_file_free(fuse_file);
|
||||
clear_entry_selection(clip_data_entry);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (size_t j = 0; filename[j]; ++j)
|
||||
{
|
||||
if (filename[j] == '\\')
|
||||
filename[j] = '/';
|
||||
}
|
||||
|
||||
path_length = strlen(clip_data_dir->filename_with_root) + 1 + strlen(filename) + 1;
|
||||
fuse_file->filename_with_root = calloc(path_length, sizeof(char));
|
||||
if (!fuse_file->filename_with_root)
|
||||
{
|
||||
WLog_Print(file_context->log, WLOG_ERROR, "Failed to allocate filename");
|
||||
free(filename);
|
||||
fuse_file_free(fuse_file);
|
||||
clear_entry_selection(clip_data_entry);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
(void)_snprintf(fuse_file->filename_with_root, path_length, "%s/%s",
|
||||
clip_data_dir->filename_with_root, filename);
|
||||
free(filename);
|
||||
|
||||
fuse_file->filename = strrchr(fuse_file->filename_with_root, '/') + 1;
|
||||
|
||||
fuse_file->parent = get_parent_directory(file_context, fuse_file->filename_with_root);
|
||||
if (!fuse_file->parent)
|
||||
{
|
||||
WLog_Print(file_context->log, WLOG_ERROR, "Found no parent for FUSE file");
|
||||
fuse_file_free(fuse_file);
|
||||
clear_entry_selection(clip_data_entry);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!ArrayList_Append(fuse_file->parent->children, fuse_file))
|
||||
{
|
||||
WLog_Print(file_context->log, WLOG_ERROR, "Failed to append FUSE file");
|
||||
fuse_file_free(fuse_file);
|
||||
clear_entry_selection(clip_data_entry);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fuse_file->list_idx = i;
|
||||
fuse_file->ino = get_next_free_inode(file_context);
|
||||
fuse_file->has_clip_data_id = clip_data_entry->has_clip_data_id;
|
||||
fuse_file->clip_data_id = clip_data_entry->clip_data_id;
|
||||
if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
fuse_file->is_directory = TRUE;
|
||||
if (file->dwFileAttributes & FILE_ATTRIBUTE_READONLY)
|
||||
fuse_file->is_readonly = TRUE;
|
||||
if (file->dwFlags & FD_FILESIZE)
|
||||
{
|
||||
fuse_file->size = ((UINT64)file->nFileSizeHigh << 32) + file->nFileSizeLow;
|
||||
fuse_file->has_size = TRUE;
|
||||
}
|
||||
if (file->dwFlags & FD_WRITESTIME)
|
||||
{
|
||||
INT64 filetime = 0;
|
||||
|
||||
filetime = file->ftLastWriteTime.dwHighDateTime;
|
||||
filetime <<= 32;
|
||||
filetime += file->ftLastWriteTime.dwLowDateTime;
|
||||
|
||||
fuse_file->last_write_time_unix =
|
||||
1LL * filetime / (10LL * 1000LL * 1000LL) - WIN32_FILETIME_TO_UNIX_EPOCH;
|
||||
fuse_file->has_last_write_time = TRUE;
|
||||
}
|
||||
|
||||
if (!HashTable_Insert(file_context->inode_table, (void*)(uintptr_t)fuse_file->ino,
|
||||
fuse_file))
|
||||
{
|
||||
WLog_Print(file_context->log, WLOG_ERROR, "Failed to insert inode into inode table");
|
||||
fuse_file_free(fuse_file);
|
||||
clear_entry_selection(clip_data_entry);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
// NOLINTEND(clang-analyzer-unix.Malloc) HashTable_Insert owns fuse_file
|
||||
|
||||
if (clip_data_entry->has_clip_data_id)
|
||||
WLog_Print(file_context->log, WLOG_DEBUG, "Selection set for clipDataId %u",
|
||||
@@ -2362,20 +2362,10 @@ static CliprdrFuseFile* fuse_file_new_root(CliprdrFileContext* file_context)
|
||||
{
|
||||
CliprdrFuseFile* root_dir = NULL;
|
||||
|
||||
root_dir = fuse_file_new();
|
||||
root_dir = fuse_file_new("/");
|
||||
if (!root_dir)
|
||||
return NULL;
|
||||
|
||||
root_dir->filename_with_root = calloc(2, sizeof(char));
|
||||
if (!root_dir->filename_with_root)
|
||||
{
|
||||
fuse_file_free(root_dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(void)_snprintf(root_dir->filename_with_root, 2, "/");
|
||||
root_dir->filename = root_dir->filename_with_root;
|
||||
|
||||
root_dir->ino = FUSE_ROOT_ID;
|
||||
root_dir->is_directory = TRUE;
|
||||
root_dir->is_readonly = TRUE;
|
||||
|
||||
Reference in New Issue
Block a user