[client,common] fix file copy client to server

This commit is contained in:
Armin Novak 2023-02-27 14:50:43 +01:00 committed by akallabeth
parent 9fb4465722
commit 39c06a4683
2 changed files with 297 additions and 89 deletions

View File

@ -76,6 +76,7 @@ typedef struct
fuse_req_t req; fuse_req_t req;
/*for FILECONTENTS_SIZE must be ino number* */ /*for FILECONTENTS_SIZE must be ino number* */
size_t req_ino; size_t req_ino;
UINT32 lockId;
} CliprdrFuseStream; } CliprdrFuseStream;
typedef struct typedef struct
@ -89,7 +90,7 @@ typedef struct
struct timespec st_mtim; struct timespec st_mtim;
char* name; char* name;
wArrayList* child_inos; wArrayList* child_inos;
UINT32 streamID; INT64 lockID;
} CliprdrFuseInode; } CliprdrFuseInode;
#endif #endif
@ -97,12 +98,12 @@ typedef struct
{ {
char* name; char* name;
FILE* fp; FILE* fp;
INT64 size;
} CliprdrLocalFile; } CliprdrLocalFile;
typedef struct typedef struct
{ {
UINT32 streamID; UINT32 lockId;
BOOL locked; BOOL locked;
size_t count; size_t count;
CliprdrLocalFile* files; CliprdrLocalFile* files;
@ -126,14 +127,15 @@ struct cliprdr_file_context
BOOL file_formats_registered; BOOL file_formats_registered;
UINT32 file_capability_flags; UINT32 file_capability_flags;
UINT32 local_stream_id; UINT32 local_lock_id;
UINT32 remote_stream_id; UINT32 remote_lock_id;
wHashTable* local_streams; wHashTable* local_streams;
wLog* log; wLog* log;
void* clipboard; void* clipboard;
CliprdrClientContext* context; CliprdrClientContext* context;
char* path; char* path;
char* current_path;
BYTE hash[WINPR_SHA256_DIGEST_LENGTH]; BYTE hash[WINPR_SHA256_DIGEST_LENGTH];
}; };
@ -144,7 +146,7 @@ static BOOL local_stream_discard(const void* key, void* value, void* arg);
#if defined(WITH_FUSE2) || defined(WITH_FUSE3) #if defined(WITH_FUSE2) || defined(WITH_FUSE3)
static BOOL cliprdr_fuse_repopulate(CliprdrFileContext* file, wArrayList* list); static BOOL cliprdr_fuse_repopulate(CliprdrFileContext* file, wArrayList* list);
static UINT cliprdr_file_send_client_file_contents(CliprdrFileContext* file, UINT32 streamId, static UINT cliprdr_file_send_client_file_contents(CliprdrFileContext* file, UINT32 streamId,
UINT32 listIndex, UINT32 dwFlags, UINT32 lockId, UINT32 listIndex, UINT32 dwFlags,
UINT32 nPositionLow, UINT32 nPositionHigh, UINT32 nPositionLow, UINT32 nPositionHigh,
UINT32 cbRequested); UINT32 cbRequested);
@ -195,14 +197,14 @@ static void cliprdr_file_fuse_node_free(void* obj)
free(inode); free(inode);
} }
static CliprdrFuseInode* cliprdr_file_fuse_node_new(UINT32 streamID, size_t lindex, size_t ino, static CliprdrFuseInode* cliprdr_file_fuse_node_new(UINT32 lockID, size_t lindex, size_t ino,
size_t parent, const char* path, mode_t mode) size_t parent, const char* path, mode_t mode)
{ {
CliprdrFuseInode* node = (CliprdrFuseInode*)calloc(1, sizeof(CliprdrFuseInode)); CliprdrFuseInode* node = (CliprdrFuseInode*)calloc(1, sizeof(CliprdrFuseInode));
if (!node) if (!node)
goto fail; goto fail;
node->streamID = streamID; node->lockID = lockID;
node->ino = ino; node->ino = ino;
node->parent_ino = parent; node->parent_ino = parent;
node->lindex = lindex; node->lindex = lindex;
@ -327,7 +329,8 @@ error:
static int cliprdr_file_fuse_util_get_and_update_stream_list(CliprdrFileContext* file, static int cliprdr_file_fuse_util_get_and_update_stream_list(CliprdrFileContext* file,
fuse_req_t req, size_t ino, fuse_req_t req, size_t ino,
UINT32 type, UINT32* stream_id) UINT32 type, UINT32* stream_id,
UINT32* lockId)
{ {
int rc = ENOMEM; int rc = ENOMEM;
@ -339,16 +342,17 @@ static int cliprdr_file_fuse_util_get_and_update_stream_list(CliprdrFileContext*
CliprdrFuseInode* node = cliprdr_file_fuse_util_get_inode(file->ino_list, ino); CliprdrFuseInode* node = cliprdr_file_fuse_util_get_inode(file->ino_list, ino);
if (node) if (node)
{ {
CliprdrFuseStream* stream = HashTable_GetItemValue(file->remote_streams, &node->streamID); CliprdrFuseStream* stream = HashTable_GetItemValue(file->remote_streams, &node->lockID);
if (stream) if (stream)
{ {
CliprdrFuseStream* request = CliprdrFuseStream* request =
cliprdr_fuse_stream_new(node->streamID, req, stream->req_ino, type); cliprdr_fuse_stream_new(node->lockID, req, stream->req_ino, type);
if (request) if (request)
{ {
if (Queue_Enqueue(file->requests_in_flight, stream)) if (Queue_Enqueue(file->requests_in_flight, stream))
{ {
*stream_id = node->streamID; *stream_id = node->lockID;
*lockId = node->lockID;
rc = 0; rc = 0;
} }
} }
@ -369,7 +373,7 @@ static int cliprdr_file_fuse_util_add_stream_list(CliprdrFileContext* file)
if (!stream) if (!stream)
return err; return err;
const BOOL res = HashTable_Insert(file->remote_streams, &stream->stream_id, stream); const BOOL res = HashTable_Insert(file->remote_streams, &stream->lockId, stream);
if (!res) if (!res)
{ {
cliprdr_fuse_stream_free(stream); cliprdr_fuse_stream_free(stream);
@ -533,8 +537,9 @@ void cliprdr_file_fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t o
{ {
int err; int err;
CliprdrFileContext* file = (CliprdrFileContext*)fuse_req_userdata(req); CliprdrFileContext* file = (CliprdrFileContext*)fuse_req_userdata(req);
UINT32 lindex; UINT32 lindex = 0;
UINT32 stream_id; UINT32 stream_id = 0;
UINT32 lock_id = 0;
WINPR_ASSERT(file); WINPR_ASSERT(file);
@ -546,7 +551,7 @@ void cliprdr_file_fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t o
} }
err = cliprdr_file_fuse_util_get_and_update_stream_list(file, req, ino, FILECONTENTS_RANGE, err = cliprdr_file_fuse_util_get_and_update_stream_list(file, req, ino, FILECONTENTS_RANGE,
&stream_id); &stream_id, &lock_id);
if (err) if (err)
{ {
fuse_reply_err(req, err); fuse_reply_err(req, err);
@ -556,7 +561,7 @@ void cliprdr_file_fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t o
UINT32 nPositionLow = (off >> 0) & 0xFFFFFFFF; UINT32 nPositionLow = (off >> 0) & 0xFFFFFFFF;
UINT32 nPositionHigh = (off >> 32) & 0xFFFFFFFF; UINT32 nPositionHigh = (off >> 32) & 0xFFFFFFFF;
cliprdr_file_send_client_file_contents(file, stream_id, lindex, FILECONTENTS_RANGE, cliprdr_file_send_client_file_contents(file, stream_id, lock_id, lindex, FILECONTENTS_RANGE,
nPositionLow, nPositionHigh, size); nPositionLow, nPositionHigh, size);
} }
@ -612,14 +617,16 @@ void cliprdr_file_fuse_lookup(fuse_req_t req, fuse_ino_t parent, const char* nam
if (!size_set) if (!size_set)
{ {
UINT32 streamID = 0; UINT32 streamID = 0;
UINT32 lockId = 0;
const int err = cliprdr_file_fuse_util_get_and_update_stream_list( const int err = cliprdr_file_fuse_util_get_and_update_stream_list(
file, req, ino, FILECONTENTS_SIZE, &streamID); file, req, ino, FILECONTENTS_SIZE, &streamID, &lockId);
if (err != 0) if (err != 0)
{ {
fuse_reply_err(req, err); fuse_reply_err(req, err);
return; return;
} }
cliprdr_file_send_client_file_contents(file, streamID, lindex, FILECONTENTS_SIZE, 0, 0, 0); cliprdr_file_send_client_file_contents(file, streamID, lockId, lindex, FILECONTENTS_SIZE, 0,
0, 0);
return; return;
} }
e.ino = ino; e.ino = ino;
@ -748,12 +755,11 @@ static BOOL add_stream_node(const void* key, void* value, void* arg)
WINPR_ASSERT(node_arg->root); WINPR_ASSERT(node_arg->root);
char name[10] = { 0 }; char name[10] = { 0 };
_snprintf(name, sizeof(name), "%08" PRIx32, stream->stream_id); _snprintf(name, sizeof(name), "%08" PRIx32, stream->lockId);
const size_t idx = ArrayList_Count(node_arg->list); const size_t idx = ArrayList_Count(node_arg->list);
CliprdrFuseInode* node = CliprdrFuseInode* node = cliprdr_file_fuse_node_new(
cliprdr_file_fuse_node_new(stream->stream_id, idx, FUSE_ROOT_ID + 1 + stream->stream_id, stream->lockId, idx, FUSE_ROOT_ID + 1 + stream->lockId, FUSE_ROOT_ID, name, S_IFDIR | 0700);
FUSE_ROOT_ID, name, S_IFDIR | 0700);
if (!node) if (!node)
return FALSE; return FALSE;
node->size_set = TRUE; node->size_set = TRUE;
@ -799,14 +805,17 @@ fail:
* @return 0 on success, otherwise a Win32 error code * @return 0 on success, otherwise a Win32 error code
*/ */
static UINT cliprdr_file_send_client_file_contents(CliprdrFileContext* file, UINT32 streamId, static UINT cliprdr_file_send_client_file_contents(CliprdrFileContext* file, UINT32 streamId,
UINT32 listIndex, UINT32 dwFlags, UINT32 lockId, UINT32 listIndex, UINT32 dwFlags,
UINT32 nPositionLow, UINT32 nPositionHigh, UINT32 nPositionLow, UINT32 nPositionHigh,
UINT32 cbRequested) UINT32 cbRequested)
{ {
CLIPRDR_FILE_CONTENTS_REQUEST formatFileContentsRequest = { 0 }; CLIPRDR_FILE_CONTENTS_REQUEST formatFileContentsRequest = {
formatFileContentsRequest.streamId = streamId; .streamId = streamId,
formatFileContentsRequest.listIndex = listIndex; .clipDataId = lockId,
formatFileContentsRequest.dwFlags = dwFlags; .haveClipDataId = cliprdr_file_context_current_flags(file) & CB_CAN_LOCK_CLIPDATA,
.listIndex = listIndex,
.dwFlags = dwFlags
};
WINPR_ASSERT(file); WINPR_ASSERT(file);
switch (dwFlags) switch (dwFlags)
@ -1001,7 +1010,8 @@ static BOOL cliprdr_file_fuse_create_nodes(CliprdrFileContext* file, wStream* s,
char curName[ARRAYSIZE(descriptor.cFileName)] = { 0 }; char curName[ARRAYSIZE(descriptor.cFileName)] = { 0 };
char dirName[ARRAYSIZE(descriptor.cFileName)] = { 0 }; char dirName[ARRAYSIZE(descriptor.cFileName)] = { 0 };
Stream_Read(s, &descriptor, sizeof(FILEDESCRIPTORW)); if (!cliprdr_read_filedescriptor(s, &descriptor))
goto fail;
ConvertWCharNToUtf8(descriptor.cFileName, ARRAYSIZE(descriptor.cFileName), curName, ConvertWCharNToUtf8(descriptor.cFileName, ARRAYSIZE(descriptor.cFileName), curName,
ARRAYSIZE(curName)); ARRAYSIZE(curName));
@ -1015,7 +1025,7 @@ static BOOL cliprdr_file_fuse_create_nodes(CliprdrFileContext* file, wStream* s,
CliprdrFuseInode* inode = NULL; CliprdrFuseInode* inode = NULL;
if (split_point == NULL) if (split_point == NULL)
{ {
inode = cliprdr_file_fuse_node_new(rootNode->streamID, lindex, nextIno++, rootNode->ino, inode = cliprdr_file_fuse_node_new(rootNode->lockID, lindex, nextIno++, rootNode->ino,
curName, 0700); curName, 0700);
if (!ArrayList_Append(file->ino_list, inode)) if (!ArrayList_Append(file->ino_list, inode))
goto fail; goto fail;
@ -1032,7 +1042,7 @@ static BOOL cliprdr_file_fuse_create_nodes(CliprdrFileContext* file, wStream* s,
parent = (CliprdrFuseInode*)HashTable_GetItemValue(mapDir, dirName); parent = (CliprdrFuseInode*)HashTable_GetItemValue(mapDir, dirName);
if (!parent) if (!parent)
goto fail; goto fail;
inode = cliprdr_file_fuse_node_new(rootNode->streamID, lindex, nextIno++, parent->ino, inode = cliprdr_file_fuse_node_new(rootNode->lockID, lindex, nextIno++, parent->ino,
baseName, 0700); baseName, 0700);
if (!inode) if (!inode)
goto fail; goto fail;
@ -1172,33 +1182,52 @@ static UINT cliprdr_file_context_send_contents(CliprdrClientContext* context,
return context->ClientFileContentsResponse(context, &response); return context->ClientFileContentsResponse(context, &response);
} }
static FILE* file_for_request(CliprdrFileContext* file, UINT32 streamId, UINT32 listIndex) static CliprdrLocalFile* file_info_for_request(CliprdrFileContext* file, UINT32 lockId,
UINT32 listIndex)
{ {
FILE* fp = NULL; WINPR_ASSERT(file);
HashTable_Lock(file->local_streams);
CliprdrLocalStream* cur = HashTable_GetItemValue(file->local_streams, &streamId); CliprdrLocalStream* cur = HashTable_GetItemValue(file->local_streams, &lockId);
if (cur) if (cur)
{ {
if (listIndex < cur->count) if (listIndex < cur->count)
{ {
CliprdrLocalFile* f = &cur->files[listIndex]; CliprdrLocalFile* f = &cur->files[listIndex];
if (f->fp) WLog_INFO("xxxx", "got %s [%" PRIu32 "]", f->name, listIndex);
fp = f->fp; return f;
else
{
if (strncmp("file://", f->name, 7) == 0)
fp = fopen(&f->name[7], "rb");
else
fp = fopen(f->name, "rb");
f->fp = fp;
}
} }
} }
HashTable_Unlock(file->local_streams); return NULL;
}
return fp; static CliprdrLocalFile* file_for_request(CliprdrFileContext* file, UINT32 lockId, UINT32 listIndex)
{
CliprdrLocalFile* f = file_info_for_request(file, lockId, listIndex);
if (f)
{
if (!f->fp)
{
const char* name = f->name;
f->fp = winpr_fopen(name, "rb");
}
if (!f->fp)
return NULL;
}
return f;
}
static void cliprdr_local_file_try_close(CliprdrLocalFile* file, UINT res, UINT64 offset,
UINT64 size)
{
WINPR_ASSERT(file);
if ((res != 0) || ((file->size > 0) && (offset + size >= file->size)))
{
fclose(file->fp);
file->fp = NULL;
}
} }
static UINT cliprdr_file_context_server_file_size_request( static UINT cliprdr_file_context_server_file_size_request(
@ -1217,15 +1246,23 @@ static UINT cliprdr_file_context_server_file_size_request(
fileContentsRequest->cbRequested); fileContentsRequest->cbRequested);
} }
FILE* fp = HashTable_Lock(file->local_streams);
file_for_request(file, fileContentsRequest->streamId, fileContentsRequest->listIndex);
if (!fp)
return cliprdr_file_context_send_file_contents_failure(file->context, fileContentsRequest);
if (_fseeki64(fp, 0, SEEK_END) < 0) UINT res = CHANNEL_RC_OK;
return cliprdr_file_context_send_file_contents_failure(file->context, fileContentsRequest); CliprdrLocalFile* rfile =
file_for_request(file, fileContentsRequest->clipDataId, fileContentsRequest->listIndex);
if (!rfile)
res = cliprdr_file_context_send_file_contents_failure(file->context, fileContentsRequest);
const INT64 size = _ftelli64(fp); if (_fseeki64(rfile->fp, 0, SEEK_END) < 0)
res = cliprdr_file_context_send_file_contents_failure(file->context, fileContentsRequest);
const INT64 size = _ftelli64(rfile->fp);
rfile->size = size;
cliprdr_local_file_try_close(rfile, res, 0, 0);
HashTable_Unlock(file->local_streams);
if (res != CHANNEL_RC_OK)
return res;
return cliprdr_file_context_send_contents(file->context, fileContentsRequest, &size, return cliprdr_file_context_send_contents(file->context, fileContentsRequest, &size,
sizeof(size)); sizeof(size));
} }
@ -1234,52 +1271,71 @@ static UINT cliprdr_file_context_server_file_range_request(
CliprdrFileContext* file, const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) CliprdrFileContext* file, const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
{ {
BYTE* data = NULL; BYTE* data = NULL;
wClipboardFileRangeRequest request = { 0 };
WINPR_ASSERT(fileContentsRequest); WINPR_ASSERT(fileContentsRequest);
request.streamId = fileContentsRequest->streamId; HashTable_Lock(file->local_streams);
request.listIndex = fileContentsRequest->listIndex;
request.nPositionLow = fileContentsRequest->nPositionLow;
request.nPositionHigh = fileContentsRequest->nPositionHigh;
request.cbRequested = fileContentsRequest->cbRequested;
FILE* fp =
file_for_request(file, fileContentsRequest->streamId, fileContentsRequest->listIndex);
if (!fp)
goto fail;
const UINT64 offset = (((UINT64)fileContentsRequest->nPositionHigh) << 32) | const UINT64 offset = (((UINT64)fileContentsRequest->nPositionHigh) << 32) |
((UINT64)fileContentsRequest->nPositionLow); ((UINT64)fileContentsRequest->nPositionLow);
if (_fseeki64(fp, offset, SEEK_SET) < 0)
CliprdrLocalFile* rfile =
file_for_request(file, fileContentsRequest->clipDataId, fileContentsRequest->listIndex);
if (!rfile)
goto fail;
if (_fseeki64(rfile->fp, offset, SEEK_SET) < 0)
goto fail; goto fail;
data = malloc(fileContentsRequest->cbRequested); data = malloc(fileContentsRequest->cbRequested);
if (!data) if (!data)
goto fail; goto fail;
const size_t r = fread(data, 1, fileContentsRequest->cbRequested, fp); const size_t r = fread(data, 1, fileContentsRequest->cbRequested, rfile->fp);
const UINT rc = cliprdr_file_context_send_contents(file->context, fileContentsRequest, data, r); const UINT rc = cliprdr_file_context_send_contents(file->context, fileContentsRequest, data, r);
free(data); free(data);
cliprdr_local_file_try_close(rfile, rc, offset, fileContentsRequest->cbRequested);
HashTable_Unlock(file->local_streams);
return rc; return rc;
fail: fail:
cliprdr_local_file_try_close(rfile, ERROR_INTERNAL_ERROR, offset,
fileContentsRequest->cbRequested);
free(data); free(data);
HashTable_Unlock(file->local_streams);
return cliprdr_file_context_send_file_contents_failure(file->context, fileContentsRequest); return cliprdr_file_context_send_file_contents_failure(file->context, fileContentsRequest);
} }
static UINT change_lock(CliprdrFileContext* file, UINT32 streamID, BOOL lock) static BOOL update_sub_path(CliprdrFileContext* file, UINT32 lockID)
{
WINPR_ASSERT(file);
WINPR_ASSERT(file->path);
char lockstr[32] = { 0 };
_snprintf(lockstr, sizeof(lockstr), "%08" PRIx32, lockID);
free(file->current_path);
file->current_path = GetCombinedPath(file->path, lockstr);
return file->current_path != NULL;
}
static UINT change_lock(CliprdrFileContext* file, UINT32 lockId, BOOL lock)
{ {
WINPR_ASSERT(file); WINPR_ASSERT(file);
HashTable_Lock(file->local_streams); HashTable_Lock(file->local_streams);
CliprdrLocalStream* stream = HashTable_GetItemValue(file->local_streams, &streamID); CliprdrLocalStream* stream = HashTable_GetItemValue(file->local_streams, &lockId);
if (lock && !stream) if (lock && !stream)
{ {
stream = cliprdr_local_stream_new(streamID, NULL, 0); stream = cliprdr_local_stream_new(lockId, NULL, 0);
HashTable_Insert(file->local_streams, &streamID, stream); HashTable_Insert(file->local_streams, &lockId, stream);
file->local_stream_id = streamID; file->local_lock_id = lockId;
} }
if (stream) if (stream)
{
stream->locked = lock; stream->locked = lock;
stream->lockId = lockId;
update_sub_path(file, lockId);
}
if (!lock) if (!lock)
HashTable_Foreach(file->local_streams, local_stream_discard, file); HashTable_Foreach(file->local_streams, local_stream_discard, file);
@ -1432,7 +1488,7 @@ void* cliprdr_file_context_get_context(CliprdrFileContext* file)
return file->clipboard; return file->clipboard;
} }
const char* cliprdr_file_context_base_path(CliprdrFileContext* file) static const char* cliprdr_file_context_base_path(CliprdrFileContext* file)
{ {
WINPR_ASSERT(file); WINPR_ASSERT(file);
return file->path; return file->path;
@ -1474,6 +1530,7 @@ void cliprdr_file_context_free(CliprdrFileContext* file)
HashTable_Free(file->local_streams); HashTable_Free(file->local_streams);
winpr_RemoveDirectory(file->path); winpr_RemoveDirectory(file->path);
free(file->path); free(file->path);
free(file->current_path);
free(file); free(file);
} }
@ -1482,12 +1539,15 @@ static BOOL create_base_path(CliprdrFileContext* file)
WINPR_ASSERT(file); WINPR_ASSERT(file);
char base[64] = { 0 }; char base[64] = { 0 };
_snprintf(base, sizeof(base), "/.xfreerdp.cliprdr.%" PRIu32, GetCurrentProcessId()); _snprintf(base, sizeof(base), "com.freerdp.client.cliprdr.%" PRIu32, GetCurrentProcessId());
file->path = GetKnownSubPath(KNOWN_PATH_TEMP, base); file->path = GetKnownSubPath(KNOWN_PATH_TEMP, base);
if (!file->path) if (!file->path)
return FALSE; return FALSE;
if (!update_sub_path(file, 0))
return FALSE;
if (!winpr_PathFileExists(file->path) && !winpr_PathMakePath(file->path, 0)) if (!winpr_PathFileExists(file->path) && !winpr_PathMakePath(file->path, 0))
{ {
WLog_Print(file->log, WLOG_ERROR, "Failed to create directory '%s'", file->path); WLog_Print(file->log, WLOG_ERROR, "Failed to create directory '%s'", file->path);
@ -1498,32 +1558,150 @@ static BOOL create_base_path(CliprdrFileContext* file)
static void cliprdr_local_file_free(CliprdrLocalFile* file) static void cliprdr_local_file_free(CliprdrLocalFile* file)
{ {
const CliprdrLocalFile empty = { 0 };
if (!file) if (!file)
return; return;
if (file->fp) if (file->fp)
fclose(file->fp); fclose(file->fp);
free(file->name); free(file->name);
*file = empty;
}
static BOOL cliprdr_local_file_new(CliprdrLocalFile* f, const char* path)
{
const CliprdrLocalFile empty = { 0 };
WINPR_ASSERT(f);
WINPR_ASSERT(path);
*f = empty;
f->name = _strdup(path);
if (!f->name)
goto fail;
return TRUE;
fail:
cliprdr_local_file_free(f);
return FALSE;
}
static void cliprdr_local_files_free(CliprdrLocalStream* stream)
{
WINPR_ASSERT(stream);
for (size_t x = 0; x < stream->count; x++)
cliprdr_local_file_free(&stream->files[x]);
free(stream->files);
stream->files = NULL;
stream->count = 0;
} }
static void cliprdr_local_stream_free(void* obj) static void cliprdr_local_stream_free(void* obj)
{ {
CliprdrLocalStream* stream = (CliprdrLocalStream*)obj; CliprdrLocalStream* stream = (CliprdrLocalStream*)obj;
if (stream) if (stream)
{ cliprdr_local_files_free(stream);
for (size_t x = 0; x < stream->count; x++)
cliprdr_local_file_free(&stream->files[x]);
free(stream->files);
}
free(stream); free(stream);
} }
static BOOL append_entry(CliprdrLocalStream* stream, const char* path)
{
CliprdrLocalFile* tmp = realloc(stream->files, sizeof(CliprdrLocalFile) * (stream->count + 1));
if (!tmp)
return FALSE;
stream->files = tmp;
CliprdrLocalFile* f = &stream->files[stream->count++];
return cliprdr_local_file_new(f, path);
}
static BOOL is_directory(const char* path)
{
WCHAR* wpath = ConvertUtf8ToWCharAlloc(path, NULL);
if (!wpath)
return FALSE;
HANDLE hFile =
CreateFileW(wpath, 0, FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
free(wpath);
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
BY_HANDLE_FILE_INFORMATION fileInformation = { 0 };
const BOOL status = GetFileInformationByHandle(hFile, &fileInformation);
CloseHandle(hFile);
if (!status)
return FALSE;
return fileInformation.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
}
static BOOL add_directory(CliprdrLocalStream* stream, const char* path)
{
char* wildcardpath = GetCombinedPath(path, "*");
if (!wildcardpath)
return FALSE;
WCHAR* wpath = ConvertUtf8ToWCharAlloc(wildcardpath, NULL);
free(wildcardpath);
if (!wpath)
return FALSE;
WIN32_FIND_DATAW FindFileData = { 0 };
HANDLE hFind = FindFirstFileW(wpath, &FindFileData);
free(wpath);
if (hFind == INVALID_HANDLE_VALUE)
return FALSE;
BOOL rc = FALSE;
char* next = NULL;
do
{
const WCHAR dot[] = { '.', '\0' };
const WCHAR dotdot[] = { '.', '.', '\0' };
if (_wcscmp(FindFileData.cFileName, dot) == 0)
continue;
if (_wcscmp(FindFileData.cFileName, dotdot) == 0)
continue;
char cFileName[MAX_PATH] = { 0 };
ConvertWCharNToUtf8(FindFileData.cFileName, ARRAYSIZE(FindFileData.cFileName), cFileName,
ARRAYSIZE(cFileName));
free(next);
next = GetCombinedPath(path, cFileName);
if (!next)
goto fail;
if (!append_entry(stream, next))
goto fail;
if (is_directory(next))
{
if (!add_directory(stream, next))
goto fail;
}
} while (FindNextFileW(hFind, &FindFileData));
rc = TRUE;
fail:
free(next);
FindClose(hFind);
return rc;
}
static BOOL cliprdr_local_stream_update(CliprdrLocalStream* stream, const char* data, size_t size) static BOOL cliprdr_local_stream_update(CliprdrLocalStream* stream, const char* data, size_t size)
{ {
BOOL rc = FALSE;
WINPR_ASSERT(stream); WINPR_ASSERT(stream);
if (size == 0) if (size == 0)
return TRUE; return TRUE;
free(stream->files); cliprdr_local_files_free(stream);
stream->files = calloc(size, sizeof(CliprdrLocalFile)); stream->files = calloc(size, sizeof(CliprdrLocalFile));
if (!stream->files) if (!stream->files)
return FALSE; return FALSE;
@ -1534,14 +1712,31 @@ static BOOL cliprdr_local_stream_update(CliprdrLocalStream* stream, const char*
char* ptr = strtok(copy, "\r\n"); char* ptr = strtok(copy, "\r\n");
while (ptr) while (ptr)
{ {
stream->files[stream->count++].name = _strdup(ptr); const char* name = ptr;
if (strncmp("file:///", ptr, 8) == 0)
name = &ptr[7];
else if (strncmp("file:/", ptr, 6) == 0)
name = &ptr[5];
if (!append_entry(stream, name))
goto fail;
if (is_directory(name))
{
const BOOL res = add_directory(stream, name);
if (!res)
goto fail;
}
ptr = strtok(NULL, "\r\n"); ptr = strtok(NULL, "\r\n");
} }
rc = TRUE;
fail:
free(copy); free(copy);
return TRUE; return rc;
} }
CliprdrLocalStream* cliprdr_local_stream_new(UINT32 streamID, const char* data, size_t size) CliprdrLocalStream* cliprdr_local_stream_new(UINT32 lockId, const char* data, size_t size)
{ {
CliprdrLocalStream* stream = calloc(1, sizeof(CliprdrLocalStream)); CliprdrLocalStream* stream = calloc(1, sizeof(CliprdrLocalStream));
if (!stream) if (!stream)
@ -1550,7 +1745,7 @@ CliprdrLocalStream* cliprdr_local_stream_new(UINT32 streamID, const char* data,
if (!cliprdr_local_stream_update(stream, data, size)) if (!cliprdr_local_stream_update(stream, data, size))
goto fail; goto fail;
stream->streamID = streamID; stream->lockId = lockId;
return stream; return stream;
fail: fail:
@ -1587,6 +1782,7 @@ static void* UINTPointerClone(const void* other)
*copy = *src; *copy = *src;
return copy; return copy;
} }
CliprdrFileContext* cliprdr_file_context_new(void* context) CliprdrFileContext* cliprdr_file_context_new(void* context)
{ {
CliprdrFileContext* file = calloc(1, sizeof(CliprdrFileContext)); CliprdrFileContext* file = calloc(1, sizeof(CliprdrFileContext));
@ -1680,6 +1876,7 @@ BOOL local_stream_discard(const void* key, void* value, void* arg)
return TRUE; return TRUE;
} }
#if defined(WITH_FUSE2) || defined(WITH_FUSE3)
static BOOL remote_stream_discard(const void* key, void* value, void* arg) static BOOL remote_stream_discard(const void* key, void* value, void* arg)
{ {
CliprdrFuseStream* stream = (CliprdrFuseStream*)value; CliprdrFuseStream* stream = (CliprdrFuseStream*)value;
@ -1691,6 +1888,7 @@ static BOOL remote_stream_discard(const void* key, void* value, void* arg)
fuse_reply_err(stream->req, EIO); fuse_reply_err(stream->req, EIO);
return HashTable_Remove(file->remote_streams, key); return HashTable_Remove(file->remote_streams, key);
} }
#endif
BOOL cliprdr_file_context_clear(CliprdrFileContext* file) BOOL cliprdr_file_context_clear(CliprdrFileContext* file)
{ {
@ -1706,17 +1904,17 @@ BOOL cliprdr_file_context_update_client_data(CliprdrFileContext* file, const cha
size_t size) size_t size)
{ {
BOOL rc = FALSE; BOOL rc = FALSE;
UINT32 streamID = file->local_stream_id++; UINT32 lockId = file->local_lock_id;
HashTable_Lock(file->local_streams); HashTable_Lock(file->local_streams);
CliprdrLocalStream* stream = HashTable_GetItemValue(file->local_streams, &streamID); CliprdrLocalStream* stream = HashTable_GetItemValue(file->local_streams, &lockId);
if (stream) if (stream)
rc = cliprdr_local_stream_update(stream, data, size); rc = cliprdr_local_stream_update(stream, data, size);
else else
{ {
stream = cliprdr_local_stream_new(streamID, data, size); stream = cliprdr_local_stream_new(lockId, data, size);
rc = HashTable_Insert(file->local_streams, &streamID, stream); rc = HashTable_Insert(file->local_streams, &stream->lockId, stream);
} }
HashTable_Unlock(file->local_streams); HashTable_Unlock(file->local_streams);
return rc; return rc;
@ -1755,3 +1953,12 @@ UINT32 cliprdr_file_context_remote_get_flags(CliprdrFileContext* file)
WINPR_ASSERT(file); WINPR_ASSERT(file);
return file->file_capability_flags; return file->file_capability_flags;
} }
BOOL cliprdr_file_context_update_base(CliprdrFileContext* file, wClipboard* clip)
{
wClipboardDelegate* delegate = ClipboardGetDelegate(clip);
if (!delegate)
return FALSE;
delegate->basePath = file->current_path;
return TRUE;
}

View File

@ -41,7 +41,8 @@ extern "C"
FREERDP_API UINT32 cliprdr_file_context_current_flags(CliprdrFileContext* file); FREERDP_API UINT32 cliprdr_file_context_current_flags(CliprdrFileContext* file);
FREERDP_API void* cliprdr_file_context_get_context(CliprdrFileContext* file); FREERDP_API void* cliprdr_file_context_get_context(CliprdrFileContext* file);
FREERDP_API const char* cliprdr_file_context_base_path(CliprdrFileContext* file);
FREERDP_API BOOL cliprdr_file_context_update_base(CliprdrFileContext* file, wClipboard* clip);
FREERDP_API BOOL cliprdr_file_context_init(CliprdrFileContext* file, FREERDP_API BOOL cliprdr_file_context_init(CliprdrFileContext* file,
CliprdrClientContext* cliprdr); CliprdrClientContext* cliprdr);